aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Kangas2023-01-19 06:30:25 +0100
committerStefan Kangas2023-01-19 06:30:25 +0100
commit9161a302c9f9fbfa1a8f33181bb332d2c5df3aa7 (patch)
tree21de62aa23f4ad770ff8afe322c0223ea7e0af76
parentefb9ec11bbee3871d77dc4e9217bd9293d525d5d (diff)
parentdb727873803a974ba210c4942ae7cbcc3d6268ab (diff)
downloademacs-9161a302c9f9fbfa1a8f33181bb332d2c5df3aa7.tar.gz
emacs-9161a302c9f9fbfa1a8f33181bb332d2c5df3aa7.zip
Merge from origin/emacs-29
db727873803 ruby-ts-mode: Use font-lock-constant-face for true/false/nil 819719330ad (ruby-ts--indent-rules): Add a rule for continuation of a... 94b9cbf96fb (ruby-ts--parent-call-or-bol): Handle more cases with nes... ba33b83ce4b (ruby-ts--statement-container-regexp): Remove "parenthesi... f2bedf695c1 ruby-ts-mode: Handle indent in parenless calls much close... 758ac5eabbe Fix split-window-below for the case when split-window-kee... 8e9783b4ce4 Rebind in read-regexp-map ‘M-c’ to ‘M-s c’ compatible wit... 78f93d92b28 * lisp/vc/vc-dir.el: Make keys ‘% m’ and ‘* %’ compatible... dc3f85fd4b0 Use proper types for Eshell warnings 6a8338a8bc8 ; Avoid byte-compiler warning in cc-fonts.el. 9186be20aeb ; Clarify doc strings of some functions in files.el bd5ef3ef95e Improve the documentation of 'auto-mode-alist' search 1798ff5a663 ; Fix minor mistakes in documentation faee7e1f1bd ; * lisp/treesit.el (treesit-font-lock-fontify-region): M... 24f0dfd3731 Revert "Revert "Add c-or-c++-ts-mode (bug#59613)"" ac3bc775b6f Make it harder to misactivate tree-sitter font-lock fast ... bdd82fa7977 ; * src/treesit.c: Remove unused boilerplate. 343b9b3dfe3 ruby-ts-mode: Obey the option ruby-method-call-indent 045404d1aac ruby-ts-mode: Obey the option ruby-after-operator-indent 300ca6ac372 ruby-ts-mode: Fix indent after operator or conditional ac5516bd7d5 ruby-ts-mode: Fix/change indentation of a continuation me... 5e2e68a0c2d ruby-ts-mode: Fix indent inside parenthesized_expr and el... 9ed9ff4690a ruby-ts-mode: Fix the rules for hanging arrays and hashes c4f0b6ccea1 Add more detail about how to invoke Eshell commands dbac923b9df CC Mode: On removal of "typedef", remove pertinent types ... 56d69c2fc47 ; Relax timeouts for failing ERC test 183e7492702 Don't preserve non-module minor modes in erc-open 7b8322f6285 Use correct buffer for local-module vars in erc-open 7b13422298a ; Avoid plist-get as generalized var in erc-compat 09e9d7c7496 Fix display of warnings on w32 console bd094207c76 Fix buffer-list-update-hook for indirect buffers 9e7a5d58eea ; Fix tree-sitter indent anchor preset 7c61a304104 Fix treesit-node-first-child-for-pos (bug#60127) b36cc7e7bbb ; * src/treesit.c (Ftreesit_induce_sparse_tree): Minor ch... # Conflicts: # etc/NEWS
-rw-r--r--doc/emacs/maintaining.texi9
-rw-r--r--doc/emacs/modes.texi13
-rw-r--r--doc/lispref/minibuf.texi2
-rw-r--r--doc/lispref/strings.texi4
-rw-r--r--doc/misc/eshell.texi136
-rw-r--r--etc/NEWS.299
-rw-r--r--lisp/emacs-lisp/cl-macs.el2
-rw-r--r--lisp/emacs-lisp/warnings.el8
-rw-r--r--lisp/erc/erc-common.el13
-rw-r--r--lisp/erc/erc-compat.el4
-rw-r--r--lisp/erc/erc.el26
-rw-r--r--lisp/eshell/em-basic.el3
-rw-r--r--lisp/eshell/esh-var.el7
-rw-r--r--lisp/files.el20
-rw-r--r--lisp/progmodes/c-ts-mode.el44
-rw-r--r--lisp/progmodes/cc-defs.el22
-rw-r--r--lisp/progmodes/cc-engine.el40
-rw-r--r--lisp/progmodes/cc-fonts.el66
-rw-r--r--lisp/progmodes/cc-mode.el40
-rw-r--r--lisp/progmodes/ruby-ts-mode.el162
-rw-r--r--lisp/replace.el6
-rw-r--r--lisp/treesit.el34
-rw-r--r--lisp/vc/vc-dir.el8
-rw-r--r--lisp/window.el12
-rw-r--r--src/buffer.c10
-rw-r--r--src/treesit.c66
-rw-r--r--test/lisp/erc/erc-scenarios-base-local-modules.el100
-rw-r--r--test/lisp/erc/erc-tests.el41
-rw-r--r--test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld10
-rw-r--r--test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld10
-rw-r--r--test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb94
-rw-r--r--test/lisp/progmodes/ruby-ts-mode-tests.el6
-rw-r--r--test/src/buffer-tests.el46
33 files changed, 808 insertions, 265 deletions
diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index 8c77ded55d3..5191bb2918d 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -1331,11 +1331,18 @@ point is on a directory entry, mark all files in that directory tree
1331listed files and directories. 1331listed files and directories.
1332 1332
1333@findex vc-dir-mark-by-regexp 1333@findex vc-dir-mark-by-regexp
1334@item % 1334@item % m
1335@itemx * %
1335You can use this command to mark files by regexp 1336You can use this command to mark files by regexp
1336(@code{vc-dir-mark-by-regexp}). If given a prefix, unmark files 1337(@code{vc-dir-mark-by-regexp}). If given a prefix, unmark files
1337instead. 1338instead.
1338 1339
1340@findex vc-dir-mark-registered-files
1341@item * r
1342You can use this command to mark files that are in one of registered
1343states, including edited, added or removed.
1344(@code{vc-dir-mark-registered-files}).
1345
1339@item G 1346@item G
1340Add the file under point to the list of files that the VC should 1347Add the file under point to the list of files that the VC should
1341ignore (@code{vc-dir-ignore}). For instance, if the VC is Git, it 1348ignore (@code{vc-dir-ignore}). For instance, if the VC is Git, it
diff --git a/doc/emacs/modes.texi b/doc/emacs/modes.texi
index d0eacce0842..06f9929092c 100644
--- a/doc/emacs/modes.texi
+++ b/doc/emacs/modes.texi
@@ -430,10 +430,15 @@ For example, one element normally found in the list has the form
430mode for files whose names end in @file{.c}. (Note that @samp{\\} is 430mode for files whose names end in @file{.c}. (Note that @samp{\\} is
431needed in Lisp syntax to include a @samp{\} in the string, which must 431needed in Lisp syntax to include a @samp{\} in the string, which must
432be used to suppress the special meaning of @samp{.} in regexps.) If 432be used to suppress the special meaning of @samp{.} in regexps.) If
433the element has the form @code{(@var{regexp} @var{mode-function} 433the element has the form @w{@code{(@var{regexp} @var{mode-function}
434@var{flag})} and @var{flag} is non-@code{nil}, then after calling 434@var{flag})}} and @var{flag} is non-@code{nil}, then after calling
435@var{mode-function}, Emacs discards the suffix that matched 435@var{mode-function} (if it is non-@code{nil}), Emacs discards the
436@var{regexp} and searches the list again for another match. 436suffix that matched @var{regexp} and searches the list again for
437another match. This ``recursive extension stripping'' is used for
438files which have multiple extensions, and the ``outer'' extension
439hides the ``inner'' one that actually specifies the right mode. For
440example, backup files and GPG-encrypted files with @file{.gpg}
441extension use this feature.
437 442
438@vindex auto-mode-case-fold 443@vindex auto-mode-case-fold
439 On GNU/Linux and other systems with case-sensitive file names, Emacs 444 On GNU/Linux and other systems with case-sensitive file names, Emacs
diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi
index 18125c372ce..114e5d38a80 100644
--- a/doc/lispref/minibuf.texi
+++ b/doc/lispref/minibuf.texi
@@ -312,7 +312,7 @@ to @code{regexp-history}.
312 312
313@cindex @code{case-fold}, text property 313@cindex @code{case-fold}, text property
314@findex read-regexp-case-fold-search 314@findex read-regexp-case-fold-search
315The user can use the @kbd{M-c} command to indicate whether case 315The user can use the @kbd{M-s c} command to indicate whether case
316folding should be on or off. If the user has used this command, the 316folding should be on or off. If the user has used this command, the
317returned string will have the text property @code{case-fold} set to 317returned string will have the text property @code{case-fold} set to
318either @code{fold} or @code{inhibit-fold}. It is up to the caller of 318either @code{fold} or @code{inhibit-fold}. It is up to the caller of
diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index ca18f0a9cc1..3d86a87516b 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -911,8 +911,8 @@ This function returns a new string containing one character,
911@end defun 911@end defun
912 912
913@defun string-to-char string 913@defun string-to-char string
914 This function returns the first character in @var{string}. This 914 This function returns the first character in @var{string}. This is
915mostly identical to @code{(aref string 0)}, except that it returns 0 915mostly identical to @w{@code{(aref string 0)}}, except that it returns 0
916if the string is empty. (The value is also 0 when the first character 916if the string is empty. (The value is also 0 when the first character
917of @var{string} is the null character, @acronym{ASCII} code 0.) This 917of @var{string} is the null character, @acronym{ASCII} code 0.) This
918function may be eliminated in the future if it does not seem useful 918function may be eliminated in the future if it does not seem useful
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index c40ff58f42c..57a2020fdca 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -64,10 +64,11 @@ modify this GNU manual.''
64 64
65Eshell is a shell-like command interpreter implemented in Emacs Lisp. 65Eshell is a shell-like command interpreter implemented in Emacs Lisp.
66It invokes no external processes except for those requested by the 66It invokes no external processes except for those requested by the
67user. It is intended to be an alternative to the IELM (@pxref{Lisp Interaction, Emacs Lisp Interaction, , emacs, The Emacs Editor}) 67user. It is intended to be an alternative to the IELM (@pxref{Lisp
68REPL for Emacs @emph{and} with an interface similar to command shells 68Interaction, Emacs Lisp Interaction, , emacs, The Emacs Editor})
69such as @command{bash}, @command{zsh}, @command{rc}, or 69REPL@footnote{Short for ``Read-Eval-Print Loop''.} for Emacs
70@command{4dos}. 70@emph{and} with an interface similar to command shells such as
71@command{bash}, @command{zsh}, @command{rc}, or @command{4dos}.
71@c This manual is updated to release 2.4 of Eshell. 72@c This manual is updated to release 2.4 of Eshell.
72 73
73@insertcopying 74@insertcopying
@@ -193,6 +194,13 @@ In a command shell, everything is done by invoking commands. This
193chapter covers command invocations in Eshell, including the command 194chapter covers command invocations in Eshell, including the command
194history and invoking commands in a script file. 195history and invoking commands in a script file.
195 196
197Unlike regular system shells, Eshell never invokes kernel functions
198directly, such as @code{exec(3)}. Instead, it uses the Lisp functions
199available in the Emacs Lisp library. It does this by transforming the
200input line into a callable Lisp form.@footnote{To see the Lisp form
201that will be invoked, type this as the Eshell prompt:
202@kbd{eshell-parse-command 'echo hello'}}
203
196@menu 204@menu
197* Invocation:: 205* Invocation::
198* Arguments:: 206* Arguments::
@@ -207,23 +215,16 @@ history and invoking commands in a script file.
207 215
208@node Invocation 216@node Invocation
209@section Invocation 217@section Invocation
210Unlike regular system shells, Eshell never invokes kernel functions 218Eshell is both a command shell and an Emacs Lisp @acronym{REPL}. As a
211directly, such as @code{exec(3)}. Instead, it uses the Lisp functions 219result, you can invoke commands in two different ways: in @dfn{command
212available in the Emacs Lisp library. It does this by transforming the 220form} or in @dfn{lisp form}.
213input line into a callable Lisp form.@footnote{To see the Lisp form that will be invoked, type: @samp{eshell-parse-command "echo hello"}}
214 221
215The command can be either an Elisp function or an external command. 222You can use the semicolon (@code{;}) to separate multiple command
216Eshell looks first for an alias (@pxref{Aliases}) with the same name as the 223invocations on a single line, executing each in turn. You can also
217command, then a built-in (@pxref{Built-ins}) or a function with the 224separate commands with @code{&&} or @code{||}. When using @code{&&},
218same name; if there is no match, it then tries to execute it as an 225Eshell will execute the second command only if the first succeeds
219external command. 226(i.e.@: has an exit status of 0); with @code{||}, Eshell will execute
220 227the second command only if the first fails.
221The semicolon (@code{;}) can be used to separate multiple command
222invocations on a single line. You can also separate commands with
223@code{&&} or @code{||}. When using @code{&&}, Eshell will execute the
224second command only if the first succeeds (i.e.@: has an exit
225status of 0); with @code{||}, Eshell will execute the second command
226only if the first fails.
227 228
228A command invocation followed by an ampersand (@code{&}) will be run 229A command invocation followed by an ampersand (@code{&}) will be run
229in the background. Eshell has no job control, so you can not suspend 230in the background. Eshell has no job control, so you can not suspend
@@ -232,12 +233,80 @@ the foreground. That said, background processes invoked from Eshell
232can be controlled the same way as any other background process in 233can be controlled the same way as any other background process in
233Emacs. 234Emacs.
234 235
236@subsection Command form
237Command form looks much the same as in other shells. A command
238consists of arguments separated by spaces; the first argument is the
239command to run, with any subsequent arguments being passed to that
240command.
241
242@example
243~ $ echo hello
244hello
245@end example
246
247@cindex order of looking for commands
248@cindex command lookup order
249The command can be either an Elisp function or an external command.
250Eshell looks for the command in the following order:
251
252@enumerate
253@item
254As a command alias (@pxref{Aliases})
255
256@item
257As a built-in command (@pxref{Built-ins})
258
259@item
260As an external program
261
262@item
263As an ordinary Lisp function
264@end enumerate
265
266@vindex eshell-prefer-lisp-functions
267If you would prefer to use ordinary Lisp functions over external
268programs, set the option @code{eshell-prefer-lisp-functions} to
269@code{t}. This will swap the lookup order of the last two items.
270
271You can also group command forms together into a subcommand with curly
272braces (@code{@{@}}). This lets you use the output of a subcommand as
273an argument to another command, or within control flow statements
274(@pxref{Control Flow}).
275
276@example
277~ $ echo @{echo hello; echo there@}
278hellothere
279@end example
280
281@subsection Lisp form
282Lisp form looks like ordinary Emacs Lisp code, because that's what it
283is. As a result, you can use any syntax normally available to an
284Emacs Lisp program (@pxref{Top, , , elisp, The Emacs Lisp Reference
285Manual}).
286
287@example
288~ $ (format "hello, %s" user-login-name)
289hello, user
290@end example
291
292In addition, you can @emph{combine} command forms and Lisp forms
293together into single statements, letting you use whatever form is the
294most convenient for expressing your intentions.
295
296@example
297~ $ ls *.patch > (format-time-string "%F.log")
298@end example
299
300This command writes a list of all files matching the glob pattern
301@code{*.patch} (@pxref{Globbing}) to a file named
302@code{@var{current-date}.log} (@pxref{Redirection}).
303
235@node Arguments 304@node Arguments
236@section Arguments 305@section Arguments
237Ordinarily, command arguments are parsed by Eshell as either strings 306Ordinarily, Eshell parses arguments in command form as either strings
238or numbers, depending on what the parser thinks they look like. To 307or numbers, depending on what the parser thinks they look like. To
239specify an argument of some other data type, you can use an 308specify an argument of some other data type, you can use a Lisp form
240@ref{Dollars Expansion, Elisp expression}: 309(@pxref{Invocation}):
241 310
242@example 311@example
243~ $ echo (list 1 2 3) 312~ $ echo (list 1 2 3)
@@ -354,10 +423,6 @@ eshell/sudo is a compiled Lisp function in `em-tramp.el'.
354sudo is an alias, defined as "*sudo $@@*" 423sudo is an alias, defined as "*sudo $@@*"
355@end example 424@end example
356 425
357@vindex eshell-prefer-lisp-functions
358If you would prefer to use the built-in commands instead of the external
359commands, set @code{eshell-prefer-lisp-functions} to @code{t}.
360
361Some of the built-in commands have different behavior from their 426Some of the built-in commands have different behavior from their
362external counterparts, and some have no external counterpart. Most of 427external counterparts, and some have no external counterpart. Most of
363these will print a usage message when given the @code{--help} option. 428these will print a usage message when given the @code{--help} option.
@@ -923,15 +988,14 @@ For example, you could handle a subset of the options for the
923@node Variables 988@node Variables
924@section Variables 989@section Variables
925@vindex eshell-prefer-lisp-variables 990@vindex eshell-prefer-lisp-variables
926Since Eshell is a combination of an Emacs @acronym{REPL}@footnote{ 991Since Eshell is a combination of an Emacs @acronym{REPL} and a command
927Short for ``Read-Eval-Print Loop''. 992shell, it can refer to variables from two different sources: ordinary
928} and a command shell, it can refer to variables from two different 993Emacs Lisp variables, as well as environment variables. By default,
929sources: ordinary Emacs Lisp variables, as well as environment 994when using a variable in Eshell, it will first look in the list of
930variables. By default, when using a variable in Eshell, it will first 995built-in variables, then in the list of environment variables, and
931look in the list of built-in variables, then in the list of 996finally in the list of Lisp variables. If you would prefer to use
932environment variables, and finally in the list of Lisp variables. If 997Lisp variables over environment variables, you can set
933you would prefer to use Lisp variables over environment variables, you 998@code{eshell-prefer-lisp-variables} to @code{t}.
934can set @code{eshell-prefer-lisp-variables} to @code{t}.
935 999
936You can set variables in a few different ways. To set a Lisp 1000You can set variables in a few different ways. To set a Lisp
937variable, you can use the command @samp{setq @var{name} @var{value}}, 1001variable, you can use the command @samp{setq @var{name} @var{value}},
diff --git a/etc/NEWS.29 b/etc/NEWS.29
index d1ddd0194c1..9f735bec443 100644
--- a/etc/NEWS.29
+++ b/etc/NEWS.29
@@ -2079,7 +2079,7 @@ The VC Directory buffer now uses the prefix 'b' for these branch-related
2079commands. 2079commands.
2080 2080
2081+++ 2081+++
2082*** New command '%' ('vc-dir-mark-by-regexp'). 2082*** New command 'vc-dir-mark-by-regexp' bound to '% m' and '* %'.
2083This command marks files based on a regexp. If given a prefix 2083This command marks files based on a regexp. If given a prefix
2084argument, unmark instead. 2084argument, unmark instead.
2085 2085
@@ -3236,6 +3236,11 @@ An optional major mode based on the tree-sitter library for editing
3236programs in the C++ language. 3236programs in the C++ language.
3237 3237
3238+++ 3238+++
3239*** New command 'c-or-c++-ts-mode'.
3240A command that automatically guesses the language of a header file,
3241and enables either 'c-ts-mode' or 'c++-ts-mode' accordingly.
3242
3243+++
3239*** New major mode 'java-ts-mode'. 3244*** New major mode 'java-ts-mode'.
3240An optional major mode based on the tree-sitter library for editing 3245An optional major mode based on the tree-sitter library for editing
3241programs in the Java language. 3246programs in the Java language.
@@ -3802,7 +3807,7 @@ These function now take an optional comparison PREDICATE argument.
3802** 'read-multiple-choice' can now use long-form answers. 3807** 'read-multiple-choice' can now use long-form answers.
3803 3808
3804+++ 3809+++
3805** 'M-c' in 'read-regexp' now toggles case folding. 3810** 'M-s c' in 'read-regexp' now toggles case folding.
3806 3811
3807+++ 3812+++
3808** 'completing-read' now allows a function as its REQUIRE-MATCH argument. 3813** 'completing-read' now allows a function as its REQUIRE-MATCH argument.
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 36aab087d94..cffe8b09f53 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2811,7 +2811,7 @@ values. Note that this macro is *not* available in Common Lisp.
2811As a special case, if `(PLACE)' is used instead of `(PLACE VALUE)', 2811As a special case, if `(PLACE)' is used instead of `(PLACE VALUE)',
2812the PLACE is not modified before executing BODY. 2812the PLACE is not modified before executing BODY.
2813 2813
2814See info node `(cl) Function Bindings' for details. 2814See info node `(cl) Modify Macros' for details.
2815 2815
2816\(fn ((PLACE VALUE) ...) BODY...)" 2816\(fn ((PLACE VALUE) ...) BODY...)"
2817 (declare (indent 1) (debug ((&rest [&or (symbolp form) 2817 (declare (indent 1) (debug ((&rest [&or (symbolp form)
diff --git a/lisp/emacs-lisp/warnings.el b/lisp/emacs-lisp/warnings.el
index 9505c935816..31b840d6c83 100644
--- a/lisp/emacs-lisp/warnings.el
+++ b/lisp/emacs-lisp/warnings.el
@@ -204,8 +204,12 @@ SUPPRESS-LIST is the list of kinds of warnings to suppress."
204 some-match)) 204 some-match))
205 205
206(define-icon warnings-suppress button 206(define-icon warnings-suppress button
207 '((emoji "⛔") 207 `((emoji "⛔")
208 (symbol " ■ ") 208 ;; Many MS-Windows console fonts don't have good glyphs for U+25A0.
209 (symbol ,(if (and (eq system-type 'windows-nt)
210 (null window-system))
211 " » "
212 " ■ "))
209 (text " stop ")) 213 (text " stop "))
210 "Suppress warnings." 214 "Suppress warnings."
211 :version "29.1" 215 :version "29.1"
diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index 9eb4f1a9000..994555acecf 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -202,12 +202,13 @@ if ARG is omitted or nil.
202 (,disable))) 202 (,disable)))
203 ,(erc--assemble-toggle local-p name enable mode t enable-body) 203 ,(erc--assemble-toggle local-p name enable mode t enable-body)
204 ,(erc--assemble-toggle local-p name disable mode nil disable-body) 204 ,(erc--assemble-toggle local-p name disable mode nil disable-body)
205 ,(when (and alias (not (eq name alias))) 205 ,@(and-let* ((alias)
206 `(defalias 206 ((not (eq name alias)))
207 ',(intern 207 (aname (intern (format "erc-%s-mode"
208 (format "erc-%s-mode" 208 (downcase (symbol-name alias))))))
209 (downcase (symbol-name alias)))) 209 `((defalias ',aname #',mode)
210 #',mode)) 210 (put ',aname 'erc-module ',(erc--normalize-module-symbol name))))
211 (put ',mode 'erc-module ',(erc--normalize-module-symbol name))
211 ;; For find-function and find-variable. 212 ;; For find-function and find-variable.
212 (put ',mode 'definition-name ',name) 213 (put ',mode 'definition-name ',name)
213 (put ',enable 'definition-name ',name) 214 (put ',enable 'definition-name ',name)
diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el
index 73ce612a33d..5601ede27a5 100644
--- a/lisp/erc/erc-compat.el
+++ b/lisp/erc/erc-compat.el
@@ -260,8 +260,8 @@ If START or END is negative, it counts from the end."
260 (dolist (e rv out) 260 (dolist (e rv out)
261 (when-let* ((s (plist-get e :secret)) 261 (when-let* ((s (plist-get e :secret))
262 (v (auth-source--obfuscate s))) 262 (v (auth-source--obfuscate s)))
263 (setf (plist-get e :secret) 263 (setq e (plist-put e :secret (apply-partially
264 (apply-partially #'auth-source--deobfuscate v))) 264 #'auth-source--deobfuscate v))))
265 (push e out))) 265 (push e out)))
266 rv))) 266 rv)))
267 267
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index ba7db15cf8c..7f51b7bfb2e 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -1305,6 +1305,14 @@ See also `erc-show-my-nick'."
1305 1305
1306(defvar-local erc-dbuf nil) 1306(defvar-local erc-dbuf nil)
1307 1307
1308;; See comments in `erc-scenarios-base-local-modules' explaining why
1309;; this is insufficient as a public interface.
1310
1311(defvar erc--target-priors nil
1312 "Analogous to `erc--server-reconnecting' but for target buffers.
1313Bound to local variables from an existing (logical) session's
1314buffer during local-module setup and `erc-mode-hook' activation.")
1315
1308(defun erc--target-from-string (string) 1316(defun erc--target-from-string (string)
1309 "Construct an `erc--target' variant from STRING." 1317 "Construct an `erc--target' variant from STRING."
1310 (funcall (if (erc-channel-p string) 1318 (funcall (if (erc-channel-p string)
@@ -1950,7 +1958,8 @@ nil."
1950 (let ((out (list (reverse new-modes)))) 1958 (let ((out (list (reverse new-modes))))
1951 (pcase-dolist (`(,k . ,v) old-vars) 1959 (pcase-dolist (`(,k . ,v) old-vars)
1952 (when (and (string-prefix-p "erc-" (symbol-name k)) 1960 (when (and (string-prefix-p "erc-" (symbol-name k))
1953 (string-suffix-p "-mode" (symbol-name k))) 1961 (string-suffix-p "-mode" (symbol-name k))
1962 (get k 'erc-module))
1954 (if v 1963 (if v
1955 (cl-pushnew k (car out)) 1964 (cl-pushnew k (car out))
1956 (setf (car out) (delq k (car out))) 1965 (setf (car out) (delq k (car out)))
@@ -1985,7 +1994,9 @@ Returns the buffer for the given server or channel."
1985 (let* ((target (and channel (erc--target-from-string channel))) 1994 (let* ((target (and channel (erc--target-from-string channel)))
1986 (buffer (erc-get-buffer-create server port nil target id)) 1995 (buffer (erc-get-buffer-create server port nil target id))
1987 (old-buffer (current-buffer)) 1996 (old-buffer (current-buffer))
1988 (old-vars (and target (buffer-local-variables))) 1997 (erc--target-priors (and target ; buf from prior session
1998 (buffer-local-value 'erc--target buffer)
1999 (buffer-local-variables buffer)))
1989 (old-recon-count erc-server-reconnect-count) 2000 (old-recon-count erc-server-reconnect-count)
1990 (old-point nil) 2001 (old-point nil)
1991 (delayed-modules nil) 2002 (delayed-modules nil)
@@ -1998,7 +2009,8 @@ Returns the buffer for the given server or channel."
1998 (setq old-point (point)) 2009 (setq old-point (point))
1999 (setq delayed-modules 2010 (setq delayed-modules
2000 (erc--merge-local-modes (erc--update-modules) 2011 (erc--merge-local-modes (erc--update-modules)
2001 (or erc--server-reconnecting old-vars))) 2012 (or erc--server-reconnecting
2013 erc--target-priors)))
2002 2014
2003 (delay-mode-hooks (erc-mode)) 2015 (delay-mode-hooks (erc-mode))
2004 2016
@@ -2071,9 +2083,7 @@ Returns the buffer for the given server or channel."
2071 2083
2072 (erc-determine-parameters server port nick full-name user passwd) 2084 (erc-determine-parameters server port nick full-name user passwd)
2073 2085
2074 (save-excursion (run-mode-hooks)) 2086 ;; FIXME consolidate this prompt-setup logic with the pass above.
2075 (dolist (mod (car delayed-modules)) (funcall mod +1))
2076 (dolist (var (cdr delayed-modules)) (set var nil))
2077 2087
2078 ;; set up prompt 2088 ;; set up prompt
2079 (unless continued-session 2089 (unless continued-session
@@ -2086,6 +2096,10 @@ Returns the buffer for the given server or channel."
2086 (erc-display-prompt) 2096 (erc-display-prompt)
2087 (goto-char (point-max))) 2097 (goto-char (point-max)))
2088 2098
2099 (save-excursion (run-mode-hooks)
2100 (dolist (mod (car delayed-modules)) (funcall mod +1))
2101 (dolist (var (cdr delayed-modules)) (set var nil)))
2102
2089 ;; Saving log file on exit 2103 ;; Saving log file on exit
2090 (run-hook-with-args 'erc-connect-pre-hook buffer) 2104 (run-hook-with-args 'erc-connect-pre-hook buffer)
2091 2105
diff --git a/lisp/eshell/em-basic.el b/lisp/eshell/em-basic.el
index dfbe4db0896..bfff3bdf56e 100644
--- a/lisp/eshell/em-basic.el
+++ b/lisp/eshell/em-basic.el
@@ -132,7 +132,8 @@ or `eshell-printn' for display."
132 ;; bug#27361. 132 ;; bug#27361.
133 (when (equal output-newline '(nil)) 133 (when (equal output-newline '(nil))
134 (display-warning 134 (display-warning
135 :warning "To terminate with a newline, you should use -N instead.")) 135 '(eshell echo)
136 "To terminate with a newline, you should use -N instead."))
136 (eshell-echo args output-newline)))) 137 (eshell-echo args output-newline))))
137 138
138(defun eshell/printnl (&rest args) 139(defun eshell/printnl (&rest args)
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el
index fd76a2c6f09..27e68138aa2 100644
--- a/lisp/eshell/esh-var.el
+++ b/lisp/eshell/esh-var.el
@@ -628,9 +628,10 @@ If QUOTED is non-nil, this was invoked inside double-quotes."
628 (if (or (eq max-arity 'many) (>= max-arity 2)) 628 (if (or (eq max-arity 'many) (>= max-arity 2))
629 (funcall target indices quoted) 629 (funcall target indices quoted)
630 (display-warning 630 (display-warning
631 :warning (concat "Function for `eshell-variable-aliases-list' " 631 '(eshell variable-alias)
632 "entry should accept two arguments: INDICES " 632 (concat "Function for `eshell-variable-aliases-list' "
633 "and QUOTED.'")) 633 "entry should accept two arguments: INDICES "
634 "and QUOTED.'"))
634 (funcall target indices))))) 635 (funcall target indices)))))
635 ((symbolp target) 636 ((symbolp target)
636 (eshell-apply-indices (symbol-value target) indices quoted)) 637 (eshell-apply-indices (symbol-value target) indices quoted))
diff --git a/lisp/files.el b/lisp/files.el
index daa86e94d76..29ba523fa69 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -5059,7 +5059,8 @@ This is a separate procedure so your site-init or startup file can
5059redefine it. 5059redefine it.
5060If the optional argument KEEP-BACKUP-VERSION is non-nil, 5060If the optional argument KEEP-BACKUP-VERSION is non-nil,
5061we do not remove backup version numbers, only true file version numbers. 5061we do not remove backup version numbers, only true file version numbers.
5062See also `file-name-version-regexp'." 5062See `file-name-version-regexp' for what constitutes backup versions
5063and version strings."
5063 (let ((handler (find-file-name-handler name 'file-name-sans-versions))) 5064 (let ((handler (find-file-name-handler name 'file-name-sans-versions)))
5064 (if handler 5065 (if handler
5065 (funcall handler 'file-name-sans-versions name keep-backup-version) 5066 (funcall handler 'file-name-sans-versions name keep-backup-version)
@@ -5111,9 +5112,12 @@ the group would be preserved too."
5111 (file-attribute-group-id attributes))))))))))) 5112 (file-attribute-group-id attributes)))))))))))
5112 5113
5113(defun file-name-sans-extension (filename) 5114(defun file-name-sans-extension (filename)
5114 "Return FILENAME sans final \"extension\". 5115 "Return FILENAME sans final \"extension\" and any backup version strings.
5115The extension, in a file name, is the part that begins with the last `.', 5116The extension, in a file name, is the part that begins with the last `.',
5116except that a leading `.' of the file name, if there is one, doesn't count." 5117except that a leading `.' of the file name, if there is one, doesn't count.
5118Any extensions that indicate backup versions and version strings are
5119removed by calling `file-name-sans-versions', which see, before looking
5120for the \"real\" file extension."
5117 (save-match-data 5121 (save-match-data
5118 (let ((file (file-name-sans-versions (file-name-nondirectory filename))) 5122 (let ((file (file-name-sans-versions (file-name-nondirectory filename)))
5119 directory) 5123 directory)
@@ -5127,12 +5131,14 @@ except that a leading `.' of the file name, if there is one, doesn't count."
5127 filename)))) 5131 filename))))
5128 5132
5129(defun file-name-extension (filename &optional period) 5133(defun file-name-extension (filename &optional period)
5130 "Return FILENAME's final \"extension\". 5134 "Return FILENAME's final \"extension\" sans any backup version strings.
5131The extension, in a file name, is the part that begins with the last `.', 5135The extension, in a file name, is the part that begins with the last `.',
5132excluding version numbers and backup suffixes, except that a leading `.' 5136except that a leading `.' of the file name, if there is one, doesn't count.
5133of the file name, if there is one, doesn't count. 5137This function calls `file-name-sans-versions', which see, to remove from
5138the extension it returns any parts that indicate backup versions and
5139version strings.
5134Return nil for extensionless file names such as `foo'. 5140Return nil for extensionless file names such as `foo'.
5135Return the empty string for file names such as `foo.'. 5141Return the empty string for file names such as `foo.' that end in a period.
5136 5142
5137By default, the returned value excludes the period that starts the 5143By default, the returned value excludes the period that starts the
5138extension, but if the optional argument PERIOD is non-nil, the period 5144extension, but if the optional argument PERIOD is non-nil, the period
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index c066a79815a..b3d162cd3ab 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -976,6 +976,50 @@ This mode is independent from the classic cc-mode.el based
976 976
977 (treesit-major-mode-setup))) 977 (treesit-major-mode-setup)))
978 978
979;; We could alternatively use parsers, but if this works well, I don't
980;; see the need to change. This is copied verbatim from cc-guess.el.
981(defconst c-ts-mode--c-or-c++-regexp
982 (eval-when-compile
983 (let ((id "[a-zA-Z_][a-zA-Z0-9_]*") (ws "[ \t]+") (ws-maybe "[ \t]*")
984 (headers '("string" "string_view" "iostream" "map" "unordered_map"
985 "set" "unordered_set" "vector" "tuple")))
986 (concat "^" ws-maybe "\\(?:"
987 "using" ws "\\(?:namespace" ws
988 "\\|" id "::"
989 "\\|" id ws-maybe "=\\)"
990 "\\|" "\\(?:inline" ws "\\)?namespace"
991 "\\(:?" ws "\\(?:" id "::\\)*" id "\\)?" ws-maybe "{"
992 "\\|" "class" ws id
993 "\\(?:" ws "final" "\\)?" ws-maybe "[:{;\n]"
994 "\\|" "struct" ws id "\\(?:" ws "final" ws-maybe "[:{\n]"
995 "\\|" ws-maybe ":\\)"
996 "\\|" "template" ws-maybe "<.*?>"
997 "\\|" "#include" ws-maybe "<" (regexp-opt headers) ">"
998 "\\)")))
999 "A regexp applied to C header files to check if they are really C++.")
1000
1001;;;###autoload
1002(defun c-or-c++-ts-mode ()
1003 "Analyze buffer and enable either C or C++ mode.
1004
1005Some people and projects use .h extension for C++ header files
1006which is also the one used for C header files. This makes
1007matching on file name insufficient for detecting major mode that
1008should be used.
1009
1010This function attempts to use file contents to determine whether
1011the code is C or C++ and based on that chooses whether to enable
1012`c-ts-mode' or `c++-ts-mode'."
1013 (interactive)
1014 (if (save-excursion
1015 (save-restriction
1016 (save-match-data ; Why `save-match-data'?
1017 (widen)
1018 (goto-char (point-min))
1019 (re-search-forward c-ts-mode--c-or-c++-regexp nil t))))
1020 (c++-ts-mode)
1021 (c-ts-mode)))
1022
979(provide 'c-ts-mode) 1023(provide 'c-ts-mode)
980 1024
981;;; c-ts-mode.el ends here 1025;;; c-ts-mode.el ends here
diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el
index 493035d38b4..bdbc03e7c94 100644
--- a/lisp/progmodes/cc-defs.el
+++ b/lisp/progmodes/cc-defs.el
@@ -1361,6 +1361,28 @@ nil; point is then left undefined."
1361 (search-forward-regexp "\\(\n\\|.\\)") ; to set the match-data. 1361 (search-forward-regexp "\\(\n\\|.\\)") ; to set the match-data.
1362 (point)))) 1362 (point))))
1363 1363
1364(defmacro c-search-forward-non-nil-char-property (property &optional limit)
1365 "Search forward for a text-property PROPERTY value non-nil.
1366LIMIT bounds the search.
1367
1368Leave point just after the character. The match data remain
1369unchanged. Return the value of PROPERTY. If a non-nil value
1370isn't found, return nil; point is then left undefined."
1371 (declare (debug t))
1372 `(let* ((-limit- (or ,limit (point-max)))
1373 (value (c-get-char-property (point) ,property)))
1374 (cond
1375 ((>= (point) -limit-)
1376 nil)
1377 (value
1378 (forward-char)
1379 value)
1380 (t (let ((place (c-next-single-property-change
1381 (point) ,property nil -limit-)))
1382 (when place
1383 (goto-char (1+ place))
1384 (c-get-char-property place ,property)))))))
1385
1364(defmacro c-search-backward-char-property (property value &optional limit) 1386(defmacro c-search-backward-char-property (property value &optional limit)
1365 "Search backward for a text-property PROPERTY having value VALUE. 1387 "Search backward for a text-property PROPERTY having value VALUE.
1366LIMIT bounds the search. The comparison is done with `equal'. 1388LIMIT bounds the search. The comparison is done with `equal'.
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 45d90ea2431..3fa407dd338 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -142,6 +142,10 @@
142;; Put on the brace which introduces a brace list and on the commas 142;; Put on the brace which introduces a brace list and on the commas
143;; which separate the elements within it. 143;; which separate the elements within it.
144;; 144;;
145;; 'c-typedef This property is applied to the first character of a
146;; "typedef" keyword. It's value is a list of the identifiers that
147;; the "typedef" declares as types.
148;;
145;; 'c-<>-c-types-set 149;; 'c-<>-c-types-set
146;; This property is set on an opening angle bracket, and indicates that 150;; This property is set on an opening angle bracket, and indicates that
147;; any "," separators within the template/generic expression have been 151;; any "," separators within the template/generic expression have been
@@ -10024,10 +10028,10 @@ This function might do hidden buffer changes."
10024 ;; an identifier instead. 10028 ;; an identifier instead.
10025 (declare (debug nil)) 10029 (declare (debug nil))
10026 `(progn 10030 `(progn
10031 (setq identifier-start type-start)
10027 ,(unless short 10032 ,(unless short
10028 ;; These identifiers are bound only in the inner let. 10033 ;; These identifiers are bound only in the inner let.
10029 '(setq identifier-type at-type 10034 '(setq identifier-type at-type
10030 identifier-start type-start
10031 got-parens nil 10035 got-parens nil
10032 got-identifier t 10036 got-identifier t
10033 got-suffix t 10037 got-suffix t
@@ -10102,10 +10106,11 @@ This function might do hidden buffer changes."
10102 ;; The second element of the return value is non-nil when something 10106 ;; The second element of the return value is non-nil when something
10103 ;; indicating the identifier is a type occurs in the declaration. 10107 ;; indicating the identifier is a type occurs in the declaration.
10104 ;; Specifically it is nil, or a three element list (A B C) where C is t 10108 ;; Specifically it is nil, or a three element list (A B C) where C is t
10105 ;; when context is '<> and the "identifier" is a found type, B is t when a 10109 ;; when context is '<> and the "identifier" is a found type, B is the
10106 ;; `c-typedef-kwds' ("typedef") is present, and A is t when some other 10110 ;; position of the `c-typedef-kwds' keyword ("typedef") when such is
10107 ;; `c-typedef-decl-kwds' (e.g. class, struct, enum) specifier is present. 10111 ;; present, and A is t when some other `c-typedef-decl-kwds' (e.g. class,
10108 ;; I.e., (some of) the declared identifier(s) are types. 10112 ;; struct, enum) specifier is present. I.e., (some of) the declared
10113 ;; identifier(s) are types.
10109 ;; 10114 ;;
10110 ;; The third element of the return value is non-nil when the declaration 10115 ;; The third element of the return value is non-nil when the declaration
10111 ;; parsed might be an expression. The fourth element is the position of 10116 ;; parsed might be an expression. The fourth element is the position of
@@ -10173,6 +10178,9 @@ This function might do hidden buffer changes."
10173 ;; `c-decl-hangon-kwds' and their associated clauses that 10178 ;; `c-decl-hangon-kwds' and their associated clauses that
10174 ;; occurs after the type. 10179 ;; occurs after the type.
10175 id-start 10180 id-start
10181 ;; The earlier value of `type-start' if we've shifted the type
10182 ;; backwards.
10183 identifier-start
10176 ;; These store `at-type', `type-start' and `id-start' of the 10184 ;; These store `at-type', `type-start' and `id-start' of the
10177 ;; identifier before the one in those variables. The previous 10185 ;; identifier before the one in those variables. The previous
10178 ;; identifier might turn out to be the real type in a 10186 ;; identifier might turn out to be the real type in a
@@ -10183,7 +10191,8 @@ This function might do hidden buffer changes."
10183 ;; Set if we've found a specifier (apart from "typedef") that makes 10191 ;; Set if we've found a specifier (apart from "typedef") that makes
10184 ;; the defined identifier(s) types. 10192 ;; the defined identifier(s) types.
10185 at-type-decl 10193 at-type-decl
10186 ;; Set if we've a "typedef" keyword. 10194 ;; If we've a "typedef" keyword (?or similar), the buffer position of
10195 ;; its first character.
10187 at-typedef 10196 at-typedef
10188 ;; Set if `context' is '<> and the identifier is definitely a type, or 10197 ;; Set if `context' is '<> and the identifier is definitely a type, or
10189 ;; has already been recorded as a found type. 10198 ;; has already been recorded as a found type.
@@ -10266,7 +10275,7 @@ This function might do hidden buffer changes."
10266 (looking-at "@[A-Za-z0-9]+"))) 10275 (looking-at "@[A-Za-z0-9]+")))
10267 (save-match-data 10276 (save-match-data
10268 (if (looking-at c-typedef-key) 10277 (if (looking-at c-typedef-key)
10269 (setq at-typedef t))) 10278 (setq at-typedef (point))))
10270 (setq kwd-sym (c-keyword-sym (match-string 1))) 10279 (setq kwd-sym (c-keyword-sym (match-string 1)))
10271 (save-excursion 10280 (save-excursion
10272 (c-forward-keyword-clause 1) 10281 (c-forward-keyword-clause 1)
@@ -10486,9 +10495,9 @@ This function might do hidden buffer changes."
10486 ;; True if we've parsed the type decl to a token that is 10495 ;; True if we've parsed the type decl to a token that is
10487 ;; known to end declarations in this context. 10496 ;; known to end declarations in this context.
10488 at-decl-end 10497 at-decl-end
10489 ;; The earlier values of `at-type' and `type-start' if we've 10498 ;; The earlier value of `at-type' if we've shifted the type
10490 ;; shifted the type backwards. 10499 ;; backwards.
10491 identifier-type identifier-start 10500 identifier-type
10492 ;; If `c-parse-and-markup-<>-arglists' is set we need to 10501 ;; If `c-parse-and-markup-<>-arglists' is set we need to
10493 ;; turn it off during the name skipping below to avoid 10502 ;; turn it off during the name skipping below to avoid
10494 ;; getting `c-type' properties that might be bogus. That 10503 ;; getting `c-type' properties that might be bogus. That
@@ -10530,6 +10539,10 @@ This function might do hidden buffer changes."
10530 (progn (setq got-identifier nil) t) 10539 (progn (setq got-identifier nil) t)
10531 ;; It turned out to be the real identifier, 10540 ;; It turned out to be the real identifier,
10532 ;; so stop. 10541 ;; so stop.
10542 (save-excursion
10543 (c-backward-syntactic-ws)
10544 (c-simple-skip-symbol-backward)
10545 (setq identifier-start (point)))
10533 nil)) 10546 nil))
10534 t)) 10547 t))
10535 10548
@@ -10555,6 +10568,10 @@ This function might do hidden buffer changes."
10555 (and (looking-at c-identifier-start) 10568 (and (looking-at c-identifier-start)
10556 (setq pos (point)) 10569 (setq pos (point))
10557 (setq got-identifier (c-forward-name)) 10570 (setq got-identifier (c-forward-name))
10571 (save-excursion
10572 (c-backward-syntactic-ws)
10573 (c-simple-skip-symbol-backward)
10574 (setq identifier-start (point)))
10558 (setq name-start pos)) 10575 (setq name-start pos))
10559 (when (looking-at "[0-9]") 10576 (when (looking-at "[0-9]")
10560 (setq got-number t)) ; We probably have an arithmetic expression. 10577 (setq got-number t)) ; We probably have an arithmetic expression.
@@ -10573,7 +10590,8 @@ This function might do hidden buffer changes."
10573 (setq at-type nil 10590 (setq at-type nil
10574 name-start type-start 10591 name-start type-start
10575 id-start type-start 10592 id-start type-start
10576 got-identifier t))) 10593 got-identifier t)
10594 (setq identifier-start type-start)))
10577 10595
10578 ;; Skip over type decl suffix operators and trailing noise macros. 10596 ;; Skip over type decl suffix operators and trailing noise macros.
10579 (while 10597 (while
diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el
index 4dcc3e0ade9..c220d8d8789 100644
--- a/lisp/progmodes/cc-fonts.el
+++ b/lisp/progmodes/cc-fonts.el
@@ -85,6 +85,8 @@
85 85
86(cc-bytecomp-defvar parse-sexp-lookup-properties) ; Emacs only. 86(cc-bytecomp-defvar parse-sexp-lookup-properties) ; Emacs only.
87 87
88(declare-function cl-set-difference "cl-seq" (cl-list1 cl-list2 &rest cl-keys))
89
88;; Need to declare these local symbols during compilation since 90;; Need to declare these local symbols during compilation since
89;; they're referenced from lambdas in `byte-compile' calls that are 91;; they're referenced from lambdas in `byte-compile' calls that are
90;; executed at compile time. They don't need to have the proper 92;; executed at compile time. They don't need to have the proper
@@ -1109,10 +1111,12 @@ casts and declarations are fontified. Used on level 2 and higher."
1109 ;; additionally, mark the commas with c-type property 'c-decl-id-start or 1111 ;; additionally, mark the commas with c-type property 'c-decl-id-start or
1110 ;; 'c-decl-type-start (according to TYPES). Stop at LIMIT. 1112 ;; 'c-decl-type-start (according to TYPES). Stop at LIMIT.
1111 ;; 1113 ;;
1112 ;; If TYPES is t, fontify all identifiers as types, if it is nil fontify as 1114 ;; If TYPES is t, fontify all identifiers as types; if it is a number, a
1113 ;; either variables or functions, otherwise TYPES is a face to use. If 1115 ;; buffer position, additionally set the `c-deftype' text property on the
1114 ;; NOT-TOP is non-nil, we are not at the top-level ("top-level" includes 1116 ;; keyword at that position; if it is nil fontify as either variables or
1115 ;; being directly inside a class or namespace, etc.). 1117 ;; functions, otherwise TYPES is a face to use. If NOT-TOP is non-nil, we
1118 ;; are not at the top-level ("top-level" includes being directly inside a
1119 ;; class or namespace, etc.).
1116 ;; 1120 ;;
1117 ;; TEMPLATE-CLASS is non-nil when the declaration is in template delimiters 1121 ;; TEMPLATE-CLASS is non-nil when the declaration is in template delimiters
1118 ;; and was introduced by, e.g. "typename" or "class", such that if there is 1122 ;; and was introduced by, e.g. "typename" or "class", such that if there is
@@ -1129,17 +1133,28 @@ casts and declarations are fontified. Used on level 2 and higher."
1129 ;;(message "c-font-lock-declarators from %s to %s" (point) limit) 1133 ;;(message "c-font-lock-declarators from %s to %s" (point) limit)
1130 (c-fontify-types-and-refs 1134 (c-fontify-types-and-refs
1131 () 1135 ()
1136 ;; If we're altering the declarators in a typedef, we need to scan ALL of
1137 ;; them because of the way we check for changes.
1138 (let ((c-do-decl-limit (if (numberp types) (point-max) limit))
1139 decl-ids)
1132 (c-do-declarators 1140 (c-do-declarators
1133 limit list not-top 1141 c-do-decl-limit
1134 (cond ((eq types t) 'c-decl-type-start) 1142 list not-top
1143 (cond ((or (numberp types)
1144 (eq types t))
1145 'c-decl-type-start)
1135 ((null types) 'c-decl-id-start)) 1146 ((null types) 'c-decl-id-start))
1136 (lambda (id-start id-end end-pos _not-top is-function init-char) 1147 (lambda (id-start id-end end-pos _not-top is-function init-char)
1137 (if (eq types t) 1148 (if (or (numberp types)
1149 (eq types t))
1138 (when id-start 1150 (when id-start
1139 ;; Register and fontify the identifier as a type. 1151 ;; Register and fontify the identifier as a type.
1140 (let ((c-promote-possible-types t)) 1152 (let ((c-promote-possible-types t))
1141 (goto-char id-start) 1153 (goto-char id-start)
1142 (c-forward-type))) 1154 (c-forward-type))
1155 (when (numberp types)
1156 (push (buffer-substring-no-properties id-start id-end)
1157 decl-ids)))
1143 (when id-start 1158 (when id-start
1144 (goto-char id-start) 1159 (goto-char id-start)
1145 (when c-opt-identifier-prefix-key 1160 (when c-opt-identifier-prefix-key
@@ -1147,7 +1162,7 @@ casts and declarations are fontified. Used on level 2 and higher."
1147 (eq (match-end 1) id-end)) 1162 (eq (match-end 1) id-end))
1148 (while (and (< (point) id-end) 1163 (while (and (< (point) id-end)
1149 (re-search-forward c-opt-identifier-prefix-key id-end t)) 1164 (re-search-forward c-opt-identifier-prefix-key id-end t))
1150 (c-forward-syntactic-ws limit)))) 1165 (c-forward-syntactic-ws c-do-decl-limit))))
1151 ;; Only apply the face when the text doesn't have one yet. 1166 ;; Only apply the face when the text doesn't have one yet.
1152 ;; Exception: The "" in C++'s operator"" will already wrongly have 1167 ;; Exception: The "" in C++'s operator"" will already wrongly have
1153 ;; string face. 1168 ;; string face.
@@ -1164,7 +1179,7 @@ casts and declarations are fontified. Used on level 2 and higher."
1164 (equal (buffer-substring-no-properties id-start id-end) 1179 (equal (buffer-substring-no-properties id-start id-end)
1165 "\"\"")) 1180 "\"\""))
1166 (goto-char id-end) 1181 (goto-char id-end)
1167 (c-forward-syntactic-ws limit) 1182 (c-forward-syntactic-ws c-do-decl-limit)
1168 (when (c-on-identifier) 1183 (when (c-on-identifier)
1169 (c-put-font-lock-face 1184 (c-put-font-lock-face
1170 (point) 1185 (point)
@@ -1174,10 +1189,21 @@ casts and declarations are fontified. Used on level 2 and higher."
1174 (eq init-char ?=) ; C++ "<class X = Y>"? 1189 (eq init-char ?=) ; C++ "<class X = Y>"?
1175 (progn 1190 (progn
1176 (goto-char end-pos) 1191 (goto-char end-pos)
1177 (c-forward-token-2 1 nil limit) ; Over "=" 1192 (c-forward-token-2 1 nil c-do-decl-limit) ; Over "="
1178 (let ((c-promote-possible-types t)) 1193 (let ((c-promote-possible-types t))
1179 (c-forward-type t))))) 1194 (c-forward-type t)))))
1180 accept-anon) ; Last argument to c-do-declarators. 1195 accept-anon) ; Last argument to c-do-declarators.
1196 ;; If we've changed types declared by a "typedef", update the `c-typedef'
1197 ;; text property.
1198 (when (numberp types)
1199 (let* ((old-decl-ids (c-get-char-property types 'c-typedef))
1200 (old-types (c--set-difference old-decl-ids decl-ids :test #'equal))
1201 (new-types (c--set-difference decl-ids old-decl-ids :test #'equal)))
1202 (dolist (type old-types)
1203 (c-unfind-type type))
1204 ;; The new types have already been added to `c-found-types', as needed.
1205 (when (or old-types new-types)
1206 (c-put-char-property types 'c-typedef decl-ids)))))
1181 nil)) 1207 nil))
1182 1208
1183(defun c-get-fontification-context (match-pos not-front-decl &optional toplev) 1209(defun c-get-fontification-context (match-pos not-front-decl &optional toplev)
@@ -1433,7 +1459,10 @@ casts and declarations are fontified. Used on level 2 and higher."
1433 (c-font-lock-declarators 1459 (c-font-lock-declarators
1434 (min limit (point-max)) 1460 (min limit (point-max))
1435 decl-list 1461 decl-list
1436 (not (null (cadr decl-or-cast))) 1462 (cond ((null (cadr decl-or-cast))
1463 nil)
1464 ((cadr (cadr decl-or-cast)))
1465 (t t))
1437 (not toplev) 1466 (not toplev)
1438 template-class 1467 template-class
1439 (memq context '(decl <>)))) 1468 (memq context '(decl <>))))
@@ -1749,12 +1778,21 @@ casts and declarations are fontified. Used on level 2 and higher."
1749 ; speeds up lisp.h tremendously. 1778 ; speeds up lisp.h tremendously.
1750 (save-excursion 1779 (save-excursion
1751 (when (not (c-back-over-member-initializers decl-search-lim)) 1780 (when (not (c-back-over-member-initializers decl-search-lim))
1781 (setq paren-state (c-parse-state))
1752 (unless (or (eobp) 1782 (unless (or (eobp)
1753 (looking-at "\\s(\\|\\s)")) 1783 (looking-at "\\s(\\|\\s)"))
1754 (forward-char)) 1784 (forward-char))
1755 (c-syntactic-skip-backward "^;{}" decl-search-lim t) 1785 (c-syntactic-skip-backward "^;{}" decl-search-lim t)
1756 (when (eq (char-before) ?}) 1786 ;; Do we have the brace block of a struct, etc.?
1757 (c-go-list-backward) ; brace block of struct, etc.? 1787 (when (cond
1788 ((and (consp (car paren-state))
1789 (eq (char-before) ?}))
1790 (goto-char (caar paren-state))
1791 t)
1792 ((and (numberp (car paren-state))
1793 (eq (char-after (car paren-state)) ?{))
1794 (goto-char (car paren-state))
1795 t))
1758 (c-syntactic-skip-backward "^;{}" decl-search-lim t)) 1796 (c-syntactic-skip-backward "^;{}" decl-search-lim t))
1759 (when (or (bobp) 1797 (when (or (bobp)
1760 (memq (char-before) '(?\; ?{ ?}))) 1798 (memq (char-before) '(?\; ?{ ?})))
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index b04ed7584c4..330202bb5f9 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -2077,6 +2077,37 @@ with // and /*, not more generic line and block comments."
2077 (not (eobp)))) 2077 (not (eobp))))
2078 (forward-char)))))) 2078 (forward-char))))))
2079 2079
2080(defun c-before-change-de-typedef (beg end)
2081 ;; For each "typedef" starting in (BEG END), remove the defined types from
2082 ;; c-found-types
2083 (let (prop)
2084 (save-excursion
2085 (goto-char beg)
2086 (while (and (< (point) end)
2087 (setq prop (c-search-forward-non-nil-char-property
2088 'c-typedef)))
2089 (dolist (type prop)
2090 (c-unfind-type type))))))
2091
2092(defun c-after-change-de-typedef (beg end _old-len)
2093 ;; For each former "typedef" in (BEG END), remove the defined types from
2094 ;; those which are no longer typedefs.
2095 (let (prop)
2096 (save-excursion
2097 (goto-char beg)
2098 (c-backward-token-2
2099 1 nil (- (point) 20))
2100 (while (and (< (point) end)
2101 (setq prop (c-search-forward-non-nil-char-property
2102 'c-typedef end)))
2103 (backward-char)
2104 (when (or (not (looking-at c-typedef-key))
2105 (<= (match-end 1) beg))
2106 (dolist (type prop)
2107 (c-unfind-type type))
2108 (c-clear-char-property (point) 'c-typedef))
2109 (forward-char)))))
2110
2080(defun c-update-new-id (end) 2111(defun c-update-new-id (end)
2081 ;; Note the bounds of any identifier that END is in or just after, in 2112 ;; Note the bounds of any identifier that END is in or just after, in
2082 ;; `c-new-id-start' and `c-new-id-end'. Otherwise set these variables to 2113 ;; `c-new-id-start' and `c-new-id-end'. Otherwise set these variables to
@@ -2086,7 +2117,9 @@ with // and /*, not more generic line and block comments."
2086 (let ((id-beg (c-on-identifier))) 2117 (let ((id-beg (c-on-identifier)))
2087 (setq c-new-id-start id-beg 2118 (setq c-new-id-start id-beg
2088 c-new-id-end (and id-beg 2119 c-new-id-end (and id-beg
2089 (progn (c-end-of-current-token) (point))) 2120 (progn (goto-char id-beg)
2121 (c-forward-token-2)
2122 (point)))
2090 c-new-id-is-type nil)))) 2123 c-new-id-is-type nil))))
2091 2124
2092(defun c-post-command () 2125(defun c-post-command ()
@@ -2215,6 +2248,10 @@ with // and /*, not more generic line and block comments."
2215 term-pos) 2248 term-pos)
2216 (buffer-substring-no-properties beg end))))))) 2249 (buffer-substring-no-properties beg end)))))))
2217 2250
2251 ;; If we're about to delete "typedef"s, clear the identifiers from
2252 ;; `c-found-types'.
2253 (c-before-change-de-typedef beg end)
2254
2218 (if c-get-state-before-change-functions 2255 (if c-get-state-before-change-functions
2219 (mapc (lambda (fn) 2256 (mapc (lambda (fn)
2220 (funcall fn beg end)) 2257 (funcall fn beg end))
@@ -2306,6 +2343,7 @@ with // and /*, not more generic line and block comments."
2306 (c-update-new-id end) 2343 (c-update-new-id end)
2307 (c-trim-found-types beg end old-len) ; maybe we don't 2344 (c-trim-found-types beg end old-len) ; maybe we don't
2308 ; need all of these. 2345 ; need all of these.
2346 (c-after-change-de-typedef beg end old-len)
2309 (c-invalidate-sws-region-after beg end old-len) 2347 (c-invalidate-sws-region-after beg end old-len)
2310 ;; (c-invalidate-state-cache beg) ; moved to 2348 ;; (c-invalidate-state-cache beg) ; moved to
2311 ;; `c-before-change'. 2349 ;; `c-before-change'.
diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el
index 939c054b041..f075824591d 100644
--- a/lisp/progmodes/ruby-ts-mode.el
+++ b/lisp/progmodes/ruby-ts-mode.el
@@ -152,7 +152,6 @@
152 "then" 152 "then"
153 "ensure" 153 "ensure"
154 "body_statement" 154 "body_statement"
155 "parenthesized_statements"
156 "interpolation") 155 "interpolation")
157 string-end) 156 string-end)
158 "Regular expression of the nodes that can contain statements.") 157 "Regular expression of the nodes that can contain statements.")
@@ -221,9 +220,9 @@ values of OVERRIDE"
221 220
222 :language language 221 :language language
223 :feature 'constant 222 :feature 'constant
224 '((true) @font-lock-doc-markup-face 223 '((true) @font-lock-constant-face
225 (false) @font-lock-doc-markup-face 224 (false) @font-lock-constant-face
226 (nil) @font-lock-doc-markup-face) 225 (nil) @font-lock-constant-face)
227 226
228 ;; Before 'operator so (unary) works. 227 ;; Before 'operator so (unary) works.
229 :language language 228 :language language
@@ -512,10 +511,6 @@ array or hash."
512 (first-child (ruby-ts--first-non-comment-child parent))) 511 (first-child (ruby-ts--first-non-comment-child parent)))
513 (= (ruby-ts--lineno open-brace) (ruby-ts--lineno first-child)))) 512 (= (ruby-ts--lineno open-brace) (ruby-ts--lineno first-child))))
514 513
515(defun ruby-ts--assignment-ancestor (node &rest _)
516 "Return the assignment ancestor of NODE if any."
517 (treesit-parent-until node (ruby-ts--type-pred "\\`assignment\\'")))
518
519(defun ruby-ts--statement-ancestor (node &rest _) 514(defun ruby-ts--statement-ancestor (node &rest _)
520 "Return the statement ancestor of NODE if any. 515 "Return the statement ancestor of NODE if any.
521A statement is defined as a child of a statement container where 516A statement is defined as a child of a statement container where
@@ -531,26 +526,6 @@ a statement container is a node that matches
531 parent (treesit-node-parent parent))) 526 parent (treesit-node-parent parent)))
532 statement)) 527 statement))
533 528
534(defun ruby-ts--is-in-condition (node &rest _)
535 "Return the condition node if NODE is within a condition."
536 (while (and node
537 (not (equal "condition" (treesit-node-field-name node)))
538 (not (string-match-p ruby-ts--statement-container-regexp
539 (treesit-node-type node))))
540 (setq node (treesit-node-parent node)))
541 (and (equal "condition" (treesit-node-field-name node)) node))
542
543(defun ruby-ts--endless-method (node &rest _)
544 "Return the expression node if NODE is in an endless method.
545i.e. expr of def foo(args) = expr is returned."
546 (let* ((method node))
547 (while (and method
548 (not (string-match-p ruby-ts--method-regex (treesit-node-type method))))
549 (setq method (treesit-node-parent method)))
550 (when method
551 (if (equal "=" (treesit-node-type (treesit-node-child method 3 nil)))
552 (treesit-node-child method 4 nil)))))
553
554;; 529;;
555;; end of functions that can be used for queries 530;; end of functions that can be used for queries
556;; 531;;
@@ -587,11 +562,11 @@ i.e. expr of def foo(args) = expr is returned."
587 ;; 562 ;;
588 ;; I'm using very restrictive patterns hoping to reduce rules 563 ;; I'm using very restrictive patterns hoping to reduce rules
589 ;; triggering unintentionally. 564 ;; triggering unintentionally.
590 ((match "else" "if") 565 ((match "else" "if\\|unless")
591 (ruby-ts--align-keywords ruby-ts--parent-node) 0) 566 (ruby-ts--align-keywords ruby-ts--parent-node) 0)
592 ((match "elsif" "if") 567 ((match "elsif" "if")
593 (ruby-ts--align-keywords ruby-ts--parent-node) 0) 568 (ruby-ts--align-keywords ruby-ts--parent-node) 0)
594 ((match "end" "if") 569 ((match "end" "if\\|unless")
595 (ruby-ts--align-keywords ruby-ts--parent-node) 0) 570 (ruby-ts--align-keywords ruby-ts--parent-node) 0)
596 ((n-p-gp nil "then\\|else\\|elsif" "if\\|unless") 571 ((n-p-gp nil "then\\|else\\|elsif" "if\\|unless")
597 (ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level) 572 (ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level)
@@ -664,6 +639,13 @@ i.e. expr of def foo(args) = expr is returned."
664 ;; else the second query aligns 639 ;; else the second query aligns
665 ;; `ruby-indent-level' spaces in from the parent. 640 ;; `ruby-indent-level' spaces in from the parent.
666 ((and ruby-ts--align-chain-p (match "\\." "call")) ruby-ts--align-chain 0) 641 ((and ruby-ts--align-chain-p (match "\\." "call")) ruby-ts--align-chain 0)
642 ;; Obery ruby-method-call-indent, whether the dot is on
643 ;; this line or the previous line.
644 ((and (not ruby-ts--method-call-indent-p)
645 (or
646 (match "\\." "call")
647 (query "(call \".\" (identifier) @indent)")))
648 parent 0)
667 ((match "\\." "call") parent ruby-indent-level) 649 ((match "\\." "call") parent ruby-indent-level)
668 650
669 ;; ruby-indent-after-block-in-continued-expression 651 ;; ruby-indent-after-block-in-continued-expression
@@ -697,23 +679,27 @@ i.e. expr of def foo(args) = expr is returned."
697 ;; 2) With paren, 1st arg on next line 679 ;; 2) With paren, 1st arg on next line
698 ((and (query "(argument_list \"(\" _ @indent)") 680 ((and (query "(argument_list \"(\" _ @indent)")
699 (node-is ")")) 681 (node-is ")"))
700 (ruby-ts--bol ruby-ts--grand-parent-node) 0) 682 ruby-ts--parent-call-or-bol 0)
701 ((query "(argument_list \"(\" _ @indent)") 683 ((query "(argument_list \"(\" _ @indent)")
702 (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level) 684 ruby-ts--parent-call-or-bol ruby-indent-level)
703 ;; 3) No paren, ruby-parenless-call-arguments-indent is t 685 ;; 3) No paren, ruby-parenless-call-arguments-indent is t
704 ((and ruby-ts--parenless-call-arguments-indent-p (parent-is "argument_list")) 686 ((and ruby-ts--parenless-call-arguments-indent-p (parent-is "argument_list"))
705 first-sibling 0) 687 first-sibling 0)
706 ;; 4) No paren, ruby-parenless-call-arguments-indent is nil 688 ;; 4) No paren, ruby-parenless-call-arguments-indent is nil
707 ((parent-is "argument_list") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level) 689 ((parent-is "argument_list")
690 (ruby-ts--bol ruby-ts--statement-ancestor) ruby-indent-level)
708 691
709 ;; Old... probably too simple 692 ;; Old... probably too simple
710 ((parent-is "block_parameters") first-sibling 1) 693 ((parent-is "block_parameters") first-sibling 1)
711 694
712 ((and (parent-is "binary") 695 ((and (not ruby-ts--after-op-indent-p)
713 (or ruby-ts--assignment-ancestor 696 (parent-is "binary\\|conditional"))
714 ruby-ts--is-in-condition 697 (ruby-ts--bol ruby-ts--statement-ancestor) ruby-indent-level)
715 ruby-ts--endless-method)) 698
716 first-sibling 0) 699 ((parent-is "binary")
700 ruby-ts--binary-indent-anchor 0)
701
702 ((parent-is "conditional") parent ruby-indent-level)
717 703
718 ;; ruby-mode does not touch these... 704 ;; ruby-mode does not touch these...
719 ((match "bare_string" "string_array") no-indent 0) 705 ((match "bare_string" "string_array") no-indent 0)
@@ -732,37 +718,15 @@ i.e. expr of def foo(args) = expr is returned."
732 ((and ruby-ts--same-line-hash-array-p (parent-is "array")) 718 ((and ruby-ts--same-line-hash-array-p (parent-is "array"))
733 (nth-sibling 0 ruby-ts--true) 0) 719 (nth-sibling 0 ruby-ts--true) 0)
734 720
735 ;; NOTE to folks trying to understand my insanity... 721 ((match "}" "hash") ruby-ts--parent-call-or-bol 0)
736 ;; I having trouble understanding the "logic" of why things 722 ((parent-is "hash") ruby-ts--parent-call-or-bol ruby-indent-level)
737 ;; are indented like they are so I am adding special cases 723 ((match "]" "array") ruby-ts--parent-call-or-bol 0)
738 ;; hoping at some point I will be struck by lightning. 724 ((parent-is "array") ruby-ts--parent-call-or-bol ruby-indent-level)
739 ((and (n-p-gp "}" "hash" "pair") 725
740 (not ruby-ts--same-line-hash-array-p)) 726 ((parent-is "pair") ruby-ts--parent-call-or-bol 0)
741 grand-parent 0) 727
742 ((and (n-p-gp "pair" "hash" "pair") 728 ((match ")" "parenthesized_statements") parent-bol 0)
743 (not ruby-ts--same-line-hash-array-p)) 729 ((parent-is "parenthesized_statements") parent-bol ruby-indent-level)
744 grand-parent ruby-indent-level)
745 ((and (n-p-gp "}" "hash" "method")
746 (not ruby-ts--same-line-hash-array-p))
747 grand-parent 0)
748 ((and (n-p-gp "pair" "hash" "method")
749 (not ruby-ts--same-line-hash-array-p))
750 grand-parent ruby-indent-level)
751
752 ((n-p-gp "}" "hash" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) 0)
753 ((n-p-gp nil "hash" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
754 ((n-p-gp "]" "array" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) 0)
755 ((n-p-gp nil "array" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
756
757 ((n-p-gp "}" "hash" "argument_list") first-sibling 0)
758 ((n-p-gp nil "hash" "argument_list") first-sibling ruby-indent-level)
759 ((n-p-gp "]" "array" "argument_list") first-sibling 0)
760 ((n-p-gp nil "array" "argument_list") first-sibling ruby-indent-level)
761
762 ((match "}" "hash") first-sibling 0)
763 ((parent-is "hash") first-sibling ruby-indent-level)
764 ((match "]" "array") first-sibling 0)
765 ((parent-is "array") first-sibling ruby-indent-level)
766 730
767 ;; If the previous method isn't finished yet, this will get 731 ;; If the previous method isn't finished yet, this will get
768 ;; the next method indented properly. 732 ;; the next method indented properly.
@@ -814,6 +778,66 @@ i.e. expr of def foo(args) = expr is returned."
814 (back-to-indentation) 778 (back-to-indentation)
815 (point))))) 779 (point)))))
816 780
781(defun ruby-ts--binary-indent-anchor (_node parent _bol &rest _)
782 (save-excursion
783 (goto-char (treesit-node-start parent))
784 (when (string-match-p ruby-ts--statement-container-regexp
785 (treesit-node-type (treesit-node-parent parent)))
786 ;; Hack alert: it's not the proper place to alter the offset.
787 ;; Redoing the analysis in the OFFSET form seems annoying,
788 ;; though. (**)
789 (forward-char ruby-indent-level))
790 (point)))
791
792(defun ruby-ts--parent-call-or-bol (_not parent _bol &rest _)
793 (let* ((parent-bol (save-excursion
794 (goto-char (treesit-node-start parent))
795 (back-to-indentation)
796 (point)))
797 (found
798 (treesit-parent-until
799 parent
800 (lambda (node)
801 (or (< (treesit-node-start node) parent-bol)
802 (string-match-p "\\`array\\|hash\\'" (treesit-node-type node))
803 ;; Method call on same line.
804 (equal (treesit-node-type node) "argument_list"))))))
805 (cond
806 ((null found)
807 parent-bol)
808 ;; No paren/curly/brace found on the same line.
809 ((< (treesit-node-start found) parent-bol)
810 parent-bol)
811 ;; Hash or array opener on the same line.
812 ((string-match-p "\\`array\\|hash\\'" (treesit-node-type found))
813 (save-excursion
814 (goto-char (treesit-node-start (treesit-node-child found 1)))
815 (point)))
816 ;; Parenless call found: indent to stmt with offset.
817 ((not ruby-parenless-call-arguments-indent)
818 (save-excursion
819 (goto-char (treesit-node-start
820 (ruby-ts--statement-ancestor found)))
821 ;; (**) Same.
822 (+ (point) ruby-indent-level)))
823 ;; Call with parens -- ident to first arg.
824 ((equal (treesit-node-type (treesit-node-child found 0))
825 "(")
826 (save-excursion
827 (goto-char (treesit-node-start (treesit-node-child found 1)))
828 (point)))
829 ;; Indent to the parenless call args beginning.
830 (t
831 (save-excursion
832 (goto-char (treesit-node-start found))
833 (point))))))
834
835(defun ruby-ts--after-op-indent-p (&rest _)
836 ruby-after-operator-indent)
837
838(defun ruby-ts--method-call-indent-p (&rest _)
839 ruby-method-call-indent)
840
817(defun ruby-ts--class-or-module-p (node) 841(defun ruby-ts--class-or-module-p (node)
818 "Predicate if NODE is a class or module." 842 "Predicate if NODE is a class or module."
819 (string-match-p ruby-ts--class-or-module-regex (treesit-node-type node))) 843 (string-match-p ruby-ts--class-or-module-regex (treesit-node-type node)))
diff --git a/lisp/replace.el b/lisp/replace.el
index 2f063bbf66b..3c2b925ea92 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -824,11 +824,11 @@ by this function to the end of values available via
824 824
825(defvar-keymap read-regexp-map 825(defvar-keymap read-regexp-map
826 :parent minibuffer-local-map 826 :parent minibuffer-local-map
827 "M-c" #'read-regexp-toggle-case-folding) 827 "M-s c" #'read-regexp-toggle-case-fold)
828 828
829(defvar read-regexp--case-fold nil) 829(defvar read-regexp--case-fold nil)
830 830
831(defun read-regexp-toggle-case-folding () 831(defun read-regexp-toggle-case-fold ()
832 (interactive) 832 (interactive)
833 (setq read-regexp--case-fold 833 (setq read-regexp--case-fold
834 (if (or (eq read-regexp--case-fold 'fold) 834 (if (or (eq read-regexp--case-fold 'fold)
@@ -875,7 +875,7 @@ in \":\", followed by optional whitespace), DEFAULT is added to the prompt.
875The optional argument HISTORY is a symbol to use for the history list. 875The optional argument HISTORY is a symbol to use for the history list.
876If nil, use `regexp-history'. 876If nil, use `regexp-history'.
877 877
878If the user has used the \\<read-regexp-map>\\[read-regexp-toggle-case-folding] command to specify case 878If the user has used the \\<read-regexp-map>\\[read-regexp-toggle-case-fold] command to specify case
879sensitivity, the returned string will have a text property named 879sensitivity, the returned string will have a text property named
880`case-fold' that has a value of either `fold' or 880`case-fold' that has a value of either `fold' or
881`inhibit-fold'. (It's up to the caller of `read-regexp' to 881`inhibit-fold'. (It's up to the caller of `read-regexp' to
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 69bfff21df3..e8571d43db3 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -905,6 +905,14 @@ This is not a general optimization and should be RARELY needed!
905See comments in `treesit-font-lock-fontify-region' for more 905See comments in `treesit-font-lock-fontify-region' for more
906detail.") 906detail.")
907 907
908(defvar-local treesit--font-lock-fast-mode-grace-count 5
909 "Grace counts before we turn on the fast mode.
910
911When query takes abnormally long time to execute, we turn on the
912\"fast mode\", but just to be on the safe side, we only turn on
913the fast mode after this number of offenses. See bug#60691,
914bug#60223.")
915
908;; Some details worth explaining: 916;; Some details worth explaining:
909;; 917;;
910;; 1. When we apply face to a node, we clip the face into the 918;; 1. When we apply face to a node, we clip the face into the
@@ -927,13 +935,13 @@ detail.")
927;; parse it into a enormously tall tree (10k levels tall). In that 935;; parse it into a enormously tall tree (10k levels tall). In that
928;; case querying the root node is very slow. So we try to get 936;; case querying the root node is very slow. So we try to get
929;; top-level nodes and query them. This ensures that querying is fast 937;; top-level nodes and query them. This ensures that querying is fast
930;; everywhere else, except for the problematic region. 938;; everywhere else, except for the problematic region. (Bug#59415).
931;; 939;;
932;; Some other time the source file has a top-level node that contains 940;; Some other time the source file has a top-level node that contains
933;; a huge number of children (say, 10k children), querying that node 941;; a huge number of immediate children (say, 10k children), querying
934;; is also very slow, so instead of getting the top-level node, we 942;; that node is also very slow, so instead of getting the top-level
935;; recursively go down the tree to find nodes that cover the region 943;; node, we recursively go down the tree to find nodes that cover the
936;; but are reasonably small. 944;; region but are reasonably small. (Bug#59738).
937;; 945;;
938;; 3. It is possible to capture a node that's completely outside the 946;; 3. It is possible to capture a node that's completely outside the
939;; region between START and END: as long as the whole pattern 947;; region between START and END: as long as the whole pattern
@@ -941,8 +949,8 @@ detail.")
941;; returned. If the node is outside of that region, (max node-start 949;; returned. If the node is outside of that region, (max node-start
942;; start) and friends return bad values, so we filter them out. 950;; start) and friends return bad values, so we filter them out.
943;; However, we don't filter these nodes out if a function will process 951;; However, we don't filter these nodes out if a function will process
944;; the node, because could (and often do) fontify the relatives of the 952;; the node, because it could (and often do) fontify the relatives of
945;; captured node, not just the node itself. If we took out those 953;; the captured node, not just the node itself. If we took out those
946;; nodes author of those functions would be very confused. 954;; nodes author of those functions would be very confused.
947(defun treesit-font-lock-fontify-region (start end &optional loudly) 955(defun treesit-font-lock-fontify-region (start end &optional loudly)
948 "Fontify the region between START and END. 956 "Fontify the region between START and END.
@@ -979,9 +987,12 @@ If LOUDLY is non-nil, display some debugging information."
979 (end-time (current-time))) 987 (end-time (current-time)))
980 ;; If for any query the query time is strangely long, 988 ;; If for any query the query time is strangely long,
981 ;; switch to fast mode (see comments above). 989 ;; switch to fast mode (see comments above).
982 (when (> (time-to-seconds (time-subtract end-time start-time)) 990 (when (and (> (time-to-seconds
983 0.01) 991 (time-subtract end-time start-time))
984 (setq-local treesit--font-lock-fast-mode t)) 992 0.01))
993 (if (> treesit--font-lock-fast-mode-grace-count 0)
994 (cl-decf treesit--font-lock-fast-mode-grace-count)
995 (setq-local treesit--font-lock-fast-mode t)))
985 996
986 ;; For each captured node, fontify that node. 997 ;; For each captured node, fontify that node.
987 (with-silent-modifications 998 (with-silent-modifications
@@ -1152,6 +1163,9 @@ See `treesit-simple-indent-presets'.")
1152 (and (>= (point) comment-start-bol) 1163 (and (>= (point) comment-start-bol)
1153 adaptive-fill-regexp 1164 adaptive-fill-regexp
1154 (looking-at adaptive-fill-regexp) 1165 (looking-at adaptive-fill-regexp)
1166 ;; If previous line is an empty line, don't
1167 ;; indent.
1168 (not (looking-at (rx (* whitespace) eol)))
1155 (match-end 0)))))) 1169 (match-end 0))))))
1156 ;; TODO: Document. 1170 ;; TODO: Document.
1157 (cons 'grand-parent 1171 (cons 'grand-parent
diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el
index 312556f644a..53d58870b32 100644
--- a/lisp/vc/vc-dir.el
+++ b/lisp/vc/vc-dir.el
@@ -325,7 +325,6 @@ See `run-hooks'."
325 (define-key map "U" #'vc-dir-unmark-all-files) 325 (define-key map "U" #'vc-dir-unmark-all-files)
326 (define-key map "\C-?" #'vc-dir-unmark-file-up) 326 (define-key map "\C-?" #'vc-dir-unmark-file-up)
327 (define-key map "\M-\C-?" #'vc-dir-unmark-all-files) 327 (define-key map "\M-\C-?" #'vc-dir-unmark-all-files)
328 (define-key map "%" #'vc-dir-mark-by-regexp)
329 ;; Movement. 328 ;; Movement.
330 (define-key map "n" #'vc-dir-next-line) 329 (define-key map "n" #'vc-dir-next-line)
331 (define-key map " " #'vc-dir-next-line) 330 (define-key map " " #'vc-dir-next-line)
@@ -361,8 +360,13 @@ See `run-hooks'."
361 (define-key branch-map "l" #'vc-print-branch-log) 360 (define-key branch-map "l" #'vc-print-branch-log)
362 (define-key branch-map "s" #'vc-switch-branch)) 361 (define-key branch-map "s" #'vc-switch-branch))
363 362
363 (let ((regexp-map (make-sparse-keymap)))
364 (define-key map "%" regexp-map)
365 (define-key regexp-map "m" #'vc-dir-mark-by-regexp))
366
364 (let ((mark-map (make-sparse-keymap))) 367 (let ((mark-map (make-sparse-keymap)))
365 (define-key map "*" mark-map) 368 (define-key map "*" mark-map)
369 (define-key mark-map "%" #'vc-dir-mark-by-regexp)
366 (define-key mark-map "r" #'vc-dir-mark-registered-files)) 370 (define-key mark-map "r" #'vc-dir-mark-registered-files))
367 371
368 ;; Hook up the menu. 372 ;; Hook up the menu.
@@ -791,7 +795,7 @@ MARK-FILES should be a list of absolute filenames."
791 vc-ewoc)) 795 vc-ewoc))
792 796
793(defun vc-dir-mark-registered-files () 797(defun vc-dir-mark-registered-files ()
794 "Mark files that are in one of registered state: edited, added or removed." 798 "Mark files that are in one of registered states: edited, added or removed."
795 (interactive) 799 (interactive)
796 (vc-dir-mark-state-files '(edited added removed))) 800 (vc-dir-mark-state-files '(edited added removed)))
797 801
diff --git a/lisp/window.el b/lisp/window.el
index 4099b707009..84f5c5c3f5a 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -5670,7 +5670,8 @@ the original point in both windows."
5670 5670
5671(defun split-window-below (&optional size window-to-split) 5671(defun split-window-below (&optional size window-to-split)
5672 "Split WINDOW-TO-SPLIT into two windows, one above the other. 5672 "Split WINDOW-TO-SPLIT into two windows, one above the other.
5673WINDOW-TO-SPLIT is above. The newly split-off window is 5673WINDOW-TO-SPLIT defaults to the selected window and and will be above
5674the other window after splitting. The newly split-off window is
5674below and displays the same buffer. Return the new window. 5675below and displays the same buffer. Return the new window.
5675 5676
5676If optional argument SIZE is omitted or nil, both windows get the 5677If optional argument SIZE is omitted or nil, both windows get the
@@ -5691,7 +5692,9 @@ amount of redisplay; this is convenient on slow terminals."
5691 ;; `split-window' would not signal an error here. 5692 ;; `split-window' would not signal an error here.
5692 (error "Size of new window too small")) 5693 (error "Size of new window too small"))
5693 (setq new-window (split-window window-to-split size)) 5694 (setq new-window (split-window window-to-split size))
5694 (unless split-window-keep-point 5695 (when (and (null split-window-keep-point)
5696 (or (null window-to-split)
5697 (eq window-to-split (selected-window))))
5695 (with-current-buffer (window-buffer window-to-split) 5698 (with-current-buffer (window-buffer window-to-split)
5696 ;; Use `save-excursion' around vertical movements below 5699 ;; Use `save-excursion' around vertical movements below
5697 ;; (Bug#10971). Note: When WINDOW-TO-SPLIT's buffer has a 5700 ;; (Bug#10971). Note: When WINDOW-TO-SPLIT's buffer has a
@@ -5732,8 +5735,9 @@ handled as in `split-window-below'."
5732 5735
5733(defun split-window-right (&optional size window-to-split) 5736(defun split-window-right (&optional size window-to-split)
5734 "Split WINDOW-TO-SPLIT into two side-by-side windows. 5737 "Split WINDOW-TO-SPLIT into two side-by-side windows.
5735WINDOW-TO-SPLIT is on the left. The newly split-off window is on 5738WINDOW-TO-SPLIT defaults to the selected window and and will be on the
5736the right and displays the same buffer. Return the new window. 5739left after splitting. The newly split-off window is on the right and
5740displays the same buffer. Return the new window.
5737 5741
5738If optional argument SIZE is omitted or nil, both windows get the 5742If optional argument SIZE is omitted or nil, both windows get the
5739same width, or close to it. If SIZE is positive, the left-hand 5743same width, or close to it. If SIZE is positive, the left-hand
diff --git a/src/buffer.c b/src/buffer.c
index 100e42fc1f9..88ca69b0dd8 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -525,14 +525,14 @@ get_truename_buffer (register Lisp_Object filename)
525 return Qnil; 525 return Qnil;
526} 526}
527 527
528/* Run buffer-list-update-hook if Vrun_hooks is non-nil, and BUF is NULL 528/* Run buffer-list-update-hook if Vrun_hooks is non-nil and BUF does
529 or does not have buffer hooks inhibited. BUF is NULL when called by 529 not have buffer hooks inhibited. */
530 make-indirect-buffer, since it does not inhibit buffer hooks. */
531 530
532static void 531static void
533run_buffer_list_update_hook (struct buffer *buf) 532run_buffer_list_update_hook (struct buffer *buf)
534{ 533{
535 if (! (NILP (Vrun_hooks) || (buf && buf->inhibit_buffer_hooks))) 534 eassert (buf);
535 if (! (NILP (Vrun_hooks) || buf->inhibit_buffer_hooks))
536 call1 (Vrun_hooks, Qbuffer_list_update_hook); 536 call1 (Vrun_hooks, Qbuffer_list_update_hook);
537} 537}
538 538
@@ -907,7 +907,7 @@ does not run the hooks `kill-buffer-hook',
907 set_buffer_internal_1 (old_b); 907 set_buffer_internal_1 (old_b);
908 } 908 }
909 909
910 run_buffer_list_update_hook (NULL); 910 run_buffer_list_update_hook (b);
911 911
912 return buf; 912 return buf;
913} 913}
diff --git a/src/treesit.c b/src/treesit.c
index 3886fed346e..917db582676 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -42,8 +42,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
42#undef ts_node_end_byte 42#undef ts_node_end_byte
43#undef ts_node_eq 43#undef ts_node_eq
44#undef ts_node_field_name_for_child 44#undef ts_node_field_name_for_child
45#undef ts_node_first_child_for_byte
46#undef ts_node_first_named_child_for_byte
47#undef ts_node_has_error 45#undef ts_node_has_error
48#undef ts_node_is_extra 46#undef ts_node_is_extra
49#undef ts_node_is_missing 47#undef ts_node_is_missing
@@ -99,8 +97,6 @@ DEF_DLL_FN (TSNode, ts_node_descendant_for_byte_range,
99DEF_DLL_FN (uint32_t, ts_node_end_byte, (TSNode)); 97DEF_DLL_FN (uint32_t, ts_node_end_byte, (TSNode));
100DEF_DLL_FN (bool, ts_node_eq, (TSNode, TSNode)); 98DEF_DLL_FN (bool, ts_node_eq, (TSNode, TSNode));
101DEF_DLL_FN (const char *, ts_node_field_name_for_child, (TSNode, uint32_t)); 99DEF_DLL_FN (const char *, ts_node_field_name_for_child, (TSNode, uint32_t));
102DEF_DLL_FN (TSNode, ts_node_first_child_for_byte, (TSNode, uint32_t));
103DEF_DLL_FN (TSNode, ts_node_first_named_child_for_byte, (TSNode, uint32_t));
104DEF_DLL_FN (bool, ts_node_has_error, (TSNode)); 100DEF_DLL_FN (bool, ts_node_has_error, (TSNode));
105DEF_DLL_FN (bool, ts_node_is_extra, (TSNode)); 101DEF_DLL_FN (bool, ts_node_is_extra, (TSNode));
106DEF_DLL_FN (bool, ts_node_is_missing, (TSNode)); 102DEF_DLL_FN (bool, ts_node_is_missing, (TSNode));
@@ -174,8 +170,6 @@ init_treesit_functions (void)
174 LOAD_DLL_FN (library, ts_node_end_byte); 170 LOAD_DLL_FN (library, ts_node_end_byte);
175 LOAD_DLL_FN (library, ts_node_eq); 171 LOAD_DLL_FN (library, ts_node_eq);
176 LOAD_DLL_FN (library, ts_node_field_name_for_child); 172 LOAD_DLL_FN (library, ts_node_field_name_for_child);
177 LOAD_DLL_FN (library, ts_node_first_child_for_byte);
178 LOAD_DLL_FN (library, ts_node_first_named_child_for_byte);
179 LOAD_DLL_FN (library, ts_node_has_error); 173 LOAD_DLL_FN (library, ts_node_has_error);
180 LOAD_DLL_FN (library, ts_node_is_extra); 174 LOAD_DLL_FN (library, ts_node_is_extra);
181 LOAD_DLL_FN (library, ts_node_is_missing); 175 LOAD_DLL_FN (library, ts_node_is_missing);
@@ -232,8 +226,6 @@ init_treesit_functions (void)
232#define ts_node_end_byte fn_ts_node_end_byte 226#define ts_node_end_byte fn_ts_node_end_byte
233#define ts_node_eq fn_ts_node_eq 227#define ts_node_eq fn_ts_node_eq
234#define ts_node_field_name_for_child fn_ts_node_field_name_for_child 228#define ts_node_field_name_for_child fn_ts_node_field_name_for_child
235#define ts_node_first_child_for_byte fn_ts_node_first_child_for_byte
236#define ts_node_first_named_child_for_byte fn_ts_node_first_named_child_for_byte
237#define ts_node_has_error fn_ts_node_has_error 229#define ts_node_has_error fn_ts_node_has_error
238#define ts_node_is_extra fn_ts_node_is_extra 230#define ts_node_is_extra fn_ts_node_is_extra
239#define ts_node_is_missing fn_ts_node_is_missing 231#define ts_node_is_missing fn_ts_node_is_missing
@@ -2095,6 +2087,41 @@ return nil. */)
2095 return make_treesit_node (XTS_NODE (node)->parser, sibling); 2087 return make_treesit_node (XTS_NODE (node)->parser, sibling);
2096} 2088}
2097 2089
2090/* Our reimplementation of ts_node_first_child_for_byte. The current
2091 implementation of that function has problems (see bug#60127), so
2092 before it's fixed upstream, we use our own reimplementation of it.
2093 Return true if there is a valid sibling, return false otherwise.
2094 If the return value is false, the position of the cursor is
2095 undefined. (We use cursor because technically we can't make a null
2096 node for ourselves, also, using cursor is more convenient.)
2097
2098 TODO: Remove this function once tree-sitter fixed the bug. */
2099static bool treesit_cursor_first_child_for_byte
2100(TSTreeCursor *cursor, ptrdiff_t pos, bool named)
2101{
2102 if (!ts_tree_cursor_goto_first_child (cursor))
2103 return false;
2104
2105 TSNode node = ts_tree_cursor_current_node (cursor);
2106 while (ts_node_end_byte (node) <= pos)
2107 {
2108 if (ts_tree_cursor_goto_next_sibling (cursor))
2109 node = ts_tree_cursor_current_node (cursor);
2110 else
2111 /* Reached the end and still can't find a valid sibling. */
2112 return false;
2113 }
2114 while (named && (!ts_node_is_named (node)))
2115 {
2116 if (ts_tree_cursor_goto_next_sibling (cursor))
2117 node = ts_tree_cursor_current_node (cursor);
2118 else
2119 /* Reached the end and still can't find a named sibling. */
2120 return false;
2121 }
2122 return true;
2123}
2124
2098DEFUN ("treesit-node-first-child-for-pos", 2125DEFUN ("treesit-node-first-child-for-pos",
2099 Ftreesit_node_first_child_for_pos, 2126 Ftreesit_node_first_child_for_pos,
2100 Streesit_node_first_child_for_pos, 2, 3, 0, 2127 Streesit_node_first_child_for_pos, 2, 3, 0,
@@ -2119,16 +2146,17 @@ Note that this function returns an immediate child, not the smallest
2119 2146
2120 ptrdiff_t byte_pos = buf_charpos_to_bytepos (buf, XFIXNUM (pos)); 2147 ptrdiff_t byte_pos = buf_charpos_to_bytepos (buf, XFIXNUM (pos));
2121 TSNode treesit_node = XTS_NODE (node)->node; 2148 TSNode treesit_node = XTS_NODE (node)->node;
2122 TSNode child;
2123 if (NILP (named))
2124 child = ts_node_first_child_for_byte (treesit_node, byte_pos - visible_beg);
2125 else
2126 child = ts_node_first_named_child_for_byte (treesit_node,
2127 byte_pos - visible_beg);
2128 2149
2129 if (ts_node_is_null (child)) 2150 TSTreeCursor cursor = ts_tree_cursor_new (treesit_node);
2130 return Qnil; 2151 ptrdiff_t treesit_pos = byte_pos - visible_beg;
2152 bool success;
2153 success = treesit_cursor_first_child_for_byte (&cursor, treesit_pos,
2154 !NILP (named));
2155 TSNode child = ts_tree_cursor_current_node (&cursor);
2156 ts_tree_cursor_delete (&cursor);
2131 2157
2158 if (!success)
2159 return Qnil;
2132 return make_treesit_node (XTS_NODE (node)->parser, child); 2160 return make_treesit_node (XTS_NODE (node)->parser, child);
2133} 2161}
2134 2162
@@ -3270,9 +3298,9 @@ a regexp. */)
3270 3298
3271 Lisp_Object parser = XTS_NODE (root)->parser; 3299 Lisp_Object parser = XTS_NODE (root)->parser;
3272 Lisp_Object parent = Fcons (Qnil, Qnil); 3300 Lisp_Object parent = Fcons (Qnil, Qnil);
3273 TSTreeCursor cursor; 3301 /* In this function we never traverse above NODE, so we don't need
3274 if (!treesit_cursor_helper (&cursor, XTS_NODE (root)->node, parser)) 3302 to use treesit_cursor_helper. */
3275 return Qnil; 3303 TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (root)->node);
3276 3304
3277 treesit_build_sparse_tree (&cursor, parent, predicate, process_fn, 3305 treesit_build_sparse_tree (&cursor, parent, predicate, process_fn,
3278 the_limit, parser); 3306 the_limit, parser);
diff --git a/test/lisp/erc/erc-scenarios-base-local-modules.el b/test/lisp/erc/erc-scenarios-base-local-modules.el
index d4001df45de..916d105779a 100644
--- a/test/lisp/erc/erc-scenarios-base-local-modules.el
+++ b/test/lisp/erc/erc-scenarios-base-local-modules.el
@@ -19,8 +19,17 @@
19 19
20;;; Commentary: 20;;; Commentary:
21 21
22;; These tests all use `sasl' because, as of ERC 5.5, it's the one 22;; A local module doubles as a minor mode whose mode variable and
23;; and only local module. 23;; associated local data can withstand service disruptions.
24;; Unfortunately, the current implementation is too unwieldy to be
25;; made public because it doesn't perform any of the boiler plate
26;; needed to save and restore buffer-local and "network-local" copies
27;; of user options. Ultimately, a user-friendly framework must fill
28;; this void if third-party local modules are ever to become
29;; practical.
30;;
31;; The following tests all use `sasl' because, as of ERC 5.5, it's the
32;; only local module.
24 33
25;;; Code: 34;;; Code:
26 35
@@ -206,7 +215,7 @@
206 (erc-cmd-QUIT "") 215 (erc-cmd-QUIT "")
207 (funcall expect 10 "finished"))) 216 (funcall expect 10 "finished")))
208 217
209 (ert-info ("Disabling works from a target buffer.") 218 (ert-info ("Disabling works from a target buffer")
210 (with-current-buffer "#chan" 219 (with-current-buffer "#chan"
211 (should erc-sasl-mode) 220 (should erc-sasl-mode)
212 (call-interactively #'erc-sasl-disable) 221 (call-interactively #'erc-sasl-disable)
@@ -214,10 +223,9 @@
214 (should (local-variable-p 'erc-sasl-mode)) 223 (should (local-variable-p 'erc-sasl-mode))
215 (should-not (buffer-local-value 'erc-sasl-mode (get-buffer "foonet"))) 224 (should-not (buffer-local-value 'erc-sasl-mode (get-buffer "foonet")))
216 (erc-cmd-RECONNECT) 225 (erc-cmd-RECONNECT)
217 (with-current-buffer "#chan" 226 (funcall expect 10 "Some enigma, some riddle")
218 (funcall expect 10 "Some enigma, some riddle") 227 (should-not erc-sasl-mode) ; regression
219 (should-not erc-sasl-mode) ; regression 228 (should (local-variable-p 'erc-sasl-mode)))
220 (should (local-variable-p 'erc-sasl-mode))))
221 229
222 (with-current-buffer "foonet" 230 (with-current-buffer "foonet"
223 (should (local-variable-p 'erc-sasl-mode)) 231 (should (local-variable-p 'erc-sasl-mode))
@@ -239,4 +247,82 @@
239 (should erc-sasl-mode) 247 (should erc-sasl-mode)
240 (funcall expect 10 "User modes for tester"))))) 248 (funcall expect 10 "User modes for tester")))))
241 249
250(defvar-local erc-scenarios-base-local-modules--local-var nil)
251
252(define-erc-module -phony-sblm- nil
253 "Test module for `erc-scenarios-base-local-modules--var-persistence'."
254 ((when-let ((vars (or erc--server-reconnecting erc--target-priors)))
255 (should (assq 'erc--phony-sblm--mode vars))
256 (setq erc-scenarios-base-local-modules--local-var
257 (alist-get 'erc-scenarios-base-local-modules--local-var vars)))
258 (setq erc-scenarios-base-local-modules--local-var
259 (or erc-scenarios-base-local-modules--local-var
260 (if erc--target 100 0))))
261 ((kill-local-variable 'erc-scenarios-base-local-modules--local-var))
262 'local)
263
264;; Note: this file has grown too expensive (time-wise) and must be
265;; split up. When that happens, this test should be rewritten without
266;; any time-saving hacks, namely, server-initiated JOINs and an
267;; absence of QUITs. (That said, three connections in under 2 seconds
268;; is pretty nice.)
269
270(ert-deftest erc-scenarios-base-local-modules--var-persistence ()
271 :tags '(:expensive-test)
272 (erc-scenarios-common-with-cleanup
273 ((erc-scenarios-common-dialog "base/reconnect")
274 (erc-server-flood-penalty 0.1)
275 (dumb-server (erc-d-run "localhost" t 'options 'options 'options))
276 (port (process-contact dumb-server :service))
277 (erc-modules (cons '-phony-sblm- (remq 'autojoin erc-modules)))
278 (expect (erc-d-t-make-expecter))
279 (server-buffer-name (format "127.0.0.1:%d" port)))
280
281 (ert-info ("Initial authentication succeeds as expected")
282 (with-current-buffer (erc :server "127.0.0.1"
283 :port port
284 :nick "tester"
285 :password "changeme"
286 :full-name "tester")
287 (should (string= (buffer-name) server-buffer-name)))
288
289 (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "FooNet"))
290 (funcall expect 10 "This server is in debug mode")
291 (should erc--phony-sblm--mode)
292 (should (eql erc-scenarios-base-local-modules--local-var 0))
293 (setq erc-scenarios-base-local-modules--local-var 1)))
294
295 (ert-info ("Save module's local var in target buffer")
296 (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
297 (should (eql erc-scenarios-base-local-modules--local-var 100))
298 (setq erc-scenarios-base-local-modules--local-var 101)
299 (funcall expect 20 "welcome")))
300
301 (with-current-buffer "FooNet" (funcall expect 20 "terminated"))
302
303 (ert-info ("Vars reused when mode was left enabled")
304 (with-current-buffer "#chan"
305 (erc-cmd-RECONNECT)
306 (funcall expect 20 "welcome")
307 (should (eql erc-scenarios-base-local-modules--local-var 101))
308 (erc--phony-sblm--mode -1))
309
310 (with-current-buffer "FooNet"
311 (funcall expect 10 "User modes for tester")
312 (should (eql erc-scenarios-base-local-modules--local-var 1))))
313
314 (with-current-buffer "FooNet" (funcall expect 20 "terminated"))
315
316 (ert-info ("Local binding gone when mode disabled in target")
317 (with-current-buffer "#chan"
318 (erc-cmd-RECONNECT)
319 (funcall expect 20 "welcome")
320 (should-not erc--phony-sblm--mode)
321 (should-not erc-scenarios-base-local-modules--local-var))
322
323 ;; But value retained in server buffer, where mode is active.
324 (with-current-buffer "FooNet"
325 (funcall expect 10 "User modes for tester")
326 (should (eql erc-scenarios-base-local-modules--local-var 1))))))
327
242;;; erc-scenarios-local-modules.el ends here 328;;; erc-scenarios-local-modules.el ends here
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 85506c3d27e..40a2d2de657 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -1251,18 +1251,28 @@
1251 (setq calls nil))))) 1251 (setq calls nil)))))
1252 1252
1253(ert-deftest erc--merge-local-modes () 1253(ert-deftest erc--merge-local-modes ()
1254 1254 (cl-letf (((get 'erc-b-mode 'erc-module) 'b)
1255 (ert-info ("No existing modes") 1255 ((get 'erc-c-mode 'erc-module) 'c)
1256 (let ((old '((a) (b . t))) 1256 ((get 'erc-d-mode 'erc-module) 'd)
1257 (new '(erc-c-mode erc-d-mode))) 1257 ((get 'erc-e-mode 'erc-module) 'e))
1258 (should (equal (erc--merge-local-modes new old) 1258
1259 '((erc-c-mode erc-d-mode)))))) 1259 (ert-info ("No existing modes")
1260 1260 (let ((old '((a) (b . t)))
1261 (ert-info ("Active existing added, inactive existing removed, deduped") 1261 (new '(erc-c-mode erc-d-mode)))
1262 (let ((old '((a) (erc-b-mode) (c . t) (erc-d-mode . t) (erc-e-mode . t))) 1262 (should (equal (erc--merge-local-modes new old)
1263 (new '(erc-b-mode erc-d-mode))) 1263 '((erc-c-mode erc-d-mode))))))
1264 (should (equal (erc--merge-local-modes new old) 1264
1265 '((erc-d-mode erc-e-mode) . (erc-b-mode))))))) 1265 (ert-info ("Active existing added, inactive existing removed, deduped")
1266 (let ((old '((a) (erc-b-mode) (c . t) (erc-d-mode . t) (erc-e-mode . t)))
1267 (new '(erc-b-mode erc-d-mode)))
1268 (should (equal (erc--merge-local-modes new old)
1269 '((erc-d-mode erc-e-mode) . (erc-b-mode))))))
1270
1271 (ert-info ("Non-module erc-prefixed mode ignored")
1272 (let ((old '((erc-b-mode) (erc-f-mode . t) (erc-d-mode . t)))
1273 (new '(erc-b-mode)))
1274 (should (equal (erc--merge-local-modes new old)
1275 '((erc-d-mode) . (erc-b-mode))))))))
1266 1276
1267(ert-deftest define-erc-module--global () 1277(ert-deftest define-erc-module--global ()
1268 (let ((global-module '(define-erc-module mname malias 1278 (let ((global-module '(define-erc-module mname malias
@@ -1300,13 +1310,15 @@ Some docstring"
1300 (ignore c) (ignore d)) 1310 (ignore c) (ignore d))
1301 1311
1302 (defalias 'erc-malias-mode #'erc-mname-mode) 1312 (defalias 'erc-malias-mode #'erc-mname-mode)
1313 (put 'erc-malias-mode 'erc-module 'mname)
1303 1314
1315 (put 'erc-mname-mode 'erc-module 'mname)
1304 (put 'erc-mname-mode 'definition-name 'mname) 1316 (put 'erc-mname-mode 'definition-name 'mname)
1305 (put 'erc-mname-enable 'definition-name 'mname) 1317 (put 'erc-mname-enable 'definition-name 'mname)
1306 (put 'erc-mname-disable 'definition-name 'mname)))))) 1318 (put 'erc-mname-disable 'definition-name 'mname))))))
1307 1319
1308(ert-deftest define-erc-module--local () 1320(ert-deftest define-erc-module--local ()
1309 (let* ((global-module '(define-erc-module mname malias 1321 (let* ((global-module '(define-erc-module mname nil ; no alias
1310 "Some docstring" 1322 "Some docstring"
1311 ((ignore a) (ignore b)) 1323 ((ignore a) (ignore b))
1312 ((ignore c) (ignore d)) 1324 ((ignore c) (ignore d))
@@ -1353,8 +1365,7 @@ When called interactively, do so in all buffers for the current connection."
1353 (setq erc-mname-mode nil) 1365 (setq erc-mname-mode nil)
1354 (ignore c) (ignore d)))) 1366 (ignore c) (ignore d))))
1355 1367
1356 (defalias 'erc-malias-mode #'erc-mname-mode) 1368 (put 'erc-mname-mode 'erc-module 'mname)
1357
1358 (put 'erc-mname-mode 'definition-name 'mname) 1369 (put 'erc-mname-mode 'definition-name 'mname)
1359 (put 'erc-mname-enable 'definition-name 'mname) 1370 (put 'erc-mname-enable 'definition-name 'mname)
1360 (put 'erc-mname-disable 'definition-name 'mname)))))) 1371 (put 'erc-mname-disable 'definition-name 'mname))))))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld b/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld
index e2fe1430283..a270c743d90 100644
--- a/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld
+++ b/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld
@@ -1,7 +1,7 @@
1;; -*- mode: lisp-data; -*- 1;; -*- mode: lisp-data; -*-
2((pass 10 "PASS :barnet:changeme")) 2((pass 10 "PASS :barnet:changeme"))
3((nick 3 "NICK tester")) 3((nick 10 "NICK tester"))
4((user 3 "USER user 0 * :tester") 4((user 10 "USER user 0 * :tester")
5 (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester") 5 (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
6 (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version oragono-2.6.0-7481bf0385b95b16") 6 (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version oragono-2.6.0-7481bf0385b95b16")
7 (0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021 07:41:08 UTC") 7 (0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021 07:41:08 UTC")
@@ -17,7 +17,7 @@
17 (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3") 17 (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
18 (0 ":irc.barnet.org 422 tester :MOTD File is missing")) 18 (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
19 19
20((mode-user 10.2 "MODE tester +i") 20((mode-user 10 "MODE tester +i")
21 ;; No mode answer ^ 21 ;; No mode answer ^
22 22
23 (0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #chan") 23 (0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #chan")
@@ -36,9 +36,9 @@
36 (0 ":irc.znc.in 306 tester :You have been marked as being away") 36 (0 ":irc.znc.in 306 tester :You have been marked as being away")
37 (0 ":irc.barnet.org 305 tester :You are no longer marked as being away")) 37 (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
38 38
39((~join 3 "JOIN #chan")) 39((~join 10 "JOIN #chan"))
40 40
41((mode 5 "MODE #chan") 41((mode 10 "MODE #chan")
42 (0 ":irc.barnet.org 324 tester #chan +nt") 42 (0 ":irc.barnet.org 324 tester #chan +nt")
43 (0 ":irc.barnet.org 329 tester #chan 1620805269") 43 (0 ":irc.barnet.org 329 tester #chan 1620805269")
44 (0.1 ":joe!~u@svpn88yjcdj42.irc PRIVMSG #chan :mike: But, in defense, by mercy, 'tis most just.") 44 (0.1 ":joe!~u@svpn88yjcdj42.irc PRIVMSG #chan :mike: But, in defense, by mercy, 'tis most just.")
diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld b/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld
index bf8712305a4..a8c352daaa7 100644
--- a/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld
+++ b/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld
@@ -1,7 +1,7 @@
1;; -*- mode: lisp-data; -*- 1;; -*- mode: lisp-data; -*-
2((pass 10 "PASS :foonet:changeme")) 2((pass 10 "PASS :foonet:changeme"))
3((nick 3 "NICK tester")) 3((nick 10 "NICK tester"))
4((user 3 "USER user 0 * :tester") 4((user 10 "USER user 0 * :tester")
5 (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester") 5 (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
6 (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.0-7481bf0385b95b16") 6 (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.0-7481bf0385b95b16")
7 (0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021 07:41:09 UTC") 7 (0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021 07:41:09 UTC")
@@ -17,7 +17,7 @@
17 (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3") 17 (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
18 (0 ":irc.foonet.org 422 tester :MOTD File is missing")) 18 (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
19 19
20((mode-user 10.2 "MODE tester +i") 20((mode-user 10 "MODE tester +i")
21 ;; No mode answer ^ 21 ;; No mode answer ^
22 (0 ":tester!~u@nvfhxvqm92rm6.irc JOIN #chan") 22 (0 ":tester!~u@nvfhxvqm92rm6.irc JOIN #chan")
23 (0 ":irc.foonet.org 353 tester = #chan :alice @bob tester") 23 (0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
@@ -36,9 +36,9 @@
36 (0 ":irc.foonet.org NOTICE tester :[07:00:32] This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect.") 36 (0 ":irc.foonet.org NOTICE tester :[07:00:32] This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect.")
37 (0 ":irc.foonet.org 305 tester :You are no longer marked as being away")) 37 (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
38 38
39((~join 3 "JOIN #chan")) 39((~join 10 "JOIN #chan"))
40 40
41((mode 8 "MODE #chan") 41((mode 10 "MODE #chan")
42 (0 ":irc.foonet.org 324 tester #chan +nt") 42 (0 ":irc.foonet.org 324 tester #chan +nt")
43 (0 ":irc.foonet.org 329 tester #chan 1620805271") 43 (0 ":irc.foonet.org 329 tester #chan 1620805271")
44 (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: Grows, lives, and dies, in single blessedness.") 44 (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: Grows, lives, and dies, in single blessedness.")
diff --git a/test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb b/test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb
new file mode 100644
index 00000000000..4be532a5e9d
--- /dev/null
+++ b/test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb
@@ -0,0 +1,94 @@
1variable = foo(
2 [
3 qwe
4 ], [
5 rty
6 ], {
7 a: 3
8 }
9)
10
11tee = [
12 qwe
13]
14
15qux = [1,
16 2]
17
18att = {a: 1,
19 b: 2}
20
21a = 1 ? 2 :(
22 2 + 3
23)
24
25unless bismark
26 sink += 12
27else
28 dog = 99
29end
30
31foo1 =
32 subject.update(
33 1
34 )
35
36foo2 =
37 subject.
38 update(
39 # Might make sense to indent this to 'subject' instead; but this
40 # style seems more popular.
41 2
42 )
43
44foo > bar &&
45 tee < qux
46
471 .. 2 &&
48 3
49
50a = foo(j, k) -
51 bar_tee
52
53qux = foo.fee ?
54 bar :
55 tee
56
57with_paren = (a + b *
58 c * d +
59 12)
60
61without_paren = a + b *
62 c * d +
63 12
64
65{'a' => {
66 'b' => 'c',
67 'd' => %w(e f)
68 }
69}
70
71[1, 2, {
72 'b' => 'c',
73 'd' => %w(e f)
74 }
75]
76
77foo(a, {
78 a: b,
79 c: d
80 })
81
82foo(foo, bar:
83 tee)
84
85foo(foo, :bar =>
86 tee)
87
88# Local Variables:
89# mode: ruby-ts
90# ruby-after-operator-indent: t
91# ruby-block-indent: t
92# ruby-method-call-indent: t
93# ruby-method-params-indent: t
94# End:
diff --git a/test/lisp/progmodes/ruby-ts-mode-tests.el b/test/lisp/progmodes/ruby-ts-mode-tests.el
index eaf6367a306..d34c235e82b 100644
--- a/test/lisp/progmodes/ruby-ts-mode-tests.el
+++ b/test/lisp/progmodes/ruby-ts-mode-tests.el
@@ -250,8 +250,12 @@ The whitespace before and including \"|\" on each line is removed."
250 (should (equal (buffer-string) orig)))) 250 (should (equal (buffer-string) orig))))
251 (kill-buffer buf))))) 251 (kill-buffer buf)))))
252 252
253(ruby-ts-deftest-indent "ruby-method-params-indent.rb") 253(ruby-ts-deftest-indent "ruby-ts.rb")
254(ruby-ts-deftest-indent "ruby-after-operator-indent.rb")
254(ruby-ts-deftest-indent "ruby-block-indent.rb") 255(ruby-ts-deftest-indent "ruby-block-indent.rb")
256(ruby-ts-deftest-indent "ruby-method-call-indent.rb")
257(ruby-ts-deftest-indent "ruby-method-params-indent.rb")
258(ruby-ts-deftest-indent "ruby-parenless-call-arguments-indent.rb")
255 259
256(provide 'ruby-ts-mode-tests) 260(provide 'ruby-ts-mode-tests)
257 261
diff --git a/test/src/buffer-tests.el b/test/src/buffer-tests.el
index e5de8f3464a..9d4bbf3e040 100644
--- a/test/src/buffer-tests.el
+++ b/test/src/buffer-tests.el
@@ -8315,29 +8315,35 @@ dicta sunt, explicabo. "))
8315 (remove-hook 'buffer-list-update-hook bluh)))) 8315 (remove-hook 'buffer-list-update-hook bluh))))
8316 8316
8317(ert-deftest buffer-tests-inhibit-buffer-hooks-indirect () 8317(ert-deftest buffer-tests-inhibit-buffer-hooks-indirect ()
8318 "Indirect buffers do not call `get-buffer-create'." 8318 "Test `make-indirect-buffer' argument INHIBIT-BUFFER-HOOKS."
8319 (dolist (inhibit '(nil t)) 8319 (let* ( base run-bluh run-kbh run-kbqf
8320 (let ((base (get-buffer-create "foo" inhibit))) 8320 (bluh (lambda () (setq run-bluh t)))
8321 (kbh (lambda () (setq run-kbh t)))
8322 (kbqf (lambda () (setq run-kbqf t))))
8323 (dolist (inhibit-base '(nil t))
8321 (unwind-protect 8324 (unwind-protect
8322 (dotimes (_i 11) 8325 (let (indirect)
8323 (let* (flag* 8326 (setq base (generate-new-buffer " base" inhibit-base))
8324 (flag (lambda () (prog1 t (setq flag* t)))) 8327 (dolist (inhibit-indirect '(nil t))
8325 (indirect (make-indirect-buffer base "foo[indirect]" nil 8328 (dotimes (_ 11)
8326 inhibit))) 8329 (unwind-protect
8327 (unwind-protect 8330 (let ((name (generate-new-buffer-name " indirect")))
8328 (progn 8331 (setq run-bluh nil run-kbh nil run-kbqf nil)
8329 (with-current-buffer indirect 8332 (add-hook 'buffer-list-update-hook bluh)
8330 (add-hook 'kill-buffer-query-functions flag nil t)) 8333 (with-current-buffer
8331 (kill-buffer indirect) 8334 (setq indirect (make-indirect-buffer
8332 (if inhibit 8335 base name nil inhibit-indirect))
8333 (should-not flag*) 8336 (add-hook 'kill-buffer-hook kbh nil t)
8334 (should flag*))) 8337 (add-hook 'kill-buffer-query-functions kbqf nil t)
8335 (let (kill-buffer-query-functions) 8338 (kill-buffer))
8339 (should (xor inhibit-indirect run-bluh))
8340 (should (xor inhibit-indirect run-kbh))
8341 (should (xor inhibit-indirect run-kbqf)))
8342 (remove-hook 'buffer-list-update-hook bluh)
8336 (when (buffer-live-p indirect) 8343 (when (buffer-live-p indirect)
8337 (kill-buffer indirect)))))) 8344 (kill-buffer indirect))))))
8338 (let (kill-buffer-query-functions) 8345 (when (buffer-live-p base)
8339 (when (buffer-live-p base) 8346 (kill-buffer base))))))
8340 (kill-buffer base)))))))
8341 8347
8342(ert-deftest zero-length-overlays-and-not () 8348(ert-deftest zero-length-overlays-and-not ()
8343 (with-temp-buffer 8349 (with-temp-buffer