From fbb4eb919b4c91dd8517a06934bf1f897eaa34bb Mon Sep 17 00:00:00 2001 From: Yuan Fu Date: Sat, 24 Dec 2022 18:24:01 -0800 Subject: [PATCH] Support treesit-defun-name in tree-sitter major modes * lisp/progmodes/csharp-mode.el (csharp-ts-mode--defun-name): New function. (csharp-ts-mode--imenu-1): Extract into new function. (csharp-ts-mode): Setup treesit-defun-name-function. * lisp/progmodes/java-ts-mode.el (java-ts-mode--defun-name): New function. (java-ts-mode--imenu-1): Extract into new function. (java-ts-mode): Setup treesit-defun-name-function. * lisp/progmodes/js.el (js-treesit-current-defun): Remove function. This function is not used (for a while already). (js--treesit-defun-name): New function. (js--treesit-imenu-1): Extract into new function. (js-ts-mode): Setup treesit-defun-name-function. * lisp/progmodes/json-ts-mode.el (json-ts-mode--defun-name): New function. (json-ts-mode--imenu-1): Extract into new function. (json-ts-mode): Setup treesit-defun-name-function. * lisp/progmodes/python.el (python--treesit-defun-name): New function. (python--imenu-treesit-create-index-1): Extract into new function. (python-ts-mode): Setup treesit-defun-name-function. * lisp/progmodes/rust-ts-mode.el (rust-ts-mode--defun-name): New function. (rust-ts-mode--imenu-1): Extract into new function. (rust-ts-mode): Setup treesit-defun-name-function. * lisp/textmodes/css-mode.el (css--treesit-defun-name): New function. (css--treesit-imenu-1): Extract into new function. (css-ts-mode): Setup treesit-defun-name-function. * lisp/textmodes/toml-ts-mode.el (toml-ts-mode--get-table-name): Remove function. (toml-ts-mode--defun-name): New function. (toml-ts-mode--imenu-1): Extract into new function. (toml-ts-mode): Setup treesit-defun-name-function. --- lisp/progmodes/csharp-mode.el | 22 +++++++++++--- lisp/progmodes/java-ts-mode.el | 22 +++++++++++--- lisp/progmodes/js.el | 42 ++++++++++---------------- lisp/progmodes/json-ts-mode.el | 17 ++++++++--- lisp/progmodes/python.el | 17 +++++++++-- lisp/progmodes/rust-ts-mode.el | 55 ++++++++++++++++++---------------- lisp/textmodes/css-mode.el | 25 ++++++++++------ lisp/textmodes/toml-ts-mode.el | 16 +++++----- 8 files changed, 133 insertions(+), 83 deletions(-) diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el index 2d13ae6930c..985e2e7b0bf 100644 --- a/lisp/progmodes/csharp-mode.el +++ b/lisp/progmodes/csharp-mode.el @@ -837,6 +837,22 @@ compilation and evaluation time conflicts." ;;;###autoload (add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode)) +(defun csharp-ts-mode--defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + (pcase (treesit-node-type node) + ((or "method_declaration" + "record_declaration" + "struct_declaration" + "enum_declaration" + "interface_declaration" + "class_declaration" + "class_declaration") + (treesit-node-text + (treesit-node-child-by-field-name + node "name") + t)))) + (defun csharp-ts-mode--imenu-1 (node) "Helper for `csharp-ts-mode--imenu'. Find string representation for NODE and set marker, then recurse @@ -844,10 +860,7 @@ the subtrees." (let* ((ts-node (car node)) (subtrees (mapcan #'csharp-ts-mode--imenu-1 (cdr node))) (name (when ts-node - (or (treesit-node-text - (or (treesit-node-child-by-field-name - ts-node "name")) - t) + (or (treesit-defun-name ts-node) "Unnamed node"))) (marker (when ts-node (set-marker (make-marker) @@ -935,6 +948,7 @@ Key bindings: ;; Navigation. (setq-local treesit-defun-type-regexp "declaration") + (setq-local treesit-defun-name-function #'csharp-ts-mode--defun-name) ;; Font-lock. (setq-local treesit-font-lock-settings csharp-ts-mode--font-lock-settings) diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index 9da2c254f87..3e0439ddf54 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -248,6 +248,22 @@ '((["," ":" ";"]) @font-lock-delimiter-face)) "Tree-sitter font-lock settings for `java-ts-mode'.") +(defun java-ts-mode--defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + (pcase (treesit-node-type node) + ((or "method_declaration" + "class_declaration" + "record_declaration" + "interface_declaration" + "enum_declaration" + "import_declaration" + "package_declaration" + "module_declaration") + (treesit-node-text + (treesit-node-child-by-field-name node "name") + t)))) + (defun java-ts-mode--imenu-1 (node) "Helper for `java-ts-mode--imenu'. Find string representation for NODE and set marker, then recurse @@ -255,10 +271,7 @@ the subtrees." (let* ((ts-node (car node)) (subtrees (mapcan #'java-ts-mode--imenu-1 (cdr node))) (name (when ts-node - (or (treesit-node-text - (or (treesit-node-child-by-field-name - ts-node "name")) - t) + (or (treesit-defun-name ts-node) "Unnamed node"))) (marker (when ts-node (set-marker (make-marker) @@ -334,6 +347,7 @@ the subtrees." "import_declaration" "package_declaration" "module_declaration"))) + (setq-local treesit-defun-name-function #'java-ts-mode--defun-name) ;; Font-lock. (setq-local treesit-font-lock-settings java-ts-mode--font-lock-settings) diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 1b34c0de418..14feed221fb 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3656,24 +3656,18 @@ OVERRIDE is the override flag described in (setq font-beg (treesit-node-end child) child (treesit-node-next-sibling child))))) -(defun js-treesit-current-defun () - "Return name of surrounding function. -This function can be used as a value in `which-func-functions'" - (let ((node (treesit-node-at (point))) - (name-list ())) - (cl-loop while node - if (pcase (treesit-node-type node) - ("function_declaration" t) - ("method_definition" t) - ("class_declaration" t) - ("variable_declarator" t) - (_ nil)) - do (push (treesit-node-text - (treesit-node-child-by-field-name node "name") - t) - name-list) - do (setq node (treesit-node-parent node)) - finally return (string-join name-list ".")))) +(defun js--treesit-defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + (treesit-node-text + (treesit-node-child-by-field-name + (pcase (treesit-node-type node) + ("lexical_declaration" + (treesit-search-subtree node "variable_declarator" nil nil 1)) + ((or "function_declaration" "method_definition" "class_declaration") + node)) + "name") + t)) (defun js--treesit-imenu-1 (node) "Given a sparse tree, create an imenu alist. @@ -3702,15 +3696,8 @@ definition*\"." ("function_declaration" 'function))) ;; The root of the tree could have a nil ts-node. (name (when ts-node - (let ((ts-node-1 - (if (eq type 'variable) - (treesit-search-subtree - ts-node "variable_declarator" nil nil 1) - ts-node))) - (treesit-node-text - (treesit-node-child-by-field-name - ts-node-1 "name") - t)))) + (or (treesit-defun-name ts-node) + "Anonymous"))) (marker (when ts-node (set-marker (make-marker) (treesit-node-start ts-node))))) @@ -3885,6 +3872,7 @@ Currently there are `js-mode' and `js-ts-mode'." "method_definition" "function_declaration" "lexical_declaration"))) + (setq-local treesit-defun-name-function #'js--treesit-defun-name) ;; Fontification. (setq-local treesit-font-lock-settings js--treesit-font-lock-settings) (setq-local treesit-font-lock-feature-list diff --git a/lisp/progmodes/json-ts-mode.el b/lisp/progmodes/json-ts-mode.el index 6c2f3805872..6725c5f2270 100644 --- a/lisp/progmodes/json-ts-mode.el +++ b/lisp/progmodes/json-ts-mode.el @@ -107,6 +107,16 @@ '((ERROR) @font-lock-warning-face)) "Font-lock settings for JSON.") +(defun json-ts-mode--defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + (pcase (treesit-node-type node) + ((or "pair" "object") + (treesit-node-text + (treesit-node-child-by-field-name + node "key") + t)))) + (defun json-ts-mode--imenu-1 (node) "Helper for `json-ts-mode--imenu'. Find string representation for NODE and set marker, then recurse @@ -114,10 +124,8 @@ the subtrees." (let* ((ts-node (car node)) (subtrees (mapcan #'json-ts-mode--imenu-1 (cdr node))) (name (when ts-node - (treesit-node-text - (treesit-node-child-by-field-name - ts-node "key") - t))) + (or (treesit-defun-name ts-node) + "Anonymous"))) (marker (when ts-node (set-marker (make-marker) (treesit-node-start ts-node))))) @@ -161,6 +169,7 @@ the subtrees." ;; Navigation. (setq-local treesit-defun-type-regexp (rx (or "pair" "object"))) + (setq-local treesit-defun-name-function #'json-ts-mode--defun-name) ;; Font-lock. (setq-local treesit-font-lock-settings json-ts-mode--font-lock-settings) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index bdc9e6fa78c..d383fa57c04 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -5448,6 +5448,16 @@ To this: ;;; Tree-sitter imenu +(defun python--treesit-defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + (pcase (treesit-node-type node) + ((or "function_definition" "class_definition") + (treesit-node-text + (treesit-node-child-by-field-name + node "name") + t)))) + (defun python--imenu-treesit-create-index-1 (node) "Given a sparse tree, create an imenu alist. @@ -5473,9 +5483,8 @@ definition*\"." ("class_definition" 'class))) ;; The root of the tree could have a nil ts-node. (name (when ts-node - (treesit-node-text - (treesit-node-child-by-field-name - ts-node "name") t))) + (or (treesit-defun-name ts-node) + "Anonymous"))) (marker (when ts-node (set-marker (make-marker) (treesit-node-start ts-node))))) @@ -6643,6 +6652,8 @@ implementations: `python-mode' and `python-ts-mode'." #'python-imenu-treesit-create-index) (setq-local treesit-defun-type-regexp (rx (or "function" "class") "_definition")) + (setq-local treesit-defun-name-function + #'python--treesit-defun-name) (treesit-major-mode-setup) (when python-indent-guess-indent-offset diff --git a/lisp/progmodes/rust-ts-mode.el b/lisp/progmodes/rust-ts-mode.el index 8b2ed191019..81f5b8765f1 100644 --- a/lisp/progmodes/rust-ts-mode.el +++ b/lisp/progmodes/rust-ts-mode.el @@ -273,6 +273,33 @@ (when struct-index `(("Struct" . ,struct-index))) (when func-index `(("Fn" . ,func-index)))))) +(defun rust-ts-mode--defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + (pcase (treesit-node-type node) + ("enum_item" + (treesit-node-text + (treesit-node-child-by-field-name node "name") t)) + ("function_item" + (treesit-node-text + (treesit-node-child-by-field-name node "name") t)) + ("impl_item" + (let ((trait-node (treesit-node-child-by-field-name node "trait"))) + (concat + (treesit-node-text trait-node t) + (when trait-node " for ") + (treesit-node-text + (treesit-node-child-by-field-name node "type") t)))) + ("mod_item" + (treesit-node-text + (treesit-node-child-by-field-name node "name") t)) + ("struct_item" + (treesit-node-text + (treesit-node-child-by-field-name node "name") t)) + ("type_item" + (treesit-node-text + (treesit-node-child-by-field-name node "name") t)))) + (defun rust-ts-mode--imenu-1 (node) "Helper for `rust-ts-mode--imenu'. Find string representation for NODE and set marker, then recurse @@ -282,31 +309,8 @@ the subtrees." (subtrees (mapcan #'rust-ts-mode--imenu-1 children)) (name (when ts-node - (pcase (treesit-node-type ts-node) - ("enum_item" - (treesit-node-text - (treesit-node-child-by-field-name ts-node "name") t)) - ("function_item" - (treesit-node-text - (treesit-node-child-by-field-name ts-node "name") t)) - ("impl_item" - (let ((trait-node (treesit-node-child-by-field-name ts-node "trait"))) - (concat - (treesit-node-text - trait-node t) - (when trait-node - " for ") - (treesit-node-text - (treesit-node-child-by-field-name ts-node "type") t)))) - ("mod_item" - (treesit-node-text - (treesit-node-child-by-field-name ts-node "name") t)) - ("struct_item" - (treesit-node-text - (treesit-node-child-by-field-name ts-node "name") t)) - ("type_item" - (treesit-node-text - (treesit-node-child-by-field-name ts-node "name") t))))) + (or (treesit-defun-name ts-node) + "Anonymous"))) (marker (when ts-node (set-marker (make-marker) (treesit-node-start ts-node))))) @@ -363,6 +367,7 @@ the subtrees." "function_item" "impl_item" "struct_item"))) + (setq-local treesit-defun-name-function #'rust-ts-mode--defun-name) (treesit-major-mode-setup))) diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el index 822097a86d8..99ef4f10a06 100644 --- a/lisp/textmodes/css-mode.el +++ b/lisp/textmodes/css-mode.el @@ -1412,6 +1412,19 @@ for determining whether point is within a selector." '((ERROR) @error)) "Tree-sitter font-lock settings for `css-ts-mode'.") +(defun css--treesit-defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + (pcase (treesit-node-type node) + ("rule_set" (treesit-node-text + (treesit-node-child node 0) t)) + ("media_statement" + (let ((block (treesit-node-child node -1))) + (string-trim + (buffer-substring-no-properties + (treesit-node-start node) + (treesit-node-start block))))))) + (defun css--treesit-imenu-1 (node) "Helper for `css--treesit-imenu'. Find string representation for NODE and set marker, then recurse @@ -1419,15 +1432,8 @@ the subtrees." (let* ((ts-node (car node)) (subtrees (mapcan #'css--treesit-imenu-1 (cdr node))) (name (when ts-node - (pcase (treesit-node-type ts-node) - ("rule_set" (treesit-node-text - (treesit-node-child ts-node 0) t)) - ("media_statement" - (let ((block (treesit-node-child ts-node -1))) - (string-trim - (buffer-substring-no-properties - (treesit-node-start ts-node) - (treesit-node-start block)))))))) + (or (treesit-defun-name ts-node) + "Anonymous"))) (marker (when ts-node (set-marker (make-marker) (treesit-node-start ts-node))))) @@ -1835,6 +1841,7 @@ can also be used to fill comments. (treesit-parser-create 'css) (setq-local treesit-simple-indent-rules css--treesit-indent-rules) (setq-local treesit-defun-type-regexp "rule_set") + (setq-local treesit-defun-name-function #'css--treesit-defun-name) (setq-local treesit-font-lock-settings css--treesit-settings) (setq-local treesit-font-lock-feature-list '((selector comment query keyword) diff --git a/lisp/textmodes/toml-ts-mode.el b/lisp/textmodes/toml-ts-mode.el index bca6a5e81ad..790de2133e8 100644 --- a/lisp/textmodes/toml-ts-mode.el +++ b/lisp/textmodes/toml-ts-mode.el @@ -107,12 +107,12 @@ '((ERROR) @font-lock-warning-face)) "Font-lock settings for TOML.") -(defun toml-ts-mode--get-table-name (node) - "Obtains the header-name for the associated tree-sitter `NODE'." - (if node - (treesit-node-text - (car (cdr (treesit-node-children node)))) - "Root table")) +(defun toml-ts-mode--defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + (pcase (treesit-node-type node) + ((or "table" "table_array_element") + (car (cdr (treesit-node-children node)))))) (defun toml-ts-mode--imenu-1 (node) "Helper for `toml-ts-mode--imenu'. @@ -120,7 +120,8 @@ Find string representation for NODE and set marker, then recurse the subtrees." (let* ((ts-node (car node)) (subtrees (mapcan #'toml-ts-mode--imenu-1 (cdr node))) - (name (toml-ts-mode--get-table-name ts-node)) + (name (or (treesit-defun-name ts-node) + "Root table")) (marker (when ts-node (set-marker (make-marker) (treesit-node-start ts-node))))) @@ -167,6 +168,7 @@ the subtrees." ;; Navigation. (setq-local treesit-defun-type-regexp (rx (or "table" "table_array_element"))) + (setq-local treesit-defun-name-function #'toml-ts-mode--defun-name) ;; Font-lock. (setq-local treesit-font-lock-settings toml-ts-mode--font-lock-settings) -- 2.39.2