branch: externals/javaimp commit 9f8e85fd58e357441658137c35d4b81d12ad495e Author: Filipp Gunbin <fgun...@fastmail.fm> Commit: Filipp Gunbin <fgun...@fastmail.fm>
Make navigation functions move over entire defun declaration --- javaimp-parse.el | 46 ++++++++++++++++++++++++++++++- javaimp.el | 84 +++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 100 insertions(+), 30 deletions(-) diff --git a/javaimp-parse.el b/javaimp-parse.el index 5433bebe6a..a5aa0af599 100644 --- a/javaimp-parse.el +++ b/javaimp-parse.el @@ -91,6 +91,9 @@ anything in the buffer. A marker pointing nowhere means everything's up-to-date.") + +;; Low-level subroutines + (defsubst javaimp-parse--substr-before-< (str) (let ((end (string-search "<" str))) (if end @@ -246,6 +249,38 @@ is unchanged." (goto-char pos) nil))) +(defun javaimp-parse--decl-prefix (&optional bound) + "Attempt to parse defun declaration prefix backwards from +point (but not farther than BOUND). Matches inside comments / +strings are skipped. Return the beginning of the match (then the +point is also at that position) or nil (then the point is left +unchanged)." + ;; If we skip a previous scope (including unnamed initializers), or + ;; reach enclosing scope start, we'll fail the check in the below + ;; loop. But a semicolon, which delimits statements, will just be + ;; skipped by scan-sexps, so find it and use as bound. If it is in + ;; another scope, that's not a problem, for the same reasons as + ;; described above. + (let* ((prev-semi (save-excursion + (javaimp-parse--rsb-keyword ";" bound t))) + (bound (when (or bound prev-semi) + (apply #'max + (delq nil + (list bound + (and prev-semi (1+ prev-semi))))))) + pos res) + (with-syntax-table javaimp--arglist-syntax-table + (while (and (ignore-errors + (setq pos (scan-sexps (point) -1))) + (or (not bound) (>= pos bound)) + (or (member (char-after pos) + '(?@ ?\( ;annotation type / args + ?<)) ;generic type + ;; keyword / identifier first char + (= (char-syntax pos) ?w))) + (goto-char (setq res pos)))) + res)) + ;;; Scopes @@ -668,6 +703,15 @@ it with PRED, and its parents with PARENT-PRED." (javaimp-scope-filter-parents scope parent-pred)) scope)) +(defun javaimp-parse-get-defun-decl-start (&optional bound) + "Return the position of the start of defun declaration at point, +but not before BOUND. Point should be at defun name, but +actually can be anywhere within the declaration, as long as it's +outside paren constructs like arg-list." + (save-excursion + (javaimp-parse--all-scopes)) + (javaimp-parse--decl-prefix bound)) + (defun javaimp-parse-get-class-abstract-methods () "Return all scopes which are abstract methods in classes." (javaimp-parse--all-scopes) @@ -683,12 +727,12 @@ it with PRED, and its parents with PARENT-PRED." (seq-mapcat #'javaimp-parse--interface-abstract-methods interfaces))) + (defun javaimp-parse-fully-parsed-p () "Return non-nil if current buffer is fully parsed." (and javaimp-parse--dirty-pos (not (marker-position javaimp-parse--dirty-pos)))) - (defmacro javaimp-parse-without-hook (&rest body) "Execute BODY, temporarily removing `javaimp-parse--update-dirty-pos' from `after-change-functions' diff --git a/javaimp.el b/javaimp.el index c68729864f..40c6b4dd01 100644 --- a/javaimp.el +++ b/javaimp.el @@ -1063,35 +1063,59 @@ buffer." "Function to be used as `beginning-of-defun-function'." (if (zerop arg) t - (when (> arg 0) (setq arg (1- arg))) (let* ((ctx (javaimp--get-sibling-context)) - (prev-idx (or (nth 2 ctx) -1)) - (siblings (nthcdr 3 ctx)) - (target-idx (- prev-idx arg))) + (parent-beg (nth 0 ctx)) + (parent-end (nth 1 ctx)) + (offset-from-prev (if (> arg 0) + (1- arg) + arg)) + (target-idx (- (nth 2 ctx) offset-from-prev)) + (siblings (nthcdr 3 ctx))) (cond ((or (not siblings) (< target-idx 0)) - (goto-char (nth 0 ctx)) - nil) + (when (= (abs arg) 1) + ;; Special case: ok to move to floor. If there's + ;; parent - try to skip its decl prefix too. + (goto-char (if parent-beg + (or (javaimp--beg-of-defun-decl parent-beg) + parent-beg) + (point-min))))) ((>= target-idx (length siblings)) - (goto-char (nth 1 ctx)) - nil) + (when (= (abs arg) 1) + ;; Special case: ok to move to ceil. + (goto-char (or parent-end (point-max))))) (t - (goto-char (javaimp-scope-open-brace - (nth target-idx siblings)))))))) + (let ((scope (nth target-idx siblings))) + (goto-char (or (javaimp--beg-of-defun-decl + (javaimp-scope-start scope) parent-beg) + (javaimp-scope-open-brace scope))))))))) + +(defun javaimp--beg-of-defun-decl (pos &optional bound) + "Subroutine of `javaimp-beginning-of-defun'." + (save-excursion + (save-restriction + (widen) + (goto-char pos) + (javaimp-parse-get-defun-decl-start bound)))) (defun javaimp-end-of-defun () "Function to be used as `end-of-defun-function'." - (when (javaimp-scope-p - (get-text-property (point) 'javaimp-parse-scope)) + (when-let* ((brace-pos + (next-single-property-change (point) 'javaimp-parse-scope)) + ((get-text-property brace-pos 'javaimp-parse-scope))) (ignore-errors (goto-char - (scan-lists (point) 1 0))))) + (scan-lists brace-pos 1 0))))) (defun javaimp--get-sibling-context () - "Return list of the form (FLOOR CEILING PREV-INDEX . SIBLINGS), -where SIBLINGS is a list of all sibling defun scopes. PREV-INDEX -is the index of the \"previous\" (relative to point) scope in -this list, or nil. FLOOR and CEILING are positions before and -after this group of defuns." + "Return list of the form (PARENT-BEG PARENT-END PREV-INDEX . + SIBLINGS), where SIBLINGS is a list of all sibling defun scopes. +PREV-INDEX is the index of the \"previous\" (relative to point) +scope in this list, or -1. PARENT-BEG and PARENT-END are the +positions of beginning and end of parent defun, if any. + +Both when we're inside a method and between methods, the parent +is the method's enclosing class. When we're inside the method, +PREV-INDEX gives the index of the method itself." (save-excursion (save-restriction (widen) @@ -1109,10 +1133,9 @@ after this group of defuns." ;; defuns whose parent is enc. enc)) (parent-beg (and parent (javaimp-scope-open-brace parent))) - (parent-end (and parent - (ignore-errors - (scan-lists - (javaimp-scope-open-brace parent) 1 0)))) + (parent-end (when parent-beg + (ignore-errors + (scan-lists parent-beg 1 0)))) (sibling-pred (javaimp-scope-same-parent-p parent)) (siblings (javaimp-parse-get-all-scopes @@ -1131,13 +1154,16 @@ after this group of defuns." (reverse siblings))))) (nconc (list - (or parent-beg (point-min)) - (or parent-end (point-max)) - (and prev - (seq-position siblings prev - (lambda (s1 s2) - (= (javaimp-scope-open-brace s1) - (javaimp-scope-open-brace s2)))))) + ;; Return start, not open brace, as this is where we'll go + ;; when no sibling + (and parent (javaimp-scope-start parent)) + parent-end + (or (and prev + (seq-position siblings prev + (lambda (s1 s2) + (= (javaimp-scope-open-brace s1) + (javaimp-scope-open-brace s2))))) + -1)) siblings)))))