[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 7184664 20/38: Add a jump to definition command bound to M
From: |
Dmitry Gutov |
Subject: |
[elpa] master 7184664 20/38: Add a jump to definition command bound to M-. |
Date: |
Wed, 09 Sep 2015 18:41:44 +0000 |
branch: master
commit 71846649a7b8ff2c3888a554a17c578ea68cd847
Author: ScottyB <address@hidden>
Commit: ScottyB <address@hidden>
Add a jump to definition command bound to M-.
---
js2-mode.el | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++
tests/navigation.el | 43 ++++++++++++++++++
2 files changed, 162 insertions(+), 0 deletions(-)
diff --git a/js2-mode.el b/js2-mode.el
index b885efd..54c33cc 100644
--- a/js2-mode.el
+++ b/js2-mode.el
@@ -1115,6 +1115,7 @@ information."
(define-key map (kbd "C-c C-o") #'js2-mode-toggle-element)
(define-key map (kbd "C-c C-w") #'js2-mode-toggle-warnings-and-errors)
(define-key map [down-mouse-3] #'js2-down-mouse-3)
+ (define-key map (kbd "M-.") #'js2-jump-to-definition)
(define-key map [menu-bar javascript]
(cons "JavaScript" (make-sparse-keymap "JavaScript")))
@@ -12297,6 +12298,124 @@ it marks the next defun after the ones already
marked."
(unless (js2-ast-root-p fn)
(narrow-to-region beg (+ beg (js2-node-len fn))))))
+(defun js2-jump-to-definition ()
+ "Jump to the definition of an object's property, variable or function."
+ (interactive)
+ (ring-insert find-tag-marker-ring (point-marker))
+ (let* ((node (js2-node-at-point))
+ (parent (js2-node-parent node))
+ (prop-names (if (js2-prop-get-node-p parent)
+ (js2-prop-names-left node)))
+ (name (if (and (js2-name-node-p node)
+ (not (js2-object-prop-node-p parent)))
+ (js2-name-node-name node)
+ (error "Node is not a supported jump node")))
+ (node-init (if (and prop-names (listp prop-names))
+ (js2-find-property prop-names)
+ (js2-name-declaration name))))
+ (unless node-init
+ (pop-tag-mark)
+ (error "No jump location found"))
+ (goto-char (js2-node-abs-pos node-init))))
+
+(defun js2-prop-names-left (name-node)
+ "Create a list of all of the names in the property NAME-NODE.
+NAME-NODE must have a js2-prop-get-node as parent. Only adds
+properties to the left of point. This is so individual jump
+points can be found for each property in the chain."
+ (let* (name
+ (parent (js2-node-parent name-node))
+ left
+ names)
+ (unless (or (js2-prop-get-node-p parent) (js2-name-node-p name-node))
+ (error "Not a name node or doesn't have a prop-get-node as parent"))
+ (setq name (js2-name-node-name name-node)
+ left (js2-prop-get-node-left parent))
+ (if (and (js2-name-node-p left)
+ (string= name (js2-name-node-name left)))
+ (setq names name)
+ (js2-visit-ast
+ parent
+ (lambda (node endp)
+ (unless endp
+ (if (js2-name-node-p node)
+ (push (js2-name-node-name node) names)
+ t))))
+ names)))
+
+(defun js2-find-property (list-names)
+ "Find the property definition that consists of LIST-NAMES.
+Supports navigation to 'foo.bar = 3' and 'foo = {bar: 3}'."
+ (catch 'prop-found
+ (js2-visit-ast-root
+ js2-mode-ast
+ (lambda (node endp)
+ (let ((parent (js2-node-parent node)))
+ (unless endp
+ (if (or (and (js2-prop-get-node-p node)
+ (not (or (js2-elem-get-node-p parent) (js2-call-node-p
parent)))
+ (equal list-names (js2-build-prop-name-list node)))
+ (and (js2-name-node-p node)
+ (js2-object-prop-node-p parent)
+ (string= (js2-name-node-name node)
+ (first list-names))))
+ (throw 'prop-found node))
+ t))))))
+
+(defun js2-name-declaration (name)
+ "Return the declaration node for node named NAME."
+ (let* ((node (js2-root-or-node))
+ (scope-def (js2-get-defining-scope node name))
+ (scope (if scope-def (js2-scope-get-symbol scope-def name) nil))
+ (symbol (if scope (js2-symbol-ast-node scope) nil)))
+ (if (not symbol)
+ (js2-get-function-node name scope-def)
+ symbol)))
+
+(defun js2-get-function-name (fn-node)
+ "Return the name of the function FN-NODE.
+Value may be either function name or the variable name that holds
+the function."
+ (let ((parent (js2-node-parent fn-node)))
+ (if (js2-function-node-p fn-node)
+ (or (js2-function-name fn-node)
+ (if (js2-var-init-node-p parent)
+ (js2-name-node-name (js2-var-init-node-target parent)))))))
+
+(defun js2-root-or-node ()
+ "Return the current node or js2-ast-root node."
+ (let ((node (js2-node-at-point)))
+ (if (js2-ast-root-p node)
+ node
+ (js2-node-get-enclosing-scope node))))
+
+(defun js2-build-prop-name-list (prop-node)
+ "Build a list of names from a PROP-NODE."
+ (let* (names
+ left
+ left-node)
+ (unless (js2-prop-get-node-p prop-node)
+ (error "Node is not a property prop-node"))
+ (while (js2-prop-get-node-p prop-node)
+ (push (js2-name-node-name (js2-prop-get-node-right prop-node)) names)
+ (setq left-node (js2-prop-get-node-left prop-node))
+ (when (js2-name-node-p left-node)
+ (setq left (js2-name-node-name left-node)))
+ (setq prop-node (js2-node-parent prop-node)))
+ (append names `(,left))))
+
+(defun js2-get-function-node (name scope)
+ "Return node of function named NAME in SCOPE."
+ (catch 'function-found
+ (js2-visit-ast
+ scope
+ (lambda (node end-p)
+ (when (and (not end-p)
+ (string= name (js2-get-function-name node)))
+ (throw 'function-found node))
+ t))
+ nil))
+
(provide 'js2-mode)
;;; js2-mode.el ends here
diff --git a/tests/navigation.el b/tests/navigation.el
new file mode 100644
index 0000000..bbd4861
--- /dev/null
+++ b/tests/navigation.el
@@ -0,0 +1,43 @@
+;;; tests/navigation.el --- Some tests for js2-mode.
+
+;; Copyright (C) 2009, 2011-2013 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'js2-mode)
+
+(cl-defun js2-navigation-helper (buffer-content expected-point &optional
(point-offset 1))
+ (with-temp-buffer
+ (insert buffer-content)
+ (js2-mode)
+ (goto-char (or (- (point) point-offset)))
+ (js2-jump-to-definition)
+ (should (= (point) expected-point))))
+
+(ert-deftest js2-jump-to-var ()
+ (js2-navigation-helper "var soup = 2; soup" 5))
+
+(ert-deftest js2-jump-to-function ()
+ (js2-navigation-helper "function aFunction() {}; aFunction" 1))
+
+(ert-deftest js2-jump-to-function-parameters ()
+ (js2-navigation-helper "var p1 = 4; function aFunction(p1, p2) {p1};" 32 4))
+
+(ert-deftest js2-jump-to-object-property ()
+ (js2-navigation-helper "var aObject = {prop1: 3, prop2: \"hello\"};
aObject.prop1" 16))
- [elpa] master c47a894 11/38: Fix #247, indentation inside block comments, (continued)
- [elpa] master c47a894 11/38: Fix #247, indentation inside block comments, Dmitry Gutov, 2015/09/09
- [elpa] master 242af01 14/38: Handle @property like @param, and handle aliases, Dmitry Gutov, 2015/09/09
- [elpa] master c68646a 12/38: Never enable js2-minor-mode in js2-mode, Dmitry Gutov, 2015/09/09
- [elpa] master 5beb8ea 13/38: Define js2-re-search-forward as an alias as well, Dmitry Gutov, 2015/09/09
- [elpa] master fc56c58 16/38: js2-define-destruct-symbols-internal: Anticipate js2-getter-setter-node, Dmitry Gutov, 2015/09/09
- [elpa] master c8b8e11 19/38: js2-define-destruct-symbols: Speed up, theoretically, Dmitry Gutov, 2015/09/09
- [elpa] master a6f2a94 15/38: Allow plain parameters after default, Dmitry Gutov, 2015/09/09
- [elpa] master d0686a0 18/38: js2-define-destruct-symbols-internal: Remove, don't need it anymore, Dmitry Gutov, 2015/09/09
- [elpa] master f146f13 17/38: js2-define-destruct-symbols-internal: Stop growing NAME-NODES exponentially, Dmitry Gutov, 2015/09/09
- [elpa] master eba59c5 21/38: Added missing etags dependency, Dmitry Gutov, 2015/09/09
- [elpa] master 7184664 20/38: Add a jump to definition command bound to M-.,
Dmitry Gutov <=
- [elpa] master bc5cdb4 23/38: Simplified property name matching, Dmitry Gutov, 2015/09/09
- [elpa] master 1ee5c45 22/38: Return correct node when searching for the definition of a property., Dmitry Gutov, 2015/09/09
- [elpa] master 579aacb 24/38: Simplified method of searching for nodes based on scope, Dmitry Gutov, 2015/09/09
- [elpa] master f942b83 26/38: Support jumping to buffers of the same major mode, Dmitry Gutov, 2015/09/09
- [elpa] master 145c5d6 25/38: Fixed jumping to object properties, Dmitry Gutov, 2015/09/09
- [elpa] master bb0476c 29/38: Clarified js2-search-scope doc string, Dmitry Gutov, 2015/09/09
- [elpa] master c4f4095 28/38: Only jump if not already at var or function definition, Dmitry Gutov, 2015/09/09
- [elpa] master af85699 30/38: Clean up todo in js2-search-scope and fix year typo, Dmitry Gutov, 2015/09/09
- [elpa] master aaf218a 27/38: Find definition by locating assignment nodes, Dmitry Gutov, 2015/09/09
- [elpa] master e236923 31/38: Removed functions: js2-build-prop-name-list and js2-names-left., Dmitry Gutov, 2015/09/09