Finish xref backend
This commit is contained in:
@@ -108,6 +108,7 @@ command.")
|
|||||||
(special_variable_name) @font-lock-variable-use-face
|
(special_variable_name) @font-lock-variable-use-face
|
||||||
(expansion_with_modifier (simple_variable_name)
|
(expansion_with_modifier (simple_variable_name)
|
||||||
@font-lock-variable-use-face)
|
@font-lock-variable-use-face)
|
||||||
|
(expansion_pattern (simple_variable_name) @font-lock-variable-use-face)
|
||||||
(expansion_substring (simple_variable_name) @font-lock-variable-use-face)
|
(expansion_substring (simple_variable_name) @font-lock-variable-use-face)
|
||||||
(variable_ref (simple_variable_name) @font-lock-variable-use-face)
|
(variable_ref (simple_variable_name) @font-lock-variable-use-face)
|
||||||
;; variables in math expansions
|
;; variables in math expansions
|
||||||
@@ -261,6 +262,13 @@ Return non-nil if NODE is not an anonymous function."
|
|||||||
name: ([(simple_variable_name)
|
name: ([(simple_variable_name)
|
||||||
(special_variable_name)]
|
(special_variable_name)]
|
||||||
@var))
|
@var))
|
||||||
|
(variable_ref ([(simple_variable_name)
|
||||||
|
(special_variable_name)]
|
||||||
|
@var))
|
||||||
|
(expansion_pattern
|
||||||
|
name: ([(simple_variable_name)
|
||||||
|
(special_variable_name)]
|
||||||
|
@var))
|
||||||
((word) @func
|
((word) @func
|
||||||
(:pred zsh-ts-mode--not-let-predicate @func))))
|
(:pred zsh-ts-mode--not-let-predicate @func))))
|
||||||
"Query for `zsh-ts-mode' `xref-backend-identifier-at-point'.")
|
"Query for `zsh-ts-mode' `xref-backend-identifier-at-point'.")
|
||||||
@@ -284,23 +292,48 @@ Return non-nil if NODE is not an anonymous function."
|
|||||||
(when-let* ((func (alist-get 'func nodes)))
|
(when-let* ((func (alist-get 'func nodes)))
|
||||||
(propertize (treesit-node-text func t) 'type 'function))))))
|
(propertize (treesit-node-text func t) 'type 'function))))))
|
||||||
|
|
||||||
(defun zsh-ts-mode--treesit-node-location (node)
|
(cl-defmethod xref-backend-identifier-completion-table ((_backend (eql zsh-ts)))
|
||||||
"Return an xref location pointing to NODE."
|
"Return nil."
|
||||||
|
nil)
|
||||||
|
|
||||||
|
(cl-defmethod xref-backend-identifier-completion-ignore-case
|
||||||
|
((_backend (eql zsh-ts)))
|
||||||
|
"Return `completion-ignore-case'."
|
||||||
|
completion-ignore-case)
|
||||||
|
|
||||||
|
(defun zsh-ts-mode--treesit-node-summary (node)
|
||||||
|
"Return the contents of the line of NODE."
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (treesit-node-start node))
|
(goto-char (treesit-node-start node))
|
||||||
(make-xref-file-location :file (buffer-file-name)
|
(buffer-substring (pos-bol) (pos-eol))))
|
||||||
:line (line-number-at-pos)
|
|
||||||
:column (- (point) (pos-bol)))))
|
|
||||||
|
|
||||||
(defun zsh-ts-mode--make-function-definition-xref (identifier node)
|
(cl-defstruct zsh-ts-mode--location
|
||||||
"Make an xref object pointing to IDENTIFIER.
|
"Xref locaton object for tree-sitter nodes."
|
||||||
NODE is IDENTIFIER's tree-sitter node."
|
node)
|
||||||
(xref-make (format "%s %s()"
|
|
||||||
(propertize "function"
|
(cl-defmethod xref-location-line ((location zsh-ts-mode--location))
|
||||||
'face 'font-lock-keyword-face)
|
"Return the line number of LOCATION."
|
||||||
(propertize identifier
|
(line-number-at-pos (treesit-node-start
|
||||||
'face 'font-lock-function-name-face))
|
(zsh-ts-mode--location-node location))))
|
||||||
(zsh-ts-mode--treesit-node-location node)))
|
|
||||||
|
(cl-defmethod xref-location-group ((location zsh-ts-mode--location))
|
||||||
|
"Return the file name of the buffer of LOCATION."
|
||||||
|
(with-slots (node) location
|
||||||
|
(or (buffer-file-name (treesit-node-buffer node))
|
||||||
|
"")))
|
||||||
|
|
||||||
|
(cl-defmethod xref-location-marker ((location zsh-ts-mode--location))
|
||||||
|
"Return a marker for LOCATION."
|
||||||
|
(let ((node (zsh-ts-mode--location-node location))
|
||||||
|
(marker (make-marker)))
|
||||||
|
(set-marker marker (treesit-node-start node)
|
||||||
|
(treesit-node-buffer node))
|
||||||
|
marker))
|
||||||
|
|
||||||
|
(defun zsh-ts-mode--make-xref-for-node (node)
|
||||||
|
"Create an xref for a tree-sitter node NODE."
|
||||||
|
(xref-make (zsh-ts-mode--treesit-node-summary node)
|
||||||
|
(make-zsh-ts-mode--location :node node)))
|
||||||
|
|
||||||
(defvar zsh-ts-mode--xref-function-definitions-query
|
(defvar zsh-ts-mode--xref-function-definitions-query
|
||||||
(treesit-query-compile 'zsh '((function_definition
|
(treesit-query-compile 'zsh '((function_definition
|
||||||
@@ -314,11 +347,7 @@ NODE is IDENTIFIER's tree-sitter node."
|
|||||||
zsh-ts-mode--xref-function-definitions-query
|
zsh-ts-mode--xref-function-definitions-query
|
||||||
nil nil t)
|
nil nil t)
|
||||||
when (equal identifier (treesit-node-text node))
|
when (equal identifier (treesit-node-text node))
|
||||||
collect (zsh-ts-mode--make-function-definition-xref identifier node)
|
collect (zsh-ts-mode--make-xref-for-node node)))
|
||||||
into out
|
|
||||||
finally return (if (length= out 1)
|
|
||||||
(car out)
|
|
||||||
out)))
|
|
||||||
|
|
||||||
(defvar zsh-ts-mode--xref-variable-definitions-query
|
(defvar zsh-ts-mode--xref-variable-definitions-query
|
||||||
(treesit-query-compile
|
(treesit-query-compile
|
||||||
@@ -331,58 +360,6 @@ NODE is IDENTIFIER's tree-sitter node."
|
|||||||
@let-arg)))))
|
@let-arg)))))
|
||||||
"Variable query for `zsh-ts-mode--xref-variable-definitions'.")
|
"Variable query for `zsh-ts-mode--xref-variable-definitions'.")
|
||||||
|
|
||||||
(defvar zsh-ts-mode--non-let-declaration-type-query
|
|
||||||
(treesit-query-compile 'zsh '((declaration_command :anchor _ @name)))
|
|
||||||
"Helper query for `zsh-ts-mode--get-non-let-assignment-type'.")
|
|
||||||
|
|
||||||
(defun zsh-ts-mode--get-assignment-parent (node)
|
|
||||||
"Get the node that is a parent of NODE that is a variable assignment.
|
|
||||||
This only looks up two levels."
|
|
||||||
(cond ((equal (treesit-node-type
|
|
||||||
(treesit-node-parent node))
|
|
||||||
"declaration_command")
|
|
||||||
(treesit-node-parent node))
|
|
||||||
((equal (treesit-node-type
|
|
||||||
(treesit-node-parent (treesit-node-parent node)))
|
|
||||||
"declaration_command")
|
|
||||||
(treesit-node-parent (treesit-node-parent node)))))
|
|
||||||
|
|
||||||
(defun zsh-ts-mode--get-non-let-assignment-type (node)
|
|
||||||
"Return the assignment command for NODE."
|
|
||||||
(when-let* ((type-node (zsh-ts-mode--get-assignment-parent node)))
|
|
||||||
(propertize (treesit-node-text
|
|
||||||
(car (treesit-query-capture
|
|
||||||
type-node
|
|
||||||
zsh-ts-mode--non-let-declaration-type-query
|
|
||||||
nil nil t))
|
|
||||||
t)
|
|
||||||
'face 'font-lock-keyword-face)))
|
|
||||||
|
|
||||||
(defun zsh-ts-mode--make-xref-for-non-let-assignment (node)
|
|
||||||
"Create an xref for an \"other\" assignment for NODE.
|
|
||||||
An \"other\" assignment is an assignment using local, typeset, etc."
|
|
||||||
(let ((type (zsh-ts-mode--get-non-let-assignment-type node)))
|
|
||||||
(xref-make (format "%s%s" (if type (concat type " ") "")
|
|
||||||
(propertize (treesit-node-text node t)
|
|
||||||
'face 'font-lock-variable-name-face))
|
|
||||||
(zsh-ts-mode--treesit-node-location node))))
|
|
||||||
|
|
||||||
(defun zsh-ts-mode--make-xref-for-let-assignment (node)
|
|
||||||
"Create an xref node for a list assingment.
|
|
||||||
NODE is the argument to let (possibly with a = in it)."
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (treesit-node-start node))
|
|
||||||
(xref-make
|
|
||||||
(format "%s %s" (propertize "let" 'face 'font-lock-keyword-face)
|
|
||||||
(propertize (buffer-substring-no-properties
|
|
||||||
(treesit-node-start node)
|
|
||||||
(if (re-search-forward (rx (or "=" "["))
|
|
||||||
(treesit-node-end node)
|
|
||||||
t)
|
|
||||||
(1- (point))
|
|
||||||
(treesit-node-end node)))))
|
|
||||||
(zsh-ts-mode--treesit-node-location node))))
|
|
||||||
|
|
||||||
(defun zsh-ts-mode--xref-variable-definitions (identifier)
|
(defun zsh-ts-mode--xref-variable-definitions (identifier)
|
||||||
"Find all definitions of variable IDENTIFIER in the current buffer."
|
"Find all definitions of variable IDENTIFIER in the current buffer."
|
||||||
(let (out)
|
(let (out)
|
||||||
@@ -393,45 +370,96 @@ NODE is the argument to let (possibly with a = in it)."
|
|||||||
(cl-case tag
|
(cl-case tag
|
||||||
(non-let
|
(non-let
|
||||||
(when (equal (treesit-node-text node) identifier)
|
(when (equal (treesit-node-text node) identifier)
|
||||||
(push (zsh-ts-mode--make-xref-for-non-let-assignment node) out)))
|
(push (zsh-ts-mode--make-xref-for-node node) out)))
|
||||||
(let-arg
|
(let-arg
|
||||||
(when (string-match-p (rx bos (literal identifier) (or eos "="))
|
(when (string-match-p (rx bos (literal identifier) (or eos "="))
|
||||||
(treesit-node-text node))
|
(treesit-node-text node))
|
||||||
(push (zsh-ts-mode--make-xref-for-let-assignment node) out))))))
|
(push (zsh-ts-mode--make-xref-for-node node) out))))))
|
||||||
(if (length= out 1) (car out) out)))
|
out))
|
||||||
|
|
||||||
(cl-defmethod xref-backend-definitions ((_backend (eql zsh-ts)) identifier)
|
(cl-defmethod xref-backend-definitions ((_backend (eql zsh-ts)) identifier)
|
||||||
"`zsh-ts-mode' implementation for finding xref definitions for IDENTIFIER."
|
"`zsh-ts-mode' implementation for finding xref definitions for IDENTIFIER."
|
||||||
(cl-case (get-text-property 0 'type identifier)
|
(when identifier
|
||||||
(function (zsh-ts-mode--xref-function-definitions identifier))
|
(let ((type (get-text-property 0 'type identifier)))
|
||||||
(variable (zsh-ts-mode--xref-variable-definitions identifier))))
|
(append
|
||||||
|
(when (memq type '(nil function))
|
||||||
|
(zsh-ts-mode--xref-function-definitions identifier))
|
||||||
|
(when (memq type '(nil variable))
|
||||||
|
(zsh-ts-mode--xref-variable-definitions identifier))))))
|
||||||
|
|
||||||
|
(defvar zsh-ts-mode--function-references-query
|
||||||
|
(treesit-query-compile
|
||||||
|
'zsh '((command name: (command_name (word) @name))))
|
||||||
|
"Query used by `zsh-ts-mode--xref-function-references'.")
|
||||||
|
|
||||||
(defun zsh-ts-mode--xref-function-references (identifier)
|
(defun zsh-ts-mode--xref-function-references (identifier)
|
||||||
"Find all references for the function IDENTIFIER in the current buffer."
|
"Find all references for the function IDENTIFIER in the current buffer."
|
||||||
(let ((nodes (treesit-query-capture
|
(let ((nodes (treesit-query-capture
|
||||||
(treesit-buffer-root-node)
|
(treesit-buffer-root-node)
|
||||||
`((command name: (command_name (word) @name)))
|
zsh-ts-mode--function-references-query
|
||||||
nil nil t))
|
nil nil t))
|
||||||
(ident-copy (copy-sequence identifier)))
|
(ident-copy (copy-sequence identifier))
|
||||||
(set-text-properties 0 (length ident-copy) nil ident-copy)
|
(quote-ident (regexp-quote identifier)))
|
||||||
|
(set-text-properties 0 (length ident-copy) () ident-copy)
|
||||||
(cl-loop for node in nodes
|
(cl-loop for node in nodes
|
||||||
collect (xref-make
|
when (save-excursion
|
||||||
(propertize ident-copy 'face
|
(goto-char (treesit-node-start node))
|
||||||
'font-lock-function-name-face)
|
(looking-at-p quote-ident))
|
||||||
(zsh-ts-mode--treesit-node-location node)))))
|
collect (zsh-ts-mode--make-xref-for-node node))))
|
||||||
|
|
||||||
|
(defvar zsh-ts-mode--variable-references-query
|
||||||
|
(treesit-query-compile
|
||||||
|
'zsh '(([(simple_variable_name) (special_variable_name)] @var)))
|
||||||
|
"Query used by `zsh-ts-mode--xref-variable-references'.")
|
||||||
|
|
||||||
(defun zsh-ts-mode--xref-variable-references (identifier)
|
(defun zsh-ts-mode--xref-variable-references (identifier)
|
||||||
"Find all references for the variable IDENTIFIER in the current buffer."
|
"Find all references for the variable IDENTIFIER in the current buffer."
|
||||||
())
|
(let ((ident-copy (copy-sequence identifier))
|
||||||
|
(quote-ident (regexp-quote identifier)))
|
||||||
|
(set-text-properties 0 (length ident-copy) () ident-copy)
|
||||||
|
(mapcan
|
||||||
|
#'(lambda (node)
|
||||||
|
(when (save-excursion
|
||||||
|
(goto-char (treesit-node-start node))
|
||||||
|
(looking-at-p quote-ident))
|
||||||
|
(list (zsh-ts-mode--make-xref-for-node node))))
|
||||||
|
(treesit-query-capture (treesit-buffer-root-node)
|
||||||
|
zsh-ts-mode--variable-references-query
|
||||||
|
nil nil t))))
|
||||||
|
|
||||||
(cl-defmethod xref-backend-references ((_backend (eql zsh-ts)) identifier)
|
(cl-defmethod xref-backend-references ((_backend (eql zsh-ts)) identifier)
|
||||||
"`zsh-ts-mode' implementation for finding xref references for IDENTIFIER."
|
"`zsh-ts-mode' implementation for finding xref references for IDENTIFIER."
|
||||||
(append
|
(let ((type (get-text-property 0 'type identifier)))
|
||||||
;; definitions are references
|
(append
|
||||||
(xref-backend-definitions 'zsh-ts identifier)
|
;; definitions are references
|
||||||
(cl-case (get-text-property 0 'type identifier)
|
(ensure-list (xref-backend-definitions 'zsh-ts identifier))
|
||||||
(function (zsh-ts-mode--xref-function-references identifier))
|
(when (memq type '(nil function))
|
||||||
(variable (zsh-ts-mode--xref-variable-references identifier)))))
|
(zsh-ts-mode--xref-function-references identifier))
|
||||||
|
(when (memq type '(nil variable))
|
||||||
|
(zsh-ts-mode--xref-variable-references identifier)))))
|
||||||
|
|
||||||
|
(defvar zsh-ts-mode--xref-apropos-query
|
||||||
|
(treesit-query-compile
|
||||||
|
'zsh '(((simple_variable_name) @ident)
|
||||||
|
((special_variable_name) @ident)
|
||||||
|
((variable_name) @ident)
|
||||||
|
(command name: (command_name ( (word) @cname (:equal @cname "let")))
|
||||||
|
argument: (word) @ident)
|
||||||
|
(declaration_command argument: (word) @ident)
|
||||||
|
((variable_name) @ident)
|
||||||
|
(function_definition name: (word) @ident)))
|
||||||
|
"Query used by `xref-backend-apropos'.")
|
||||||
|
|
||||||
|
(cl-defmethod xref-backend-apropos ((_backend (eql zsh-ts)) pattern)
|
||||||
|
"Search though the buffer for PATTERN."
|
||||||
|
(let (out)
|
||||||
|
(dolist (ent (treesit-query-capture (treesit-buffer-root-node)
|
||||||
|
zsh-ts-mode--xref-apropos-query))
|
||||||
|
(cl-destructuring-bind (type . node) ent
|
||||||
|
(when (and (eq type 'ident)
|
||||||
|
(string-match-p pattern (treesit-node-text node)))
|
||||||
|
(push (zsh-ts-mode--make-xref-for-node node) out))))
|
||||||
|
out))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(define-derived-mode zsh-ts-mode sh-base-mode "Zsh"
|
(define-derived-mode zsh-ts-mode sh-base-mode "Zsh"
|
||||||
@@ -457,6 +485,7 @@ not written in Zsh."
|
|||||||
(setq-local treesit-simple-imenu-settings zsh-ts-mode--simple-imenu-settings
|
(setq-local treesit-simple-imenu-settings zsh-ts-mode--simple-imenu-settings
|
||||||
treesit-defun-name-function #'zsh-ts-mode--defun-name
|
treesit-defun-name-function #'zsh-ts-mode--defun-name
|
||||||
imenu-create-index-function #'treesit-simple-imenu)
|
imenu-create-index-function #'treesit-simple-imenu)
|
||||||
|
(add-hook 'xref-backend-functions #'zsh-ts-mode--xref-backend nil t)
|
||||||
(treesit-major-mode-setup)))
|
(treesit-major-mode-setup)))
|
||||||
|
|
||||||
(provide 'zsh-ts-mode)
|
(provide 'zsh-ts-mode)
|
||||||
|
|||||||
Reference in New Issue
Block a user