branch: elpa/scala-mode commit 68959cd48385f586f66a0c4954b7a3a1197650c5 Author: Ivan Malison <ivanmali...@gmail.com> Commit: Ivan Malison <ivanmali...@gmail.com>
imenu is mostly working. --- scala-mode2-imenu.el | 45 +++++++++++++++++++ scala-mode2-syntax.el | 120 +++++++++++++++++++++++++++----------------------- scala-mode2.el | 14 ++++-- 3 files changed, 121 insertions(+), 58 deletions(-) diff --git a/scala-mode2-imenu.el b/scala-mode2-imenu.el new file mode 100644 index 0000000..29b0c22 --- /dev/null +++ b/scala-mode2-imenu.el @@ -0,0 +1,45 @@ +;;; scala-mode-lib.el - Major mode for editing scala, common functions +;;; Copyright (c) 2012 Heikki Vesalainen +;;; For information on the License, see the LICENSE file + +(require 'scala-mode2-syntax) + +(defun scala-imenu:create-index () + (interactive) + (let ((class nil) (index nil)) + (goto-char (point-max)) + (while (setq class (scala-imenu:previous-class)) + (setq index (cons class index))) + index)) + +(defun scala-imenu:previous-class () + (interactive) + (let ((last-point (point)) (class-name nil)) + (scala-syntax:beginning-of-definition) + (if (eq (point) last-point) nil + (progn (save-excursion (re-search-forward scala-syntax:all-definition-re) + + (setq class-name (match-string-no-properties 2))) + `(,class-name . ,(cons `("<class>" . ,(point-marker)) + (scala-imenu:class-members))))))) + +(defun scala-imenu:class-members () + (interactive) + (let ((start-point (point))) + (save-excursion (scala-syntax:end-of-definition) + (backward-char) + (scala-imenu:get-class-members start-point)))) + +(defun scala-imenu:get-class-members (stop-at-point) + (scala-syntax:beginning-of-definition) + (let ((marker (point-marker))) + (if (< stop-at-point (point)) + (let ((member-name (save-excursion + (re-search-forward scala-syntax:all-definition-re) + (match-string-no-properties 2)))) + (cons `(,member-name . ,marker) + (scala-imenu:get-class-members stop-at-point))) + nil))) + + +(provide 'scala-mode2-imenu) diff --git a/scala-mode2-syntax.el b/scala-mode2-syntax.el index fcf0ee1..3261ca4 100644 --- a/scala-mode2-syntax.el +++ b/scala-mode2-syntax.el @@ -19,9 +19,6 @@ ;; single letter matching groups (Chapter 1) -(defun scala-syntax:regexp-or (regexps) - (concat "\\(?:" (mapconcat 'identity regexps "\\|") "\\)")) - (defconst scala-syntax:hexDigit-group "0-9A-Fa-f") (defconst scala-syntax:UnicodeEscape-re (concat "\\\\u[" scala-syntax:hexDigit-group "]\\{4\\}")) @@ -375,7 +372,7 @@ (concat "\\(^\\|[^`'_]\\)\\(" scala-syntax:modifiers-unsafe-re "\\)")) (defconst scala-syntax:whitespace-delimeted-modifiers-re - (concat " *\\(?:" scala-syntax:modifiers-unsafe-re "\\(?: *\\)" "\\)*")) + (concat "\\(?:" scala-syntax:modifiers-unsafe-re "\\(?: *\\)" "\\)*")) (defconst scala-syntax:body-start-re (concat "=" scala-syntax:end-of-code-line-re) @@ -385,8 +382,7 @@ (regexp-opt '("var" "val" "import") 'words) ("Keywords that can start a list")) -(defconst scala-syntax:multiLineStringLiteral-end-re - "\"\"+\\(\"\\)") +(defconst scala-syntax:multiLineStringLiteral-end-re "\"\"+\\(\"\\)") (defconst scala-syntax:case-re "\\<case\\>") @@ -407,7 +403,8 @@ (regexp-opt '("class" "object" "trait" "val" "var" "def" "type") 'words)) (defun scala-syntax:build-definition-re (words-re) - (concat scala-syntax:whitespace-delimeted-modifiers-re + (concat "[:space:]*" + scala-syntax:whitespace-delimeted-modifiers-re words-re "\\(?: *\\)" "\\(?2:" @@ -830,53 +827,6 @@ end of the skipped expression." (when (= (skip-syntax-forward ".") 0) (goto-char (or (scan-sexps (point) 1) (buffer-end 1))))) -(defun backward-sexp-forcing () - (condition-case ex (backward-sexp) ('error (backward-char)))) - -(defun scala-syntax:beginning-of-definition () - "This function is not totally correct. Scala syntax is hard." - (interactive) - (let ((found-position - (save-excursion - (funcall 'backward-sexp-forcing) - (scala-syntax:search-re-movement-function scala-syntax:all-definition-re - 'backward-sexp-forcing)))) - (when found-position (goto-char found-position)))) - -(defun scala-syntax:end-of-definition () - "This function is not totally correct. Scala syntax is hard." - (interactive) - (re-search-forward scala-syntax:all-definition-re) - (let ((found-position - (scala-syntax:search-re-movement-function scala-syntax:top-level-definition-re - #'backward-sexp))) - (when found-position (goto-char found-position)))) - -(defun find-brace-equals-or-next () - (interactive) - (let ((found-position - (scala-syntax:search-re-movement-function - (scala-syntax:regexp-or - `(,scala-syntax:all-definition-re "=" "{")) - #'forward-sexp))) - (when found-position (goto-char found-position)))) - - -(setq beginning-of-defun-function 'scala-syntax:beginning-of-defun) -(setq end-of-defun-function 'scala-syntax:end-of-defun) - -(defun scala-syntax:search-re-movement-function (re movement-function) - "Applies movement-function until something matching re is matched by -looking-at-p or the end/beginning of the buffer is reached. - -The position is returned if something is found, nil is returned if not. -" - (save-excursion - (progn - (while (not (or (bobp) (eobp) (looking-at re))) - (funcall movement-function)) - (if (looking-at re) (point) nil)))) - (defun scala-syntax:forward-token () "Move forward one scala token, comment word or string word. It can be: start or end of list (value or type), id, reserved @@ -977,4 +927,66 @@ not. A list must be either enclosed in parentheses or start with (when (looking-at scala-syntax:list-keywords-re) (goto-char (match-end 0)))))))) +;; Functions to help with beginning and end of definitions. + +(defun scala-syntax:backward-sexp-forcing () + (condition-case ex (backward-sexp) ('error (backward-char)))) + +(defun scala-syntax:forward-sexp-or-next-line () + (interactive) + (cond ((looking-at "\n") (next-line) (beginning-of-line)) + (t (forward-sexp)))) + +(defun scala-syntax:beginning-of-definition () + "This function is not totally correct. Scala syntax is hard." + (interactive) + (let ((found-position + (save-excursion + (funcall 'scala-syntax:backward-sexp-forcing) + (scala-syntax:movement-function-until-re scala-syntax:all-definition-re + 'scala-syntax:backward-sexp-forcing)))) + (when found-position (progn (goto-char found-position) (back-to-indentation))))) + +(defun scala-syntax:end-of-definition () + "This function is not totally correct. Scala syntax is hard. +According to the documentation of end-of-defun it should be assumed that +beginning-of-defun was executed prior to the execution of this function." + (interactive) + (re-search-forward scala-syntax:all-definition-re) + (scala-syntax:find-brace-equals-or-next) + (scala-syntax:handle-brace-equals-or-next)) + +(defun scala-syntax:find-brace-equals-or-next () + (interactive) + (scala-syntax:go-to-pos + (save-excursion + (scala-syntax:movement-function-until-cond-function + (lambda () (or (looking-at " *[{=]") + (looking-at scala-syntax:all-definition-re))) + (lambda () (condition-case ex (scala-syntax:forward-sexp-or-next-line) ('error nil))))))) + +(defun scala-syntax:handle-brace-equals-or-next () + (interactive) + (cond ((looking-at " *{") (forward-sexp)) + ((looking-at " *=") (scala-syntax:forward-sexp-or-next-line) + (scala-syntax:handle-brace-equals-or-next)) + ((looking-at scala-syntax:all-definition-re) nil) + (t (scala-syntax:forward-sexp-or-next-line) + (scala-syntax:handle-brace-equals-or-next)))) + +(defun scala-syntax:movement-function-until-re (re movement-function) + (save-excursion + (scala-syntax:movement-function-until-cond-function + (lambda () (looking-at re)) movement-function))) + +(defun scala-syntax:movement-function-until-cond-function (cond-function movement-function) + (let ((last-point (point))) + (if (not (funcall cond-function)) + (progn (funcall movement-function) + (if (equal last-point (point)) nil + (scala-syntax:movement-function-until-cond-function + cond-function movement-function))) last-point))) + +(defun scala-syntax:go-to-pos (pos) (when pos (goto-char pos))) + (provide 'scala-mode2-syntax) diff --git a/scala-mode2.el b/scala-mode2.el index efe2a68..d6ee564 100644 --- a/scala-mode2.el +++ b/scala-mode2.el @@ -12,6 +12,7 @@ (require 'scala-mode2-fontlock) (require 'scala-mode2-map) (require 'scala-mode2-sbt) +(require 'scala-mode2-imenu) ;; Tested only for emacs 24 (unless (<= 24 emacs-major-version) @@ -68,13 +69,17 @@ If there is no plausible default, return nil." (scala-mode:make-local-variables 'syntax-propertize-function 'parse-sexp-lookup-properties - 'forward-sexp-function) + 'forward-sexp-function + 'beginning-of-defun-function + 'end-of-defun-function) (add-hook 'syntax-propertize-extend-region-functions 'scala-syntax:propertize-extend-region) (setq syntax-propertize-function 'scala-syntax:propertize parse-sexp-lookup-properties t - forward-sexp-function 'scala-mode:forward-sexp-function)) + forward-sexp-function 'scala-mode:forward-sexp-function + beginning-of-defun-function 'scala-syntax:beginning-of-definition + end-of-defun-function 'scala-syntax:end-of-definition)) ;;;###autoload (define-derived-mode scala-mode prog-mode "Scala" @@ -108,7 +113,8 @@ When started, runs `scala-mode-hook'. 'indent-line-function 'fixup-whitespace 'delete-indentation - 'indent-tabs-mode) + 'indent-tabs-mode + 'imenu-create-index-function) (add-hook 'syntax-propertize-extend-region-functions 'scala-syntax:propertize-extend-region) @@ -142,7 +148,7 @@ When started, runs `scala-mode-hook'. fixup-whitespace 'scala-indent:fixup-whitespace delete-indentation 'scala-indent:join-line indent-tabs-mode nil - ) + imenu-create-index-function 'scala-imenu:create-index) (use-local-map scala-mode-map) ;; add indent functionality to some characters (scala-mode-map:add-remove-indent-hook)