branch: scratch/javaimp-wip commit 86cd3b9b9eb8f0da4d873cac2ead1475d2ed986f Author: Filipp Gunbin <fgun...@fastmail.fm> Commit: Filipp Gunbin <fgun...@fastmail.fm>
wip --- javaimp-parse.el | 101 +++++++++++++++++++++++++++++++++++++------------------ javaimp.el | 20 +++++++++-- 2 files changed, 87 insertions(+), 34 deletions(-) diff --git a/javaimp-parse.el b/javaimp-parse.el index fca0369..db58e0e 100644 --- a/javaimp-parse.el +++ b/javaimp-parse.el @@ -335,6 +335,7 @@ those may later become 'local-class' (see `javaimp--parse-scopes')." (javaimp--parse-skip-back-until) (= (char-before) ?\))) (ignore-errors + ;; for method this is arglist (goto-char (scan-lists (point) -1 0)))) (let* (;; leave open/close parens out @@ -367,14 +368,14 @@ those may later become 'local-class' (see `javaimp--parse-scopes')." "Attempts to parse 'array' scope." (save-excursion (and (javaimp--parse-skip-back-until) - (member (char-before) '(?, ?{ ?\])) + (member (char-before) '(?, ?\])) (make-javaimp-scope :type 'array :name "" :start nil :open-brace (nth 1 state))))) (defun javaimp--parse-scope-unknown (state) - "Catch-all parser which produces `unknown' scope." + "Catch-all parser which produces 'unknown' scope." (make-javaimp-scope :type 'unknown :name "unknown" :start nil @@ -382,34 +383,50 @@ those may later become 'local-class' (see `javaimp--parse-scopes')." (defun javaimp--parse-scopes (count) "Attempts to parse COUNT enclosing scopes at point. If COUNT is -nil then goes all the way up." - (let ((state (syntax-ppss)) res) +nil then goes all the way up. Examines and sets property +'javaimp-parse-scope' at each scope's open brace." + (let ((state (syntax-ppss)) + res) (unless (syntax-ppss-context state) - (save-excursion - (while (and (nth 1 state) - (or (not count) - (>= (setq count (1- count)) 0))) - ;; find innermost enclosing open-bracket - (goto-char (nth 1 state)) - (when (= (char-after) ?{) - (let ((scope (run-hook-with-args-until-success - 'javaimp--parse-scope-hook state))) - (push scope res) - (if (javaimp-scope-start scope) - (goto-char (javaimp-scope-start scope))))) - (setq state (syntax-ppss))))) + (while (and (nth 1 state) + (or (not count) + (>= (setq count (1- count)) 0))) + ;; find innermost enclosing open-bracket + (goto-char (nth 1 state)) + (when (= (char-after) ?{) + (let ((scope (get-text-property 'javaimp-parse-scope))) + (unless scope + (setq scope (run-hook-with-args-until-success + 'javaimp--parse-scope-hook state)) + (put-text-property (point) (1+ (point)) + 'javaimp--parse-scope scope)) + (push scope res) + (if (javaimp-scope-start scope) + (goto-char (javaimp-scope-start scope))))) + (setq state (syntax-ppss)))) ;; if a class is enclosed in anything other than a class, then it ;; should be local (let ((tmp res) in-local) (while tmp (if (javaimp--parse-is-class (car tmp)) - (if in-local - (setf (javaimp-scope-type (car tmp)) 'local-class)) + (when in-local + (setf (javaimp-scope-type (car tmp)) 'local-class)) (setq in-local t)) (setq tmp (cdr tmp)))) res)) +(defun javaimp--parse-all-scopes () + "Parses all scopes in a buffer." + (goto-char (point-max)) + (let ((parse-sexp-ignore-comments t) ; FIXME remove with major mode + (parse-sexp-lookup-properties nil)) + (while (javaimp--parse-rsb-keyword "{" nil t) + (save-excursion + (forward-char) + ;; Set props at this brace and all the way up + (javaimp--parse-scopes nil))))) + ;; Main @@ -422,18 +439,38 @@ nil then goes all the way up." (defun javaimp--parse-get-file-classes () (goto-char (point-max)) - (let (res) - (while (javaimp--parse-rsb-keyword - (regexp-opt javaimp--parse-class-keywords 'words) nil t) - (save-excursion - (let ((parse-sexp-ignore-comments t) ; FIXME remove with major mode - (parse-sexp-lookup-properties nil)) - (when (and (ignore-errors - (goto-char (scan-lists (point) 1 -1))) - (= (char-before) ?{)) - (let ((scopes (javaimp--parse-scopes nil))) - (when (seq-every-p #'javaimp--parse-is-class scopes) - (push (mapconcat #'javaimp-scope-name scopes ".") res))))))) - res)) + (let (match res) + (while (setq match (text-property-search-backward + 'javaimp-parse-scope nil nil)) + (when (javaimp--parse-is-class (prop-match-value match)) + (push (mapconcat #'javaimp-scope-name + (javaimp--parse-scopes nil) + ".") + res))))) + +;; Imenu support + +(defun javaimp-imenu-create-index () + (goto-char (point-max)) + (let (match methods top-classes) + (while (setq match (text-property-search-backward + 'javaimp-parse-scope nil nil)) + (let* ((scope (prop-match-value match)) + (parent (javaimp--parse-scopes 1))) + (cond ((and (eq (javaimp-scope-type scope) 'method) + (and parent (javaimp--parse-is-class parent))) + ;; TODO store parent location in scope?; reuse + ;; javaimp--build-tree; collect top-level classes + ) + ;; TODO javaimp-imenu-group-methods - t / nil / qualified + + ;; create sub-alist for each enclosing scope, which must be + ;; a class + ;; + ;; (INDEX-NAME . INDEX-POSITION) + ;; (MENU-TITLE . SUB-ALIST) + + ;; TODO imenu function - to javaimp-scope-start, and back-to-indentation + ))))) (provide 'javaimp-parse) diff --git a/javaimp.el b/javaimp.el index 8309d50..eb996f3 100644 --- a/javaimp.el +++ b/javaimp.el @@ -148,6 +148,18 @@ files in the current project and add their fully-qualified names to the completion alternatives list." :type 'boolean) +(defcustom javaimp-imenu-group-methods t + "How to lay out methods in Imenu index. +If t (the default), methods are grouped in their enclosing +scopes. nil means use just flat list of simple method names. +`qualified' means use flat list where each method name is +prepended with nested scopes. See also +`javaimp-parse-format-method-name'." + :type '(choice :tag "Group methods" + (const :tag "Group into enclosing scopes" t) + (const :tag "Flat list of simple name" nil) + (const :tag "Flat list of qualified names" qualified))) + ;; Variables @@ -423,13 +435,16 @@ prefix arg is given, don't do this filtering." (directory-files-recursively dir "\\.java\\'"))))) (defun javaimp--get-file-classes (file) + ;; TODO per-file cache (check file modification ts) (with-temp-buffer (insert-file-contents file) (let ((package (javaimp--parse-get-package))) (mapcar (lambda (class) (if package (concat package "." class))) - (javaimp--parse-get-file-classes))))) + (progn + (javaimp--parse-all-scopes) + (javaimp--parse-get-file-classes)))))) ;; Organizing imports @@ -603,7 +618,8 @@ which is first cleared." (interactive) (let* ((parse-sexp-ignore-comments t) ; FIXME remove with major mode (parse-sexp-lookup-properties nil) - (scopes (javaimp--parse-scopes nil)) + (scopes (save-excursion + (javaimp--parse-scopes nil))) (file buffer-file-name) (pos (point)) (buf (get-buffer-create "*javaimp-scopes*")))