summaryrefslogtreecommitdiff
path: root/lisp/progmodes
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes')
-rw-r--r--lisp/progmodes/c-ts-mode.el435
-rw-r--r--lisp/progmodes/cc-engine.el2
-rw-r--r--lisp/progmodes/csharp-mode.el91
-rw-r--r--lisp/progmodes/eglot.el9
-rw-r--r--lisp/progmodes/idlw-help.el2
-rw-r--r--lisp/progmodes/java-ts-mode.el86
-rw-r--r--lisp/progmodes/js.el252
-rw-r--r--lisp/progmodes/json-ts-mode.el43
-rw-r--r--lisp/progmodes/prog-mode.el6
-rw-r--r--lisp/progmodes/project.el4
-rw-r--r--lisp/progmodes/python.el62
-rw-r--r--lisp/progmodes/ruby-mode.el30
-rw-r--r--lisp/progmodes/rust-ts-mode.el122
-rw-r--r--lisp/progmodes/scheme.el20
-rw-r--r--lisp/progmodes/sh-script.el2
-rw-r--r--lisp/progmodes/typescript-ts-mode.el32
16 files changed, 604 insertions, 594 deletions
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index cf941236f82..50b951888ae 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -39,6 +39,8 @@
(declare-function treesit-node-child-by-field-name "treesit.c")
(declare-function treesit-node-type "treesit.c")
+;;; Custom variables
+
(defcustom c-ts-mode-indent-offset 2
"Number of spaces for each indentation step in `c-ts-mode'."
:version "29.1"
@@ -61,6 +63,8 @@ follows the form of `treesit-simple-indent-rules'."
(function :tag "A function for user customized style" ignore))
:group 'c)
+;;; Syntax table
+
(defvar c-ts-mode--syntax-table
(let ((table (make-syntax-table)))
;; Taken from the cc-langs version
@@ -83,13 +87,29 @@ follows the form of `treesit-simple-indent-rules'."
table)
"Syntax table for `c-ts-mode'.")
-(defvar c++-ts-mode--syntax-table
- (let ((table (make-syntax-table c-ts-mode--syntax-table)))
- ;; Template delimiters.
- (modify-syntax-entry ?< "(" table)
- (modify-syntax-entry ?> ")" table)
- table)
- "Syntax table for `c++-ts-mode'.")
+(defun c-ts-mode--syntax-propertize (beg end)
+ "Apply syntax text property to template delimiters between BEG and END.
+
+< and > are usually punctuation, e.g., in ->. But when used for
+templates, they should be considered pairs.
+
+This function checks for < and > in the changed RANGES and apply
+appropriate text property to alter the syntax of template
+delimiters < and >'s."
+ (goto-char beg)
+ (while (re-search-forward (rx (or "<" ">")) end t)
+ (pcase (treesit-node-type
+ (treesit-node-parent
+ (treesit-node-at (match-beginning 0))))
+ ("template_argument_list"
+ (put-text-property (match-beginning 0)
+ (match-end 0)
+ 'syntax-table
+ (pcase (char-before)
+ (?< '(4 . ?>))
+ (?> '(5 . ?<))))))))
+
+;;; Indent
(defun c-ts-mode--indent-styles (mode)
"Indent rules supported by `c-ts-mode'.
@@ -98,11 +118,13 @@ MODE is either `c' or `cpp'."
`(((parent-is "translation_unit") parent-bol 0)
((node-is ")") parent 1)
((node-is "]") parent-bol 0)
- ((node-is "}") (and parent parent-bol) 0)
+ ((node-is "}") c-ts-mode--bracket-children-anchor 0)
((node-is "else") parent-bol 0)
((node-is "case") parent-bol 0)
((node-is "preproc_arg") no-indent)
- ((and (parent-is "comment") comment-end) comment-start -1)
+ ((and (parent-is "comment") c-ts-mode--looking-at-star)
+ c-ts-mode--comment-start-after-first-star -1)
+ ((parent-is "comment") prev-adaptive-prefix 0)
((node-is "labeled_statement") parent-bol 0)
((parent-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
((match "preproc_ifdef" "compound_statement") point-min 0)
@@ -111,7 +133,8 @@ MODE is either `c' or `cpp'."
((match "#endif" "preproc_if") point-min 0)
((match "preproc_function_def" "compound_statement") point-min 0)
((match "preproc_call" "compound_statement") point-min 0)
- ((parent-is "compound_statement") (and parent parent-bol) c-ts-mode-indent-offset)
+ ((parent-is "compound_statement")
+ c-ts-mode--bracket-children-anchor c-ts-mode-indent-offset)
((parent-is "function_definition") parent-bol 0)
((parent-is "conditional_expression") first-sibling 0)
((parent-is "assignment_expression") parent-bol c-ts-mode-indent-offset)
@@ -167,6 +190,39 @@ MODE is either `c' or `cpp'."
('linux (alist-get 'linux (c-ts-mode--indent-styles mode)))))))
`((,mode ,@style))))
+(defun c-ts-mode--bracket-children-anchor (_n parent &rest _)
+ "This anchor is used for children of a compound_statement.
+So anything inside a {} block. PARENT should be the
+compound_statement. This anchor looks at the {, if itson its own
+line, anchor at it, if it has stuff before it, anchor at the
+beginning of grandparent."
+ (save-excursion
+ (goto-char (treesit-node-start parent))
+ (let ((bol (line-beginning-position)))
+ (skip-chars-backward " \t")
+ (treesit-node-start
+ (if (< bol (point))
+ (treesit-node-parent parent)
+ parent)))))
+
+(defun c-ts-mode--looking-at-star (&rest _)
+ "A tree-sitter simple indent matcher.
+Matches if there is a \"*\" after point (ignoring whitespace in
+between)."
+ (looking-at (rx (* (syntax whitespace)) "*")))
+
+(defun c-ts-mode--comment-start-after-first-star (_n parent &rest _)
+ "A tree-sitter simple indent anchor.
+Finds the \"/*\" and returns the point after the \"*\".
+Assumes PARENT is a comment node."
+ (save-excursion
+ (goto-char (treesit-node-start parent))
+ (if (looking-at (rx "/*"))
+ (match-end 0)
+ (point))))
+
+;;; Font-lock
+
(defvar c-ts-mode--preproc-keywords
'("#define" "#if" "#ifdef" "#ifndef"
"#else" "#elif" "#endif" "#include")
@@ -361,28 +417,34 @@ MODE is either `c' or `cpp'."
@c-ts-mode--fontify-defun)
(:match "^DEFUN$" @fn)))))
-(defun c-ts-mode--fontify-declarator (node override start end &rest args)
- "Fontify a declarator (whatever under the \"declarator\" field).
-For NODE, OVERRIDE, START, END, and ARGS, see
-`treesit-font-lock-rules'."
+;;; Font-lock helpers
+
+(defun c-ts-mode--declarator-identifier (node)
+ "Return the identifier of the declarator node NODE."
(pcase (treesit-node-type node)
+ ;; Recurse.
((or "attributed_declarator" "parenthesized_declarator")
- (apply #'c-ts-mode--fontify-declarator
- (treesit-node-child node 0 t) override start end args))
+ (c-ts-mode--declarator-identifier (treesit-node-child node 0 t)))
("pointer_declarator"
- (apply #'c-ts-mode--fontify-declarator
- (treesit-node-child node -1) override start end args))
+ (c-ts-mode--declarator-identifier (treesit-node-child node -1)))
((or "function_declarator" "array_declarator" "init_declarator")
- (apply #'c-ts-mode--fontify-declarator
- (treesit-node-child-by-field-name node "declarator")
- override start end args))
+ (c-ts-mode--declarator-identifier
+ (treesit-node-child-by-field-name node "declarator")))
+ ;; Terminal case.
((or "identifier" "field_identifier")
- (treesit-fontify-with-override
- (treesit-node-start node) (treesit-node-end node)
- (pcase (treesit-node-type (treesit-node-parent node))
- ("function_declarator" 'font-lock-function-name-face)
- (_ 'font-lock-variable-name-face))
- override start end))))
+ node)))
+
+(defun c-ts-mode--fontify-declarator (node override start end &rest _args)
+ "Fontify a declarator (whatever under the \"declarator\" field).
+For NODE, OVERRIDE, START, END, and ARGS, see
+`treesit-font-lock-rules'."
+ (let* ((identifier (c-ts-mode--declarator-identifier node))
+ (face (pcase (treesit-node-type (treesit-node-parent identifier))
+ ("function_declarator" 'font-lock-function-name-face)
+ (_ 'font-lock-variable-name-face))))
+ (treesit-fontify-with-override
+ (treesit-node-start identifier) (treesit-node-end identifier)
+ face override start end)))
(defun c-ts-mode--fontify-variable (node override start end &rest _)
"Fontify an identifier node if it is a variable.
@@ -453,94 +515,48 @@ For NODE, OVERRIDE, START, and END, see
(t 'font-lock-warning-face))
override start end)))
-(defun c-ts-mode--imenu-1 (node)
- "Helper for `c-ts-mode--imenu'.
-Find string representation for NODE and set marker, then recurse
-the subtrees."
- (let* ((ts-node (car node))
- (subtrees (mapcan #'c-ts-mode--imenu-1 (cdr node)))
- (name (when ts-node
- (treesit-node-text
- (pcase (treesit-node-type ts-node)
- ("function_definition"
- (treesit-node-child-by-field-name
- (treesit-node-child-by-field-name
- ts-node "declarator")
- "declarator"))
- ("declaration"
- (let ((child (treesit-node-child ts-node -1 t)))
- (pcase (treesit-node-type child)
- ("identifier" child)
- (_ (treesit-node-child-by-field-name
- child "declarator")))))
- ("struct_specifier"
- (treesit-node-child-by-field-name
- ts-node "name"))))))
- (marker (when ts-node
- (set-marker (make-marker)
- (treesit-node-start ts-node)))))
- (cond
- ;; A struct_specifier could be inside a parameter list, another
- ;; struct definition, a variable declaration, a function
- ;; declaration. In those cases we don't include it.
- ((string-match-p
- (rx (or "parameter_declaration" "field_declaration"
- "declaration" "function_definition"))
- (or (treesit-node-type (treesit-node-parent ts-node))
- ""))
- nil)
- ;; Ignore function local variable declarations.
- ((and (equal (treesit-node-type ts-node) "declaration")
- (not (equal (treesit-node-type (treesit-node-parent ts-node))
- "translation_unit")))
- nil)
- ((or (null ts-node) (null name)) subtrees)
- (subtrees
- `((,name ,(cons name marker) ,@subtrees)))
- (t
- `((,name . ,marker))))))
-
-(defun c-ts-mode--imenu ()
- "Return Imenu alist for the current buffer."
- (let* ((node (treesit-buffer-root-node))
- (func-tree (treesit-induce-sparse-tree
- node "^function_definition$" nil 1000))
- (var-tree (treesit-induce-sparse-tree
- node "^declaration$" nil 1000))
- (struct-tree (treesit-induce-sparse-tree
- node "^struct_specifier$" nil 1000))
- (func-index (c-ts-mode--imenu-1 func-tree))
- (var-index (c-ts-mode--imenu-1 var-tree))
- (struct-index (c-ts-mode--imenu-1 struct-tree)))
- (append
- (when struct-index `(("Struct" . ,struct-index)))
- (when var-index `(("Variable" . ,var-index)))
- (when func-index `(("Function" . ,func-index))))))
-
-(defun c-ts-mode--end-of-defun ()
- "`end-of-defun-function' of `c-ts-mode'."
- ;; A struct/enum/union_specifier node doesn't include the ; at the
- ;; end, so we manually skip it.
- (treesit-end-of-defun)
- (when (looking-at (rx (* " ") ";"))
- (goto-char (match-end 0))
- ;; This part is copied from `end-of-defun'.
- (unless (bolp)
- (skip-chars-forward " \t")
- (if (looking-at "\\s<\\|\n")
- (forward-line 1)))))
+;;; Imenu
+
+(defun c-ts-mode--defun-name (node)
+ "Return the name of the defun NODE.
+Return nil if NODE is not a defun node or doesn't have a name."
+ (treesit-node-text
+ (pcase (treesit-node-type node)
+ ((or "function_definition" "declaration")
+ (c-ts-mode--declarator-identifier
+ (treesit-node-child-by-field-name node "declarator")))
+ ((or "struct_specifier" "enum_specifier"
+ "union_specifier" "class_specifier")
+ (treesit-node-child-by-field-name node "name")))
+ t))
+
+;;; Defun navigation
(defun c-ts-mode--defun-valid-p (node)
- (if (string-match-p
- (rx (or "struct_specifier"
- "enum_specifier"
- "union_specifier"))
- (treesit-node-type node))
- (null
- (treesit-node-top-level
- node (rx (or "function_definition"
- "type_definition"))))
- t))
+ "Return non-nil if NODE is a valid defun node.
+Ie, NODE is not nested."
+ (not (or (and (member (treesit-node-type node)
+ '("struct_specifier"
+ "enum_specifier"
+ "union_specifier"
+ "declaration"))
+ ;; If NODE's type is one of the above, make sure it is
+ ;; top-level.
+ (treesit-node-top-level
+ node (rx (or "function_definition"
+ "type_definition"
+ "struct_specifier"
+ "enum_specifier"
+ "union_specifier"
+ "declaration"))))
+
+ (and (equal (treesit-node-type node) "declaration")
+ ;; If NODE is a declaration, make sure it is not a
+ ;; function declaration.
+ (equal (treesit-node-type
+ (treesit-node-child-by-field-name
+ node "declarator"))
+ "function_declarator")))))
(defun c-ts-mode--defun-skipper ()
"Custom defun skipper for `c-ts-mode' and friends.
@@ -556,15 +572,144 @@ the semicolon. This function skips the semicolon."
`treesit-defun-type-regexp' defines what constructs to indent."
(interactive "*")
- (let ((orig-point (point-marker)))
- ;; If `treesit-beginning-of-defun' returns nil, we are not in a
- ;; defun, so don't indent anything.
- (when (treesit-beginning-of-defun)
- (let ((start (point)))
- (treesit-end-of-defun)
- (indent-region start (point))))
+ (when-let ((orig-point (point-marker))
+ (node (treesit-defun-at-point)))
+ (indent-region (treesit-node-start node)
+ (treesit-node-end node))
(goto-char orig-point)))
+;;; Filling
+
+(defun c-ts-mode--fill-paragraph (&optional arg)
+ "Fillling function for `c-ts-mode'.
+ARG is passed to `fill-paragraph'."
+ (interactive "*P")
+ (save-restriction
+ (widen)
+ (let* ((node (treesit-node-at (point)))
+ (start (treesit-node-start node))
+ (end (treesit-node-end node))
+ ;; Bind to nil to avoid infinite recursion.
+ (fill-paragraph-function nil)
+ (orig-point (point-marker))
+ (start-marker nil)
+ (end-marker nil)
+ (end-len 0))
+ (when (equal (treesit-node-type node) "comment")
+ ;; We mask "/*" and the space before "*/" like
+ ;; `c-fill-paragraph' does.
+ (atomic-change-group
+ ;; Mask "/*".
+ (goto-char start)
+ (when (looking-at (rx (* (syntax whitespace))
+ (group "/") "*"))
+ (goto-char (match-beginning 1))
+ (setq start-marker (point-marker))
+ (replace-match " " nil nil nil 1))
+ ;; Include whitespaces before /*.
+ (goto-char start)
+ (beginning-of-line)
+ (setq start (point))
+ ;; Mask spaces before "*/" if it is attached at the end
+ ;; of a sentence rather than on its own line.
+ (goto-char end)
+ (when (looking-back (rx (not (syntax whitespace))
+ (group (+ (syntax whitespace)))
+ "*/")
+ (line-beginning-position))
+ (goto-char (match-beginning 1))
+ (setq end-marker (point-marker))
+ (setq end-len (- (match-end 1) (match-beginning 1)))
+ (replace-match (make-string end-len ?x)
+ nil nil nil 1))
+ ;; If "*/" is on its own line, don't included it in the
+ ;; filling region.
+ (when (not end-marker)
+ (goto-char end)
+ (when (looking-back (rx "*/") 2)
+ (backward-char 2)
+ (skip-syntax-backward "-")
+ (setq end (point))))
+ ;; Let `fill-paragraph' do its thing.
+ (goto-char orig-point)
+ (narrow-to-region start end)
+ (funcall #'fill-paragraph arg)
+ ;; Unmask.
+ (when start-marker
+ (goto-char start-marker)
+ (delete-char 1)
+ (insert "/"))
+ (when end-marker
+ (goto-char end-marker)
+ (delete-region (point) (+ end-len (point)))
+ (insert (make-string end-len ?\s))))
+ (goto-char orig-point))
+ ;; Return t so `fill-paragraph' doesn't attempt to fill by
+ ;; itself.
+ t)))
+
+(defun c-ts-mode-comment-setup ()
+ "Set up local variables for C-like comment.
+
+Set up:
+ - `comment-start'
+ - `comment-end'
+ - `comment-start-skip'
+ - `comment-end-skip'
+ - `adaptive-fill-mode'
+ - `adaptive-fill-first-line-regexp'
+ - `paragraph-start'
+ - `paragraph-separate'
+ - `fill-paragraph-function'"
+ (setq-local comment-start "// ")
+ (setq-local comment-end "")
+ (setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
+ (seq "/" (+ "*")))
+ (* (syntax whitespace))))
+ (setq-local comment-end-skip
+ (rx (* (syntax whitespace))
+ (group (or (syntax comment-end)
+ (seq (+ "*") "/")))))
+ (setq-local adaptive-fill-mode t)
+ ;; This matches (1) empty spaces (the default), (2) "//", (3) "*",
+ ;; but do not match "/*", because we don't want to use "/*" as
+ ;; prefix when filling. (Actually, it doesn't matter, because
+ ;; `comment-start-skip' matches "/*" which will cause
+ ;; `fill-context-prefix' to use "/*" as a prefix for filling, that's
+ ;; why we mask the "/*" in `c-ts-mode--fill-paragraph'.)
+ (setq-local adaptive-fill-regexp
+ (concat (rx (* (syntax whitespace))
+ (group (or (seq "/" (+ "/")) (* "*"))))
+ adaptive-fill-regexp))
+ ;; Note the missing * comparing to `adaptive-fill-regexp'. The
+ ;; reason for its absence is a bit convoluted to explain. Suffice
+ ;; to say that without it, filling a single line paragraph that
+ ;; starts with /* doesn't insert * at the beginning of each
+ ;; following line, and filling a multi-line paragraph whose first
+ ;; two lines start with * does insert * at the beginning of each
+ ;; following line. If you know how does adaptive filling works, you
+ ;; know what I mean.
+ (setq-local adaptive-fill-first-line-regexp
+ (rx bos
+ (seq (* (syntax whitespace))
+ (group (seq "/" (+ "/")))
+ (* (syntax whitespace)))
+ eos))
+ ;; Same as `adaptive-fill-regexp'.
+ (setq-local paragraph-start
+ (rx (or (seq (* (syntax whitespace))
+ (group (or (seq "/" (+ "/")) (* "*")))
+ (* (syntax whitespace))
+ ;; Add this eol so that in
+ ;; `fill-context-prefix', `paragraph-start'
+ ;; doesn't match the prefix.
+ eol)
+ "\f")))
+ (setq-local paragraph-separate paragraph-start)
+ (setq-local fill-paragraph-function #'c-ts-mode--fill-paragraph))
+
+;;; Modes
+
(defvar-keymap c-ts-mode-map
:doc "Keymap for the C language with tree-sitter"
:parent prog-mode-map
@@ -587,6 +732,7 @@ the semicolon. This function skips the semicolon."
"class_specifier"))
#'c-ts-mode--defun-valid-p))
(setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper)
+ (setq-local treesit-defun-name-function #'c-ts-mode--defun-name)
;; Nodes like struct/enum/union_specifier can appear in
;; function_definitions, so we need to find the top-level node.
@@ -596,13 +742,25 @@ the semicolon. This function skips the semicolon."
(when (eq c-ts-mode-indent-style 'linux)
(setq-local indent-tabs-mode t))
+ ;; Comment
+ (c-ts-mode-comment-setup)
+
;; Electric
(setq-local electric-indent-chars
(append "{}():;," electric-indent-chars))
;; Imenu.
- (setq-local imenu-create-index-function #'c-ts-mode--imenu)
- (setq-local which-func-functions nil)
+ (setq-local treesit-simple-imenu-settings
+ (let ((pred #'c-ts-mode--defun-valid-p))
+ `(("Struct" ,(rx bos (or "struct" "enum" "union")
+ "_specifier" eos)
+ ,pred nil)
+ ("Variable" ,(rx bos "declaration" eos) ,pred nil)
+ ("Function" "\\`function_definition\\'" ,pred nil)
+ ("Class" ,(rx bos (or "class_specifier"
+ "function_definition")
+ eos)
+ ,pred nil))))
(setq-local treesit-font-lock-feature-list
'(( comment definition)
@@ -623,13 +781,6 @@ the semicolon. This function skips the semicolon."
;; Comments.
(setq-local comment-start "/* ")
(setq-local comment-end " */")
- (setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
- (seq "/" (+ "*")))
- (* (syntax whitespace))))
- (setq-local comment-end-skip
- (rx (* (syntax whitespace))
- (group (or (syntax comment-end)
- (seq (+ "*") "/")))))
(setq-local treesit-simple-indent-rules
(c-ts-mode--set-indent-style 'c))
@@ -637,37 +788,23 @@ the semicolon. This function skips the semicolon."
;; Font-lock.
(setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c))
- (treesit-major-mode-setup)
-
- ;; Override default value of end-of-defun-function set by
- ;; `treesit-major-mode-setup'.
- (setq-local end-of-defun-function #'c-ts-mode--end-of-defun))
+ (treesit-major-mode-setup))
;;;###autoload
(define-derived-mode c++-ts-mode c-ts-base-mode "C++"
"Major mode for editing C++, powered by tree-sitter."
:group 'c++
- :syntax-table c++-ts-mode--syntax-table
(unless (treesit-ready-p 'cpp)
(error "Tree-sitter for C++ isn't available"))
- ;; Comments.
- (setq-local comment-start "// ")
- (setq-local comment-end "")
- (setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
- (seq "/" (+ "*")))
- (* (syntax whitespace))))
- (setq-local comment-end-skip
- (rx (* (syntax whitespace))
- (group (or (syntax comment-end)
- (seq (+ "*") "/")))))
-
(setq-local treesit-text-type-regexp
(regexp-opt '("comment"
"raw_string_literal")))
(treesit-parser-create 'cpp)
+ (setq-local syntax-propertize-function
+ #'c-ts-mode--syntax-propertize)
(setq-local treesit-simple-indent-rules
(c-ts-mode--set-indent-style 'cpp))
@@ -675,11 +812,7 @@ the semicolon. This function skips the semicolon."
;; Font-lock.
(setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp))
- (treesit-major-mode-setup)
-
- ;; Override default value of end-of-defun-function set by
- ;; `treesit-major-mode-setup'.
- (setq-local end-of-defun-function #'c-ts-mode--end-of-defun))
+ (treesit-major-mode-setup))
(provide 'c-ts-mode)
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index edb873f5a62..2198f3115a5 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -7757,7 +7757,7 @@ multi-line strings (but not C++, for example)."
(1- (match-end 1)) ; 1- For the inserted ".
eoll))))
- ;; ...and clear `syntax-table' text propertes from the
+ ;; ...and clear `syntax-table' text properties from the
;; following raw strings.
(c-depropertize-ml-strings-in-region (point) (1+ eoll)))
;; Remove the temporary string delimiter.
diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el
index 9e8b22c6aba..33a5f7046f1 100644
--- a/lisp/progmodes/csharp-mode.el
+++ b/lisp/progmodes/csharp-mode.el
@@ -34,6 +34,7 @@
(require 'cc-mode)
(require 'cc-langs)
(require 'treesit)
+(require 'c-ts-mode) ; For comment indenting and filling.
(eval-when-compile
(require 'cc-fonts)
@@ -42,6 +43,7 @@
(declare-function treesit-parser-create "treesit.c")
(declare-function treesit-induce-sparse-tree "treesit.c")
(declare-function treesit-node-start "treesit.c")
+(declare-function treesit-node-type "treesit.c")
(declare-function treesit-node-child-by-field-name "treesit.c")
(defgroup csharp nil
@@ -632,6 +634,9 @@ compilation and evaluation time conflicts."
((node-is "}") parent-bol 0)
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
+ ((and (parent-is "comment") c-ts-mode--looking-at-star)
+ c-ts-mode--comment-start-after-first-star -1)
+ ((parent-is "comment") prev-adaptive-prefix 0)
((parent-is "namespace_declaration") parent-bol 0)
((parent-is "class_declaration") parent-bol 0)
((parent-is "constructor_declaration") parent-bol 0)
@@ -837,56 +842,21 @@ compilation and evaluation time conflicts."
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode))
-(defun csharp-ts-mode--imenu-1 (node)
- "Helper for `csharp-ts-mode--imenu'.
-Find string representation for NODE and set marker, then recurse
-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)
- "Unnamed node")))
- (marker (when ts-node
- (set-marker (make-marker)
- (treesit-node-start ts-node)))))
- (cond
- ((null ts-node) subtrees)
- (subtrees
- `((,name ,(cons name marker) ,@subtrees)))
- (t
- `((,name . ,marker))))))
-
-(defun csharp-ts-mode--imenu ()
- "Return Imenu alist for the current buffer."
- (let* ((node (treesit-buffer-root-node))
- (class-tree (treesit-induce-sparse-tree
- node "^class_declaration$" nil 1000))
- (interface-tree (treesit-induce-sparse-tree
- node "^interface_declaration$" nil 1000))
- (enum-tree (treesit-induce-sparse-tree
- node "^enum_declaration$" nil 1000))
- (struct-tree (treesit-induce-sparse-tree
- node "^struct_declaration$" nil 1000))
- (record-tree (treesit-induce-sparse-tree
- node "^record_declaration$" nil 1000))
- (method-tree (treesit-induce-sparse-tree
- node "^method_declaration$" nil 1000))
- (class-index (csharp-ts-mode--imenu-1 class-tree))
- (interface-index (csharp-ts-mode--imenu-1 interface-tree))
- (enum-index (csharp-ts-mode--imenu-1 enum-tree))
- (record-index (csharp-ts-mode--imenu-1 record-tree))
- (struct-index (csharp-ts-mode--imenu-1 struct-tree))
- (method-index (csharp-ts-mode--imenu-1 method-tree)))
- (append
- (when class-index `(("Class" . ,class-index)))
- (when interface-index `(("Interface" . ,interface-index)))
- (when enum-index `(("Enum" . ,enum-index)))
- (when record-index `(("Record" . ,record-index)))
- (when struct-index `(("Struct" . ,struct-index)))
- (when method-index `(("Method" . ,method-index))))))
+(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))))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode))
@@ -916,15 +886,7 @@ Key bindings:
(treesit-parser-create 'c-sharp)
;; Comments.
- (setq-local comment-start "// ")
- (setq-local comment-end "")
- (setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
- (seq "/" (+ "*")))
- (* (syntax whitespace))))
- (setq-local comment-end-skip
- (rx (* (syntax whitespace))
- (group (or (syntax comment-end)
- (seq (+ "*") "/")))))
+ (c-ts-mode-comment-setup)
(setq-local treesit-text-type-regexp
(regexp-opt '("comment"
@@ -940,6 +902,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)
@@ -950,8 +913,14 @@ Key bindings:
( bracket delimiter)))
;; Imenu.
- (setq-local imenu-create-index-function #'csharp-ts-mode--imenu)
- (setq-local which-func-functions nil) ;; Piggyback on imenu
+ (setq-local treesit-simple-imenu-settings
+ '(("Class" "\\`class_declaration\\'" nil nil)
+ ("Interface" "\\`interface_declaration\\'" nil nil)
+ ("Enum" "\\`enum_declaration\\'" nil nil)
+ ("Record" "\\`record_declaration\\'" nil nil)
+ ("Struct" "\\`struct_declaration\\'" nil nil)
+ ("Method" "\\`method_declaration\\'" nil nil)))
+
(treesit-major-mode-setup))
(provide 'csharp-mode)
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index ce4ca4f3d92..15cb1b6fad0 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -190,6 +190,7 @@ chosen (interactively or automatically)."
'("pylsp" "pyls" ("pyright-langserver" "--stdio") "jedi-language-server")))
((js-json-mode json-mode json-ts-mode)
. ,(eglot-alternatives '(("vscode-json-language-server" "--stdio")
+ ("vscode-json-languageserver" "--stdio")
("json-languageserver" "--stdio"))))
((js-mode js-ts-mode tsx-ts-mode typescript-ts-mode typescript-mode)
. ("typescript-language-server" "--stdio"))
@@ -907,6 +908,8 @@ PRESERVE-BUFFERS as in `eglot-shutdown', which see."
do (with-demoted-errors "[eglot] shutdown all: %s"
(cl-loop for s in ss do (eglot-shutdown s nil nil preserve-buffers)))))
+(defvar eglot--servers-by-xrefed-file (make-hash-table :test 'equal))
+
(defun eglot--on-shutdown (server)
"Called by jsonrpc.el when SERVER is already dead."
;; Turn off `eglot--managed-mode' where appropriate.
@@ -925,6 +928,9 @@ PRESERVE-BUFFERS as in `eglot-shutdown', which see."
(setf (gethash (eglot--project server) eglot--servers-by-project)
(delq server
(gethash (eglot--project server) eglot--servers-by-project)))
+ (maphash (lambda (f s)
+ (when (eq s server) (remhash f eglot--servers-by-xrefed-file)))
+ eglot--servers-by-xrefed-file)
(cond ((eglot--shutdown-requested server)
t)
((not (eglot--inhibit-autoreconnect server))
@@ -1056,9 +1062,6 @@ be guessed."
(put 'eglot-lsp-context 'variable-documentation
"Dynamically non-nil when searching for projects in LSP context.")
-(defvar eglot--servers-by-xrefed-file
- (make-hash-table :test 'equal :weakness 'value))
-
(defun eglot--current-project ()
"Return a project object for Eglot's LSP purposes.
This relies on `project-current' and thus on
diff --git a/lisp/progmodes/idlw-help.el b/lisp/progmodes/idlw-help.el
index a19abf77e5f..51afb7e4850 100644
--- a/lisp/progmodes/idlw-help.el
+++ b/lisp/progmodes/idlw-help.el
@@ -269,7 +269,7 @@ Scrolling: SPC DEL RET
Text Searches: Inside Topic: Use Emacs search functions
Exit: [q]uit or mouse button 3 will kill the frame
-When the hep text is a source file, the following commands are available
+When the help text is a source file, the following commands are available
Fontification: [F]ontify the buffer like source code
Jump: [h] to function doclib header
diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el
index bd6a8aa4743..215b5c16388 100644
--- a/lisp/progmodes/java-ts-mode.el
+++ b/lisp/progmodes/java-ts-mode.el
@@ -29,10 +29,12 @@
(require 'treesit)
(eval-when-compile (require 'rx))
+(require 'c-ts-mode) ; For comment indent and filling.
(declare-function treesit-parser-create "treesit.c")
(declare-function treesit-induce-sparse-tree "treesit.c")
(declare-function treesit-node-start "treesit.c")
+(declare-function treesit-node-type "treesit.c")
(declare-function treesit-node-child-by-field-name "treesit.c")
(defcustom java-ts-mode-indent-offset 4
@@ -71,8 +73,9 @@
((node-is "}") (and parent parent-bol) 0)
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
- ((and (parent-is "comment") comment-end) comment-start -1)
- ((parent-is "comment") comment-start-skip 0)
+ ((and (parent-is "comment") c-ts-mode--looking-at-star)
+ c-ts-mode--comment-start-after-first-star -1)
+ ((parent-is "comment") prev-adaptive-prefix 0)
((parent-is "text_block") no-indent)
((parent-is "class_body") parent-bol java-ts-mode-indent-offset)
((parent-is "interface_body") parent-bol java-ts-mode-indent-offset)
@@ -248,52 +251,21 @@
'((["," ":" ";"]) @font-lock-delimiter-face))
"Tree-sitter font-lock settings for `java-ts-mode'.")
-(defun java-ts-mode--imenu-1 (node)
- "Helper for `java-ts-mode--imenu'.
-Find string representation for NODE and set marker, then recurse
-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)
- "Unnamed node")))
- (marker (when ts-node
- (set-marker (make-marker)
- (treesit-node-start ts-node)))))
- (cond
- ((null ts-node) subtrees)
- (subtrees
- `((,name ,(cons name marker) ,@subtrees)))
- (t
- `((,name . ,marker))))))
-
-(defun java-ts-mode--imenu ()
- "Return Imenu alist for the current buffer."
- (let* ((node (treesit-buffer-root-node))
- (class-tree (treesit-induce-sparse-tree
- node "^class_declaration$" nil 1000))
- (interface-tree (treesit-induce-sparse-tree
- node "^interface_declaration$" nil 1000))
- (enum-tree (treesit-induce-sparse-tree
- node "^enum_declaration$" nil 1000))
- (record-tree (treesit-induce-sparse-tree
- node "^record_declaration$" nil 1000))
- (method-tree (treesit-induce-sparse-tree
- node "^method_declaration$" nil 1000))
- (class-index (java-ts-mode--imenu-1 class-tree))
- (interface-index (java-ts-mode--imenu-1 interface-tree))
- (enum-index (java-ts-mode--imenu-1 enum-tree))
- (record-index (java-ts-mode--imenu-1 record-tree))
- (method-index (java-ts-mode--imenu-1 method-tree)))
- (append
- (when class-index `(("Class" . ,class-index)))
- (when interface-index `(("Interface" . ,interface-index)))
- (when enum-index `(("Enum" . ,enum-index)))
- (when record-index `(("Record" . ,record-index)))
- (when method-index `(("Method" . ,method-index))))))
+(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))))
;;;###autoload
(define-derived-mode java-ts-mode prog-mode "Java"
@@ -307,15 +279,7 @@ the subtrees."
(treesit-parser-create 'java)
;; Comments.
- (setq-local comment-start "// ")
- (setq-local comment-end "")
- (setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
- (seq "/" (+ "*")))
- (* (syntax whitespace))))
- (setq-local comment-end-skip
- (rx (* (syntax whitespace))
- (group (or (syntax comment-end)
- (seq (+ "*") "/")))))
+ (c-ts-mode-comment-setup)
(setq-local treesit-text-type-regexp
(regexp-opt '("line_comment"
@@ -339,6 +303,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)
@@ -349,8 +314,11 @@ the subtrees."
( bracket delimiter operator)))
;; Imenu.
- (setq-local imenu-create-index-function #'java-ts-mode--imenu)
- (setq-local which-func-functions nil) ;; Piggyback on imenu
+ (setq-local treesit-simple-imenu-settings
+ '(("Class" "\\`class_declaration\\'" nil nil)
+ ("Interface" "\\`interface_declaration\\'" nil nil)
+ ("Enum" "\\`record_declaration\\'" nil nil)
+ ("Method" "\\`method_declaration\\'" nil nil)))
(treesit-major-mode-setup))
(provide 'java-ts-mode)
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index cbcca81baaa..9c26c52df94 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -54,6 +54,7 @@
(require 'json)
(require 'prog-mode)
(require 'treesit)
+(require 'c-ts-mode) ; For comment indent and filling.
(eval-when-compile
(require 'cl-lib)
@@ -73,6 +74,8 @@
(declare-function treesit-node-start "treesit.c")
(declare-function treesit-node-end "treesit.c")
(declare-function treesit-node-type "treesit.c")
+(declare-function treesit-query-compile "treesit.c")
+(declare-function treesit-query-capture "treesit.c")
;;; Constants
@@ -3425,9 +3428,9 @@ This function is intended for use in `after-change-functions'."
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
((node-is ">") parent-bol 0)
- ((parent-is "comment") comment-start 0)
- ((and (parent-is "comment") comment-end) comment-start -1)
- ((parent-is "comment") comment-start-skip 0)
+ ((and (parent-is "comment") c-ts-mode--looking-at-star)
+ c-ts-mode--comment-start-after-first-star -1)
+ ((parent-is "comment") prev-adaptive-prefix 0)
((parent-is "ternary_expression") parent-bol js-indent-level)
((parent-is "member_expression") parent-bol js-indent-level)
((node-is ,switch-case) parent-bol 0)
@@ -3478,36 +3481,35 @@ This function is intended for use in `after-change-functions'."
(treesit-font-lock-rules
:language 'javascript
- :override t
:feature 'comment
- `((comment) @font-lock-comment-face)
+ '((comment) @font-lock-comment-face)
:language 'javascript
- :override t
:feature 'constant
- `(((identifier) @font-lock-constant-face
+ '(((identifier) @font-lock-constant-face
(:match "^[A-Z_][A-Z_\\d]*$" @font-lock-constant-face))
[(true) (false) (null)] @font-lock-constant-face)
:language 'javascript
- :override t
:feature 'keyword
`([,@js--treesit-keywords] @font-lock-keyword-face
[(this) (super)] @font-lock-keyword-face)
:language 'javascript
- :override t
:feature 'string
- `((regex pattern: (regex_pattern)) @font-lock-string-face
- (string) @font-lock-string-face
- (template_string) @js--fontify-template-string
- (template_substitution ["${" "}"] @font-lock-builtin-face))
+ '((regex pattern: (regex_pattern)) @font-lock-string-face
+ (string) @font-lock-string-face)
:language 'javascript
+ :feature 'string-interpolation
:override t
- :feature 'declaration
- `((function
+ '((template_string) @js--fontify-template-string
+ (template_substitution ["${" "}"] @font-lock-delimiter-face))
+
+ :language 'javascript
+ :feature 'definition
+ '((function
name: (identifier) @font-lock-function-name-face)
(class_declaration
@@ -3534,24 +3536,10 @@ This function is intended for use in `after-change-functions'."
value: (array (number) (function))))
:language 'javascript
- :override t
- :feature 'identifier
- `((new_expression
- constructor: (identifier) @font-lock-type-face)
-
- (for_in_statement
- left: (identifier) @font-lock-variable-name-face)
-
- (arrow_function
- parameter: (identifier) @font-lock-variable-name-face))
-
- :language 'javascript
- :override t
:feature 'property
- ;; This needs to be before function-name feature, because methods
- ;; can be both property and function-name, and we want them in
- ;; function-name face.
- `((property_identifier) @font-lock-property-face
+ '(((property_identifier) @font-lock-property-face
+ (:pred js--treesit-property-not-function-p
+ @font-lock-property-face))
(pair value: (identifier) @font-lock-variable-name-face)
@@ -3560,36 +3548,27 @@ This function is intended for use in `after-change-functions'."
((shorthand_property_identifier_pattern) @font-lock-property-face))
:language 'javascript
- :override t
- :feature 'expression
- `((assignment_expression
- left: [(identifier) @font-lock-function-name-face
- (member_expression property: (property_identifier)
- @font-lock-function-name-face)]
- right: [(function) (arrow_function)])
-
- (call_expression
+ :feature 'assignment
+ '((assignment_expression
+ left: (_) @js--treesit-fontify-assignment-lhs))
+
+ :language 'javascript
+ :feature 'function
+ '((call_expression
function: [(identifier) @font-lock-function-name-face
(member_expression
property:
(property_identifier) @font-lock-function-name-face)])
-
- (assignment_expression
- left: [(identifier) @font-lock-variable-name-face
- (member_expression
- property: (property_identifier) @font-lock-variable-name-face)]))
-
- :language 'javascript
- :override t
- :feature 'pattern
- `((pair_pattern key: (property_identifier) @font-lock-variable-name-face)
- (array_pattern (identifier) @font-lock-variable-name-face))
+ (method_definition
+ name: (property_identifier) @font-lock-function-name-face)
+ (function_declaration
+ name: (identifier) @font-lock-function-name-face)
+ (function
+ name: (identifier) @font-lock-function-name-face))
:language 'javascript
- :override t
:feature 'jsx
- `(
- (jsx_opening_element
+ '((jsx_opening_element
[(nested_identifier (identifier)) (identifier)]
@font-lock-function-name-face)
@@ -3607,7 +3586,7 @@ This function is intended for use in `after-change-functions'."
:language 'javascript
:feature 'number
- `((number) @font-lock-number-face
+ '((number) @font-lock-number-face
((identifier) @font-lock-number-face
(:match "^\\(:?NaN\\|Infinity\\)$" @font-lock-number-face)))
@@ -3656,91 +3635,50 @@ 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-imenu-1 (node)
- "Given a sparse tree, create an imenu alist.
-
-NODE is the root node of the tree returned by
-`treesit-induce-sparse-tree' (not a tree-sitter node, its car is
-a tree-sitter node). Walk that tree and return an imenu alist.
-
-Return a list of ENTRY where
-
-ENTRY := (NAME . MARKER)
- | (NAME . ((JUMP-LABEL . MARKER)
- ENTRY
- ...)
-
-NAME is the function/class's name, JUMP-LABEL is like \"*function
-definition*\"."
- (let* ((ts-node (car node))
- (children (cdr node))
- (subtrees (mapcan #'js--treesit-imenu-1
- children))
- (type (pcase (treesit-node-type ts-node)
- ("lexical_declaration" 'variable)
- ("class_declaration" 'class)
- ("method_definition" 'method)
- ("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))))
- (marker (when ts-node
- (set-marker (make-marker)
- (treesit-node-start ts-node)))))
- (cond
- ((null ts-node)
- subtrees)
- ;; Don't included non-top-level variable declarations.
- ((and (eq type 'variable)
- (treesit-node-top-level ts-node))
- nil)
- (subtrees
- `((,name
- ,(cons "" marker)
- ,@subtrees)))
- (t (list (cons name marker))))))
-
-(defun js--treesit-imenu ()
- "Return Imenu alist for the current buffer."
- (let* ((node (treesit-buffer-root-node))
- (class-tree (treesit-induce-sparse-tree
- node (rx (or "class_declaration"
- "method_definition"))
- nil 1000))
- (func-tree (treesit-induce-sparse-tree
- node "function_declaration" nil 1000))
- (var-tree (treesit-induce-sparse-tree
- node "lexical_declaration" nil 1000)))
- `(("Class" . ,(js--treesit-imenu-1 class-tree))
- ("Variable" . ,(js--treesit-imenu-1 var-tree))
- ("Function" . ,(js--treesit-imenu-1 func-tree)))))
+(defun js--treesit-property-not-function-p (node)
+ "Check that NODE, a property_identifier, is not used as a function."
+ (not (equal (treesit-node-type
+ (treesit-node-parent ; Maybe call_expression.
+ (treesit-node-parent ; Maybe member_expression.
+ node)))
+ "call_expression")))
+
+(defvar js--treesit-lhs-identifier-query
+ (when (treesit-available-p)
+ (treesit-query-compile 'javascript '((identifier) @id
+ (property_identifier) @id)))
+ "Query that captures identifier and query_identifier.")
+
+(defun js--treesit-fontify-assignment-lhs (node override start end &rest _)
+ "Fontify the lhs NODE of an assignment_expression.
+For OVERRIDE, START, END, see `treesit-font-lock-rules'."
+ (dolist (node (treesit-query-capture
+ node js--treesit-lhs-identifier-query nil nil t))
+ (treesit-fontify-with-override
+ (treesit-node-start node) (treesit-node-end node)
+ (pcase (treesit-node-type node)
+ ("identifier" 'font-lock-variable-name-face)
+ ("property_identifier" 'font-lock-property-face))
+ override start end)))
+
+(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-valid-imenu-entry (node)
+ "Return nil if NODE is a non-top-level \"lexical_declaration\"."
+ (pcase (treesit-node-type node)
+ ("lexical_declaration" (treesit-node-top-level node))
+ (_ t)))
;;; Main Function
@@ -3853,15 +3791,7 @@ Currently there are `js-mode' and `js-ts-mode'."
;; Which-func.
(setq-local which-func-imenu-joiner-function #'js--which-func-joiner)
;; Comment.
- (setq-local comment-start "// ")
- (setq-local comment-end "")
- (setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
- (seq "/" (+ "*")))
- (* (syntax whitespace))))
- (setq-local comment-end-skip
- (rx (* (syntax whitespace))
- (group (or (syntax comment-end)
- (seq (+ "*") "/")))))
+ (c-ts-mode-comment-setup)
(setq-local comment-multi-line t)
(setq-local treesit-text-type-regexp
@@ -3885,19 +3815,25 @@ 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
- '(( comment declaration)
+ '(( comment definition)
( keyword string)
- ( constant escape-sequence expression
- identifier jsx number pattern property)
- ( bracket delimiter operator)))
+ ( assignment constant escape-sequence jsx number
+ pattern)
+ ( bracket delimiter function operator property
+ string-interpolation)))
;; Imenu
- (setq-local imenu-create-index-function
- #'js--treesit-imenu)
- ;; Which-func (use imenu).
- (setq-local which-func-functions nil)
+ (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)))
(treesit-major-mode-setup)))
;;;###autoload
diff --git a/lisp/progmodes/json-ts-mode.el b/lisp/progmodes/json-ts-mode.el
index 6c2f3805872..adba2f820fa 100644
--- a/lisp/progmodes/json-ts-mode.el
+++ b/lisp/progmodes/json-ts-mode.el
@@ -33,6 +33,7 @@
(declare-function treesit-parser-create "treesit.c")
(declare-function treesit-induce-sparse-tree "treesit.c")
(declare-function treesit-node-start "treesit.c")
+(declare-function treesit-node-type "treesit.c")
(declare-function treesit-node-child-by-field-name "treesit.c")
@@ -107,33 +108,16 @@
'((ERROR) @font-lock-warning-face))
"Font-lock settings for JSON.")
-(defun json-ts-mode--imenu-1 (node)
- "Helper for `json-ts-mode--imenu'.
-Find string representation for NODE and set marker, then recurse
-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)))
- (marker (when ts-node
- (set-marker (make-marker)
- (treesit-node-start ts-node)))))
- (cond
- ((null ts-node) subtrees)
- (subtrees
- `((,name ,(cons name marker) ,@subtrees)))
- (t
- `((,name . ,marker))))))
-
-(defun json-ts-mode--imenu ()
- "Return Imenu alist for the current buffer."
- (let* ((node (treesit-buffer-root-node))
- (tree (treesit-induce-sparse-tree
- node "pair" nil 1000)))
- (json-ts-mode--imenu-1 tree)))
+(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")
+ (string-trim (treesit-node-text
+ (treesit-node-child-by-field-name
+ node "key")
+ t)
+ "\"" "\""))))
;;;###autoload
(define-derived-mode json-ts-mode prog-mode "JSON"
@@ -161,6 +145,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)
@@ -170,8 +155,8 @@ the subtrees."
(bracket delimiter error)))
;; Imenu.
- (setq-local imenu-create-index-function #'json-ts-mode--imenu)
- (setq-local which-func-functions nil) ;; Piggyback on imenu
+ (setq-local treesit-simple-imenu-settings
+ '((nil "\\`pair\\'" nil nil)))
(treesit-major-mode-setup))
diff --git a/lisp/progmodes/prog-mode.el b/lisp/progmodes/prog-mode.el
index aa37a4ac865..2e0cb6cd25c 100644
--- a/lisp/progmodes/prog-mode.el
+++ b/lisp/progmodes/prog-mode.el
@@ -164,10 +164,8 @@ or follows point."
(treesit-node-type (treesit-node-at (point)))))))
(if (or treesit-text-node
(nth 8 (syntax-ppss))
- (re-search-forward comment-start-skip (line-end-position) t))
- (if (memq fill-paragraph-function '(t nil))
- (lisp-fill-paragraph argument)
- (funcall fill-paragraph-function argument))
+ (re-search-forward "\\s-*\\s<" (line-end-position) t))
+ (fill-paragraph argument (region-active-p))
(beginning-of-defun)
(let ((start (point)))
(end-of-defun)
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 559da6dd649..c2633798473 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1040,12 +1040,14 @@ by the user at will."
(setq substrings (cons "./" substrings))))
(new-collection (project--file-completion-table substrings))
(abbr-cpd (abbreviate-file-name common-parent-directory))
+ (abbr-cpd-length (length abbr-cpd))
(relname (cl-letf ((history-add-new-input nil)
((symbol-value hist)
(mapcan
(lambda (s)
(and (string-prefix-p abbr-cpd s)
- (list (substring s (length abbr-cpd)))))
+ (not (eq abbr-cpd-length (length s)))
+ (list (substring s abbr-cpd-length))))
(symbol-value hist))))
(project--completing-read-strict prompt
new-collection
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index bdc9e6fa78c..07f86d31551 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -1080,7 +1080,6 @@ fontified."
:feature 'string
:language 'python
- :override t
'((string) @python--treesit-fontify-string)
:feature 'string-interpolation
@@ -1097,9 +1096,7 @@ fontified."
:feature 'function
:language 'python
- '((function_definition
- name: (identifier) @font-lock-function-name-face)
- (call function: (identifier) @font-lock-function-name-face)
+ '((call function: (identifier) @font-lock-function-name-face)
(call function: (attribute
attribute: (identifier) @font-lock-function-name-face)))
@@ -1130,7 +1127,7 @@ fontified."
@font-lock-variable-name-face)
(assignment left: (attribute
attribute: (identifier)
- @font-lock-variable-name-face))
+ @font-lock-property-face))
(pattern_list (identifier)
@font-lock-variable-name-face)
(tuple_pattern (identifier)
@@ -1162,12 +1159,10 @@ fontified."
:feature 'number
:language 'python
- :override t
'([(integer) (float)] @font-lock-number-face)
:feature 'property
:language 'python
- :override t
'((attribute
attribute: (identifier) @font-lock-property-face)
(class_definition
@@ -1178,20 +1173,44 @@ fontified."
:feature 'operator
:language 'python
- :override t
`([,@python--treesit-operators] @font-lock-operator-face)
:feature 'bracket
:language 'python
- :override t
'(["(" ")" "[" "]" "{" "}"] @font-lock-bracket-face)
:feature 'delimiter
:language 'python
- :override t
- '(["," "." ":" ";" (ellipsis)] @font-lock-delimiter-face))
+ '(["," "." ":" ";" (ellipsis)] @font-lock-delimiter-face)
+
+ :feature 'variable
+ :language 'python
+ '((identifier) @python--treesit-fontify-variable))
"Tree-sitter font-lock settings.")
+(defun python--treesit-variable-p (node)
+ "Check whether NODE is a variable.
+NODE's type should be \"identifier\"."
+ ;; An identifier can be a function/class name, a property, or a
+ ;; variables. This funtion filters out function/class names and
+ ;; properties.
+ (pcase (treesit-node-type (treesit-node-parent node))
+ ((or "function_definition" "class_definition") nil)
+ ("attribute"
+ (pcase (treesit-node-field-name node)
+ ("object" t)
+ (_ nil)))
+ (_ t)))
+
+(defun python--treesit-fontify-variable (node override start end &rest _)
+ "Fontify an identifier node if it is a variable.
+For NODE, OVERRIDE, START, END, and ARGS, see
+`treesit-font-lock-rules'."
+ (when (python--treesit-variable-p node)
+ (treesit-fontify-with-override
+ (treesit-node-start node) (treesit-node-end node)
+ 'font-lock-variable-name-face override start end)))
+
;;; Indentation
@@ -4540,7 +4559,7 @@ Commands that must finish the tracking session are listed in
(when (and python-pdbtrack-tracked-buffer
;; Empty input is sent by C-d or `comint-send-eof'
(or (string-empty-p input)
- ;; "n some text" is "n" command for pdb. Split input and get firs part
+ ;; "n some text" is "n" command for pdb. Split input and get first part
(let* ((command (car (split-string (string-trim input) " "))))
(setq python-pdbtrack-prev-command-continue
(or (member command python-pdbtrack-continue-command)
@@ -5448,6 +5467,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 +5502,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)))))
@@ -6637,12 +6665,14 @@ implementations: `python-mode' and `python-ts-mode'."
( keyword string type)
( assignment builtin constant decorator
escape-sequence number property string-interpolation )
- ( function bracket delimiter operator)))
+ ( bracket delimiter function operator variable)))
(setq-local treesit-font-lock-settings python--treesit-settings)
(setq-local imenu-create-index-function
#'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/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index fa51597697f..a4aa61905e4 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -212,7 +212,7 @@ It should match the part after \"def\" and until \"=\".")
:safe 'booleanp)
(defcustom ruby-indent-level 2
- "Indentation of Ruby statements."
+ "Number of spaces for each indentation step in `ruby-mode'."
:type 'integer
:safe 'integerp)
@@ -268,6 +268,23 @@ Only has effect when `ruby-use-smie' is t."
:safe 'booleanp
:version "24.4")
+(defcustom ruby-method-params-indent t
+ "Indentation of multiline method parameters.
+
+When t, the parameters list is indented to the method name.
+
+When a number, indent the parameters list this many columns
+against the beginning of the method (the \"def\" keyword).
+
+The value nil means the same as 0.
+
+Only has effect when `ruby-use-smie' is t."
+ :type '(choice (const :tag "Indent to the method name" t)
+ (number :tag "Indent specified number of columns against def")
+ (const :tag "Indent to def" nil))
+ :safe (lambda (val) (or (memq val '(t nil)) (numberp val)))
+ :version "29.1")
+
(defcustom ruby-deep-arglist t
"Deep indent lists in parenthesis when non-nil.
Also ignores spaces after parenthesis when `space'.
@@ -660,9 +677,12 @@ This only affects the output of the command `ruby-toggle-block'."
(unless (or (eolp) (forward-comment 1))
(cons 'column (current-column)))))
('(:before . " @ ")
- (save-excursion
- (skip-chars-forward " \t")
- (cons 'column (current-column))))
+ (if (or (eq ruby-method-params-indent t)
+ (not (smie-rule-parent-p "def" "def=")))
+ (save-excursion
+ (skip-chars-forward " \t")
+ (cons 'column (current-column)))
+ (smie-rule-parent (or ruby-method-params-indent 0))))
('(:before . "do") (ruby-smie--indent-to-stmt))
('(:before . ".")
(if (smie-rule-sibling-p)
@@ -1879,7 +1899,7 @@ or `gem' statement around point."
(setq feature-name (read-string "Feature name: " init))))
(let ((out
(substring
- (shell-command-to-string (concat "gem which " feature-name))
+ (shell-command-to-string (concat "gem which " (shell-quote-argument feature-name)))
0 -1)))
(if (string-match-p "\\`ERROR" out)
(user-error "%s" out)
diff --git a/lisp/progmodes/rust-ts-mode.el b/lisp/progmodes/rust-ts-mode.el
index 8b2ed191019..d03dffe628e 100644
--- a/lisp/progmodes/rust-ts-mode.el
+++ b/lisp/progmodes/rust-ts-mode.el
@@ -29,6 +29,7 @@
(require 'treesit)
(eval-when-compile (require 'rx))
+(require 'c-ts-mode) ; For comment indent and filling.
(declare-function treesit-parser-create "treesit.c")
(declare-function treesit-induce-sparse-tree "treesit.c")
@@ -70,6 +71,9 @@
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
((node-is "}") (and parent parent-bol) 0)
+ ((and (parent-is "comment") c-ts-mode--looking-at-star)
+ c-ts-mode--comment-start-after-first-star -1)
+ ((parent-is "comment") prev-adaptive-prefix 0)
((parent-is "arguments") parent-bol rust-ts-mode-indent-offset)
((parent-is "await_expression") parent-bol rust-ts-mode-indent-offset)
((parent-is "array_expression") parent-bol rust-ts-mode-indent-offset)
@@ -244,78 +248,32 @@
'((ERROR) @font-lock-warning-face))
"Tree-sitter font-lock settings for `rust-ts-mode'.")
-(defun rust-ts-mode--imenu ()
- "Return Imenu alist for the current buffer."
- (let* ((node (treesit-buffer-root-node))
- (enum-tree (treesit-induce-sparse-tree
- node "enum_item" nil))
- (enum-index (rust-ts-mode--imenu-1 enum-tree))
- (func-tree (treesit-induce-sparse-tree
- node "function_item" nil))
- (func-index (rust-ts-mode--imenu-1 func-tree))
- (impl-tree (treesit-induce-sparse-tree
- node "impl_item" nil))
- (impl-index (rust-ts-mode--imenu-1 impl-tree))
- (mod-tree (treesit-induce-sparse-tree
- node "mod_item" nil))
- (mod-index (rust-ts-mode--imenu-1 mod-tree))
- (struct-tree (treesit-induce-sparse-tree
- node "struct_item" nil))
- (struct-index (rust-ts-mode--imenu-1 struct-tree))
- (type-tree (treesit-induce-sparse-tree
- node "type_item" nil))
- (type-index (rust-ts-mode--imenu-1 type-tree)))
- (append
- (when mod-index `(("Module" . ,mod-index)))
- (when enum-index `(("Enum" . ,enum-index)))
- (when impl-index `(("Impl" . ,impl-index)))
- (when type-index `(("Type" . ,type-index)))
- (when struct-index `(("Struct" . ,struct-index)))
- (when func-index `(("Fn" . ,func-index))))))
-
-(defun rust-ts-mode--imenu-1 (node)
- "Helper for `rust-ts-mode--imenu'.
-Find string representation for NODE and set marker, then recurse
-the subtrees."
- (let* ((ts-node (car node))
- (children (cdr node))
- (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)))))
- (marker (when ts-node
- (set-marker (make-marker)
- (treesit-node-start ts-node)))))
- (cond
- ((or (null ts-node) (null name)) subtrees)
- (subtrees
- `((,name ,(cons name marker) ,@subtrees)))
- (t
- `((,name . ,marker))))))
+(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))))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))
@@ -330,15 +288,7 @@ the subtrees."
(treesit-parser-create 'rust)
;; Comments.
- (setq-local comment-start "// ")
- (setq-local comment-end "")
- (setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
- (seq "/" (+ "*")))
- (* (syntax whitespace))))
- (setq-local comment-end-skip
- (rx (* (syntax whitespace))
- (group (or (syntax comment-end)
- (seq (+ "*") "/")))))
+ (c-ts-mode-comment-setup)
;; Font-lock.
(setq-local treesit-font-lock-settings rust-ts-mode--font-lock-settings)
@@ -350,8 +300,13 @@ the subtrees."
( bracket delimiter error operator)))
;; Imenu.
- (setq-local imenu-create-index-function #'rust-ts-mode--imenu)
- (setq-local which-func-functions nil)
+ (setq-local treesit-simple-imenu-settings
+ `(("Module" "\\`mod_item\\'" nil nil)
+ ("Enum" "\\`enum_item\\'" nil nil)
+ ("Impl" "\\`impl_item\\'" nil nil)
+ ("Type" "\\`type_item\\'" nil nil)
+ ("Struct" "\\`struct_item\\'" nil nil)
+ ("Fn" "\\`function_item\\'" nil nil)))
;; Indent.
(setq-local indent-tabs-mode nil
@@ -363,6 +318,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/progmodes/scheme.el b/lisp/progmodes/scheme.el
index 8454f24356a..f45d7992524 100644
--- a/lisp/progmodes/scheme.el
+++ b/lisp/progmodes/scheme.el
@@ -115,7 +115,8 @@
(defvar scheme-imenu-generic-expression
`((nil
- ,(rx bol "(define"
+ ,(rx bol (zero-or-more space)
+ "(define"
(zero-or-one "*")
(zero-or-one "-public")
(one-or-more space)
@@ -123,36 +124,41 @@
(group (one-or-more (or word (syntax symbol)))))
1)
("Methods"
- ,(rx bol "(define-"
+ ,(rx bol (zero-or-more space)
+ "(define-"
(or "generic" "method" "accessor")
(one-or-more space)
(zero-or-one "(")
(group (one-or-more (or word (syntax symbol)))))
1)
("Classes"
- ,(rx bol "(define-class"
+ ,(rx bol (zero-or-more space)
+ "(define-class"
(one-or-more space)
(zero-or-one "(")
(group (one-or-more (or word (syntax symbol)))))
1)
("Records"
- ,(rx bol "(define-record-type"
+ ,(rx bol (zero-or-more space)
+ "(define-record-type"
(zero-or-one "*")
(one-or-more space)
(group (one-or-more (or word (syntax symbol)))))
1)
("Conditions"
- ,(rx bol "(define-condition-type"
+ ,(rx bol (zero-or-more space)
+ "(define-condition-type"
(one-or-more space)
(group (one-or-more (or word (syntax symbol)))))
1)
("Modules"
- ,(rx bol "(define-module"
+ ,(rx bol (zero-or-more space)
+ "(define-module"
(one-or-more space)
(group "(" (one-or-more any) ")"))
1)
("Macros"
- ,(rx bol "("
+ ,(rx bol (zero-or-more space) "("
(or (and "defmacro"
(zero-or-one "*")
(zero-or-one "-public"))
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index 3f995d17b5a..d12ade36af3 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -150,6 +150,8 @@
(require 'executable)
(require 'treesit)
+(declare-function treesit-parser-create "treesit.c")
+
(autoload 'comint-completion-at-point "comint")
(autoload 'comint-filename-completion "comint")
(autoload 'comint-send-string "comint")
diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el
index 6ba1b9b12c0..05ddc0e7a94 100644
--- a/lisp/progmodes/typescript-ts-mode.el
+++ b/lisp/progmodes/typescript-ts-mode.el
@@ -30,6 +30,7 @@
(require 'treesit)
(require 'js)
(eval-when-compile (require 'rx))
+(require 'c-ts-mode) ; For comment indent and filling.
(declare-function treesit-parser-create "treesit.c")
@@ -73,8 +74,9 @@ Argument LANGUAGE is either `typescript' or `tsx'."
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
((node-is ">") parent-bol 0)
- ((and (parent-is "comment") comment-end) comment-start -1)
- ((parent-is "comment") comment-start-skip 0)
+ ((and (parent-is "comment") c-ts-mode--looking-at-star)
+ c-ts-mode--comment-start-after-first-star -1)
+ ((parent-is "comment") prev-adaptive-prefix 0)
((parent-is "ternary_expression") parent-bol typescript-ts-mode-indent-offset)
((parent-is "member_expression") parent-bol typescript-ts-mode-indent-offset)
((parent-is "named_imports") parent-bol typescript-ts-mode-indent-offset)
@@ -331,18 +333,12 @@ Argument LANGUAGE is either `typescript' or `tsx'."
:syntax-table typescript-ts-mode--syntax-table
;; Comments.
- (setq-local comment-start "// ")
- (setq-local comment-end "")
- (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
- (setq-local comment-end-skip
- (rx (* (syntax whitespace))
- (group (or (syntax comment-end)
- (seq (+ "*") "/")))))
+ (c-ts-mode-comment-setup)
+ (setq-local treesit-defun-prefer-top-level t)
(setq-local treesit-text-type-regexp
(regexp-opt '("comment"
"template_string")))
- (setq-local treesit-defun-prefer-top-level t)
;; Electric
(setq-local electric-indent-chars
@@ -354,11 +350,17 @@ Argument LANGUAGE is either `typescript' or `tsx'."
"method_definition"
"function_declaration"
"lexical_declaration")))
- ;; Imenu.
- (setq-local imenu-create-index-function #'js--treesit-imenu)
-
- ;; Which-func (use imenu).
- (setq-local which-func-functions nil))
+ (setq-local treesit-defun-name-function #'js--treesit-defun-name)
+
+ ;; Imenu (same as in `js-ts-mode').
+ (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))))
;;;###autoload
(define-derived-mode typescript-ts-mode typescript-ts-base-mode "TypeScript"