From a389c5d5b1e2e8fb36892e7ef1e6afadb9cf2a42 Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Wed, 5 Mar 2025 19:44:44 +0200 Subject: [PATCH] Improve treesit settings for typescript/tsx-ts-mode (bug#73404) * lisp/progmodes/typescript-ts-mode.el (typescript-ts-mode--font-lock-settings): Add @font-lock-type-face for 'internal_module' with 'identifier'. (typescript-ts-mode--defun-type-regexp): New variable with "internal_module" and "interface_declaration". (typescript-ts-mode--defun-name): New function that uses 'js--treesit-defun-name' and adds "internal_module" and "interface_declaration". (typescript-ts-mode--simple-imenu-settings): New variable like in 'js-ts-mode' with "Namespace" and "Interface" sections. (typescript-ts-mode--outline-predicate): New variable. (typescript-ts-base-mode): Set treesit-defun-type-regexp to typescript-ts-mode--defun-type-regexp, treesit-defun-name-function to typescript-ts-mode--defun-name, treesit-simple-imenu-settings to typescript-ts-mode--simple-imenu-settings, treesit-outline-predicate to typescript-ts-mode--outline-predicate. Use js--regexp-opt-symbol for treesit-thing-settings. (tsx-ts-mode): For 'sentence' thing use the same nodes as js--treesit-sentence-nodes. Use js--regexp-opt-symbol for treesit-thing-settings. * lisp/progmodes/js.el (js--treesit-sentence-nodes): Add "jsx_opening_element" and "jsx_closing_element" like in html. * lisp/progmodes/c-ts-mode.el (c-ts-mode--outline-predicate): Add outline headings for C++ "namespace_definition" and "class_specifier". (cherry picked from commit 68def672e61a5b25ec5bdee69493c09d79632ce2) --- lisp/progmodes/c-ts-mode.el | 4 +- lisp/progmodes/js.el | 14 ++-- lisp/progmodes/typescript-ts-mode.el | 106 +++++++++++++++++---------- 3 files changed, 78 insertions(+), 46 deletions(-) diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 499c2ad66d4..fa5f8567b60 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -1048,7 +1048,9 @@ Return nil if NODE is not a defun node or doesn't have a name." (treesit-parent-until node "function_definition")) ;; DEFUNs in Emacs sources. (and c-ts-mode-emacs-sources-support - (c-ts-mode--emacs-defun-p node)))) + (c-ts-mode--emacs-defun-p node)) + (member (treesit-node-type node) '("namespace_definition" + "class_specifier")))) ;;; Defun navigation diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 4346e0fd3a9..abe7e15b9c7 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3863,7 +3863,9 @@ Currently there are `js-mode' and `js-ts-mode'." "labeled_statement" "variable_declaration" "lexical_declaration" - "jsx_attribute") + "jsx_opening_element" + "jsx_attribute" + "jsx_closing_element") "Nodes that designate sentences in JavaScript. See `treesit-thing-settings' for more information.") @@ -3955,10 +3957,10 @@ See `treesit-thing-settings' for more information.") (defvar js-ts-mode--outline-predicate `(or (and "\\`class\\'" named) - ,(rx bos (or"class_declaration" - "method_definition" - "function_declaration" - "function_expression") + ,(rx bos (or "class_declaration" + "method_definition" + "function_declaration" + "function_expression") eos))) (defvar js--treesit-defun-type-regexp @@ -4004,9 +4006,7 @@ See `treesit-thing-settings' for more information.") (setq-local treesit-simple-indent-rules js--treesit-indent-rules) ;; Navigation. (setq-local treesit-defun-type-regexp js--treesit-defun-type-regexp) - (setq-local treesit-defun-name-function #'js--treesit-defun-name) - (setq-local treesit-thing-settings js--treesit-thing-settings) ;; Fontification. diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 0a3b91d12c1..ece8eebd028 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -317,6 +317,8 @@ Argument LANGUAGE is either `typescript' or `tsx'." object: (identifier) @font-lock-type-face property: (property_identifier) @font-lock-type-face)) + (internal_module (identifier) @font-lock-type-face) + (arrow_function parameter: (identifier) @font-lock-variable-name-face) @@ -509,6 +511,49 @@ See `treesit-thing-settings' for more information.") "Nodes that designate lists in TypeScript. See `treesit-thing-settings' for more information.") +(defvar typescript-ts-mode--defun-type-regexp + (rx bos (or "internal_module" + "interface_declaration" + "class_declaration" + "method_definition" + "function_declaration" + "lexical_declaration") + eos) + "Settings for `treesit-defun-type-regexp'.") + +(defun typescript-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." + (or (js--treesit-defun-name node) + (treesit-node-text + (pcase (treesit-node-type node) + ("internal_module" + (treesit-node-child node 1)) + ("interface_declaration" + (treesit-node-child-by-field-name node "name"))) + t))) + +(defvar typescript-ts-mode--simple-imenu-settings + `(("Namespace" "\\`internal_module\\'" nil nil) + ("Interface" "\\`interface_declaration\\'" nil nil) + ("Class" "\\`class_declaration\\'" nil nil) + ("Method" "\\`method_definition\\'" nil nil) + ("Function" "\\`function_declaration\\'" nil nil) + ("Variable" ,(rx bos (or "lexical_declaration" + "variable_declaration") + eos) + ,#'js--treesit-valid-imenu-entry nil)) + "Settings for `treesit-simple-imenu'.") + +(defvar typescript-ts-mode--outline-predicate + (rx bos (or "internal_module" + "interface_declaration" + "class_declaration" + "method_definition" + "function_declaration" + "function_expression") + eos)) + ;;;###autoload (define-derived-mode typescript-ts-base-mode prog-mode "TypeScript" "Generic major mode for editing TypeScript. @@ -524,33 +569,21 @@ This mode is intended to be inherited by concrete major modes." (setq-local electric-indent-chars (append "{}():;,<>/" electric-indent-chars)) ;; Navigation. - (setq-local treesit-defun-type-regexp - (regexp-opt '("class_declaration" - "method_definition" - "function_declaration" - "lexical_declaration"))) - (setq-local treesit-defun-name-function #'js--treesit-defun-name) + (setq-local treesit-defun-type-regexp typescript-ts-mode--defun-type-regexp) + (setq-local treesit-defun-name-function #'typescript-ts-mode--defun-name) (setq-local treesit-thing-settings `((typescript - (sexp ,(regexp-opt typescript-ts-mode--sexp-nodes 'symbols)) - (list ,(regexp-opt typescript-ts-mode--list-nodes - 'symbols)) - (sentence ,(regexp-opt - typescript-ts-mode--sentence-nodes 'symbols)) - (text ,(regexp-opt '("comment" - "template_string") - 'symbols))))) - - ;; Imenu (same as in `js-ts-mode'). + (sexp ,(js--regexp-opt-symbol typescript-ts-mode--sexp-nodes)) + (list ,(js--regexp-opt-symbol typescript-ts-mode--list-nodes)) + (sentence ,(js--regexp-opt-symbol typescript-ts-mode--sentence-nodes)) + (text ,(js--regexp-opt-symbol '("comment" "template_string")))))) + + ;; Imenu (same as in `js-ts-mode') + namespace/interface. (setq-local treesit-simple-imenu-settings - `(("Function" "\\`function_declaration\\'" nil nil) - ("Variable" "\\`lexical_declaration\\'" - js--treesit-valid-imenu-entry nil) - ("Class" ,(rx bos (or "class_declaration" - "method_definition") - eos) - nil nil)))) + typescript-ts-mode--simple-imenu-settings) + ;; Outline minor mode + (setq-local treesit-outline-predicate typescript-ts-mode--outline-predicate)) ;;;###autoload (define-derived-mode typescript-ts-mode typescript-ts-base-mode "TypeScript" @@ -616,24 +649,21 @@ at least 3 (which is the default value)." (setq-local treesit-thing-settings `((tsx - (sexp ,(regexp-opt + (sexp ,(js--regexp-opt-symbol (append typescript-ts-mode--sexp-nodes '("jsx")))) - (list ,(concat "^" - (regexp-opt - (append typescript-ts-mode--list-nodes - '( - "jsx_element" - "jsx_self_closing_element" - "jsx_expression"))) - "$")) - (sentence ,(regexp-opt + (list ,(js--regexp-opt-symbol + (append typescript-ts-mode--list-nodes + '("jsx_element" + "jsx_self_closing_element" + "jsx_expression")))) + (sentence ,(js--regexp-opt-symbol (append typescript-ts-mode--sentence-nodes - '("jsx_element" - "jsx_self_closing_element")))) - (text ,(regexp-opt '("comment" - "template_string")) - 'symbols)))) + '("jsx_opening_element" + "jsx_attribute" + "jsx_closing_element")))) + (text ,(js--regexp-opt-symbol '("comment" + "template_string")))))) ;; Font-lock. (setq-local treesit-font-lock-settings -- 2.39.5