1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-08 07:20:28 -08:00

Merge from origin/emacs-29

db96b1282f * lisp/help.el: Use 'C-h C-q' to toggle 'help-quick' wind...
489865c21e ; Improve markup of long key sequences
d42c2668cf ; * etc/NEWS: Fix wording of a recently edited entry.
7a0eaee198 * lisp/isearch.el: Small fixes.
b69bffeec0 * lisp/vc/diff-mode.el (diff-minor-mode-prefix): Replace ...
9263847ab7 ; * etc/NEWS: Move the paragraph with 'C-u RET' closer to...
62fb2dc37d * doc/emacs/display.texi (Text Scale): Improve section ab...
70480d3b6b * lisp/repeat.el (repeat-echo-function): Suggest 'add-fun...
fd48201ffe * lisp/tab-line.el (tab-line-cache-key-default): More cac...
b164660260 * etc/package-keyring.gpg: Update with new key
c0be51389e ; Yet another declare-function to avoid treesit-related w...
8676bec51d ; * lisp/treesit.el (treesit--simple-imenu-1): Doc fix; w...
2ddc480f44 Warn of absent networks module in ERC
19d00fab9a Avoid "already compiled" warning in erc-compat
2d8f7b66bc ; Fix one more treesit byte-compilation warning.
2d0a921486 ; Avoid treesit-related byte-compiler warnings
8503b370be (python--treesit-settings): Remove duplicate matcher
b464e6c490 Make last change of w32 GUI dialogs conditional and rever...
eedc9d79ae Fix tree-sitter typos
248c13dcfe Update tree-sitter major modes to use the new Imenu facility
b39dc7ab27 Add tree-sitter helper functions for Imenu
ba1ddea9da Fix treesit--things-around (bug#60355)
7512b9025a ; * lisp/treesit.el (treesit-traverse-parent): Remove alias.
5326b04198 Improve treesit-node-top-level and treesit-parent-until
637f5b164f ; Add "src" to the heuristic sub-directory heuristic
8ab6df0c9f ; * lisp/epa-ks.el (epa-ks-do-key-to-fetch): Fix 'when' u...
2b55a48d3e * src/w32menu.c (simple_dialog_show): Use MB_YESNOCANCEL ...
8b8b791567 ; Improve documentation of TAB/SPC indentation
624e382211 ; Improve doc strings of some new faces
41f12e1019 ; * lisp/elide-head.el (elide-head): Doc fix to silence c...
e3b4cd0ac1 ; * lisp/htmlfontify.el (hfy-text-p): Fix whitespace.
1b4dc4691c Fix htmlfontify.el command injection vulnerability.
1fe4b98b4d Improve support for Scheme R6RS and R7RS libraries (bug#5...
2347f37f67 ; * test/src/treesit-tests.el: remove dead store (bytecom...
a6d961ae2f Add a new tree-sitter query predicate 'pred'
835a80dcc4 ; Fix tree-sitter defun tests
a14821d615 Improve gnutls-min-prime-bits docstring
b14bbd108e Improve handling of tab-bar height.
669160d47b ; * nt/INSTALL.W64: More fixes and updates.
26b2ec7cb8 Simplify last change (bug#60311)
082fc6e308 Fix 'json-available-p' on MS-Windows
6c86faec29 loaddefs-gen: Group results by absolute file name
d90d7d15f2 ; Fix vindexes in parsing.texi
eb26872837 Fix imenu for c-ts-mode (bug#60296)
8f68b6497e Clean up python-ts-mode font-lock features
28f26b11a1 Add comment indent and filling to other tree-sitter major...
c6b0282645 ; Remove unused function in c-ts-mode
6e52a9fcad ; * doc/lispref/modes.texi (Parser-based Font Lock): Mino...
2bcd1e9a99 ; * doc/lispref/parsing.texi (Retrieving Nodes): Add notice.
7c7950fe00 Add maintainer stub for tree-sitter files
cf32776622 ; * doc/lispref/parsing.texi (Using Parser): Remove delet...

# Conflicts:
#	etc/NEWS
#	lisp/progmodes/c-ts-mode.el
#	lisp/progmodes/typescript-ts-mode.el
#	lisp/treesit.el
This commit is contained in:
Stefan Kangas 2022-12-28 21:40:59 +01:00
commit dce6791e99
50 changed files with 945 additions and 813 deletions

View file

@ -164,10 +164,11 @@ mode hooks."
(defun elide-head (&optional arg)
"Hide header material in buffer according to `elide-head-headers-to-hide'.
The header is made invisible with an overlay. With a prefix arg, show
an elided material again.
The header is made invisible with an overlay. With a prefix
argument ARG, show an elided material again.
This is suitable as an entry on `find-file-hook' or appropriate mode hooks."
This is suitable as an entry on `find-file-hook' or appropriate
mode hooks."
(declare (obsolete elide-head-mode "29.1"))
(interactive "P")
(if arg

View file

@ -608,7 +608,8 @@ instead of just updating them with the new/changed autoloads."
(write-region (point-min) (point-max) output-file nil 'silent))
;; We have some data, so generate the loaddef files. First
;; group per output file.
(dolist (fdefs (seq-group-by #'car defs))
(dolist (fdefs (seq-group-by (lambda (x) (expand-file-name (car x)))
defs))
(let ((loaddefs-file (car fdefs))
hash)
(with-temp-buffer

View file

@ -613,18 +613,21 @@ checkout. This overrides the `:branch' attribute in PKG-SPEC."
;; When nothing is specified about a `lisp-dir', then should
;; heuristically check if there is a sub-directory with lisp
;; files. These are conventionally just called "lisp". If this
;; directory exists and contains non-zero number of lisp files, we
;; will use that instead of `pkg-dir'.
(when-let* (((null lisp-dir))
(dir (expand-file-name "lisp" pkg-dir))
((file-directory-p dir))
((directory-files dir nil "\\`[^.].+\\.el\\'" t 1)))
;; We won't use `dir', since dir is an absolute path and we
;; don't want `lisp-dir' to depend on the current location of
;; the package installation, ie. to break if moved around the
;; file system or between installations.
(setq lisp-dir "lisp"))
;; files. These are conventionally just called "lisp" or "src".
;; If this directory exists and contains non-zero number of lisp
;; files, we will use that instead of `pkg-dir'.
(catch 'done
(dolist (name '("lisp" "src"))
(when-let* (((null lisp-dir))
(dir (expand-file-name name pkg-dir))
((file-directory-p dir))
((directory-files dir nil "\\`[^.].+\\.el\\'" t 1)))
;; We won't use `dir', since dir is an absolute path and we
;; don't want `lisp-dir' to depend on the current location of
;; the package installation, ie. to break if moved around the
;; file system or between installations.
(throw 'done (setq lisp-dir name)))))
(when lisp-dir
(push (cons :lisp-dir lisp-dir)
(package-desc-extras pkg-desc)))

View file

@ -135,9 +135,9 @@ Keys are marked using `epa-ks-mark-key-to-fetch'."
keys))
(forward-line))
(when (yes-or-no-p (format "Proceed with fetching all %d key(s)? "
(length keys))))
(dolist (id keys)
(epa-ks--fetch-key id))))
(length keys)))
(dolist (id keys)
(epa-ks--fetch-key id)))))
(tabulated-list-clear-all-tags))
(defun epa-ks--query-url (query exact)

View file

@ -320,6 +320,15 @@ session when reconnecting. Once `erc-reuse-buffers' is retired
and fully removed, modules can switch to leveraging the
`permanent-local' property instead.")
(defvar erc--server-post-connect-hook '(erc-networks--warn-on-connect)
"Functions to run when a network connection is successfully opened.
Though internal, this complements `erc-connect-pre-hook' in that
it bookends the process rather than the logical connection, which
is the domain of `erc-before-connect' and `erc-after-connect'.
Note that unlike `erc-connect-pre-hook', this only runs in server
buffers, and it does so immediately before the first protocol
exchange.")
(defvar-local erc-server-timed-out nil
"Non-nil if the IRC server failed to respond to a ping.")
@ -646,6 +655,7 @@ The current buffer is given by BUFFER."
(cl-defmethod erc--register-connection ()
"Perform opening IRC protocol exchange with server."
(run-hooks 'erc--server-post-connect-hook)
(erc-login))
(defvar erc--server-connect-dumb-ipv6-regexp

View file

@ -261,7 +261,7 @@ If START or END is negative, it counts from the end."
(when-let* ((s (plist-get e :secret))
(v (auth-source--obfuscate s)))
(setf (plist-get e :secret)
(byte-compile (lambda () (auth-source--deobfuscate v)))))
(apply-partially #'auth-source--deobfuscate v)))
(push e out)))
rv)))

View file

@ -1472,14 +1472,16 @@ to be a false alarm. If `erc-reuse-buffers' is nil, let
(t (rename-buffer (generate-new-buffer-name name)))))
nil)
;; Soju v0.4.0 only sends ISUPPORT on upstream reconnect, so this
;; doesn't apply. ZNC 1.8.2, however, still sends the entire burst.
(defconst erc-networks--bouncer-targets '(*status bouncerserv)
"Case-mapped symbols matching known bouncer service-bot targets.")
;; Soju v0.4.0 sends ISUPPORT and nothing else on upstream reconnect,
;; so this actually doesn't apply. ZNC 1.8.2, however, still sends
;; the entire burst.
(defvar erc-networks--bouncer-targets '(*status bouncerserv)
"Symbols matching proxy-bot targets.")
(defun erc-networks-on-MOTD-end (proc parsed)
"Call on-connect functions with server PROC and PARSED message.
This must run before `erc-server-connected' is set."
"Call on-connect functions with server PROC and PARSED message."
;; This should normally run before `erc-server-connected' is set.
;; However, bouncers and other proxies may interfere with that.
(when erc-server-connected
(unless (erc-buffer-filter (lambda ()
(and erc--target
@ -1502,6 +1504,18 @@ This must run before `erc-server-connected' is set."
((remove-hook 'erc-server-376-functions #'erc-networks-on-MOTD-end)
(remove-hook 'erc-server-422-functions #'erc-networks-on-MOTD-end)))
(defun erc-networks--warn-on-connect ()
"Emit warning when the `networks' module hasn't been loaded.
Ideally, do so upon opening the network process."
(unless (or erc--target erc-networks-mode)
(require 'info nil t)
(let ((m (concat "Required module `networks' not loaded. If this "
" was unexpected, please add it to `erc-modules'.")))
;; Assume the server buffer has been marked as active.
(erc-display-error-notice
nil (concat m " See Info:\"(erc) Required Modules\" for more."))
(lwarn 'erc :warning m))))
(defun erc-ports-list (ports)
"Return a list of PORTS.

View file

@ -435,7 +435,7 @@ Otherwise, expect it to disappear in subsequent versions.")
(if (eq :user (alist-get 'user erc-sasl--options))
(erc-current-nick)
erc-session-username)))
(erc-login))
(cl-call-next-method))
(when erc-sasl--send-cap-ls
(erc-server-send "CAP REQ :sasl"))
(erc-server-send (format "AUTHENTICATE %s" m)))

View file

@ -1607,7 +1607,8 @@ same manner."
(when target ; compat
(setq tgt-info (erc--target-from-string target)))
(if tgt-info
(let* ((esid (erc-networks--id-symbol erc-networks--id))
(let* ((esid (and erc-networks--id
(erc-networks--id-symbol erc-networks--id)))
(name (if esid
(erc-networks--reconcile-buffer-names tgt-info
erc-networks--id)
@ -6760,7 +6761,8 @@ This should be a string with substitution variables recognized by
If the name of the network is not available, then use the
shortened server name instead."
(if-let ((erc--target)
(name (if-let ((esid (erc-networks--id-symbol erc-networks--id)))
(name (if-let ((erc-networks--id)
(esid (erc-networks--id-symbol erc-networks--id)))
(symbol-name esid)
(erc-shorten-server-name (or erc-server-announced-name
erc-session-server)))))

View file

@ -2850,7 +2850,7 @@ since only a single case-insensitive search through the alist is made."
("\\.emacs-places\\'" . lisp-data-mode)
("\\.el\\'" . emacs-lisp-mode)
("Project\\.ede\\'" . emacs-lisp-mode)
("\\.\\(scm\\|stk\\|ss\\|sch\\)\\'" . scheme-mode)
("\\.\\(scm\\|sls\\|sld\\|stk\\|ss\\|sch\\)\\'" . scheme-mode)
("\\.l\\'" . lisp-mode)
("\\.li?sp\\'" . lisp-mode)
("\\.[fF]\\'" . fortran-mode)

View file

@ -2110,7 +2110,7 @@ For example, the declaration and use of fields in a struct."
(defface font-lock-punctuation-face
'((t nil))
"Font Lock mode face used to highlight punctuation."
"Font Lock mode face used to highlight punctuation characters."
:group 'font-lock-faces
:version "29.1")
@ -2122,7 +2122,9 @@ For example, the declaration and use of fields in a struct."
(defface font-lock-delimiter-face
'((t :inherit font-lock-punctuation-face))
"Font Lock mode face used to highlight delimiters."
"Font Lock mode face used to highlight delimiters.
What exactly is a delimiter depends on the major mode, but usually
these are characters like comma, colon, and semi-colon."
:group 'font-lock-faces
:version "29.1")

View file

@ -76,6 +76,7 @@ buffer.")
"C-n" #'view-emacs-news
"C-o" #'describe-distribution
"C-p" #'view-emacs-problems
"C-q" #'help-quick-toggle
"C-s" #'search-forward-help-for-help
"C-t" #'view-emacs-todo
"C-w" #'describe-no-warranty
@ -116,7 +117,7 @@ buffer.")
"v" #'describe-variable
"w" #'where-is
"x" #'describe-command
"q" #'help-quit-or-quick)
"q" #'help-quit)
(define-key global-map (char-to-string help-char) 'help-command)
(define-key global-map [help] 'help-command)
@ -243,7 +244,17 @@ buffer.")
;; ... and shrink it immediately.
(fit-window-to-buffer))
(message
(substitute-command-keys "Toggle the quick help buffer using \\[help-quit-or-quick]."))))
(substitute-command-keys "Toggle the quick help buffer using \\[help-quick-toggle]."))))
(defun help-quick-toggle ()
"Toggle the quick-help window."
(interactive)
(if (and-let* ((window (get-buffer-window "*Quick Help*")))
(quit-window t window))
;; Clear the message we may have gotten from `C-h' and then
;; waiting before hitting `q'.
(message "")
(help-quick)))
(defalias 'cheat-sheet #'help-quick)
@ -252,21 +263,6 @@ buffer.")
(interactive)
nil)
(defun help-quit-or-quick ()
"Call `help-quit' or `help-quick' depending on the context."
(interactive)
(cond
(help-buffer-under-preparation
;; FIXME: There should be a better way to detect if we are in the
;; help command loop.
(help-quit))
((and-let* ((window (get-buffer-window "*Quick Help*")))
(quit-window t window)
;; Clear the message we may have gotten from `C-h' and then
;; waiting before hitting `q'.
(message "")))
((help-quick))))
(defvar help-return-method nil
"What to do to \"exit\" the help buffer.
This is a list
@ -416,7 +412,7 @@ Do not call this in the scope of `with-help-window'."
("describe-package" "Describe a specific Emacs package")
""
("help-with-tutorial" "Start the Emacs tutorial")
("help-quick-or-quit" "Display the quick help buffer.")
("help-quick-toggle" "Display the quick help buffer.")
("view-echo-area-messages"
"Show recent messages (from echo area)")
("view-lossage" ,(format "Show last %d input keystrokes (lossage)"

View file

@ -1850,8 +1850,9 @@ Hardly bombproof, but good enough in the context in which it is being used."
(defun hfy-text-p (srcdir file)
"Is SRCDIR/FILE text? Use `hfy-istext-command' to determine this."
(let* ((cmd (format hfy-istext-command (expand-file-name file srcdir)))
(rsp (shell-command-to-string cmd)))
(let* ((cmd (format hfy-istext-command
(shell-quote-argument (expand-file-name file srcdir))))
(rsp (shell-command-to-string cmd)))
(string-match "text" rsp)))
;; open a file, check fontification, if fontified, write a fontified copy

View file

@ -784,7 +784,8 @@ If PREV is non-nil, return the previous one instead."
(defun tab-to-tab-stop ()
"Insert spaces or tabs to next defined tab-stop column.
The variable `tab-stop-list' is a list of columns at which there are tab stops.
Use \\[edit-tab-stops] to edit them interactively."
Use \\[edit-tab-stops] to edit them interactively.
Whether this inserts tabs or spaces depends on `indent-tabs-mode'."
(interactive)
(and abbrev-mode (= (char-syntax (preceding-char)) ?w)
(expand-abbrev))

View file

@ -181,7 +181,9 @@ When t (by default), signal an error when no more matches are found.
Then after repeating the search, wrap with `isearch-wrap-function'.
When `no', wrap immediately after reaching the last match.
When `no-ding', wrap immediately without flashing the screen.
When nil, never wrap, just stop at the last match."
When nil, never wrap, just stop at the last match.
With the values `no' and `no-ding' the search will try
to wrap around also on typing a character."
:type '(choice (const :tag "Pause before wrapping" t)
(const :tag "No pause before wrapping" no)
(const :tag "No pause and no flashing" no-ding)
@ -880,6 +882,7 @@ matches literally, against one space. You can toggle the value of this
variable by the command `isearch-toggle-lax-whitespace', usually bound to
`M-s SPC' during isearch."
:type 'boolean
:group 'isearch
:version "25.1")
(defvar isearch-regexp-lax-whitespace nil
@ -1179,6 +1182,7 @@ Each element of the list should be one of the symbols supported by
`isearch-forward-thing-at-point' to yank the initial \"thing\"
as text to the search string."
:type '(repeat (symbol :tag "Thing symbol"))
:group 'isearch
:version "28.1")
(defun isearch-forward-thing-at-point ()
@ -2525,10 +2529,11 @@ If no input items have been entered yet, just beep."
(ding)
(isearch-pop-state))
;; When going back to the hidden match, reopen it and close other overlays.
(when (and (eq search-invisible 'open) isearch-hide-immediately)
(when (and (eq isearch-invisible 'open) isearch-hide-immediately)
(if isearch-other-end
(isearch-range-invisible (min (point) isearch-other-end)
(max (point) isearch-other-end))
(let ((search-invisible isearch-invisible))
(isearch-range-invisible (min (point) isearch-other-end)
(max (point) isearch-other-end)))
(isearch-close-unnecessary-overlays (point) (point))))
(isearch-update))

View file

@ -128,10 +128,7 @@ key exchange is against man-in-the-middle attacks.)
A value of nil says to use the default GnuTLS value.
The default value of this variable is such that virtually any
connection can be established, whether this connection can be
considered cryptographically \"safe\" or not. However, Emacs
network security is handled at a higher level via
Emacs network security is handled at a higher level via
`open-network-stream' and the Network Security Manager. See Info
node `(emacs) Network Security'."
:type '(choice (const :tag "Use default value" nil)

View file

@ -487,92 +487,44 @@ For NODE, OVERRIDE, START, and END, see
(defun c-ts-mode--defun-name (node)
"Return the name of the defun NODE.
Return nil if NODE is not a defun node, return an empty string if
NODE doesn't have a name."
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")))
("struct_specifier"
((or "struct_specifier" "enum_specifier"
"union_specifier" "class_specifier")
(treesit-node-child-by-field-name node "name")))
t))
(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-defun-name ts-node)))
(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 navigation
(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)))))
(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.
@ -660,6 +612,59 @@ ARG is passed to `fill-paragraph'."
;; 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))
;; Same as `adaptive-fill-regexp'.
(setq-local adaptive-fill-first-line-regexp
(rx bos
(seq (* (syntax whitespace))
(group (or (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
@ -694,44 +699,25 @@ ARG is passed to `fill-paragraph'."
(when (eq c-ts-mode-indent-style 'linux)
(setq-local indent-tabs-mode t))
(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))
;; Same as `adaptive-fill-regexp'.
(setq-local adaptive-fill-first-line-regexp
(rx bos
(seq (* (syntax whitespace))
(group (or (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)
;; 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)
@ -752,13 +738,6 @@ ARG is passed to `fill-paragraph'."
;; 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))
@ -766,11 +745,7 @@ ARG is passed to `fill-paragraph'."
;; 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++"
@ -781,17 +756,6 @@ ARG is passed to `fill-paragraph'."
(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")))
@ -804,11 +768,7 @@ ARG is passed to `fill-paragraph'."
;; 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)

View file

@ -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)
@ -853,54 +858,6 @@ Return nil if there is no name or if NODE is not a defun node."
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
the subtrees."
(let* ((ts-node (car node))
(subtrees (mapcan #'csharp-ts-mode--imenu-1 (cdr node)))
(name (when ts-node
(or (treesit-defun-name ts-node)
"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))))))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode))
@ -929,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"
@ -964,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)

View file

@ -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)
@ -264,50 +267,6 @@ Return nil if there is no name or if NODE is not a defun node."
(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
the subtrees."
(let* ((ts-node (car node))
(subtrees (mapcan #'java-ts-mode--imenu-1 (cdr node)))
(name (when ts-node
(or (treesit-defun-name ts-node)
"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))))))
;;;###autoload
(define-derived-mode java-ts-mode prog-mode "Java"
"Major mode for editing Java, powered by tree-sitter."
@ -320,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"
@ -363,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)

View file

@ -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)
@ -3425,9 +3426,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)
@ -3669,70 +3670,11 @@ Return nil if there is no name or if NODE is not a defun node."
"name")
t))
(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
(or (treesit-defun-name ts-node)
"Anonymous")))
(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)))
;; When a sub-tree is empty, we should not return that pair at all.
(append
(and func-tree
`(("Function" . ,(js--treesit-imenu-1 func-tree))))
(and var-tree
`(("Variable" . ,(js--treesit-imenu-1 var-tree))))
(and class-tree
`(("Class" . ,(js--treesit-imenu-1 class-tree)))))))
(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
@ -3845,15 +3787,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
@ -3887,10 +3821,14 @@ Currently there are `js-mode' and `js-ts-mode'."
identifier jsx number pattern property)
( bracket delimiter operator)))
;; 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

View file

@ -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")
@ -112,36 +113,11 @@
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
the subtrees."
(let* ((ts-node (car node))
(subtrees (mapcan #'json-ts-mode--imenu-1 (cdr node)))
(name (when ts-node
(or (treesit-defun-name ts-node)
"Anonymous")))
(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)))
(string-trim (treesit-node-text
(treesit-node-child-by-field-name
node "key")
t)
"\"" "\""))))
;;;###autoload
(define-derived-mode json-ts-mode prog-mode "JSON"
@ -179,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))

View file

@ -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
@ -6646,7 +6665,7 @@ 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)

View file

@ -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,35 +248,6 @@
'((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--defun-name (node)
"Return the defun name of NODE.
Return nil if there is no name or if NODE is not a defun node."
@ -300,27 +275,6 @@ Return nil if there is no name or if NODE is not a defun node."
(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
the subtrees."
(let* ((ts-node (car node))
(children (cdr node))
(subtrees (mapcan #'rust-ts-mode--imenu-1
children))
(name (when ts-node
(or (treesit-defun-name ts-node)
"Anonymous")))
(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))))))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))
@ -334,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)
@ -354,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

View file

@ -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"))

View file

@ -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")

View file

@ -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)
(setq-local treesit-defun-name-function #'js--treesit-defun-name)
;; Which-func (use imenu).
(setq-local which-func-functions nil))
;; 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"

View file

@ -399,7 +399,8 @@ but the property value is `t', then check the last key."
(defcustom repeat-echo-function #'repeat-echo-message
"Function to display a hint about available keys.
Function is called after every repeatable command with one argument:
a repeating map, or nil after deactivating the transient repeating mode."
a repeating map, or nil after deactivating the transient repeating mode.
You can use `add-function' for multiple functions simultaneously."
:type '(choice (const :tag "Show hints in the echo area"
repeat-echo-message)
(const :tag "Show indicator in the mode line"

View file

@ -6905,11 +6905,8 @@ sentence (see Info node `(elisp) Documentation Tips')."
(defun json-available-p ()
"Return non-nil if Emacs has libjansson support."
(and (fboundp 'json-serialize)
(condition-case nil
(json-serialize t)
(:success t)
(json-unavailable nil))))
(and (fboundp 'json--available-p)
(json--available-p)))
(defun ensure-list (object)
"Return OBJECT as a list.

View file

@ -572,9 +572,14 @@ For use in `tab-line-tab-face-functions'."
(defvar tab-line-auto-hscroll)
(defun tab-line-cache-key-default (_tabs)
(defun tab-line-cache-key-default (tabs)
"Return default list of cache keys."
(list
tabs
;; handle buffer renames
(buffer-name (window-buffer))
;; handle tab-line scrolling
(window-parameter nil 'tab-line-hscroll)
;; for setting face 'tab-line-tab-current'
(mode-line-window-selected-p)
;; for `tab-line-tab-face-modified'
@ -591,12 +596,7 @@ of cache keys. You can use `add-function' to add more cache keys.")
(defun tab-line-format ()
"Format for displaying the tab line of the selected window."
(let* ((tabs (funcall tab-line-tabs-function))
(cache-key (append (list tabs
;; handle buffer renames
(buffer-name (window-buffer))
;; handle tab-line scrolling
(window-parameter nil 'tab-line-hscroll))
(funcall tab-line-cache-key-function tabs)))
(cache-key (funcall tab-line-cache-key-function tabs))
(cache (window-parameter nil 'tab-line-cache)))
;; Enable auto-hscroll again after it was disabled on manual scrolling.
;; The moment to enable it is when the window-buffer was updated.

View file

@ -1425,33 +1425,6 @@ Return nil if there is no name or if NODE is not a defun node."
(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
the subtrees."
(let* ((ts-node (car node))
(subtrees (mapcan #'css--treesit-imenu-1 (cdr node)))
(name (when ts-node
(or (treesit-defun-name ts-node)
"Anonymous")))
(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 css--treesit-imenu ()
"Return Imenu alist for the current buffer."
(let* ((node (treesit-buffer-root-node))
(tree (treesit-induce-sparse-tree
node (rx (or "rule_set" "media_statement"))
nil 1000)))
(css--treesit-imenu-1 tree)))
;;; Completion
(defun css--complete-property ()
@ -1847,8 +1820,9 @@ can also be used to fill comments.
'((selector comment query keyword)
(property constant string)
(error variable function operator bracket)))
(setq-local imenu-create-index-function #'css--treesit-imenu)
(setq-local which-func-functions nil)
(setq-local treesit-simple-imenu-settings
`( nil ,(rx bos (or "rule_set" "media_statement") eos)
nil nil))
(treesit-major-mode-setup)))
;;;###autoload

View file

@ -32,6 +32,8 @@
(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 "treesit.c")
(declare-function treesit-node-child-by-field-name "treesit.c")
(defcustom toml-ts-mode-indent-offset 2
@ -112,39 +114,8 @@
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'.
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 (or (treesit-defun-name ts-node)
"Root table"))
(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 toml-ts-mode--imenu ()
"Return Imenu alist for the current buffer."
(let* ((node (treesit-buffer-root-node))
(table-tree (treesit-induce-sparse-tree
node "^table$" nil 1000))
(table-array-tree (treesit-induce-sparse-tree
node "^table_array_element$" nil 1000))
(table-index (toml-ts-mode--imenu-1 table-tree))
(table-array-index (toml-ts-mode--imenu-1 table-array-tree)))
(append
(when table-index `(("Headers" . ,table-index)))
(when table-array-index `(("Arrays" . ,table-array-index))))))
(or (treesit-node-text (treesit-node-child node 1) t)
"Root table"))))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode))
@ -179,8 +150,9 @@ the subtrees."
(delimiter error)))
;; Imenu.
(setq-local imenu-create-index-function #'toml-ts-mode--imenu)
(setq-local which-func-functions nil) ;; Piggyback on imenu
(setq-local treesit-simple-imenu-settings
'(("Header" "\\`table\\'" nil nil)
("Array" "\\`table_array_element\\'" nil nil)))
(treesit-major-mode-setup)))

View file

@ -2,6 +2,10 @@
;; Copyright (C) 2021-2022 Free Software Foundation, Inc.
;; Maintainer: 付禹安 (Yuan Fu) <casouri@gmail.com>
;; Keywords: treesit, tree-sitter, languages
;; Package: emacs
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
@ -230,19 +234,27 @@ is nil, try to guess the language at BEG using `treesit-language-at'."
(or parser-or-lang (treesit-language-at beg))))))
(treesit-node-descendant-for-range root beg (or end beg) named)))
(defun treesit-node-top-level (node &optional type)
(defun treesit-node-top-level (node &optional pred include-node)
"Return the top-level equivalent of NODE.
Specifically, return the highest parent of NODE that has the same
type as it. If no such parent exists, return nil.
If TYPE is non-nil, match each parent's type with TYPE as a
regexp, rather than using NODE's type."
(let ((type (or type (treesit-node-type node)))
If PRED is non-nil, match each parent's type with PRED as a
regexp, rather than using NODE's type. PRED can also be a
function that takes the node as an argument, and return
non-nil/nil for match/no match.
If INCLUDE-NODE is non-nil, return NODE if it satisfies PRED."
(let ((pred (or pred (treesit-node-type node)))
(result nil))
(cl-loop for cursor = (treesit-node-parent node)
(cl-loop for cursor = (if include-node node
(treesit-node-parent node))
then (treesit-node-parent cursor)
while cursor
if (string-match-p type (treesit-node-type cursor))
if (if (stringp pred)
(string-match-p pred (treesit-node-type cursor))
(funcall pred cursor))
do (setq result cursor))
result))
@ -286,11 +298,16 @@ properties."
(treesit-node-start node)
(treesit-node-end node))))))
(defun treesit-parent-until (node pred)
(defun treesit-parent-until (node pred &optional include-node)
"Return the closest parent of NODE that satisfies PRED.
Return nil if none was found. PRED should be a function that
takes one argument, the parent node."
(let ((node (treesit-node-parent node)))
takes one argument, the parent node, and return non-nil/nil for
match/no match.
If INCLUDE-NODE is non-nil, return NODE if it satisfies PRED."
(let ((node (if include-node node
(treesit-node-parent node))))
(while (and node (not (funcall pred node)))
(setq node (treesit-node-parent node)))
node))
@ -305,8 +322,6 @@ takes one argument, the parent node."
node (treesit-node-parent node)))
last))
(defalias 'treesit-traverse-parent #'treesit-parent-until)
(defun treesit-node-children (node &optional named)
"Return a list of NODE's children.
If NAMED is non-nil, collect named child only."
@ -1644,7 +1659,7 @@ For example, \"(function|class)_definition\".
Sometimes not all nodes matched by the regexp are valid defuns.
In that case, set this variable to a cons cell of the
form (REGEXP . FILTER), where FILTER is a function that takes a
form (REGEXP . PRED), where PRED is a function that takes a
node (the matched node) and returns t if node is valid, or nil
for invalid node.
@ -1793,78 +1808,67 @@ sound things exists.
REGEXP and PRED are the same as in `treesit-thing-at-point'."
(let* ((node (treesit-node-at pos))
;; NODE-BEFORE/AFTER = NODE when POS is completely in NODE,
;; but if not, that means point could be in between two
;; defun, in that case we want to use a node that's actually
;; before/after point.
(node-before (if (>= (treesit-node-start node) pos)
(save-excursion
(treesit-search-forward-goto node "" t t t))
node))
(node-after (if (<= (treesit-node-end node) pos)
(save-excursion
(treesit-search-forward-goto
node "" nil nil t))
node))
(result (list nil nil nil))
(pred (or pred (lambda (_) t))))
(result (list nil nil nil)))
;; 1. Find previous and next sibling defuns.
(cl-loop
for idx from 0 to 1
for node in (list node-before node-after)
for backward in '(t nil)
;; Make sure we go in the right direction, and the defun we find
;; doesn't cover POS.
for pos-pred in (list (lambda (n) (<= (treesit-node-end n) pos))
(lambda (n) (>= (treesit-node-start n) pos)))
;; If point is inside a defun, our process below will never
;; return a next/prev sibling outside of that defun, effectively
;; any prev/next sibling is locked inside the smallest defun
;; covering point, which is the correct behavior. That's because
;; when there exists a defun that covers point,
;; `treesit-search-forward' will first reach that defun, after
;; that we only go upwards in the tree, so other defuns outside
;; of the covering defun is never reached. (Don't use
;; `treesit-search-forward-goto' as it breaks when NODE-AFTER is
;; the last token of a parent defun: it will skip the parent
;; defun because it wants to ensure progress.)
do (cl-loop for cursor = (when node
(save-excursion
(treesit-search-forward
node regexp backward backward)))
then (treesit-node-parent cursor)
while cursor
if (and (string-match-p
regexp (treesit-node-type cursor))
(funcall pred cursor)
(funcall pos-pred cursor))
do (setf (nth idx result) cursor)))
;; We repeatedly find next defun candidate with
;; `treesit-search-forward', and check if it is a valid defun,
;; until the node we find covers POS, meaning we've gone through
;; every possible sibling defuns. But there is a catch:
;; `treesit-search-forward' searches bottom-up, so for each
;; candidate we need to go up the tree and find the top-most
;; valid sibling, this defun will be at the same level as POS.
;; Don't use `treesit-search-forward-goto', it skips nodes in
;; order to enforce progress.
when node
do (let ((cursor node)
(iter-pred (lambda (node)
(and (string-match-p
regexp (treesit-node-type node))
(or (null pred) (funcall pred node))
(funcall pos-pred node)))))
;; Find the node just before/after POS to start searching.
(save-excursion
(while (and cursor (not (funcall pos-pred cursor)))
(setq cursor (treesit-search-forward-goto
cursor "" backward backward t))))
;; Keep searching until we run out of candidates.
(while (and cursor
(funcall pos-pred cursor)
(null (nth idx result)))
(setf (nth idx result)
(treesit-node-top-level cursor iter-pred t))
(setq cursor (treesit-search-forward
cursor regexp backward backward)))))
;; 2. Find the parent defun.
(setf (nth 2 result)
(cl-loop for cursor = (or (nth 0 result)
(nth 1 result)
node)
then (treesit-node-parent cursor)
while cursor
if (and (string-match-p
regexp (treesit-node-type cursor))
(funcall pred cursor)
(not (member cursor result)))
return cursor))
(let ((cursor (or (nth 0 result) (nth 1 result) node))
(iter-pred (lambda (node)
(and (string-match-p
regexp (treesit-node-type node))
(or (null pred) (funcall pred node))
(not (treesit-node-eq node (nth 0 result)))
(not (treesit-node-eq node (nth 1 result)))
(< (treesit-node-start node)
pos
(treesit-node-end node))))))
(setf (nth 2 result)
(treesit-parent-until cursor iter-pred)))
result))
(defun treesit--top-level-thing (node regexp &optional pred)
"Return the top-level parent thing of NODE.
REGEXP and PRED are the same as in `treesit-thing-at-point'."
(let* ((pred (or pred (lambda (_) t))))
;; `treesit-search-forward-goto' will make sure the matched node
;; is before POS.
(cl-loop for cursor = node
then (treesit-node-parent cursor)
while cursor
if (and (string-match-p
regexp (treesit-node-type cursor))
(funcall pred cursor))
do (setq node cursor))
node))
(treesit-node-top-level
node (lambda (node)
(and (string-match-p regexp (treesit-node-type node))
(or (null pred) (funcall pred node))))
t))
;; The basic idea for nested defun navigation is that we first try to
;; move across sibling defuns in the same level, if no more siblings
@ -2040,6 +2044,91 @@ The delimiter between nested defun names is controlled by
(setq node (treesit-node-parent node)))
name))
;;; Imenu
(defvar treesit-simple-imenu-settings nil
"Settings that configure `treesit-simple-imenu'.
It should be a list of (CATEGORY REGEXP PRED NAME-FN).
CATEGORY is the name of a category, like \"Function\", \"Class\",
etc. REGEXP should be a regexp matching the type of nodes that
belong to CATEGORY. PRED should be either nil or a function
that takes a node an the argument. It should return non-nil if
the node is a valid node for CATEGORY, or nil if not.
CATEGORY could also be nil. In that case the entries matched by
REGEXP and PRED are not grouped under CATEGORY.
NAME-FN should be either nil or a function that takes a defun
node and returns the name of that defun node. If NAME-FN is nil,
`treesit-defun-name' is used.
`treesit-major-mode-setup' automatically sets up Imenu if this
variable is non-nil.")
(defun treesit--simple-imenu-1 (node pred name-fn)
"Given a sparse tree, create an Imenu index.
NODE is a node in 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 index.
Return a list of entries where each ENTRY has the form:
ENTRY := (NAME . MARKER)
| (NAME . ((\" \" . MARKER)
ENTRY
...)
PRED and NAME-FN are the same as described in
`treesit-simple-imenu-settings'. NAME-FN computes NAME in an
ENTRY. MARKER marks the start of each tree-sitter node."
(let* ((ts-node (car node))
(children (cdr node))
(subtrees (mapcan (lambda (node)
(treesit--simple-imenu-1 node pred name-fn))
children))
;; The root of the tree could have a nil ts-node.
(name (when ts-node
(or (if name-fn
(funcall name-fn ts-node)
(treesit-defun-name ts-node))
"Anonymous")))
(marker (when ts-node
(set-marker (make-marker)
(treesit-node-start ts-node)))))
(cond
;; The tree-sitter node in the root node of the tree returned by
;; `treesit-induce-sparse-tree' is often nil.
((null ts-node)
subtrees)
;; This tree-sitter node is not a valid entry, skip it.
((and pred (not (funcall pred ts-node)))
subtrees)
;; Non-leaf node, return a (list of) subgroup.
(subtrees
`((,name
,(cons " " marker)
,@subtrees)))
;; Leaf node, return a (list of) plain index entry.
(t (list (cons name marker))))))
(defun treesit-simple-imenu ()
"Return an Imenu index for the current buffer."
(let ((root (treesit-buffer-root-node)))
(mapcan (lambda (setting)
(pcase-let ((`(,category ,regexp ,pred ,name-fn)
setting))
(when-let* ((tree (treesit-induce-sparse-tree
root regexp))
(index (treesit--simple-imenu-1
tree pred name-fn)))
(if category
(list (cons category index))
index))))
treesit-simple-imenu-settings)))
;;; Activating tree-sitter
(defun treesit-ready-p (language &optional quiet)
@ -2097,6 +2186,11 @@ If `treesit-simple-indent-rules' is non-nil, setup indentation.
If `treesit-defun-type-regexp' is non-nil, setup
`beginning/end-of-defun' functions.
If `treesit-defun-name-function' is non-nil, setup
`add-log-current-defun'.
If `treesit-simple-imenu-settings' is non-nil, setup Imenu.
Make sure necessary parsers are created for the current buffer
before calling this function."
;; Font-lock.
@ -2138,7 +2232,13 @@ before calling this function."
(when treesit-defun-name-function
(setq-local add-log-current-defun-function
#'treesit-add-log-current-defun))
(setq-local transpose-sexps-function #'treesit-transpose-sexps))
(setq-local transpose-sexps-function #'treesit-transpose-sexps)
;; Imenu.
(when treesit-simple-imenu-settings
(setq-local imenu-create-index-function
#'treesit-simple-imenu)))
;;; Debugging

View file

@ -272,8 +272,7 @@ and hunk-based syntax highlighting otherwise as a fallback."
(defcustom diff-minor-mode-prefix "\C-c="
"Prefix key for `diff-minor-mode' commands."
:type '(choice (string "ESC")
(string "\C-c=") string))
:type '(choice (string "\e") (string "\C-c=") string))
(defvar-keymap diff-minor-mode-map
:doc "Keymap for `diff-minor-mode'. See also `diff-mode-shared-map'."