aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Kangas2023-01-23 01:34:39 +0100
committerStefan Kangas2023-01-23 01:34:39 +0100
commit0805972e4cab3493d172edf2e303486d7c3cb386 (patch)
treee806d00b1518012c00cdd6b8a0e29fac4c16bd5a
parent8febda46c458f11270350d0b68c69d8a58b59f8d (diff)
parentb3de81a6ee3b379fc1dfb9a071e469365081f438 (diff)
downloademacs-0805972e4cab3493d172edf2e303486d7c3cb386.tar.gz
emacs-0805972e4cab3493d172edf2e303486d7c3cb386.zip
Merge from origin/emacs-29
b3de81a6ee3 MH-E: handle removal of mhparam libdir from nmh 1.8 d63e1a89518 Use point-min to anchor top-level constructs (bug#60602) 34793337783 * lisp/org/ob-ruby.el: Fix outdated comments. 472f1425985 ; ruby-ts-mode: Add a Version tag 0cf053648a4 ; ruby-ts-mode: Update font-lock features list in Commentary 67ee627c38d (project-try-vc): Add string-start and string-end anchors... 06953fc8e1d Make `keymap-set-after' work for menus dcd59457b48 Use `key-parse' in `keymap-lookup' 8904a26a9d2 Improve `keymap-set-after' documentation c7e02eaa3d9 Handle after arg correctly in `keymap-set-after' 628b6241763 Don't load erc-goodies atop erc.el 40cf494b7ce ; * etc/NEWS: Fix typos. 6b2f85caa6c Make tree-sitter based modes optional b56cf28b325 ; (ruby-ts--predefined-variables): Make it a little shorter d94dc606a09 ruby-ts-mode: Claw back half of the performance drop from... d0d34514097 (ruby-ts-mode): Rename 'builtin-functions' to 'builtin-fu... d66ac5285f7 ruby-ts-mode: Highlight builtin methods 370b1ac99ec ; ruby-ts-mode.el: Add customize-group mention to commentary 7b7b2b95138 Fix c-ts-mode indent (bug#60873) 7ca71d66dc7 Fix various problems in treesit-explore-mode (bug#60800) b7d6bb47ee5 ; * lisp/treesit.el (treesit-font-lock-fontify-region): M... 0c6bfeddb21 ; Update tree-sitter major mode manual c289786886b ; Add commentary and dostring in c-ts-mode # Conflicts: # etc/NEWS # lisp/progmodes/c-ts-mode.el # lisp/progmodes/go-ts-mode.el
-rw-r--r--doc/lispref/keymaps.texi18
-rw-r--r--doc/lispref/parsing.texi51
-rw-r--r--etc/NEWS.2962
-rw-r--r--lisp/erc/erc.el3
-rw-r--r--lisp/keymap.el15
-rw-r--r--lisp/mh-e/mh-e.el5
-rw-r--r--lisp/org/ob-ruby.el5
-rw-r--r--lisp/progmodes/c-ts-mode.el109
-rw-r--r--lisp/progmodes/cmake-ts-mode.el8
-rw-r--r--lisp/progmodes/csharp-mode.el7
-rw-r--r--lisp/progmodes/dockerfile-ts-mode.el12
-rw-r--r--lisp/progmodes/go-ts-mode.el12
-rw-r--r--lisp/progmodes/java-ts-mode.el5
-rw-r--r--lisp/progmodes/js.el5
-rw-r--r--lisp/progmodes/json-ts-mode.el4
-rw-r--r--lisp/progmodes/project.el15
-rw-r--r--lisp/progmodes/python.el5
-rw-r--r--lisp/progmodes/ruby-mode.el150
-rw-r--r--lisp/progmodes/ruby-ts-mode.el54
-rw-r--r--lisp/progmodes/rust-ts-mode.el6
-rw-r--r--lisp/progmodes/typescript-ts-mode.el14
-rw-r--r--lisp/textmodes/css-mode.el4
-rw-r--r--lisp/textmodes/toml-ts-mode.el5
-rw-r--r--lisp/textmodes/yaml-ts-mode.el6
-rw-r--r--lisp/treesit.el62
-rw-r--r--test/lisp/progmodes/c-ts-mode-resources/indent.erts13
-rw-r--r--test/src/keymap-tests.el33
27 files changed, 469 insertions, 219 deletions
diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi
index 1c548af1990..7876780dcd4 100644
--- a/doc/lispref/keymaps.texi
+++ b/doc/lispref/keymaps.texi
@@ -1378,7 +1378,8 @@ Binding Conventions}).
1378or if @var{key} is not a valid key. 1378or if @var{key} is not a valid key.
1379 1379
1380@var{key} is a string representing a single key or a series of key 1380@var{key} is a string representing a single key or a series of key
1381strokes. Key strokes are separated by a single space character. 1381strokes, and must satisfy @code{key-valid-p}. Key strokes are
1382separated by a single space character.
1382 1383
1383Each key stroke is either a single character, or the name of an 1384Each key stroke is either a single character, or the name of an
1384event, surrounded by angle brackets. In addition, any key stroke 1385event, surrounded by angle brackets. In addition, any key stroke
@@ -1413,6 +1414,7 @@ The only keys that have a special shorthand syntax are @kbd{NUL},
1413The modifiers have to be specified in alphabetical order: 1414The modifiers have to be specified in alphabetical order:
1414@samp{A-C-H-M-S-s}, which is @samp{Alt-Control-Hyper-Meta-Shift-super}. 1415@samp{A-C-H-M-S-s}, which is @samp{Alt-Control-Hyper-Meta-Shift-super}.
1415 1416
1417@findex keymap-set
1416@defun keymap-set keymap key binding 1418@defun keymap-set keymap key binding
1417This function sets the binding for @var{key} in @var{keymap}. (If 1419This function sets the binding for @var{key} in @var{keymap}. (If
1418@var{key} is more than one event long, the change is actually made 1420@var{key} is more than one event long, the change is actually made
@@ -3079,13 +3081,13 @@ the menu. To put it elsewhere in the menu, use @code{keymap-set-after}:
3079@defun keymap-set-after map key binding &optional after 3081@defun keymap-set-after map key binding &optional after
3080Define a binding in @var{map} for @var{key}, with value @var{binding}, 3082Define a binding in @var{map} for @var{key}, with value @var{binding},
3081just like @code{define-key}, but position the binding in @var{map} after 3083just like @code{define-key}, but position the binding in @var{map} after
3082the binding for the event @var{after}. The argument @var{key} should be 3084the binding for the event @var{after}. The argument @var{key} should
3083of length one---a vector or string with just one element. But 3085represent a single menu item or key, and @var{after} should be a
3084@var{after} should be a single event type---a symbol or a character, not 3086single event type---a symbol or a character, not a sequence. The new
3085a sequence. The new binding goes after the binding for @var{after}. If 3087binding goes after the binding for @var{after}. If @var{after} is
3086@var{after} is @code{t} or is omitted, then the new binding goes last, at 3088@code{t} or is omitted, then the new binding goes last, at the end of
3087the end of the keymap. However, new bindings are added before any 3089the keymap. However, new bindings are added before any inherited
3088inherited keymap. 3090keymap.
3089 3091
3090Here is an example: 3092Here is an example:
3091 3093
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index e4a25249829..cebb59b6501 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -1692,26 +1692,48 @@ integration for a major mode.
1692A major mode supporting tree-sitter features should roughly follow 1692A major mode supporting tree-sitter features should roughly follow
1693this pattern: 1693this pattern:
1694 1694
1695@c FIXME: Update this part once we settle on the exact format.
1696@example 1695@example
1697@group 1696@group
1698(define-derived-mode woomy-mode prog-mode "Woomy" 1697(define-derived-mode woomy-mode prog-mode "Woomy"
1699 "A mode for Woomy programming language." 1698 "A mode for Woomy programming language."
1700 ;; Shared setup. 1699 (when (treesit-ready-p 'woomy)
1701 ...
1702 (cond
1703 ;; Tree-sitter setup.
1704 ((treesit-ready-p 'woomy)
1705 (setq-local treesit-variables ...) 1700 (setq-local treesit-variables ...)
1706 (treesit-major-mode-setup)) 1701 ...
1707 ;; Non-tree-sitter setup. 1702 (treesit-major-mode-setup)))
1708 (t
1709 ...)))
1710@end group 1703@end group
1711@end example 1704@end example
1712 1705
1713First, the major mode should use @code{treesit-ready-p} to determine 1706@code{treesit-ready-p} automatically emits a warning if conditions for
1714whether tree-sitter can be activated in this mode. 1707enabling tree-sitter aren't met.
1708
1709If a tree-sitter major mode shares setup with their ``native''
1710counterpart, they can create a ``base mode'' that contains the common
1711setup, like this:
1712
1713@example
1714@group
1715(define-derived-mode woomy--base-mode prog-mode "Woomy"
1716 "An internal mode for Woomy programming language."
1717 (common-setup)
1718 ...)
1719@end group
1720
1721@group
1722(define-derived-mode woomy-mode woomy--base-mode "Woomy"
1723 "A mode for Woomy programming language."
1724 (native-setup)
1725 ...)
1726@end group
1727
1728@group
1729(define-derived-mode woomy-ts-mode woomy--base-mode "Woomy"
1730 "A mode for Woomy programming language."
1731 (when (treesit-ready-p 'woomy)
1732 (setq-local treesit-variables ...)
1733 ...
1734 (treesit-major-mode-setup)))
1735@end group
1736@end example
1715 1737
1716@defun treesit-ready-p language &optional quiet 1738@defun treesit-ready-p language &optional quiet
1717This function checks for conditions for activating tree-sitter. It 1739This function checks for conditions for activating tree-sitter. It
@@ -1722,15 +1744,12 @@ language grammar for @var{language} is available on the system
1722 1744
1723This function emits a warning if tree-sitter cannot be activated. If 1745This function emits a warning if tree-sitter cannot be activated. If
1724@var{quiet} is @code{message}, the warning is turned into a message; 1746@var{quiet} is @code{message}, the warning is turned into a message;
1725if @var{quiet} is @code{nil}, no warning or message is displayed. 1747if @var{quiet} is @code{t}, no warning or message is displayed.
1726 1748
1727If all the necessary conditions are met, this function returns 1749If all the necessary conditions are met, this function returns
1728non-@code{nil}; otherwise it returns @code{nil}. 1750non-@code{nil}; otherwise it returns @code{nil}.
1729@end defun 1751@end defun
1730 1752
1731Next, the major mode should set up tree-sitter variables and call
1732@code{treesit-major-mode-setup}.
1733
1734@defun treesit-major-mode-setup 1753@defun treesit-major-mode-setup
1735This function activates some tree-sitter features for a major mode. 1754This function activates some tree-sitter features for a major mode.
1736 1755
diff --git a/etc/NEWS.29 b/etc/NEWS.29
index 38f2db26a1a..64c26f93c50 100644
--- a/etc/NEWS.29
+++ b/etc/NEWS.29
@@ -34,13 +34,14 @@ This feature existed in Emacs 28.1, but was less easy to request.
34 34
35+++ 35+++
36** Emacs can be built with the tree-sitter parsing library. 36** Emacs can be built with the tree-sitter parsing library.
37This library, together with grammar libraries, provides incremental 37This library, together with separate grammar libraries for each
38parsing capabilities for several popular programming languages and 38language, provides incremental parsing capabilities for several
39other formatted files. Emacs built with this library offers major 39popular programming languages and other formatted files. Emacs built
40modes, described elsewhere in this file, that are based on the 40with this library offers major modes, described elsewhere in this
41tree-sitter's parsers. If you have the tree-sitter library 41file, that are based on the tree-sitter's parsers. If you have the
42installed, the configure script will automatically include it in the 42tree-sitter library installed, the configure script will automatically
43build; use '--without-tree-sitter' at configure time to disable that. 43include it in the build; use '--without-tree-sitter' at configure time
44to disable that.
44 45
45Emacs modes based on the tree-sitter library require an additional 46Emacs modes based on the tree-sitter library require an additional
46grammar library for each mode. These grammar libraries provide the 47grammar library for each mode. These grammar libraries provide the
@@ -3183,19 +3184,19 @@ indentation, and navigation by defuns based on parsing the buffer text
3183by a tree-sitter parser. Some major modes also offer support for 3184by a tree-sitter parser. Some major modes also offer support for
3184Imenu and 'which-func'. 3185Imenu and 'which-func'.
3185 3186
3186Where major modes already exist in Emacs for editing certain kinds of 3187The new modes based on tree-sitter are for now entirely optional, and
3187files, the new modes based on tree-sitter are for now entirely 3188you must turn them on manually, or load them in your init file, or
3188optional, and you must turn them on manually, or customize 3189customize 'auto-mode-alist' to turn them on automatically for certain
3189'auto-mode-alist' to turn them on automatically. 3190files. You can also customize 'major-mode-remap-alist' to
3191automatically turn on some tree-sitter based modes for the same files
3192for which a "built-in" mode would be turned on. For example:
3190 3193
3191Where no major modes previously existed in Emacs for editing the kinds 3194 (add-to-list 'major-mode-remap-alist '(ruby-mode . ruby-ts-mode))
3192of files for which Emacs now provides a tree-sitter based mode, Emacs 3195
3193will now try to enable these new modes automatically when you visit 3196If you try these modes and don't like them, you can go back to the
3194such files, and will display a warning if the tree-sitter library or 3197"built-in" modes by restarting Emacs. But please tell us why you
3195the parser grammar library is not available. To prevent the warnings, 3198didn't like the tree-sitter based modes, so that we could try
3196either build Emacs with tree-sitter and install the grammar libraries, 3199improving them.
3197or customize 'auto-mode-alist' to specify some other major mode (or
3198even 'fundamental-mode') for those kinds of files.
3199 3200
3200Each major mode based on tree-sitter needs a language grammar library, 3201Each major mode based on tree-sitter needs a language grammar library,
3201usually named "libtree-sitter-LANG.so" ("libtree-sitter-LANG.dll" on 3202usually named "libtree-sitter-LANG.so" ("libtree-sitter-LANG.dll" on
@@ -3212,20 +3213,18 @@ We recommend to install these libraries in one of the standard system
3212locations (the last place in the above list). 3213locations (the last place in the above list).
3213 3214
3214If a language grammar library required by a mode is not found in any 3215If a language grammar library required by a mode is not found in any
3215of the above places, the mode will signal an error when you try to 3216of the above places, the mode will display a warning when you try to
3216turn it on. 3217turn it on.
3217 3218
3218+++ 3219+++
3219*** New major mode 'typescript-ts-mode'. 3220*** New major mode 'typescript-ts-mode'.
3220A major mode based on the tree-sitter library for editing programs 3221A major mode based on the tree-sitter library for editing programs
3221in the TypeScript language. This mode is auto-enabled for files with 3222in the TypeScript language.
3222the ".ts" extension.
3223 3223
3224+++ 3224+++
3225*** New major mode 'tsx-ts-mode'. 3225*** New major mode 'tsx-ts-mode'.
3226A major mode based on the tree-sitter library for editing programs 3226A major mode based on the tree-sitter library for editing programs
3227in the TypeScript language, with support for TSX. This mode is 3227in the TypeScript language, with support for TSX.
3228auto-enabled for files with the ".tsx" extension.
3229 3228
3230+++ 3229+++
3231*** New major mode 'c-ts-mode'. 3230*** New major mode 'c-ts-mode'.
@@ -3275,15 +3274,11 @@ Bash shell scripts.
3275+++ 3274+++
3276*** New major mode 'dockerfile-ts-mode'. 3275*** New major mode 'dockerfile-ts-mode'.
3277A major mode based on the tree-sitter library for editing 3276A major mode based on the tree-sitter library for editing
3278Dockerfiles. This mode is auto-enabled for files which are named 3277Dockerfiles.
3279"Dockerfile", have the "Dockerfile." prefix, or have the ".dockerfile"
3280extension.
3281 3278
3282+++ 3279+++
3283*** New major mode 'cmake-ts-mode'. 3280*** New major mode 'cmake-ts-mode'.
3284A major mode based on the tree-sitter library for editing CMake files. 3281A major mode based on the tree-sitter library for editing CMake files.
3285It is auto-enabled for files whose name is "CMakeLists.txt" or whose
3286extension is ".cmake".
3287 3282
3288+++ 3283+++
3289*** New major mode 'toml-ts-mode'. 3284*** New major mode 'toml-ts-mode'.
@@ -3293,23 +3288,22 @@ files written in TOML, a format for writing configuration files.
3293+++ 3288+++
3294*** New major mode 'go-ts-mode'. 3289*** New major mode 'go-ts-mode'.
3295A major mode based on the tree-sitter library for editing programs in 3290A major mode based on the tree-sitter library for editing programs in
3296the Go language. It is auto-enabled for files with the ".go" extension. 3291the Go language.
3297 3292
3298+++ 3293+++
3299*** New major mode 'go-mod-ts-mode'. 3294*** New major mode 'go-mod-ts-mode'.
3300A major mode based on the tree-sitter library for editing "go.mod" 3295A major mode based on the tree-sitter library for editing "go.mod"
3301files. It is auto-enabled for files which are named "go.mod". 3296files.
3302 3297
3303+++ 3298+++
3304*** New major mode 'yaml-ts-mode'. 3299*** New major mode 'yaml-ts-mode'.
3305A major mode based on the tree-sitter library for editing files 3300A major mode based on the tree-sitter library for editing files
3306written in YAML. It is auto-enabled for files with the ".yaml" or 3301written in YAML.
3307".yml" extensions.
3308 3302
3309+++ 3303+++
3310*** New major mode 'rust-ts-mode'. 3304*** New major mode 'rust-ts-mode'.
3311A major mode based on the tree-sitter library for editing programs in 3305A major mode based on the tree-sitter library for editing programs in
3312the Rust language. It is auto-enabled for files with the ".rs" extension. 3306the Rust language.
3313 3307
3314--- 3308---
3315*** New major mode 'ruby-ts-mode'. 3309*** New major mode 'ruby-ts-mode'.
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 7f51b7bfb2e..ff1820cfaf2 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -61,7 +61,6 @@
61(load "erc-loaddefs" 'noerror 'nomessage) 61(load "erc-loaddefs" 'noerror 'nomessage)
62 62
63(require 'erc-networks) 63(require 'erc-networks)
64(require 'erc-goodies)
65(require 'erc-backend) 64(require 'erc-backend)
66(require 'cl-lib) 65(require 'cl-lib)
67(require 'format-spec) 66(require 'format-spec)
@@ -7386,4 +7385,6 @@ Customize `erc-url-connect-function' to override this."
7386 7385
7387(provide 'erc) 7386(provide 'erc)
7388 7387
7388;; FIXME this is a temporary stopgap for Emacs 29.
7389(require 'erc-goodies)
7389;;; erc.el ends here 7390;;; erc.el ends here
diff --git a/lisp/keymap.el b/lisp/keymap.el
index 315eaab7560..791221f2459 100644
--- a/lisp/keymap.el
+++ b/lisp/keymap.el
@@ -186,10 +186,17 @@ a menu, so this function is not useful for non-menu keymaps."
186 (declare (indent defun) 186 (declare (indent defun)
187 (compiler-macro (lambda (form) (keymap--compile-check key) form))) 187 (compiler-macro (lambda (form) (keymap--compile-check key) form)))
188 (keymap--check key) 188 (keymap--check key)
189 (when after 189 (when (eq after t) (setq after nil)) ; nil and t are treated the same
190 (keymap--check after)) 190 (when (stringp after)
191 (keymap--check after)
192 (setq after (key-parse after)))
193 ;; If we're binding this key to another key, then parse that other
194 ;; key, too.
195 (when (stringp definition)
196 (keymap--check definition)
197 (setq definition (key-parse definition)))
191 (define-key-after keymap (key-parse key) definition 198 (define-key-after keymap (key-parse key) definition
192 (and after (key-parse after)))) 199 after))
193 200
194(defun key-parse (keys) 201(defun key-parse (keys)
195 "Convert KEYS to the internal Emacs key representation. 202 "Convert KEYS to the internal Emacs key representation.
@@ -404,7 +411,7 @@ specified buffer position instead of point are used."
404 (symbolp value)) 411 (symbolp value))
405 (or (command-remapping value) value) 412 (or (command-remapping value) value)
406 value)) 413 value))
407 (key-binding (kbd key) accept-default no-remap position))) 414 (key-binding (key-parse key) accept-default no-remap position)))
408 415
409(defun keymap-local-lookup (keys &optional accept-default) 416(defun keymap-local-lookup (keys &optional accept-default)
410 "Return the binding for command KEYS in current local keymap only. 417 "Return the binding for command KEYS in current local keymap only.
diff --git a/lisp/mh-e/mh-e.el b/lisp/mh-e/mh-e.el
index 1640c23e002..34c809a5ecd 100644
--- a/lisp/mh-e/mh-e.el
+++ b/lisp/mh-e/mh-e.el
@@ -764,6 +764,8 @@ This assumes that a temporary buffer is set up."
764 ;; Sample '-version' outputs: 764 ;; Sample '-version' outputs:
765 ;; mhparam -- nmh-1.1-RC1 [compiled on chaak at Fri Jun 20 11:03:28 PDT 2003] 765 ;; mhparam -- nmh-1.1-RC1 [compiled on chaak at Fri Jun 20 11:03:28 PDT 2003]
766 ;; install-mh -- nmh-1.7.1 built October 26, 2019 on build-server-000 766 ;; install-mh -- nmh-1.7.1 built October 26, 2019 on build-server-000
767 ;; "libdir" was deprecated in nmh-1.7 in favor of "libexecdir", and
768 ;; removed completely in nmh-1.8.
767 (let ((install-mh (expand-file-name "install-mh" dir))) 769 (let ((install-mh (expand-file-name "install-mh" dir)))
768 (when (mh-file-command-p install-mh) 770 (when (mh-file-command-p install-mh)
769 (erase-buffer) 771 (erase-buffer)
@@ -774,7 +776,8 @@ This assumes that a temporary buffer is set up."
774 (mh-progs dir)) 776 (mh-progs dir))
775 `(,version 777 `(,version
776 (variant nmh) 778 (variant nmh)
777 (mh-lib-progs ,(mh-profile-component "libdir")) 779 (mh-lib-progs ,(or (mh-profile-component "libdir")
780 (mh-profile-component "libexecdir")))
778 (mh-lib ,(mh-profile-component "etcdir")) 781 (mh-lib ,(mh-profile-component "etcdir"))
779 (mh-progs ,dir) 782 (mh-progs ,dir)
780 (flists ,(file-exists-p 783 (flists ,(file-exists-p
diff --git a/lisp/org/ob-ruby.el b/lisp/org/ob-ruby.el
index 03c94b1ba99..b94bc73dd79 100644
--- a/lisp/org/ob-ruby.el
+++ b/lisp/org/ob-ruby.el
@@ -29,11 +29,10 @@
29 29
30;; - ruby and irb executables :: https://www.ruby-lang.org/ 30;; - ruby and irb executables :: https://www.ruby-lang.org/
31;; 31;;
32;; - ruby-mode :: Can be installed through ELPA, or from 32;; - ruby-mode :: Comes with Emacs.
33;; https://github.com/eschulte/rinari/raw/master/util/ruby-mode.el
34;; 33;;
35;; - inf-ruby mode :: Can be installed through ELPA, or from 34;; - inf-ruby mode :: Can be installed through ELPA, or from
36;; https://github.com/eschulte/rinari/raw/master/util/inf-ruby.el 35;; https://raw.githubusercontent.com/nonsequitur/inf-ruby/master/inf-ruby.el
37 36
38;;; Code: 37;;; Code:
39 38
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 14bbb099a0a..e4755bb315f 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -24,6 +24,58 @@
24 24
25;;; Commentary: 25;;; Commentary:
26;; 26;;
27;; This package provides major modes for C and C++, plus some handy
28;; functions that are useful generally to major modes for C-like
29;; languages.
30;;
31;; This package provides `c-ts-mode' for C, `c++-ts-mode' for C++, and
32;; `c-or-c++-ts-mode' which automatically chooses the right mode for
33;; C/C++ header files.
34;;
35;; To use these modes by default, assuming you have the respective
36;; tree-sitter grammars available, do one of the following:
37;;
38;; - If you have both C and C++ grammars installed, add
39;;
40;; (require 'c-ts-mode)
41;;
42;; to your init file.
43;;
44;; - Add one or mode of the following to your init file:
45;;
46;; (add-to-list 'major-mode-remap-alist '(c-mode . c-ts-mode))
47;; (add-to-list 'major-mode-remap-alist '(c++-mode . c++-ts-mode))
48;; (add-to-list 'major-mode-remap-alist '(c-or-c++-mode . c-or-c++-ts-mode))
49;;
50;; If you have only C grammar available, use only the first one; if
51;; you have only the C++ grammar, use only the second one.
52;;
53;; - Customize 'auto-mode-alist' to turn one or more of the modes
54;; automatically. For example:
55;;
56;; (add-to-list 'auto-mode-alist
57;; '("\\(\\.ii\\|\\.\\(CC?\\|HH?\\)\\|\\.[ch]\\(pp\\|xx\\|\\+\\+\\)\\|\\.\\(cc\\|hh\\)\\)\\'"
58;; . c++-ts-mode))
59;;
60;; will turn on the c++-ts-mode for C++ source files.
61;;
62;; You can also turn on these modes manually in a buffer. Doing so
63;; will set up Emacs to use the C/C++ modes defined here for other
64;; files, provided that you have the corresponding parser grammar
65;; libraries installed.
66;;
67;; For C-like language major modes:
68;;
69;; - Use `c-ts-mode-comment-setup' to setup comment variables and
70;; filling.
71;;
72;; - Use simple-indent matcher `c-ts-mode--looking-at-star' and anchor
73;; `c-ts-mode--comment-start-after-first-star' for indenting block
74;; comments. See `c-ts-mode--indent-styles' for example.
75;;
76;; - Use variable `c-ts-mode-indent-block-type-regexp' with indent
77;; offset c-ts-mode--statement-offset for indenting statements.
78;; Again, see `c-ts-mode--indent-styles' for example.
27 79
28;;; Code: 80;;; Code:
29 81
@@ -115,7 +167,7 @@ delimiters < and >'s."
115 "Indent rules supported by `c-ts-mode'. 167 "Indent rules supported by `c-ts-mode'.
116MODE is either `c' or `cpp'." 168MODE is either `c' or `cpp'."
117 (let ((common 169 (let ((common
118 `(((parent-is "translation_unit") parent-bol 0) 170 `(((parent-is "translation_unit") point-min 0)
119 ((node-is ")") parent 1) 171 ((node-is ")") parent 1)
120 ((node-is "]") parent-bol 0) 172 ((node-is "]") parent-bol 0)
121 ((node-is "else") parent-bol 0) 173 ((node-is "else") parent-bol 0)
@@ -257,7 +309,18 @@ PARENT is NODE's parent."
257 (cl-incf level) 309 (cl-incf level)
258 (save-excursion 310 (save-excursion
259 (goto-char (treesit-node-start node)) 311 (goto-char (treesit-node-start node))
260 (cond ((bolp) nil) 312 ;; Add an extra level if the opening bracket is on its own
313 ;; line, except (1) it's at top-level, or (2) it's immedate
314 ;; parent is another block.
315 (cond ((bolp) nil) ; Case (1).
316 ((let ((parent-type (treesit-node-type
317 (treesit-node-parent node))))
318 ;; Case (2).
319 (and parent-type
320 (string-match-p c-ts-mode-indent-block-type-regexp
321 parent-type)))
322 nil)
323 ;; Add a level.
261 ((looking-back (rx bol (* whitespace)) 324 ((looking-back (rx bol (* whitespace))
262 (line-beginning-position)) 325 (line-beginning-position))
263 (cl-incf level)))))) 326 (cl-incf level))))))
@@ -967,7 +1030,16 @@ Set up:
967 1030
968This mode is independent from the classic cc-mode.el based 1031This mode is independent from the classic cc-mode.el based
969`c-mode', so configuration variables of that mode, like 1032`c-mode', so configuration variables of that mode, like
970`c-basic-offset', don't affect this mode." 1033`c-basic-offset', doesn't affect this mode.
1034
1035To use tree-sitter C/C++ modes by default, evaluate
1036
1037 (add-to-list \\='major-mode-remap-alist \\='(c-mode . c-ts-mode))
1038 (add-to-list \\='major-mode-remap-alist \\='(c++-mode . c++-ts-mode))
1039 (add-to-list \\='major-mode-remap-alist
1040 \\='(c-or-c++-mode . c-or-c++-ts-mode))
1041
1042in your configuration."
971 :group 'c 1043 :group 'c
972 1044
973 (when (treesit-ready-p 'c) 1045 (when (treesit-ready-p 'c)
@@ -984,7 +1056,20 @@ This mode is independent from the classic cc-mode.el based
984 1056
985;;;###autoload 1057;;;###autoload
986(define-derived-mode c++-ts-mode c-ts-base-mode "C++" 1058(define-derived-mode c++-ts-mode c-ts-base-mode "C++"
987 "Major mode for editing C++, powered by tree-sitter." 1059 "Major mode for editing C++, powered by tree-sitter.
1060
1061This mode is independent from the classic cc-mode.el based
1062`c++-mode', so configuration variables of that mode, like
1063`c-basic-offset', don't affect this mode.
1064
1065To use tree-sitter C/C++ modes by default, evaluate
1066
1067 (add-to-list \\='major-mode-remap-alist \\='(c-mode . c-ts-mode))
1068 (add-to-list \\='major-mode-remap-alist \\='(c++-mode . c++-ts-mode))
1069 (add-to-list \\='major-mode-remap-alist
1070 \\='(c-or-c++-mode . c-or-c++-ts-mode))
1071
1072in your configuration."
988 :group 'c++ 1073 :group 'c++
989 1074
990 (when (treesit-ready-p 'cpp) 1075 (when (treesit-ready-p 'cpp)
@@ -1050,6 +1135,22 @@ the code is C or C++ and based on that chooses whether to enable
1050 (re-search-forward c-ts-mode--c-or-c++-regexp nil t)))) 1135 (re-search-forward c-ts-mode--c-or-c++-regexp nil t))))
1051 (c++-ts-mode) 1136 (c++-ts-mode)
1052 (c-ts-mode))) 1137 (c-ts-mode)))
1138;; The entries for C++ must come first to prevent *.c files be taken
1139;; as C++ on case-insensitive filesystems, since *.C files are C++,
1140;; not C.
1141(if (treesit-ready-p 'cpp)
1142 (add-to-list 'auto-mode-alist
1143 '("\\(\\.ii\\|\\.\\(CC?\\|HH?\\)\\|\\.[ch]\\(pp\\|xx\\|\\+\\+\\)\\|\\.\\(cc\\|hh\\)\\)\\'"
1144 . c++-ts-mode)))
1145
1146(if (treesit-ready-p 'c)
1147 (add-to-list 'auto-mode-alist
1148 '("\\(\\.[chi]\\|\\.lex\\|\\.y\\(acc\\)?\\|\\.x[bp]m\\)\\'"
1149 . c-ts-mode)))
1150
1151(if (and (treesit-ready-p 'cpp)
1152 (treesit-ready-p 'c))
1153 (add-to-list 'auto-mode-alist '("\\.h\\'" . c-or-c++-ts-mode)))
1053 1154
1054(provide 'c-ts-mode) 1155(provide 'c-ts-mode)
1055 1156
diff --git a/lisp/progmodes/cmake-ts-mode.el b/lisp/progmodes/cmake-ts-mode.el
index a31250f68be..c241a2868e5 100644
--- a/lisp/progmodes/cmake-ts-mode.el
+++ b/lisp/progmodes/cmake-ts-mode.el
@@ -195,10 +195,6 @@ the subtrees."
195 `((,name . ,marker)))))) 195 `((,name . ,marker))))))
196 196
197;;;###autoload 197;;;###autoload
198(add-to-list 'auto-mode-alist
199 '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)\\'" . cmake-ts-mode))
200
201;;;###autoload
202(define-derived-mode cmake-ts-mode prog-mode "CMake" 198(define-derived-mode cmake-ts-mode prog-mode "CMake"
203 "Major mode for editing CMake files, powered by tree-sitter." 199 "Major mode for editing CMake files, powered by tree-sitter."
204 :group 'cmake 200 :group 'cmake
@@ -229,6 +225,10 @@ the subtrees."
229 225
230 (treesit-major-mode-setup))) 226 (treesit-major-mode-setup)))
231 227
228(if (treesit-ready-p 'cmake)
229 (add-to-list 'auto-mode-alist
230 '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)\\'" . cmake-ts-mode)))
231
232(provide 'cmake-ts-mode) 232(provide 'cmake-ts-mode)
233 233
234;;; cmake-ts-mode.el ends here 234;;; cmake-ts-mode.el ends here
diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el
index 870e6c84b40..936420bbe8b 100644
--- a/lisp/progmodes/csharp-mode.el
+++ b/lisp/progmodes/csharp-mode.el
@@ -884,9 +884,6 @@ Return nil if there is no name or if NODE is not a defun node."
884 t)))) 884 t))))
885 885
886;;;###autoload 886;;;###autoload
887(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode))
888
889;;;###autoload
890(define-derived-mode csharp-mode prog-mode "C#" 887(define-derived-mode csharp-mode prog-mode "C#"
891 "Major mode for editing Csharp code. 888 "Major mode for editing Csharp code.
892 889
@@ -946,7 +943,9 @@ Key bindings:
946 ("Struct" "\\`struct_declaration\\'" nil nil) 943 ("Struct" "\\`struct_declaration\\'" nil nil)
947 ("Method" "\\`method_declaration\\'" nil nil))) 944 ("Method" "\\`method_declaration\\'" nil nil)))
948 945
949 (treesit-major-mode-setup)) 946 (treesit-major-mode-setup)
947
948 (add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-ts-mode)))
950 949
951(provide 'csharp-mode) 950(provide 'csharp-mode)
952 951
diff --git a/lisp/progmodes/dockerfile-ts-mode.el b/lisp/progmodes/dockerfile-ts-mode.el
index 1b91681f085..23ac48a6117 100644
--- a/lisp/progmodes/dockerfile-ts-mode.el
+++ b/lisp/progmodes/dockerfile-ts-mode.el
@@ -133,12 +133,6 @@ the subtrees."
133 `((,name . ,marker)))))) 133 `((,name . ,marker))))))
134 134
135;;;###autoload 135;;;###autoload
136(add-to-list 'auto-mode-alist
137 ;; NOTE: We can't use `rx' here, as it breaks bootstrap.
138 '("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'"
139 . dockerfile-ts-mode))
140
141;;;###autoload
142(define-derived-mode dockerfile-ts-mode prog-mode "Dockerfile" 136(define-derived-mode dockerfile-ts-mode prog-mode "Dockerfile"
143 "Major mode for editing Dockerfiles, powered by tree-sitter." 137 "Major mode for editing Dockerfiles, powered by tree-sitter."
144 :group 'dockerfile 138 :group 'dockerfile
@@ -176,6 +170,12 @@ the subtrees."
176 170
177 (treesit-major-mode-setup))) 171 (treesit-major-mode-setup)))
178 172
173(if (treesit-ready-p 'dockerfile)
174 (add-to-list 'auto-mode-alist
175 ;; NOTE: We can't use `rx' here, as it breaks bootstrap.
176 '("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'"
177 . dockerfile-ts-mode)))
178
179(provide 'dockerfile-ts-mode) 179(provide 'dockerfile-ts-mode)
180 180
181;;; dockerfile-ts-mode.el ends here 181;;; dockerfile-ts-mode.el ends here
diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
index be5a69c2ec4..44f141217bc 100644
--- a/lisp/progmodes/go-ts-mode.el
+++ b/lisp/progmodes/go-ts-mode.el
@@ -174,9 +174,6 @@
174 '((ERROR) @font-lock-warning-face)) 174 '((ERROR) @font-lock-warning-face))
175 "Tree-sitter font-lock settings for `go-ts-mode'.") 175 "Tree-sitter font-lock settings for `go-ts-mode'.")
176 176
177;;;###autoload
178(add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
179
180(defvar-keymap go-ts-mode-map 177(defvar-keymap go-ts-mode-map
181 :doc "Keymap used in Go mode, powered by tree-sitter" 178 :doc "Keymap used in Go mode, powered by tree-sitter"
182 :parent prog-mode-map 179 :parent prog-mode-map
@@ -233,6 +230,9 @@
233 230
234 (treesit-major-mode-setup))) 231 (treesit-major-mode-setup)))
235 232
233(if (treesit-ready-p 'go)
234 (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode)))
235
236(defun go-ts-mode--defun-name (node) 236(defun go-ts-mode--defun-name (node)
237 "Return the defun name of NODE. 237 "Return the defun name of NODE.
238Return nil if there is no name or if NODE is not a defun node." 238Return nil if there is no name or if NODE is not a defun node."
@@ -379,9 +379,6 @@ what the parent of the node would be if it were a node."
379 "Tree-sitter font-lock settings for `go-mod-ts-mode'.") 379 "Tree-sitter font-lock settings for `go-mod-ts-mode'.")
380 380
381;;;###autoload 381;;;###autoload
382(add-to-list 'auto-mode-alist '("/go\\.mod\\'" . go-mod-ts-mode))
383
384;;;###autoload
385(define-derived-mode go-mod-ts-mode prog-mode "Go Mod" 382(define-derived-mode go-mod-ts-mode prog-mode "Go Mod"
386 "Major mode for editing go.mod files, powered by tree-sitter." 383 "Major mode for editing go.mod files, powered by tree-sitter."
387 :group 'go 384 :group 'go
@@ -409,6 +406,9 @@ what the parent of the node would be if it were a node."
409 406
410 (treesit-major-mode-setup))) 407 (treesit-major-mode-setup)))
411 408
409(if (treesit-ready-p 'gomod)
410 (add-to-list 'auto-mode-alist '("/go\\.mod\\'" . go-mod-ts-mode)))
411
412(provide 'go-ts-mode) 412(provide 'go-ts-mode)
413 413
414;;; go-ts-mode.el ends here 414;;; go-ts-mode.el ends here
diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el
index 03093e09805..532b3f5aefb 100644
--- a/lisp/progmodes/java-ts-mode.el
+++ b/lisp/progmodes/java-ts-mode.el
@@ -69,7 +69,7 @@
69 69
70(defvar java-ts-mode--indent-rules 70(defvar java-ts-mode--indent-rules
71 `((java 71 `((java
72 ((parent-is "program") parent-bol 0) 72 ((parent-is "program") point-min 0)
73 ((node-is "}") (and parent parent-bol) 0) 73 ((node-is "}") (and parent parent-bol) 0)
74 ((node-is ")") parent-bol 0) 74 ((node-is ")") parent-bol 0)
75 ((node-is "]") parent-bol 0) 75 ((node-is "]") parent-bol 0)
@@ -359,6 +359,9 @@ Return nil if there is no name or if NODE is not a defun node."
359 ("Method" "\\`method_declaration\\'" nil nil))) 359 ("Method" "\\`method_declaration\\'" nil nil)))
360 (treesit-major-mode-setup)) 360 (treesit-major-mode-setup))
361 361
362(if (treesit-ready-p 'java)
363 (add-to-list 'auto-mode-alist '("\\.java\\'" . java-ts-mode)))
364
362(provide 'java-ts-mode) 365(provide 'java-ts-mode)
363 366
364;;; java-ts-mode.el ends here 367;;; java-ts-mode.el ends here
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 6f3746ca72a..4b21ae2290f 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -3903,7 +3903,10 @@ See `treesit-sexp-type-regexp' for more information.")
3903 "method_definition") 3903 "method_definition")
3904 eos) 3904 eos)
3905 nil nil))) 3905 nil nil)))
3906 (treesit-major-mode-setup))) 3906 (treesit-major-mode-setup)
3907
3908 (add-to-list 'auto-mode-alist
3909 '("\\(\\.js[mx]\\|\\.har\\)\\'" . js-ts-mode))))
3907 3910
3908;;;###autoload 3911;;;###autoload
3909(define-derived-mode js-json-mode js-mode "JSON" 3912(define-derived-mode js-json-mode js-mode "JSON"
diff --git a/lisp/progmodes/json-ts-mode.el b/lisp/progmodes/json-ts-mode.el
index f6a303290a8..6bd9d30328e 100644
--- a/lisp/progmodes/json-ts-mode.el
+++ b/lisp/progmodes/json-ts-mode.el
@@ -162,6 +162,10 @@ Return nil if there is no name or if NODE is not a defun node."
162 162
163 (treesit-major-mode-setup)) 163 (treesit-major-mode-setup))
164 164
165(if (treesit-ready-p 'json)
166 (add-to-list 'auto-mode-alist
167 '("\\.json\\'" . json-ts-mode)))
168
165(provide 'json-ts-mode) 169(provide 'json-ts-mode)
166 170
167;;; json-ts-mode.el ends here 171;;; json-ts-mode.el ends here
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index dc87cb8e15d..59270070484 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1,7 +1,7 @@
1;;; project.el --- Operations on the current project -*- lexical-binding: t; -*- 1;;; project.el --- Operations on the current project -*- lexical-binding: t; -*-
2 2
3;; Copyright (C) 2015-2023 Free Software Foundation, Inc. 3;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
4;; Version: 0.9.4 4;; Version: 0.9.5
5;; Package-Requires: ((emacs "26.1") (xref "1.4.0")) 5;; Package-Requires: ((emacs "26.1") (xref "1.4.0"))
6 6
7;; This is a GNU ELPA :core package. Avoid using functionality that 7;; This is a GNU ELPA :core package. Avoid using functionality that
@@ -514,11 +514,14 @@ project backend implementation of `project-external-roots'.")
514 (lambda (b) (assoc-default b backend-markers-alist)) 514 (lambda (b) (assoc-default b backend-markers-alist))
515 vc-handled-backends))) 515 vc-handled-backends)))
516 (marker-re 516 (marker-re
517 (mapconcat 517 (concat
518 (lambda (m) (format "\\(%s\\)" (wildcard-to-regexp m))) 518 "\\`"
519 (append backend-markers 519 (mapconcat
520 (project--value-in-dir 'project-vc-extra-root-markers dir)) 520 (lambda (m) (format "\\(%s\\)" (wildcard-to-regexp m)))
521 "\\|")) 521 (append backend-markers
522 (project--value-in-dir 'project-vc-extra-root-markers dir))
523 "\\|")
524 "\\'"))
522 (locate-dominating-stop-dir-regexp 525 (locate-dominating-stop-dir-regexp
523 (or vc-ignore-dir-regexp locate-dominating-stop-dir-regexp)) 526 (or vc-ignore-dir-regexp locate-dominating-stop-dir-regexp))
524 last-matches 527 last-matches
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 21d16db287c..a869cdc5fdb 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -6713,7 +6713,10 @@ implementations: `python-mode' and `python-ts-mode'."
6713 (treesit-major-mode-setup) 6713 (treesit-major-mode-setup)
6714 6714
6715 (when python-indent-guess-indent-offset 6715 (when python-indent-guess-indent-offset
6716 (python-indent-guess-indent-offset)))) 6716 (python-indent-guess-indent-offset))
6717
6718 (add-to-list 'auto-mode-alist
6719 '("\\.py[iw]?\\'\\|python[0-9.]*" . python-ts-mode))))
6717 6720
6718;;; Completion predicates for M-x 6721;;; Completion predicates for M-x
6719;; Commands that only make sense when editing Python code 6722;; Commands that only make sense when editing Python code
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index 2de7395f765..6e524693e37 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -141,6 +141,81 @@ This should only be called after matching against `ruby-here-doc-beg-re'."
141 141
142It should match the part after \"def\" and until \"=\".") 142It should match the part after \"def\" and until \"=\".")
143 143
144(defconst ruby-builtin-methods-with-reqs
145 '( ;; built-in methods on Kernel
146 "at_exit"
147 "autoload"
148 "autoload?"
149 "callcc"
150 "catch"
151 "eval"
152 "exec"
153 "format"
154 "lambda"
155 "load"
156 "loop"
157 "open"
158 "p"
159 "printf"
160 "proc"
161 "putc"
162 "require"
163 "require_relative"
164 "spawn"
165 "sprintf"
166 "syscall"
167 "system"
168 "throw"
169 "trace_var"
170 "trap"
171 "untrace_var"
172 "warn"
173 ;; keyword-like private methods on Module
174 "alias_method"
175 "attr"
176 "attr_accessor"
177 "attr_reader"
178 "attr_writer"
179 "define_method"
180 "extend"
181 "include"
182 "module_function"
183 "prepend"
184 "private_class_method"
185 "private_constant"
186 "public_class_method"
187 "public_constant"
188 "refine"
189 "using")
190 "List of built-in methods that require at least one argument.")
191
192(defconst ruby-builtin-methods-no-reqs
193 '("__callee__"
194 "__dir__"
195 "__method__"
196 "abort"
197 "binding"
198 "block_given?"
199 "caller"
200 "exit"
201 "exit!"
202 "fail"
203 "fork"
204 "global_variables"
205 "local_variables"
206 "print"
207 "private"
208 "protected"
209 "public"
210 "puts"
211 "raise"
212 "rand"
213 "readline"
214 "readlines"
215 "sleep"
216 "srand")
217 "List of built-in methods that only have optional arguments.")
218
144(defvar ruby-use-smie t) 219(defvar ruby-use-smie t)
145(make-obsolete-variable 'ruby-use-smie nil "28.1") 220(make-obsolete-variable 'ruby-use-smie nil "28.1")
146 221
@@ -2292,84 +2367,13 @@ It will be properly highlighted even when the call omits parens.")
2292 ;; Core methods that have required arguments. 2367 ;; Core methods that have required arguments.
2293 (,(concat 2368 (,(concat
2294 ruby-font-lock-keyword-beg-re 2369 ruby-font-lock-keyword-beg-re
2295 (regexp-opt 2370 (regexp-opt ruby-builtin-methods-with-reqs 'symbols))
2296 '( ;; built-in methods on Kernel
2297 "at_exit"
2298 "autoload"
2299 "autoload?"
2300 "callcc"
2301 "catch"
2302 "eval"
2303 "exec"
2304 "format"
2305 "lambda"
2306 "load"
2307 "loop"
2308 "open"
2309 "p"
2310 "printf"
2311 "proc"
2312 "putc"
2313 "require"
2314 "require_relative"
2315 "spawn"
2316 "sprintf"
2317 "syscall"
2318 "system"
2319 "throw"
2320 "trace_var"
2321 "trap"
2322 "untrace_var"
2323 "warn"
2324 ;; keyword-like private methods on Module
2325 "alias_method"
2326 "attr"
2327 "attr_accessor"
2328 "attr_reader"
2329 "attr_writer"
2330 "define_method"
2331 "extend"
2332 "include"
2333 "module_function"
2334 "prepend"
2335 "private_class_method"
2336 "private_constant"
2337 "public_class_method"
2338 "public_constant"
2339 "refine"
2340 "using")
2341 'symbols))
2342 (1 (unless (looking-at " *\\(?:[]|,.)}=]\\|$\\)") 2371 (1 (unless (looking-at " *\\(?:[]|,.)}=]\\|$\\)")
2343 font-lock-builtin-face))) 2372 font-lock-builtin-face)))
2344 ;; Kernel methods that have no required arguments. 2373 ;; Kernel methods that have no required arguments.
2345 (,(concat 2374 (,(concat
2346 ruby-font-lock-keyword-beg-re 2375 ruby-font-lock-keyword-beg-re
2347 (regexp-opt 2376 (regexp-opt ruby-builtin-methods-no-reqs 'symbols))
2348 '("__callee__"
2349 "__dir__"
2350 "__method__"
2351 "abort"
2352 "binding"
2353 "block_given?"
2354 "caller"
2355 "exit"
2356 "exit!"
2357 "fail"
2358 "fork"
2359 "global_variables"
2360 "local_variables"
2361 "print"
2362 "private"
2363 "protected"
2364 "public"
2365 "puts"
2366 "raise"
2367 "rand"
2368 "readline"
2369 "readlines"
2370 "sleep"
2371 "srand")
2372 'symbols))
2373 (1 font-lock-builtin-face)) 2377 (1 font-lock-builtin-face))
2374 ;; Here-doc beginnings. 2378 ;; Here-doc beginnings.
2375 (,ruby-here-doc-beg-re 2379 (,ruby-here-doc-beg-re
diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el
index f0337775d51..edadb2fc3ee 100644
--- a/lisp/progmodes/ruby-ts-mode.el
+++ b/lisp/progmodes/ruby-ts-mode.el
@@ -5,6 +5,7 @@
5;; Author: Perry Smith <pedz@easesoftware.com> 5;; Author: Perry Smith <pedz@easesoftware.com>
6;; Created: December 2022 6;; Created: December 2022
7;; Keywords: ruby languages tree-sitter 7;; Keywords: ruby languages tree-sitter
8;; Version: 0.2
8 9
9;; This file is part of GNU Emacs. 10;; This file is part of GNU Emacs.
10 11
@@ -50,11 +51,11 @@
50 51
51;; Currently tree treesit-font-lock-feature-list is set with the 52;; Currently tree treesit-font-lock-feature-list is set with the
52;; following levels: 53;; following levels:
53;; 1: comment method-definition 54;; 1: comment method-definition parameter-definition
54;; 2: keyword regexp string type 55;; 2: keyword regexp string type
55;; 3: builtin-variable builtin-constant constant 56;; 3: builtin-variable builtin-constant builtin-function
56;; delimiter escape-sequence 57;; delimiter escape-sequence
57;; global instance 58;; constant global instance
58;; interpolation literal symbol assignment 59;; interpolation literal symbol assignment
59;; 4: bracket error function operator punctuation 60;; 4: bracket error function operator punctuation
60 61
@@ -71,6 +72,8 @@
71;; ruby-ts-mode tries to adhere to the indentation related user 72;; ruby-ts-mode tries to adhere to the indentation related user
72;; options from ruby-mode, such as ruby-indent-level, 73;; options from ruby-mode, such as ruby-indent-level,
73;; ruby-indent-tabs-mode, and so on. 74;; ruby-indent-tabs-mode, and so on.
75;;
76;; Type 'M-x customize-group RET ruby RET' to see the options.
74 77
75;; * IMenu 78;; * IMenu
76;; * Navigation 79;; * Navigation
@@ -114,21 +117,30 @@
114 "Ruby's punctuation characters.") 117 "Ruby's punctuation characters.")
115 118
116(defvar ruby-ts--predefined-constants 119(defvar ruby-ts--predefined-constants
117 (rx (or "ARGF" "ARGV" "DATA" "ENV" "RUBY_COPYRIGHT" 120 (rx string-start
121 (or "ARGF" "ARGV" "DATA" "ENV" "RUBY_COPYRIGHT"
118 "RUBY_DESCRIPTION" "RUBY_ENGINE" "RUBY_ENGINE_VERSION" 122 "RUBY_DESCRIPTION" "RUBY_ENGINE" "RUBY_ENGINE_VERSION"
119 "RUBY_PATCHLEVEL" "RUBY_PLATFORM" "RUBY_RELEASE_DATE" 123 "RUBY_PATCHLEVEL" "RUBY_PLATFORM" "RUBY_RELEASE_DATE"
120 "RUBY_REVISION" "RUBY_VERSION" "STDERR" "STDIN" "STDOUT" 124 "RUBY_REVISION" "RUBY_VERSION" "STDERR" "STDIN" "STDOUT"
121 "TOPLEVEL_BINDING")) 125 "TOPLEVEL_BINDING")
126 string-end)
122 "Ruby predefined global constants.") 127 "Ruby predefined global constants.")
123 128
124(defvar ruby-ts--predefined-variables 129(defvar ruby-ts--predefined-variables
125 (rx (or "$!" "$@" "$~" "$&" "$‘" "$‘" "$+" "$=" "$/" "$\\" "$," "$;" 130 (rx string-start
131 (or "$!" "$@" "$~" "$&" "$‘" "$‘" "$+" "$=" "$/" "$\\" "$," "$;"
126 "$." "$<" "$>" "$_" "$*" "$$" "$?" "$:" "$LOAD_PATH" 132 "$." "$<" "$>" "$_" "$*" "$$" "$?" "$:" "$LOAD_PATH"
127 "$LOADED_FEATURES" "$DEBUG" "$FILENAME" "$stderr" "$stdin" 133 "$LOADED_FEATURES" "$DEBUG" "$FILENAME" "$stderr" "$stdin"
128 "$stdout" "$VERBOSE" "$-a" "$-i" "$-l" "$-p" 134 "$stdout" "$VERBOSE" "$-a" "$-i" "$-l" "$-p"
129 (seq "$" (+ digit)))) 135 "$0" "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9")
136 string-end)
130 "Ruby predefined global variables.") 137 "Ruby predefined global variables.")
131 138
139(defvar ruby-ts--builtin-methods
140 (format "\\`%s\\'" (regexp-opt (append ruby-builtin-methods-no-reqs
141 ruby-builtin-methods-with-reqs)))
142 "Ruby built-in methods.")
143
132(defconst ruby-ts--class-or-module-regex 144(defconst ruby-ts--class-or-module-regex
133 (rx string-start 145 (rx string-start
134 (or "class" "module" "singleton_class") 146 (or "class" "module" "singleton_class")
@@ -197,6 +209,9 @@ values of OVERRIDE"
197 (treesit-fontify-with-override (max plus-1 start) (min node-end end) 209 (treesit-fontify-with-override (max plus-1 start) (min node-end end)
198 font-lock-comment-face override))) 210 font-lock-comment-face override)))
199 211
212(defun ruby-ts--builtin-method-p (node)
213 (string-match-p ruby-ts--builtin-methods (treesit-node-text node t)))
214
200(defun ruby-ts--font-lock-settings (language) 215(defun ruby-ts--font-lock-settings (language)
201 "Tree-sitter font-lock settings for Ruby." 216 "Tree-sitter font-lock settings for Ruby."
202 (treesit-font-lock-rules 217 (treesit-font-lock-rules
@@ -322,6 +337,11 @@ values of OVERRIDE"
322 (in_clause 337 (in_clause
323 pattern: (identifier) @font-lock-variable-name-face)) 338 pattern: (identifier) @font-lock-variable-name-face))
324 339
340 :language language
341 :feature 'builtin-function
342 `((((identifier) @font-lock-builtin-face)
343 (:pred ruby-ts--builtin-method-p @font-lock-builtin-face)))
344
325 ;; Yuan recommends also putting method definitions into the 345 ;; Yuan recommends also putting method definitions into the
326 ;; 'function' category (thus keeping it in both). I've opted to 346 ;; 'function' category (thus keeping it in both). I've opted to
327 ;; just use separate categories for them -- dgutov. 347 ;; just use separate categories for them -- dgutov.
@@ -535,7 +555,7 @@ a statement container is a node that matches
535 (let ((common 555 (let ((common
536 `( 556 `(
537 ;; Slam all top level nodes to the left margin 557 ;; Slam all top level nodes to the left margin
538 ((parent-is "program") parent 0) 558 ((parent-is "program") point-min 0)
539 559
540 ;; Do not indent here docs or the end. Not sure why it 560 ;; Do not indent here docs or the end. Not sure why it
541 ;; takes the grand-parent but ok fine. 561 ;; takes the grand-parent but ok fine.
@@ -1034,14 +1054,28 @@ leading double colon is not added."
1034 (setq-local treesit-font-lock-feature-list 1054 (setq-local treesit-font-lock-feature-list
1035 '(( comment method-definition parameter-definition) 1055 '(( comment method-definition parameter-definition)
1036 ( keyword regexp string type) 1056 ( keyword regexp string type)
1037 ( builtin-variable builtin-constant constant 1057 ( builtin-variable builtin-constant builtin-function
1038 delimiter escape-sequence 1058 delimiter escape-sequence
1039 global instance 1059 constant global instance
1040 interpolation literal symbol assignment) 1060 interpolation literal symbol assignment)
1041 ( bracket error function operator punctuation))) 1061 ( bracket error function operator punctuation)))
1042 1062
1043 (treesit-major-mode-setup)) 1063 (treesit-major-mode-setup))
1044 1064
1065(if (treesit-ready-p 'ruby)
1066 ;; Copied from ruby-mode.el.
1067 (add-to-list 'auto-mode-alist
1068 (cons (concat "\\(?:\\.\\(?:"
1069 "rbw?\\|ru\\|rake\\|thor"
1070 "\\|jbuilder\\|rabl\\|gemspec\\|podspec"
1071 "\\)"
1072 "\\|/"
1073 "\\(?:Gem\\|Rake\\|Cap\\|Thor"
1074 "\\|Puppet\\|Berks\\|Brew"
1075 "\\|Vagrant\\|Guard\\|Pod\\)file"
1076 "\\)\\'")
1077 'ruby-ts-mode)))
1078
1045(provide 'ruby-ts-mode) 1079(provide 'ruby-ts-mode)
1046 1080
1047;;; ruby-ts-mode.el ends here 1081;;; ruby-ts-mode.el ends here
diff --git a/lisp/progmodes/rust-ts-mode.el b/lisp/progmodes/rust-ts-mode.el
index 7536726165e..08590ae6a86 100644
--- a/lisp/progmodes/rust-ts-mode.el
+++ b/lisp/progmodes/rust-ts-mode.el
@@ -276,9 +276,6 @@ Return nil if there is no name or if NODE is not a defun node."
276 (treesit-node-child-by-field-name node "name") t)))) 276 (treesit-node-child-by-field-name node "name") t))))
277 277
278;;;###autoload 278;;;###autoload
279(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))
280
281;;;###autoload
282(define-derived-mode rust-ts-mode prog-mode "Rust" 279(define-derived-mode rust-ts-mode prog-mode "Rust"
283 "Major mode for editing Rust, powered by tree-sitter." 280 "Major mode for editing Rust, powered by tree-sitter."
284 :group 'rust 281 :group 'rust
@@ -322,6 +319,9 @@ Return nil if there is no name or if NODE is not a defun node."
322 319
323 (treesit-major-mode-setup))) 320 (treesit-major-mode-setup)))
324 321
322(if (treesit-ready-p 'rust)
323 (add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode)))
324
325(provide 'rust-ts-mode) 325(provide 'rust-ts-mode)
326 326
327;;; rust-ts-mode.el ends here 327;;; rust-ts-mode.el ends here
diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el
index 69e4746bcc4..9212d2c590d 100644
--- a/lisp/progmodes/typescript-ts-mode.el
+++ b/lisp/progmodes/typescript-ts-mode.el
@@ -69,7 +69,7 @@
69 "Rules used for indentation. 69 "Rules used for indentation.
70Argument LANGUAGE is either `typescript' or `tsx'." 70Argument LANGUAGE is either `typescript' or `tsx'."
71 `((,language 71 `((,language
72 ((parent-is "program") parent-bol 0) 72 ((parent-is "program") point-min 0)
73 ((node-is "}") parent-bol 0) 73 ((node-is "}") parent-bol 0)
74 ((node-is ")") parent-bol 0) 74 ((node-is ")") parent-bol 0)
75 ((node-is "]") parent-bol 0) 75 ((node-is "]") parent-bol 0)
@@ -361,12 +361,6 @@ See `treesit-sentence-type-regexp' for more information.")
361See `treesit-sexp-type-regexp' for more information.") 361See `treesit-sexp-type-regexp' for more information.")
362 362
363;;;###autoload 363;;;###autoload
364(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))
365
366;;;###autoload
367(add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode))
368
369;;;###autoload
370(define-derived-mode typescript-ts-base-mode prog-mode "TypeScript" 364(define-derived-mode typescript-ts-base-mode prog-mode "TypeScript"
371 "Major mode for editing TypeScript." 365 "Major mode for editing TypeScript."
372 :group 'typescript 366 :group 'typescript
@@ -432,6 +426,9 @@ See `treesit-sexp-type-regexp' for more information.")
432 426
433 (treesit-major-mode-setup))) 427 (treesit-major-mode-setup)))
434 428
429(if (treesit-ready-p 'typescript)
430 (add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode)))
431
435;;;###autoload 432;;;###autoload
436(define-derived-mode tsx-ts-mode typescript-ts-base-mode "TypeScript[TSX]" 433(define-derived-mode tsx-ts-mode typescript-ts-base-mode "TypeScript[TSX]"
437 "Major mode for editing TypeScript." 434 "Major mode for editing TypeScript."
@@ -479,6 +476,9 @@ See `treesit-sexp-type-regexp' for more information.")
479 476
480 (treesit-major-mode-setup))) 477 (treesit-major-mode-setup)))
481 478
479(if (treesit-ready-p 'tsx)
480 (add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode)))
481
482(provide 'typescript-ts-mode) 482(provide 'typescript-ts-mode)
483 483
484;;; typescript-ts-mode.el ends here 484;;; typescript-ts-mode.el ends here
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index 8991610a50f..a1d7d4bbbec 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -1827,7 +1827,9 @@ can also be used to fill comments.
1827 (setq-local treesit-simple-imenu-settings 1827 (setq-local treesit-simple-imenu-settings
1828 `(( nil ,(rx bos (or "rule_set" "media_statement") eos) 1828 `(( nil ,(rx bos (or "rule_set" "media_statement") eos)
1829 nil nil))) 1829 nil nil)))
1830 (treesit-major-mode-setup))) 1830 (treesit-major-mode-setup)
1831
1832 (add-to-list 'auto-mode-alist '("\\.css\\'" . css-ts-mode))))
1831 1833
1832;;;###autoload 1834;;;###autoload
1833(define-derived-mode css-mode css-base-mode "CSS" 1835(define-derived-mode css-mode css-base-mode "CSS"
diff --git a/lisp/textmodes/toml-ts-mode.el b/lisp/textmodes/toml-ts-mode.el
index 2430c5f3e76..416542084f1 100644
--- a/lisp/textmodes/toml-ts-mode.el
+++ b/lisp/textmodes/toml-ts-mode.el
@@ -117,8 +117,6 @@ Return nil if there is no name or if NODE is not a defun node."
117 (or (treesit-node-text (treesit-node-child node 1) t) 117 (or (treesit-node-text (treesit-node-child node 1) t)
118 "Root table")))) 118 "Root table"))))
119 119
120(add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode))
121
122;;;###autoload 120;;;###autoload
123(define-derived-mode toml-ts-mode text-mode "TOML" 121(define-derived-mode toml-ts-mode text-mode "TOML"
124 "Major mode for editing TOML, powered by tree-sitter." 122 "Major mode for editing TOML, powered by tree-sitter."
@@ -155,6 +153,9 @@ Return nil if there is no name or if NODE is not a defun node."
155 153
156 (treesit-major-mode-setup))) 154 (treesit-major-mode-setup)))
157 155
156(if (treesit-ready-p 'toml)
157 (add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode)))
158
158(provide 'toml-ts-mode) 159(provide 'toml-ts-mode)
159 160
160;;; toml-ts-mode.el ends here 161;;; toml-ts-mode.el ends here
diff --git a/lisp/textmodes/yaml-ts-mode.el b/lisp/textmodes/yaml-ts-mode.el
index 8c61ee062cf..a25230e6e61 100644
--- a/lisp/textmodes/yaml-ts-mode.el
+++ b/lisp/textmodes/yaml-ts-mode.el
@@ -118,9 +118,6 @@
118 "Tree-sitter font-lock settings for `yaml-ts-mode'.") 118 "Tree-sitter font-lock settings for `yaml-ts-mode'.")
119 119
120;;;###autoload 120;;;###autoload
121(add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-ts-mode))
122
123;;;###autoload
124(define-derived-mode yaml-ts-mode text-mode "YAML" 121(define-derived-mode yaml-ts-mode text-mode "YAML"
125 "Major mode for editing YAML, powered by tree-sitter." 122 "Major mode for editing YAML, powered by tree-sitter."
126 :group 'yaml 123 :group 'yaml
@@ -146,6 +143,9 @@
146 143
147 (treesit-major-mode-setup))) 144 (treesit-major-mode-setup)))
148 145
146(if (treesit-ready-p 'yaml)
147 (add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-ts-mode)))
148
149(provide 'yaml-ts-mode) 149(provide 'yaml-ts-mode)
150 150
151;;; yaml-ts-mode.el ends here 151;;; yaml-ts-mode.el ends here
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 9d622de5580..5fad6b21fae 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -987,7 +987,8 @@ If LOUDLY is non-nil, display some debugging information."
987 (end-time (current-time))) 987 (end-time (current-time)))
988 ;; If for any query the query time is strangely long, 988 ;; If for any query the query time is strangely long,
989 ;; switch to fast mode (see comments above). 989 ;; switch to fast mode (see comments above).
990 (when (and (> (time-to-seconds 990 (when (and (null treesit--font-lock-fast-mode)
991 (> (time-to-seconds
991 (time-subtract end-time start-time)) 992 (time-subtract end-time start-time))
992 0.01)) 993 0.01))
993 (if (> treesit--font-lock-fast-mode-grace-count 0) 994 (if (> treesit--font-lock-fast-mode-grace-count 0)
@@ -2702,6 +2703,11 @@ leaves point at the end of the last line of NODE."
2702 (when (not named) 2703 (when (not named)
2703 (overlay-put ov 'face 'treesit-explorer-anonymous-node))))) 2704 (overlay-put ov 'face 'treesit-explorer-anonymous-node)))))
2704 2705
2706(defun treesit--explorer-kill-explorer-buffer ()
2707 "Kill the explorer buffer of this buffer."
2708 (when (buffer-live-p treesit--explorer-buffer)
2709 (kill-buffer treesit--explorer-buffer)))
2710
2705(define-derived-mode treesit--explorer-tree-mode special-mode 2711(define-derived-mode treesit--explorer-tree-mode special-mode
2706 "TS Explorer" 2712 "TS Explorer"
2707 "Mode for displaying syntax trees for `treesit-explore-mode'." 2713 "Mode for displaying syntax trees for `treesit-explore-mode'."
@@ -2713,30 +2719,46 @@ Pops up a window showing the syntax tree of the source in the
2713current buffer in real time. The corresponding node enclosing 2719current buffer in real time. The corresponding node enclosing
2714the text in the active region is highlighted in the explorer 2720the text in the active region is highlighted in the explorer
2715window." 2721window."
2716 :lighter " TSplay" 2722 :lighter " TSexplore"
2717 (if treesit-explore-mode 2723 (if treesit-explore-mode
2718 (progn 2724 (let ((language (intern (completing-read
2719 (unless (buffer-live-p treesit--explorer-buffer)
2720 (setq-local treesit--explorer-buffer
2721 (get-buffer-create
2722 (format "*tree-sitter explorer for %s*"
2723 (buffer-name))))
2724 (setq-local treesit--explorer-language
2725 (intern (completing-read
2726 "Language: " 2725 "Language: "
2727 (mapcar #'treesit-parser-language 2726 (mapcar #'treesit-parser-language
2728 (treesit-parser-list))))) 2727 (treesit-parser-list))))))
2729 (with-current-buffer treesit--explorer-buffer 2728 (if (not (treesit-language-available-p language))
2730 (treesit--explorer-tree-mode))) 2729 (user-error "Cannot find tree-sitter grammar for %s: %s"
2731 (display-buffer treesit--explorer-buffer 2730 language (cdr (treesit-language-available-p
2732 (cons nil '((inhibit-same-window . t)))) 2731 language t)))
2733 (treesit--explorer-refresh) 2732 ;; Create explorer buffer.
2734 (add-hook 'post-command-hook 2733 (unless (buffer-live-p treesit--explorer-buffer)
2735 #'treesit--explorer-post-command 0 t) 2734 (setq-local treesit--explorer-buffer
2736 (setq-local treesit--explorer-last-node nil)) 2735 (get-buffer-create
2736 (format "*tree-sitter explorer for %s*"
2737 (buffer-name))))
2738 (setq-local treesit--explorer-language language)
2739 (with-current-buffer treesit--explorer-buffer
2740 (treesit--explorer-tree-mode)))
2741 (display-buffer treesit--explorer-buffer
2742 (cons nil '((inhibit-same-window . t))))
2743 (treesit--explorer-refresh)
2744 ;; Setup variables and hooks.
2745 (add-hook 'post-command-hook
2746 #'treesit--explorer-post-command 0 t)
2747 (add-hook 'kill-buffer-hook
2748 #'treesit--explorer-kill-explorer-buffer 0 t)
2749 (setq-local treesit--explorer-last-node nil)
2750 ;; Tell `desktop-save' to not save explorer buffers.
2751 (when (boundp 'desktop-modes-not-to-save)
2752 (unless (memq 'treesit--explorer-tree-mode
2753 desktop-modes-not-to-save)
2754 (push 'treesit--explorer-tree-mode
2755 desktop-modes-not-to-save)))))
2756 ;; Turn off explore mode.
2737 (remove-hook 'post-command-hook 2757 (remove-hook 'post-command-hook
2738 #'treesit--explorer-post-command t) 2758 #'treesit--explorer-post-command t)
2739 (kill-buffer treesit--explorer-buffer))) 2759 (remove-hook 'post-command-hook
2760 #'treesit--explorer-kill-explorer-buffer t)
2761 (treesit--explorer-kill-explorer-buffer)))
2740 2762
2741;;; Install & build language grammar 2763;;; Install & build language grammar
2742 2764
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent.erts b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
index 70fce68b0ec..b8524432d02 100644
--- a/test/lisp/progmodes/c-ts-mode-resources/indent.erts
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
@@ -92,6 +92,19 @@ int main()
92} 92}
93=-=-= 93=-=-=
94 94
95Name: Concecutive blocks (GNU Style) (bug#60873)
96
97=-=
98int
99main (int argc,
100 char *argv[])
101{
102 {
103 int i = 0;
104 }
105}
106=-=-=
107
95Name: Multiline Parameter List (bug#60398) 108Name: Multiline Parameter List (bug#60398)
96 109
97=-= 110=-=
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
index b7715a280a6..aa710519825 100644
--- a/test/src/keymap-tests.el
+++ b/test/src/keymap-tests.el
@@ -226,6 +226,7 @@ commit 86c19714b097aa477d339ed99ffb5136c755a046."
226 226
227(defun keymap-tests--command-1 () (interactive) nil) 227(defun keymap-tests--command-1 () (interactive) nil)
228(defun keymap-tests--command-2 () (interactive) nil) 228(defun keymap-tests--command-2 () (interactive) nil)
229(defun keymap-tests--command-3 () (interactive) nil)
229(put 'keymap-tests--command-1 :advertised-binding [?y]) 230(put 'keymap-tests--command-1 :advertised-binding [?y])
230 231
231(ert-deftest keymap-where-is-internal () 232(ert-deftest keymap-where-is-internal ()
@@ -430,6 +431,38 @@ g .. h foo
430 (make-non-key-event 'keymap-tests-event) 431 (make-non-key-event 'keymap-tests-event)
431 (should (equal (where-is-internal 'keymap-tests-command) '([3 103])))) 432 (should (equal (where-is-internal 'keymap-tests-command) '([3 103]))))
432 433
434(ert-deftest keymap-set-consistency ()
435 (let ((k (make-sparse-keymap)))
436 ;; `keymap-set' returns the binding, `keymap-set-after' doesn't,
437 ;; so we need to check for nil. <sigh>
438 (should (keymap-set k "a" "a"))
439 (should (equal (keymap-lookup k "a") (key-parse "a")))
440 (should-not (keymap-set-after k "b" "b"))
441 (should (equal (keymap-lookup k "b") (key-parse "b")))
442 (should-not (keymap-set-after k "d" "d" t))
443 (should (equal (keymap-lookup k "d") (key-parse "d")))
444 (should-not (keymap-set-after k "e" "e" nil))
445 (should (equal (keymap-lookup k "e") (key-parse "e")))
446 ;; This doesn't fail, but it does not add the 'f' binding after 'a'
447 (should-not (keymap-set-after k "f" "f" "a"))
448 (should (equal (keymap-lookup k "f") (key-parse "f")))))
449
450(ert-deftest keymap-set-after-menus ()
451 (let ((map (make-sparse-keymap)))
452 (keymap-set map "<cmd1>"
453 '(menu-item "Run Command 1" keymap-tests--command-1
454 :help "Command 1 Help"))
455 (keymap-set-after map "<cmd2>"
456 '(menu-item "Run Command 2" keymap-tests--command-2
457 :help "Command 2 Help"))
458 (keymap-set-after map "<cmd3>"
459 '(menu-item "Run Command 3" keymap-tests--command-3
460 :help "Command 3 Help")
461 'cmd1)
462 (should (equal (caadr map) 'cmd1))
463 (should (equal (caaddr map) 'cmd3))
464 (should (equal (caar (last map)) 'cmd2))))
465
433(ert-deftest keymap-test-duplicate-definitions () 466(ert-deftest keymap-test-duplicate-definitions ()
434 "Check that defvar-keymap rejects duplicate key definitions." 467 "Check that defvar-keymap rejects duplicate key definitions."
435 (should-error 468 (should-error