summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Whitton <spwhitton@spwhitton.name>2023-02-03 14:47:28 -0700
committerSean Whitton <spwhitton@spwhitton.name>2023-02-03 14:47:28 -0700
commit7c947b1c27f0f32169ffac630a7e79a79cf2af8b (patch)
tree368325ea4d94134fc6e67da1111849146c00759f
parent5bf195aace31dacda96651a576c3afaa3fc3f346 (diff)
parentcb9628373a8dcb5ace0cb8fcc7b636dea39b5703 (diff)
downloademacs-7c947b1c27f0f32169ffac630a7e79a79cf2af8b.tar.gz
Merge upstream Git snapshot into athena/unstable
-rw-r--r--admin/notes/tree-sitter/html-manual/Accessing-Node.html2
-rw-r--r--admin/notes/tree-sitter/html-manual/Language-Definitions.html2
-rw-r--r--admin/notes/tree-sitter/html-manual/Parser_002dbased-Font-Lock.html2
-rw-r--r--admin/notes/tree-sitter/html-manual/Retrieving-Node.html10
-rw-r--r--admin/notes/tree-sitter/html-manual/Tree_002dsitter-C-API.html12
-rw-r--r--admin/notes/tree-sitter/starter-guide2
-rw-r--r--doc/emacs/custom.texi49
-rw-r--r--doc/emacs/maintaining.texi9
-rw-r--r--doc/emacs/misc.texi177
-rw-r--r--doc/emacs/modes.texi18
-rw-r--r--doc/lispref/functions.texi14
-rw-r--r--doc/lispref/help.texi18
-rw-r--r--doc/lispref/keymaps.texi18
-rw-r--r--doc/lispref/minibuf.texi2
-rw-r--r--doc/lispref/modes.texi24
-rw-r--r--doc/lispref/parsing.texi104
-rw-r--r--doc/lispref/positions.texi2
-rw-r--r--doc/lispref/strings.texi4
-rw-r--r--doc/lispref/symbols.texi17
-rw-r--r--doc/misc/eglot.texi2
-rw-r--r--doc/misc/eshell.texi136
-rw-r--r--doc/misc/htmlfontify.texi13
-rw-r--r--doc/misc/modus-themes.org4
-rw-r--r--doc/misc/org.org15
-rw-r--r--etc/NEWS403
-rw-r--r--etc/PROBLEMS12
-rw-r--r--etc/refcards/orgcard.tex2
-rw-r--r--lisp/align.el3
-rw-r--r--lisp/apropos.el177
-rw-r--r--lisp/calendar/diary-lib.el5
-rw-r--r--lisp/cedet/semantic/symref/grep.el5
-rw-r--r--lisp/char-fold.el18
-rw-r--r--lisp/doc-view.el4
-rw-r--r--lisp/emacs-lisp/advice.el2
-rw-r--r--lisp/emacs-lisp/cl-macs.el2
-rw-r--r--lisp/emacs-lisp/ert-x.el2
-rw-r--r--lisp/emacs-lisp/package-vc.el8
-rw-r--r--lisp/emacs-lisp/pp.el12
-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-networks.el6
-rw-r--r--lisp/erc/erc-track.el12
-rw-r--r--lisp/erc/erc.el35
-rw-r--r--lisp/eshell/em-basic.el3
-rw-r--r--lisp/eshell/esh-var.el7
-rw-r--r--lisp/files.el35
-rw-r--r--lisp/find-dired.el6
-rw-r--r--lisp/font-lock.el15
-rw-r--r--lisp/frame.el2
-rw-r--r--lisp/htmlfontify.el24
-rw-r--r--lisp/icomplete.el4
-rw-r--r--lisp/international/mule.el7
-rw-r--r--lisp/keymap.el15
-rw-r--r--lisp/ldefs-boot.el72
-rw-r--r--lisp/ls-lisp.el18
-rw-r--r--lisp/mh-e/mh-e.el5
-rw-r--r--lisp/minibuffer.el2
-rw-r--r--lisp/net/sieve-manage.el26
-rw-r--r--lisp/net/tramp.el15
-rw-r--r--lisp/org/ob-core.el16
-rw-r--r--lisp/org/ob-ruby.el5
-rw-r--r--lisp/org/ob-shell.el2
-rw-r--r--lisp/org/org-agenda.el17
-rw-r--r--lisp/org/org-clock.el30
-rw-r--r--lisp/org/org-element.el4
-rw-r--r--lisp/org/org-fold-core.el21
-rw-r--r--lisp/org/org-macs.el11
-rw-r--r--lisp/org/org-mouse.el4
-rw-r--r--lisp/org/org-persist.el7
-rw-r--r--lisp/org/org-table.el11
-rw-r--r--lisp/org/org-version.el4
-rw-r--r--lisp/org/org.el26
-rw-r--r--lisp/org/ox-odt.el2
-rw-r--r--lisp/org/ox.el5
-rw-r--r--lisp/outline.el22
-rw-r--r--lisp/pcomplete.el29
-rw-r--r--lisp/progmodes/c-ts-common.el247
-rw-r--r--lisp/progmodes/c-ts-mode.el515
-rw-r--r--lisp/progmodes/cc-defs.el22
-rw-r--r--lisp/progmodes/cc-engine.el90
-rw-r--r--lisp/progmodes/cc-fonts.el70
-rw-r--r--lisp/progmodes/cc-mode.el40
-rw-r--r--lisp/progmodes/cmake-ts-mode.el8
-rw-r--r--lisp/progmodes/csharp-mode.el23
-rw-r--r--lisp/progmodes/dockerfile-ts-mode.el12
-rw-r--r--lisp/progmodes/eglot.el27
-rw-r--r--lisp/progmodes/go-ts-mode.el119
-rw-r--r--lisp/progmodes/gud.el5
-rw-r--r--lisp/progmodes/java-ts-mode.el34
-rw-r--r--lisp/progmodes/js.el37
-rw-r--r--lisp/progmodes/json-ts-mode.el4
-rw-r--r--lisp/progmodes/project.el15
-rw-r--r--lisp/progmodes/python.el41
-rw-r--r--lisp/progmodes/ruby-mode.el241
-rw-r--r--lisp/progmodes/ruby-ts-mode.el398
-rw-r--r--lisp/progmodes/rust-ts-mode.el14
-rw-r--r--lisp/progmodes/typescript-ts-mode.el62
-rw-r--r--lisp/progmodes/xref.el2
-rw-r--r--lisp/replace.el6
-rw-r--r--lisp/simple.el83
-rw-r--r--lisp/sqlite-mode.el4
-rw-r--r--lisp/startup.el2
-rw-r--r--lisp/subr.el21
-rw-r--r--lisp/textmodes/css-mode.el4
-rw-r--r--lisp/textmodes/reftex-cite.el2
-rw-r--r--lisp/textmodes/toml-ts-mode.el6
-rw-r--r--lisp/textmodes/yaml-ts-mode.el6
-rw-r--r--lisp/treesit.el238
-rw-r--r--lisp/use-package/use-package-core.el2
-rw-r--r--lisp/use-package/use-package.el2
-rw-r--r--lisp/vc/diff-mode.el14
-rw-r--r--lisp/vc/vc-dir.el8
-rw-r--r--lisp/vc/vc-git.el32
-rw-r--r--lisp/vc/vc.el17
-rw-r--r--lisp/wid-edit.el4
-rw-r--r--lisp/window.el12
-rw-r--r--lisp/woman.el60
-rw-r--r--lwlib/Makefile.in2
-rw-r--r--src/buffer.c10
-rw-r--r--src/callint.c12
-rw-r--r--src/ccl.c2
-rw-r--r--src/coding.c2
-rw-r--r--src/fns.c12
-rw-r--r--src/gnutls.c2
-rw-r--r--src/keyboard.c2
-rw-r--r--src/pgtkfns.c2
-rw-r--r--src/pgtkterm.c3
-rw-r--r--src/print.c9
-rw-r--r--src/regex-emacs.c2
-rw-r--r--src/treesit.c228
-rw-r--r--src/treesit.h1
-rw-r--r--src/w32.c45
-rw-r--r--src/w32fns.c44
-rw-r--r--src/xdisp.c15
-rw-r--r--test/lisp/erc/erc-scenarios-base-association.el49
-rw-r--r--test/lisp/erc/erc-scenarios-base-local-modules.el100
-rw-r--r--test/lisp/erc/erc-services-tests.el9
-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/erc/resources/erc-d/erc-d-t.el2
-rw-r--r--test/lisp/erc/resources/networks/merge-server/track.eld44
-rw-r--r--test/lisp/international/mule-tests.el66
-rw-r--r--test/lisp/net/tramp-archive-tests.el3
-rw-r--r--test/lisp/net/tramp-tests.el41
-rw-r--r--test/lisp/progmodes/c-ts-mode-resources/filling.erts198
-rw-r--r--test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts93
-rw-r--r--test/lisp/progmodes/c-ts-mode-resources/indent.erts190
-rw-r--r--test/lisp/progmodes/c-ts-mode-tests.el39
-rw-r--r--test/lisp/progmodes/python-tests.el10
-rw-r--r--test/lisp/progmodes/ruby-mode-resources/ruby-method-call-indent.rb9
-rw-r--r--test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb94
-rw-r--r--test/lisp/progmodes/ruby-mode-resources/ruby.rb2
-rw-r--r--test/lisp/progmodes/ruby-mode-tests.el3
-rw-r--r--test/lisp/progmodes/ruby-ts-mode-tests.el20
-rw-r--r--test/lisp/wid-edit-tests.el16
-rw-r--r--test/manual/indent/octave.m2
-rw-r--r--test/src/buffer-tests.el46
-rw-r--r--test/src/coding-tests.el30
-rw-r--r--test/src/keymap-tests.el33
161 files changed, 4238 insertions, 1725 deletions
diff --git a/admin/notes/tree-sitter/html-manual/Accessing-Node.html b/admin/notes/tree-sitter/html-manual/Accessing-Node.html
index 9e7a4b68299..afbbdaa11b5 100644
--- a/admin/notes/tree-sitter/html-manual/Accessing-Node.html
+++ b/admin/notes/tree-sitter/html-manual/Accessing-Node.html
@@ -187,7 +187,7 @@ of <var>node</var> as a child of its parent.
</p></dd></dl>
<dl class="def">
-<dt id="index-treesit_002dchild_002dcount"><span class="category">Function: </span><span><strong>treesit-child-count</strong> <em>node &amp;optional named</em><a href='#index-treesit_002dchild_002dcount' class='copiable-anchor'> &para;</a></span></dt>
+<dt id="index-treesit_002dchild_002dcount"><span class="category">Function: </span><span><strong>treesit-node-child-count</strong> <em>node &amp;optional named</em><a href='#index-treesit_002dchild_002dcount' class='copiable-anchor'> &para;</a></span></dt>
<dd><p>This function finds the number of children of <var>node</var>. If
<var>named</var> is non-nil, it only counts named child (see <a href="Language-Definitions.html#tree_002dsitter-named-node">named node</a>).
</p></dd></dl>
diff --git a/admin/notes/tree-sitter/html-manual/Language-Definitions.html b/admin/notes/tree-sitter/html-manual/Language-Definitions.html
index 6c17e8c3344..9b1e0021272 100644
--- a/admin/notes/tree-sitter/html-manual/Language-Definitions.html
+++ b/admin/notes/tree-sitter/html-manual/Language-Definitions.html
@@ -94,7 +94,7 @@ specified by <code>user-emacs-directory</code> (see <a href="Init-File.html">The
</li></ul>
<p>In each of these directories, Emacs looks for a file with file-name
-extensions specified by the variable <code>treesit-load-suffixes</code>.
+extensions specified by the variable <code>dynamic-library-suffixes</code>.
</p>
<p>If Emacs cannot find the library or has problems loading it, Emacs
signals the <code>treesit-load-language-error</code> error. The data of
diff --git a/admin/notes/tree-sitter/html-manual/Parser_002dbased-Font-Lock.html b/admin/notes/tree-sitter/html-manual/Parser_002dbased-Font-Lock.html
index 670f235bd20..a3fe6622162 100644
--- a/admin/notes/tree-sitter/html-manual/Parser_002dbased-Font-Lock.html
+++ b/admin/notes/tree-sitter/html-manual/Parser_002dbased-Font-Lock.html
@@ -134,7 +134,7 @@ example:
tree-sitter query in either the string, s-expression or compiled form.
</p>
<p>For each <var>query</var>, the <var>:keyword</var>/<var>value</var> pairs that
-precede it add meta information to it. The <code>:lang</code> keyword
+precede it add meta information to it. The <code>:language</code> keyword
declares <var>query</var>&rsquo;s language. The <code>:feature</code> keyword sets the
feature name of <var>query</var>. Users can control which features are
enabled with <code>font-lock-maximum-decoration</code> and
diff --git a/admin/notes/tree-sitter/html-manual/Retrieving-Node.html b/admin/notes/tree-sitter/html-manual/Retrieving-Node.html
index 58e87e8df7f..16eeb0b1091 100644
--- a/admin/notes/tree-sitter/html-manual/Retrieving-Node.html
+++ b/admin/notes/tree-sitter/html-manual/Retrieving-Node.html
@@ -201,13 +201,13 @@ is the string text.
</p></dd></dl>
<dl class="def">
-<dt id="index-treesit_002dnext_002dsibling"><span class="category">Function: </span><span><strong>treesit-next-sibling</strong> <em>node &amp;optional named</em><a href='#index-treesit_002dnext_002dsibling' class='copiable-anchor'> &para;</a></span></dt>
+<dt id="index-treesit_002dnext_002dsibling"><span class="category">Function: </span><span><strong>treesit-node-next-sibling</strong> <em>node &amp;optional named</em><a href='#index-treesit_002dnext_002dsibling' class='copiable-anchor'> &para;</a></span></dt>
<dd><p>This function finds the next sibling of <var>node</var>. If <var>named</var> is
non-<code>nil</code>, it finds the next named sibling.
</p></dd></dl>
<dl class="def">
-<dt id="index-treesit_002dprev_002dsibling"><span class="category">Function: </span><span><strong>treesit-prev-sibling</strong> <em>node &amp;optional named</em><a href='#index-treesit_002dprev_002dsibling' class='copiable-anchor'> &para;</a></span></dt>
+<dt id="index-treesit_002dprev_002dsibling"><span class="category">Function: </span><span><strong>treesit-node-prev-sibling</strong> <em>node &amp;optional named</em><a href='#index-treesit_002dprev_002dsibling' class='copiable-anchor'> &para;</a></span></dt>
<dd><p>This function finds the previous sibling of <var>node</var>. If
<var>named</var> is non-<code>nil</code>, it finds the previous named sibling.
</p></dd></dl>
@@ -221,13 +221,13 @@ assign <em>field names</em> to child nodes (see <a href="Language-Definitions.ht
could have a <code>declarator</code> node and a <code>body</code> node.
</p>
<dl class="def">
-<dt id="index-treesit_002dchild_002dby_002dfield_002dname"><span class="category">Function: </span><span><strong>treesit-child-by-field-name</strong> <em>node field-name</em><a href='#index-treesit_002dchild_002dby_002dfield_002dname' class='copiable-anchor'> &para;</a></span></dt>
+<dt id="index-treesit_002dchild_002dby_002dfield_002dname"><span class="category">Function: </span><span><strong>treesit-node-child-by-field-name</strong> <em>node field-name</em><a href='#index-treesit_002dchild_002dby_002dfield_002dname' class='copiable-anchor'> &para;</a></span></dt>
<dd><p>This function finds the child of <var>node</var> whose field name is
<var>field-name</var>, a string.
</p>
<div class="example">
<pre class="example">;; Get the child that has &quot;body&quot; as its field name.
-(treesit-child-by-field-name node &quot;body&quot;)
+(treesit-node-child-by-field-name node &quot;body&quot;)
&rArr; #&lt;treesit-node (compound_statement) in 45-89&gt;
</pre></div>
</dd></dl>
@@ -237,7 +237,7 @@ could have a <code>declarator</code> node and a <code>body</code> node.
<span id="index-syntax-tree-nodes_002c-by-position"></span>
<dl class="def">
-<dt id="index-treesit_002dfirst_002dchild_002dfor_002dpos"><span class="category">Function: </span><span><strong>treesit-first-child-for-pos</strong> <em>node pos &amp;optional named</em><a href='#index-treesit_002dfirst_002dchild_002dfor_002dpos' class='copiable-anchor'> &para;</a></span></dt>
+<dt id="index-treesit_002dfirst_002dchild_002dfor_002dpos"><span class="category">Function: </span><span><strong>treesit-node-first-child-for-pos</strong> <em>node pos &amp;optional named</em><a href='#index-treesit_002dfirst_002dchild_002dfor_002dpos' class='copiable-anchor'> &para;</a></span></dt>
<dd><p>This function finds the first child of <var>node</var> that extends beyond
buffer position <var>pos</var>. &ldquo;Extends beyond&rdquo; means the end of the
child node is greater or equal to <var>pos</var>. This function only looks
diff --git a/admin/notes/tree-sitter/html-manual/Tree_002dsitter-C-API.html b/admin/notes/tree-sitter/html-manual/Tree_002dsitter-C-API.html
index 0c827b3e755..1d992b828ea 100644
--- a/admin/notes/tree-sitter/html-manual/Tree_002dsitter-C-API.html
+++ b/admin/notes/tree-sitter/html-manual/Tree_002dsitter-C-API.html
@@ -142,12 +142,12 @@ ts_node_named_child treesit-node-child
ts_node_named_child_count treesit-node-child-count
ts_node_child_by_field_name treesit-node-by-field-name
ts_node_child_by_field_id
-ts_node_next_sibling treesit-next-sibling
-ts_node_prev_sibling treesit-prev-sibling
-ts_node_next_named_sibling treesit-next-sibling
-ts_node_prev_named_sibling treesit-prev-sibling
-ts_node_first_child_for_byte treesit-first-child-for-pos
-ts_node_first_named_child_for_byte treesit-first-child-for-pos
+ts_node_next_sibling treesit-node-next-sibling
+ts_node_prev_sibling treesit-node-prev-sibling
+ts_node_next_named_sibling treesit-node-next-sibling
+ts_node_prev_named_sibling treesit-node-prev-sibling
+ts_node_first_child_for_byte treesit-node-first-child-for-pos
+ts_node_first_named_child_for_byte treesit-node-first-child-for-pos
ts_node_descendant_for_byte_range treesit-descendant-for-range
ts_node_descendant_for_point_range
ts_node_named_descendant_for_byte_range treesit-descendant-for-range
diff --git a/admin/notes/tree-sitter/starter-guide b/admin/notes/tree-sitter/starter-guide
index a6a4c647f23..606f7891dfa 100644
--- a/admin/notes/tree-sitter/starter-guide
+++ b/admin/notes/tree-sitter/starter-guide
@@ -238,7 +238,7 @@ Concretely, something like this:
...
(cond
;; Tree-sitter.
- ((treesit-ready-p 'python-mode 'python)
+ ((treesit-ready-p 'python)
(treesit-parser-create 'python)
(setq-local treesit-font-lock-settings python--treesit-settings)
(setq-local treesit-font-lock-feature-list
diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi
index 91df15a21d7..ee818a74b57 100644
--- a/doc/emacs/custom.texi
+++ b/doc/emacs/custom.texi
@@ -1887,23 +1887,31 @@ command is less work to invoke when you really want to.
you can specify them in your initialization file by writing Lisp code.
@xref{Init File}, for a description of the initialization file.
-@findex kbd
- There are several ways to write a key binding using Lisp. The
-simplest is to use the @code{kbd} function, which converts a textual
-representation of a key sequence---similar to how we have written key
-sequences in this manual---into a form that can be passed as an
-argument to @code{keymap-global-set}. For example, here's how to bind
-@kbd{C-z} to the @code{shell} command (@pxref{Interactive Shell}):
+@findex keymap-global-set
+ The recommended way to write a key binding using Lisp is to use
+either the @code{keymap-global-set} or the @code{keymap-set}
+functions. For example, here's how to bind @kbd{C-z} to the
+@code{shell} command in the global keymap (@pxref{Interactive Shell}):
@example
(keymap-global-set "C-z" 'shell)
@end example
+@cindex key sequence syntax
@noindent
-The single-quote before the command name, @code{shell}, marks it as a
+The first argument to @code{keymap-global-set} describes the key
+sequence. It is a string made of a series of characters separated
+by spaces, with each character corresponding to a key. Keys with
+modifiers can be specified by prepending the modifier, such as
+@samp{C-} for Control, or @samp{M-} for Meta. Special keys, such as
+@key{TAB} and @key{RET}, can be specified within angle brackets as in
+@kbd{@key{TAB}} and @kbd{@key{RET}}.
+
+ The single-quote before the command name that is being bound to the
+key sequence, @code{shell} in the above example, marks it as a
constant symbol rather than a variable. If you omit the quote, Emacs
-would try to evaluate @code{shell} as a variable. This probably
-causes an error; it certainly isn't what you want.
+would try to evaluate @code{shell} as a variable. This will probably
+cause an error; it certainly isn't what you want.
Here are some additional examples, including binding function keys
and mouse events:
@@ -1920,6 +1928,27 @@ and mouse events:
Language and coding systems may cause problems with key bindings for
non-@acronym{ASCII} characters. @xref{Init Non-ASCII}.
+@findex global-set-key
+@findex define-key
+ Alternatively, you can use the low level functions @code{define-key}
+and @code{global-set-key}. For example, to bind @kbd{C-z} to the
+@code{shell} command, as in the above example, using these low-level
+functions, use:
+
+@example
+(global-set-key (kbd "C-z") 'shell)
+@end example
+
+@findex kbd
+@noindent
+There are various ways to specify the key sequence but the simplest is
+to use the function @code{kbd} as shown in the example above.
+@code{kbd} takes a single string argument that is a textual
+representation of a key sequence, and converts it into a form suitable
+for low-level functions such as @code{global-set-key}. For more
+details about binding keys using Lisp, @pxref{Keymaps,,, elisp, The
+Emacs Lisp Reference Manual}.
+
@findex keymap-set
@findex keymap-unset
As described in @ref{Local Keymaps}, major modes and minor modes can
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
listed files and directories.
@findex vc-dir-mark-by-regexp
-@item %
+@item % m
+@itemx * %
You can use this command to mark files by regexp
(@code{vc-dir-mark-by-regexp}). If given a prefix, unmark files
instead.
+@findex vc-dir-mark-registered-files
+@item * r
+You can use this command to mark files that are in one of registered
+states, including edited, added or removed.
+(@code{vc-dir-mark-registered-files}).
+
@item G
Add the file under point to the list of files that the VC should
ignore (@code{vc-dir-ignore}). For instance, if the VC is Git, it
diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi
index 5b60e93bb3d..e2764c34482 100644
--- a/doc/emacs/misc.texi
+++ b/doc/emacs/misc.texi
@@ -2705,40 +2705,16 @@ when point is on the first byte of a multibyte sequence in the file.
@cindex restore session
@cindex remember editing session
@cindex reload files
-@cindex desktop
-@vindex desktop-restore-frames
- Use the desktop library to save the state of Emacs from one session
-to another. Once you save the Emacs @dfn{desktop}---the buffers,
-their file names, major modes, buffer positions, and so on---then
-subsequent Emacs sessions reload the saved desktop. By default,
-the desktop also tries to save the frame and window configuration.
-To disable this, set @code{desktop-restore-frames} to @code{nil}.
-(See that variable's documentation for some related options
-that you can customize to fine-tune this behavior.)
-
-@vindex desktop-files-not-to-save
-Information about buffers visiting remote files is not saved by
-default. Customize the variable @code{desktop-files-not-to-save} to
-change this.
-
-@vindex frameset-filter-alist
- When the desktop restores the frame and window configuration, it
-uses the recorded values of frame parameters, disregarding any
-settings for those parameters you have in your init file (@pxref{Init
-File}). This means that frame parameters such as fonts and faces for
-the restored frames will come from the desktop file, where they were
-saved when you exited your previous Emacs session; any settings for
-those parameters in your init file will be ignored. To disable this,
-customize the value of @code{frameset-filter-alist} to filter out the
-frame parameters you don't want to be restored.
+@cindex desktop configuration
+ You can use the desktop library to save the state of Emacs from one
+session to another. The saved Emacs @dfn{desktop configuration}
+includes the buffers, their file names, major modes, buffer positions,
+window and frame configuration, and some important global variables.
-@findex desktop-save
@vindex desktop-save-mode
- You can save the desktop manually with the command @kbd{M-x
-desktop-save}. You can also enable automatic saving of the desktop
-when you exit Emacs, and automatic restoration of the last saved
-desktop when Emacs starts: use the Customization buffer (@pxref{Easy
+@findex desktop-save-mode
+ To enable this feature, use the Customization buffer (@pxref{Easy
Customization}) to set @code{desktop-save-mode} to @code{t} for future
sessions, or add this line in your init file (@pxref{Init File}):
@@ -2746,51 +2722,34 @@ sessions, or add this line in your init file (@pxref{Init File}):
(desktop-save-mode 1)
@end example
-@findex desktop-change-dir
-@findex desktop-revert
@vindex desktop-path
+@vindex desktop-auto-save-timeout
If you turn on @code{desktop-save-mode} in your init file, then when
-Emacs starts, it looks for a saved desktop in the current directory.
-(More precisely, it looks in the directories specified by
-@code{desktop-path}, and uses the first desktop it finds.)
-Thus, you can have separate saved desktops in different directories,
-and the starting directory determines which one Emacs reloads. You
-can save the current desktop and reload one saved in another directory
-by typing @kbd{M-x desktop-change-dir}. Typing @kbd{M-x
-desktop-revert} reverts to the desktop previously reloaded.
-
- Specify the option @samp{--no-desktop} on the command line when you
-don't want it to reload any saved desktop. This turns off
-@code{desktop-save-mode} for the current session. Starting Emacs with
-the @samp{--no-init-file} option also disables desktop reloading,
-since it bypasses the init file, where @code{desktop-save-mode} is
-usually turned on.
-
-@vindex desktop-restore-eager
- By default, all the buffers in the desktop are restored in one go.
-However, this may be slow if there are a lot of buffers in the
-desktop. You can specify the maximum number of buffers to restore
-immediately with the variable @code{desktop-restore-eager}; the
-remaining buffers are restored lazily, when Emacs is idle.
-
-@findex desktop-clear
-@vindex desktop-globals-to-clear
-@vindex desktop-clear-preserve-buffers-regexp
- Type @kbd{M-x desktop-clear} to empty the Emacs desktop. This kills
-all buffers except for internal ones, and clears the global variables
-listed in @code{desktop-globals-to-clear}. If you want this to
-preserve certain buffers, customize the variable
-@code{desktop-clear-preserve-buffers-regexp}, whose value is a regular
-expression matching the names of buffers not to kill.
+Emacs starts, it looks for a saved desktop in @code{desktop-path}
+(which defaults to @code{user-emacs-directory} and then your home
+directory) and uses the first desktop it finds. While Emacs runs with
+@code{desktop-save-mode} turned on, it by default auto-saves the
+desktop whenever any of the desktop configuration changes. The
+variable @code{desktop-auto-save-timeout} determines how frequently
+Emacs checks for modifications to your desktop. The desktop is also
+saved when you exit Emacs.
- If you want to save minibuffer history from one session to
-another, use the @code{savehist} library.
+@cindex disable restoring of desktop configuration
+ Specify the option @samp{--no-desktop} on the Emacs command line
+when you don't want it to reload any saved desktop configurations.
+This turns off @code{desktop-save-mode} for the current session.
+Starting Emacs with the @samp{--no-init-file} option also disables
+desktop reloading, since it bypasses the init file, where
+@code{desktop-save-mode} is usually turned on.
-@vindex desktop-auto-save-timeout
- While Emacs runs with @code{desktop-save-mode} turned on, it by
-default auto-saves the desktop whenever any of it changes. The
-variable @code{desktop-auto-save-timeout} determines how frequently
-Emacs checks for modifications to your desktop.
+@findex desktop-change-dir
+@findex desktop-revert
+ You can have separate saved desktop configurations in different
+directories; starting Emacs from a directory where you have a saved
+desktop configuration will restore that configuration. You can save
+the current desktop and reload the one saved in another directory by
+typing @kbd{M-x desktop-change-dir}. Typing @kbd{M-x desktop-revert}
+reverts to the previously reloaded desktop.
@vindex desktop-load-locked-desktop
The file in which Emacs saves the desktop is locked while the
@@ -2801,12 +2760,13 @@ will by default ask you whether to use the locked desktop file. You
can avoid the question by customizing the variable
@code{desktop-load-locked-desktop} to either @code{nil}, which means
never load the desktop in this case, or @code{t}, which means load the
-desktop without asking. Finally, the @code{check-pid} value means to
-load the file if the Emacs process that has locked the desktop is not
-running on the local machine. This should not be used in
-circumstances where the locking Emacs might still be running on
-another machine. This could be the case in multi-user environments
-where your home directory is mounted remotely using NFS or similar.
+desktop without asking. You can also customize the variable to the
+special value @code{check-pid}, which means to load the file if the
+Emacs process that has locked the desktop is not running on the local
+machine. This should not be used in circumstances where the locking
+Emacs might still be running on another machine, which could be the
+case in multi-user environments where your home directory is mounted
+remotely using NFS or similar.
@cindex desktop restore in daemon mode
When Emacs starts in daemon mode, it cannot ask you any questions,
@@ -2816,10 +2776,67 @@ the desktop in daemon mode is somewhat problematic for other reasons:
e.g., the daemon cannot use GUI features, so parameters such as frame
position, size, and decorations cannot be restored. For that reason,
you may wish to delay restoring the desktop in daemon mode until the
-first client connects, by calling @code{desktop-read} in a hook
-function that you add to @code{server-after-make-frame-hook}
+first client connects, by calling @code{desktop-read} (see below) in a
+hook function that you add to @code{server-after-make-frame-hook}
(@pxref{Creating Frames,,, elisp, The Emacs Lisp Reference Manual}).
+@findex desktop-save
+@findex desktop-read
+ Whenever you want, you can use the command @kbd{M-x desktop-save} to
+force immediate saving of the current desktop. This is useful either
+if you do not want to use the automatic desktop restoration, and thus
+don't turn on @code{desktop-save-mode}, or when you have made
+significant changes to the desktop, and want to make sure the
+configuration doesn't get lost if Emacs or your system crashes. You
+can use @kbd{M-x desktop-read} to restore a previously-saved desktop
+if the current Emacs session didn't load any desktop yet.
+
+@vindex desktop-restore-frames
+ By default, the desktop tries to save and restore the frame and
+window configuration. To disable this, set
+@code{desktop-restore-frames} to @code{nil}. (See that variable's
+documentation for some related options that you can customize to
+fine-tune this behavior.)
+
+@vindex frameset-filter-alist
+ When the desktop restores the frame and window configuration, it
+uses the recorded values of frame parameters, disregarding any
+settings for those parameters you have in your init file (@pxref{Init
+File}). This means that frame parameters such as fonts and faces for
+the restored frames will come from the desktop file, where they were
+saved when you exited your previous Emacs session; any settings for
+those parameters in your init file will be ignored. To disable this,
+customize the value of @code{frameset-filter-alist} to filter out the
+frame parameters you don't want to be restored; they will then be set
+according to your customizations in the init file.
+
+@vindex desktop-files-not-to-save
+ Information about buffers visiting remote files is not saved by
+default. Customize the variable @code{desktop-files-not-to-save} to
+change this.
+
+@vindex desktop-restore-eager
+ By default, all the buffers in the desktop are restored in one go.
+However, this may be slow if there are a lot of buffers in the
+desktop. You can specify the maximum number of buffers to restore
+immediately with the variable @code{desktop-restore-eager}; the
+remaining buffers are restored lazily, when Emacs is idle.
+
+@findex desktop-clear
+@vindex desktop-globals-to-clear
+@vindex desktop-clear-preserve-buffers-regexp
+ Type @kbd{M-x desktop-clear} to empty the Emacs desktop; this can be
+useful, for example, if you want to switch to another desktop by
+invoking @kbd{M-x desktop-read} next. The @code{desktop-clear}
+command kills all buffers except for internal ones, and clears the
+global variables listed in @code{desktop-globals-to-clear}. If you
+want it to preserve certain buffers, customize the variable
+@code{desktop-clear-preserve-buffers-regexp}, whose value is a regular
+expression matching the names of buffers not to kill.
+
+ If you want to save minibuffer history from one session to
+another, use the @code{savehist} library.
+
@node Recursive Edit
@section Recursive Editing Levels
@cindex recursive editing level
diff --git a/doc/emacs/modes.texi b/doc/emacs/modes.texi
index d0eacce0842..0e4b15fb514 100644
--- a/doc/emacs/modes.texi
+++ b/doc/emacs/modes.texi
@@ -429,11 +429,19 @@ For example, one element normally found in the list has the form
@code{(@t{"\\.c\\'"} . c-mode)}, and it is responsible for selecting C
mode for files whose names end in @file{.c}. (Note that @samp{\\} is
needed in Lisp syntax to include a @samp{\} in the string, which must
-be used to suppress the special meaning of @samp{.} in regexps.) If
-the element has the form @code{(@var{regexp} @var{mode-function}
-@var{flag})} and @var{flag} is non-@code{nil}, then after calling
-@var{mode-function}, Emacs discards the suffix that matched
-@var{regexp} and searches the list again for another match.
+be used to suppress the special meaning of @samp{.} in regexps.)
+
+@cindex backup files, choosing a major mode
+@cindex encrypted files, choosing a major mode
+If the element has the form @w{@code{(@var{regexp} @var{mode-function}
+@var{flag})}} and @var{flag} is non-@code{nil}, then after calling
+@var{mode-function} (if it is non-@code{nil}), Emacs discards the
+suffix that matched @var{regexp} and searches the list again for
+another match. This ``recursive extension stripping'' is used for
+files which have multiple extensions, and the ``outer'' extension
+hides the ``inner'' one that actually specifies the right mode. For
+example, backup files and GPG-encrypted files with @file{.gpg}
+extension use this feature.
@vindex auto-mode-case-fold
On GNU/Linux and other systems with case-sensitive file names, Emacs
diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi
index 3a8eddb93ea..f5572e447d3 100644
--- a/doc/lispref/functions.texi
+++ b/doc/lispref/functions.texi
@@ -685,6 +685,20 @@ Here are some examples:
@end group
@end example
+@cindex defining functions dynamically
+Most Emacs functions are part of the source code of Lisp programs, and
+are defined when the Emacs Lisp reader reads the program source before
+executing it. However, you can also define functions dynamically at
+run time, e.g., by generating @code{defun} calls when your program's
+code is executed. If you do this, be aware that Emacs's Help
+commands, such as @kbd{C-h f}, which present in the @file{*Help*}
+buffer a button to jump to the function's definition, might be unable
+to find the source code because generating a function dynamically
+usually looks very different from the usual static calls to
+@code{defun}. You can make the job of finding the code which
+generates such functions easier by using the @code{definition-name}
+property, @pxref{Standard Properties}.
+
@cindex override existing functions
@cindex redefine existing functions
Be careful not to redefine existing functions unintentionally.
diff --git a/doc/lispref/help.texi b/doc/lispref/help.texi
index de5ed76c7f7..59b6b6dab1d 100644
--- a/doc/lispref/help.texi
+++ b/doc/lispref/help.texi
@@ -69,14 +69,14 @@ Variables}. The string is stored in the variable's
@cindex @file{DOC} (documentation) file
Sometimes, Emacs does not keep documentation strings in memory.
There are two such circumstances. Firstly, to save memory, the
-documentation for preloaded functions and variables (including
-primitives) is kept in a file named @file{DOC}, in the directory
-specified by @code{doc-directory} (@pxref{Accessing Documentation}).
-Secondly, when a function or variable is loaded from a byte-compiled
-file, Emacs avoids loading its documentation string (@pxref{Docs and
-Compilation}). In both cases, Emacs looks up the documentation string
-from the file only when needed, such as when the user calls @kbd{C-h
-f} (@code{describe-function}) for a function.
+documentation for primitive functions (@pxref{What Is a Function}) and
+built-in variables is kept in a file named @file{DOC}, in the
+directory specified by @code{doc-directory} (@pxref{Accessing
+Documentation}). Secondly, when a function or variable is loaded from
+a byte-compiled file, Emacs avoids loading its documentation string
+(@pxref{Docs and Compilation}). In both cases, Emacs looks up the
+documentation string from the file only when needed, such as when the
+user calls @kbd{C-h f} (@code{describe-function}) for a function.
Documentation strings can contain special @dfn{key substitution
sequences}, referring to key bindings which are looked up only when
@@ -303,7 +303,7 @@ for in the directory @code{doc-directory}. Usually @var{filename} is
@defvar doc-directory
This variable holds the name of the directory which should contain the
file @code{"DOC"} that contains documentation strings for
-built-in and preloaded functions and variables.
+built-in functions and variables.
In most cases, this is the same as @code{data-directory}. They may be
different when you run Emacs from the directory where you built it,
diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi
index 1c548af1990..7876780dcd4 100644
--- a/doc/lispref/keymaps.texi
+++ b/doc/lispref/keymaps.texi
@@ -1378,7 +1378,8 @@ Binding Conventions}).
or if @var{key} is not a valid key.
@var{key} is a string representing a single key or a series of key
-strokes. Key strokes are separated by a single space character.
+strokes, and must satisfy @code{key-valid-p}. Key strokes are
+separated by a single space character.
Each key stroke is either a single character, or the name of an
event, surrounded by angle brackets. In addition, any key stroke
@@ -1413,6 +1414,7 @@ The only keys that have a special shorthand syntax are @kbd{NUL},
The modifiers have to be specified in alphabetical order:
@samp{A-C-H-M-S-s}, which is @samp{Alt-Control-Hyper-Meta-Shift-super}.
+@findex keymap-set
@defun keymap-set keymap key binding
This function sets the binding for @var{key} in @var{keymap}. (If
@var{key} is more than one event long, the change is actually made
@@ -3079,13 +3081,13 @@ the menu. To put it elsewhere in the menu, use @code{keymap-set-after}:
@defun keymap-set-after map key binding &optional after
Define a binding in @var{map} for @var{key}, with value @var{binding},
just like @code{define-key}, but position the binding in @var{map} after
-the binding for the event @var{after}. The argument @var{key} should be
-of length one---a vector or string with just one element. But
-@var{after} should be a single event type---a symbol or a character, not
-a sequence. The new binding goes after the binding for @var{after}. If
-@var{after} is @code{t} or is omitted, then the new binding goes last, at
-the end of the keymap. However, new bindings are added before any
-inherited keymap.
+the binding for the event @var{after}. The argument @var{key} should
+represent a single menu item or key, and @var{after} should be a
+single event type---a symbol or a character, not a sequence. The new
+binding goes after the binding for @var{after}. If @var{after} is
+@code{t} or is omitted, then the new binding goes last, at the end of
+the keymap. However, new bindings are added before any inherited
+keymap.
Here is an example:
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}.
@cindex @code{case-fold}, text property
@findex read-regexp-case-fold-search
-The user can use the @kbd{M-c} command to indicate whether case
+The user can use the @kbd{M-s c} command to indicate whether case
folding should be on or off. If the user has used this command, the
returned string will have the text property @code{case-fold} set to
either @code{fold} or @code{inhibit-fold}. It is up to the caller of
diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index dffd6653369..fe5eb8a1b8d 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -4054,7 +4054,7 @@ tree-sitter query in either the string, s-expression or compiled form.
@c FIXME: Cross-ref treesit-font-lock-level to user manual.
For each @var{query}, the @var{:keyword}/@var{value} pairs that
-precede it add meta information to it. The @code{:lang} keyword
+precede it add meta information to it. The @code{:language} keyword
declares @var{query}'s language. The @code{:feature} keyword sets the
feature name of @var{query}. Users can control which features are
enabled with @code{treesit-font-lock-level} and
@@ -4926,8 +4926,7 @@ the current line to @var{matcher}; if it returns non-@code{nil}, this
rule is applicable. Then Emacs passes the node to @var{anchor}, which
returns a buffer position. Emacs takes the column number of that
position, adds @var{offset} to it, and the result is the indentation
-column for the current line. @var{offset} can be an integer or a
-variable whose value is an integer.
+column for the current line.
The @var{matcher} and @var{anchor} are functions, and Emacs provides
convenient defaults for them.
@@ -4936,17 +4935,20 @@ Each @var{matcher} or @var{anchor} is a function that takes three
arguments: @var{node}, @var{parent}, and @var{bol}. The argument
@var{bol} is the buffer position whose indentation is required: the
position of the first non-whitespace character after the beginning of
-the line. The argument @var{node} is the largest (highest-in-tree)
-node that starts at that position; and @var{parent} is the parent of
-@var{node}. However, when that position is in a whitespace or inside
-a multi-line string, no node can start at that position, so
+the line. The argument @var{node} is the largest node that starts at
+that position (and is not a root node); and @var{parent} is the parent
+of @var{node}. However, when that position is in a whitespace or
+inside a multi-line string, no node can start at that position, so
@var{node} is @code{nil}. In that case, @var{parent} would be the
smallest node that spans that position.
-Emacs finds @var{bol}, @var{node} and @var{parent} and
-passes them to each @var{matcher} and @var{anchor}. @var{matcher}
-should return non-@code{nil} if the rule is applicable, and
-@var{anchor} should return a buffer position.
+@var{matcher} should return non-@code{nil} if the rule is applicable,
+and @var{anchor} should return a buffer position.
+
+@var{offset} can be an integer, a variable whose value is an integer,
+or a function that returns an integer. If it is a function, it is
+passed @var{node}, @var{parent}, and @var{bol}, like matchers and
+anchors.
@end defvar
@defvar treesit-simple-indent-presets
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index 19a22c121de..cebb59b6501 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -65,7 +65,6 @@ For example, the C language grammar is represented as the symbol
@vindex treesit-extra-load-path
@vindex treesit-load-language-error
-@vindex treesit-load-suffixes
Tree-sitter language grammar are distributed as dynamic libraries.
In order to use a language grammar in Emacs, you need to make sure
that the dynamic library is installed on the system. Emacs looks for
@@ -83,7 +82,7 @@ and finally, in the system's default locations for dynamic libraries.
@end itemize
In each of these directories, Emacs looks for a file with file-name
-extensions specified by the variable @code{treesit-load-suffixes}.
+extensions specified by the variable @code{dynamic-library-suffixes}.
If Emacs cannot find the library or has problems loading it, Emacs
signals the @code{treesit-load-language-error} error. The data of
@@ -541,11 +540,15 @@ This function returns the list of @var{parser}'s notifier functions.
Here's some terminology and conventions we use when documenting
tree-sitter functions.
-We talk about a node being ``smaller'' or ``larger'', and ``lower'' or
-``higher''. A smaller and lower node is lower in the syntax tree and
-therefore spans a smaller portion of buffer text; a larger and higher
-node is higher up in the syntax tree, it contains many smaller nodes
-as its children, and therefore spans a larger portion of text.
+A node in a syntax tree spans some portion of the program text in the
+buffer. We say that a node is ``smaller'' or ``larger'' than another
+if it spans, respectively, a smaller or larger portion of buffer text
+than the other node. Since nodes that are deeper (``lower'') in the
+tree are children of the nodes that are ``higher'' in the tree, it
+follows that a lower node will always be smaller than a node that is
+higher in the node hierarchy. A node that is higher up in the syntax
+tree contains one or more smaller nodes as its children, and therefore
+spans a larger portion of buffer text.
When a function cannot find a node, it returns @code{nil}. For
convenience, all functions that take a node as argument and return
@@ -677,12 +680,12 @@ This function returns all of @var{node}'s children as a list. If
@var{named} is non-@code{nil}, it retrieves only named nodes.
@end defun
-@defun treesit-next-sibling node &optional named
+@defun treesit-node-next-sibling node &optional named
This function finds the next sibling of @var{node}. If @var{named} is
non-@code{nil}, it finds the next named sibling.
@end defun
-@defun treesit-prev-sibling node &optional named
+@defun treesit-node-prev-sibling node &optional named
This function finds the previous sibling of @var{node}. If
@var{named} is non-@code{nil}, it finds the previous named sibling.
@end defun
@@ -696,14 +699,14 @@ assign @dfn{field names} to child nodes (@pxref{tree-sitter node field
name, field name}). For example, a @code{function_definition} node
could have a @code{declarator} node and a @code{body} node.
-@defun treesit-child-by-field-name node field-name
+@defun treesit-node-child-by-field-name node field-name
This function finds the child of @var{node} whose field name is
@var{field-name}, a string.
@example
@group
;; Get the child that has "body" as its field name.
-(treesit-child-by-field-name node "body")
+(treesit-node-child-by-field-name node "body")
@result{} #<treesit-node (compound_statement) in 45-89>
@end group
@end example
@@ -713,7 +716,7 @@ This function finds the child of @var{node} whose field name is
@cindex nodes, by position
@cindex syntax tree nodes, by position
-@defun treesit-first-child-for-pos node pos &optional named
+@defun treesit-node-first-child-for-pos node pos &optional named
This function finds the first child of @var{node} that extends beyond
buffer position @var{pos}. ``Extends beyond'' means the end of the
child node is greater or equal to @var{pos}. This function only looks
@@ -926,9 +929,13 @@ Here are some predicates on tree-sitter nodes:
Checks if @var{object} is a tree-sitter syntax node.
@end defun
+@cindex compare tree-sitter syntax nodes
+@cindex tree-sitter nodes, comparing
@defun treesit-node-eq node1 node2
-Checks if @var{node1} and @var{node2} are the same node in a syntax
-tree.
+Checks if @var{node1} and @var{node2} refer to the same node in a
+tree-sitter syntax tree. This function uses the same equivalence
+metric as @code{equal}. You can also compare nodes using @code{equal}
+(@pxref{Equality Predicates}).
@end defun
@heading Property information
@@ -1002,7 +1009,7 @@ Note that @var{n} counts both named and anonymous child. And @var{n}
could be negative, e.g., @code{-1} represents the last child.
@end defun
-@defun treesit-child-count node &optional named
+@defun treesit-node-child-count node &optional named
This function finds the number of children of @var{node}. If
@var{named} is non-@code{nil}, it only counts named children
(@pxref{tree-sitter named node, named node}).
@@ -1685,28 +1692,50 @@ integration for a major mode.
A major mode supporting tree-sitter features should roughly follow
this pattern:
-@c FIXME: Update this part once we settle on the exact format.
@example
@group
(define-derived-mode woomy-mode prog-mode "Woomy"
"A mode for Woomy programming language."
- ;; Shared setup.
- ...
- (cond
- ;; Tree-sitter setup.
- ((treesit-ready-p 'woomy-mode 'woomy)
+ (when (treesit-ready-p 'woomy)
(setq-local treesit-variables ...)
- (treesit-major-mode-setup))
- ;; Non-tree-sitter setup.
- (t
- ...)))
+ ...
+ (treesit-major-mode-setup)))
@end group
@end example
-First, the major mode should use @code{treesit-ready-p} to determine
-whether tree-sitter can be activated in this mode.
+@code{treesit-ready-p} automatically emits a warning if conditions for
+enabling tree-sitter aren't met.
-@defun treesit-ready-p mode language &optional quiet
+If a tree-sitter major mode shares setup with their ``native''
+counterpart, they can create a ``base mode'' that contains the common
+setup, like this:
+
+@example
+@group
+(define-derived-mode woomy--base-mode prog-mode "Woomy"
+ "An internal mode for Woomy programming language."
+ (common-setup)
+ ...)
+@end group
+
+@group
+(define-derived-mode woomy-mode woomy--base-mode "Woomy"
+ "A mode for Woomy programming language."
+ (native-setup)
+ ...)
+@end group
+
+@group
+(define-derived-mode woomy-ts-mode woomy--base-mode "Woomy"
+ "A mode for Woomy programming language."
+ (when (treesit-ready-p 'woomy)
+ (setq-local treesit-variables ...)
+ ...
+ (treesit-major-mode-setup)))
+@end group
+@end example
+
+@defun treesit-ready-p language &optional quiet
This function checks for conditions for activating tree-sitter. It
checks whether Emacs was built with tree-sitter, whether the buffer's
size is not too large for tree-sitter to handle it, and whether the
@@ -1715,15 +1744,12 @@ language grammar for @var{language} is available on the system
This function emits a warning if tree-sitter cannot be activated. If
@var{quiet} is @code{message}, the warning is turned into a message;
-if @var{quiet} is @code{nil}, no warning or message is displayed.
+if @var{quiet} is @code{t}, no warning or message is displayed.
If all the necessary conditions are met, this function returns
non-@code{nil}; otherwise it returns @code{nil}.
@end defun
-Next, the major mode should set up tree-sitter variables and call
-@code{treesit-major-mode-setup}.
-
@defun treesit-major-mode-setup
This function activates some tree-sitter features for a major mode.
@@ -1734,7 +1760,7 @@ If @code{treesit-font-lock-settings} (@pxref{Parser-based Font Lock})
is non-@code{nil}, it sets up fontification.
@item
-If @code{treesit-simple-indent-rules} (@pxref{Parser-based Font Lock})
+If @code{treesit-simple-indent-rules} (@pxref{Parser-based Indentation})
is non-@code{nil}, it sets up indentation.
@item
@@ -1897,12 +1923,12 @@ ts_node_named_child treesit-node-child
ts_node_named_child_count treesit-node-child-count
ts_node_child_by_field_name treesit-node-by-field-name
ts_node_child_by_field_id
-ts_node_next_sibling treesit-next-sibling
-ts_node_prev_sibling treesit-prev-sibling
-ts_node_next_named_sibling treesit-next-sibling
-ts_node_prev_named_sibling treesit-prev-sibling
-ts_node_first_child_for_byte treesit-first-child-for-pos
-ts_node_first_named_child_for_byte treesit-first-child-for-pos
+ts_node_next_sibling treesit-node-next-sibling
+ts_node_prev_sibling treesit-node-prev-sibling
+ts_node_next_named_sibling treesit-node-next-sibling
+ts_node_prev_named_sibling treesit-node-prev-sibling
+ts_node_first_child_for_byte treesit-node-first-child-for-pos
+ts_node_first_named_child_for_byte treesit-node-first-child-for-pos
ts_node_descendant_for_byte_range treesit-descendant-for-range
ts_node_descendant_for_point_range
ts_node_named_descendant_for_byte_range treesit-descendant-for-range
diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi
index f47720184a3..f3824436246 100644
--- a/doc/lispref/positions.texi
+++ b/doc/lispref/positions.texi
@@ -852,7 +852,7 @@ matches either @code{"function_definition"} or @code{"class_definition"}.
@end defvar
@defvar treesit-defun-tactic
-This variable determines how does Emacs treat nested defuns. If the
+This variable determines how Emacs treats nested defuns. If the
value is @code{top-level}, navigation functions only move across
top-level defuns, if the value is @code{nested}, navigation functions
recognize nested defuns.
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,
@end defun
@defun string-to-char string
- This function returns the first character in @var{string}. This
-mostly identical to @code{(aref string 0)}, except that it returns 0
+ This function returns the first character in @var{string}. This is
+mostly identical to @w{@code{(aref string 0)}}, except that it returns 0
if the string is empty. (The value is also 0 when the first character
of @var{string} is the null character, @acronym{ASCII} code 0.) This
function may be eliminated in the future if it does not seem useful
diff --git a/doc/lispref/symbols.texi b/doc/lispref/symbols.texi
index 183367c0cda..5b53cbe310a 100644
--- a/doc/lispref/symbols.texi
+++ b/doc/lispref/symbols.texi
@@ -555,6 +555,23 @@ value, saved value, customized-but-unsaved value, and themed values.
Do not set them directly; they are managed by @code{defcustom} and
related functions. @xref{Variable Definitions}.
+@item definition-name
+This property is used to find the definition of a symbol in the source
+code, when it might be hard to find the definition by textual search
+of the source file. For example, a @code{define-derived-mode}
+(@pxref{Derived Modes}) might define a mode-specific function or a
+variable implicitly; or your Lisp program might generate a run-time
+call to @code{defun} to define a function (@pxref{Defining
+Functions}). In these and similar cases, the @code{definition-name}
+property of the symbol should be another symbol whose definition can
+be found by textual search and whose code defines the original symbol.
+In the example with @code{define-derived-mode}, the value of this
+property of the functions and variables it defines should be the mode
+symbol. The Emacs Help commands such as @kbd{C-h f} (@pxref{Help,,,
+emacs, The GNU Emacs Manual}) use this property to show the definition
+of a symbol via a button in the @file{*Help*} buffer where the
+symbol's documentation is shown.
+
@item disabled
If the value is non-@code{nil}, the named function is disabled as a
command. @xref{Disabling Commands}.
diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi
index 253bf169ccb..56151b5482f 100644
--- a/doc/misc/eglot.texi
+++ b/doc/misc/eglot.texi
@@ -1104,7 +1104,7 @@ troubleshoot Eglot problems. It also provides guidelines for
reporting Eglot bugs in a way that facilitates their resolution.
When you encounter problems with Eglot, try first using the commands
-@kbd{M-x eglot-events-server} and @kbd{M-x eglot-stderr-buffer}. They
+@kbd{M-x eglot-events-buffer} and @kbd{M-x eglot-stderr-buffer}. They
pop up special buffers that can be used to inspect the communications
between the Eglot and language server. In many cases, this will
indicate the problems or at least provide a hint.
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index 4ad1c3f74f6..1789cded9d3 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -64,10 +64,11 @@ modify this GNU manual.''
Eshell is a shell-like command interpreter implemented in Emacs Lisp.
It invokes no external processes except for those requested by the
-user. It is intended to be an alternative to the IELM (@pxref{Lisp Interaction, Emacs Lisp Interaction, , emacs, The Emacs Editor})
-REPL for Emacs @emph{and} with an interface similar to command shells
-such as @command{bash}, @command{zsh}, @command{rc}, or
-@command{4dos}.
+user. It is intended to be an alternative to the IELM (@pxref{Lisp
+Interaction, Emacs Lisp Interaction, , emacs, The Emacs Editor})
+REPL@footnote{Short for ``Read-Eval-Print Loop''.} for Emacs
+@emph{and} with an interface similar to command shells such as
+@command{bash}, @command{zsh}, @command{rc}, or @command{4dos}.
@c This manual is updated to release 2.4 of Eshell.
@insertcopying
@@ -193,6 +194,13 @@ In a command shell, everything is done by invoking commands. This
chapter covers command invocations in Eshell, including the command
history and invoking commands in a script file.
+Unlike regular system shells, Eshell never invokes kernel functions
+directly, such as @code{exec(3)}. Instead, it uses the Lisp functions
+available in the Emacs Lisp library. It does this by transforming the
+input line into a callable Lisp form.@footnote{To see the Lisp form
+that will be invoked, type this as the Eshell prompt:
+@kbd{eshell-parse-command 'echo hello'}}
+
@menu
* Invocation::
* Arguments::
@@ -207,23 +215,16 @@ history and invoking commands in a script file.
@node Invocation
@section Invocation
-Unlike regular system shells, Eshell never invokes kernel functions
-directly, such as @code{exec(3)}. Instead, it uses the Lisp functions
-available in the Emacs Lisp library. It does this by transforming the
-input line into a callable Lisp form.@footnote{To see the Lisp form that will be invoked, type: @samp{eshell-parse-command "echo hello"}}
+Eshell is both a command shell and an Emacs Lisp @acronym{REPL}. As a
+result, you can invoke commands in two different ways: in @dfn{command
+form} or in @dfn{lisp form}.
-The command can be either an Elisp function or an external command.
-Eshell looks first for an alias (@pxref{Aliases}) with the same name as the
-command, then a built-in (@pxref{Built-ins}) or a function with the
-same name; if there is no match, it then tries to execute it as an
-external command.
-
-The semicolon (@code{;}) can be used to separate multiple command
-invocations on a single line. You can also separate commands with
-@code{&&} or @code{||}. When using @code{&&}, Eshell will execute the
-second command only if the first succeeds (i.e.@: has an exit
-status of 0); with @code{||}, Eshell will execute the second command
-only if the first fails.
+You can use the semicolon (@code{;}) to separate multiple command
+invocations on a single line, executing each in turn. You can also
+separate commands with @code{&&} or @code{||}. When using @code{&&},
+Eshell will execute the second command only if the first succeeds
+(i.e.@: has an exit status of 0); with @code{||}, Eshell will execute
+the second command only if the first fails.
A command invocation followed by an ampersand (@code{&}) will be run
in 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
can be controlled the same way as any other background process in
Emacs.
+@subsection Command form
+Command form looks much the same as in other shells. A command
+consists of arguments separated by spaces; the first argument is the
+command to run, with any subsequent arguments being passed to that
+command.
+
+@example
+~ $ echo hello
+hello
+@end example
+
+@cindex order of looking for commands
+@cindex command lookup order
+The command can be either an Elisp function or an external command.
+Eshell looks for the command in the following order:
+
+@enumerate
+@item
+As a command alias (@pxref{Aliases})
+
+@item
+As a built-in command (@pxref{Built-ins})
+
+@item
+As an external program
+
+@item
+As an ordinary Lisp function
+@end enumerate
+
+@vindex eshell-prefer-lisp-functions
+If you would prefer to use ordinary Lisp functions over external
+programs, set the option @code{eshell-prefer-lisp-functions} to
+@code{t}. This will swap the lookup order of the last two items.
+
+You can also group command forms together into a subcommand with curly
+braces (@code{@{@}}). This lets you use the output of a subcommand as
+an argument to another command, or within control flow statements
+(@pxref{Control Flow}).
+
+@example
+~ $ echo @{echo hello; echo there@}
+hellothere
+@end example
+
+@subsection Lisp form
+Lisp form looks like ordinary Emacs Lisp code, because that's what it
+is. As a result, you can use any syntax normally available to an
+Emacs Lisp program (@pxref{Top, , , elisp, The Emacs Lisp Reference
+Manual}).
+
+@example
+~ $ (format "hello, %s" user-login-name)
+hello, user
+@end example
+
+In addition, you can @emph{combine} command forms and Lisp forms
+together into single statements, letting you use whatever form is the
+most convenient for expressing your intentions.
+
+@example
+~ $ ls *.patch > (format-time-string "%F.log")
+@end example
+
+This command writes a list of all files matching the glob pattern
+@code{*.patch} (@pxref{Globbing}) to a file named
+@code{@var{current-date}.log} (@pxref{Redirection}).
+
@node Arguments
@section Arguments
-Ordinarily, command arguments are parsed by Eshell as either strings
+Ordinarily, Eshell parses arguments in command form as either strings
or numbers, depending on what the parser thinks they look like. To
-specify an argument of some other data type, you can use an
-@ref{Dollars Expansion, Elisp expression}:
+specify an argument of some other data type, you can use a Lisp form
+(@pxref{Invocation}):
@example
~ $ echo (list 1 2 3)
@@ -354,10 +423,6 @@ eshell/sudo is a compiled Lisp function in `em-tramp.el'.
sudo is an alias, defined as "*sudo $*"
@end example
-@vindex eshell-prefer-lisp-functions
-If you would prefer to use the built-in commands instead of the external
-commands, set @code{eshell-prefer-lisp-functions} to @code{t}.
-
Some of the built-in commands have different behavior from their
external counterparts, and some have no external counterpart. Most of
these 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
@node Variables
@section Variables
@vindex eshell-prefer-lisp-variables
-Since Eshell is a combination of an Emacs @acronym{REPL}@footnote{
-Short for ``Read-Eval-Print Loop''.
-} and a command shell, it can refer to variables from two different
-sources: ordinary Emacs Lisp variables, as well as environment
-variables. By default, when using a variable in Eshell, it will first
-look in the list of built-in variables, then in the list of
-environment variables, and finally in the list of Lisp variables. If
-you would prefer to use Lisp variables over environment variables, you
-can set @code{eshell-prefer-lisp-variables} to @code{t}.
+Since Eshell is a combination of an Emacs @acronym{REPL} and a command
+shell, it can refer to variables from two different sources: ordinary
+Emacs Lisp variables, as well as environment variables. By default,
+when using a variable in Eshell, it will first look in the list of
+built-in variables, then in the list of environment variables, and
+finally in the list of Lisp variables. If you would prefer to use
+Lisp variables over environment variables, you can set
+@code{eshell-prefer-lisp-variables} to @code{t}.
You can set variables in a few different ways. To set a Lisp
variable, you can use the command @samp{setq @var{name} @var{value}},
diff --git a/doc/misc/htmlfontify.texi b/doc/misc/htmlfontify.texi
index 2c96002fb16..fa45f9361ab 100644
--- a/doc/misc/htmlfontify.texi
+++ b/doc/misc/htmlfontify.texi
@@ -1351,11 +1351,10 @@ Whether or not to split the index @ref{hfy-index-file} alphabetically
on the first letter of each tag. Useful when the index would otherwise
be large and take a long time to render or be difficult to navigate.
-@item hfy-find-cmd
-@vindex hfy-find-cmd
-@anchor{hfy-find-cmd}
+@item hfy-exclude-file-rules
+@vindex hfy-exclude-file-rules
-The ``find'' command used to harvest a list of files to attempt to fontify.
+Regular expressions to exclude files which shouldn't be fontified.
@item hfy-extn
@vindex hfy-extn
@@ -1546,12 +1545,6 @@ but you should be able to override this.
See: @ref{Customization}
@item
-A copy of find (e.g., GNU find) that provides the @code{-path} predicate.
-
-You may be able to work around this with a suitable clever shell
-command and the customization entry: @ref{hfy-find-cmd}
-
-@item
A copy of sed (e.g., GNU sed).
@item
diff --git a/doc/misc/modus-themes.org b/doc/misc/modus-themes.org
index 0dbe7a6c5b6..4bf78379c10 100644
--- a/doc/misc/modus-themes.org
+++ b/doc/misc/modus-themes.org
@@ -2811,7 +2811,7 @@ that can be overridden):
As one can tell, we bind a key to a hexadecimal RGB color value. Now
say we wish to override those specific values and have our changes
propagate to all faces that use those keys. We could write something
-like this, which adds a subtle ochre tint:
+like this, which adds a subtle ocher tint:
#+begin_src emacs-lisp
(setq modus-themes-operandi-color-overrides
@@ -2886,7 +2886,7 @@ look like this:
With those in place, one can use {{{kbd(M-x my-modus-themes-tinted)}}}
and then load the Modus theme of their choice. The new palette subset
-will come into effect: subtle ochre tints (or shades of gray) for Modus
+will come into effect: subtle ocher tints (or shades of gray) for Modus
Operandi and night sky blue shades for Modus Vivendi. Switching between
the two themes, such as with {{{kbd(M-x modus-themes-toggle)}}} will
also use the overrides.
diff --git a/doc/misc/org.org b/doc/misc/org.org
index ed3eb0626f2..14699e77395 100644
--- a/doc/misc/org.org
+++ b/doc/misc/org.org
@@ -1249,11 +1249,12 @@ After the drawer.
#+findex: org-insert-drawer
You can interactively insert a drawer at point by calling
~org-insert-drawer~, which is bound to {{{kbd(C-c C-x d)}}}. With an
-active region, this command puts the region inside the drawer. With
-a prefix argument, this command calls ~org-insert-property-drawer~,
-which creates a =PROPERTIES= drawer right below the current headline.
-Org mode uses this special drawer for storing properties (see
-[[*Properties and Columns]]). You cannot use it for anything else.
+active region, this command puts the region inside the drawer. With a
+prefix argument, this command calls non-interactive function
+~org-insert-property-drawer~, which creates a =PROPERTIES= drawer
+right below the current headline. Org mode uses this special drawer
+for storing properties (see [[*Properties and Columns]]). You cannot use
+it for anything else.
Completion over drawer keywords is also possible using
{{{kbd(M-TAB)}}}[fn:6].
@@ -8787,7 +8788,9 @@ a ~day~, ~week~, ~month~ or ~year~. For weekly agendas, the default
is to start on the previous Monday (see
~org-agenda-start-on-weekday~). You can also set the start date using
a date shift: =(setq org-agenda-start-day "+10d")= starts the agenda
-ten days from today in the future.
+ten days from today in the future. ~org-agenda-start-on-weekday~
+takes precedence over ~org-agenda-start-day~ in weekly and bi-weekly
+agendas.
Remote editing from the agenda buffer means, for example, that you can
change the dates of deadlines and appointments from the agenda buffer.
diff --git a/etc/NEWS b/etc/NEWS
index 355ba6ba8aa..64c26f93c50 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -25,20 +25,23 @@ applies, and please also update docstrings as needed.
* Installation Changes in Emacs 29.1
---
-** Ahead-of-time native compilation can now be specified via configure.
-Use '--with-native-compilation=aot' to specify that all the Lisp files
+** Ahead-of-time native compilation can now be requested via configure.
+Use '--with-native-compilation=aot' to request that all the Lisp files
in the Emacs tree should be natively compiled ahead of time. (This is
slow on most machines.)
+This feature existed in Emacs 28.1, but was less easy to request.
+
+++
** Emacs can be built with the tree-sitter parsing library.
-This library, together with grammar libraries, provides incremental
-parsing capabilities for several popular programming languages and
-other formatted files. Emacs built with this library offers major
-modes, described elsewhere in this file, that are based on the
-tree-sitter's parsers. If you have the tree-sitter library
-installed, the configure script will automatically include it in the
-build; use '--without-tree-sitter' at configure time to disable that.
+This library, together with separate grammar libraries for each
+language, provides incremental parsing capabilities for several
+popular programming languages and other formatted files. Emacs built
+with this library offers major modes, described elsewhere in this
+file, that are based on the tree-sitter's parsers. If you have the
+tree-sitter library installed, the configure script will automatically
+include it in the build; use '--without-tree-sitter' at configure time
+to disable that.
Emacs modes based on the tree-sitter library require an additional
grammar library for each mode. These grammar libraries provide the
@@ -51,17 +54,25 @@ yourself. Many libraries can be downloaded from the tree-sitter site:
https://github.com/tree-sitter
-To compile such a library, compile the files "scanner.c" and "parser.c"
-(sometimes named "scanner.cc" and "parser.cc") in the "src" subdirectory
-of the library's source tree using the C or C++ compiler, then link
-these two files into a shared library named "libtree-sitter-LANG.so",
-where LANG is the name of the language supported by the grammar as it
-is expected by the Emacs major mode (for example, "c" for 'c-ts-mode',
-"cpp" for 'c++-ts-mode', "python" for 'python-ts-mode', etc.). Then place
-the shared library you've built in the same directory where you keep
-the other shared libraries used by Emacs, or in the "tree-sitter"
-subdirectory of your 'user-emacs-directory', or in a directory
-mentioned in the variable 'treesit-extra-load-path'.
+Emacs provides a user command, 'treesit-install-language-grammar',
+that automates the download and build process of a grammar library.
+It prompts for the language, the URL of the language grammar's VCS
+repository, and then uses the installed C/C++ compiler to build the
+library and install it.
+
+You can also do this manually. To compile such a library after
+cloning its Git repository, compile the files "scanner.c" and
+"parser.c" (sometimes named "scanner.cc" and "parser.cc") in the "src"
+subdirectory of the library's source tree using the C or C++ compiler,
+then link these two files into a shared library named
+"libtree-sitter-LANG.so", where LANG is the name of the language
+supported by the grammar as it is expected by the Emacs major mode
+(for example, "c" for 'c-ts-mode', "cpp" for 'c++-ts-mode', "python"
+for 'python-ts-mode', etc.). Then place the shared library you've
+built in the same directory where you keep the other shared libraries
+used by Emacs, or in the "tree-sitter" subdirectory of your
+'user-emacs-directory', or in a directory mentioned in the variable
+'treesit-extra-load-path'.
You only need to install language grammar libraries required by the
Emacs modes you will use, as Emacs loads these libraries only when the
@@ -326,7 +337,7 @@ this off, disable the new 'isearch-fold-quotes-mode' minor mode.
---
** Sorting commands no longer necessarily change modification status.
-In earlier Emacs versions, commands like 'M-x sort-lines' would always
+In earlier Emacs versions, commands like 'sort-lines' would always
change buffer modification status to "modified", whether they changed
something in the buffer or not. This has been changed: the buffer is
marked as modified only if the sorting ended up actually changing the
@@ -345,6 +356,15 @@ also means that 'TAB' on a button in an 'outline-minor-mode' heading
will move point instead of collapsing the outline.
---
+** 'outline-minor-mode-cycle-map' is now parent of 'outline-minor-mode'.
+Instead of adding text property 'keymap' with 'outline-minor-mode-cycle'
+on outline headings in 'outline-minor-mode', the keymap
+'outline-minor-mode-cycle' is now active in the whole buffer.
+But keybindings in 'outline-minor-mode-cycle' still take effect
+only on outline headings because they are bound with the help of
+'outline-minor-mode-cycle--bind' that checks if point is on a heading.
+
+---
** 'Info-default-directory-list' is no longer populated at Emacs startup.
If you have code in your init file that removes directories from
'Info-default-directory-list', this will no longer work.
@@ -377,7 +397,7 @@ files that were compiled with an old EIEIO (Emacs<25).
This is to open up the 'C-x 8 .' map to bind further characters there.
---
-** 'C-x 8 =' moved to 'C-x 8 = ='.
+** 'C-x 8 =' has been moved to 'C-x 8 = ='.
You can now use 'C-x 8 =' to insert several characters with macron;
for example, 'C-x 8 = a' will insert U+0101 LATIN SMALL LETTER A WITH
MACRON. To insert a lone macron, type 'C-x 8 = =' instead of the
@@ -387,8 +407,8 @@ previous 'C-x ='.
*** Eshell's PATH is now derived from 'exec-path'.
For consistency with remote connections, Eshell now uses 'exec-path'
-to determine the execution path on the local system, instead of using
-the PATH environment variable directly.
+to determine the execution path on the local or remote system, instead
+of using the PATH environment variable directly.
---
*** 'source' and '.' no longer accept the '--help' option.
@@ -410,12 +430,12 @@ To pipe both stdout and stderr, use the '|&' operator instead of '|'.
---
** The 'delete-forward-char' command now deletes by grapheme clusters.
-This command is by default bound to the <Delete> function key
-(a.k.a. <deletechar>). When invoked without a prefix argument or with
-a positive prefix numeric argument, the command will now delete
+This command is by default bound to the '<Delete>' function key
+(a.k.a. '<deletechar>'). When invoked without a prefix argument or
+with a positive prefix numeric argument, the command will now delete
complete grapheme clusters produced by character composition. For
-example, if point is before an Emoji sequence, pressing <Delete> will
-delete the entire sequence, not just a single character at its
+example, if point is before an Emoji sequence, pressing '<Delete>'
+will delete the entire sequence, not just a single character at its
beginning.
+++
@@ -504,7 +524,7 @@ performance, but the latter is closer to a drop-in replacement.
---
** The thumbs.el library is now obsolete.
-We recommend using 'M-x image-dired' instead.
+We recommend using command 'image-dired' instead.
---
** The autoarg.el library is now marked obsolete.
@@ -642,7 +662,7 @@ duplicated on its right-hand side.
+++
** 'network-lookup-address-info' can now check numeric IP address validity.
-Specifying 'numeric' as the new optional 'hints' argument makes it
+Specifying 'numeric' as the new optional HINTS argument makes it
check if the passed address is a valid IPv4/IPv6 address (without DNS
traffic).
@@ -691,7 +711,7 @@ This is like 'save-buffers-kill-emacs', but instead of just killing
the current Emacs process at the end, it starts a new Emacs process
(using the same command line arguments as the running Emacs process).
'kill-emacs' and 'save-buffers-kill-emacs' have also gained new
-optional parameters to restart instead of just killing the current
+optional arguments to restart instead of just killing the current
process.
** Drag and Drop
@@ -791,9 +811,10 @@ filter/sentinel error has been handled.
** New faces for font-lock.
These faces are primarily meant for use with tree-sitter. They are:
'font-lock-bracket-face', 'font-lock-delimiter-face',
-'font-lock-escape-face', 'font-lock-number-face',
-'font-lock-misc-punctuation-face', 'font-lock-operator-face',
-'font-lock-property-face', and 'font-lock-punctuation-face'.
+'font-lock-escape-face', 'font-lock-misc-punctuation-face',
+'font-lock-number-face', 'font-lock-operator-face',
+'font-lock-property-face', and 'font-lock-punctuation-face',
+'font-lock-regexp-face'.
+++
** New face 'variable-pitch-text'.
@@ -896,7 +917,7 @@ the 'COLORTERM' environment variable is set to the value "truecolor".
---
*** Select active regions with xterm selection support.
-On terminals with xterm setSelection support, the active region may be
+On terminals with xterm "setSelection" support, the active region may be
saved to the X primary selection, following the
'select-active-regions' variable. This support is enabled when
'tty-select-active-regions' is non-nil.
@@ -1035,7 +1056,7 @@ instead.
*** New user option 'help-enable-variable-value-editing'.
If enabled, 'e' on a value in "*Help*" will pop you to a new buffer
where you can edit the value. This is not enabled by default, because
-it's easy to make an edit that yields an invalid result.
+it is easy to make an edit that yields an invalid result.
---
*** 'C-h b' uses outlining by default.
@@ -1080,7 +1101,7 @@ helpful commands for various tasks. You can toggle the display using
'C-h C-q'.
** Emacs now comes with Org v9.6.
-See the file ORG-NEWS for user-visible changes in Org.
+See the file "ORG-NEWS" for user-visible changes in Org.
** Outline Mode
@@ -1129,14 +1150,14 @@ buffer on that frame.
*** 'display-buffer' now can set up the body size of the chosen window.
For example, a 'display-buffer-alist' entry of
- '(window-width . (body-columns . 40))'
+ (window-width . (body-columns . 40))
will make the body of the chosen window 40 columns wide. For the
height use 'window-height' and 'body-lines', respectively.
---
*** You can customize on which window 'scroll-other-window' operates.
-This is controlled by the new 'other-window-scroll-default' user option.
+This is controlled by the new 'other-window-scroll-default' variable.
** Frames
@@ -1176,7 +1197,7 @@ LRI). The new command 'highlight-confusing-reorderings' finds and
highlights segments of buffer text whose reordering for display is
suspicious and could be malicious.
-** Emacs server and client changes
+** Emacs Server and Client
+++
*** New command-line option '-r'/'--reuse-frame' for emacsclient.
@@ -1209,9 +1230,9 @@ available options can be restored by enabling this option.
*** New user option 'rcirc-bridge-bot-alist'.
If you are in a channel where a bot is responsible for bridging
between networks, you can use this variable to make these messages
-appear more native. For example you might set the option to:
+appear more native. For example, you might set the option to:
- (setq rcirc-bridge-bot-alist '(("bridge" . "{\\(.+?\\)}[[:space:]]+")))
+ (setopt rcirc-bridge-bot-alist '(("bridge" . "{\\(.+?\\)}[[:space:]]+")))
for messages like
@@ -1250,6 +1271,7 @@ will wait forever for redisplay to finish. (We believe you won't need
this feature, given the ability to display buffers with very long
lines.)
+
* Editing Changes in Emacs 29.1
+++
@@ -1307,12 +1329,12 @@ dragged.
---
** New user option 'yank-menu-max-items'.
Customize this option to limit the number of entries in the menu
-"Edit->Paste from Kill Menu". The default is 60.
+"Edit → Paste from Kill Menu". The default is 60.
+++
** Performing a pinch gesture on a touchpad now increases the text scale.
-** show-paren-mode
+** Show Paren Mode
+++
*** New user option 'show-paren-context-when-offscreen'.
@@ -1352,15 +1374,16 @@ you don't want to enable input fontification by default.
---
*** New user options for alternate wheel events.
-The options 'mouse-wheel-down-alternate-event',
-'mouse-wheel-up-alternate-event', 'mouse-wheel-left-alternate-event',
-and 'mouse-wheel-right-alternate-event' have been added to better
-support systems where two kinds of wheel events can be received.
+The user options 'mouse-wheel-down-alternate-event' and
+'mouse-wheel-up-alternate-event' as well as the variables
+'mouse-wheel-left-alternate-event' and
+'mouse-wheel-right-alternate-event' have been added to better support
+systems where two kinds of wheel events can be received.
-** Internationalization changes
+** Internationalization
---
-*** The <Delete> function key now allows deleting the entire composed sequence.
+*** The '<Delete>' function key now allows deleting the entire composed sequence.
For the details, see the item about the 'delete-forward-char' command
above.
@@ -1465,7 +1488,7 @@ change the input method's translation rules, customize the user option
'tamil-translation-rules'.
---
-*** New tamil99 input method for the Tamil language.
+*** New 'tamil99' input method for the Tamil language.
This supports the keyboard layout specifically designed for the Tamil
language.
@@ -1499,7 +1522,7 @@ If non-nil and there's only one matching option, auto-select that.
If non-nil, this user option describes what entries not to add to the
database stored on disk.
-** Auth-Source
+** Auth Source
+++
*** New user option 'auth-source-pass-extra-query-keywords'.
@@ -1531,7 +1554,7 @@ The corresponding key 'Y' is now bound by default in Dired.
+++
*** 'dired-do-relsymlink-regexp' moved from dired-x to dired.
-The corresponding key '% Y' is now bound by default in Dired.
+The corresponding key sequence '% Y' is now bound by default in Dired.
---
*** 'M-G' is now bound to 'dired-goto-subdir'.
@@ -1577,7 +1600,7 @@ Dired will now, by default, include the free space in the first line
instead of having it on a separate line. To get the previous behavior
back, say:
- (setq dired-free-space 'separate)
+ (setopt dired-free-space 'separate)
---
*** New user option 'dired-make-directory-clickable'.
@@ -1618,6 +1641,20 @@ randomness as before, or to use a bag).
*** New user option 'battery-update-functions'.
This can be used to trigger actions based on the battery status.
+** DocView
+
+---
+*** doc-view can now generate SVG images when viewing PDF files.
+If Emacs is built with SVG support, doc-view can generate SVG files
+when using MuPDF as the converter for PDF files, which generally leads
+to sharper images (especially when zooming), and allows customization
+of background and foreground color of the page via the new user
+options 'doc-view-svg-background' and 'doc-view-svg-foreground'. To
+activate this behavior, set 'doc-view-mupdf-use-svg' to non-nil if
+your Emacs has SVG support. Note that, with some versions of MuPDF,
+SVG generation is known to sometimes produce SVG files that are buggy
+or can take a long time to render.
+
** Enriched Mode
+++
@@ -1670,7 +1707,7 @@ this invocation as its default.
This is bound to 'H' and toggles whether to hide or show the widget
contents.
-** Diff mode
+** Diff Mode
---
*** New user option 'diff-whitespace-style'.
@@ -1820,7 +1857,7 @@ only jump if the location of the first error is known), and
+++
*** New user option 'compilation-max-output-line-length'.
-Lines longer than the value of this variable will have their ends
+Lines longer than the value of this option will have their ends
hidden, with a button to reveal the hidden text. This speeds up
operations like grepping on files that have few newlines. The default
value is 400; set to nil to disable hiding.
@@ -1852,10 +1889,10 @@ uses the 'key-parse' syntax. It replaces the old 'kmacro-lambda-form'
---
** savehist.el can now truncate variables that are too long.
-An element of 'savehist-additional-variables' can now be of the form
-'(VARIABLE . MAX-ELTS)', which means to truncate the VARIABLE's value to
-at most MAX-ELTS elements (if the value is a list) before saving the
-value.
+An element of user option 'savehist-additional-variables' can now be
+of the form '(VARIABLE . MAX-ELTS)', which means to truncate the
+VARIABLE's value to at most MAX-ELTS elements (if the value is a list)
+before saving the value.
** Minibuffer and Completions
@@ -1972,7 +2009,7 @@ command accepts the Unicode name of an Emoji (for example, "smiling
face" or "heart with arrow"), like 'C-x 8 e e', with minibuffer
completion, and adds the Emoji into the search string.
-** Glyphless characters
+** Glyphless Characters
+++
*** New minor mode 'glyphless-display-mode'.
@@ -1989,7 +2026,7 @@ and GUI terminals.
*** "Replacement character" feature for undisplayable characters on TTYs.
The 'acronym' method of displaying glyphless characters on text-mode
frames treats single-character acronyms specially: they are displayed
-without the surrounding [..] "box", thus in effect treating such
+without the surrounding '[..]' "box", thus in effect treating such
"acronyms" as replacement characters.
** Registers
@@ -2001,7 +2038,7 @@ For instance, to enable jumping to the "*Messages*" buffer with
(set-register ?m '(buffer . "*Messages*"))
-** Pixel-fill
+** Pixel Fill
+++
*** This is a new package that deals with filling variable-pitch text.
@@ -2013,11 +2050,11 @@ This fills the region to be no wider than a specified pixel width.
** Info
+++
-*** 'M-x info-apropos' now takes a prefix argument to search for regexps.
+*** Command 'info-apropos' now takes a prefix argument to search for regexps.
---
*** New command 'Info-goto-node-web' and key binding 'G'.
-This will take you to the gnu.org web server's version of the current
+This will take you to the "gnu.org" web server's version of the current
info node. This command only works for the Emacs and Emacs Lisp manuals.
** Shortdoc
@@ -2045,7 +2082,7 @@ The VC Directory buffer now uses the prefix 'b' for these branch-related
commands.
+++
-*** New command '%' ('vc-dir-mark-by-regexp').
+*** New command 'vc-dir-mark-by-regexp' bound to '% m' and '* %'.
This command marks files based on a regexp. If given a prefix
argument, unmark instead.
@@ -2158,9 +2195,9 @@ main Emacs initialization file ("~/.emacs" or "~/.emacs.d/init.el").
+++
*** 'eudc-expansion-overwrites-query' to 'eudc-expansion-save-query-as-kill'.
-'eudc-expansion-overwrites-query' is renamed to
+The user option 'eudc-expansion-overwrites-query' is renamed to
'eudc-expansion-save-query-as-kill' to reflect the actual behavior of
-the user option.
+the user option. The former is kept as alias.
+++
*** New command 'eudc-expand-try-all'.
@@ -2174,7 +2211,7 @@ for a name that happens to match a contact in one's BBDB.
*** New behavior and default for user option 'eudc-inline-expansion-format'.
EUDC inline expansion result formatting defaulted to
- '("%s %s <%s>" firstname name email)
+ ("%s %s <%s>" firstname name email)
Since email address specifications need to comply with RFC 5322 in
order to be useful in messages, there was a risk to produce syntax
@@ -2221,8 +2258,9 @@ are supported only.
The 'eww-auto-rename-buffer' user option can be configured to rename
rendered web pages by using their title, URL, or a user-defined
function which returns a string. For the first two cases, the length
-of the resulting name is controlled by 'eww-buffer-name-length'. By
-default, no automatic renaming is performed.
+of the resulting name is controlled by the user option
+'eww-buffer-name-length'. By default, no automatic renaming is
+performed.
+++
*** New user option 'shr-allowed-images'.
@@ -2241,7 +2279,7 @@ doesn't work on other systems. Also see etc/PROBLEMS.
These are used to alter an URL before using it. By default it removes
the common "utm_" trackers from URLs.
-** Find-Dired
+** Find Dired
---
*** New command 'find-dired-with-command'.
@@ -2258,14 +2296,14 @@ Message, referred to as 'gnus-summary-tool-bar-retro',
'gnus-group-tool-bar-retro' and 'message-tool-bar-retro', and
'gnus-summary-tool-bar-gnome', 'gnus-group-tool-bar-gnome' and
'message-tool-bar-gnome'. The "retro" tool bars have been removed (as
-well as the icons used), and the "Gnome" tool bars are now the only
+well as the icons used), and the "gnome" tool bars are now the only
pre-defined toolbars.
---
*** 'gnus-summary-up-thread' and 'gnus-summary-down-thread' bindings removed.
-The 'gnus-summary-down-thread' binding to "M-C-d" was shadowed by
+The 'gnus-summary-down-thread' binding to 'M-C-d' was shadowed by
'gnus-summary-read-document', and these commands are also available on
-"T-u" and "T-d" respectively.
+'T u' and 'T d' respectively.
---
*** Gnus now uses a variable-pitch font in the headers by default.
@@ -2349,7 +2387,7 @@ displayed in the "*Help*" buffer will be linked to the documentation
for the command they are bound to. This does not affect listings of
key bindings and functions (such as 'C-h b').
-** Info-look
+** Info Look
---
*** info-look specs can now be expanded at run time instead of a load time.
@@ -2357,14 +2395,14 @@ The new ':doc-spec-function' element can be used to compute the
':doc-spec' element when the user asks for info on that particular
mode (instead of at load time).
-** Ansi-color
+** Ansi Color
---
*** Support for ANSI 256-color and 24-bit colors.
256-color and 24-bit color codes are now handled by ANSI color
filters and displayed with the specified color.
-** Term-mode
+** Term Mode
---
*** New user option 'term-bind-function-keys'.
@@ -2428,7 +2466,7 @@ matches.
---
*** New function 'xref-show-xrefs'.
-** File notifications
+** File Notifications
+++
*** The new command 'file-notify-rm-all-watches' removes all file notifications.
@@ -2499,7 +2537,7 @@ The old name was confusing, and is now an obsolete function alias.
*** Users can now add special image conversion functions.
This is done via 'image-converter-add-handler'.
-** Image-Dired
+** Image Dired
+++
*** 'image-dired-image-mode' is now based on 'image-mode'.
@@ -2600,9 +2638,9 @@ programs. Version 0.9.0 adds two larger thumbnail sizes: 512x512 and
to use it; it is not enabled by default.
---
-*** Reduce dependency on external "exiftool" command.
-The 'image-dired-copy-with-exif-file-name' no longer requires an
-external "exiftool" command to be available. The user options
+*** Reduce dependency on external "exiftool" program.
+The 'image-dired-copy-with-exif-file-name' command no longer requires
+an external "exiftool" program to be available. The user options
'image-dired-cmd-read-exif-data-program' and
'image-dired-cmd-read-exif-data-options' are now obsolete.
@@ -2706,7 +2744,7 @@ fringe (or nil to disable showing this marker).
This is a convenience function to extract the field data from
'exif-parse-file' and 'exif-parse-buffer'.
-** Xwidgets
+** Xwidget
---
*** New user option 'xwidget-webkit-buffer-name-format'.
@@ -2749,7 +2787,7 @@ and friends.
+++
*** New connection methods "docker", "podman" and "kubernetes".
-They allow accessing environments provided by Docker and similar
+They allow accessing containers provided by Docker and similar
programs.
---
@@ -2847,7 +2885,7 @@ will cause the whole command to be passed to the operating system
shell. This is particularly useful to bypass Eshell's own pipelining
support for pipelines which will move a lot of data. See section
"Running Shell Pipelines Natively" in the Eshell manual, node
-"(eshell) Input/Output".
+"(eshell) Pipelines".
+++
*** New module to help supplying absolute file names to remote commands.
@@ -2902,8 +2940,8 @@ values passed as a single token, such as '-oVALUE' or
commands" in the "(eshell) Built-ins" node of the Eshell manual.
---
-*** Eshell globs ending with '/' now match only directories.
-Additionally, globs ending with '**/' or '***/' no longer raise an
+*** Eshell globs ending with "/" now match only directories.
+Additionally, globs ending with "**/" or "***/" no longer raise an
error, and now expand to all directories recursively (following
symlinks in the latter case).
@@ -3046,7 +3084,7 @@ The old name is still available as an obsolete function alias.
*** The url-irc library now understands "ircs://" links.
---
-*** New command 'world-clock-copy-time-as-kill' for 'M-x world-clock'.
+*** New command 'world-clock-copy-time-as-kill' for 'world-clock-mode'.
It copies the current line into the kill ring.
---
@@ -3055,17 +3093,17 @@ The new face 'abbrev-table-name' is used to display the abbrev table
name.
---
-*** New key binding 'O' in 'M-x list-buffers'.
+*** New key binding 'O' in "*Buffer List*".
This key is now bound to 'Buffer-menu-view-other-window', which will
view this line's buffer in View mode in another window.
-** Scheme mode
+** Scheme Mode
---
*** Auto-detection of Scheme library files.
Emacs now automatically enables the Scheme mode when opening R6RS
-Scheme Library Source ('.sls') files and R7RS Scheme Library
-Definition ('.sld') files.
+Scheme Library Source (".sls") files and R7RS Scheme Library
+Definition (".sld") files.
---
*** Imenu members for R6RS and R7RS library members.
@@ -3080,10 +3118,10 @@ Imenu now lists the members directly nested in R6RS Scheme libraries
Emacs now comes with the Eglot package, which enhances various Emacs
features, such as completion, documentation, error detection, etc.,
based on data provided by language servers using the Language Server
-Protocol (LSP).
+Protocol (LSP). See the new Info manual "(eglot) Top" for more.
+++
-*** use-package: Declarative package configuration.
+** use-package: Declarative package configuration.
use-package is now shipped with Emacs. It provides the 'use-package'
macro, which allows you to isolate package configuration in your init
file in a way that is declarative, tidy, and performance-oriented.
@@ -3146,10 +3184,19 @@ indentation, and navigation by defuns based on parsing the buffer text
by a tree-sitter parser. Some major modes also offer support for
Imenu and 'which-func'.
-Where major modes already exist in Emacs for editing certain kinds of
-files, the new modes based on tree-sitter are for now entirely
-optional, and you must turn them on manually, or customize
-'auto-mode-alist' to turn them on automatically.
+The new modes based on tree-sitter are for now entirely optional, and
+you must turn them on manually, or load them in your init file, or
+customize 'auto-mode-alist' to turn them on automatically for certain
+files. You can also customize 'major-mode-remap-alist' to
+automatically turn on some tree-sitter based modes for the same files
+for which a "built-in" mode would be turned on. For example:
+
+ (add-to-list 'major-mode-remap-alist '(ruby-mode . ruby-ts-mode))
+
+If you try these modes and don't like them, you can go back to the
+"built-in" modes by restarting Emacs. But please tell us why you
+didn't like the tree-sitter based modes, so that we could try
+improving them.
Each major mode based on tree-sitter needs a language grammar library,
usually named "libtree-sitter-LANG.so" ("libtree-sitter-LANG.dll" on
@@ -3166,20 +3213,18 @@ We recommend to install these libraries in one of the standard system
locations (the last place in the above list).
If a language grammar library required by a mode is not found in any
-of the above places, the mode will signal an error when you try to
+of the above places, the mode will display a warning when you try to
turn it on.
+++
*** New major mode 'typescript-ts-mode'.
A major mode based on the tree-sitter library for editing programs
-in the TypeScript language. This mode is auto-enabled for files with
-the ".ts" extension.
+in the TypeScript language.
+++
*** New major mode 'tsx-ts-mode'.
A major mode based on the tree-sitter library for editing programs
-in the TypeScript language, with support for TSX. This mode is
-auto-enabled for files with the ".tsx" extension.
+in the TypeScript language, with support for TSX.
+++
*** New major mode 'c-ts-mode'.
@@ -3192,6 +3237,11 @@ An optional major mode based on the tree-sitter library for editing
programs in the C++ language.
+++
+*** New command 'c-or-c++-ts-mode'.
+A command that automatically guesses the language of a header file,
+and enables either 'c-ts-mode' or 'c++-ts-mode' accordingly.
+
++++
*** New major mode 'java-ts-mode'.
An optional major mode based on the tree-sitter library for editing
programs in the Java language.
@@ -3224,42 +3274,36 @@ Bash shell scripts.
+++
*** New major mode 'dockerfile-ts-mode'.
A major mode based on the tree-sitter library for editing
-Dockerfiles. This mode is auto-enabled for files which are named
-"Dockerfile", have the "Dockerfile." prefix, or have the ".dockerfile"
-extension.
+Dockerfiles.
+++
*** New major mode 'cmake-ts-mode'.
A major mode based on the tree-sitter library for editing CMake files.
-It is auto-enabled for files whose name is "CMakeLists.txt" or whose
-extension is ".cmake".
+++
*** New major mode 'toml-ts-mode'.
-A major mode based on the tree-sitter library for editing files
-written in TOML, a format for writing configuration files. It is
-auto-enabled for files with the ".toml" extension.
+An optional major mode based on the tree-sitter library for editing
+files written in TOML, a format for writing configuration files.
+++
*** New major mode 'go-ts-mode'.
A major mode based on the tree-sitter library for editing programs in
-the Go language. It is auto-enabled for files with the ".go" extension.
+the Go language.
+++
*** New major mode 'go-mod-ts-mode'.
A major mode based on the tree-sitter library for editing "go.mod"
-files. It is auto-enabled for files which are named "go.mod".
+files.
+++
*** New major mode 'yaml-ts-mode'.
A major mode based on the tree-sitter library for editing files
-written in YAML. It is auto-enabled for files with the ".yaml" or
-".yml" extensions.
+written in YAML.
+++
*** New major mode 'rust-ts-mode'.
A major mode based on the tree-sitter library for editing programs in
-the Rust language. It is auto-enabled for files with the ".rs" extension.
+the Rust language.
---
*** New major mode 'ruby-ts-mode'.
@@ -3317,13 +3361,13 @@ auto-scaling applied. (This only makes a difference on HiDPI
displays.)
+++
-** Changes in how "raw" in-memory xbm images are specified.
+** Changes in how "raw" in-memory XBM images are specified.
Some years back Emacs gained the ability to scale images, and you
could then specify ':width' and ':height' when using 'create-image' on all
-image types -- except xbm images, because this format already used the
+image types -- except XBM images, because this format already used the
':width' and ':height' arguments to specify the width/height of the "raw"
in-memory format. This meant that if you used these specifications
-on, for instance, xbm files, Emacs would refuse to display them. This
+on, for instance, XBM files, Emacs would refuse to display them. This
has been changed, and ':width'/':height' now works as with all other image
formats, and the way to specify the width/height of the "raw"
in-memory format is now by using ':data-width' and ':data-height'.
@@ -3334,7 +3378,7 @@ The various "loaddefs.el" files in the Emacs tree (which contain
information about autoloads, built-in packages and package prefixes)
used to be generated by functions in autoloads.el. These are now
generated by loaddefs-gen.el instead. This leads to functionally
-equivalent "loaddef.el" files, but they do not use exactly the same
+equivalent "loaddefs.el" files, but they do not use exactly the same
syntax, so using 'M-x update-file-autoloads' no longer works. (This
didn't work well in most files in the past, either, but it will now
signal an error in any file.)
@@ -3479,7 +3523,7 @@ This change is now applied in 'dired-insert-directory'.
---
** 'compilation-last-buffer' is (finally) declared obsolete.
-It's been obsolete since Emacs-22.1, actually.
+It has been obsolete since Emacs 22.1, actually.
---
** Calling 'lsh' now elicits a byte-compiler warning.
@@ -3509,9 +3553,9 @@ but switching to 'ash' is generally much preferable.
'command-history-map', 'compilation-parse-errors-function',
'completion-annotate-function', 'condition-case-no-debug',
'count-lines-region', 'crisp-mode-modeline-string',
-'custom-print-functions', 'custom-print-functions',
-'cvs-string-prefix-p', 'data-debug-map', 'deferred-action-function',
-'deferred-action-list', 'dired-pop-to-buffer', 'dired-shrink-to-fit',
+'custom-print-functions', 'cvs-string-prefix-p', 'data-debug-map',
+'deferred-action-function', 'deferred-action-list',
+'dired-pop-to-buffer', 'dired-shrink-to-fit',
'dired-sort-set-modeline', 'dired-x-submit-report',
'display-buffer-function',
'ediff-choose-window-setup-function-automatically',
@@ -3533,11 +3577,10 @@ but switching to 'ash' is generally much preferable.
'inhibit-first-line-modes-suffixes', 'input-method-inactivate-hook',
'intdos', 'javascript-generic-mode', 'javascript-generic-mode-hook',
'latex-string-prefix-p', 'macro-declaration-function' (function),
-'macro-declaration-function' (variable), 'mail-complete-function',
-'mail-completion-at-point-function',
-'mail-mailer-swallows-blank-line', 'mail-sent-via', 'make-register',
-'makefile-complete', 'menu-bar-kill-ring-save',
-'meta-complete-symbol', 'meta-mode-map',
+'macro-declaration-function' (variable), 'mail-complete',
+'mail-complete-function', 'mail-mailer-swallows-blank-line',
+'mail-sent-via', 'make-register', 'makefile-complete',
+'menu-bar-kill-ring-save', 'meta-complete-symbol', 'meta-mode-map',
'mh-kill-folder-suppress-prompt-hooks',
'minibuffer-completing-symbol',
'minibuffer-local-filename-must-match-map', 'mode25', 'mode4350',
@@ -3708,7 +3751,7 @@ This can be used to specify what forms to put into 'command-history'
when executing commands interactively.
+++
-** The FORM arg of 'time-convert' is mandatory.
+** The FORM argument of 'time-convert' is mandatory.
'time-convert' can still be called without it, as before, but the
compiler now emits a warning about this deprecated usage.
@@ -3725,7 +3768,7 @@ TIMEOUT is the idle time after which to deactivate the transient map.
The default timeout value can be defined by the new variable
'set-transient-map-timeout'.
-** Connection-local variables
+** Connection Local Variables
+++
*** Some connection-local variables are now user options.
@@ -3754,13 +3797,13 @@ Reference manual for more information.
+++
** 'plist-get', 'plist-put' and 'plist-member' are no longer limited to 'eq'.
-These function now take an optional comparison predicate argument.
+These function now take an optional comparison PREDICATE argument.
+++
** 'read-multiple-choice' can now use long-form answers.
+++
-** 'M-c' in 'read-regexp' now toggles case folding.
+** 'M-s c' in 'read-regexp' now toggles case folding.
+++
** 'completing-read' now allows a function as its REQUIRE-MATCH argument.
@@ -3814,7 +3857,7 @@ When called with a new optional argument UNICODE non-nil, 'max-char'
will now report the maximum valid codepoint defined by the Unicode
Standard.
-** seq
+** Seq
+++
*** New function 'seq-split'.
@@ -3852,8 +3895,8 @@ It is called whenever the configuration of different monitors on a
display changes.
+++
-** 'prin1' and 'prin1-to-string' now take an optional OVERRIDES parameter.
-This parameter can be used to override values of print-related settings.
+** 'prin1' and 'prin1-to-string' now take an optional OVERRIDES argument.
+This argument can be used to override values of print-related settings.
+++
** New minor mode 'header-line-indent-mode'.
@@ -3862,9 +3905,9 @@ be kept aligned with the buffer contents when the user switches
'display-line-numbers-mode' on or off.
+++
-** New minor mode 'lost-selection-mode'.
-This minor mode makes Emacs deactivate the mark in all buffers when
-the primary selection is obtained by another program.
+** New global minor mode 'lost-selection-mode'.
+This global minor mode makes Emacs deactivate the mark in all buffers
+when the primary selection is obtained by another program.
---
** On X, Emacs will try to preserve selection ownership when a frame is deleted.
@@ -3879,7 +3922,7 @@ setting the user option 'x-auto-preserve-selections' to nil.
** New predicate 'char-uppercase-p'.
This returns non-nil if its argument its an uppercase character.
-** Byte compilation
+** Byte Compilation
---
*** Byte compilation will now warn about some quoting mistakes in docstrings.
@@ -3897,7 +3940,7 @@ should really be present in the docstring, they should be quoted with
---
*** Byte compilation will now warn about some malformed 'defcustom' types.
-It's very common to write 'defcustom' types on the form:
+It is very common to write 'defcustom' types on the form:
:type '(choice (const :tag "foo" 'bar))
@@ -3976,7 +4019,7 @@ batch-based Emacs scripts.
This works like 'buttonize', but for a region instead of a string.
+++
-** 'macroexp-let2*' can omit TEST arg and use single-var bindings.
+** 'macroexp-let2*' can omit TEST argument and use single-var bindings.
+++
** New macro-writing macros, 'cl-with-gensyms' and 'cl-once-only'.
@@ -3989,7 +4032,7 @@ from which the last input event originated, and 'device-class' can be
used to determine the type of an input device.
+++
-** 'track-mouse' can have a new value 'drag-source'.
+** Variable 'track-mouse' can have a new value 'drag-source'.
This means the same as 'dropping', but modifies the mouse position
list in reported motion events if there is no frame underneath the
mouse pointer.
@@ -4037,7 +4080,7 @@ frequently than once in a second.
---
** New function 'bidi-string-strip-control-characters'.
-This utility function is meant for displaying strings when it's
+This utility function is meant for displaying strings when it is
essential that there's no bidirectional context. It removes all the
bidirectional formatting control characters (such as RLM, LRO, PDF,
etc.) from its argument string. The characters it removes are listed
@@ -4095,21 +4138,21 @@ them towards or away from each other.
+++
** New hook 'x-pre-popup-menu-hook'.
-This hook is run before 'x-popup-menu' is about to display a
+This hook, run before 'x-popup-menu', is about to display a
deck-of-cards menu on screen.
---
** New hook 'post-select-region-hook'.
-This hook is run immediately after 'select-active-regions' causes the
-region to be set as the primary selection.
+This hook is run immediately after 'select-active-regions'. It causes
+the region to be set as the primary selection.
+++
** New function 'buffer-match-p'.
Check if a buffer satisfies some condition. Some examples for
conditions can be regular expressions that match a buffer name, a
cons-cell like '(major-mode . shell-mode)' that matches any buffer
-where 'major-mode' is 'shell-mode' or a combined with a condition like
-'(and "\\`\\*.+\\*\\'" (major-mode . special-mode))'.
+where 'major-mode' is 'shell-mode' or a combination with a condition
+like '(and "\\`\\*.+\\*\\'" (major-mode . special-mode))'.
+++
** New function 'match-buffers'.
@@ -4117,19 +4160,19 @@ It uses 'buffer-match-p' to gather a list of buffers that match a
condition.
---
-** New optional arguments 'text-face' and 'default-face' for 'tooltip-show'.
+** New optional arguments TEXT-FACE and DEFAULT-FACE for 'tooltip-show'.
They allow changing the faces used for the tooltip text and frame
colors of the resulting tooltip frame from the default 'tooltip' face.
-** Text security and suspiciousness
+** Text Security and Suspiciousness
+++
*** New library textsec.el.
This library contains a number of checks for whether a string is
"suspicious". This usually means that the string contains characters
that have glyphs that can be confused with other, more commonly used
-glyphs, or contain bidirectional (or other) formatting characters that
-may be used to confuse a user.
+glyphs, or contains bidirectional (or other) formatting characters
+that may be used to confuse a user.
+++
*** New user option 'textsec-check'.
@@ -4147,7 +4190,7 @@ This is the main function Emacs applications should be using to check
whether a string is suspicious. It heeds the 'textsec-check' user
option.
-** Keymaps and key definitions
+** Keymaps and Key Definitions
+++
*** 'where-is-internal' can now filter events marked as non key events.
@@ -4183,7 +4226,7 @@ de-emphasized in the documentation.
*** Use 'keymap-set-after' instead of 'define-key-after'.
+++
-*** Use 'keymap-lookup' instead of 'lookup-keymap' and 'key-binding'.
+*** Use 'keymap-lookup' instead of 'lookup-key' and 'key-binding'.
+++
*** Use 'keymap-local-lookup' instead of 'local-key-binding'.
@@ -4271,9 +4314,9 @@ instance) when covering huge amounts of data (that has no meaningful
searchable data, like image data) with a 'display' text property.
+++
-** 'insert-image' now takes an INHIBIT-ISEARCH optional parameter.
+** 'insert-image' now takes an INHIBIT-ISEARCH optional argument.
It marks the image with the 'inhibit-isearch' text property, which
-inhibits 'isearch' matching the STRING parameter.
+inhibits 'isearch' matching the STRING argument.
---
** New variable 'replace-regexp-function'.
@@ -4295,15 +4338,21 @@ whose matches are to be replaced. If these variables are nil (which
is the default), 'query-replace' and 'query-replace-regexp' take the
default value from the previous FROM-TO pair.
----
-** New user option 'pp-use-max-width'.
-If non-nil, 'pp' will attempt to limit the line length when formatting
-long lists and vectors.
+** Lisp pretty-printer ('pp')
---
-** New function 'pp-emacs-lisp-code'.
+*** New function 'pp-emacs-lisp-code'.
'pp' formats general Lisp sexps. This function does much the same,
-but applies formatting rules appropriate for Emacs Lisp code.
+but applies formatting rules appropriate for Emacs Lisp code. Note
+that this could currently be quite slow, and is thus appropriate only
+for relatively small code fragments.
+
+---
+*** New user option 'pp-use-max-width'.
+If non-nil, 'pp' and all 'pp-*' commands that format the results, will
+attempt to limit the line length when formatting long lists and
+vectors. This uses 'pp-emacs-lisp-code', and thus could be slow for
+large lists.
+++
** New function 'file-has-changed-p'.
@@ -4341,7 +4390,7 @@ character width/height.
This means the vscroll will not be reset when set on a window that is
"frozen" due to a mini-window being resized.
-** XDG support
+** XDG Support
---
*** New function 'xdg-state-home'.
@@ -4387,7 +4436,7 @@ This holds the value of the previous call to 'set-locale-environment'.
This macro can be used to change the locale temporarily while
executing code.
-** table.el
+** Table
---
*** New user option 'table-latex-environment'.
@@ -4413,8 +4462,8 @@ local variables and removes overlays and text properties.
+++
** 'kill-all-local-variables' can now kill all local variables.
-If given the new optional KILL-PERMANENT argument, also kill permanent
-local variables.
+If given the new optional KILL-PERMANENT argument, it also kills
+permanent local variables.
+++
** Third 'mapconcat' argument SEPARATOR is now optional.
@@ -4432,7 +4481,7 @@ This macro allows defining keymap variables more conveniently.
Use ':repeat t' to have all bindings be repeatable or for more
advanced usage:
- ':repeat (:enter (commands ...) :exit (commands ...))'
+ :repeat (:enter (commands ...) :exit (commands ...))
---
** 'kbd' can now be used in built-in, preloaded libraries.
@@ -4473,7 +4522,7 @@ an exact match, then the lowercased '[menu-bar foo\ bar]' and finally
'[menu-bar foo-bar]'. This further improves backwards-compatibility
when converting menus to use 'easy-menu-define'.
-** xwidgets
+** Xwidget
+++
*** The function 'make-xwidget' now accepts an optional RELATED argument.
@@ -4525,7 +4574,7 @@ commits to the load.
+++
*** New event type 'xwidget-display-event'.
-These events are sent whenever an xwidget requests that Emacs display
+These events are sent whenever an xwidget requests that Emacs displays
another xwidget. The only arguments to this event are the xwidget
that should be displayed, and the xwidget that asked to display it.
@@ -4550,10 +4599,10 @@ temporary transition aid for Emacs 27, has served its purpose.
'(encode-time (list SECOND MINUTE HOUR DAY MONTH YEAR nil -1 nil))'.
+++
-** 'date-to-time' now accepts arguments that lacks month, day, or time.
+** 'date-to-time' now accepts arguments that lack month, day, or time.
The function now assumes the earliest possible values if its argument
lacks month, day, or time. For example, (date-to-time "2021-12-04")
-now assumes a time of 00:00 instead of signaling an error.
+now assumes a time of "00:00" instead of signaling an error.
+++
** 'format-seconds' now allows suppressing zero-value trailing elements.
@@ -4562,7 +4611,7 @@ elements that appear after "%x".
+++
** New events for taking advantage of touchscreen devices.
-The events 'touchscreen-begin, 'touchscreen-update', and
+The events 'touchscreen-begin', 'touchscreen-update', and
'touchscreen-end' have been added to take better advantage of
touch-capable display panels.
@@ -4596,7 +4645,7 @@ Use 'indian-tml-itrans-digits-v5-hash' if you want digits
translation.
+++
-** 'shell-quote-argument' has a new optional parameter POSIX.
+** 'shell-quote-argument' has a new optional argument POSIX.
This is useful when quoting shell arguments for a remote shell
invocation. Such shells are POSIX conformant by default.
@@ -4713,7 +4762,7 @@ has built-in support for displaying BMP images.
---
*** GUI Yes/No dialogs now include a "Cancel" button.
The "Cancel" button is in addition to "Yes" and "No", and is intended
-to allow users to quit the dialog, as an equivalent of C-g when Emacs
+to allow users to quit the dialog, as an equivalent of 'C-g' when Emacs
asks a yes/no question via the echo area. This is controlled by the
new variable 'w32-yes-no-dialog-show-cancel', by default t. Set it to
nil to get back the old behavior of showing a modal dialog with only
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index 1b796b11caf..69c42e9bed0 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -628,6 +628,18 @@ To work around the problem, customize the option
'window-adjust-process-window-size-function' to "Do not adjust process
window sizes" (Lisp value 'ignore').
+*** Displaying PDF files in DocView produces an empty buffer.
+
+This can happen if your Emacs is configured to convert PDF to SVG for
+display, and the version of the MuPDF package you have installed has a
+a known bug, whereby it sometimes produces invalid SVG images.
+Version 1.21 of MuPDF is known to be affected.
+
+The solution is either to upgrade or downgrade to a version of MuPDF
+that doesn't have this bug, or to disable conversion of PDF files to
+SVG images by customizing the user option 'doc-view-mupdf-use-svg'.
+Emacs will then convert PDF to PNG images instead.
+
*** In Inferior Python mode, input is echoed and native completion doesn't work.
<https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25753>
diff --git a/etc/refcards/orgcard.tex b/etc/refcards/orgcard.tex
index 04d46756155..093dfceafa7 100644
--- a/etc/refcards/orgcard.tex
+++ b/etc/refcards/orgcard.tex
@@ -1,5 +1,5 @@
% Reference Card for Org Mode
-\def\orgversionnumber{9.6}
+\def\orgversionnumber{9.6.1}
\def\versionyear{2021} % latest update
\input emacsver.tex
diff --git a/lisp/align.el b/lisp/align.el
index 569186d241d..79a75dcec79 100644
--- a/lisp/align.el
+++ b/lisp/align.el
@@ -179,7 +179,8 @@ If nil, then no messages will ever be printed to the minibuffer."
:type '(choice (const :tag "Align a large region silently" nil) integer)
:group 'align)
-(defcustom align-c++-modes '(c++-mode c-mode java-mode)
+(defcustom align-c++-modes '( c++-mode c-mode java-mode
+ c-ts-mode c++-ts-mode)
"A list of modes whose syntax resembles C/C++."
:type '(repeat symbol)
:group 'align)
diff --git a/lisp/apropos.el b/lisp/apropos.el
index b260d889955..5d7fe6962a5 100644
--- a/lisp/apropos.el
+++ b/lisp/apropos.el
@@ -886,6 +886,26 @@ Optional arg BUFFER (default: current buffer) is the buffer to check."
(if (consp pattern) "keywords " "")
pattern))))
+(defun apropos--map-preloaded-atoms (f)
+ "Like `mapatoms' but only enumerates functions&vars that are predefined."
+ (let ((preloaded-regexp
+ (concat "\\`"
+ (regexp-quote lisp-directory)
+ (regexp-opt preloaded-file-list)
+ "\\.elc?\\'")))
+ ;; FIXME: I find this regexp approach brittle. Maybe a better
+ ;; option would be find/record the nthcdr of `load-history' which
+ ;; corresponds to the `load-history' state when we dumped.
+ ;; (Then again, maybe an even better approach would be to record the
+ ;; state of the `obarray' when we dumped, which we may also be able to
+ ;; use in `bytecomp' to provide a clean initial environment?)
+ (dolist (x load-history)
+ (when (string-match preloaded-regexp (car x))
+ (dolist (def (cdr x))
+ (cond
+ ((symbolp def) (funcall f def))
+ ((eq 'defun (car-safe def)) (funcall f (cdr def)))))))))
+
;;;###autoload
(defun apropos-documentation (pattern &optional do-all)
"Show symbols whose documentation contains matches for PATTERN.
@@ -894,10 +914,11 @@ or a regexp (using some regexp special characters). If it is a word,
search for matches for that word as a substring. If it is a list of words,
search for matches for any two (or more) of those words.
-Note that by default this command only searches in the file specified by
-`internal-doc-file-name'; i.e., the etc/DOC file. With \\[universal-argument] prefix,
-or if `apropos-do-all' is non-nil, it searches all currently defined
-documentation strings.
+Note that by default this command only searches in the functions predefined
+at Emacs startup, i.e., the primitives implemented in C or preloaded in the
+Emacs dump image.
+With \\[universal-argument] prefix, or if `apropos-do-all' is non-nil, it searches
+all currently defined documentation strings.
Returns list of symbols and documentation found."
;; The doc used to say that DO-ALL includes key-bindings info in the
@@ -913,33 +934,33 @@ Returns list of symbols and documentation found."
(apropos-sort-by-scores apropos-documentation-sort-by-scores)
f v sf sv)
(apropos-documentation-check-doc-file)
- (if do-all
- (mapatoms
- (lambda (symbol)
- (setq f (apropos-safe-documentation symbol)
- v (get symbol 'variable-documentation))
- (if (integerp v) (setq v nil))
- (setq f (apropos-documentation-internal f)
- v (apropos-documentation-internal v))
- (setq sf (apropos-score-doc f)
- sv (apropos-score-doc v))
- (if (or f v)
- (if (setq apropos-item
- (cdr (assq symbol apropos-accumulator)))
- (progn
- (if f
- (progn
- (setcar (nthcdr 1 apropos-item) f)
- (setcar apropos-item (+ (car apropos-item) sf))))
- (if v
- (progn
- (setcar (nthcdr 2 apropos-item) v)
- (setcar apropos-item (+ (car apropos-item) sv)))))
- (setq apropos-accumulator
- (cons (list symbol
- (+ (apropos-score-symbol symbol 2) sf sv)
- f v)
- apropos-accumulator)))))))
+ (funcall
+ (if do-all #'mapatoms #'apropos--map-preloaded-atoms)
+ (lambda (symbol)
+ (setq f (apropos-safe-documentation symbol)
+ v (get symbol 'variable-documentation))
+ (if (integerp v) (setq v nil))
+ (setq f (apropos-documentation-internal f)
+ v (apropos-documentation-internal v))
+ (setq sf (apropos-score-doc f)
+ sv (apropos-score-doc v))
+ (if (or f v)
+ (if (setq apropos-item
+ (cdr (assq symbol apropos-accumulator)))
+ (progn
+ (if f
+ (progn
+ (setcar (nthcdr 1 apropos-item) f)
+ (setcar apropos-item (+ (car apropos-item) sf))))
+ (if v
+ (progn
+ (setcar (nthcdr 2 apropos-item) v)
+ (setcar apropos-item (+ (car apropos-item) sv)))))
+ (setq apropos-accumulator
+ (cons (list symbol
+ (+ (apropos-score-symbol symbol 2) sf sv)
+ f v)
+ apropos-accumulator))))))
(apropos-print nil "\n----------------\n" nil t))))
@@ -1064,53 +1085,55 @@ non-nil."
(setq apropos-files-scanned (cons file apropos-files-scanned))
(erase-buffer)
(insert-file-contents file)
- (while (search-forward "\n#@" nil t)
+ (while (search-forward "#@" nil t)
;; Read the comment length, and advance over it.
- (setq end (read)
- beg (1+ (point))
- end (+ (point) end -1))
- (forward-char)
- (if (save-restriction
- ;; match ^ and $ relative to doc string
- (narrow-to-region beg end)
- (re-search-forward apropos-all-words-regexp nil t))
- (progn
- (goto-char (+ end 2))
- (setq doc (buffer-substring beg end)
- end (- (match-end 0) beg)
- beg (- (match-beginning 0) beg))
- (when (apropos-true-hit-doc doc)
- (setq this-is-a-variable (looking-at "(def\\(var\\|const\\) ")
- symbol (progn
- (skip-chars-forward "(a-z")
- (forward-char)
- (read))
- symbol (if (consp symbol)
- (nth 1 symbol)
- symbol))
- (if (if this-is-a-variable
- (get symbol 'variable-documentation)
- (and (fboundp symbol) (apropos-safe-documentation symbol)))
- (progn
- (or (and (setq apropos-item (assq symbol apropos-accumulator))
- (setcar (cdr apropos-item)
- (+ (cadr apropos-item) (apropos-score-doc doc))))
- (setq apropos-item (list symbol
- (+ (apropos-score-symbol symbol 2)
- (apropos-score-doc doc))
- nil nil)
- apropos-accumulator (cons apropos-item
- apropos-accumulator)))
- (when apropos-match-face
- (setq doc (substitute-command-keys doc))
- (if (or (string-match apropos-pattern-quoted doc)
- (string-match apropos-all-words-regexp doc))
- (put-text-property (match-beginning 0)
- (match-end 0)
- 'face apropos-match-face doc)))
- (setcar (nthcdr (if this-is-a-variable 3 2)
- apropos-item)
- doc))))))))))
+ ;; This #@ may be a false positive, so don't get upset if
+ ;; it's not followed by the expected number of bytes to skip.
+ (when (and (setq end (ignore-errors (read))) (natnump end))
+ (setq beg (1+ (point))
+ end (+ (point) end -1))
+ (forward-char)
+ (if (save-restriction
+ ;; match ^ and $ relative to doc string
+ (narrow-to-region beg end)
+ (re-search-forward apropos-all-words-regexp nil t))
+ (progn
+ (goto-char (+ end 2))
+ (setq doc (buffer-substring beg end)
+ end (- (match-end 0) beg)
+ beg (- (match-beginning 0) beg))
+ (when (apropos-true-hit-doc doc)
+ (setq this-is-a-variable (looking-at "(def\\(var\\|const\\) ")
+ symbol (progn
+ (skip-chars-forward "(a-z")
+ (forward-char)
+ (read))
+ symbol (if (consp symbol)
+ (nth 1 symbol)
+ symbol))
+ (if (if this-is-a-variable
+ (get symbol 'variable-documentation)
+ (and (fboundp symbol) (apropos-safe-documentation symbol)))
+ (progn
+ (or (and (setq apropos-item (assq symbol apropos-accumulator))
+ (setcar (cdr apropos-item)
+ (+ (cadr apropos-item) (apropos-score-doc doc))))
+ (setq apropos-item (list symbol
+ (+ (apropos-score-symbol symbol 2)
+ (apropos-score-doc doc))
+ nil nil)
+ apropos-accumulator (cons apropos-item
+ apropos-accumulator)))
+ (when apropos-match-face
+ (setq doc (substitute-command-keys doc))
+ (if (or (string-match apropos-pattern-quoted doc)
+ (string-match apropos-all-words-regexp doc))
+ (put-text-property (match-beginning 0)
+ (match-end 0)
+ 'face apropos-match-face doc)))
+ (setcar (nthcdr (if this-is-a-variable 3 2)
+ apropos-item)
+ doc)))))))))))
diff --git a/lisp/calendar/diary-lib.el b/lisp/calendar/diary-lib.el
index b90ed715fae..44fb5eb5a86 100644
--- a/lisp/calendar/diary-lib.el
+++ b/lisp/calendar/diary-lib.el
@@ -880,7 +880,10 @@ LIST-ONLY is non-nil, in which case it just returns the list."
(original-date original-date))
(run-hooks 'diary-hook))))))
(and temp-buff (buffer-name temp-buff) (kill-buffer temp-buff)))
- (or d-incp (message "Preparing diary...done"))
+ (or d-incp
+ ;; Don't clobber messages displayed while preparing the diary.
+ (not (equal (current-message) "Preparing diary..."))
+ (message "Preparing diary...done"))
diary-entries-list)))
(defun diary-unhide-everything ()
diff --git a/lisp/cedet/semantic/symref/grep.el b/lisp/cedet/semantic/symref/grep.el
index c698c2ef5a2..cebeac3adca 100644
--- a/lisp/cedet/semantic/symref/grep.el
+++ b/lisp/cedet/semantic/symref/grep.el
@@ -44,7 +44,9 @@ those hits returned.")
(defvar semantic-symref-filepattern-alist
'((c-mode "*.[ch]")
+ (c-ts-mode "*.[ch]")
(c++-mode "*.[chCH]" "*.[ch]pp" "*.cc" "*.hh")
+ (c++-ts-mode "*.[chCH]" "*.[ch]pp" "*.cc" "*.hh")
(html-mode "*.html" "*.shtml" "*.php")
(mhtml-mode "*.html" "*.shtml" "*.php") ; FIXME: remove
; duplication of
@@ -53,7 +55,10 @@ those hits returned.")
; major mode definition?
(ruby-mode "*.r[bu]" "*.rake" "*.gemspec" "*.erb" "*.haml"
"Rakefile" "Thorfile" "Capfile" "Guardfile" "Vagrantfile")
+ (ruby-ts-mode "*.r[bu]" "*.rake" "*.gemspec" "*.erb" "*.haml"
+ "Rakefile" "Thorfile" "Capfile" "Guardfile" "Vagrantfile")
(python-mode "*.py" "*.pyi" "*.pyw")
+ (python-ts-mode "*.py" "*.pyi" "*.pyw")
(perl-mode "*.pl" "*.PL")
(cperl-mode "*.pl" "*.PL")
(lisp-interaction-mode "*.el" "*.ede" ".emacs" "_emacs")
diff --git a/lisp/char-fold.el b/lisp/char-fold.el
index eff2f5558b3..6da2dae8471 100644
--- a/lisp/char-fold.el
+++ b/lisp/char-fold.el
@@ -436,7 +436,23 @@ specify the character). With no input, i.e. when CHAR is nil,
describe all available character equivalences of `char-fold-to-regexp'.
Optional argument LAX (interactively, the prefix argument), if
non-nil, means also include partially matching ligatures and
-non-canonical equivalences."
+non-canonical equivalences.
+
+Each line of the display shows the equivalences in two different
+ways separated by a colon:
+
+ - as the literal character or sequence
+ - using an ASCII-only escape syntax
+
+For example, for the letter \\='r\\=', the first line is
+
+ r: ?\\N{LATIN SMALL LETTER R}
+
+which is for the requested character itself, and a later line has
+
+ ṟ: ?\\N{LATIN SMALL LETTER R}?\\N{COMBINING MACRON BELOW}
+
+which clearly shows what the constituent characters are."
(interactive (list (ignore-errors
(read-char-by-name
(format-prompt "Unicode name, single char, or hex"
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index 7c272f52fb3..427da557d23 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -209,8 +209,8 @@ are available (see Info node `(emacs)Document View')."
function)
:version "24.4")
-(defcustom doc-view-mupdf-use-svg (image-type-available-p 'svg)
- "Whether to use svg images for PDF files."
+(defcustom doc-view-mupdf-use-svg nil
+ "Whether to use SVG images for PDF files."
:type 'boolean
:version "29.1")
diff --git a/lisp/emacs-lisp/advice.el b/lisp/emacs-lisp/advice.el
index 080a6d84498..56f0ae2212c 100644
--- a/lisp/emacs-lisp/advice.el
+++ b/lisp/emacs-lisp/advice.el
@@ -1850,7 +1850,7 @@ function at point for which PREDICATE returns non-nil)."
ad-advised-functions
(if predicate
(lambda (function)
- (funcall predicate (intern (car function)))))
+ (funcall predicate (intern function))))
t)))
(if (equal function "")
(if (ad-is-advised default)
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 685ab99c26e..43207ce7026 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2810,7 +2810,7 @@ values. Note that this macro is *not* available in Common Lisp.
As a special case, if `(PLACE)' is used instead of `(PLACE VALUE)',
the PLACE is not modified before executing BODY.
-See info node `(cl) Function Bindings' for details.
+See info node `(cl) Modify Macros' for details.
\(fn ((PLACE VALUE) ...) BODY...)"
(declare (indent 1) (debug ((&rest [&or (symbolp form)
diff --git a/lisp/emacs-lisp/ert-x.el b/lisp/emacs-lisp/ert-x.el
index 83705ca5b89..98a017c8a8e 100644
--- a/lisp/emacs-lisp/ert-x.el
+++ b/lisp/emacs-lisp/ert-x.el
@@ -496,7 +496,7 @@ See also `ert-with-temp-directory'."
(progn ,@body)
(ignore-errors
,@(when buffer
- (list `(with-current-buffer buf
+ (list `(with-current-buffer ,buffer
(set-buffer-modified-p nil))
`(kill-buffer ,buffer))))
(ignore-errors
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index ddcfe57928b..33bd0bfd5cd 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -600,10 +600,14 @@ PKG-SPEC is a package specification, a property list describing
how to fetch and build the package. See `package-vc--archive-spec-alist'
for details. The optional argument REV specifies a specific revision to
checkout. This overrides the `:branch' attribute in PKG-SPEC."
+ (unless pkg-desc
+ (setq pkg-desc (package-desc-create :name (car pkg-spec) :kind 'vc)))
(pcase-let* (((map :lisp-dir) pkg-spec)
(name (package-desc-name pkg-desc))
(dirname (package-desc-full-name pkg-desc))
(pkg-dir (expand-file-name dirname package-user-dir)))
+ (when (string-empty-p name)
+ (user-error "Empty package name"))
(setf (package-desc-dir pkg-desc) pkg-dir)
(when (file-exists-p pkg-dir)
(if (yes-or-no-p (format "Overwrite previous checkout for package `%s'?" name))
@@ -771,7 +775,9 @@ regular package, but it will not remove a VC package.
(package-vc--archives-initialize)
(let* ((name-or-url (package-vc--read-package-name
"Fetch and install package: " t))
- (name (file-name-base name-or-url)))
+ (name (file-name-base (directory-file-name name-or-url))))
+ (when (string-empty-p name)
+ (user-error "Empty package name"))
(list name-or-url
(and current-prefix-arg :last-release)
nil
diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el
index ebda37419f7..e6e3cd6c6f4 100644
--- a/lisp/emacs-lisp/pp.el
+++ b/lisp/emacs-lisp/pp.el
@@ -47,7 +47,9 @@ Otherwise this should be a number."
(defcustom pp-use-max-width nil
"If non-nil, `pp'-related functions will try to fold lines.
-The target width is given by the `pp-max-width' variable."
+The target width is given by the `pp-max-width' variable.
+Note that this could slow down `pp' considerably when formatting
+large lists."
:type 'boolean
:version "29.1")
@@ -162,14 +164,15 @@ Also add the value to the front of the list in the variable `values'."
(message "Evaluating...")
(let ((result (eval expression lexical-binding)))
(values--store-value result)
- (pp-display-expression result "*Pp Eval Output*")))
+ (pp-display-expression result "*Pp Eval Output*" pp-use-max-width)))
;;;###autoload
(defun pp-macroexpand-expression (expression)
"Macroexpand EXPRESSION and pretty-print its value."
(interactive
(list (read--expression "Macroexpand: ")))
- (pp-display-expression (macroexpand-1 expression) "*Pp Macroexpand Output*"))
+ (pp-display-expression (macroexpand-1 expression) "*Pp Macroexpand Output*"
+ pp-use-max-width))
(defun pp-last-sexp ()
"Read sexp before point. Ignore leading comment characters."
@@ -219,7 +222,8 @@ Ignores leading comment characters."
;;;###autoload
(defun pp-emacs-lisp-code (sexp)
"Insert SEXP into the current buffer, formatted as Emacs Lisp code.
-Use the `pp-max-width' variable to control the desired line length."
+Use the `pp-max-width' variable to control the desired line length.
+Note that this could be slow for large SEXPs."
(require 'edebug)
(let ((obuf (current-buffer)))
(with-temp-buffer
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."
some-match))
(define-icon warnings-suppress button
- '((emoji "⛔")
- (symbol " ■ ")
+ `((emoji "⛔")
+ ;; Many MS-Windows console fonts don't have good glyphs for U+25A0.
+ (symbol ,(if (and (eq system-type 'windows-nt)
+ (null window-system))
+ " » "
+ " ■ "))
(text " stop "))
"Suppress warnings."
: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.
(,disable)))
,(erc--assemble-toggle local-p name enable mode t enable-body)
,(erc--assemble-toggle local-p name disable mode nil disable-body)
- ,(when (and alias (not (eq name alias)))
- `(defalias
- ',(intern
- (format "erc-%s-mode"
- (downcase (symbol-name alias))))
- #',mode))
+ ,@(and-let* ((alias)
+ ((not (eq name alias)))
+ (aname (intern (format "erc-%s-mode"
+ (downcase (symbol-name alias))))))
+ `((defalias ',aname #',mode)
+ (put ',aname 'erc-module ',(erc--normalize-module-symbol name))))
+ (put ',mode 'erc-module ',(erc--normalize-module-symbol name))
;; For find-function and find-variable.
(put ',mode 'definition-name ',name)
(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."
(dolist (e rv out)
(when-let* ((s (plist-get e :secret))
(v (auth-source--obfuscate s)))
- (setf (plist-get e :secret)
- (apply-partially #'auth-source--deobfuscate v)))
+ (setq e (plist-put e :secret (apply-partially
+ #'auth-source--deobfuscate v))))
(push e out)))
rv)))
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el
index 4044be08f92..95fd8990c99 100644
--- a/lisp/erc/erc-networks.el
+++ b/lisp/erc/erc-networks.el
@@ -1366,6 +1366,11 @@ ANNOUNCED is the server's reported host name."
erc-server-connected t
erc-networks--id nid))))))
+(defvar erc-networks--copy-server-buffer-functions nil
+ "Abnormal hook run in new server buffers when deduping.
+Passed the existing buffer to be killed, whose contents have
+already been copied over to the current, replacement buffer.")
+
(defun erc-networks--copy-over-server-buffer-contents (existing name)
"Kill off existing server buffer after copying its contents.
Must be called from the replacement buffer."
@@ -1386,6 +1391,7 @@ Must be called from the replacement buffer."
erc-kill-server-hook
erc-kill-buffer-hook)
(erc-networks--insert-transplanted-content text)
+ (run-hook-with-args 'erc-networks--copy-server-buffer-functions existing)
(kill-buffer name)))
;; This stands alone for testing purposes
diff --git a/lisp/erc/erc-track.el b/lisp/erc/erc-track.el
index 61c0c66abfb..7fd7b53602e 100644
--- a/lisp/erc/erc-track.el
+++ b/lisp/erc/erc-track.el
@@ -521,7 +521,9 @@ keybindings will not do anything useful."
(add-hook 'erc-disconnected-hook #'erc-modified-channels-update))
;; enable the tracking keybindings
(add-hook 'erc-connect-pre-hook #'erc-track-minor-mode-maybe)
- (erc-track-minor-mode-maybe)))
+ (erc-track-minor-mode-maybe))
+ (add-hook 'erc-networks--copy-server-buffer-functions
+ #'erc-track--replace-killed-buffer))
;; Disable:
((when (boundp 'erc-track-when-inactive)
(erc-track-remove-from-mode-line)
@@ -539,7 +541,9 @@ keybindings will not do anything useful."
;; disable the tracking keybindings
(remove-hook 'erc-connect-pre-hook #'erc-track-minor-mode-maybe)
(when erc-track-minor-mode
- (erc-track-minor-mode -1)))))
+ (erc-track-minor-mode -1)))
+ (remove-hook 'erc-networks--copy-server-buffer-functions
+ #'erc-track--replace-killed-buffer)))
(defcustom erc-track-when-inactive nil
"Enable channel tracking even for visible buffers, if you are inactive."
@@ -942,6 +946,10 @@ reverse it."
(interactive "p")
(erc-track--switch-buffer 'switch-to-buffer-other-window arg))
+(defun erc-track--replace-killed-buffer (existing)
+ (when-let ((found (assq existing erc-modified-channels-alist)))
+ (setcar found (current-buffer))))
+
(provide 'erc-track)
;;; erc-track.el ends here
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 6315d5aa482..ff1820cfaf2 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -61,7 +61,6 @@
(load "erc-loaddefs" 'noerror 'nomessage)
(require 'erc-networks)
-(require 'erc-goodies)
(require 'erc-backend)
(require 'cl-lib)
(require 'format-spec)
@@ -323,7 +322,8 @@ A typical value would be \((\"Libera.Chat\" \"MODE\")
\(\"OFTC\" \"JOIN\" \"QUIT\"))."
:version "25.1"
:group 'erc-ignore
- :type 'erc-message-type)
+ :type '(alist :key-type string :value-type erc-message-type
+ :options ("Libera.Chat")))
(defcustom erc-channel-hide-list nil
"A list of IRC channels to hide message types from.
@@ -331,7 +331,8 @@ A typical value would be \((\"#emacs\" \"QUIT\" \"JOIN\")
\(\"#erc\" \"NICK\")."
:version "25.1"
:group 'erc-ignore
- :type 'erc-message-type)
+ :type '(alist :key-type string :value-type erc-message-type
+ :options ("#emacs")))
(defcustom erc-disconnected-hook nil
"Run this hook with arguments (NICK IP REASON) when disconnected.
@@ -1303,6 +1304,14 @@ See also `erc-show-my-nick'."
(defvar-local erc-dbuf nil)
+;; See comments in `erc-scenarios-base-local-modules' explaining why
+;; this is insufficient as a public interface.
+
+(defvar erc--target-priors nil
+ "Analogous to `erc--server-reconnecting' but for target buffers.
+Bound to local variables from an existing (logical) session's
+buffer during local-module setup and `erc-mode-hook' activation.")
+
(defun erc--target-from-string (string)
"Construct an `erc--target' variant from STRING."
(funcall (if (erc-channel-p string)
@@ -1948,7 +1957,8 @@ nil."
(let ((out (list (reverse new-modes))))
(pcase-dolist (`(,k . ,v) old-vars)
(when (and (string-prefix-p "erc-" (symbol-name k))
- (string-suffix-p "-mode" (symbol-name k)))
+ (string-suffix-p "-mode" (symbol-name k))
+ (get k 'erc-module))
(if v
(cl-pushnew k (car out))
(setf (car out) (delq k (car out)))
@@ -1983,7 +1993,9 @@ Returns the buffer for the given server or channel."
(let* ((target (and channel (erc--target-from-string channel)))
(buffer (erc-get-buffer-create server port nil target id))
(old-buffer (current-buffer))
- (old-vars (and target (buffer-local-variables)))
+ (erc--target-priors (and target ; buf from prior session
+ (buffer-local-value 'erc--target buffer)
+ (buffer-local-variables buffer)))
(old-recon-count erc-server-reconnect-count)
(old-point nil)
(delayed-modules nil)
@@ -1996,7 +2008,8 @@ Returns the buffer for the given server or channel."
(setq old-point (point))
(setq delayed-modules
(erc--merge-local-modes (erc--update-modules)
- (or erc--server-reconnecting old-vars)))
+ (or erc--server-reconnecting
+ erc--target-priors)))
(delay-mode-hooks (erc-mode))
@@ -2069,9 +2082,7 @@ Returns the buffer for the given server or channel."
(erc-determine-parameters server port nick full-name user passwd)
- (save-excursion (run-mode-hooks))
- (dolist (mod (car delayed-modules)) (funcall mod +1))
- (dolist (var (cdr delayed-modules)) (set var nil))
+ ;; FIXME consolidate this prompt-setup logic with the pass above.
;; set up prompt
(unless continued-session
@@ -2084,6 +2095,10 @@ Returns the buffer for the given server or channel."
(erc-display-prompt)
(goto-char (point-max)))
+ (save-excursion (run-mode-hooks)
+ (dolist (mod (car delayed-modules)) (funcall mod +1))
+ (dolist (var (cdr delayed-modules)) (set var nil)))
+
;; Saving log file on exit
(run-hook-with-args 'erc-connect-pre-hook buffer)
@@ -7370,4 +7385,6 @@ Customize `erc-url-connect-function' to override this."
(provide 'erc)
+;; FIXME this is a temporary stopgap for Emacs 29.
+(require 'erc-goodies)
;;; erc.el ends here
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."
;; bug#27361.
(when (equal output-newline '(nil))
(display-warning
- :warning "To terminate with a newline, you should use -N instead."))
+ '(eshell echo)
+ "To terminate with a newline, you should use -N instead."))
(eshell-echo args output-newline))))
(defun eshell/printnl (&rest args)
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el
index df1413c2de7..dfc52083acb 100644
--- a/lisp/eshell/esh-var.el
+++ b/lisp/eshell/esh-var.el
@@ -613,9 +613,10 @@ If QUOTED is non-nil, this was invoked inside double-quotes."
(if (or (eq max-arity 'many) (>= max-arity 2))
(funcall target indices quoted)
(display-warning
- :warning (concat "Function for `eshell-variable-aliases-list' "
- "entry should accept two arguments: INDICES "
- "and QUOTED.'"))
+ '(eshell variable-alias)
+ (concat "Function for `eshell-variable-aliases-list' "
+ "entry should accept two arguments: INDICES "
+ "and QUOTED.'"))
(funcall target indices)))))
((symbolp target)
(eshell-apply-indices (symbol-value target) indices quoted))
diff --git a/lisp/files.el b/lisp/files.el
index c45c3d40a5d..0d24852358e 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
redefine it.
If the optional argument KEEP-BACKUP-VERSION is non-nil,
we do not remove backup version numbers, only true file version numbers.
-See also `file-name-version-regexp'."
+See `file-name-version-regexp' for what constitutes backup versions
+and version strings."
(let ((handler (find-file-name-handler name 'file-name-sans-versions)))
(if handler
(funcall handler 'file-name-sans-versions name keep-backup-version)
@@ -5111,9 +5112,12 @@ the group would be preserved too."
(file-attribute-group-id attributes)))))))))))
(defun file-name-sans-extension (filename)
- "Return FILENAME sans final \"extension\".
+ "Return FILENAME sans final \"extension\" and any backup version strings.
The extension, in a file name, is the part that begins with the last `.',
-except that a leading `.' of the file name, if there is one, doesn't count."
+except that a leading `.' of the file name, if there is one, doesn't count.
+Any extensions that indicate backup versions and version strings are
+removed by calling `file-name-sans-versions', which see, before looking
+for the \"real\" file extension."
(save-match-data
(let ((file (file-name-sans-versions (file-name-nondirectory filename)))
directory)
@@ -5127,12 +5131,14 @@ except that a leading `.' of the file name, if there is one, doesn't count."
filename))))
(defun file-name-extension (filename &optional period)
- "Return FILENAME's final \"extension\".
+ "Return FILENAME's final \"extension\" sans any backup version strings.
The extension, in a file name, is the part that begins with the last `.',
-excluding version numbers and backup suffixes, except that a leading `.'
-of the file name, if there is one, doesn't count.
+except that a leading `.' of the file name, if there is one, doesn't count.
+This function calls `file-name-sans-versions', which see, to remove from
+the extension it returns any parts that indicate backup versions and
+version strings.
Return nil for extensionless file names such as `foo'.
-Return the empty string for file names such as `foo.'.
+Return the empty string for file names such as `foo.' that end in a period.
By default, the returned value excludes the period that starts the
extension, but if the optional argument PERIOD is non-nil, the period
@@ -7419,9 +7425,9 @@ files, you could say something like:
(\"src/emacs/[^/]+/\\\\(.*\\\\)\\\\\\='\" \"src/emacs/.*/\\\\1\\\\\\='\")
-In this example, if you're in src/emacs/emacs-27/lisp/abbrev.el,
-and you an src/emacs/emacs-28/lisp/abbrev.el file exists, it's
-now defined as a sibling."
+In this example, if you're in \"src/emacs/emacs-27/lisp/abbrev.el\",
+and a \"src/emacs/emacs-28/lisp/abbrev.el\" file exists, it's now
+defined as a sibling."
:type 'sexp
:version "29.1")
@@ -7674,9 +7680,12 @@ regardless of the language.")
(defvar insert-directory-ls-version 'unknown)
(defun insert-directory-wildcard-in-dir-p (dir)
- "Return non-nil if DIR contents a shell wildcard in the directory part.
-The return value is a cons (DIR . WILDCARDS); DIR is the
-`default-directory' in the Dired buffer, and WILDCARDS are the wildcards.
+ "Return non-nil if DIR contains shell wildcards in its parent directory part.
+The return value is a cons (DIRECTORY . WILDCARD), where DIRECTORY is the
+part of DIR up to and excluding the first component that includes
+wildcard characters, and WILDCARD is the rest of DIR's components. The
+DIRECTORY part of the value includes the trailing slash, to indicate that
+it is a directory.
Valid wildcards are `*', `?', `[abc]' and `[a-z]'."
(let ((wildcards "[?*"))
diff --git a/lisp/find-dired.el b/lisp/find-dired.el
index 83bdaba5352..33376ee4ed9 100644
--- a/lisp/find-dired.el
+++ b/lisp/find-dired.el
@@ -177,7 +177,9 @@ using GNU findutils (on macOS and *BSD systems), see instead the
man page for \"find\"."
(interactive (list (read-directory-name "Run find in directory: " nil "" t)
(read-string "Run find (with args): " find-args
- '(find-args-history . 1))))
+ (if find-args
+ '(find-args-history . 1)
+ 'find-args-history))))
(setq find-args args ; save for next interactive call
args (concat find-program " . "
(if (string= args "")
@@ -209,7 +211,7 @@ it finishes, type \\[kill-find]."
" . \\( \\) "
(find-dired--escaped-ls-option))
(+ 1 (length find-program) (length " . \\( ")))
- find-command-history)))
+ 'find-command-history)))
(let ((dired-buffers dired-buffers))
;; Expand DIR ("" means default-directory), and make sure it has a
;; trailing slash.
diff --git a/lisp/font-lock.el b/lisp/font-lock.el
index 74881a14ccf..1fa45379b9f 100644
--- a/lisp/font-lock.el
+++ b/lisp/font-lock.el
@@ -1183,7 +1183,7 @@ This function is the default `font-lock-fontify-region-function'."
(setq font-lock-syntactically-fontified end))
(font-lock-fontify-syntactic-keywords-region start end)))
(unless font-lock-keywords-only
- (funcall font-lock-fontify-syntactically-function beg end loudly))
+ (font-lock-fontify-syntactically-region beg end loudly))
(font-lock-fontify-keywords-region beg end loudly)
`(jit-lock-bounds ,beg . ,end))))
@@ -1531,6 +1531,12 @@ START should be at the beginning of a line."
(defvar font-lock-comment-end-skip nil
"If non-nil, Font Lock mode uses this instead of `comment-end-skip'.")
+(defun font-lock-fontify-syntactically-region (beg end &optional loudly)
+ "Syntactically fontify the text between BEG and END.
+If LOUDLY is non-nil, print status messages while fontifying.
+This works by calling `font-lock-fontify-syntactically-function'."
+ (funcall font-lock-fontify-syntactically-function beg end loudly))
+
(defun font-lock-default-fontify-syntactically (start end &optional loudly)
"Put proper face on each string and comment between START and END.
START should be at the beginning of a line."
@@ -2073,6 +2079,12 @@ as the constructs of Haddock, Javadoc and similar systems."
"Font Lock mode face used to highlight preprocessor directives."
:group 'font-lock-faces)
+(defface font-lock-regexp-face
+ '((t :inherit font-lock-string-face))
+ "Font Lock mode face used to highlight regexp literals."
+ :group 'font-lock-faces
+ :version "29.1")
+
(defface font-lock-regexp-grouping-backslash
'((t :inherit bold))
"Font Lock mode face for backslashes in Lisp regexp grouping constructs."
@@ -2363,7 +2375,6 @@ in which C preprocessor directives are used, e.g. `asm-mode' and
(define-obsolete-function-alias 'font-lock-after-fontify-buffer #'ignore "29.1")
(define-obsolete-function-alias 'font-lock-after-unfontify-buffer #'ignore "29.1")
-(define-obsolete-function-alias 'font-lock-fontify-syntactically-region #'font-lock-default-fontify-syntactically "29.1")
(provide 'font-lock)
diff --git a/lisp/frame.el b/lisp/frame.el
index 9c3fa9ae4bb..af95a047c38 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -2189,7 +2189,7 @@ frame's display)."
This means that, for example, DISPLAY can differentiate between
the keybinding RET and [return]."
(let ((frame-type (framep-on-display display)))
- (or (memq frame-type '(x w32 ns pc pgtk))
+ (or (memq frame-type '(x w32 ns pc pgtk haiku))
;; MS-DOS and MS-Windows terminals have built-in support for
;; function (symbol) keys
(memq system-type '(ms-dos windows-nt)))))
diff --git a/lisp/htmlfontify.el b/lisp/htmlfontify.el
index c989a12d205..1ab33cc6411 100644
--- a/lisp/htmlfontify.el
+++ b/lisp/htmlfontify.el
@@ -78,7 +78,7 @@
;;; Code:
-(eval-when-compile (require 'cl-lib))
+(require 'cl-lib)
(require 'cus-edit)
(defconst hfy-meta-tags
@@ -372,11 +372,15 @@ otherwise."
:tag "istext-command"
:type '(string))
-(defcustom hfy-find-cmd
- "find . -type f \\! -name \\*~ \\! -name \\*.flc \\! -path \\*/CVS/\\*"
- "Find command used to harvest a list of files to attempt to fontify."
- :tag "find-command"
- :type '(string))
+(defcustom hfy-exclude-file-rules
+ '("\\.flc\\'"
+ "/CVS/"
+ "~\\'"
+ "/\\.git\\(?:/\\|\\'\\)")
+ "Regular expressions matching files to exclude."
+ :tag "exclude-rules"
+ :type '(repeat regexp)
+ :version "29.1")
(defcustom hfy-display-class nil
"Display class to use to determine which display class to use when
@@ -1826,8 +1830,12 @@ Strips any leading \"./\" from each filename."
;;(message "hfy-list-files");;DBUG
;; FIXME: this changes the dir of the current buffer. Is that right??
(cd directory)
- (mapcar (lambda (F) (if (string-match "^./\\(.*\\)" F) (match-string 1 F) F))
- (split-string (shell-command-to-string hfy-find-cmd))) )
+ (cl-remove-if (lambda (f)
+ (or (null (file-regular-p f))
+ (seq-some (lambda (r)
+ (string-match r f))
+ hfy-exclude-file-rules)))
+ (directory-files-recursively "." "" nil t)))
;; strip the filename off, return a directory name
;; not a particularly thorough implementation, but it will be
diff --git a/lisp/icomplete.el b/lisp/icomplete.el
index 9fa622017f7..014f38b2024 100644
--- a/lisp/icomplete.el
+++ b/lisp/icomplete.el
@@ -252,7 +252,7 @@ the default otherwise."
"Step forward completions by one entry.
Second entry becomes the first and can be selected with
`icomplete-force-complete-and-exit'.
-Return non-nil iff something was stepped."
+Return non-nil if something was stepped."
(interactive)
(let* ((beg (icomplete--field-beg))
(end (icomplete--field-end))
@@ -270,7 +270,7 @@ Return non-nil iff something was stepped."
"Step backward completions by one entry.
Last entry becomes the first and can be selected with
`icomplete-force-complete-and-exit'.
-Return non-nil iff something was stepped."
+Return non-nil if something was stepped."
(interactive)
(let* ((beg (icomplete--field-beg))
(end (icomplete--field-end))
diff --git a/lisp/international/mule.el b/lisp/international/mule.el
index 4f6addea387..52019697ad7 100644
--- a/lisp/international/mule.el
+++ b/lisp/international/mule.el
@@ -863,7 +863,8 @@ This attribute is meaningful only when `:coding-type' is `utf-16' or
VALUE must be `big' or `little' specifying big-endian and
little-endian respectively. The default value is `big'.
-This attribute is meaningful only when `:coding-type' is `utf-16'.
+Changing this attribute is only meaningful when `:coding-type'
+is `utf-16'.
`:ccl-decoder' (required if :coding-type is `ccl')
@@ -2539,6 +2540,10 @@ This function is intended to be added to `auto-coding-functions'."
(bfcs-type
(coding-system-type buffer-file-coding-system)))
(if (and enable-multibyte-characters
+ ;; 'charset' will signal an error in
+ ;; coding-system-equal, since it isn't a
+ ;; coding-system. So test that up front.
+ (not (equal sym-type 'charset))
(coding-system-equal 'utf-8 sym-type)
(coding-system-equal 'utf-8 bfcs-type))
buffer-file-coding-system
diff --git a/lisp/keymap.el b/lisp/keymap.el
index 315eaab7560..791221f2459 100644
--- a/lisp/keymap.el
+++ b/lisp/keymap.el
@@ -186,10 +186,17 @@ a menu, so this function is not useful for non-menu keymaps."
(declare (indent defun)
(compiler-macro (lambda (form) (keymap--compile-check key) form)))
(keymap--check key)
- (when after
- (keymap--check after))
+ (when (eq after t) (setq after nil)) ; nil and t are treated the same
+ (when (stringp after)
+ (keymap--check after)
+ (setq after (key-parse after)))
+ ;; If we're binding this key to another key, then parse that other
+ ;; key, too.
+ (when (stringp definition)
+ (keymap--check definition)
+ (setq definition (key-parse definition)))
(define-key-after keymap (key-parse key) definition
- (and after (key-parse after))))
+ after))
(defun key-parse (keys)
"Convert KEYS to the internal Emacs key representation.
@@ -404,7 +411,7 @@ specified buffer position instead of point are used."
(symbolp value))
(or (command-remapping value) value)
value))
- (key-binding (kbd key) accept-default no-remap position)))
+ (key-binding (key-parse key) accept-default no-remap position)))
(defun keymap-local-lookup (keys &optional accept-default)
"Return the binding for command KEYS in current local keymap only.
diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el
index bad13e9bb9f..a463a7da67e 100644
--- a/lisp/ldefs-boot.el
+++ b/lisp/ldefs-boot.el
@@ -1079,10 +1079,11 @@ or a regexp (using some regexp special characters). If it is a word,
search for matches for that word as a substring. If it is a list of words,
search for matches for any two (or more) of those words.
-Note that by default this command only searches in the file specified by
-`internal-doc-file-name'; i.e., the etc/DOC file. With \\[universal-argument] prefix,
-or if `apropos-do-all' is non-nil, it searches all currently defined
-documentation strings.
+Note that by default this command only searches in the functions predefined
+at Emacs startup, i.e., the primitives implemented in C or preloaded in the
+Emacs dump image.
+With \\[universal-argument] prefix, or if `apropos-do-all' is non-nil, it searches
+all currently defined documentation strings.
Returns list of symbols and documentation found.
@@ -2929,10 +2930,18 @@ Major mode for editing C, powered by tree-sitter.
(autoload 'c-ts-mode "c-ts-mode" "\
Major mode for editing C, powered by tree-sitter.
+This mode is independent from the classic cc-mode.el based
+`c-mode', so configuration variables of that mode, like
+`c-basic-offset', don't affect this mode.
+
(fn)" t)
(autoload 'c++-ts-mode "c-ts-mode" "\
Major mode for editing C++, powered by tree-sitter.
+This mode is independent from the classic cc-mode.el based
+`c++-mode', so configuration variables of that mode, like
+`c-basic-offset', don't affect this mode.
+
(fn)" t)
(register-definition-prefixes "c-ts-mode" '("c-ts-mode-"))
@@ -4114,6 +4123,22 @@ Optional argument LAX (interactively, the prefix argument), if
non-nil, means also include partially matching ligatures and
non-canonical equivalences.
+Each line of the display shows the equivalences in two different
+ways separated by a colon:
+
+ - as the literal character or sequence
+ - using an ASCII-only escape syntax
+
+For example, for the letter \\='r\\=', the first line is
+
+ r: ?\\N{LATIN SMALL LETTER R}
+
+which is for the requested character itself, and a later line has
+
+ ṟ: ?\\N{LATIN SMALL LETTER R}?\\N{COMBINING MACRON BELOW}
+
+which clearly shows what the constituent characters are.
+
(fn CHAR &optional LAX)" t)
(register-definition-prefixes "char-fold" '("char-fold-"))
@@ -22325,7 +22350,7 @@ Coloring:
;;; Generated autoloads from org/org.el
-(push (purecopy '(org 9 6)) package--builtin-versions)
+(push (purecopy '(org 9 6 1)) package--builtin-versions)
(autoload 'org-babel-do-load-languages "org" "\
Load the languages defined in `org-babel-load-languages'.
@@ -24504,6 +24529,7 @@ Ignores leading comment characters.
(autoload 'pp-emacs-lisp-code "pp" "\
Insert SEXP into the current buffer, formatted as Emacs Lisp code.
Use the `pp-max-width' variable to control the desired line length.
+Note that this could be slow for large SEXPs.
(fn SEXP)")
(register-definition-prefixes "pp" '("pp-"))
@@ -25090,7 +25116,7 @@ Open profile FILENAME.
;;; Generated autoloads from progmodes/project.el
-(push (purecopy '(project 0 9 3)) package--builtin-versions)
+(push (purecopy '(project 0 9 4)) package--builtin-versions)
(autoload 'project-current "project" "\
Return the project instance in DIRECTORY, defaulting to `default-directory'.
@@ -27313,6 +27339,13 @@ it is disabled.
;;; Generated autoloads from progmodes/ruby-mode.el
(push (purecopy '(ruby-mode 1 2)) package--builtin-versions)
+(autoload 'ruby-base-mode "ruby-mode" "\
+Generic major mode for editing Ruby.
+
+This mode is intended to be inherited by concrete major modes.
+Currently there are `ruby-mode' and `ruby-ts-mode'.
+
+(fn)" t)
(autoload 'ruby-mode "ruby-mode" "\
Major mode for editing Ruby code.
@@ -27322,6 +27355,15 @@ Major mode for editing Ruby code.
(register-definition-prefixes "ruby-mode" '("ruby-"))
+;;; Generated autoloads from progmodes/ruby-ts-mode.el
+
+(autoload 'ruby-ts-mode "ruby-ts-mode" "\
+Major mode for editing Ruby, powered by tree-sitter.
+
+(fn)" t)
+(register-definition-prefixes "ruby-ts-mode" '("ruby-ts-"))
+
+
;;; Generated autoloads from ruler-mode.el
(defvar-local ruler-mode nil "\
@@ -32414,7 +32456,6 @@ Mode for displaying and reprioritizing top priority Todo.
;;; Generated autoloads from textmodes/toml-ts-mode.el
-(add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode))
(autoload 'toml-ts-mode "toml-ts-mode" "\
Major mode for editing TOML, powered by tree-sitter.
@@ -32802,6 +32843,21 @@ See info node `(transient)Modifying Existing Transients'.
;;; Generated autoloads from treesit.el
+(autoload 'treesit-install-language-grammar "treesit" "\
+Build and install the tree-sitter language grammar library for LANG.
+
+Interactively, if `treesit-language-source-alist' doesn't already
+have data for building the grammar for LANG, prompt for its
+repository URL and the C/C++ compiler to use.
+
+This command requires Git, a C compiler and (sometimes) a C++ compiler,
+and the linker to be installed and on PATH. It also requires that the
+recipe for LANG exists in `treesit-language-source-alist'.
+
+See `exec-path' for the current path where Emacs looks for
+executable programs, such as the C/C++ compiler and linker.
+
+(fn LANG)" t)
(register-definition-prefixes "treesit" '("treesit-"))
@@ -36777,7 +36833,7 @@ If LIMIT is non-nil, then do not consider characters beyond LIMIT.
;;; Generated autoloads from progmodes/xref.el
-(push (purecopy '(xref 1 6 0)) package--builtin-versions)
+(push (purecopy '(xref 1 6 1)) package--builtin-versions)
(autoload 'xref-find-backend "xref")
(define-obsolete-function-alias 'xref-pop-marker-stack #'xref-go-back "29.1")
(autoload 'xref-go-back "xref" "\
diff --git a/lisp/ls-lisp.el b/lisp/ls-lisp.el
index 217bebcfcb2..81ff14932c6 100644
--- a/lisp/ls-lisp.el
+++ b/lisp/ls-lisp.el
@@ -482,8 +482,22 @@ not contain `d', so that a full listing is expected."
(if (not dir-wildcard)
(funcall orig-fun dir-or-list switches)
(let* ((default-directory (car dir-wildcard))
- (files (file-expand-wildcards (cdr dir-wildcard)))
+ (wildcard (cdr dir-wildcard))
+ (files (file-expand-wildcards wildcard))
(dir (car dir-wildcard)))
+ ;; When the wildcard ends in a slash, file-expand-wildcards
+ ;; returns nil; fix that by treating the wildcards as
+ ;; specifying only directories whose names match the
+ ;; widlcard.
+ (if (and (null files)
+ (directory-name-p wildcard))
+ (setq files
+ (delq nil
+ (mapcar (lambda (fname)
+ (if (file-accessible-directory-p fname)
+ fname))
+ (file-expand-wildcards
+ (directory-file-name wildcard))))))
(if files
(let ((inhibit-read-only t)
(buf
@@ -494,7 +508,7 @@ not contain `d', so that a full listing is expected."
(dired-goto-next-file)
(forward-line 0)
(insert " wildcard " (cdr dir-wildcard) "\n"))))
- (user-error "No files matching regexp")))))))
+ (user-error "No files matching wildcard")))))))
(advice-add 'dired :around #'ls-lisp--dired)
diff --git a/lisp/mh-e/mh-e.el b/lisp/mh-e/mh-e.el
index 1640c23e002..34c809a5ecd 100644
--- a/lisp/mh-e/mh-e.el
+++ b/lisp/mh-e/mh-e.el
@@ -764,6 +764,8 @@ This assumes that a temporary buffer is set up."
;; Sample '-version' outputs:
;; mhparam -- nmh-1.1-RC1 [compiled on chaak at Fri Jun 20 11:03:28 PDT 2003]
;; install-mh -- nmh-1.7.1 built October 26, 2019 on build-server-000
+ ;; "libdir" was deprecated in nmh-1.7 in favor of "libexecdir", and
+ ;; removed completely in nmh-1.8.
(let ((install-mh (expand-file-name "install-mh" dir)))
(when (mh-file-command-p install-mh)
(erase-buffer)
@@ -774,7 +776,8 @@ This assumes that a temporary buffer is set up."
(mh-progs dir))
`(,version
(variant nmh)
- (mh-lib-progs ,(mh-profile-component "libdir"))
+ (mh-lib-progs ,(or (mh-profile-component "libdir")
+ (mh-profile-component "libexecdir")))
(mh-lib ,(mh-profile-component "etcdir"))
(mh-progs ,dir)
(flists ,(file-exists-p
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index f47299bd0da..21d4607e7cf 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -986,7 +986,7 @@ already visible.
If the value is `visible', the *Completions* buffer is displayed
whenever completion is requested but cannot be done for the first time,
but remains visible thereafter, and the list of completions in it is
-updated for subsequent attempts to complete.."
+updated for subsequent attempts to complete."
:type '(choice (const :tag "Don't show" nil)
(const :tag "Show only when cannot complete" t)
(const :tag "Show after second failed completion attempt" lazy)
diff --git a/lisp/net/sieve-manage.el b/lisp/net/sieve-manage.el
index 5bee4f4c4ad..4866f788bff 100644
--- a/lisp/net/sieve-manage.el
+++ b/lisp/net/sieve-manage.el
@@ -168,19 +168,25 @@ Valid states are `closed', `initial', `nonauth', and `auth'.")
;; Internal utility functions
(defun sieve-manage--append-to-log (&rest args)
- "Append ARGS to sieve-manage log buffer.
+ "Append ARGS to `sieve-manage-log' buffer.
ARGS can be a string or a list of strings.
-The buffer to use for logging is specifified via
-`sieve-manage-log'. If it is nil, logging is disabled."
+The buffer to use for logging is specifified via `sieve-manage-log'.
+If it is nil, logging is disabled.
+
+When the `sieve-manage-log' buffer doesn't exist, it gets created (and
+configured with some initial settings)."
(when sieve-manage-log
- (with-current-buffer (or (get-buffer sieve-manage-log)
- (with-current-buffer
- (get-buffer-create sieve-manage-log)
- (set-buffer-multibyte nil)
- (buffer-disable-undo)))
- (goto-char (point-max))
- (apply #'insert args))))
+ (let* ((existing-log-buffer (get-buffer sieve-manage-log))
+ (log-buffer (or existing-log-buffer
+ (get-buffer-create sieve-manage-log))))
+ (with-current-buffer log-buffer
+ (unless existing-log-buffer
+ ;; Do this only once, when creating the log buffer.
+ (set-buffer-multibyte nil)
+ (buffer-disable-undo))
+ (goto-char (point-max))
+ (apply #'insert args)))))
(defun sieve-manage--message (format-string &rest args)
"Wrapper around `message' which also logs to sieve manage log.
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 61a606c3383..123d01c747d 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -4031,9 +4031,15 @@ Let-bind it when necessary.")
"Like `file-regular-p' for Tramp files."
(and (file-exists-p filename)
;; Sometimes, `file-attributes' does not return a proper value
- ;; even if `file-exists-p' does.
- (when-let ((attr (file-attributes filename)))
- (eq ?- (aref (file-attribute-modes attr) 0)))))
+ ;; even if `file-exists-p' does. Protect by `ignore-errors',
+ ;; because `file-truename' could raise an error for cyclic
+ ;; symlinks.
+ (ignore-errors
+ (when-let ((attr (file-attributes filename)))
+ (cond
+ ((eq ?- (aref (file-attribute-modes attr) 0)))
+ ((eq ?l (aref (file-attribute-modes attr) 0))
+ (file-regular-p (file-truename filename))))))))
(defun tramp-handle-file-remote-p (filename &optional identification connected)
"Like `file-remote-p' for Tramp files."
@@ -4694,7 +4700,8 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.")
(or
;; The host name is used for the remote shell command.
(member
- '("%h") (tramp-get-method-parameter item 'tramp-login-args))
+ "%h" (tramp-compat-flatten-tree
+ (tramp-get-method-parameter item 'tramp-login-args)))
;; The host name must match previous hop.
(string-match-p previous-host host))
(setq tramp-default-proxies-alist saved-tdpa)
diff --git a/lisp/org/ob-core.el b/lisp/org/ob-core.el
index 9bb77f7920b..3f6696fce77 100644
--- a/lisp/org/ob-core.el
+++ b/lisp/org/ob-core.el
@@ -1690,6 +1690,7 @@ shown below.
(append
(split-string (if (stringp raw-result)
raw-result
+ ;; FIXME: Arbitrary code evaluation.
(eval raw-result t)))
(cdr (assq :result-params params))))))
(append
@@ -2860,6 +2861,7 @@ parameters when merging lists."
(split-string
(cond ((stringp value) value)
((functionp value) (funcall value))
+ ;; FIXME: Arbitrary code evaluation.
(t (eval value t)))))))
(`(:exports . ,value)
(setq exports (funcall merge
@@ -3188,16 +3190,8 @@ situations in which is it not appropriate."
((and (not inhibit-lisp-eval)
(or (memq (string-to-char cell) '(?\( ?' ?` ?\[))
(string= cell "*this*")))
- ;; Prevent arbitrary function calls.
- (if (and (memq (string-to-char cell) '(?\( ?`))
- (not (org-babel-confirm-evaluate
- ;; See `org-babel-get-src-block-info'.
- (list "emacs-lisp" cell
- '((:eval . yes)) nil (format "%s" cell)
- nil nil))))
- ;; Not allowed.
- (user-error "Evaluation of elisp code %S aborted." cell)
- (eval (read cell) t)))
+ ;; FIXME: Arbitrary code evaluation.
+ (eval (read cell) t))
((save-match-data
(and (string-match "^[[:space:]]*\"\\(.*\\)\"[[:space:]]*$" cell)
(not (string-match "[^\\]\"" (match-string 1 cell)))))
@@ -3283,7 +3277,7 @@ Emacs shutdown.")
(while (or (not dir) (file-exists-p dir))
(setq dir (expand-file-name
(format "babel-stable-%d" (random 1000))
- (temporary-file-directory))))
+ temporary-file-directory)))
(make-directory dir)
dir))
"Directory to hold temporary files created to execute code blocks.
diff --git a/lisp/org/ob-ruby.el b/lisp/org/ob-ruby.el
index 03c94b1ba99..b94bc73dd79 100644
--- a/lisp/org/ob-ruby.el
+++ b/lisp/org/ob-ruby.el
@@ -29,11 +29,10 @@
;; - ruby and irb executables :: https://www.ruby-lang.org/
;;
-;; - ruby-mode :: Can be installed through ELPA, or from
-;; https://github.com/eschulte/rinari/raw/master/util/ruby-mode.el
+;; - ruby-mode :: Comes with Emacs.
;;
;; - inf-ruby mode :: Can be installed through ELPA, or from
-;; https://github.com/eschulte/rinari/raw/master/util/inf-ruby.el
+;; https://raw.githubusercontent.com/nonsequitur/inf-ruby/master/inf-ruby.el
;;; Code:
diff --git a/lisp/org/ob-shell.el b/lisp/org/ob-shell.el
index 4a60186cd5d..2c30a26056b 100644
--- a/lisp/org/ob-shell.el
+++ b/lisp/org/ob-shell.el
@@ -79,7 +79,7 @@ is modified outside the Customize interface."
,(format "Execute a block of %s commands with Babel." name)
(let ((shell-file-name ,name)
(org-babel-prompt-command
- (or (alist-get ,name org-babel-shell-set-prompt-commands)
+ (or (cdr (assoc ,name org-babel-shell-set-prompt-commands))
(alist-get t org-babel-shell-set-prompt-commands))))
(org-babel-execute:shell body params))))
(eval `(defalias ',(intern (concat "org-babel-variable-assignments:" name))
diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el
index 66b08adf535..2d194ad3413 100644
--- a/lisp/org/org-agenda.el
+++ b/lisp/org/org-agenda.el
@@ -54,6 +54,7 @@
(require 'org)
(require 'org-macs)
(require 'org-refile)
+(require 'org-element)
(declare-function diary-add-to-list "diary-lib"
(date string specifier &optional marker globcolor literal))
@@ -80,11 +81,6 @@
(declare-function org-columns-quit "org-colview" ())
(declare-function diary-date-display-form "diary-lib" (&optional type))
(declare-function org-mobile-write-agenda-for-mobile "org-mobile" (file))
-(declare-function org-element-property "org-element" (property element))
-(declare-function org-element--cache-active-p "org-element"
- (&optional called-from-cache-change-func-p))
-(declare-function org-element-lineage "org-element"
- (datum &optional types with-self))
(declare-function org-habit-insert-consistency-graphs
"org-habit" (&optional line))
(declare-function org-is-habit-p "org-habit" (&optional pom))
@@ -95,8 +91,6 @@
(declare-function org-capture "org-capture" (&optional goto keys))
(declare-function org-clock-modify-effort-estimate "org-clock" (&optional value))
-(declare-function org-element-type "org-element" (&optional element))
-
(defvar calendar-mode-map)
(defvar org-clock-current-task)
(defvar org-current-tag-alist)
@@ -1184,7 +1178,9 @@ Custom commands can set this variable in the options section."
"Non-nil means start the overview always on the specified weekday.
0 denotes Sunday, 1 denotes Monday, etc.
When nil, always start on the current day.
-Custom commands can set this variable in the options section."
+Custom commands can set this variable in the options section.
+
+This variable only applies when agenda spans either 7 or 14 days."
:group 'org-agenda-daily/weekly
:type '(choice (const :tag "Today" nil)
(integer :tag "Weekday No.")))
@@ -4357,7 +4353,10 @@ This check for agenda markers in all agenda buffers currently active."
Custom commands can set this variable in the options section.
This is usually a string like \"2007-11-01\", \"+2d\" or any other
input allowed when reading a date through the Org calendar.
-See the docstring of `org-read-date' for details.")
+See the docstring of `org-read-date' for details.
+
+This variable has no effect when `org-agenda-start-on-weekday' is set
+and agenda spans 7 or 14 days.")
(defvar org-starting-day nil) ; local variable in the agenda buffer
(defvar org-arg-loc nil) ; local variable
diff --git a/lisp/org/org-clock.el b/lisp/org/org-clock.el
index 4e72141cdc9..55372e5649b 100644
--- a/lisp/org/org-clock.el
+++ b/lisp/org/org-clock.el
@@ -1800,17 +1800,25 @@ Optional argument N tells to change by that many units."
(time-subtract
(org-time-string-to-time org-last-changed-timestamp)
(org-time-string-to-time ts)))
- (save-excursion
- (goto-char begts)
- (org-timestamp-change
- (round (/ (float-time tdiff)
- (pcase timestamp?
- (`minute 60)
- (`hour 3600)
- (`day (* 24 3600))
- (`month (* 24 3600 31))
- (`year (* 24 3600 365.2)))))
- timestamp? 'updown)))))))
+ ;; `save-excursion' won't work because
+ ;; `org-timestamp-change' deletes and re-inserts the
+ ;; timestamp.
+ (let ((origin (point)))
+ (save-excursion
+ (goto-char begts)
+ (org-timestamp-change
+ (round (/ (float-time tdiff)
+ (pcase timestamp?
+ (`minute 60)
+ (`hour 3600)
+ (`day (* 24 3600))
+ (`month (* 24 3600 31))
+ (`year (* 24 3600 365.2)))))
+ timestamp? 'updown))
+ ;; Move back to initial position, but never beyond updated
+ ;; clock.
+ (unless (< (point) origin)
+ (goto-char origin))))))))
;;;###autoload
(defun org-clock-cancel ()
diff --git a/lisp/org/org-element.el b/lisp/org/org-element.el
index f787fb1f713..389acf82500 100644
--- a/lisp/org/org-element.el
+++ b/lisp/org/org-element.el
@@ -2382,7 +2382,9 @@ Assume point is at the beginning of the fixed-width area."
(defun org-element-fixed-width-interpreter (fixed-width _)
"Interpret FIXED-WIDTH element as Org syntax."
(let ((value (org-element-property :value fixed-width)))
- (and value (replace-regexp-in-string "^" ": " value))))
+ (and value
+ (if (string-empty-p value) ":\n"
+ (replace-regexp-in-string "^" ": " value)))))
;;;; Horizontal Rule
diff --git a/lisp/org/org-fold-core.el b/lisp/org/org-fold-core.el
index 0855e6f39ce..027ff921581 100644
--- a/lisp/org/org-fold-core.el
+++ b/lisp/org/org-fold-core.el
@@ -1003,7 +1003,13 @@ If SPEC-OR-ALIAS is omitted and FLAG is nil, unfold everything in the region."
(overlay-put o (org-fold-core--property-symbol-get-create spec) spec)
(overlay-put o 'invisible spec)
(overlay-put o 'isearch-open-invisible #'org-fold-core--isearch-show)
- (overlay-put o 'isearch-open-invisible-temporary #'org-fold-core--isearch-show-temporary))
+ ;; FIXME: Disabling to work around Emacs bug#60399
+ ;; and https://orgmode.org/list/87zgb6tk6h.fsf@localhost.
+ ;; The proper fix will require making sure that
+ ;; `org-fold-core-isearch-open-function' does not
+ ;; delete the overlays used by isearch.
+ ;; (overlay-put o 'isearch-open-invisible-temporary #'org-fold-core--isearch-show-temporary)
+ )
(put-text-property from to (org-fold-core--property-symbol-get-create spec) spec)
(put-text-property from to 'isearch-open-invisible #'org-fold-core--isearch-show)
(put-text-property from to 'isearch-open-invisible-temporary #'org-fold-core--isearch-show-temporary)
@@ -1131,16 +1137,9 @@ This function is intended to be used as `isearch-filter-predicate'."
"Clear `org-fold-core--isearch-local-regions'."
(clrhash org-fold-core--isearch-local-regions))
-(defun org-fold-core--isearch-show (region)
- "Reveal text in REGION found by isearch.
-REGION can also be an overlay in current buffer."
- (when (overlayp region)
- (setq region (cons (overlay-start region)
- (overlay-end region))))
- (org-with-point-at (car region)
- (while (< (point) (cdr region))
- (funcall org-fold-core-isearch-open-function (car region))
- (goto-char (org-fold-core-next-visibility-change (point) (cdr region) 'ignore-hidden)))))
+(defun org-fold-core--isearch-show (_)
+ "Reveal text at point found by isearch."
+ (funcall org-fold-core-isearch-open-function (point)))
(defun org-fold-core--isearch-show-temporary (region hide-p)
"Temporarily reveal text in REGION.
diff --git a/lisp/org/org-macs.el b/lisp/org/org-macs.el
index 72929cdd26c..07c668a807d 100644
--- a/lisp/org/org-macs.el
+++ b/lisp/org/org-macs.el
@@ -372,18 +372,23 @@ be set to a buffer or a buffer name. `shell-command' then uses
it for output."
(let* ((base-name (file-name-base source))
(full-name (file-truename source))
- (out-dir (or (file-name-directory source) "./"))
+ (relative-name (file-relative-name source))
+ (out-dir (if (file-name-directory source)
+ ;; Expand "~". Shell expansion will be disabled
+ ;; in the shell command call.
+ (file-name-directory full-name)
+ "./"))
(output (expand-file-name (concat base-name "." ext) out-dir))
(time (file-attribute-modification-time (file-attributes output)))
(err-msg (if (stringp err-msg) (concat ". " err-msg) "")))
(save-window-excursion
(pcase process
- ((pred functionp) (funcall process (shell-quote-argument source)))
+ ((pred functionp) (funcall process (shell-quote-argument relative-name)))
((pred consp)
(let ((log-buf (and log-buf (get-buffer-create log-buf)))
(spec (append spec
`((?b . ,(shell-quote-argument base-name))
- (?f . ,(shell-quote-argument source))
+ (?f . ,(shell-quote-argument relative-name))
(?F . ,(shell-quote-argument full-name))
(?o . ,(shell-quote-argument out-dir))
(?O . ,(shell-quote-argument output))))))
diff --git a/lisp/org/org-mouse.el b/lisp/org/org-mouse.el
index 6a733f09db7..3b2c4cba624 100644
--- a/lisp/org/org-mouse.el
+++ b/lisp/org/org-mouse.el
@@ -241,7 +241,7 @@ return `:middle'."
(t :middle)))
(defun org-mouse-empty-line ()
- "Return non-nil iff the line contains only white space."
+ "Return non-nil if the line contains only white space."
(save-excursion (beginning-of-line) (looking-at "[ \t]*$")))
(defun org-mouse-next-heading ()
@@ -283,7 +283,7 @@ keyword as the only argument.
If SELECTED is nil, then all items are normal menu items. If
SELECTED is a function, then each item is a checkbox, which is
-enabled for a given keyword iff (funcall SELECTED keyword) return
+enabled for a given keyword if (funcall SELECTED keyword) return
non-nil. If SELECTED is neither nil nor a function, then the
items are radio buttons. A radio button is enabled for the
keyword `equal' to SELECTED.
diff --git a/lisp/org/org-persist.el b/lisp/org/org-persist.el
index c3650c167e2..a0652b99c56 100644
--- a/lisp/org/org-persist.el
+++ b/lisp/org/org-persist.el
@@ -160,6 +160,8 @@
(declare-function org-next-visible-heading "org" (arg))
(declare-function org-at-heading-p "org" (&optional invisible-not-ok))
+;; Silence byte-compiler (used in `org-persist--write-elisp-file').
+(defvar pp-use-max-width)
(defconst org-persist--storage-version "3.1"
"Persistent storage layout version.")
@@ -335,7 +337,8 @@ FORMAT and ARGS are passed to `message'."
(make-directory (file-name-directory file) t))
(with-temp-file file
(if pp
- (pp data (current-buffer))
+ (let ((pp-use-max-width nil)) ; Emacs bug#58687
+ (pp data (current-buffer)))
(prin1 data (current-buffer))))
(org-persist--display-time
(- (float-time) start-time)
@@ -753,12 +756,12 @@ with `org-persist-write'."
When ASSOCIATED is `all', unregister CONTAINER everywhere."
(unless org-persist--index (org-persist--load-index))
(setq container (org-persist--normalize-container container))
- (setq associated (org-persist--normalize-associated associated))
(if (eq associated 'all)
(mapc (lambda (collection)
(when (member container (plist-get collection :container))
(org-persist-unregister container (plist-get collection :associated))))
org-persist--index)
+ (setq associated (org-persist--normalize-associated associated))
(let ((collection (org-persist--find-index `(:container ,container :associated ,associated))))
(when collection
(if (= (length (plist-get collection :container)) 1)
diff --git a/lisp/org/org-table.el b/lisp/org/org-table.el
index 06cf919db76..5116b1127f7 100644
--- a/lisp/org/org-table.el
+++ b/lisp/org/org-table.el
@@ -1229,7 +1229,7 @@ Return t when the line exists, nil if it does not exist."
(if (looking-at "|[^|\n]+")
(let* ((pos (match-beginning 0))
(match (match-string 0))
- (len (org-string-width match)))
+ (len (save-match-data (org-string-width match))))
(replace-match (concat "|" (make-string (1- len) ?\ )))
(goto-char (+ 2 pos))
(substring match 1)))))
@@ -1725,8 +1725,12 @@ In particular, this does handle wide and invisible characters."
(setq s (mapconcat (lambda (x) (if (member x '(?| ?+)) "|" " ")) s ""))
(while (string-match "|\\([ \t]*?[^ \t\r\n|][^\r\n|]*\\)|" s)
(setq s (replace-match
- (concat "|" (make-string (org-string-width (match-string 1 s))
- ?\ ) "|")
+ (concat "|"
+ (make-string
+ (save-match-data
+ (org-string-width (match-string 1 s)))
+ ?\ )
+ "|")
t t s)))
s))
@@ -2614,6 +2618,7 @@ location of point."
(if lispp
(setq ev (condition-case nil
+ ;; FIXME: Arbitrary code evaluation.
(eval (eval (read form)))
(error "#ERROR"))
ev (if (numberp ev) (number-to-string ev) ev)
diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el
index dd6d92d8e58..22f952d7a30 100644
--- a/lisp/org/org-version.el
+++ b/lisp/org/org-version.el
@@ -5,13 +5,13 @@
(defun org-release ()
"The release version of Org.
Inserted by installing Org mode or when a release is made."
- (let ((org-release "9.6"))
+ (let ((org-release "9.6.1"))
org-release))
;;;###autoload
(defun org-git-version ()
"The Git version of Org mode.
Inserted by installing Org or when a release is made."
- (let ((org-git-version "release_9.6-81-g563a43"))
+ (let ((org-git-version "release_9.6.1-16-ge37e9b"))
org-git-version))
(provide 'org-version)
diff --git a/lisp/org/org.el b/lisp/org/org.el
index 21764f3d434..153e860f9a5 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -7,9 +7,9 @@
;; Maintainer: Bastien Guerry <bzg@gnu.org>
;; Keywords: outlines, hypermedia, calendar, wp
;; URL: https://orgmode.org
-;; Package-Requires: ((emacs "25.1"))
+;; Package-Requires: ((emacs "26.1"))
-;; Version: 9.6
+;; Version: 9.6.1
;; This file is part of GNU Emacs.
;;
@@ -4898,16 +4898,20 @@ The following commands are available:
(= (point-min) (point-max)))
(insert "# -*- mode: org -*-\n\n"))
(unless org-inhibit-startup
+ (when (or org-startup-align-all-tables org-startup-shrink-all-tables)
+ (org-table-map-tables
+ (cond ((and org-startup-align-all-tables
+ org-startup-shrink-all-tables)
+ (lambda () (org-table-align) (org-table-shrink)))
+ (org-startup-align-all-tables #'org-table-align)
+ (t #'org-table-shrink))
+ t))
+ ;; Suppress modification hooks to speed up the startup.
+ ;; However, do it only when text properties/overlays, but not
+ ;; buffer text are actually modified. We still need to track text
+ ;; modifications to make cache updates work reliably.
(org-unmodified
(when org-startup-with-beamer-mode (org-beamer-mode))
- (when (or org-startup-align-all-tables org-startup-shrink-all-tables)
- (org-table-map-tables
- (cond ((and org-startup-align-all-tables
- org-startup-shrink-all-tables)
- (lambda () (org-table-align) (org-table-shrink)))
- (org-startup-align-all-tables #'org-table-align)
- (t #'org-table-shrink))
- t))
(when org-startup-with-inline-images (org-display-inline-images))
(when org-startup-with-latex-preview (org-latex-preview '(16)))
(unless org-inhibit-startup-visibility-stuff (org-cycle-set-startup-visibility))
@@ -8855,7 +8859,7 @@ keywords relative to each registered export back-end."
"EXCLUDE_TAGS:" "FILETAGS:" "INCLUDE:" "INDEX:" "KEYWORDS:" "LANGUAGE:"
"MACRO:" "OPTIONS:" "PROPERTY:" "PRINT_BIBLIOGRAPHY" "PRIORITIES:"
"SELECT_TAGS:" "SEQ_TODO:" "SETUPFILE:" "STARTUP:" "TAGS:" "TITLE:" "TODO:"
- "TYP_TODO:" "SELECT_TAGS:" "EXCLUDE_TAGS:"))
+ "TYP_TODO:" "SELECT_TAGS:" "EXCLUDE_TAGS:" "EXPORT_FILE_NAME:"))
(defcustom org-structure-template-alist
'(("a" . "export ascii")
diff --git a/lisp/org/ox-odt.el b/lisp/org/ox-odt.el
index 1c233a266a1..949c8f9b5b2 100644
--- a/lisp/org/ox-odt.el
+++ b/lisp/org/ox-odt.el
@@ -2935,7 +2935,7 @@ contextual information."
(trailing (and (string-match (rx (1+ blank) eos) output)
(match-string 0 output))))
;; Unfill, retaining leading/trailing space.
- (let ((fill-column (point-max)))
+ (let ((fill-column most-positive-fixnum))
(fill-region (point-min) (point-max)))
(concat leading (buffer-string) trailing))))))
;; Return value.
diff --git a/lisp/org/ox.el b/lisp/org/ox.el
index 62fc8d583e4..65f9ff18279 100644
--- a/lisp/org/ox.el
+++ b/lisp/org/ox.el
@@ -3040,7 +3040,7 @@ Return code as a string."
;; This way, we will be able to retrieve its export
;; options when calling
;; `org-export--get-subtree-options'.
- (backward-char)
+ (when (bolp) (backward-char))
(narrow-to-region (point) (point-max))))
;; Initialize communication channel with original buffer
;; attributes, unavailable in its copy.
@@ -6407,7 +6407,7 @@ them."
("nb" :default "Innhold")
("nn" :default "Innhald")
("pl" :html "Spis tre&#x015b;ci")
- ("pt_BR" :html "&Iacute;ndice" :utf8 "Índice" :ascii "Indice")
+ ("pt_BR" :html "&Iacute;ndice" :utf-8 "Índice" :ascii "Indice")
("ro" :default "Cuprins")
("ru" :html "&#1057;&#1086;&#1076;&#1077;&#1088;&#1078;&#1072;&#1085;&#1080;&#1077;"
:utf-8 "Содержание")
@@ -6757,7 +6757,6 @@ Return file name as a string."
(cond
(pub-dir (concat (file-name-as-directory pub-dir)
(file-name-nondirectory base-name)))
- ((file-name-absolute-p base-name) base-name)
(t base-name))))
;; If writing to OUTPUT-FILE would overwrite original file, append
;; EXTENSION another time to final name.
diff --git a/lisp/outline.el b/lisp/outline.el
index 91f6040687b..0bfda8388ed 100644
--- a/lisp/outline.el
+++ b/lisp/outline.el
@@ -209,8 +209,14 @@ This option is only in effect when `outline-minor-mode-cycle' is non-nil."
:version "28.1")
(defvar outline-minor-mode-cycle)
+(defvar outline-minor-mode-cycle-map)
(defun outline-minor-mode-cycle--bind (map key binding &optional filter)
- (define-key map key
+ "Define KEY as BINDING in MAP using FILTER.
+The key takes effect only on the following conditions:
+`outline-minor-mode-cycle' is non-nil, point is located on the heading line,
+FILTER or `outline-minor-mode-cycle-filter' is nil or returns non-nil.
+The argument MAP is optional and defaults to `outline-minor-mode-cycle-map'."
+ (define-key (or map outline-minor-mode-cycle-map) key
`(menu-item
"" ,binding
;; Filter out specific positions on the heading.
@@ -227,8 +233,16 @@ This option is only in effect when `outline-minor-mode-cycle' is non-nil."
(let ((map (make-sparse-keymap)))
(outline-minor-mode-cycle--bind map (kbd "TAB") #'outline-cycle)
(outline-minor-mode-cycle--bind map (kbd "<backtab>") #'outline-cycle-buffer)
+ (keymap-set map "<left-margin> <mouse-1>" 'outline-cycle)
+ (keymap-set map "<right-margin> <mouse-1>" 'outline-cycle)
+ (keymap-set map "<left-margin> S-<mouse-1>" 'outline-cycle-buffer)
+ (keymap-set map "<right-margin> S-<mouse-1>" 'outline-cycle-buffer)
map)
- "Keymap used by `outline-minor-mode-cycle'.")
+ "Keymap used as a parent of the `outline-minor-mode' keymap.
+It contains key bindings that can be used to cycle visibility.
+The recommended way to bind keys is with `outline-minor-mode-cycle--bind'
+when the key should be enabled only when `outline-minor-mode-cycle' is
+non-nil and point is located on the heading line.")
(defvar outline-mode-map
(let ((map (make-sparse-keymap)))
@@ -518,10 +532,6 @@ See the command `outline-mode' for more information on this mode."
:keymap (define-keymap
:parent outline-minor-mode-cycle-map
"<menu-bar>" outline-minor-mode-menu-bar-map
- "<left-margin> <mouse-1>" 'outline-cycle
- "<right-margin> <mouse-1>" 'outline-cycle
- "<left-margin> S-<mouse-1>" 'outline-cycle-buffer
- "<right-margin> S-<mouse-1>" 'outline-cycle-buffer
(key-description outline-minor-mode-prefix) outline-mode-prefix-map)
(if outline-minor-mode
(progn
diff --git a/lisp/pcomplete.el b/lisp/pcomplete.el
index 5bee5152463..1ca7a213361 100644
--- a/lisp/pcomplete.el
+++ b/lisp/pcomplete.el
@@ -632,6 +632,13 @@ This will modify the current buffer."
;;; Internal Functions:
;; argument handling
+(defsubst pcomplete-actual-arg (&optional index offset)
+ "Return the actual text representation of the last argument.
+This is different from `pcomplete-arg', which returns the textual value
+that the last argument evaluated to. This function returns what the
+user actually typed in."
+ (buffer-substring (pcomplete-begin index offset) (point)))
+
(defun pcomplete-arg (&optional index offset)
"Return the textual content of the INDEXth argument.
INDEX is based from the current processing position. If INDEX is
@@ -659,11 +666,20 @@ the pcomplete-arg-value text property of that string."
(_ (- pcomplete-index (or index 0))))
(or offset 0))
pcomplete-args)))
- (if (stringp arg)
+ (if (or (stringp arg)
+ ;; FIXME: 'last' is handled specially in Emacs 29, because
+ ;; 'pcomplete-parse-arguments' accepts a list of strings
+ ;; (which are completion candidates) as return value for
+ ;; (pcomplete-arg 'last). See below: "it means it's a
+ ;; list of completions computed during parsing,
+ ;; e.g. Eshell uses that to turn globs into lists of
+ ;; completions". This special case will be dealt with
+ ;; differently in Emacs 30: the pcomplete-arg-value
+ ;; property will be used by 'pcomplete-parse-arguments'.
+ (eq index 'last))
arg
(propertize
- (buffer-substring (pcomplete-begin index offset)
- (pcomplete-begin (1- (or index 0)) offset))
+ (car (split-string (pcomplete-actual-arg index offset)))
'pcomplete-arg-value arg))))
(defun pcomplete-begin (&optional index offset)
@@ -679,13 +695,6 @@ See the documentation for `pcomplete-arg'."
(setq index (+ index offset)))
(nth index pcomplete-begins))
-(defsubst pcomplete-actual-arg (&optional index offset)
- "Return the actual text representation of the last argument.
-This is different from `pcomplete-arg', which returns the textual value
-that the last argument evaluated to. This function returns what the
-user actually typed in."
- (buffer-substring (pcomplete-begin index offset) (point)))
-
(defsubst pcomplete-next-arg ()
"Move the various pointers to the next argument."
(setq pcomplete-index (1+ pcomplete-index)
diff --git a/lisp/progmodes/c-ts-common.el b/lisp/progmodes/c-ts-common.el
new file mode 100644
index 00000000000..6671d4be5b6
--- /dev/null
+++ b/lisp/progmodes/c-ts-common.el
@@ -0,0 +1,247 @@
+;;; c-ts-common.el --- Utilities for C like Languages -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; Author : 付禹安 (Yuan Fu) <casouri@gmail.com>
+;; Keywords : c c++ java javascript rust languages tree-sitter
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; For C-like language major modes:
+;;
+;; - Use `c-ts-common-comment-setup' to setup comment variables and
+;; filling.
+;;
+;; - Use simple-indent matcher `c-ts-common-looking-at-star' and
+;; anchor `c-ts-common-comment-start-after-first-star' for indenting
+;; block comments. See `c-ts-mode--indent-styles' for example.
+
+;;; Code:
+
+(require 'treesit)
+(eval-when-compile (require 'rx))
+
+(declare-function treesit-node-start "treesit.c")
+(declare-function treesit-node-end "treesit.c")
+(declare-function treesit-node-type "treesit.c")
+
+(defun c-ts-common-looking-at-star (_n _p bol &rest _)
+ "A tree-sitter simple indent matcher.
+Matches if there is a \"*\" after BOL."
+ (eq (char-after bol) ?*))
+
+(defun c-ts-common-comment-start-after-first-star (_n parent &rest _)
+ "A tree-sitter simple indent anchor.
+Finds the \"/*\" and returns the point after the \"*\".
+Assumes PARENT is a comment node."
+ (save-excursion
+ (goto-char (treesit-node-start parent))
+ (if (looking-at (rx "/*"))
+ (match-end 0)
+ (point))))
+
+(defun c-ts-common-comment-2nd-line-matcher (_n parent &rest _)
+ "Matches if point is at the second line of a block comment.
+PARENT should be a comment node."
+ (and (equal (treesit-node-type parent) "comment")
+ (save-excursion
+ (forward-line -1)
+ (back-to-indentation)
+ (eq (point) (treesit-node-start parent)))))
+
+(defun c-ts-common-comment-2nd-line-anchor (_n _p bol &rest _)
+ "Return appropriate anchor for the second line of a comment.
+
+If the first line is /* alone, return the position right after
+the star; if the first line is /* followed by some text, return
+the position right before the text minus 1.
+
+Use an offset of 1 with this anchor. BOL is the beginning of
+non-whitespace characters of the current line."
+ (save-excursion
+ (forward-line -1)
+ (back-to-indentation)
+ (when (looking-at comment-start-skip)
+ (goto-char (match-end 0))
+ (if (looking-at (rx (* (or " " "\t")) eol))
+ ;; Only /* at the first line.
+ (progn (skip-chars-backward " \t")
+ (if (save-excursion
+ (goto-char bol)
+ (looking-at (rx "*")))
+ ;; The common case. Checked by "Multiline Block
+ ;; Comments 4".
+ (point)
+ ;; The "Multiline Block Comments 2" test in
+ ;; c-ts-common-resources/indent.erts checks this.
+ (1- (point))))
+ ;; There is something after /* at the first line. The
+ ;; "Multiline Block Comments 3" test checks this.
+ (1- (point))))))
+
+(defvar c-ts-common--comment-regexp
+ ;; These covers C/C++, Java, JavaScript, TypeScript, Rust, C#.
+ (rx (or "comment" "line_comment" "block_comment"))
+ "Regexp pattern that matches a comment in C-like languages.")
+
+(defun c-ts-common--fill-paragraph (&optional arg)
+ "Fillling function for `c-ts-common'.
+ARG is passed to `fill-paragraph'."
+ (interactive "*P")
+ (save-restriction
+ (widen)
+ (let ((node (treesit-node-at (point))))
+ (when (string-match-p c-ts-common--comment-regexp
+ (treesit-node-type node))
+ (if (save-excursion
+ (goto-char (treesit-node-start node))
+ (looking-at "//"))
+ (fill-comment-paragraph arg)
+ (c-ts-common--fill-block-comment arg)))
+ ;; Return t so `fill-paragraph' doesn't attempt to fill by
+ ;; itself.
+ t)))
+
+(defun c-ts-common--fill-block-comment (&optional arg)
+ "Fillling function for block comments.
+ARG is passed to `fill-paragraph'. Assume point is in a block
+comment."
+ (let* ((node (treesit-node-at (point)))
+ (start (treesit-node-start node))
+ (end (treesit-node-end node))
+ ;; Bind to nil to avoid infinite recursion.
+ (fill-paragraph-function nil)
+ (orig-point (point-marker))
+ (start-marker (point-marker))
+ (end-marker nil)
+ (end-len 0))
+ (move-marker start-marker start)
+ ;; We mask "/*" and the space before "*/" like
+ ;; `c-fill-paragraph' does.
+ (atomic-change-group
+ ;; Mask "/*".
+ (goto-char start)
+ (when (looking-at (rx (* (syntax whitespace))
+ (group "/") "*"))
+ (goto-char (match-beginning 1))
+ (move-marker start-marker (point))
+ (replace-match " " nil nil nil 1))
+ ;; Include whitespaces before /*.
+ (goto-char start)
+ (beginning-of-line)
+ (setq start (point))
+ ;; Mask spaces before "*/" if it is attached at the end
+ ;; of a sentence rather than on its own line.
+ (goto-char end)
+ (when (looking-back (rx (not (syntax whitespace))
+ (group (+ (syntax whitespace)))
+ "*/")
+ (line-beginning-position))
+ (goto-char (match-beginning 1))
+ (setq end-marker (point-marker))
+ (setq end-len (- (match-end 1) (match-beginning 1)))
+ (replace-match (make-string end-len ?x)
+ nil nil nil 1))
+ ;; If "*/" is on its own line, don't included it in the
+ ;; filling region.
+ (when (not end-marker)
+ (goto-char end)
+ (when (looking-back (rx "*/") 2)
+ (backward-char 2)
+ (skip-syntax-backward "-")
+ (setq end (point))))
+ ;; Let `fill-paragraph' do its thing.
+ (goto-char orig-point)
+ (narrow-to-region start end)
+ ;; We don't want to fill the region between START and
+ ;; START-MARKER, otherwise the filling function might delete
+ ;; some spaces there.
+ (fill-region start-marker end arg)
+ ;; Unmask.
+ (when start-marker
+ (goto-char start-marker)
+ (delete-char 1)
+ (insert "/"))
+ (when end-marker
+ (goto-char end-marker)
+ (delete-region (point) (+ end-len (point)))
+ (insert (make-string end-len ?\s))))))
+
+(defun c-ts-common-comment-setup ()
+ "Set up local variables for C-like comment.
+
+Set up:
+ - `comment-start'
+ - `comment-end'
+ - `comment-start-skip'
+ - `comment-end-skip'
+ - `adaptive-fill-mode'
+ - `adaptive-fill-first-line-regexp'
+ - `paragraph-start'
+ - `paragraph-separate'
+ - `fill-paragraph-function'"
+ (setq-local comment-start "// ")
+ (setq-local comment-end "")
+ (setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
+ (seq "/" (+ "*")))
+ (* (syntax whitespace))))
+ (setq-local comment-end-skip
+ (rx (* (syntax whitespace))
+ (group (or (syntax comment-end)
+ (seq (+ "*") "/")))))
+ (setq-local adaptive-fill-mode t)
+ ;; This matches (1) empty spaces (the default), (2) "//", (3) "*",
+ ;; but do not match "/*", because we don't want to use "/*" as
+ ;; prefix when filling. (Actually, it doesn't matter, because
+ ;; `comment-start-skip' matches "/*" which will cause
+ ;; `fill-context-prefix' to use "/*" as a prefix for filling, that's
+ ;; why we mask the "/*" in `c-ts-common--fill-paragraph'.)
+ (setq-local adaptive-fill-regexp
+ (concat (rx (* (syntax whitespace))
+ (group (or (seq "/" (+ "/")) (* "*"))))
+ adaptive-fill-regexp))
+ ;; Note the missing * comparing to `adaptive-fill-regexp'. The
+ ;; reason for its absence is a bit convoluted to explain. Suffice
+ ;; to say that without it, filling a single line paragraph that
+ ;; starts with /* doesn't insert * at the beginning of each
+ ;; following line, and filling a multi-line paragraph whose first
+ ;; two lines start with * does insert * at the beginning of each
+ ;; following line. If you know how does adaptive filling works, you
+ ;; know what I mean.
+ (setq-local adaptive-fill-first-line-regexp
+ (rx bos
+ (seq (* (syntax whitespace))
+ (group (seq "/" (+ "/")))
+ (* (syntax whitespace)))
+ eos))
+ ;; Same as `adaptive-fill-regexp'.
+ (setq-local paragraph-start
+ (rx (or (seq (* (syntax whitespace))
+ (group (or (seq "/" (+ "/")) (* "*")))
+ (* (syntax whitespace))
+ ;; Add this eol so that in
+ ;; `fill-context-prefix', `paragraph-start'
+ ;; doesn't match the prefix.
+ eol)
+ "\f")))
+ (setq-local paragraph-separate paragraph-start)
+ (setq-local fill-paragraph-function #'c-ts-common--fill-paragraph))
+
+(provide 'c-ts-common)
+
+;;; c-ts-common.el ends here
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 1f2a195bf64..95f9001e0d7 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -24,14 +24,58 @@
;;; Commentary:
;;
+;; This package provides major modes for C and C++, plus some handy
+;; functions that are useful generally to major modes for C-like
+;; languages.
+;;
+;; This package provides `c-ts-mode' for C, `c++-ts-mode' for C++, and
+;; `c-or-c++-ts-mode' which automatically chooses the right mode for
+;; C/C++ header files.
+;;
+;; To use these modes by default, assuming you have the respective
+;; tree-sitter grammars available, do one of the following:
+;;
+;; - If you have both C and C++ grammars installed, add
+;;
+;; (require 'c-ts-mode)
+;;
+;; to your init file.
+;;
+;; - Add one or mode of the following to your init file:
+;;
+;; (add-to-list 'major-mode-remap-alist '(c-mode . c-ts-mode))
+;; (add-to-list 'major-mode-remap-alist '(c++-mode . c++-ts-mode))
+;; (add-to-list 'major-mode-remap-alist '(c-or-c++-mode . c-or-c++-ts-mode))
+;;
+;; If you have only C grammar available, use only the first one; if
+;; you have only the C++ grammar, use only the second one.
+;;
+;; - Customize 'auto-mode-alist' to turn one or more of the modes
+;; automatically. For example:
+;;
+;; (add-to-list 'auto-mode-alist
+;; '("\\(\\.ii\\|\\.\\(CC?\\|HH?\\)\\|\\.[ch]\\(pp\\|xx\\|\\+\\+\\)\\|\\.\\(cc\\|hh\\)\\)\\'"
+;; . c++-ts-mode))
+;;
+;; will turn on the c++-ts-mode for C++ source files.
+;;
+;; You can also turn on these modes manually in a buffer. Doing so
+;; will set up Emacs to use the C/C++ modes defined here for other
+;; files, provided that you have the corresponding parser grammar
+;; libraries installed.
+;;
+;; - Use variable `c-ts-mode-indent-block-type-regexp' with indent
+;; offset c-ts-mode--statement-offset for indenting statements.
+;; Again, see `c-ts-mode--indent-styles' for example.
+;;
;;; Code:
(require 'treesit)
+(require 'c-ts-common)
(eval-when-compile (require 'rx))
(declare-function treesit-parser-create "treesit.c")
-(declare-function treesit-induce-sparse-tree "treesit.c")
(declare-function treesit-node-parent "treesit.c")
(declare-function treesit-node-start "treesit.c")
(declare-function treesit-node-end "treesit.c")
@@ -115,29 +159,46 @@ delimiters < and >'s."
"Indent rules supported by `c-ts-mode'.
MODE is either `c' or `cpp'."
(let ((common
- `(((parent-is "translation_unit") parent-bol 0)
+ `(((parent-is "translation_unit") point-min 0)
((node-is ")") parent 1)
((node-is "]") parent-bol 0)
- ((node-is "}") c-ts-mode--bracket-children-anchor 0)
((node-is "else") parent-bol 0)
((node-is "case") parent-bol 0)
((node-is "preproc_arg") no-indent)
- ((and (parent-is "comment") c-ts-mode--looking-at-star)
- c-ts-mode--comment-start-after-first-star -1)
+ ;; `c-ts-common-looking-at-star' has to come before
+ ;; `c-ts-common-comment-2nd-line-matcher'.
+ ((and (parent-is "comment") c-ts-common-looking-at-star)
+ c-ts-common-comment-start-after-first-star -1)
+ (c-ts-common-comment-2nd-line-matcher
+ c-ts-common-comment-2nd-line-anchor
+ 1)
((parent-is "comment") prev-adaptive-prefix 0)
+
+ ;; Labels.
((node-is "labeled_statement") parent-bol 0)
- ((parent-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
+ ((parent-is "labeled_statement")
+ point-min c-ts-mode--statement-offset)
+
((match "preproc_ifdef" "compound_statement") point-min 0)
((match "#endif" "preproc_ifdef") point-min 0)
((match "preproc_if" "compound_statement") point-min 0)
((match "#endif" "preproc_if") point-min 0)
((match "preproc_function_def" "compound_statement") point-min 0)
((match "preproc_call" "compound_statement") point-min 0)
+
+ ;; {} blocks.
+ ((node-is "}") point-min c-ts-mode--close-bracket-offset)
((parent-is "compound_statement")
- c-ts-mode--bracket-children-anchor c-ts-mode-indent-offset)
+ point-min c-ts-mode--statement-offset)
+ ((parent-is "enumerator_list")
+ point-min c-ts-mode--statement-offset)
+ ((parent-is "field_declaration_list")
+ point-min c-ts-mode--statement-offset)
+
((parent-is "function_definition") parent-bol 0)
((parent-is "conditional_expression") first-sibling 0)
((parent-is "assignment_expression") parent-bol c-ts-mode-indent-offset)
+ ((parent-is "concatenated_string") parent-bol c-ts-mode-indent-offset)
((parent-is "comma_expression") first-sibling 0)
((parent-is "init_declarator") parent-bol c-ts-mode-indent-offset)
((parent-is "parenthesized_expression") first-sibling 1)
@@ -149,10 +210,11 @@ MODE is either `c' or `cpp'."
((query "(for_statement update: (_) @indent)") parent-bol 5)
((query "(call_expression arguments: (_) @indent)") parent c-ts-mode-indent-offset)
((parent-is "call_expression") parent 0)
- ((parent-is "enumerator_list") parent-bol c-ts-mode-indent-offset)
,@(when (eq mode 'cpp)
- '(((node-is "access_specifier") parent-bol 0)))
- ((parent-is "field_declaration_list") parent-bol c-ts-mode-indent-offset)
+ '(((node-is "access_specifier") parent-bol 0)
+ ;; Indent the body of namespace definitions.
+ ((parent-is "declaration_list") parent-bol c-ts-mode-indent-offset)))
+
((parent-is "initializer_list") parent-bol c-ts-mode-indent-offset)
((parent-is "if_statement") parent-bol c-ts-mode-indent-offset)
((parent-is "for_statement") parent-bol c-ts-mode-indent-offset)
@@ -165,10 +227,20 @@ MODE is either `c' or `cpp'."
`((gnu
;; Prepend rules to set highest priority
((match "while" "do_statement") parent 0)
+ (c-ts-mode--top-level-label-matcher point-min 1)
,@common)
(k&r ,@common)
- (linux ,@common)
+ (linux
+ ;; Reference:
+ ;; https://www.kernel.org/doc/html/latest/process/coding-style.html,
+ ;; and script/Lindent in Linux kernel repository.
+ ((node-is "labeled_statement") point-min 0)
+ ,@common)
(bsd
+ ((node-is "}") parent-bol 0)
+ ((node-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
+ ((parent-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
+ ((parent-is "compound_statement") parent-bol c-ts-mode-indent-offset)
((parent-is "if_statement") parent-bol 0)
((parent-is "for_statement") parent-bol 0)
((parent-is "while_statement") parent-bol 0)
@@ -190,36 +262,72 @@ MODE is either `c' or `cpp'."
('linux (alist-get 'linux (c-ts-mode--indent-styles mode)))))))
`((,mode ,@style))))
-(defun c-ts-mode--bracket-children-anchor (_n parent &rest _)
- "This anchor is used for children of a compound_statement.
-So anything inside a {} block. PARENT should be the
-compound_statement. This anchor looks at the {, if itson its own
-line, anchor at it, if it has stuff before it, anchor at the
-beginning of grandparent."
- (save-excursion
- (goto-char (treesit-node-start parent))
- (let ((bol (line-beginning-position)))
- (skip-chars-backward " \t")
- (treesit-node-start
- (if (< bol (point))
- (treesit-node-parent parent)
- parent)))))
-
-(defun c-ts-mode--looking-at-star (&rest _)
- "A tree-sitter simple indent matcher.
-Matches if there is a \"*\" after point (ignoring whitespace in
-between)."
- (looking-at (rx (* (syntax whitespace)) "*")))
-
-(defun c-ts-mode--comment-start-after-first-star (_n parent &rest _)
- "A tree-sitter simple indent anchor.
-Finds the \"/*\" and returns the point after the \"*\".
-Assumes PARENT is a comment node."
- (save-excursion
- (goto-char (treesit-node-start parent))
- (if (looking-at (rx "/*"))
- (match-end 0)
- (point))))
+(defun c-ts-mode--top-level-label-matcher (node &rest _)
+ "A matcher that matches a top-level label.
+NODE should be a labeled_statement."
+ (let ((func (treesit-parent-until
+ node (lambda (n)
+ (equal (treesit-node-type n)
+ "compound_statement")))))
+ (and (equal (treesit-node-type node)
+ "labeled_statement")
+ (not (treesit-node-top-level func "compound_statement")))))
+
+(defvar c-ts-mode-indent-block-type-regexp
+ (rx (or "compound_statement"
+ "field_declaration_list"
+ "enumerator_list"))
+ "Regexp matching types of block nodes (i.e., {} blocks).")
+
+(defun c-ts-mode--statement-offset (node parent &rest _)
+ "This anchor is used for children of a statement inside a block.
+
+This function basically counts the number of block nodes (defined
+by `c-ts-mode--indent-block-type-regexp') between NODE and the
+root node (not counting NODE itself), and multiply that by
+`c-ts-mode-indent-offset'.
+
+To support GNU style, on each block level, this function also
+checks whether the opening bracket { is on its own line, if so,
+it adds an extra level, except for the top-level.
+
+PARENT is NODE's parent."
+ (let ((level 0))
+ ;; If point is on an empty line, NODE would be nil, but we pretend
+ ;; there is a statement node.
+ (when (null node)
+ (setq node t))
+ (while (if (eq node t)
+ (setq node parent)
+ (setq node (treesit-node-parent node)))
+ (when (string-match-p c-ts-mode-indent-block-type-regexp
+ (treesit-node-type node))
+ (cl-incf level)
+ (save-excursion
+ (goto-char (treesit-node-start node))
+ ;; Add an extra level if the opening bracket is on its own
+ ;; line, except (1) it's at top-level, or (2) it's immedate
+ ;; parent is another block.
+ (cond ((bolp) nil) ; Case (1).
+ ((let ((parent-type (treesit-node-type
+ (treesit-node-parent node))))
+ ;; Case (2).
+ (and parent-type
+ (string-match-p c-ts-mode-indent-block-type-regexp
+ parent-type)))
+ nil)
+ ;; Add a level.
+ ((looking-back (rx bol (* whitespace))
+ (line-beginning-position))
+ (cl-incf level))))))
+ (* level c-ts-mode-indent-offset)))
+
+(defun c-ts-mode--close-bracket-offset (node parent &rest _)
+ "Offset for the closing bracket, NODE.
+It's basically one level less that the statements in the block.
+PARENT is NODE's parent."
+ (- (c-ts-mode--statement-offset node parent)
+ c-ts-mode-indent-offset))
;;; Font-lock
@@ -358,7 +466,7 @@ MODE is either `c' or `cpp'."
:language mode
:feature 'assignment
;; TODO: Recursively highlight identifiers in parenthesized
- ;; expressions, see `c-ts-mode--fontify-struct-declarator' for
+ ;; expressions, see `c-ts-mode--fontify-declarator' for
;; inspiration.
'((assignment_expression
left: (identifier) @font-lock-variable-name-face)
@@ -419,17 +527,29 @@ MODE is either `c' or `cpp'."
;;; Font-lock helpers
-(defun c-ts-mode--declarator-identifier (node)
- "Return the identifier of the declarator node NODE."
+(defun c-ts-mode--declarator-identifier (node &optional qualified)
+ "Return the identifier of the declarator node NODE.
+
+If QUALIFIED is non-nil, include the names space part of the
+identifier and return a qualified_identifier."
(pcase (treesit-node-type node)
;; Recurse.
((or "attributed_declarator" "parenthesized_declarator")
- (c-ts-mode--declarator-identifier (treesit-node-child node 0 t)))
+ (c-ts-mode--declarator-identifier (treesit-node-child node 0 t)
+ qualified))
((or "pointer_declarator" "reference_declarator")
- (c-ts-mode--declarator-identifier (treesit-node-child node -1)))
+ (c-ts-mode--declarator-identifier (treesit-node-child node -1)
+ qualified))
((or "function_declarator" "array_declarator" "init_declarator")
(c-ts-mode--declarator-identifier
- (treesit-node-child-by-field-name node "declarator")))
+ (treesit-node-child-by-field-name node "declarator")
+ qualified))
+ ("qualified_identifier"
+ (if qualified
+ node
+ (c-ts-mode--declarator-identifier
+ (treesit-node-child-by-field-name node "name")
+ qualified)))
;; Terminal case.
((or "identifier" "field_identifier")
node)))
@@ -439,7 +559,14 @@ MODE is either `c' or `cpp'."
For NODE, OVERRIDE, START, END, and ARGS, see
`treesit-font-lock-rules'."
(let* ((identifier (c-ts-mode--declarator-identifier node))
- (face (pcase (treesit-node-type (treesit-node-parent identifier))
+ (qualified-root
+ (treesit-parent-while (treesit-node-parent identifier)
+ (lambda (node)
+ (equal (treesit-node-type node)
+ "qualified_identifier"))))
+ (face (pcase (treesit-node-type (treesit-node-parent
+ (or qualified-root
+ identifier)))
("function_declarator" 'font-lock-function-name-face)
(_ 'font-lock-variable-name-face))))
(treesit-fontify-with-override
@@ -524,9 +651,11 @@ Return nil if NODE is not a defun node or doesn't have a name."
(pcase (treesit-node-type node)
((or "function_definition" "declaration")
(c-ts-mode--declarator-identifier
- (treesit-node-child-by-field-name node "declarator")))
+ (treesit-node-child-by-field-name node "declarator")
+ t))
((or "struct_specifier" "enum_specifier"
- "union_specifier" "class_specifier")
+ "union_specifier" "class_specifier"
+ "namespace_definition")
(treesit-node-child-by-field-name node "name")))
t))
@@ -558,6 +687,23 @@ Ie, NODE is not nested."
node "declarator"))
"function_declarator")))))
+(defun c-ts-mode--defun-for-class-in-imenu-p (node)
+ "Check if NODE is a valid entry for the Class subindex.
+
+Basically, if NODE is a class, return non-nil; if NODE is a
+function but is under a class, return non-nil; if NODE is a
+top-level function, return nil.
+
+This is for the Class subindex in
+`treesit-simple-imenu-settings'."
+ (pcase (treesit-node-type node)
+ ;; The Class subindex only has class_specifier and
+ ;; function_definition.
+ ("class_specifier" t)
+ ("function_definition"
+ ;; Return t if this function is nested in a class.
+ (treesit-node-top-level node "class_specifier"))))
+
(defun c-ts-mode--defun-skipper ()
"Custom defun skipper for `c-ts-mode' and friends.
Structs in C ends with a semicolon, but the semicolon is not
@@ -578,138 +724,6 @@ the semicolon. This function skips the semicolon."
(treesit-node-end node))
(goto-char orig-point)))
-;;; Filling
-
-(defun c-ts-mode--fill-paragraph (&optional arg)
- "Fillling function for `c-ts-mode'.
-ARG is passed to `fill-paragraph'."
- (interactive "*P")
- (save-restriction
- (widen)
- (let* ((node (treesit-node-at (point)))
- (start (treesit-node-start node))
- (end (treesit-node-end node))
- ;; Bind to nil to avoid infinite recursion.
- (fill-paragraph-function nil)
- (orig-point (point-marker))
- (start-marker nil)
- (end-marker nil)
- (end-len 0))
- ;; These covers C/C++, Java, JavaScript, TypeScript, Rust, C#.
- (when (member (treesit-node-type node)
- '("comment" "line_comment" "block_comment"))
- ;; We mask "/*" and the space before "*/" like
- ;; `c-fill-paragraph' does.
- (atomic-change-group
- ;; Mask "/*".
- (goto-char start)
- (when (looking-at (rx (* (syntax whitespace))
- (group "/") "*"))
- (goto-char (match-beginning 1))
- (setq start-marker (point-marker))
- (replace-match " " nil nil nil 1))
- ;; Include whitespaces before /*.
- (goto-char start)
- (beginning-of-line)
- (setq start (point))
- ;; Mask spaces before "*/" if it is attached at the end
- ;; of a sentence rather than on its own line.
- (goto-char end)
- (when (looking-back (rx (not (syntax whitespace))
- (group (+ (syntax whitespace)))
- "*/")
- (line-beginning-position))
- (goto-char (match-beginning 1))
- (setq end-marker (point-marker))
- (setq end-len (- (match-end 1) (match-beginning 1)))
- (replace-match (make-string end-len ?x)
- nil nil nil 1))
- ;; If "*/" is on its own line, don't included it in the
- ;; filling region.
- (when (not end-marker)
- (goto-char end)
- (when (looking-back (rx "*/") 2)
- (backward-char 2)
- (skip-syntax-backward "-")
- (setq end (point))))
- ;; Let `fill-paragraph' do its thing.
- (goto-char orig-point)
- (narrow-to-region start end)
- (funcall #'fill-paragraph arg)
- ;; Unmask.
- (when start-marker
- (goto-char start-marker)
- (delete-char 1)
- (insert "/"))
- (when end-marker
- (goto-char end-marker)
- (delete-region (point) (+ end-len (point)))
- (insert (make-string end-len ?\s))))
- (goto-char orig-point))
- ;; Return t so `fill-paragraph' doesn't attempt to fill by
- ;; itself.
- t)))
-
-(defun c-ts-mode-comment-setup ()
- "Set up local variables for C-like comment.
-
-Set up:
- - `comment-start'
- - `comment-end'
- - `comment-start-skip'
- - `comment-end-skip'
- - `adaptive-fill-mode'
- - `adaptive-fill-first-line-regexp'
- - `paragraph-start'
- - `paragraph-separate'
- - `fill-paragraph-function'"
- (setq-local comment-start "// ")
- (setq-local comment-end "")
- (setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
- (seq "/" (+ "*")))
- (* (syntax whitespace))))
- (setq-local comment-end-skip
- (rx (* (syntax whitespace))
- (group (or (syntax comment-end)
- (seq (+ "*") "/")))))
- (setq-local adaptive-fill-mode t)
- ;; This matches (1) empty spaces (the default), (2) "//", (3) "*",
- ;; but do not match "/*", because we don't want to use "/*" as
- ;; prefix when filling. (Actually, it doesn't matter, because
- ;; `comment-start-skip' matches "/*" which will cause
- ;; `fill-context-prefix' to use "/*" as a prefix for filling, that's
- ;; why we mask the "/*" in `c-ts-mode--fill-paragraph'.)
- (setq-local adaptive-fill-regexp
- (concat (rx (* (syntax whitespace))
- (group (or (seq "/" (+ "/")) (* "*"))))
- adaptive-fill-regexp))
- ;; Note the missing * comparing to `adaptive-fill-regexp'. The
- ;; reason for its absence is a bit convoluted to explain. Suffice
- ;; to say that without it, filling a single line paragraph that
- ;; starts with /* doesn't insert * at the beginning of each
- ;; following line, and filling a multi-line paragraph whose first
- ;; two lines start with * does insert * at the beginning of each
- ;; following line. If you know how does adaptive filling works, you
- ;; know what I mean.
- (setq-local adaptive-fill-first-line-regexp
- (rx bos
- (seq (* (syntax whitespace))
- (group (seq "/" (+ "/")))
- (* (syntax whitespace)))
- eos))
- ;; Same as `adaptive-fill-regexp'.
- (setq-local paragraph-start
- (rx (or (seq (* (syntax whitespace))
- (group (or (seq "/" (+ "/")) (* "*")))
- (* (syntax whitespace))
- ;; Add this eol so that in
- ;; `fill-context-prefix', `paragraph-start'
- ;; doesn't match the prefix.
- eol)
- "\f")))
- (setq-local paragraph-separate paragraph-start)
- (setq-local fill-paragraph-function #'c-ts-mode--fill-paragraph))
-
;;; Modes
(defvar-keymap c-ts-mode-map
@@ -731,7 +745,8 @@ Set up:
"struct_specifier"
"enum_specifier"
"union_specifier"
- "class_specifier"))
+ "class_specifier"
+ "namespace_definition"))
#'c-ts-mode--defun-valid-p))
(setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper)
(setq-local treesit-defun-name-function #'c-ts-mode--defun-name)
@@ -745,7 +760,7 @@ Set up:
(setq-local indent-tabs-mode t))
;; Comment
- (c-ts-mode-comment-setup)
+ (c-ts-common-comment-setup)
;; Electric
(setq-local electric-indent-chars
@@ -762,7 +777,7 @@ Set up:
("Class" ,(rx bos (or "class_specifier"
"function_definition")
eos)
- ,pred nil))))
+ c-ts-mode--defun-for-class-in-imenu-p nil))))
(setq-local treesit-font-lock-feature-list
'(( comment definition)
@@ -772,45 +787,123 @@ Set up:
;;;###autoload
(define-derived-mode c-ts-mode c-ts-base-mode "C"
- "Major mode for editing C, powered by tree-sitter."
- :group 'c
-
- (unless (treesit-ready-p 'c)
- (error "Tree-sitter for C isn't available"))
+ "Major mode for editing C, powered by tree-sitter.
- (treesit-parser-create 'c)
+This mode is independent from the classic cc-mode.el based
+`c-mode', so configuration variables of that mode, like
+`c-basic-offset', doesn't affect this mode.
- ;; Comments.
- (setq-local comment-start "/* ")
- (setq-local comment-end " */")
+To use tree-sitter C/C++ modes by default, evaluate
- (setq-local treesit-simple-indent-rules
- (c-ts-mode--set-indent-style 'c))
+ (add-to-list \\='major-mode-remap-alist \\='(c-mode . c-ts-mode))
+ (add-to-list \\='major-mode-remap-alist \\='(c++-mode . c++-ts-mode))
+ (add-to-list \\='major-mode-remap-alist
+ \\='(c-or-c++-mode . c-or-c++-ts-mode))
- ;; Font-lock.
- (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c))
+in your configuration."
+ :group 'c
- (treesit-major-mode-setup))
+ (when (treesit-ready-p 'c)
+ (treesit-parser-create 'c)
+ ;; Comments.
+ (setq-local comment-start "/* ")
+ (setq-local comment-end " */")
+ ;; Indent.
+ (setq-local treesit-simple-indent-rules
+ (c-ts-mode--set-indent-style 'c))
+ ;; Font-lock.
+ (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c))
+ (treesit-major-mode-setup)))
;;;###autoload
(define-derived-mode c++-ts-mode c-ts-base-mode "C++"
- "Major mode for editing C++, powered by tree-sitter."
- :group 'c++
+ "Major mode for editing C++, powered by tree-sitter.
+
+This mode is independent from the classic cc-mode.el based
+`c++-mode', so configuration variables of that mode, like
+`c-basic-offset', don't affect this mode.
- (unless (treesit-ready-p 'cpp)
- (error "Tree-sitter for C++ isn't available"))
+To use tree-sitter C/C++ modes by default, evaluate
- (treesit-parser-create 'cpp)
- (setq-local syntax-propertize-function
- #'c-ts-mode--syntax-propertize)
+ (add-to-list \\='major-mode-remap-alist \\='(c-mode . c-ts-mode))
+ (add-to-list \\='major-mode-remap-alist \\='(c++-mode . c++-ts-mode))
+ (add-to-list \\='major-mode-remap-alist
+ \\='(c-or-c++-mode . c-or-c++-ts-mode))
- (setq-local treesit-simple-indent-rules
- (c-ts-mode--set-indent-style 'cpp))
+in your configuration."
+ :group 'c++
- ;; Font-lock.
- (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp))
+ (when (treesit-ready-p 'cpp)
+ (treesit-parser-create 'cpp)
+ ;; Syntax.
+ (setq-local syntax-propertize-function
+ #'c-ts-mode--syntax-propertize)
+ ;; Indent.
+ (setq-local treesit-simple-indent-rules
+ (c-ts-mode--set-indent-style 'cpp))
+ ;; Font-lock.
+ (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp))
+ (treesit-major-mode-setup)))
+
+;; We could alternatively use parsers, but if this works well, I don't
+;; see the need to change. This is copied verbatim from cc-guess.el.
+(defconst c-ts-mode--c-or-c++-regexp
+ (eval-when-compile
+ (let ((id "[a-zA-Z_][a-zA-Z0-9_]*") (ws "[ \t]+") (ws-maybe "[ \t]*")
+ (headers '("string" "string_view" "iostream" "map" "unordered_map"
+ "set" "unordered_set" "vector" "tuple")))
+ (concat "^" ws-maybe "\\(?:"
+ "using" ws "\\(?:namespace" ws
+ "\\|" id "::"
+ "\\|" id ws-maybe "=\\)"
+ "\\|" "\\(?:inline" ws "\\)?namespace"
+ "\\(:?" ws "\\(?:" id "::\\)*" id "\\)?" ws-maybe "{"
+ "\\|" "class" ws id
+ "\\(?:" ws "final" "\\)?" ws-maybe "[:{;\n]"
+ "\\|" "struct" ws id "\\(?:" ws "final" ws-maybe "[:{\n]"
+ "\\|" ws-maybe ":\\)"
+ "\\|" "template" ws-maybe "<.*?>"
+ "\\|" "#include" ws-maybe "<" (regexp-opt headers) ">"
+ "\\)")))
+ "A regexp applied to C header files to check if they are really C++.")
- (treesit-major-mode-setup))
+;;;###autoload
+(defun c-or-c++-ts-mode ()
+ "Analyze buffer and enable either C or C++ mode.
+
+Some people and projects use .h extension for C++ header files
+which is also the one used for C header files. This makes
+matching on file name insufficient for detecting major mode that
+should be used.
+
+This function attempts to use file contents to determine whether
+the code is C or C++ and based on that chooses whether to enable
+`c-ts-mode' or `c++-ts-mode'."
+ (interactive)
+ (if (save-excursion
+ (save-restriction
+ (save-match-data ; Why `save-match-data'?
+ (widen)
+ (goto-char (point-min))
+ (re-search-forward c-ts-mode--c-or-c++-regexp nil t))))
+ (c++-ts-mode)
+ (c-ts-mode)))
+;; The entries for C++ must come first to prevent *.c files be taken
+;; as C++ on case-insensitive filesystems, since *.C files are C++,
+;; not C.
+(if (treesit-ready-p 'cpp)
+ (add-to-list 'auto-mode-alist
+ '("\\(\\.ii\\|\\.\\(CC?\\|HH?\\)\\|\\.[ch]\\(pp\\|xx\\|\\+\\+\\)\\|\\.\\(cc\\|hh\\)\\)\\'"
+ . c++-ts-mode)))
+
+(if (treesit-ready-p 'c)
+ (add-to-list 'auto-mode-alist
+ '("\\(\\.[chi]\\|\\.lex\\|\\.y\\(acc\\)?\\|\\.x[bp]m\\)\\'"
+ . c-ts-mode)))
+
+(if (and (treesit-ready-p 'cpp)
+ (treesit-ready-p 'c))
+ (add-to-list 'auto-mode-alist '("\\.h\\'" . c-or-c++-ts-mode)))
(provide 'c-ts-mode)
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."
(search-forward-regexp "\\(\n\\|.\\)") ; to set the match-data.
(point))))
+(defmacro c-search-forward-non-nil-char-property (property &optional limit)
+ "Search forward for a text-property PROPERTY value non-nil.
+LIMIT bounds the search.
+
+Leave point just after the character. The match data remain
+unchanged. Return the value of PROPERTY. If a non-nil value
+isn't found, return nil; point is then left undefined."
+ (declare (debug t))
+ `(let* ((-limit- (or ,limit (point-max)))
+ (value (c-get-char-property (point) ,property)))
+ (cond
+ ((>= (point) -limit-)
+ nil)
+ (value
+ (forward-char)
+ value)
+ (t (let ((place (c-next-single-property-change
+ (point) ,property nil -limit-)))
+ (when place
+ (goto-char (1+ place))
+ (c-get-char-property place ,property)))))))
+
(defmacro c-search-backward-char-property (property value &optional limit)
"Search backward for a text-property PROPERTY having value VALUE.
LIMIT bounds the search. The comparison is done with `equal'.
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 8ac3ef6808d..ebcb20f0f8c 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -142,6 +142,10 @@
;; Put on the brace which introduces a brace list and on the commas
;; which separate the elements within it.
;;
+;; 'c-typedef This property is applied to the first character of a
+;; "typedef" keyword. It's value is a list of the identifiers that
+;; the "typedef" declares as types.
+;;
;; 'c-<>-c-types-set
;; This property is set on an opening angle bracket, and indicates that
;; any "," separators within the template/generic expression have been
@@ -10024,10 +10028,10 @@ This function might do hidden buffer changes."
;; an identifier instead.
(declare (debug nil))
`(progn
+ (setq identifier-start type-start)
,(unless short
;; These identifiers are bound only in the inner let.
'(setq identifier-type at-type
- identifier-start type-start
got-parens nil
got-identifier t
got-suffix t
@@ -10102,10 +10106,11 @@ This function might do hidden buffer changes."
;; The second element of the return value is non-nil when something
;; indicating the identifier is a type occurs in the declaration.
;; Specifically it is nil, or a three element list (A B C) where C is t
- ;; when context is '<> and the "identifier" is a found type, B is t when a
- ;; `c-typedef-kwds' ("typedef") is present, and A is t when some other
- ;; `c-typedef-decl-kwds' (e.g. class, struct, enum) specifier is present.
- ;; I.e., (some of) the declared identifier(s) are types.
+ ;; when context is '<> and the "identifier" is a found type, B is the
+ ;; position of the `c-typedef-kwds' keyword ("typedef") when such is
+ ;; present, and A is t when some other `c-typedef-decl-kwds' (e.g. class,
+ ;; struct, enum) specifier is present. I.e., (some of) the declared
+ ;; identifier(s) are types.
;;
;; The third element of the return value is non-nil when the declaration
;; parsed might be an expression. The fourth element is the position of
@@ -10173,6 +10178,9 @@ This function might do hidden buffer changes."
;; `c-decl-hangon-kwds' and their associated clauses that
;; occurs after the type.
id-start
+ ;; The earlier value of `type-start' if we've shifted the type
+ ;; backwards.
+ identifier-start
;; These store `at-type', `type-start' and `id-start' of the
;; identifier before the one in those variables. The previous
;; identifier might turn out to be the real type in a
@@ -10183,7 +10191,8 @@ This function might do hidden buffer changes."
;; Set if we've found a specifier (apart from "typedef") that makes
;; the defined identifier(s) types.
at-type-decl
- ;; Set if we've a "typedef" keyword.
+ ;; If we've a "typedef" keyword (?or similar), the buffer position of
+ ;; its first character.
at-typedef
;; Set if `context' is '<> and the identifier is definitely a type, or
;; has already been recorded as a found type.
@@ -10266,7 +10275,7 @@ This function might do hidden buffer changes."
(looking-at "@[A-Za-z0-9]+")))
(save-match-data
(if (looking-at c-typedef-key)
- (setq at-typedef t)))
+ (setq at-typedef (point))))
(setq kwd-sym (c-keyword-sym (match-string 1)))
(save-excursion
(c-forward-keyword-clause 1)
@@ -10466,6 +10475,8 @@ This function might do hidden buffer changes."
got-prefix
;; True if the declarator is surrounded by a parenthesis pair.
got-parens
+ ;; True if there is a terminated argument list.
+ got-arglist
;; True if there is an identifier in the declarator.
got-identifier
;; True if we find a number where an identifier was expected.
@@ -10486,9 +10497,9 @@ This function might do hidden buffer changes."
;; True if we've parsed the type decl to a token that is
;; known to end declarations in this context.
at-decl-end
- ;; The earlier values of `at-type' and `type-start' if we've
- ;; shifted the type backwards.
- identifier-type identifier-start
+ ;; The earlier value of `at-type' if we've shifted the type
+ ;; backwards.
+ identifier-type
;; If `c-parse-and-markup-<>-arglists' is set we need to
;; turn it off during the name skipping below to avoid
;; getting `c-type' properties that might be bogus. That
@@ -10530,6 +10541,10 @@ This function might do hidden buffer changes."
(progn (setq got-identifier nil) t)
;; It turned out to be the real identifier,
;; so stop.
+ (save-excursion
+ (c-backward-syntactic-ws)
+ (c-simple-skip-symbol-backward)
+ (setq identifier-start (point)))
nil))
t))
@@ -10555,6 +10570,10 @@ This function might do hidden buffer changes."
(and (looking-at c-identifier-start)
(setq pos (point))
(setq got-identifier (c-forward-name))
+ (save-excursion
+ (c-backward-syntactic-ws)
+ (c-simple-skip-symbol-backward)
+ (setq identifier-start (point)))
(setq name-start pos))
(when (looking-at "[0-9]")
(setq got-number t)) ; We probably have an arithmetic expression.
@@ -10573,7 +10592,8 @@ This function might do hidden buffer changes."
(setq at-type nil
name-start type-start
id-start type-start
- got-identifier t)))
+ got-identifier t)
+ (setq identifier-start type-start)))
;; Skip over type decl suffix operators and trailing noise macros.
(while
@@ -10604,13 +10624,17 @@ This function might do hidden buffer changes."
(when (> paren-depth 0)
(setq paren-depth (1- paren-depth))
(forward-char)
+ (when (and (not got-parens)
+ (eq paren-depth 0))
+ (setq got-arglist t))
t)
- (when (if (save-match-data (looking-at "\\s("))
- (c-safe (c-forward-sexp 1) t)
- (if (save-match-data
- (looking-at c-fun-name-substitute-key)) ; requires
- (c-forward-c++-requires-clause)
- (goto-char (match-end 1))
+ (when (cond
+ ((save-match-data (looking-at "\\s("))
+ (c-safe (c-forward-sexp 1) t))
+ ((save-match-data
+ (looking-at c-fun-name-substitute-key)) ; C++ requires
+ (c-forward-c++-requires-clause))
+ (t (goto-char (match-end 1))
t))
(when (and (not got-suffix-after-parens)
(= paren-depth 0))
@@ -10672,8 +10696,11 @@ This function might do hidden buffer changes."
(goto-char pos)
(setq pd (1- pd)))
t)))
- (c-fdoc-shift-type-backward)
- t)))
+ (c-fdoc-shift-type-backward)
+ (when (and (not got-parens)
+ (eq paren-depth 0))
+ (setq got-arglist t))
+ t)))
(c-forward-syntactic-ws))
@@ -10741,6 +10768,9 @@ This function might do hidden buffer changes."
(not (or got-prefix got-parens)))
;; Got another identifier directly after the type, so it's a
;; declaration.
+ (when (and got-arglist
+ (eq at-type 'maybe))
+ (setq unsafe-maybe t))
(throw 'at-decl-or-cast t))
(when (and got-parens
@@ -10863,7 +10893,13 @@ This function might do hidden buffer changes."
;; types; other identifiers could just as well be
;; constants in C++.
(memq at-type '(known found)))))
- (throw 'at-decl-or-cast t)
+ (progn
+ ;; The user may be part way through typing a statement
+ ;; beginning with an identifier. This makes a 'maybe
+ ;; type in the following "declarator"'s arglist suspect.
+ (when (eq at-type 'maybe)
+ (setq unsafe-maybe t))
+ (throw 'at-decl-or-cast t))
;; CASE 7
;; Can't be a valid declaration or cast, but if we've found a
;; specifier it can't be anything else either, so treat it as
@@ -11123,9 +11159,17 @@ This function might do hidden buffer changes."
;; inside an arglist that contains declarations. Update (2017-09): We
;; now recognize a top-level "foo(bar);" as a declaration in C.
;; CASE 19
- (or (eq context 'decl)
- (and (c-major-mode-is 'c-mode)
- (or (eq context 'top) make-top))))))
+ (when
+ (or (eq context 'decl)
+ (and (c-major-mode-is 'c-mode)
+ (or (eq context 'top) make-top)))
+ (when (and (eq at-type 'maybe)
+ got-parens)
+ ;; If we've got "foo d(bar () ...)", the d could be a typing
+ ;; mistake, so we don't promote the 'maybe type "bar" to a 'found
+ ;; type.
+ (setq unsafe-maybe t))
+ t))))
;; The point is now after the type decl expression.
diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el
index d84c4f8ad8a..c220d8d8789 100644
--- a/lisp/progmodes/cc-fonts.el
+++ b/lisp/progmodes/cc-fonts.el
@@ -85,6 +85,8 @@
(cc-bytecomp-defvar parse-sexp-lookup-properties) ; Emacs only.
+(declare-function cl-set-difference "cl-seq" (cl-list1 cl-list2 &rest cl-keys))
+
;; Need to declare these local symbols during compilation since
;; they're referenced from lambdas in `byte-compile' calls that are
;; 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."
;; additionally, mark the commas with c-type property 'c-decl-id-start or
;; 'c-decl-type-start (according to TYPES). Stop at LIMIT.
;;
- ;; If TYPES is t, fontify all identifiers as types, if it is nil fontify as
- ;; either variables or functions, otherwise TYPES is a face to use. If
- ;; NOT-TOP is non-nil, we are not at the top-level ("top-level" includes
- ;; being directly inside a class or namespace, etc.).
+ ;; If TYPES is t, fontify all identifiers as types; if it is a number, a
+ ;; buffer position, additionally set the `c-deftype' text property on the
+ ;; keyword at that position; if it is nil fontify as either variables or
+ ;; functions, otherwise TYPES is a face to use. If NOT-TOP is non-nil, we
+ ;; are not at the top-level ("top-level" includes being directly inside a
+ ;; class or namespace, etc.).
;;
;; TEMPLATE-CLASS is non-nil when the declaration is in template delimiters
;; 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."
;;(message "c-font-lock-declarators from %s to %s" (point) limit)
(c-fontify-types-and-refs
()
+ ;; If we're altering the declarators in a typedef, we need to scan ALL of
+ ;; them because of the way we check for changes.
+ (let ((c-do-decl-limit (if (numberp types) (point-max) limit))
+ decl-ids)
(c-do-declarators
- limit list not-top
- (cond ((eq types t) 'c-decl-type-start)
+ c-do-decl-limit
+ list not-top
+ (cond ((or (numberp types)
+ (eq types t))
+ 'c-decl-type-start)
((null types) 'c-decl-id-start))
(lambda (id-start id-end end-pos _not-top is-function init-char)
- (if (eq types t)
+ (if (or (numberp types)
+ (eq types t))
(when id-start
;; Register and fontify the identifier as a type.
(let ((c-promote-possible-types t))
(goto-char id-start)
- (c-forward-type)))
+ (c-forward-type))
+ (when (numberp types)
+ (push (buffer-substring-no-properties id-start id-end)
+ decl-ids)))
(when id-start
(goto-char id-start)
(when c-opt-identifier-prefix-key
@@ -1147,7 +1162,7 @@ casts and declarations are fontified. Used on level 2 and higher."
(eq (match-end 1) id-end))
(while (and (< (point) id-end)
(re-search-forward c-opt-identifier-prefix-key id-end t))
- (c-forward-syntactic-ws limit))))
+ (c-forward-syntactic-ws c-do-decl-limit))))
;; Only apply the face when the text doesn't have one yet.
;; Exception: The "" in C++'s operator"" will already wrongly have
;; string face.
@@ -1164,7 +1179,7 @@ casts and declarations are fontified. Used on level 2 and higher."
(equal (buffer-substring-no-properties id-start id-end)
"\"\""))
(goto-char id-end)
- (c-forward-syntactic-ws limit)
+ (c-forward-syntactic-ws c-do-decl-limit)
(when (c-on-identifier)
(c-put-font-lock-face
(point)
@@ -1174,10 +1189,21 @@ casts and declarations are fontified. Used on level 2 and higher."
(eq init-char ?=) ; C++ "<class X = Y>"?
(progn
(goto-char end-pos)
- (c-forward-token-2 1 nil limit) ; Over "="
+ (c-forward-token-2 1 nil c-do-decl-limit) ; Over "="
(let ((c-promote-possible-types t))
(c-forward-type t)))))
accept-anon) ; Last argument to c-do-declarators.
+ ;; If we've changed types declared by a "typedef", update the `c-typedef'
+ ;; text property.
+ (when (numberp types)
+ (let* ((old-decl-ids (c-get-char-property types 'c-typedef))
+ (old-types (c--set-difference old-decl-ids decl-ids :test #'equal))
+ (new-types (c--set-difference decl-ids old-decl-ids :test #'equal)))
+ (dolist (type old-types)
+ (c-unfind-type type))
+ ;; The new types have already been added to `c-found-types', as needed.
+ (when (or old-types new-types)
+ (c-put-char-property types 'c-typedef decl-ids)))))
nil))
(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."
(c-font-lock-declarators
(min limit (point-max))
decl-list
- (not (null (cadr decl-or-cast)))
+ (cond ((null (cadr decl-or-cast))
+ nil)
+ ((cadr (cadr decl-or-cast)))
+ (t t))
(not toplev)
template-class
(memq context '(decl <>))))
@@ -1749,12 +1778,21 @@ casts and declarations are fontified. Used on level 2 and higher."
; speeds up lisp.h tremendously.
(save-excursion
(when (not (c-back-over-member-initializers decl-search-lim))
+ (setq paren-state (c-parse-state))
(unless (or (eobp)
(looking-at "\\s(\\|\\s)"))
(forward-char))
(c-syntactic-skip-backward "^;{}" decl-search-lim t)
- (when (eq (char-before) ?})
- (c-go-list-backward) ; brace block of struct, etc.?
+ ;; Do we have the brace block of a struct, etc.?
+ (when (cond
+ ((and (consp (car paren-state))
+ (eq (char-before) ?}))
+ (goto-char (caar paren-state))
+ t)
+ ((and (numberp (car paren-state))
+ (eq (char-after (car paren-state)) ?{))
+ (goto-char (car paren-state))
+ t))
(c-syntactic-skip-backward "^;{}" decl-search-lim t))
(when (or (bobp)
(memq (char-before) '(?\; ?{ ?})))
@@ -2530,8 +2568,8 @@ higher."
(get-text-property (match-beginning 0) 'fontified)
(not (memq (c-get-char-property (match-beginning 0) 'face)
c-literal-faces)))
- (c-put-font-lock-face (match-beginning 0) (match-end 0)
- font-lock-type-face))
+ (put-text-property (match-beginning 0) (match-end 0)
+ 'fontified nil))
(dolist (win-boundary window-boundaries)
(when (and (< (match-beginning 0) (cdr win-boundary))
(> (match-end 0) (car win-boundary))
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."
(not (eobp))))
(forward-char))))))
+(defun c-before-change-de-typedef (beg end)
+ ;; For each "typedef" starting in (BEG END), remove the defined types from
+ ;; c-found-types
+ (let (prop)
+ (save-excursion
+ (goto-char beg)
+ (while (and (< (point) end)
+ (setq prop (c-search-forward-non-nil-char-property
+ 'c-typedef)))
+ (dolist (type prop)
+ (c-unfind-type type))))))
+
+(defun c-after-change-de-typedef (beg end _old-len)
+ ;; For each former "typedef" in (BEG END), remove the defined types from
+ ;; those which are no longer typedefs.
+ (let (prop)
+ (save-excursion
+ (goto-char beg)
+ (c-backward-token-2
+ 1 nil (- (point) 20))
+ (while (and (< (point) end)
+ (setq prop (c-search-forward-non-nil-char-property
+ 'c-typedef end)))
+ (backward-char)
+ (when (or (not (looking-at c-typedef-key))
+ (<= (match-end 1) beg))
+ (dolist (type prop)
+ (c-unfind-type type))
+ (c-clear-char-property (point) 'c-typedef))
+ (forward-char)))))
+
(defun c-update-new-id (end)
;; Note the bounds of any identifier that END is in or just after, in
;; `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."
(let ((id-beg (c-on-identifier)))
(setq c-new-id-start id-beg
c-new-id-end (and id-beg
- (progn (c-end-of-current-token) (point)))
+ (progn (goto-char id-beg)
+ (c-forward-token-2)
+ (point)))
c-new-id-is-type nil))))
(defun c-post-command ()
@@ -2215,6 +2248,10 @@ with // and /*, not more generic line and block comments."
term-pos)
(buffer-substring-no-properties beg end)))))))
+ ;; If we're about to delete "typedef"s, clear the identifiers from
+ ;; `c-found-types'.
+ (c-before-change-de-typedef beg end)
+
(if c-get-state-before-change-functions
(mapc (lambda (fn)
(funcall fn beg end))
@@ -2306,6 +2343,7 @@ with // and /*, not more generic line and block comments."
(c-update-new-id end)
(c-trim-found-types beg end old-len) ; maybe we don't
; need all of these.
+ (c-after-change-de-typedef beg end old-len)
(c-invalidate-sws-region-after beg end old-len)
;; (c-invalidate-state-cache beg) ; moved to
;; `c-before-change'.
diff --git a/lisp/progmodes/cmake-ts-mode.el b/lisp/progmodes/cmake-ts-mode.el
index a31250f68be..c241a2868e5 100644
--- a/lisp/progmodes/cmake-ts-mode.el
+++ b/lisp/progmodes/cmake-ts-mode.el
@@ -195,10 +195,6 @@ the subtrees."
`((,name . ,marker))))))
;;;###autoload
-(add-to-list 'auto-mode-alist
- '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)\\'" . cmake-ts-mode))
-
-;;;###autoload
(define-derived-mode cmake-ts-mode prog-mode "CMake"
"Major mode for editing CMake files, powered by tree-sitter."
:group 'cmake
@@ -229,6 +225,10 @@ the subtrees."
(treesit-major-mode-setup)))
+(if (treesit-ready-p 'cmake)
+ (add-to-list 'auto-mode-alist
+ '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)\\'" . cmake-ts-mode)))
+
(provide 'cmake-ts-mode)
;;; cmake-ts-mode.el ends here
diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el
index 473e8f49fd3..852e893dc25 100644
--- a/lisp/progmodes/csharp-mode.el
+++ b/lisp/progmodes/csharp-mode.el
@@ -34,7 +34,7 @@
(require 'cc-mode)
(require 'cc-langs)
(require 'treesit)
-(require 'c-ts-mode) ; For comment indenting and filling.
+(require 'c-ts-common) ; For comment indenting and filling.
(eval-when-compile
(require 'cc-fonts)
@@ -634,12 +634,17 @@ compilation and evaluation time conflicts."
((node-is "}") parent-bol 0)
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
- ((and (parent-is "comment") c-ts-mode--looking-at-star)
- c-ts-mode--comment-start-after-first-star -1)
+ ((and (parent-is "comment") c-ts-common-looking-at-star)
+ c-ts-common-comment-start-after-first-star -1)
((parent-is "comment") prev-adaptive-prefix 0)
((parent-is "namespace_declaration") parent-bol 0)
((parent-is "class_declaration") parent-bol 0)
((parent-is "constructor_declaration") parent-bol 0)
+ ((parent-is "initializer_expression") parent-bol csharp-ts-mode-indent-offset)
+ ((match "{" "anonymous_object_creation_expression") parent-bol 0)
+ ((parent-is "anonymous_object_creation_expression") parent-bol csharp-ts-mode-indent-offset)
+ ((match "{" "object_creation_expression") parent-bol 0)
+ ((parent-is "object_creation_expression") parent-bol 0)
((parent-is "method_declaration") parent-bol 0)
((parent-is "enum_declaration") parent-bol 0)
((parent-is "operator_declaration") parent-bol 0)
@@ -773,9 +778,12 @@ compilation and evaluation time conflicts."
(array_type
(identifier) @font-lock-type-face)
(cast_expression (identifier) @font-lock-type-face)
+ (cast_expression (generic_name (identifier) @font-lock-type-face))
["operator"] @font-lock-type-face
(type_parameter_constraints_clause
target: (identifier) @font-lock-type-face)
+ (type_constraint type: (identifier) @font-lock-type-face)
+ (type_constraint type: (generic_name (identifier) @font-lock-type-face))
(type_of_expression (identifier) @font-lock-type-face)
(object_creation_expression
type: (identifier) @font-lock-type-face)
@@ -876,9 +884,6 @@ Return nil if there is no name or if NODE is not a defun node."
t))))
;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode))
-
-;;;###autoload
(define-derived-mode csharp-mode prog-mode "C#"
"Major mode for editing Csharp code.
@@ -903,7 +908,7 @@ Key bindings:
(treesit-parser-create 'c-sharp)
;; Comments.
- (c-ts-mode-comment-setup)
+ (c-ts-common-comment-setup)
;; Indent.
(setq-local treesit-simple-indent-rules csharp-ts-mode--indent-rules)
@@ -933,7 +938,9 @@ Key bindings:
("Struct" "\\`struct_declaration\\'" nil nil)
("Method" "\\`method_declaration\\'" nil nil)))
- (treesit-major-mode-setup))
+ (treesit-major-mode-setup)
+
+ (add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-ts-mode)))
(provide 'csharp-mode)
diff --git a/lisp/progmodes/dockerfile-ts-mode.el b/lisp/progmodes/dockerfile-ts-mode.el
index 3f8766e6713..2a295e885b0 100644
--- a/lisp/progmodes/dockerfile-ts-mode.el
+++ b/lisp/progmodes/dockerfile-ts-mode.el
@@ -133,12 +133,6 @@ the subtrees."
`((,name . ,marker))))))
;;;###autoload
-(add-to-list 'auto-mode-alist
- ;; NOTE: We can't use `rx' here, as it breaks bootstrap.
- '("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'"
- . dockerfile-ts-mode))
-
-;;;###autoload
(define-derived-mode dockerfile-ts-mode prog-mode "Dockerfile"
"Major mode for editing Dockerfiles, powered by tree-sitter."
:group 'dockerfile
@@ -172,6 +166,12 @@ the subtrees."
(treesit-major-mode-setup)))
+(if (treesit-ready-p 'dockerfile)
+ (add-to-list 'auto-mode-alist
+ ;; NOTE: We can't use `rx' here, as it breaks bootstrap.
+ '("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'"
+ . dockerfile-ts-mode)))
+
(provide 'dockerfile-ts-mode)
;;; dockerfile-ts-mode.el ends here
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index 6d192d9b333..dc73152f5ab 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -991,6 +991,7 @@ Return (MANAGED-MODE PROJECT CLASS CONTACT LANG-ID). If INTERACTIVE is
non-nil, maybe prompt user, else error as soon as something can't
be guessed."
(let* ((guessed-mode (if buffer-file-name major-mode))
+ (guessed-mode-name (and guessed-mode (symbol-name guessed-mode)))
(main-mode
(cond
((and interactive
@@ -1000,7 +1001,7 @@ be guessed."
(completing-read
"[eglot] Start a server to manage buffers of what major mode? "
(mapcar #'symbol-name (eglot--all-major-modes)) nil t
- (symbol-name guessed-mode) nil (symbol-name guessed-mode) nil)))
+ guessed-mode-name nil guessed-mode-name nil)))
((not guessed-mode)
(eglot--error "Can't guess mode to manage for `%s'" (current-buffer)))
(t guessed-mode)))
@@ -1074,7 +1075,7 @@ suitable root directory for a given LSP server's purposes."
;;;###autoload
(defun eglot (managed-major-mode project class contact language-id
- &optional interactive)
+ &optional _interactive)
"Start LSP server in support of PROJECT's buffers under MANAGED-MAJOR-MODE.
This starts a Language Server Protocol (LSP) server suitable for the
@@ -1111,17 +1112,17 @@ described in `eglot-server-programs', which see.
LANGUAGE-ID is the language ID string to send to the server for
MANAGED-MAJOR-MODE, which matters to a minority of servers.
-INTERACTIVE is t if called interactively."
- (interactive (append (eglot--guess-contact t) '(t)))
- (setq managed-major-mode (eglot--ensure-list managed-major-mode))
- (let* ((current-server (eglot-current-server))
- (live-p (and current-server (jsonrpc-running-p current-server))))
- (if (and live-p
- interactive
- (y-or-n-p "[eglot] Live process found, reconnect instead? "))
- (eglot-reconnect current-server interactive)
- (when live-p (ignore-errors (eglot-shutdown current-server)))
- (eglot--connect managed-major-mode project class contact language-id))))
+INTERACTIVE is ignored and provided for backward compatibility."
+ (interactive
+ (let ((current-server (eglot-current-server)))
+ (unless (or (null current-server)
+ (y-or-n-p "\
+[eglot] Shut down current connection before attempting new one?"))
+ (user-error "[eglot] Connection attempt aborted by user."))
+ (prog1 (append (eglot--guess-contact t) '(t))
+ (when current-server (ignore-errors (eglot-shutdown current-server))))))
+ (eglot--connect (eglot--ensure-list managed-major-mode)
+ project class contact language-id))
(defun eglot-reconnect (server &optional interactive)
"Reconnect to SERVER.
diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
index 1d6a8a30db5..d552e1360e0 100644
--- a/lisp/progmodes/go-ts-mode.el
+++ b/lisp/progmodes/go-ts-mode.el
@@ -36,6 +36,7 @@
(declare-function treesit-node-child-by-field-name "treesit.c")
(declare-function treesit-node-start "treesit.c")
(declare-function treesit-node-type "treesit.c")
+(declare-function treesit-search-subtree "treesit.c")
(defcustom go-ts-mode-indent-offset 4
"Number of spaces for each indentation step in `go-ts-mode'."
@@ -173,47 +174,6 @@
'((ERROR) @font-lock-warning-face))
"Tree-sitter font-lock settings for `go-ts-mode'.")
-(defun go-ts-mode--imenu ()
- "Return Imenu alist for the current buffer."
- (let* ((node (treesit-buffer-root-node))
- (func-tree (treesit-induce-sparse-tree
- node "function_declaration" nil 1000))
- (type-tree (treesit-induce-sparse-tree
- node "type_spec" nil 1000))
- (func-index (go-ts-mode--imenu-1 func-tree))
- (type-index (go-ts-mode--imenu-1 type-tree)))
- (append
- (when func-index `(("Function" . ,func-index)))
- (when type-index `(("Type" . ,type-index))))))
-
-(defun go-ts-mode--imenu-1 (node)
- "Helper for `go-ts-mode--imenu'.
-Find string representation for NODE and set marker, then recurse
-the subtrees."
- (let* ((ts-node (car node))
- (children (cdr node))
- (subtrees (mapcan #'go-ts-mode--imenu-1
- children))
- (name (when ts-node
- (treesit-node-text
- (pcase (treesit-node-type ts-node)
- ("function_declaration"
- (treesit-node-child-by-field-name ts-node "name"))
- ("type_spec"
- (treesit-node-child-by-field-name ts-node "name"))))))
- (marker (when ts-node
- (set-marker (make-marker)
- (treesit-node-start ts-node)))))
- (cond
- ((or (null ts-node) (null name)) subtrees)
- (subtrees
- `((,name ,(cons name marker) ,@subtrees)))
- (t
- `((,name . ,marker))))))
-
-;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
-
;;;###autoload
(define-derived-mode go-ts-mode prog-mode "Go"
"Major mode for editing Go, powered by tree-sitter."
@@ -228,14 +188,30 @@ the subtrees."
(setq-local comment-end "")
(setq-local comment-start-skip (rx "//" (* (syntax whitespace))))
+ ;; Navigation.
+ (setq-local treesit-defun-type-regexp
+ (regexp-opt '("method_declaration"
+ "function_declaration"
+ "type_declaration")))
+ (setq-local treesit-defun-name-function #'go-ts-mode--defun-name)
+
;; Imenu.
- (setq-local imenu-create-index-function #'go-ts-mode--imenu)
- (setq-local which-func-functions nil)
+ (setq-local treesit-simple-imenu-settings
+ `(("Function" "\\`function_declaration\\'" nil nil)
+ ("Method" "\\`method_declaration\\'" nil nil)
+ ("Struct" "\\`type_declaration\\'" go-ts-mode--struct-node-p nil)
+ ("Interface" "\\`type_declaration\\'" go-ts-mode--interface-node-p nil)
+ ("Type" "\\`type_declaration\\'" go-ts-mode--other-type-node-p nil)
+ ("Alias" "\\`type_declaration\\'" go-ts-mode--alias-node-p nil)))
;; Indent.
(setq-local indent-tabs-mode t
treesit-simple-indent-rules go-ts-mode--indent-rules)
+ ;; Electric
+ (setq-local electric-indent-chars
+ (append "{}()" electric-indent-chars))
+
;; Font-lock.
(setq-local treesit-font-lock-settings go-ts-mode--font-lock-settings)
(setq-local treesit-font-lock-feature-list
@@ -247,6 +223,57 @@ the subtrees."
(treesit-major-mode-setup)))
+(if (treesit-ready-p 'go)
+ (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode)))
+
+(defun go-ts-mode--defun-name (node)
+ "Return the defun name of NODE.
+Return nil if there is no name or if NODE is not a defun node."
+ (pcase (treesit-node-type node)
+ ("function_declaration"
+ (treesit-node-text
+ (treesit-node-child-by-field-name
+ node "name")
+ t))
+ ("method_declaration"
+ (let* ((receiver-node (treesit-node-child-by-field-name node "receiver"))
+ (type-node (treesit-search-subtree receiver-node "type_identifier"))
+ (name-node (treesit-node-child-by-field-name node "name")))
+ (concat
+ "(" (treesit-node-text type-node) ")."
+ (treesit-node-text name-node))))
+ ("type_declaration"
+ (treesit-node-text
+ (treesit-node-child-by-field-name
+ (treesit-node-child node 0 t) "name")
+ t))))
+
+(defun go-ts-mode--interface-node-p (node)
+ "Return t if NODE is an interface."
+ (and
+ (string-equal "type_declaration" (treesit-node-type node))
+ (treesit-search-subtree node "interface_type" nil nil 2)))
+
+(defun go-ts-mode--struct-node-p (node)
+ "Return t if NODE is a struct."
+ (and
+ (string-equal "type_declaration" (treesit-node-type node))
+ (treesit-search-subtree node "struct_type" nil nil 2)))
+
+(defun go-ts-mode--alias-node-p (node)
+ "Return t if NODE is a type alias."
+ (and
+ (string-equal "type_declaration" (treesit-node-type node))
+ (treesit-search-subtree node "type_alias" nil nil 1)))
+
+(defun go-ts-mode--other-type-node-p (node)
+ "Return t if NODE is a type, other than interface, struct or alias."
+ (and
+ (string-equal "type_declaration" (treesit-node-type node))
+ (not (go-ts-mode--interface-node-p node))
+ (not (go-ts-mode--struct-node-p node))
+ (not (go-ts-mode--alias-node-p node))))
+
;; go.mod support.
(defvar go-mod-ts-mode--syntax-table
@@ -319,9 +346,6 @@ what the parent of the node would be if it were a node."
"Tree-sitter font-lock settings for `go-mod-ts-mode'.")
;;;###autoload
-(add-to-list 'auto-mode-alist '("/go\\.mod\\'" . go-mod-ts-mode))
-
-;;;###autoload
(define-derived-mode go-mod-ts-mode prog-mode "Go Mod"
"Major mode for editing go.mod files, powered by tree-sitter."
:group 'go
@@ -349,6 +373,9 @@ what the parent of the node would be if it were a node."
(treesit-major-mode-setup)))
+(if (treesit-ready-p 'gomod)
+ (add-to-list 'auto-mode-alist '("/go\\.mod\\'" . go-mod-ts-mode)))
+
(provide 'go-ts-mode)
;;; go-ts-mode.el ends here
diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el
index cb766c68411..3b792354cbc 100644
--- a/lisp/progmodes/gud.el
+++ b/lisp/progmodes/gud.el
@@ -3608,8 +3608,9 @@ Treats actions as defuns."
(kill-local-variable 'gdb-define-alist)
(remove-hook 'after-save-hook #'gdb-create-define-alist t))))
-(defcustom gud-tooltip-modes '(gud-mode c-mode c++-mode fortran-mode
- python-mode)
+(defcustom gud-tooltip-modes '( gud-mode c-mode c++-mode fortran-mode
+ python-mode c-ts-mode c++-ts-mode
+ python-ts-mode)
"List of modes for which to enable GUD tooltips."
:type '(repeat (symbol :tag "Major mode"))
:group 'tooltip)
diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el
index 96d8045bd61..af2b0c1fa8d 100644
--- a/lisp/progmodes/java-ts-mode.el
+++ b/lisp/progmodes/java-ts-mode.el
@@ -29,7 +29,7 @@
(require 'treesit)
(eval-when-compile (require 'rx))
-(require 'c-ts-mode) ; For comment indent and filling.
+(require 'c-ts-common) ; For comment indent and filling.
(declare-function treesit-parser-create "treesit.c")
(declare-function treesit-induce-sparse-tree "treesit.c")
@@ -69,15 +69,16 @@
(defvar java-ts-mode--indent-rules
`((java
- ((parent-is "program") parent-bol 0)
+ ((parent-is "program") point-min 0)
((node-is "}") (and parent parent-bol) 0)
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
- ((and (parent-is "comment") c-ts-mode--looking-at-star)
- c-ts-mode--comment-start-after-first-star -1)
+ ((and (parent-is "comment") c-ts-common-looking-at-star)
+ c-ts-common-comment-start-after-first-star -1)
((parent-is "comment") prev-adaptive-prefix 0)
((parent-is "text_block") no-indent)
((parent-is "class_body") parent-bol java-ts-mode-indent-offset)
+ ((parent-is "annotation_type_body") parent-bol java-ts-mode-indent-offset)
((parent-is "interface_body") parent-bol java-ts-mode-indent-offset)
((parent-is "constructor_body") parent-bol java-ts-mode-indent-offset)
((parent-is "enum_body") parent-bol java-ts-mode-indent-offset)
@@ -85,6 +86,10 @@
((parent-is "record_declaration_body") parent-bol java-ts-mode-indent-offset)
((query "(method_declaration (block _ @indent))") parent-bol java-ts-mode-indent-offset)
((query "(method_declaration (block (_) @indent))") parent-bol java-ts-mode-indent-offset)
+ ((parent-is "local_variable_declaration") parent-bol java-ts-mode-indent-offset)
+ ((parent-is "expression_statement") parent-bol java-ts-mode-indent-offset)
+ ((parent-is "field_declaration") parent-bol java-ts-mode-indent-offset)
+ ((parent-is "return_statement") parent-bol java-ts-mode-indent-offset)
((parent-is "variable_declarator") parent-bol java-ts-mode-indent-offset)
((parent-is "method_invocation") parent-bol java-ts-mode-indent-offset)
((parent-is "switch_rule") parent-bol java-ts-mode-indent-offset)
@@ -122,7 +127,8 @@
"provides" "public" "requires" "return" "sealed"
"static" "strictfp" "switch" "synchronized"
"throw" "throws" "to" "transient" "transitive"
- "try" "uses" "volatile" "while" "with" "record")
+ "try" "uses" "volatile" "while" "with" "record"
+ "@interface")
"Java keywords for tree-sitter font-locking.")
(defvar java-ts-mode--operators
@@ -183,7 +189,10 @@
:language 'java
:override t
:feature 'type
- '((interface_declaration
+ '((annotation_type_declaration
+ name: (identifier) @font-lock-type-face)
+
+ (interface_declaration
name: (identifier) @font-lock-type-face)
(class_declaration
@@ -217,7 +226,10 @@
:language 'java
:override t
:feature 'definition
- `((method_declaration
+ `((annotation_type_element_declaration
+ name: (identifier) @font-lock-function-name-face)
+
+ (method_declaration
name: (identifier) @font-lock-function-name-face)
(variable_declarator
@@ -281,7 +293,7 @@ Return nil if there is no name or if NODE is not a defun node."
(treesit-parser-create 'java)
;; Comments.
- (c-ts-mode-comment-setup)
+ (c-ts-common-comment-setup)
;; Indent.
(setq-local treesit-simple-indent-rules java-ts-mode--indent-rules)
@@ -299,7 +311,8 @@ Return nil if there is no name or if NODE is not a defun node."
"enum_declaration"
"import_declaration"
"package_declaration"
- "module_declaration")))
+ "module_declaration"
+ "constructor_declaration")))
(setq-local treesit-defun-name-function #'java-ts-mode--defun-name)
;; Font-lock.
@@ -318,6 +331,9 @@ Return nil if there is no name or if NODE is not a defun node."
("Method" "\\`method_declaration\\'" nil nil)))
(treesit-major-mode-setup))
+(if (treesit-ready-p 'java)
+ (add-to-list 'auto-mode-alist '("\\.java\\'" . java-ts-mode)))
+
(provide 'java-ts-mode)
;;; java-ts-mode.el ends here
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 050472002bb..b5c912b8b0d 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -54,7 +54,7 @@
(require 'json)
(require 'prog-mode)
(require 'treesit)
-(require 'c-ts-mode) ; For comment indent and filling.
+(require 'c-ts-common) ; For comment indent and filling.
(eval-when-compile
(require 'cl-lib)
@@ -3428,8 +3428,8 @@ This function is intended for use in `after-change-functions'."
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
((node-is ">") parent-bol 0)
- ((and (parent-is "comment") c-ts-mode--looking-at-star)
- c-ts-mode--comment-start-after-first-star -1)
+ ((and (parent-is "comment") c-ts-common-looking-at-star)
+ c-ts-common-comment-start-after-first-star -1)
((parent-is "comment") prev-adaptive-prefix 0)
((parent-is "ternary_expression") parent-bol js-indent-level)
((parent-is "member_expression") parent-bol js-indent-level)
@@ -3454,13 +3454,16 @@ This function is intended for use in `after-change-functions'."
((parent-is "statement_block") parent-bol js-indent-level)
;; JSX
- ((node-is "jsx_fragment") parent typescript-ts-mode-indent-offset)
- ((node-is "jsx_element") parent typescript-ts-mode-indent-offset)
- ((node-is "jsx_expression") parent typescript-ts-mode-indent-offset)
- ((node-is "jsx_self_closing_element") parent typescript-ts-mode-indent-offset)
+ ((match "<" "jsx_fragment") parent 0)
+ ((parent-is "jsx_fragment") parent js-indent-level)
((node-is "jsx_closing_element") parent 0)
- ((node-is "/") parent 0)
- ((node-is ">") parent 0)))))
+ ((node-is "jsx_element") parent js-indent-level)
+ ((parent-is "jsx_element") parent js-indent-level)
+ ((parent-is "jsx_opening_element") parent js-indent-level)
+ ((parent-is "jsx_expression") parent-bol js-indent-level)
+ ((match "/" "jsx_self_closing_element") parent 0)
+ ((parent-is "jsx_self_closing_element") parent js-indent-level)
+ (no-node parent-bol 0)))))
(defvar js--treesit-keywords
'("as" "async" "await" "break" "case" "catch" "class" "const" "continue"
@@ -3498,14 +3501,14 @@ This function is intended for use in `after-change-functions'."
:language 'javascript
:feature 'string
- '((regex pattern: (regex_pattern)) @font-lock-string-face
+ '((regex pattern: (regex_pattern)) @font-lock-regexp-face
(string) @font-lock-string-face)
:language 'javascript
:feature 'string-interpolation
:override t
'((template_string) @js--fontify-template-string
- (template_substitution ["${" "}"] @font-lock-delimiter-face))
+ (template_substitution ["${" "}"] @font-lock-misc-punctuation-face))
:language 'javascript
:feature 'definition
@@ -3542,7 +3545,10 @@ This function is intended for use in `after-change-functions'."
(identifier)
(identifier)
@font-lock-function-name-face)
- value: (array (number) (function))))
+ value: (array (number) (function)))
+ (import_clause (identifier) @font-lock-variable-name-face)
+ (import_clause (named_imports (import_specifier (identifier))
+ @font-lock-variable-name-face)))
:language 'javascript
:feature 'property
@@ -3800,7 +3806,7 @@ Currently there are `js-mode' and `js-ts-mode'."
;; Which-func.
(setq-local which-func-imenu-joiner-function #'js--which-func-joiner)
;; Comment.
- (c-ts-mode-comment-setup)
+ (c-ts-common-comment-setup)
(setq-local comment-multi-line t)
;; Electric-indent.
(setq-local electric-indent-chars
@@ -3837,7 +3843,10 @@ Currently there are `js-mode' and `js-ts-mode'."
"method_definition")
eos)
nil nil)))
- (treesit-major-mode-setup)))
+ (treesit-major-mode-setup)
+
+ (add-to-list 'auto-mode-alist
+ '("\\(\\.js[mx]\\|\\.har\\)\\'" . js-ts-mode))))
;;;###autoload
(define-derived-mode js-json-mode js-mode "JSON"
diff --git a/lisp/progmodes/json-ts-mode.el b/lisp/progmodes/json-ts-mode.el
index fbcda22acca..f54d0187f98 100644
--- a/lisp/progmodes/json-ts-mode.el
+++ b/lisp/progmodes/json-ts-mode.el
@@ -160,6 +160,10 @@ Return nil if there is no name or if NODE is not a defun node."
(treesit-major-mode-setup))
+(if (treesit-ready-p 'json)
+ (add-to-list 'auto-mode-alist
+ '("\\.json\\'" . json-ts-mode)))
+
(provide 'json-ts-mode)
;;; json-ts-mode.el ends here
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 730998727ce..59270070484 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1,7 +1,7 @@
;;; project.el --- Operations on the current project -*- lexical-binding: t; -*-
;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
-;; Version: 0.9.3
+;; Version: 0.9.5
;; Package-Requires: ((emacs "26.1") (xref "1.4.0"))
;; This is a GNU ELPA :core package. Avoid using functionality that
@@ -514,11 +514,14 @@ project backend implementation of `project-external-roots'.")
(lambda (b) (assoc-default b backend-markers-alist))
vc-handled-backends)))
(marker-re
- (mapconcat
- (lambda (m) (format "\\(%s\\)" (wildcard-to-regexp m)))
- (append backend-markers
- (project--value-in-dir 'project-vc-extra-root-markers dir))
- "\\|"))
+ (concat
+ "\\`"
+ (mapconcat
+ (lambda (m) (format "\\(%s\\)" (wildcard-to-regexp m)))
+ (append backend-markers
+ (project--value-in-dir 'project-vc-extra-root-markers dir))
+ "\\|")
+ "\\'"))
(locate-dominating-stop-dir-regexp
(or vc-ignore-dir-regexp locate-dominating-stop-dir-regexp))
last-matches
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 59164d7d50c..a869cdc5fdb 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -1067,11 +1067,28 @@ fontified."
"expression_statement"))
'font-lock-doc-face
'font-lock-string-face)))
- (when (eq (char-after string-beg) ?f)
- (cl-incf string-beg))
+ ;; Don't highlight string prefixes like f/r/b.
+ (save-excursion
+ (goto-char string-beg)
+ (when (search-forward "\"" string-end t)
+ (setq string-beg (match-beginning 0))))
(treesit-fontify-with-override
string-beg string-end face override start end)))
+(defun python--treesit-fontify-string-interpolation
+ (node _ start end &rest _)
+ "Fontify string interpolation.
+NODE is the string node. Do not fontify the initial f for
+f-strings. START and END mark the region to be
+fontified."
+ ;; This is kind of a hack, it basically removes the face applied by
+ ;; the string feature, so that following features can apply their
+ ;; face.
+ (let ((n-start (treesit-node-start node))
+ (n-end (treesit-node-end node)))
+ (remove-text-properties
+ (max start n-start) (min end n-end) '(face))))
+
(defvar python--treesit-settings
(treesit-font-lock-rules
:feature 'comment
@@ -1082,10 +1099,12 @@ fontified."
:language 'python
'((string) @python--treesit-fontify-string)
+ ;; HACK: This feature must come after the string feature and before
+ ;; other features. Maybe we should make string-interpolation an
+ ;; option rather than a feature.
:feature 'string-interpolation
:language 'python
- :override t
- '((interpolation (identifier) @font-lock-variable-name-face))
+ '((interpolation) @python--treesit-fontify-string-interpolation)
:feature 'definition
:language 'python
@@ -3766,15 +3785,16 @@ the python shell:
(line-beginning-position)
start))))
(substring (buffer-substring-no-properties start end))
- (starts-at-point-min-p (save-restriction
- (widen)
- (= (point-min) start)))
+ (starts-at-first-line-p (save-restriction
+ (widen)
+ (goto-char start)
+ (= (line-number-at-pos) 1)))
(encoding (python-info-encoding))
(toplevel-p (zerop (save-excursion
(goto-char start)
(python-util-forward-comment 1)
(current-indentation))))
- (fillstr (cond (starts-at-point-min-p
+ (fillstr (cond (starts-at-first-line-p
nil)
((not no-cookie)
(concat
@@ -6693,7 +6713,10 @@ implementations: `python-mode' and `python-ts-mode'."
(treesit-major-mode-setup)
(when python-indent-guess-indent-offset
- (python-indent-guess-indent-offset))))
+ (python-indent-guess-indent-offset))
+
+ (add-to-list 'auto-mode-alist
+ '("\\.py[iw]?\\'\\|python[0-9.]*" . python-ts-mode))))
;;; Completion predicates for M-x
;; Commands that only make sense when editing Python code
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index 14cdf0a1a26..dba9ff0a846 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -141,6 +141,81 @@ This should only be called after matching against `ruby-here-doc-beg-re'."
It should match the part after \"def\" and until \"=\".")
+(defconst ruby-builtin-methods-with-reqs
+ '( ;; built-in methods on Kernel
+ "at_exit"
+ "autoload"
+ "autoload?"
+ "callcc"
+ "catch"
+ "eval"
+ "exec"
+ "format"
+ "lambda"
+ "load"
+ "loop"
+ "open"
+ "p"
+ "printf"
+ "proc"
+ "putc"
+ "require"
+ "require_relative"
+ "spawn"
+ "sprintf"
+ "syscall"
+ "system"
+ "throw"
+ "trace_var"
+ "trap"
+ "untrace_var"
+ "warn"
+ ;; keyword-like private methods on Module
+ "alias_method"
+ "attr"
+ "attr_accessor"
+ "attr_reader"
+ "attr_writer"
+ "define_method"
+ "extend"
+ "include"
+ "module_function"
+ "prepend"
+ "private_class_method"
+ "private_constant"
+ "public_class_method"
+ "public_constant"
+ "refine"
+ "using")
+ "List of built-in methods that require at least one argument.")
+
+(defconst ruby-builtin-methods-no-reqs
+ '("__callee__"
+ "__dir__"
+ "__method__"
+ "abort"
+ "binding"
+ "block_given?"
+ "caller"
+ "exit"
+ "exit!"
+ "fail"
+ "fork"
+ "global_variables"
+ "local_variables"
+ "print"
+ "private"
+ "protected"
+ "public"
+ "puts"
+ "raise"
+ "rand"
+ "readline"
+ "readlines"
+ "sleep"
+ "srand")
+ "List of built-in methods that only have optional arguments.")
+
(defvar ruby-use-smie t)
(make-obsolete-variable 'ruby-use-smie nil "28.1")
@@ -261,7 +336,15 @@ Only has effect when `ruby-use-smie' is t."
"If non-nil, align chained method calls.
Each method call on a separate line will be aligned to the column
-of its parent.
+of its parent. Example:
+
+ my_array.select { |str| str.size > 5 }
+ .map { |str| str.downcase }
+
+When nil, each method call is indented with the usual offset:
+
+ my_array.select { |str| str.size > 5 }
+ .map { |str| str.downcase }
Only has effect when `ruby-use-smie' is t."
:type 'boolean
@@ -271,12 +354,26 @@ Only has effect when `ruby-use-smie' is t."
(defcustom ruby-method-params-indent t
"Indentation of multiline method parameters.
-When t, the parameters list is indented to the method name.
+When t, the parameters list is indented to the method name:
+
+ def foo(
+ baz,
+ bar
+ )
+ hello
+ end
When a number, indent the parameters list this many columns
against the beginning of the method (the \"def\" keyword).
-The value nil means the same as 0.
+The value nil means the same as 0:
+
+ def foo(
+ baz,
+ bar
+ )
+ hello
+ end
Only has effect when `ruby-use-smie' is t."
:type '(choice (const :tag "Indent to the method name" t)
@@ -899,24 +996,6 @@ This only affects the output of the command `ruby-toggle-block'."
(while (and (setq state (apply #'ruby-parse-partial end state))
(>= (nth 2 state) 0) (< (point) end))))))
-(defun ruby-mode-variables ()
- "Set up initial buffer-local variables for Ruby mode."
- (setq indent-tabs-mode ruby-indent-tabs-mode)
- (smie-setup ruby-smie-grammar #'ruby-smie-rules
- :forward-token #'ruby-smie--forward-token
- :backward-token #'ruby-smie--backward-token)
- (unless ruby-use-smie
- (setq-local indent-line-function #'ruby-indent-line))
- (setq-local comment-start "# ")
- (setq-local comment-end "")
- (setq-local comment-column ruby-comment-column)
- (setq-local comment-start-skip "#+ *")
- (setq-local parse-sexp-ignore-comments t)
- (setq-local parse-sexp-lookup-properties t)
- (setq-local paragraph-start (concat "$\\|" page-delimiter))
- (setq-local paragraph-separate paragraph-start)
- (setq-local paragraph-ignore-fill-prefix t))
-
(defun ruby--insert-coding-comment (encoding)
"Insert a magic coding comment for ENCODING.
The style of the comment is controlled by `ruby-encoding-magic-comment-style'."
@@ -1945,7 +2024,7 @@ If the result is do-end block, it will always be multiline."
(end-of-line)
(unless
(if (and (re-search-backward "\\(?:[^#]\\)\\({\\)\\|\\(\\_<do\\_>\\)")
- (progn
+ (let ((ruby-use-smie (and ruby-use-smie (consp smie-grammar))))
(goto-char (or (match-beginning 1) (match-beginning 2)))
(setq beg (point))
(with-suppressed-warnings ((obsolete ruby-forward-sexp))
@@ -2310,84 +2389,13 @@ It will be properly highlighted even when the call omits parens.")
;; Core methods that have required arguments.
(,(concat
ruby-font-lock-keyword-beg-re
- (regexp-opt
- '( ;; built-in methods on Kernel
- "at_exit"
- "autoload"
- "autoload?"
- "callcc"
- "catch"
- "eval"
- "exec"
- "format"
- "lambda"
- "load"
- "loop"
- "open"
- "p"
- "printf"
- "proc"
- "putc"
- "require"
- "require_relative"
- "spawn"
- "sprintf"
- "syscall"
- "system"
- "throw"
- "trace_var"
- "trap"
- "untrace_var"
- "warn"
- ;; keyword-like private methods on Module
- "alias_method"
- "attr"
- "attr_accessor"
- "attr_reader"
- "attr_writer"
- "define_method"
- "extend"
- "include"
- "module_function"
- "prepend"
- "private_class_method"
- "private_constant"
- "public_class_method"
- "public_constant"
- "refine"
- "using")
- 'symbols))
+ (regexp-opt ruby-builtin-methods-with-reqs 'symbols))
(1 (unless (looking-at " *\\(?:[]|,.)}=]\\|$\\)")
font-lock-builtin-face)))
;; Kernel methods that have no required arguments.
(,(concat
ruby-font-lock-keyword-beg-re
- (regexp-opt
- '("__callee__"
- "__dir__"
- "__method__"
- "abort"
- "binding"
- "block_given?"
- "caller"
- "exit"
- "exit!"
- "fail"
- "fork"
- "global_variables"
- "local_variables"
- "print"
- "private"
- "protected"
- "public"
- "puts"
- "raise"
- "rand"
- "readline"
- "readlines"
- "sleep"
- "srand")
- 'symbols))
+ (regexp-opt ruby-builtin-methods-no-reqs 'symbols))
(1 font-lock-builtin-face))
;; Here-doc beginnings.
(,ruby-here-doc-beg-re
@@ -2629,29 +2637,54 @@ If there is no Rubocop config file, Rubocop will be passed a flag
"Value for `prettify-symbols-alist' in `ruby-mode'.")
;;;###autoload
-(define-derived-mode ruby-mode prog-mode "Ruby"
- "Major mode for editing Ruby code."
- (ruby-mode-variables)
+(define-derived-mode ruby-base-mode prog-mode "Ruby"
+ "Generic major mode for editing Ruby.
- (setq-local imenu-create-index-function #'ruby-imenu-create-index)
- (setq-local add-log-current-defun-function #'ruby-add-log-current-method)
- (setq-local beginning-of-defun-function #'ruby-beginning-of-defun)
- (setq-local end-of-defun-function #'ruby-end-of-defun)
+This mode is intended to be inherited by concrete major modes.
+Currently there are `ruby-mode' and `ruby-ts-mode'."
+ (setq indent-tabs-mode ruby-indent-tabs-mode)
+
+ (setq-local comment-start "# ")
+ (setq-local comment-end "")
+ (setq-local comment-column ruby-comment-column)
+ (setq-local comment-start-skip "#+ *")
+
+ (setq-local parse-sexp-ignore-comments t)
+ (setq-local parse-sexp-lookup-properties t)
+
+ (setq-local paragraph-start (concat "$\\|" page-delimiter))
+ (setq-local paragraph-separate paragraph-start)
+ (setq-local paragraph-ignore-fill-prefix t)
;; `outline-regexp' contains the first part of `ruby-indent-beg-re'
(setq-local outline-regexp (concat "^\\s *"
(regexp-opt '("class" "module" "def"))
"\\_>"))
(setq-local outline-level (lambda () (1+ (/ (current-indentation)
- ruby-indent-level))))
+ ruby-indent-level))))
(add-hook 'after-save-hook #'ruby-mode-set-encoding nil 'local)
(add-hook 'electric-indent-functions #'ruby--electric-indent-p nil 'local)
(add-hook 'flymake-diagnostic-functions #'ruby-flymake-auto nil 'local)
+ (setq-local prettify-symbols-alist ruby--prettify-symbols-alist))
+
+;;;###autoload
+(define-derived-mode ruby-mode ruby-base-mode "Ruby"
+ "Major mode for editing Ruby code."
+ (smie-setup ruby-smie-grammar #'ruby-smie-rules
+ :forward-token #'ruby-smie--forward-token
+ :backward-token #'ruby-smie--backward-token)
+ (unless ruby-use-smie
+ (setq-local indent-line-function #'ruby-indent-line))
+
+ (setq-local imenu-create-index-function #'ruby-imenu-create-index)
+ (setq-local add-log-current-defun-function #'ruby-add-log-current-method)
+ (setq-local beginning-of-defun-function #'ruby-beginning-of-defun)
+ (setq-local end-of-defun-function #'ruby-end-of-defun)
+
(setq-local font-lock-defaults '((ruby-font-lock-keywords) nil nil
((?_ . "w"))))
- (setq-local prettify-symbols-alist ruby--prettify-symbols-alist)
(setq-local syntax-propertize-function #'ruby-syntax-propertize))
diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el
index 96596cb5daf..eff846f8585 100644
--- a/lisp/progmodes/ruby-ts-mode.el
+++ b/lisp/progmodes/ruby-ts-mode.el
@@ -5,6 +5,7 @@
;; Author: Perry Smith <pedz@easesoftware.com>
;; Created: December 2022
;; Keywords: ruby languages tree-sitter
+;; Version: 0.2
;; This file is part of GNU Emacs.
@@ -50,11 +51,12 @@
;; Currently tree treesit-font-lock-feature-list is set with the
;; following levels:
-;; 1: comment method-definition
+;; 1: comment method-definition parameter-definition
;; 2: keyword regexp string type
-;; 3: builtin constant delimiter escape-sequence
-;; global instance
-;; interpolation literal symbol variable
+;; 3: builtin-variable builtin-constant builtin-function
+;; delimiter escape-sequence
+;; constant global instance
+;; interpolation literal symbol assignment
;; 4: bracket error function operator punctuation
;; Thus if treesit-font-lock-level is set to level 3 which is its
@@ -70,6 +72,8 @@
;; ruby-ts-mode tries to adhere to the indentation related user
;; options from ruby-mode, such as ruby-indent-level,
;; ruby-indent-tabs-mode, and so on.
+;;
+;; Type 'M-x customize-group RET ruby RET' to see the options.
;; * IMenu
;; * Navigation
@@ -81,17 +85,22 @@
(require 'ruby-mode)
(declare-function treesit-parser-create "treesit.c")
+(declare-function treesit-induce-sparse-tree "treesit.c")
+(declare-function treesit-node-child-by-field-name "treesit.c")
+(declare-function treesit-search-subtree "treesit.c")
+(declare-function treesit-node-parent "treesit.c")
+(declare-function treesit-node-next-sibling "treesit.c")
+(declare-function treesit-node-type "treesit.c")
+(declare-function treesit-node-child "treesit.c")
+(declare-function treesit-node-end "treesit.c")
+(declare-function treesit-node-start "treesit.c")
+(declare-function treesit-node-string "treesit.c")
(defgroup ruby-ts nil
"Major mode for editing Ruby code."
:prefix "ruby-ts-"
:group 'languages)
-(defcustom ruby-ts-highlight-predefined-constants t
- "When non-nil, the pre-defined constants are highlighted.
-They will be highlighted the same way as the pre-defined variables."
- :type 'boolean)
-
(defvar ruby-ts--operators
'("+" "-" "*" "/" "%" "**"
"==" "!=" ">" "<" ">=" "<=" "<=>" "==="
@@ -108,21 +117,29 @@ They will be highlighted the same way as the pre-defined variables."
"Ruby's punctuation characters.")
(defvar ruby-ts--predefined-constants
- (rx (or "ARGF" "ARGV" "DATA" "ENV" "RUBY_COPYRIGHT"
+ (rx string-start
+ (or "ARGF" "ARGV" "DATA" "ENV" "RUBY_COPYRIGHT"
"RUBY_DESCRIPTION" "RUBY_ENGINE" "RUBY_ENGINE_VERSION"
"RUBY_PATCHLEVEL" "RUBY_PLATFORM" "RUBY_RELEASE_DATE"
"RUBY_REVISION" "RUBY_VERSION" "STDERR" "STDIN" "STDOUT"
- "TOPLEVEL_BINDING"))
- "Ruby predefined global constants.
-These are currently unused")
+ "TOPLEVEL_BINDING")
+ string-end)
+ "Ruby predefined global constants.")
(defvar ruby-ts--predefined-variables
- (rx (or "$!" "$@" "$~" "$&" "$‘" "$‘" "$+" "$=" "$/" "$\\" "$," "$;"
+ (rx string-start
+ (or "$!" "$@" "$~" "$&" "$`" "$'" "$+" "$=" "$/" "$\\" "$," "$;"
"$." "$<" "$>" "$_" "$*" "$$" "$?" "$:" "$LOAD_PATH"
"$LOADED_FEATURES" "$DEBUG" "$FILENAME" "$stderr" "$stdin"
"$stdout" "$VERBOSE" "$-a" "$-i" "$-l" "$-p"
- (seq "$" (+ digit))))
- "Ruby global variables (but not global constants.")
+ "$0" "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9")
+ string-end)
+ "Ruby predefined global variables.")
+
+(defvar ruby-ts--builtin-methods
+ (format "\\`%s\\'" (regexp-opt (append ruby-builtin-methods-no-reqs
+ ruby-builtin-methods-with-reqs)))
+ "Ruby built-in methods.")
(defconst ruby-ts--class-or-module-regex
(rx string-start
@@ -147,7 +164,6 @@ These are currently unused")
"then"
"ensure"
"body_statement"
- "parenthesized_statements"
"interpolation")
string-end)
"Regular expression of the nodes that can contain statements.")
@@ -193,6 +209,9 @@ values of OVERRIDE"
(treesit-fontify-with-override (max plus-1 start) (min node-end end)
font-lock-comment-face override)))
+(defun ruby-ts--builtin-method-p (node)
+ (string-match-p ruby-ts--builtin-methods (treesit-node-text node t)))
+
(defun ruby-ts--font-lock-settings (language)
"Tree-sitter font-lock settings for Ruby."
(treesit-font-lock-rules
@@ -201,29 +220,24 @@ values of OVERRIDE"
'((comment) @ruby-ts--comment-font-lock)
:language language
- :feature 'builtin
- `(((global_variable) @var (:match ,ruby-ts--predefined-variables @var)) @font-lock-builtin-face
- ,@(when ruby-ts-highlight-predefined-constants
- `(((constant) @var (:match ,ruby-ts--predefined-constants @var)) @font-lock-builtin-face)))
+ :feature 'builtin-variable
+ `(((global_variable) @var (:match ,ruby-ts--predefined-variables @var)) @font-lock-builtin-face)
:language language
- :feature 'keyword
- `([,@ruby-ts--keywords] @font-lock-keyword-face)
+ :feature 'builtin-constant
+ `(((constant) @var (:match ,ruby-ts--predefined-constants @var)) @font-lock-builtin-face)
:language language
- :feature 'constant
- '((true) @font-lock-doc-markup-face
- (false) @font-lock-doc-markup-face
- (nil) @font-lock-doc-markup-face
- (self) @font-lock-doc-markup-face
- (super) @font-lock-doc-markup-face)
+ :feature 'keyword
+ `([,@ruby-ts--keywords] @font-lock-keyword-face
+ (self) @font-lock-keyword-face
+ (super) @font-lock-keyword-face)
:language language
- :feature 'symbol
- '((bare_symbol) @font-lock-constant-face
- (delimited_symbol (string_content) @font-lock-constant-face)
- (hash_key_symbol) @font-lock-constant-face
- (simple_symbol) @font-lock-constant-face)
+ :feature 'constant
+ '((true) @font-lock-constant-face
+ (false) @font-lock-constant-face
+ (nil) @font-lock-constant-face)
;; Before 'operator so (unary) works.
:language language
@@ -237,10 +251,8 @@ values of OVERRIDE"
;; Also before 'operator because % and / are operators
:language language
:feature 'regexp
- ;; TODO: We probably need a separate face for regexps everywhere.
- ;; Maybe another one for regexp delimiters as well.
- '((regex "/" @font-lock-string-face)
- (regex _ (string_content) @font-lock-string-face))
+ '((regex "/" @font-lock-regexp-face)
+ (regex _ (string_content) @font-lock-regexp-face))
:language language
:feature 'operator
@@ -269,8 +281,8 @@ values of OVERRIDE"
:language language
:feature 'interpolation
- '((interpolation "#{" @font-lock-delimiter-face)
- (interpolation "}" @font-lock-delimiter-face))
+ '((interpolation "#{" @font-lock-misc-punctuation-face)
+ (interpolation "}" @font-lock-misc-punctuation-face))
:language language
:feature 'type
@@ -293,6 +305,43 @@ values of OVERRIDE"
(method
name: (setter) @font-lock-function-name-face))
+ :language language
+ :feature 'parameter-definition
+ '((method_parameters
+ (identifier) @font-lock-variable-name-face)
+ (block_parameters
+ (identifier) @font-lock-variable-name-face)
+ (optional_parameter
+ name: (identifier) @font-lock-variable-name-face)
+ (splat_parameter
+ name: (identifier) @font-lock-variable-name-face)
+ (hash_splat_parameter
+ name: (identifier) @font-lock-variable-name-face)
+ (block_parameter
+ name: (identifier) @font-lock-variable-name-face)
+ (destructured_parameter
+ (identifier) @font-lock-variable-name-face)
+ (lambda_parameters
+ (identifier) @font-lock-variable-name-face)
+ (exception_variable
+ (identifier) @font-lock-variable-name-face)
+ (array_pattern
+ (identifier) @font-lock-variable-name-face)
+ (keyword_pattern
+ value: (identifier) @font-lock-variable-name-face)
+ (keyword_pattern
+ key: (hash_key_symbol) @font-lock-variable-name-face
+ !value)
+ (as_pattern
+ name: (identifier) @font-lock-variable-name-face)
+ (in_clause
+ pattern: (identifier) @font-lock-variable-name-face))
+
+ :language language
+ :feature 'builtin-function
+ `((((identifier) @font-lock-builtin-face)
+ (:pred ruby-ts--builtin-method-p @font-lock-builtin-face)))
+
;; Yuan recommends also putting method definitions into the
;; 'function' category (thus keeping it in both). I've opted to
;; just use separate categories for them -- dgutov.
@@ -302,6 +351,22 @@ values of OVERRIDE"
method: (identifier) @font-lock-function-name-face))
:language language
+ :feature 'assignment
+ '((assignment
+ left: (identifier) @font-lock-variable-name-face)
+ (assignment
+ left: (left_assignment_list (identifier) @font-lock-variable-name-face))
+ (operator_assignment
+ left: (identifier) @font-lock-variable-name-face))
+
+ :language language
+ :feature 'symbol
+ '((bare_symbol) @font-lock-constant-face
+ (delimited_symbol (string_content) @font-lock-constant-face)
+ (hash_key_symbol) @font-lock-constant-face
+ (simple_symbol) @font-lock-constant-face)
+
+ :language language
:feature 'error
'((ERROR) @font-lock-warning-face)
@@ -355,8 +420,11 @@ Otherwise return start of PRED."
(lambda (node parent bol &rest rest)
(let* ((pred-node (funcall pred node parent bol rest))
(temp (treesit-node-start pred-node))
- (keyword (treesit-node-type pred-node))
- (bol (ruby-smie--indent-to-stmt-p keyword)))
+ (type (treesit-node-type pred-node))
+ (bol (ruby-smie--indent-to-stmt-p
+ (if (equal type "method")
+ "def"
+ type))))
(when temp
(if bol
(save-excursion
@@ -463,10 +531,6 @@ array or hash."
(first-child (ruby-ts--first-non-comment-child parent)))
(= (ruby-ts--lineno open-brace) (ruby-ts--lineno first-child))))
-(defun ruby-ts--assignment-ancestor (node &rest _)
- "Return the assignment ancestor of NODE if any."
- (treesit-parent-until node (ruby-ts--type-pred "\\`assignment\\'")))
-
(defun ruby-ts--statement-ancestor (node &rest _)
"Return the statement ancestor of NODE if any.
A statement is defined as a child of a statement container where
@@ -482,26 +546,6 @@ a statement container is a node that matches
parent (treesit-node-parent parent)))
statement))
-(defun ruby-ts--is-in-condition (node &rest _)
- "Return the condition node if NODE is within a condition."
- (while (and node
- (not (equal "condition" (treesit-node-field-name node)))
- (not (string-match-p ruby-ts--statement-container-regexp
- (treesit-node-type node))))
- (setq node (treesit-node-parent node)))
- (and (equal "condition" (treesit-node-field-name node)) node))
-
-(defun ruby-ts--endless-method (node &rest _)
- "Return the expression node if NODE is in an endless method.
-i.e. expr of def foo(args) = expr is returned."
- (let* ((method node))
- (while (and method
- (not (string-match-p ruby-ts--method-regex (treesit-node-type method))))
- (setq method (treesit-node-parent method)))
- (when method
- (if (equal "=" (treesit-node-type (treesit-node-child method 3 nil)))
- (treesit-node-child method 4 nil)))))
-
;;
;; end of functions that can be used for queries
;;
@@ -511,7 +555,7 @@ i.e. expr of def foo(args) = expr is returned."
(let ((common
`(
;; Slam all top level nodes to the left margin
- ((parent-is "program") parent 0)
+ ((parent-is "program") point-min 0)
;; Do not indent here docs or the end. Not sure why it
;; takes the grand-parent but ok fine.
@@ -538,11 +582,11 @@ i.e. expr of def foo(args) = expr is returned."
;;
;; I'm using very restrictive patterns hoping to reduce rules
;; triggering unintentionally.
- ((match "else" "if")
+ ((match "else" "if\\|unless")
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
((match "elsif" "if")
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
- ((match "end" "if")
+ ((match "end" "if\\|unless")
(ruby-ts--align-keywords ruby-ts--parent-node) 0)
((n-p-gp nil "then\\|else\\|elsif" "if\\|unless")
(ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level)
@@ -615,11 +659,15 @@ i.e. expr of def foo(args) = expr is returned."
;; else the second query aligns
;; `ruby-indent-level' spaces in from the parent.
((and ruby-ts--align-chain-p (match "\\." "call")) ruby-ts--align-chain 0)
+ ;; Obery ruby-method-call-indent, whether the dot is on
+ ;; this line or the previous line.
+ ((and (not ruby-ts--method-call-indent-p)
+ (or
+ (match "\\." "call")
+ (query "(call \".\" (identifier) @indent)")))
+ (ruby-ts--bol ruby-ts--statement-ancestor) ruby-indent-level)
((match "\\." "call") parent ruby-indent-level)
- ;; ruby-indent-after-block-in-continued-expression
- ((match "begin" "assignment") parent ruby-indent-level)
-
;; method parameters -- four styles:
;; 1) With paren, first arg on same line:
((and (query "(method_parameters \"(\" _ @indent)")
@@ -648,31 +696,36 @@ i.e. expr of def foo(args) = expr is returned."
;; 2) With paren, 1st arg on next line
((and (query "(argument_list \"(\" _ @indent)")
(node-is ")"))
- (ruby-ts--bol ruby-ts--grand-parent-node) 0)
- ((query "(argument_list \"(\" _ @indent)")
- (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
+ ruby-ts--parent-call-or-bol 0)
+ ((or (query "(argument_list \"(\" _ @indent)")
+ ;; No arguments yet; NODE is nil in that case.
+ (match "\\`\\'" "argument_list"))
+ ruby-ts--parent-call-or-bol ruby-indent-level)
;; 3) No paren, ruby-parenless-call-arguments-indent is t
((and ruby-ts--parenless-call-arguments-indent-p (parent-is "argument_list"))
first-sibling 0)
;; 4) No paren, ruby-parenless-call-arguments-indent is nil
- ((parent-is "argument_list") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
+ ((parent-is "argument_list")
+ (ruby-ts--bol ruby-ts--statement-ancestor) ruby-indent-level)
;; Old... probably too simple
((parent-is "block_parameters") first-sibling 1)
- ((and (parent-is "binary")
- (or ruby-ts--assignment-ancestor
- ruby-ts--is-in-condition
- ruby-ts--endless-method))
- first-sibling 0)
+ ((and (not ruby-ts--after-op-indent-p)
+ (parent-is "binary\\|conditional"))
+ (ruby-ts--bol ruby-ts--statement-ancestor) ruby-indent-level)
+
+ ((parent-is "binary")
+ ruby-ts--binary-indent-anchor 0)
+
+ ((parent-is "conditional") parent ruby-indent-level)
;; ruby-mode does not touch these...
((match "bare_string" "string_array") no-indent 0)
- ;; hash and array other than assignments. Note that the
- ;; first sibling is the "{" or "[". There is a special
- ;; case where the hash is an argument to a method. These
- ;; need to be processed first.
+ ;; hash and array. Note that the first sibling is the "{"
+ ;; or "[". There is a special case where the hash is an
+ ;; argument to a method. These need to be processed first.
((and ruby-ts--same-line-hash-array-p (match "}" "hash"))
first-sibling 0)
@@ -683,37 +736,15 @@ i.e. expr of def foo(args) = expr is returned."
((and ruby-ts--same-line-hash-array-p (parent-is "array"))
(nth-sibling 0 ruby-ts--true) 0)
- ;; NOTE to folks trying to understand my insanity...
- ;; I having trouble understanding the "logic" of why things
- ;; are indented like they are so I am adding special cases
- ;; hoping at some point I will be struck by lightning.
- ((and (n-p-gp "}" "hash" "pair")
- (not ruby-ts--same-line-hash-array-p))
- grand-parent 0)
- ((and (n-p-gp "pair" "hash" "pair")
- (not ruby-ts--same-line-hash-array-p))
- grand-parent ruby-indent-level)
- ((and (n-p-gp "}" "hash" "method")
- (not ruby-ts--same-line-hash-array-p))
- grand-parent 0)
- ((and (n-p-gp "pair" "hash" "method")
- (not ruby-ts--same-line-hash-array-p))
- grand-parent ruby-indent-level)
-
- ((n-p-gp "}" "hash" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) 0)
- ((n-p-gp nil "hash" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
- ((n-p-gp "]" "array" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) 0)
- ((n-p-gp nil "array" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
-
- ((n-p-gp "}" "hash" "argument_list") first-sibling 0)
- ((n-p-gp nil "hash" "argument_list") first-sibling ruby-indent-level)
- ((n-p-gp "]" "array" "argument_list") first-sibling 0)
- ((n-p-gp nil "array" "argument_list") first-sibling ruby-indent-level)
-
- ((match "}" "hash") first-sibling 0)
- ((parent-is "hash") first-sibling ruby-indent-level)
- ((match "]" "array") first-sibling 0)
- ((parent-is "array") first-sibling ruby-indent-level)
+ ((match "}" "hash") ruby-ts--parent-call-or-bol 0)
+ ((parent-is "hash") ruby-ts--parent-call-or-bol ruby-indent-level)
+ ((match "]" "array") ruby-ts--parent-call-or-bol 0)
+ ((parent-is "array") ruby-ts--parent-call-or-bol ruby-indent-level)
+
+ ((parent-is "pair") ruby-ts--parent-call-or-bol 0)
+
+ ((match ")" "parenthesized_statements") parent-bol 0)
+ ((parent-is "parenthesized_statements") parent-bol ruby-indent-level)
;; If the previous method isn't finished yet, this will get
;; the next method indented properly.
@@ -731,12 +762,20 @@ i.e. expr of def foo(args) = expr is returned."
;; but with node set to the statement and parent set to
;; body_statement for all others. ... Fine. Be that way.
;; Ditto for "block" and "block_body"
- ((node-is "body_statement") parent-bol ruby-indent-level)
- ((parent-is "body_statement") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
- ((match "end" "do_block") parent-bol 0)
- ((n-p-gp "block_body" "block" nil) parent-bol ruby-indent-level)
- ((n-p-gp nil "block_body" "block") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
- ((match "}" "block") (ruby-ts--bol ruby-ts--grand-parent-node) 0)
+ ((node-is "body_statement")
+ (ruby-ts--block-indent-anchor ruby-ts--parent-node)
+ ruby-indent-level)
+ ((parent-is "body_statement")
+ (ruby-ts--block-indent-anchor ruby-ts--grand-parent-node)
+ ruby-indent-level)
+ ((match "end" "do_block") (ruby-ts--block-indent-anchor ruby-ts--parent-node) 0)
+ ((n-p-gp "block_body" "block" nil)
+ (ruby-ts--block-indent-anchor ruby-ts--parent-node)
+ ruby-indent-level)
+ ((n-p-gp nil "block_body" "block")
+ (ruby-ts--block-indent-anchor ruby-ts--grand-parent-node)
+ ruby-indent-level)
+ ((match "}" "block") (ruby-ts--block-indent-anchor ruby-ts--parent-node) 0)
;; Chained strings
((match "string" "chained_string") first-sibling 0)
@@ -745,6 +784,78 @@ i.e. expr of def foo(args) = expr is returned."
(catch-all parent-bol ruby-indent-level))))
`((ruby . ,common))))
+(defun ruby-ts--block-indent-anchor (block-node-getter)
+ (lambda (node parent _bol &rest _rest)
+ (let ((block-node (funcall block-node-getter node parent)))
+ (save-excursion
+ (goto-char
+ (treesit-node-start
+ (if ruby-block-indent
+ (ruby-ts--statement-ancestor block-node)
+ block-node)))
+ (back-to-indentation)
+ (point)))))
+
+(defun ruby-ts--binary-indent-anchor (_node parent _bol &rest _)
+ (save-excursion
+ (goto-char (treesit-node-start parent))
+ (when (string-match-p ruby-ts--statement-container-regexp
+ (treesit-node-type (treesit-node-parent parent)))
+ ;; Hack alert: it's not the proper place to alter the offset.
+ ;; Redoing the analysis in the OFFSET form seems annoying,
+ ;; though. (**)
+ (forward-char ruby-indent-level))
+ (point)))
+
+(defun ruby-ts--parent-call-or-bol (_not parent _bol &rest _)
+ (let* ((parent-bol (save-excursion
+ (goto-char (treesit-node-start parent))
+ (back-to-indentation)
+ (point)))
+ (found
+ (treesit-parent-until
+ parent
+ (lambda (node)
+ (or (< (treesit-node-start node) parent-bol)
+ (string-match-p "\\`array\\|hash\\'" (treesit-node-type node))
+ ;; Method call on same line.
+ (equal (treesit-node-type node) "argument_list"))))))
+ (cond
+ ((null found)
+ parent-bol)
+ ;; No paren/curly/brace found on the same line.
+ ((< (treesit-node-start found) parent-bol)
+ parent-bol)
+ ;; Hash or array opener on the same line.
+ ((string-match-p "\\`array\\|hash\\'" (treesit-node-type found))
+ (save-excursion
+ (goto-char (treesit-node-start (treesit-node-child found 1)))
+ (point)))
+ ;; Parenless call found: indent to stmt with offset.
+ ((not ruby-parenless-call-arguments-indent)
+ (save-excursion
+ (goto-char (treesit-node-start
+ (ruby-ts--statement-ancestor found)))
+ ;; (**) Same.
+ (+ (point) ruby-indent-level)))
+ ;; Call with parens -- ident to first arg.
+ ((equal (treesit-node-type (treesit-node-child found 0))
+ "(")
+ (save-excursion
+ (goto-char (treesit-node-start (treesit-node-child found 1)))
+ (point)))
+ ;; Indent to the parenless call args beginning.
+ (t
+ (save-excursion
+ (goto-char (treesit-node-start found))
+ (point))))))
+
+(defun ruby-ts--after-op-indent-p (&rest _)
+ ruby-after-operator-indent)
+
+(defun ruby-ts--method-call-indent-p (&rest _)
+ ruby-method-call-indent)
+
(defun ruby-ts--class-or-module-p (node)
"Predicate if NODE is a class or module."
(string-match-p ruby-ts--class-or-module-regex (treesit-node-type node)))
@@ -847,7 +958,12 @@ The hash (#) is for instance methods only which are methods
dot (.) is used. Double colon (::) is used between classes. The
leading double colon is not added."
(let* ((node (treesit-node-at (point)))
- (method (treesit-parent-until node (ruby-ts--type-pred ruby-ts--method-regex)))
+ (method-pred
+ (lambda (node)
+ (and (<= (treesit-node-start node) (point))
+ (>= (treesit-node-end node) (point))
+ (string-match-p ruby-ts--method-regex (treesit-node-type node)))))
+ (method (treesit-parent-until node method-pred t))
(class (or method node))
(result nil)
(sep "#")
@@ -895,21 +1011,11 @@ leading double colon is not added."
"C-c C-f" #'ruby-find-library-file)
;;;###autoload
-(define-derived-mode ruby-ts-mode prog-mode "Ruby"
+(define-derived-mode ruby-ts-mode ruby-base-mode "Ruby"
"Major mode for editing Ruby, powered by tree-sitter."
:group 'ruby
:syntax-table ruby-mode-syntax-table
- (setq indent-tabs-mode ruby-indent-tabs-mode)
-
- (setq-local paragraph-start (concat "$\\|" page-delimiter))
- (setq-local paragraph-separate paragraph-start)
- (setq-local paragraph-ignore-fill-prefix t)
-
- (setq-local comment-start "# ")
- (setq-local comment-end "")
- (setq-local comment-start-skip "#+ *")
-
(unless (treesit-ready-p 'ruby)
(error "Tree-sitter for Ruby isn't available"))
@@ -932,16 +1038,30 @@ leading double colon is not added."
(setq-local treesit-font-lock-settings (ruby-ts--font-lock-settings 'ruby))
;; Level 3 is the default.
(setq-local treesit-font-lock-feature-list
- '(( comment method-definition )
+ '(( comment method-definition parameter-definition)
( keyword regexp string type)
- ( builtin constant
- delimiter escape-sequence global
- instance
- interpolation literal symbol variable)
+ ( builtin-variable builtin-constant builtin-function
+ delimiter escape-sequence
+ constant global instance
+ interpolation literal symbol assignment)
( bracket error function operator punctuation)))
(treesit-major-mode-setup))
+(if (treesit-ready-p 'ruby)
+ ;; Copied from ruby-mode.el.
+ (add-to-list 'auto-mode-alist
+ (cons (concat "\\(?:\\.\\(?:"
+ "rbw?\\|ru\\|rake\\|thor"
+ "\\|jbuilder\\|rabl\\|gemspec\\|podspec"
+ "\\)"
+ "\\|/"
+ "\\(?:Gem\\|Rake\\|Cap\\|Thor"
+ "\\|Puppet\\|Berks\\|Brew"
+ "\\|Vagrant\\|Guard\\|Pod\\)file"
+ "\\)\\'")
+ 'ruby-ts-mode)))
+
(provide 'ruby-ts-mode)
;;; ruby-ts-mode.el ends here
diff --git a/lisp/progmodes/rust-ts-mode.el b/lisp/progmodes/rust-ts-mode.el
index 7536726165e..3a6cb61b719 100644
--- a/lisp/progmodes/rust-ts-mode.el
+++ b/lisp/progmodes/rust-ts-mode.el
@@ -29,7 +29,7 @@
(require 'treesit)
(eval-when-compile (require 'rx))
-(require 'c-ts-mode) ; For comment indent and filling.
+(require 'c-ts-common) ; For comment indent and filling.
(declare-function treesit-parser-create "treesit.c")
(declare-function treesit-induce-sparse-tree "treesit.c")
@@ -71,8 +71,8 @@
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
((node-is "}") (and parent parent-bol) 0)
- ((and (parent-is "comment") c-ts-mode--looking-at-star)
- c-ts-mode--comment-start-after-first-star -1)
+ ((and (parent-is "comment") c-ts-common-looking-at-star)
+ c-ts-common-comment-start-after-first-star -1)
((parent-is "comment") prev-adaptive-prefix 0)
((parent-is "arguments") parent-bol rust-ts-mode-indent-offset)
((parent-is "await_expression") parent-bol rust-ts-mode-indent-offset)
@@ -276,9 +276,6 @@ Return nil if there is no name or if NODE is not a defun node."
(treesit-node-child-by-field-name node "name") t))))
;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))
-
-;;;###autoload
(define-derived-mode rust-ts-mode prog-mode "Rust"
"Major mode for editing Rust, powered by tree-sitter."
:group 'rust
@@ -288,7 +285,7 @@ Return nil if there is no name or if NODE is not a defun node."
(treesit-parser-create 'rust)
;; Comments.
- (c-ts-mode-comment-setup)
+ (c-ts-common-comment-setup)
;; Font-lock.
(setq-local treesit-font-lock-settings rust-ts-mode--font-lock-settings)
@@ -322,6 +319,9 @@ Return nil if there is no name or if NODE is not a defun node."
(treesit-major-mode-setup)))
+(if (treesit-ready-p 'rust)
+ (add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode)))
+
(provide 'rust-ts-mode)
;;; rust-ts-mode.el ends here
diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el
index e0583f4b05c..34030968806 100644
--- a/lisp/progmodes/typescript-ts-mode.el
+++ b/lisp/progmodes/typescript-ts-mode.el
@@ -30,7 +30,7 @@
(require 'treesit)
(require 'js)
(eval-when-compile (require 'rx))
-(require 'c-ts-mode) ; For comment indent and filling.
+(require 'c-ts-common) ; For comment indent and filling.
(declare-function treesit-parser-create "treesit.c")
@@ -69,13 +69,13 @@
"Rules used for indentation.
Argument LANGUAGE is either `typescript' or `tsx'."
`((,language
- ((parent-is "program") parent-bol 0)
+ ((parent-is "program") point-min 0)
((node-is "}") parent-bol 0)
((node-is ")") parent-bol 0)
((node-is "]") parent-bol 0)
((node-is ">") parent-bol 0)
- ((and (parent-is "comment") c-ts-mode--looking-at-star)
- c-ts-mode--comment-start-after-first-star -1)
+ ((and (parent-is "comment") c-ts-common-looking-at-star)
+ c-ts-common-comment-start-after-first-star -1)
((parent-is "comment") prev-adaptive-prefix 0)
((parent-is "ternary_expression") parent-bol typescript-ts-mode-indent-offset)
((parent-is "member_expression") parent-bol typescript-ts-mode-indent-offset)
@@ -97,13 +97,15 @@ Argument LANGUAGE is either `typescript' or `tsx'."
((parent-is "binary_expression") parent-bol typescript-ts-mode-indent-offset)
,@(when (eq language 'tsx)
- `(((node-is "jsx_fragment") parent typescript-ts-mode-indent-offset)
- ((node-is "jsx_element") parent typescript-ts-mode-indent-offset)
- ((node-is "jsx_expression") parent typescript-ts-mode-indent-offset)
- ((node-is "jsx_self_closing_element") parent typescript-ts-mode-indent-offset)
+ `(((match "<" "jsx_fragment") parent 0)
+ ((parent-is "jsx_fragment") parent typescript-ts-mode-indent-offset)
((node-is "jsx_closing_element") parent 0)
- ((node-is "/") parent 0)
- ((node-is ">") parent 0)))
+ ((node-is "jsx_element") parent typescript-ts-mode-indent-offset)
+ ((parent-is "jsx_element") parent typescript-ts-mode-indent-offset)
+ ((parent-is "jsx_opening_element") parent typescript-ts-mode-indent-offset)
+ ((parent-is "jsx_expression") parent-bol typescript-ts-mode-indent-offset)
+ ((match "/" "jsx_self_closing_element") parent 0)
+ ((parent-is "jsx_self_closing_element") parent typescript-ts-mode-indent-offset)))
(no-node parent-bol 0))))
(defvar typescript-ts-mode--keywords
@@ -151,10 +153,10 @@ Argument LANGUAGE is either `typescript' or `tsx'."
:language language
:override t
:feature 'string
- `((regex pattern: (regex_pattern)) @font-lock-string-face
+ `((regex pattern: (regex_pattern)) @font-lock-regexp-face
(string) @font-lock-string-face
(template_string) @js--fontify-template-string
- (template_substitution ["${" "}"] @font-lock-builtin-face))
+ (template_substitution ["${" "}"] @font-lock-misc-punctuation-face))
:language language
:override t
@@ -194,7 +196,13 @@ Argument LANGUAGE is either `typescript' or `tsx'."
name: (array_pattern
(identifier)
(identifier) @font-lock-function-name-face)
- value: (array (number) (function))))
+ value: (array (number) (function)))
+
+ (catch_clause
+ parameter: (identifier) @font-lock-variable-name-face)
+
+ (import_clause (identifier) @font-lock-variable-name-face)
+ (import_clause (named_imports (import_specifier (identifier)) @font-lock-variable-name-face)))
:language language
:override t
@@ -223,17 +231,7 @@ Argument LANGUAGE is either `typescript' or `tsx'."
parameters:
[(_ (identifier) @font-lock-variable-name-face)
(_ (_ (identifier) @font-lock-variable-name-face))
- (_ (_ (_ (identifier) @font-lock-variable-name-face)))])
-
- (return_statement (identifier) @font-lock-variable-name-face)
-
- (binary_expression left: (identifier) @font-lock-variable-name-face)
- (binary_expression right: (identifier) @font-lock-variable-name-face)
-
- (arguments (identifier) @font-lock-variable-name-face)
-
- (parenthesized_expression (identifier) @font-lock-variable-name-face)
- (parenthesized_expression (_ (identifier) @font-lock-variable-name-face)))
+ (_ (_ (_ (identifier) @font-lock-variable-name-face)))]))
:language language
:override t
@@ -245,8 +243,6 @@ Argument LANGUAGE is either `typescript' or `tsx'."
(pair key: (property_identifier) @font-lock-variable-name-face)
- (pair value: (identifier) @font-lock-variable-name-face)
-
((shorthand_property_identifier) @font-lock-property-face)
((shorthand_property_identifier_pattern)
@@ -319,19 +315,13 @@ Argument LANGUAGE is either `typescript' or `tsx'."
'((escape_sequence) @font-lock-escape-face)))
;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))
-
-;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode))
-
-;;;###autoload
(define-derived-mode typescript-ts-base-mode prog-mode "TypeScript"
"Major mode for editing TypeScript."
:group 'typescript
:syntax-table typescript-ts-mode--syntax-table
;; Comments.
- (c-ts-mode-comment-setup)
+ (c-ts-common-comment-setup)
;; Electric
(setq-local electric-indent-chars
@@ -379,6 +369,9 @@ Argument LANGUAGE is either `typescript' or `tsx'."
(treesit-major-mode-setup)))
+(if (treesit-ready-p 'typescript)
+ (add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode)))
+
;;;###autoload
(define-derived-mode tsx-ts-mode typescript-ts-base-mode "TypeScript[TSX]"
"Major mode for editing TypeScript."
@@ -414,6 +407,9 @@ Argument LANGUAGE is either `typescript' or `tsx'."
(treesit-major-mode-setup)))
+(if (treesit-ready-p 'tsx)
+ (add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode)))
+
(provide 'typescript-ts-mode)
;;; typescript-ts-mode.el ends here
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index d5cee9fa84f..916d83d407b 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -1,7 +1,7 @@
;;; xref.el --- Cross-referencing commands -*-lexical-binding:t-*-
;; Copyright (C) 2014-2023 Free Software Foundation, Inc.
-;; Version: 1.6.0
+;; Version: 1.6.1
;; Package-Requires: ((emacs "26.1"))
;; This is a GNU ELPA :core package. Avoid functionality that is not
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
(defvar-keymap read-regexp-map
:parent minibuffer-local-map
- "M-c" #'read-regexp-toggle-case-folding)
+ "M-s c" #'read-regexp-toggle-case-fold)
(defvar read-regexp--case-fold nil)
-(defun read-regexp-toggle-case-folding ()
+(defun read-regexp-toggle-case-fold ()
(interactive)
(setq read-regexp--case-fold
(if (or (eq read-regexp--case-fold 'fold)
@@ -875,7 +875,7 @@ in \":\", followed by optional whitespace), DEFAULT is added to the prompt.
The optional argument HISTORY is a symbol to use for the history list.
If nil, use `regexp-history'.
-If the user has used the \\<read-regexp-map>\\[read-regexp-toggle-case-folding] command to specify case
+If the user has used the \\<read-regexp-map>\\[read-regexp-toggle-case-fold] command to specify case
sensitivity, the returned string will have a text property named
`case-fold' that has a value of either `fold' or
`inhibit-fold'. (It's up to the caller of `read-regexp' to
diff --git a/lisp/simple.el b/lisp/simple.el
index 63479e9ce0a..aaad3217982 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -2207,15 +2207,39 @@ to get different commands to edit and resubmit."
"Predicate to use to determine which commands to include when completing.
If it's nil, include all the commands.
If it's a function, it will be called with two parameters: the
-symbol of the command and a buffer. The predicate should return
-non-nil if the command should be present when doing \\`M-x TAB'
-in that buffer."
+symbol of the command and the current buffer. The predicate should
+return non-nil if the command should be considered as a completion
+candidate for \\`M-x' in that buffer.
+
+Several predicate functions suitable for various optional behaviors
+are available:
+
+ `command-completion-default-include-p'
+ This excludes from completion candidates those commands
+ which have been marked specific to modes other than the
+ current buffer's mode. Commands that are not specific
+ to any mode are included.
+
+ `command-completion-using-modes-p'
+ This includes in completion candidates only commands
+ marked as specific to the current buffer's mode.
+
+ `command-completion-using-modes-and-keymaps-p'
+ This includes commands marked as specific to the current
+ buffer's modes and commands that have keybindings in the
+ current buffer's active local keymaps. It also includes
+ several commands, like Customize commands, which should
+ always be available."
:version "28.1"
:group 'completion
:type '(choice (const :tag "Don't exclude any commands" nil)
(const :tag "Exclude commands irrelevant to current buffer's mode"
command-completion-default-include-p)
- (function :tag "Other function")))
+ (const :tag "Include only commands relevant to current buffer's mode"
+ command-completion-using-modes-p)
+ (const :tag "Commands relevant to current buffer's mode or bound in its keymaps"
+ command-completion-using-modes-and-keymaps-p)
+ (function :tag "Other predicate function")))
(defun execute-extended-command-cycle ()
"Choose the next version of the extended command predicates.
@@ -2401,6 +2425,35 @@ or (if one of MODES is a minor mode), if it is switched on in BUFFER."
#'eq)
(seq-intersection modes global-minor-modes #'eq)))
+(defun command-completion-using-modes-and-keymaps-p (symbol buffer)
+ "Return non-nil if SYMBOL is marked for BUFFER's mode or bound in its keymaps."
+ (with-current-buffer buffer
+ (let ((keymaps
+ ;; The major mode's keymap and any active minor modes.
+ (nconc
+ (and (current-local-map) (list (current-local-map)))
+ (mapcar
+ #'cdr
+ (seq-filter
+ (lambda (elem)
+ (symbol-value (car elem)))
+ minor-mode-map-alist)))))
+ (or (command-completion-using-modes-p symbol buffer)
+ ;; Include commands that are bound in a keymap in the
+ ;; current buffer.
+ (and (where-is-internal symbol keymaps)
+ ;; But not if they have a command predicate that
+ ;; says that they shouldn't. (This is the case
+ ;; for `ignore' and `undefined' and similar
+ ;; commands commonly found in keymaps.)
+ (or (null (get symbol 'completion-predicate))
+ (funcall (get symbol 'completion-predicate)
+ symbol buffer)))
+ ;; Include customize-* commands (do we need a list of such
+ ;; "always available" commands? customizable?)
+ (string-match-p "customize-" (symbol-name symbol))))))
+
+
(defun command-completion-button-p (category buffer)
"Return non-nil if there's a button of CATEGORY at point in BUFFER."
(with-current-buffer buffer
@@ -2502,7 +2555,11 @@ Also see `suggest-key-bindings'."
(defun execute-extended-command (prefixarg &optional command-name typed)
"Read a command name, then read the arguments and call the command.
To pass a prefix argument to the command you are
-invoking, give a prefix argument to `execute-extended-command'."
+invoking, give a prefix argument to `execute-extended-command'.
+
+This command provides completion when reading the command name.
+Which completion candidates are shown can be controlled by
+customizing `read-extended-command-predicate'."
(declare (interactive-only command-execute))
;; FIXME: Remember the actual text typed by the user before completion,
;; so that we don't later on suggest the same shortening.
@@ -9665,7 +9722,11 @@ the completions is popped up and down."
"Move to the first item in the completion list."
(interactive)
(goto-char (point-min))
- (unless (get-text-property (point) 'mouse-face)
+ (if (get-text-property (point) 'mouse-face)
+ (unless (get-text-property (point) 'first-completion)
+ (let ((inhibit-read-only t))
+ (add-text-properties (point) (min (1+ (point)) (point-max))
+ '(first-completion t))))
(when-let ((pos (next-single-property-change (point) 'mouse-face)))
(goto-char pos))))
@@ -9698,6 +9759,14 @@ Also see the `completion-auto-wrap' variable."
(let ((tabcommand (member (this-command-keys) '("\t" [backtab])))
pos)
(catch 'bound
+ (when (and (bobp)
+ (> n 0)
+ (get-text-property (point) 'mouse-face)
+ (not (get-text-property (point) 'first-completion)))
+ (let ((inhibit-read-only t))
+ (add-text-properties (point) (1+ (point)) '(first-completion t)))
+ (setq n (1- n)))
+
(while (> n 0)
(setq pos (point))
;; If in a completion, move to the end of it.
@@ -10317,7 +10386,7 @@ call `normal-erase-is-backspace-mode' (which see) instead."
(if (if (eq normal-erase-is-backspace 'maybe)
(and (not noninteractive)
(or (memq system-type '(ms-dos windows-nt))
- (memq window-system '(w32 ns pgtk))
+ (memq window-system '(w32 ns pgtk haiku))
(and (eq window-system 'x)
(fboundp 'x-backspace-delete-keys-p)
(x-backspace-delete-keys-p))
diff --git a/lisp/sqlite-mode.el b/lisp/sqlite-mode.el
index 83762b61943..c3047c786f7 100644
--- a/lisp/sqlite-mode.el
+++ b/lisp/sqlite-mode.el
@@ -55,10 +55,14 @@
(interactive "fSQLite file name: ")
(unless (sqlite-available-p)
(error "This Emacs doesn't have SQLite support, so it can't view SQLite files"))
+ (if (file-remote-p file)
+ (error "Remote SQLite files are not yet supported"))
(pop-to-buffer (get-buffer-create
(format "*SQLite %s*" (file-name-nondirectory file))))
(sqlite-mode)
(setq-local sqlite--db (sqlite-open file))
+ (unless (sqlitep sqlite--db)
+ (error "`sqlite-open' failed to open SQLite file"))
(sqlite-mode-list-tables))
(defun sqlite-mode-list-tables ()
diff --git a/lisp/startup.el b/lisp/startup.el
index 115f0e4937f..bbcf60556ae 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -1609,7 +1609,7 @@ please check its value")
(display-warning 'initialization
(format-message "\
Your `load-path' seems to contain\n\
-your `.emacs.d' directory: %s\n\
+your `user-emacs-directory': %s\n\
This is likely to cause problems...\n\
Consider using a subdirectory instead, e.g.: %s"
dir (expand-file-name
diff --git a/lisp/subr.el b/lisp/subr.el
index 9087f9a4044..0f754fcd31f 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -2540,11 +2540,13 @@ The variable list SPEC is the same as in `if-let'."
Evaluate each binding in turn, stopping if a binding value is nil.
If all bindings are non-nil, eval BODY and repeat.
-The variable list SPEC is the same as in `if-let'."
+The variable list SPEC is the same as in `if-let*'."
(declare (indent 1) (debug if-let))
(let ((done (gensym "done")))
`(catch ',done
(while t
+ ;; This is `if-let*', not `if-let', deliberately, despite the
+ ;; name of this macro. See bug#60758.
(if-let* ,spec
(progn
,@body)
@@ -3535,8 +3537,7 @@ character. This is not possible when using `read-key', but using
Return t if answer is \"y\" and nil if it is \"n\".
PROMPT is the string to display to ask the question; `y-or-n-p'
-adds \" (y or n) \" to it. It does not need to end in space, but
-if it does up to one space will be removed.
+adds \"(y or n) \" to it.
If you bind the variable `help-form' to a non-nil value
while calling this function, then pressing `help-char'
@@ -4947,13 +4948,13 @@ the function `undo--wrap-and-run-primitive-undo'."
(progn
(while (and (not (eq (cdr ptr) old-bul))
;; In case garbage collection has removed OLD-BUL.
- (cdr ptr)
- ;; Don't include a timestamp entry.
- (not (and (consp (cdr ptr))
- (consp (cadr ptr))
- (eq (caadr ptr) t)
- (setq old-bul (cdr ptr)))))
- (setq ptr (cdr ptr)))
+ (cdr ptr))
+ (if (and (consp (cdr ptr))
+ (consp (cadr ptr))
+ (eq (caadr ptr) t))
+ ;; Don't include a timestamp entry.
+ (setcdr ptr (cddr ptr))
+ (setq ptr (cdr ptr))))
(unless (cdr ptr)
(message "combine-change-calls: buffer-undo-list broken"))
(setcdr ptr nil)
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index 8991610a50f..a1d7d4bbbec 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -1827,7 +1827,9 @@ can also be used to fill comments.
(setq-local treesit-simple-imenu-settings
`(( nil ,(rx bos (or "rule_set" "media_statement") eos)
nil nil)))
- (treesit-major-mode-setup)))
+ (treesit-major-mode-setup)
+
+ (add-to-list 'auto-mode-alist '("\\.css\\'" . css-ts-mode))))
;;;###autoload
(define-derived-mode css-mode css-base-mode "CSS"
diff --git a/lisp/textmodes/reftex-cite.el b/lisp/textmodes/reftex-cite.el
index 77373707d65..6beae816257 100644
--- a/lisp/textmodes/reftex-cite.el
+++ b/lisp/textmodes/reftex-cite.el
@@ -636,7 +636,7 @@ command, it will add another key, ignoring the value of
The regular expression uses an expanded syntax: && is interpreted as `and'.
Thus, `aaaa&&bbb' matches entries which contain both `aaaa' and `bbb'.
-While entering the regexp, completion on knows citation keys is possible.
+While entering the regexp, completion on known citation keys is possible.
`=' is a good regular expression to match all entries in all files."
(interactive)
diff --git a/lisp/textmodes/toml-ts-mode.el b/lisp/textmodes/toml-ts-mode.el
index 1b68632f58c..416542084f1 100644
--- a/lisp/textmodes/toml-ts-mode.el
+++ b/lisp/textmodes/toml-ts-mode.el
@@ -118,9 +118,6 @@ Return nil if there is no name or if NODE is not a defun node."
"Root table"))))
;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode))
-
-;;;###autoload
(define-derived-mode toml-ts-mode text-mode "TOML"
"Major mode for editing TOML, powered by tree-sitter."
:group 'toml-mode
@@ -156,6 +153,9 @@ Return nil if there is no name or if NODE is not a defun node."
(treesit-major-mode-setup)))
+(if (treesit-ready-p 'toml)
+ (add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode)))
+
(provide 'toml-ts-mode)
;;; toml-ts-mode.el ends here
diff --git a/lisp/textmodes/yaml-ts-mode.el b/lisp/textmodes/yaml-ts-mode.el
index 8c61ee062cf..a25230e6e61 100644
--- a/lisp/textmodes/yaml-ts-mode.el
+++ b/lisp/textmodes/yaml-ts-mode.el
@@ -118,9 +118,6 @@
"Tree-sitter font-lock settings for `yaml-ts-mode'.")
;;;###autoload
-(add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-ts-mode))
-
-;;;###autoload
(define-derived-mode yaml-ts-mode text-mode "YAML"
"Major mode for editing YAML, powered by tree-sitter."
:group 'yaml
@@ -146,6 +143,9 @@
(treesit-major-mode-setup)))
+(if (treesit-ready-p 'yaml)
+ (add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-ts-mode)))
+
(provide 'yaml-ts-mode)
;;; yaml-ts-mode.el ends here
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 1ca72af5c2d..660039cc7cc 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -302,9 +302,15 @@ properties."
(defun treesit-parent-until (node pred &optional include-node)
"Return the closest parent of NODE that satisfies PRED.
-Return nil if none was found. PRED should be a function that
-takes one argument, the parent node, and return non-nil/nil for
-match/no match.
+This function successively examines the parent of NODE, then
+the parent of the parent, etc., until it finds the first
+ancestor node which satisfies the predicate PRED; then it
+returns that ancestor node. It returns nil if no ancestor
+node was found that satisfies PRED.
+
+PRED should be a function that takes one argument, the node to
+examine, and returns a boolean value indicating whether that
+node is a match.
If INCLUDE-NODE is non-nil, return NODE if it satisfies PRED."
(let ((node (if include-node node
@@ -315,8 +321,16 @@ If INCLUDE-NODE is non-nil, return NODE if it satisfies PRED."
(defun treesit-parent-while (node pred)
"Return the furthest parent of NODE that satisfies PRED.
-Return nil if none was found. PRED should be a function that
-takes one argument, the parent node."
+
+This function successively examines the parent of NODE, then
+the parent of the parent, etc., until it finds an ancestor node
+which no longer satisfies the predicate PRED; it returns the last
+examined ancestor that satisfies PRED. It returns nil if no
+ancestor node was found that satisfies PRED.
+
+PRED should be a function that takes one argument, the node to
+examine, and returns a boolean value indicating whether that
+node is a match."
(let ((last nil))
(while (and node (funcall pred node))
(setq last node
@@ -891,6 +905,14 @@ This is not a general optimization and should be RARELY needed!
See comments in `treesit-font-lock-fontify-region' for more
detail.")
+(defvar-local treesit--font-lock-fast-mode-grace-count 5
+ "Grace counts before we turn on the fast mode.
+
+When query takes abnormally long time to execute, we turn on the
+\"fast mode\", but just to be on the safe side, we only turn on
+the fast mode after this number of offenses. See bug#60691,
+bug#60223.")
+
;; Some details worth explaining:
;;
;; 1. When we apply face to a node, we clip the face into the
@@ -913,13 +935,13 @@ detail.")
;; parse it into a enormously tall tree (10k levels tall). In that
;; case querying the root node is very slow. So we try to get
;; top-level nodes and query them. This ensures that querying is fast
-;; everywhere else, except for the problematic region.
+;; everywhere else, except for the problematic region. (Bug#59415).
;;
;; Some other time the source file has a top-level node that contains
-;; a huge number of children (say, 10k children), querying that node
-;; is also very slow, so instead of getting the top-level node, we
-;; recursively go down the tree to find nodes that cover the region
-;; but are reasonably small.
+;; a huge number of immediate children (say, 10k children), querying
+;; that node is also very slow, so instead of getting the top-level
+;; node, we recursively go down the tree to find nodes that cover the
+;; region but are reasonably small. (Bug#59738).
;;
;; 3. It is possible to capture a node that's completely outside the
;; region between START and END: as long as the whole pattern
@@ -927,8 +949,8 @@ detail.")
;; returned. If the node is outside of that region, (max node-start
;; start) and friends return bad values, so we filter them out.
;; However, we don't filter these nodes out if a function will process
-;; the node, because could (and often do) fontify the relatives of the
-;; captured node, not just the node itself. If we took out those
+;; the node, because it could (and often do) fontify the relatives of
+;; the captured node, not just the node itself. If we took out those
;; nodes author of those functions would be very confused.
(defun treesit-font-lock-fontify-region (start end &optional loudly)
"Fontify the region between START and END.
@@ -965,9 +987,13 @@ If LOUDLY is non-nil, display some debugging information."
(end-time (current-time)))
;; If for any query the query time is strangely long,
;; switch to fast mode (see comments above).
- (when (> (time-to-seconds (time-subtract end-time start-time))
- 0.01)
- (setq-local treesit--font-lock-fast-mode t))
+ (when (and (null treesit--font-lock-fast-mode)
+ (> (time-to-seconds
+ (time-subtract end-time start-time))
+ 0.01))
+ (if (> treesit--font-lock-fast-mode-grace-count 0)
+ (cl-decf treesit--font-lock-fast-mode-grace-count)
+ (setq-local treesit--font-lock-fast-mode t)))
;; For each captured node, fontify that node.
(with-silent-modifications
@@ -1077,10 +1103,12 @@ See `treesit-simple-indent-presets'.")
(string-match-p
parent-t (treesit-node-type parent)))
(or (null grand-parent-t)
- (string-match-p
- grand-parent-t
- (treesit-node-type
- (treesit-node-parent parent))))))))
+ (and
+ (treesit-node-parent parent)
+ (string-match-p
+ grand-parent-t
+ (treesit-node-type
+ (treesit-node-parent parent)))))))))
(cons 'no-node (lambda (node &rest _) (null node)))
(cons 'parent-is (lambda (type)
(lambda (_n parent &rest _)
@@ -1129,20 +1157,19 @@ See `treesit-simple-indent-presets'.")
(point))))
(cons 'prev-adaptive-prefix
(lambda (_n parent &rest _)
- (save-excursion
- (re-search-backward
- (rx (not (or " " "\t" "\n"))) nil t)
- (beginning-of-line)
- (and (>= (point) (treesit-node-start parent))
- ;; `adaptive-fill-regexp' will not match "/*",
- ;; so we need to also try `comment-start-skip'.
- (or (and adaptive-fill-regexp
- (looking-at adaptive-fill-regexp)
- (> (- (match-end 0) (match-beginning 0)) 0)
- (match-end 0))
- (and comment-start-skip
- (looking-at comment-start-skip)
- (match-end 0)))))))
+ (let ((comment-start-bol
+ (save-excursion
+ (goto-char (treesit-node-start parent))
+ (line-beginning-position))))
+ (save-excursion
+ (forward-line -1)
+ (and (>= (point) comment-start-bol)
+ adaptive-fill-regexp
+ (looking-at adaptive-fill-regexp)
+ ;; If previous line is an empty line, don't
+ ;; indent.
+ (not (looking-at (rx (* whitespace) eol)))
+ (match-end 0))))))
;; TODO: Document.
(cons 'grand-parent
(lambda (_n parent &rest _)
@@ -1165,16 +1192,20 @@ See `treesit-simple-indent-presets'.")
;; TODO: Document.
(cons 'and (lambda (&rest fns)
(lambda (node parent bol &rest _)
- (cl-reduce (lambda (a b) (and a b))
- (mapcar (lambda (fn)
- (funcall fn node parent bol))
- fns)))))
+ (let (res)
+ (catch 'break
+ (dolist (fn fns)
+ (setq res (funcall fn node parent bol))
+ (unless res (throw 'break t))))
+ res))))
(cons 'or (lambda (&rest fns)
(lambda (node parent bol &rest _)
- (cl-reduce (lambda (a b) (or a b))
- (mapcar (lambda (fn)
- (funcall fn node parent bol))
- fns)))))
+ (let (res)
+ (catch 'break
+ (dolist (fn fns)
+ (setq res (funcall fn node parent bol))
+ (and res (throw 'break t))))
+ res))))
(cons 'not (lambda (fn)
(lambda (node parent bol &rest _)
(not (funcall fn node parent bol)))))
@@ -1288,8 +1319,7 @@ the function."
(cdr exp))))
;; Presets override functions, so this condition comes before
;; `functionp'.
- ((alist-get exp treesit-simple-indent-presets)
- (alist-get exp treesit-simple-indent-presets))
+ ((alist-get exp treesit-simple-indent-presets))
((functionp exp) exp)
((symbolp exp)
(if (null exp)
@@ -1324,10 +1354,10 @@ and returns
(ANCHOR . OFFSET).
BOL is the position of the beginning of the line; NODE is the
-\"largest\" node that starts at BOL; PARENT is its parent; ANCHOR
-is a point (not a node), and OFFSET is a number. Emacs finds the
-column of ANCHOR and adds OFFSET to it as the final indentation
-of the current line.")
+\"largest\" node that starts at BOL (and isn't a root node);
+PARENT is its parent; ANCHOR is a point (not a node), and OFFSET
+is a number. Emacs finds the column of ANCHOR and adds OFFSET to
+it as the final indentation of the current line.")
(defun treesit--indent-1 ()
"Indent the current line.
@@ -1345,10 +1375,13 @@ Return (ANCHOR . OFFSET). This function is used by
((treesit-language-at (point))
(treesit-node-at bol (treesit-language-at (point))))
(t (treesit-node-at bol))))
+ (root (treesit-parser-root-node
+ (treesit-node-parser smallest-node)))
(node (treesit-parent-while
smallest-node
(lambda (node)
- (eq bol (treesit-node-start node))))))
+ (and (eq bol (treesit-node-start node))
+ (not (treesit-node-eq node root)))))))
(let*
((parser (if smallest-node
(treesit-node-parser smallest-node)
@@ -1494,10 +1527,15 @@ OFFSET."
return
(let ((anchor-pos
(treesit--simple-indent-eval
- (list anchor node parent bol))))
- (cons anchor-pos (if (symbolp offset)
- (symbol-value offset)
- offset)))
+ (list anchor node parent bol)))
+ (offset-val
+ (cond ((numberp offset) offset)
+ ((and (symbolp offset)
+ (boundp offset))
+ (symbol-value offset))
+ (t (treesit--simple-indent-eval
+ (list offset node parent bol))))))
+ (cons anchor-pos offset-val))
finally return
(progn (when treesit--indent-verbose
(message "No matched rule"))
@@ -1534,6 +1572,10 @@ RULES."
(pcase func
(`(query ,qry)
(list 'query (treesit-query-compile lang qry)))
+ (`(and . ,fns)
+ (cons 'and (mapcar #'optimize-func fns)))
+ (`(or . ,fns)
+ (cons 'or (mapcar #'optimize-func fns)))
(_ func)))
;; Optimize a rule (MATCHER ANCHOR OFFSET).
(optimize-rule (rule)
@@ -2391,11 +2433,15 @@ in the region."
(window-start) (window-end) treesit--explorer-language))
;; Only highlight the current top-level construct.
;; Highlighting the whole buffer is slow and unnecessary.
- (top-level (treesit-node-first-child-for-pos
- root (if (eolp)
- (max (point-min) (1- (point)))
- (point))
- t))
+ ;; But if the buffer is small (ie, used in playground
+ ;; style), just highlight the whole buffer.
+ (top-level (if (< (buffer-size) 4000)
+ root
+ (treesit-node-first-child-for-pos
+ root (if (eolp)
+ (max (point-min) (1- (point)))
+ (point))
+ t)))
;; Only highlight node when region is active, if we
;; highlight node at point the syntax tree is too jumpy.
(nodes-hl
@@ -2575,6 +2621,11 @@ leaves point at the end of the last line of NODE."
(when (not named)
(overlay-put ov 'face 'treesit-explorer-anonymous-node)))))
+(defun treesit--explorer-kill-explorer-buffer ()
+ "Kill the explorer buffer of this buffer."
+ (when (buffer-live-p treesit--explorer-buffer)
+ (kill-buffer treesit--explorer-buffer)))
+
(define-derived-mode treesit--explorer-tree-mode special-mode
"TS Explorer"
"Mode for displaying syntax trees for `treesit-explore-mode'."
@@ -2586,30 +2637,46 @@ Pops up a window showing the syntax tree of the source in the
current buffer in real time. The corresponding node enclosing
the text in the active region is highlighted in the explorer
window."
- :lighter " TSplay"
+ :lighter " TSexplore"
(if treesit-explore-mode
- (progn
- (unless (buffer-live-p treesit--explorer-buffer)
- (setq-local treesit--explorer-buffer
- (get-buffer-create
- (format "*tree-sitter explorer for %s*"
- (buffer-name))))
- (setq-local treesit--explorer-language
- (intern (completing-read
+ (let ((language (intern (completing-read
"Language: "
(mapcar #'treesit-parser-language
- (treesit-parser-list)))))
- (with-current-buffer treesit--explorer-buffer
- (treesit--explorer-tree-mode)))
- (display-buffer treesit--explorer-buffer
- (cons nil '((inhibit-same-window . t))))
- (treesit--explorer-refresh)
- (add-hook 'post-command-hook
- #'treesit--explorer-post-command 0 t)
- (setq-local treesit--explorer-last-node nil))
+ (treesit-parser-list))))))
+ (if (not (treesit-language-available-p language))
+ (user-error "Cannot find tree-sitter grammar for %s: %s"
+ language (cdr (treesit-language-available-p
+ language t)))
+ ;; Create explorer buffer.
+ (unless (buffer-live-p treesit--explorer-buffer)
+ (setq-local treesit--explorer-buffer
+ (get-buffer-create
+ (format "*tree-sitter explorer for %s*"
+ (buffer-name))))
+ (setq-local treesit--explorer-language language)
+ (with-current-buffer treesit--explorer-buffer
+ (treesit--explorer-tree-mode)))
+ (display-buffer treesit--explorer-buffer
+ (cons nil '((inhibit-same-window . t))))
+ (treesit--explorer-refresh)
+ ;; Setup variables and hooks.
+ (add-hook 'post-command-hook
+ #'treesit--explorer-post-command 0 t)
+ (add-hook 'kill-buffer-hook
+ #'treesit--explorer-kill-explorer-buffer 0 t)
+ (setq-local treesit--explorer-last-node nil)
+ ;; Tell `desktop-save' to not save explorer buffers.
+ (when (boundp 'desktop-modes-not-to-save)
+ (unless (memq 'treesit--explorer-tree-mode
+ desktop-modes-not-to-save)
+ (push 'treesit--explorer-tree-mode
+ desktop-modes-not-to-save)))))
+ ;; Turn off explore mode.
(remove-hook 'post-command-hook
#'treesit--explorer-post-command t)
- (kill-buffer treesit--explorer-buffer)))
+ (remove-hook 'post-command-hook
+ #'treesit--explorer-kill-explorer-buffer t)
+ (treesit--explorer-kill-explorer-buffer)))
;;; Install & build language grammar
@@ -2633,7 +2700,7 @@ CC and C++ are C and C++ compilers, defaulting to \"cc\" and
\"c++\", respectively.")
(defun treesit--install-language-grammar-build-recipe (lang)
- "Interactively build a recipe for LANG and return it.
+ "Interactively produce a download/build recipe for LANG and return it.
See `treesit-language-source-alist' for details."
(when (y-or-n-p (format "There is no recipe for %s, do you want to build it interactively?" lang))
(cl-labels ((empty-string-to-nil (string)
@@ -2655,9 +2722,14 @@ See `treesit-language-source-alist' for details."
(read-string
"Enter the C++ compiler to use (default: auto-detect): "))))))
+;;;###autoload
(defun treesit-install-language-grammar (lang)
"Build and install the tree-sitter language grammar library for LANG.
+Interactively, if `treesit-language-source-alist' doesn't already
+have data for building the grammar for LANG, prompt for its
+repository URL and the C/C++ compiler to use.
+
This command requires Git, a C compiler and (sometimes) a C++ compiler,
and the linker to be installed and on PATH. It also requires that the
recipe for LANG exists in `treesit-language-source-alist'.
@@ -2909,8 +2981,8 @@ function signals an error."
:eg-result-string "#<treesit-node (init_declarator) in 5-10>")
- (treesit-first-child-for-pos
- :no-eval (treesit-first-child-for-pos node 1)
+ (treesit-node-first-child-for-pos
+ :no-eval (treesit-node-first-child-for-pos node 1)
:eg-result-string "#<treesit-node (primitive_type) in 1-4>")
(treesit-node-descendant-for-range
:no-eval (treesit-node-descendant-for-range node 2 3)
@@ -2984,11 +3056,11 @@ function signals an error."
:eg-result t)
- (treesit-field-name-for-child
- :no-eval (treesit-field-name-for-child node)
+ (treesit-node-field-name-for-child
+ :no-eval (treesit-node-field-name-for-child node)
:eg-result "body")
- (treesit-child-count
- :no-eval (treesit-child-count node)
+ (treesit-node-child-count
+ :no-eval (treesit-node-child-count node)
:eg-result 3)
diff --git a/lisp/use-package/use-package-core.el b/lisp/use-package/use-package-core.el
index 379e119b60f..7ab5bdc276f 100644
--- a/lisp/use-package/use-package-core.el
+++ b/lisp/use-package/use-package-core.el
@@ -65,7 +65,7 @@
:link '(custom-manual "(use-package) Top")
:version "29.1")
-(defconst use-package-version "2.4.4"
+(defconst use-package-version "2.4.5"
"This version of `use-package'.")
(defcustom use-package-keywords
diff --git a/lisp/use-package/use-package.el b/lisp/use-package/use-package.el
index 7682468522d..1b63a6d651a 100644
--- a/lisp/use-package/use-package.el
+++ b/lisp/use-package/use-package.el
@@ -5,7 +5,7 @@
;; Author: John Wiegley <johnw@newartisans.com>
;; Maintainer: John Wiegley <johnw@newartisans.com>
;; Created: 17 Jun 2012
-;; Version: 2.4.4
+;; Version: 2.4.5
;; Package-Requires: ((emacs "24.3") (bind-key "2.4"))
;; Keywords: dotemacs startup speed config package extensions
;; URL: https://github.com/jwiegley/use-package
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index acfd2c30f0c..eb01dede56e 100644
--- a/lisp/vc/diff-mode.el
+++ b/lisp/vc/diff-mode.el
@@ -485,17 +485,19 @@ use the face `diff-removed' for removed lines, and the face
;; if below, use `diff-added'.
(save-match-data
(let ((limit (save-excursion (diff-beginning-of-hunk))))
- (if (save-excursion (re-search-backward diff-context-mid-hunk-header-re limit t))
- diff-indicator-added-face
- diff-indicator-removed-face)))))
+ (when (< limit (point))
+ (if (save-excursion (re-search-backward diff-context-mid-hunk-header-re limit t))
+ diff-indicator-added-face
+ diff-indicator-removed-face))))))
(2 (if diff-use-changed-face
'diff-changed-unspecified
;; Otherwise, use the same method as above.
(save-match-data
(let ((limit (save-excursion (diff-beginning-of-hunk))))
- (if (save-excursion (re-search-backward diff-context-mid-hunk-header-re limit t))
- 'diff-added
- 'diff-removed))))))
+ (when (< limit (point))
+ (if (save-excursion (re-search-backward diff-context-mid-hunk-header-re limit t))
+ 'diff-added
+ 'diff-removed)))))))
("^\\(?:Index\\|revno\\): \\(.+\\).*\n"
(0 'diff-header) (1 'diff-index prepend))
("^\\(?:index .*\\.\\.\\|diff \\).*\n" . 'diff-header)
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'."
(define-key map "U" #'vc-dir-unmark-all-files)
(define-key map "\C-?" #'vc-dir-unmark-file-up)
(define-key map "\M-\C-?" #'vc-dir-unmark-all-files)
- (define-key map "%" #'vc-dir-mark-by-regexp)
;; Movement.
(define-key map "n" #'vc-dir-next-line)
(define-key map " " #'vc-dir-next-line)
@@ -361,8 +360,13 @@ See `run-hooks'."
(define-key branch-map "l" #'vc-print-branch-log)
(define-key branch-map "s" #'vc-switch-branch))
+ (let ((regexp-map (make-sparse-keymap)))
+ (define-key map "%" regexp-map)
+ (define-key regexp-map "m" #'vc-dir-mark-by-regexp))
+
(let ((mark-map (make-sparse-keymap)))
(define-key map "*" mark-map)
+ (define-key mark-map "%" #'vc-dir-mark-by-regexp)
(define-key mark-map "r" #'vc-dir-mark-registered-files))
;; Hook up the menu.
@@ -791,7 +795,7 @@ MARK-FILES should be a list of absolute filenames."
vc-ewoc))
(defun vc-dir-mark-registered-files ()
- "Mark files that are in one of registered state: edited, added or removed."
+ "Mark files that are in one of registered states: edited, added or removed."
(interactive)
(vc-dir-mark-state-files '(edited added removed)))
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 7413ecb79b1..04aa37d6400 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -992,6 +992,8 @@ It is based on `log-edit-mode', and has Git-specific extensions."
(let ((vc-git-patch-string patch-string))
(vc-git-checkin nil comment)))
+(autoload 'vc-switches "vc")
+
(defun vc-git-checkin (files comment &optional _rev)
(let* ((file1 (or (car files) default-directory))
(root (vc-git-root file1))
@@ -1021,7 +1023,14 @@ It is based on `log-edit-mode', and has Git-specific extensions."
;; currently staged to the index. So remove the whole file diff
;; from the patch because commit will take it from the index.
(with-temp-buffer
- (vc-git-command (current-buffer) t nil "diff" "--cached")
+ ;; If the user has switches like -D, -M etc. in their
+ ;; `vc-git-diff-switches', we must pass them here too, or
+ ;; our string matches will fail.
+ (if vc-git-diff-switches
+ (apply #'vc-git-command (current-buffer) t nil
+ "diff" "--cached" (vc-switches 'git 'diff))
+ ;; Following code doesn't understand plain diff(1) output.
+ (user-error "Cannot commit patch with nil `vc-git-diff-switches'"))
(goto-char (point-min))
(let ((pos (point)) file-diff file-beg)
(while (not (eobp))
@@ -1173,25 +1182,6 @@ Normally, this runs \"git push\". If PROMPT is non-nil, prompt
for the Git command to run."
(vc-git--pushpull "push" prompt nil))
-(defun vc-git-pull-and-push (prompt)
- "Pull changes into the current Git branch, and then push.
-The push will only be performed if the pull was successful.
-
-Normally, this runs \"git pull\". If PROMPT is non-nil, prompt
-for the Git command to run."
- (let ((proc (vc-git--pushpull "pull" prompt '("--stat"))))
- (when (process-buffer proc)
- (with-current-buffer (process-buffer proc)
- (if (and (eq (process-status proc) 'exit)
- (zerop (process-exit-status proc)))
- (let ((vc--inhibit-async-window t))
- (vc-git-push nil))
- (vc-exec-after
- (lambda ()
- (let ((vc--inhibit-async-window t))
- (vc-git-push nil)))
- proc))))))
-
(defun vc-git-merge-branch ()
"Merge changes into the current Git branch.
This prompts for a branch to merge from."
@@ -1291,8 +1281,6 @@ This prompts for a branch to merge from."
:type 'boolean
:version "26.1")
-(autoload 'vc-switches "vc")
-
(defun vc-git-print-log (files buffer &optional shortlog start-revision limit)
"Print commit log associated with FILES into specified BUFFER.
If SHORTLOG is non-nil, use a short format based on `vc-git-root-log-format'.
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index f105461b210..d4a3280f1bd 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -3071,9 +3071,20 @@ It also signals an error in a Bazaar bound branch."
(interactive "P")
(let* ((vc-fileset (vc-deduce-fileset t))
(backend (car vc-fileset)))
- (if (vc-find-backend-function backend 'pull-and-push)
- (vc-call-backend backend 'pull-and-push arg)
- (user-error "VC pull-and-push is unsupported for `%s'" backend))))
+ (if (vc-find-backend-function backend 'pull)
+ (let ((proc (vc-call-backend backend 'pull arg)))
+ (when (and (processp proc) (process-buffer proc))
+ (with-current-buffer (process-buffer proc)
+ (if (and (eq (process-status proc) 'exit)
+ (zerop (process-exit-status proc)))
+ (let ((vc--inhibit-async-window t))
+ (vc-push arg))
+ (vc-exec-after
+ (lambda ()
+ (let ((vc--inhibit-async-window t))
+ (vc-push arg)))
+ proc)))))
+ (user-error "VC pull is unsupported for `%s'" backend))))
(defun vc-version-backup-file (file &optional rev)
"Return name of backup file for revision REV of FILE.
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index 798db9f9dd2..60bd2baa6fb 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -2220,7 +2220,9 @@ But if NO-TRUNCATE is non-nil, include them."
(if (widget-get current :inline)
(setq val value
fun :match-inline)
- (setq val (car value)
+ (setq val (if (consp value)
+ (car value)
+ value)
fun :match))
(setq val value
fun :match))
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."
(defun split-window-below (&optional size window-to-split)
"Split WINDOW-TO-SPLIT into two windows, one above the other.
-WINDOW-TO-SPLIT is above. The newly split-off window is
+WINDOW-TO-SPLIT defaults to the selected window and and will be above
+the other window after splitting. The newly split-off window is
below and displays the same buffer. Return the new window.
If optional argument SIZE is omitted or nil, both windows get the
@@ -5691,7 +5692,9 @@ amount of redisplay; this is convenient on slow terminals."
;; `split-window' would not signal an error here.
(error "Size of new window too small"))
(setq new-window (split-window window-to-split size))
- (unless split-window-keep-point
+ (when (and (null split-window-keep-point)
+ (or (null window-to-split)
+ (eq window-to-split (selected-window))))
(with-current-buffer (window-buffer window-to-split)
;; Use `save-excursion' around vertical movements below
;; (Bug#10971). Note: When WINDOW-TO-SPLIT's buffer has a
@@ -5732,8 +5735,9 @@ handled as in `split-window-below'."
(defun split-window-right (&optional size window-to-split)
"Split WINDOW-TO-SPLIT into two side-by-side windows.
-WINDOW-TO-SPLIT is on the left. The newly split-off window is on
-the right and displays the same buffer. Return the new window.
+WINDOW-TO-SPLIT defaults to the selected window and and will be on the
+left after splitting. The newly split-off window is on the right and
+displays the same buffer. Return the new window.
If optional argument SIZE is omitted or nil, both windows get the
same width, or close to it. If SIZE is positive, the left-hand
diff --git a/lisp/woman.el b/lisp/woman.el
index dfb5e69778f..92cd425d32f 100644
--- a/lisp/woman.el
+++ b/lisp/woman.el
@@ -2355,7 +2355,7 @@ Currently set only from \\='\\\" t in the first line of the source file.")
(point-max)))
(defun woman-horizontal-escapes (to)
- "Process \\h'+/-N' local horizontal motion escapes upto TO.
+ "Process \\h'+/-N' local horizontal motion escapes up to TO.
Implements arbitrary forward and non-overlapping backward motion.
Preserves location of `point'."
;; Moved from `woman-decode-region' for version 0.50.
@@ -3346,7 +3346,7 @@ Ignore the default face and underline only word characters."
(defun woman2-tr (to)
".tr abcde -- Translate a -> b, c -> d, ..., e -> space.
-Format paragraphs upto TO. Supports special chars.
+Format paragraphs up to TO. Supports special chars.
\(Breaks, but should not.)"
;; This should be an update, but consing onto the front of the alist
;; has the same effect and match duplicates should not matter.
@@ -3402,7 +3402,7 @@ Format paragraphs upto TO. Supports special chars.
(defvar woman-registers ; these are all read-only
'((".H" 24) (".V" 48) ; resolution in basic units
(".g" 0) ; not groff
- ;; (Iff emulating groff need to implement groff italic correction
+ ;; (If emulating groff need to implement groff italic correction
;; \/, e.g. for pic.1)
(".i" left-margin) ; current indent
(".j" woman-adjust) ; current adjustment
@@ -3432,7 +3432,7 @@ Handle numeric arguments specially if optional argument NUMERIC is non-nil."
(defun woman2-nr (to)
".nr R +/-N M -- Assign +/-N (wrt to previous value, if any) to register R.
The increment for auto-incrementing is set to M.
-Format paragraphs upto TO. (Breaks, but should not!)"
+Format paragraphs up to TO. (Breaks, but should not!)"
(let* ((name (buffer-substring
(point)
(progn (skip-syntax-forward "^ ") (point))))
@@ -3699,7 +3699,7 @@ regexp, \"\\(\\\\c\\)?\\n[.\\=']\"."
(defun woman2-PD (to)
".PD d -- Set the interparagraph distance to d.
-Round to whole lines, default 1 line. Format paragraphs upto TO.
+Round to whole lines, default 1 line. Format paragraphs up to TO.
\(Breaks, but should not.)"
;; .ie \\n[.$] .nr PD (v;\\$1)
;; .el .nr PD .4v>?\n[.V]
@@ -3718,7 +3718,7 @@ Round to whole lines, default 1 line. Format paragraphs upto TO.
(setq woman-leave-blank-lines woman-interparagraph-distance))
(defun woman2-TH (to)
- ".TH n c x v m -- Begin a man page. Format paragraphs upto TO.
+ ".TH n c x v m -- Begin a man page. Format paragraphs up to TO.
n is the name of the page in chapter c; x is extra commentary;
v alters page foot left; m alters page head center.
\(Should set prevailing indent and tabs to 5.)"
@@ -3748,7 +3748,7 @@ v alters page foot left; m alters page head center.
(defun woman2-SH (to)
".SH -- Sub-head. Leave blank line and subhead.
-Format paragraphs upto TO. Set prevailing indent to 5."
+Format paragraphs up to TO. Set prevailing indent to 5."
(if (eolp) ; If no args then
(delete-char 1) ; apply to next line
(woman-unquote-args) ; else unquote to end of heading
@@ -3767,7 +3767,7 @@ Format paragraphs upto TO. Set prevailing indent to 5."
(defun woman2-SS (to)
".SS -- Sub-sub-head. Like .SH but indent heading 3 spaces.
-Format paragraphs upto TO."
+Format paragraphs up to TO."
(if (eolp) ; If no args then
(delete-char 1)) ; apply to next line.
(insert " ")
@@ -3776,7 +3776,7 @@ Format paragraphs upto TO."
(defun woman2-LP (to)
".LP,.PP -- Begin paragraph. Set prevailing indent to 5.
-Leave 1 blank line. Format paragraphs upto TO."
+Leave 1 blank line. Format paragraphs up to TO."
(woman-delete-line 1) ; ignore any arguments
(woman-interparagraph-space)
(setq woman-prevailing-indent woman-default-indent)
@@ -3786,21 +3786,21 @@ Leave 1 blank line. Format paragraphs upto TO."
(defalias 'woman2-P #'woman2-LP)
(defun woman2-ns (to)
- ".ns -- Turn on no-space mode. Format paragraphs upto TO."
+ ".ns -- Turn on no-space mode. Format paragraphs up to TO."
;; Should not cause a break!
(woman-delete-line 1) ; ignore argument(s)
(setq woman-nospace t)
(woman2-format-paragraphs to))
(defun woman2-rs (to)
- ".rs -- Turn off no-space mode. Format paragraphs upto TO."
+ ".rs -- Turn off no-space mode. Format paragraphs up to TO."
;; Should not cause a break!
(woman-delete-line 1) ; ignore argument(s)
(setq woman-nospace nil)
(woman2-format-paragraphs to))
(defun woman2-sp (to)
- ".sp N -- If N > 0 then leave 1 blank line. Format paragraphs upto TO."
+ ".sp N -- If N > 0 then leave 1 blank line. Format paragraphs up to TO."
(let ((N (if (eolp) 1 (woman-get-numeric-arg))))
(if (>= N 0)
(woman-delete-line 1) ; ignore argument(s)
@@ -3955,13 +3955,13 @@ Optional argument NUMERIC, if non-nil, means the argument is numeric."
;;; 4. Text Filling, Adjusting, and Centering
(defun woman2-br (to)
- ".br -- Break. Leave no blank line. Format paragraphs upto TO."
+ ".br -- Break. Leave no blank line. Format paragraphs up to TO."
(woman-delete-line 1) ; ignore any arguments
(woman2-format-paragraphs to))
(defun woman2-fi (to)
".fi -- Fill subsequent output lines. Leave no blank line.
-Format paragraphs upto TO."
+Format paragraphs up to TO."
(setq woman-nofill nil)
(woman-delete-line 1) ; ignore any arguments
;; Preserve any final blank line in the nofill region:
@@ -3981,7 +3981,7 @@ for the current line length. Format paragraphs up to TO."
(defun woman2-ad (to)
".ad c -- Line adjustment is begun (once fill mode is on).
Set justification mode to c if specified.
-Format paragraphs upto TO. (Breaks, but should not.)"
+Format paragraphs up to TO. (Breaks, but should not.)"
;; c = l -- left, r -- right, c -- center, b or n -- both,
;; absent -- unchanged. Initial mode adj,both.
(setq woman-adjust
@@ -3997,7 +3997,7 @@ Format paragraphs upto TO. (Breaks, but should not.)"
(woman2-format-paragraphs to))
(defun woman2-na (to)
- ".na -- No adjusting. Format paragraphs upto TO.
+ ".na -- No adjusting. Format paragraphs up to TO.
\(Breaks, but should not.)"
(setq woman-adjust-previous woman-adjust
woman-justify-previous woman-justify
@@ -4037,7 +4037,7 @@ non-nil and non-zero."
(defvar woman-temp-indent nil)
(defun woman2-format-paragraphs (to &optional new-left)
- "Indent, fill and adjust paragraphs upto TO to current left margin.
+ "Indent, fill and adjust paragraphs up to TO to current left margin.
If optional arg NEW-LEFT is non-nil then reset current left margin.
If `woman-nofill' is non-nil then indent without filling or adjusting."
;; Blank space should only ever be output before text.
@@ -4103,7 +4103,7 @@ If `woman-nofill' is non-nil then indent without filling or adjusting."
;;; Tagged, indented and hanging paragraphs:
(defun woman2-TP (to)
- ".TP i -- Set prevailing indent to i. Format paragraphs upto TO.
+ ".TP i -- Set prevailing indent to i. Format paragraphs up to TO.
Begin indented paragraph with hanging tag given by next text line.
If tag doesn't fit, place it on a separate line."
(let ((i (woman2-get-prevailing-indent)))
@@ -4111,7 +4111,7 @@ If tag doesn't fit, place it on a separate line."
(woman2-tagged-paragraph to i)))
(defun woman2-IP (to)
- ".IP x i -- Same as .TP with tag x. Format paragraphs upto TO."
+ ".IP x i -- Same as .TP with tag x. Format paragraphs up to TO."
(woman-interparagraph-space)
(if (eolp) ; no args
;; Like LP without resetting prevailing indent
@@ -4152,7 +4152,7 @@ If tag doesn't fit, place it on a separate line."
(defun woman2-tagged-paragraph (to i)
"Begin indented paragraph with hanging tag given by current text line.
If tag doesn't fit, leave it on separate line.
-Format paragraphs upto TO. Set prevailing indent to I."
+Format paragraphs up to TO. Set prevailing indent to I."
(if (not (looking-at "\\s *$")) ; non-empty tag
(setq woman-leave-blank-lines nil))
@@ -4206,7 +4206,7 @@ Format paragraphs upto TO. Set prevailing indent to I."
(goto-char to)))))
(defun woman2-HP (to)
- ".HP i -- Set prevailing indent to i. Format paragraphs upto TO.
+ ".HP i -- Set prevailing indent to i. Format paragraphs up to TO.
Begin paragraph with hanging indent."
(let ((i (woman2-get-prevailing-indent)))
(woman-interparagraph-space)
@@ -4228,7 +4228,7 @@ Delete line from point and eol unless LEAVE-EOL is non-nil."
(defun woman2-RS (to)
".RS i -- Start relative indent, move left margin in distance i.
-Set prevailing indent to 5 for nested indents. Format paragraphs upto TO."
+Set prevailing indent to 5 for nested indents. Format paragraphs up to TO."
(push woman-left-margin woman-RS-left-margin)
(push woman-prevailing-indent woman-RS-prevailing-indent)
(setq woman-left-margin (+ woman-left-margin
@@ -4237,7 +4237,7 @@ Set prevailing indent to 5 for nested indents. Format paragraphs upto TO."
(woman2-format-paragraphs to woman-left-margin))
(defun woman2-RE (to)
- ".RE -- End of relative indent. Format paragraphs upto TO.
+ ".RE -- End of relative indent. Format paragraphs up to TO.
Set prevailing indent to amount of starting .RS."
(when woman-RS-left-margin
(setq woman-left-margin (pop woman-RS-left-margin)))
@@ -4274,18 +4274,18 @@ otherwise set PREVIOUS. Delete the whole remaining control line."
(defun woman2-ll (to)
".ll +/-N -- Set, increment or decrement line length.
-Format paragraphs upto TO. (Breaks, but should not.)"
+Format paragraphs up to TO. (Breaks, but should not.)"
(woman-set-arg 'fill-column 'woman-ll-fill-column)
(woman2-format-paragraphs to))
(defun woman2-in (to)
".in +/-N -- Set, increment or decrement the indent.
-Format paragraphs upto TO."
+Format paragraphs up to TO."
(woman-set-arg 'left-margin 'woman-in-left-margin)
(woman2-format-paragraphs to))
(defun woman2-ti (to)
- ".ti +/-N -- Temporary indent. Format paragraphs upto TO."
+ ".ti +/-N -- Temporary indent. Format paragraphs up to TO."
;; Ignore if no argument.
;; Indent next output line only wrt current indent.
;; Current indent is not changed.
@@ -4300,7 +4300,7 @@ Format paragraphs upto TO."
".ta Nt ... -- Set tabs, left type, unless t=R(right), C(centered).
\(Breaks, but should not.) The tab stops are separated by spaces;
a value preceded by + represents an increment to the previous stop value.
-Format paragraphs upto TO."
+Format paragraphs up to TO."
(setq tab-stop-list nil)
(woman2-process-escapes-to-eol 'numeric)
(save-excursion
@@ -4350,7 +4350,7 @@ tab stop columns or pairs (COLUMN . TYPE) where TYPE is R or C."
(insert ?\s))))
(defun woman2-DT (to)
- ".DT -- Restore default tabs. Format paragraphs upto TO.
+ ".DT -- Restore default tabs. Format paragraphs up to TO.
\(Breaks, but should not.)"
;; Currently just terminates special tab processing.
(setq tab-stop-list nil)
@@ -4359,7 +4359,7 @@ tab stop columns or pairs (COLUMN . TYPE) where TYPE is R or C."
(defun woman2-fc (to)
".fc a b -- Set field delimiter a and pad character b.
-Format paragraphs upto TO.
+Format paragraphs up to TO.
A VERY FIRST ATTEMPT to make fields at least readable!
Needs doing properly!"
(if (eolp)
@@ -4395,7 +4395,7 @@ Needs doing properly!"
(defun woman2-TS (to)
".TS -- Start of table code for the tbl processor.
-Format paragraphs upto TO."
+Format paragraphs up to TO."
(when woman-emulate-tbl
;; Assumes column separator is \t and intercolumn spacing is 3.
;; The first line may optionally be a list of options terminated by
diff --git a/lwlib/Makefile.in b/lwlib/Makefile.in
index 903461a2f4a..70f6cd17d78 100644
--- a/lwlib/Makefile.in
+++ b/lwlib/Makefile.in
@@ -63,7 +63,7 @@ AUTO_DEPEND = @AUTO_DEPEND@
DEPDIR = deps
ifeq ($(AUTO_DEPEND),yes)
DEPFLAGS = -MMD -MF $(DEPDIR)/$*.d -MP
- -include $(ALLOBJS:%.o=$(DEPDIR)/%.d)
+ -include $(OBJS:%.o=$(DEPDIR)/%.d)
else
DEPFLAGS =
include $(srcdir)/deps.mk
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)
return Qnil;
}
-/* Run buffer-list-update-hook if Vrun_hooks is non-nil, and BUF is NULL
- or does not have buffer hooks inhibited. BUF is NULL when called by
- make-indirect-buffer, since it does not inhibit buffer hooks. */
+/* Run buffer-list-update-hook if Vrun_hooks is non-nil and BUF does
+ not have buffer hooks inhibited. */
static void
run_buffer_list_update_hook (struct buffer *buf)
{
- if (! (NILP (Vrun_hooks) || (buf && buf->inhibit_buffer_hooks)))
+ eassert (buf);
+ if (! (NILP (Vrun_hooks) || buf->inhibit_buffer_hooks))
call1 (Vrun_hooks, Qbuffer_list_update_hook);
}
@@ -907,7 +907,7 @@ does not run the hooks `kill-buffer-hook',
set_buffer_internal_1 (old_b);
}
- run_buffer_list_update_hook (NULL);
+ run_buffer_list_update_hook (b);
return buf;
}
diff --git a/src/callint.c b/src/callint.c
index c60a376b958..d8d2b278458 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -105,11 +105,13 @@ If the string begins with `^' and `shift-select-mode' is non-nil,
You may use `@', `*', and `^' together. They are processed in the
order that they appear, before reading any arguments.
-If MODES is present, it should be a list of mode names (symbols) that
-this command is applicable for. The main effect of this is that
-`M-x TAB' (by default) won't list this command if the current buffer's
-mode doesn't match the list. That is, if either the major mode isn't
-derived from them, or (when it's a minor mode) the mode isn't in effect.
+If MODES is present, it should be one or more mode names (symbols)
+for which this command is applicable. This is so that `M-x TAB'
+will be able to exclude this command from the list of completion
+candidates if the current buffer's mode doesn't match the list.
+Which commands are excluded from the list of completion
+candidates based on this information is controlled by the value
+of `read-extended-command-predicate', which see.
usage: (interactive &optional ARG-DESCRIPTOR &rest MODES) */
attributes: const)
diff --git a/src/ccl.c b/src/ccl.c
index c92684f4bc7..6e780ef9f0c 100644
--- a/src/ccl.c
+++ b/src/ccl.c
@@ -1987,7 +1987,7 @@ ccl_get_compiled_code (Lisp_Object ccl_prog, ptrdiff_t *idx)
/* Setup fields of the structure pointed by CCL appropriately for the
execution of CCL program CCL_PROG. CCL_PROG is the name (symbol)
of the CCL program or the already compiled code (vector).
- Return true iff successful.
+ Return true if successful.
If CCL_PROG is nil, just reset the structure pointed by CCL. */
bool
diff --git a/src/coding.c b/src/coding.c
index 4e59f2b6a1b..49dcd8634f3 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -1431,7 +1431,7 @@ encode_coding_utf_8 (struct coding_system *coding)
ptrdiff_t produced_chars = 0;
int c;
- if (CODING_UTF_8_BOM (coding) == utf_with_bom)
+ if (CODING_UTF_8_BOM (coding) != utf_without_bom)
{
ASSURE_DESTINATION (3);
EMIT_THREE_BYTES (UTF_8_BOM_1, UTF_8_BOM_2, UTF_8_BOM_3);
diff --git a/src/fns.c b/src/fns.c
index 51ef1153fb7..3984e318feb 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -38,6 +38,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "puresize.h"
#include "gnutls.h"
+#ifdef HAVE_TREE_SITTER
+#include "treesit.h"
+#endif
+
enum equal_kind { EQUAL_NO_QUIT, EQUAL_PLAIN, EQUAL_INCLUDING_PROPERTIES };
static bool internal_equal (Lisp_Object, Lisp_Object,
enum equal_kind, int, Lisp_Object);
@@ -2823,6 +2827,11 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, enum equal_kind equal_kind,
bool_vector_bytes (size)));
}
+#ifdef HAVE_TREE_SITTER
+ if (TS_NODEP (o1))
+ return treesit_node_eq (o1, o2);
+#endif
+
/* Aside from them, only true vectors, char-tables, compiled
functions, and fonts (font-spec, font-entity, font-object)
are sensible to compare, so eliminate the others now. */
@@ -3168,8 +3177,7 @@ DEFUN ("yes-or-no-p", Fyes_or_no_p, Syes_or_no_p, 1, 1, 0,
Return t if answer is yes, and nil if the answer is no.
PROMPT is the string to display to ask the question; `yes-or-no-p'
-adds \"(yes or no) \" to it. It does not need to end in space, but if
-it does up to one space will be removed.
+adds \"(yes or no) \" to it.
The user must confirm the answer with RET, and can edit it until it
has been confirmed.
diff --git a/src/gnutls.c b/src/gnutls.c
index 45dd1b0aa53..91e369375f2 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -1060,7 +1060,7 @@ usage: (gnutls-error-string ERROR) */)
DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
doc: /* Deallocate GnuTLS resources associated with process PROC.
-See also `gnutls-init'. */)
+See also `gnutls-boot'. */)
(Lisp_Object proc)
{
return emacs_gnutls_deinit (proc);
diff --git a/src/keyboard.c b/src/keyboard.c
index 0ed28070335..6f0f075e54e 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -10010,7 +10010,7 @@ read_key_sequence (Lisp_Object *keybuf, Lisp_Object prompt,
if (/* first_unbound < indec.start && first_unbound < fkey.start && */
first_unbound < keytran.start)
- { /* The prefix upto first_unbound has no binding and has
+ { /* The prefix up to first_unbound has no binding and has
no translation left to do either, so we know it's unbound.
If we don't stop now, we risk staying here indefinitely
(if the user keeps entering fkey or keytran prefixes
diff --git a/src/pgtkfns.c b/src/pgtkfns.c
index 6b3a0459d36..6e5bb22375a 100644
--- a/src/pgtkfns.c
+++ b/src/pgtkfns.c
@@ -1902,7 +1902,7 @@ parse_resource_key (const char *res_key, char *setting_key)
/* check existence of setting_key */
GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default ();
- GSettingsSchema *scm = g_settings_schema_source_lookup (ssrc, SCHEMA_ID, FALSE);
+ GSettingsSchema *scm = g_settings_schema_source_lookup (ssrc, SCHEMA_ID, TRUE);
if (!scm)
return NULL; /* *.schema.xml is not installed. */
if (!g_settings_schema_has_key (scm, setting_key))
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index 5158492ca09..c00e13550bd 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -2959,7 +2959,8 @@ pgtk_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, int x,
if (w == XWINDOW (f->selected_window))
{
int frame_x = (WINDOW_TO_FRAME_PIXEL_X (w, x)
- + WINDOW_LEFT_FRINGE_WIDTH (w));
+ + WINDOW_LEFT_FRINGE_WIDTH (w)
+ + WINDOW_LEFT_MARGIN_WIDTH (w));
int frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, y);
pgtk_im_set_cursor_location (f, frame_x, frame_y,
w->phys_cursor_width,
diff --git a/src/print.c b/src/print.c
index d4a9ff89246..e65b4c40b0e 100644
--- a/src/print.c
+++ b/src/print.c
@@ -2034,8 +2034,13 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
/* Now the node must be up-to-date, and calling functions like
Ftreesit_node_start will not signal. */
bool named = treesit_named_node_p (XTS_NODE (obj)->node);
- const char *delim1 = named ? "(" : "\"";
- const char *delim2 = named ? ")" : "\"";
+ /* We used to use () as delimiters for named nodes, but that
+ confuses pretty-printing a tad bit. There might be more
+ little breakages here and there if we print parenthesizes
+ inside an object, so I guess better not do it.
+ (bug#60696) */
+ const char *delim1 = named ? "" : "\"";
+ const char *delim2 = named ? "" : "\"";
print_c_string (delim1, printcharfun);
print_string (Ftreesit_node_type (obj), printcharfun);
print_c_string (delim2, printcharfun);
diff --git a/src/regex-emacs.c b/src/regex-emacs.c
index 6b2fa5df037..2dca0d16ad9 100644
--- a/src/regex-emacs.c
+++ b/src/regex-emacs.c
@@ -223,7 +223,7 @@ typedef enum
is followed by a range table:
2 bytes of flags for character sets (low 8 bits, high 8 bits)
See RANGE_TABLE_WORK_BITS below.
- 2 bytes, the number of pairs that follow (upto 32767)
+ 2 bytes, the number of pairs that follow (up to 32767)
pairs, each 2 multibyte characters,
each multibyte character represented as 3 bytes. */
charset,
diff --git a/src/treesit.c b/src/treesit.c
index 55463122d14..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/>. */
#undef ts_node_end_byte
#undef ts_node_eq
#undef ts_node_field_name_for_child
-#undef ts_node_first_child_for_byte
-#undef ts_node_first_named_child_for_byte
#undef ts_node_has_error
#undef ts_node_is_extra
#undef ts_node_is_missing
@@ -99,8 +97,6 @@ DEF_DLL_FN (TSNode, ts_node_descendant_for_byte_range,
DEF_DLL_FN (uint32_t, ts_node_end_byte, (TSNode));
DEF_DLL_FN (bool, ts_node_eq, (TSNode, TSNode));
DEF_DLL_FN (const char *, ts_node_field_name_for_child, (TSNode, uint32_t));
-DEF_DLL_FN (TSNode, ts_node_first_child_for_byte, (TSNode, uint32_t));
-DEF_DLL_FN (TSNode, ts_node_first_named_child_for_byte, (TSNode, uint32_t));
DEF_DLL_FN (bool, ts_node_has_error, (TSNode));
DEF_DLL_FN (bool, ts_node_is_extra, (TSNode));
DEF_DLL_FN (bool, ts_node_is_missing, (TSNode));
@@ -174,8 +170,6 @@ init_treesit_functions (void)
LOAD_DLL_FN (library, ts_node_end_byte);
LOAD_DLL_FN (library, ts_node_eq);
LOAD_DLL_FN (library, ts_node_field_name_for_child);
- LOAD_DLL_FN (library, ts_node_first_child_for_byte);
- LOAD_DLL_FN (library, ts_node_first_named_child_for_byte);
LOAD_DLL_FN (library, ts_node_has_error);
LOAD_DLL_FN (library, ts_node_is_extra);
LOAD_DLL_FN (library, ts_node_is_missing);
@@ -232,8 +226,6 @@ init_treesit_functions (void)
#define ts_node_end_byte fn_ts_node_end_byte
#define ts_node_eq fn_ts_node_eq
#define ts_node_field_name_for_child fn_ts_node_field_name_for_child
-#define ts_node_first_child_for_byte fn_ts_node_first_child_for_byte
-#define ts_node_first_named_child_for_byte fn_ts_node_first_named_child_for_byte
#define ts_node_has_error fn_ts_node_has_error
#define ts_node_is_extra fn_ts_node_is_extra
#define ts_node_is_missing fn_ts_node_is_missing
@@ -406,6 +398,24 @@ init_treesit_functions (void)
/*** Initialization */
+static Lisp_Object Vtreesit_str_libtree_sitter;
+static Lisp_Object Vtreesit_str_tree_sitter;
+static Lisp_Object Vtreesit_str_dot;
+static Lisp_Object Vtreesit_str_question_mark;
+static Lisp_Object Vtreesit_str_star;
+static Lisp_Object Vtreesit_str_plus;
+static Lisp_Object Vtreesit_str_pound_equal;
+static Lisp_Object Vtreesit_str_pound_match;
+static Lisp_Object Vtreesit_str_pound_pred;
+static Lisp_Object Vtreesit_str_open_bracket;
+static Lisp_Object Vtreesit_str_close_bracket;
+static Lisp_Object Vtreesit_str_open_paren;
+static Lisp_Object Vtreesit_str_close_paren;
+static Lisp_Object Vtreesit_str_space;
+static Lisp_Object Vtreesit_str_equal;
+static Lisp_Object Vtreesit_str_match;
+static Lisp_Object Vtreesit_str_pred;
+
/* This is the limit on recursion levels for some tree-sitter
functions. Remember to update docstrings when changing this
value. */
@@ -534,9 +544,9 @@ treesit_load_language (Lisp_Object language_symbol,
/* Figure out the library name and C name. */
Lisp_Object lib_base_name
- = concat2 (build_pure_c_string ("libtree-sitter-"), symbol_name);
+ = concat2 (Vtreesit_str_libtree_sitter, symbol_name);
Lisp_Object base_name
- = concat2 (build_pure_c_string ("tree-sitter-"), symbol_name);
+ = concat2 (Vtreesit_str_tree_sitter, symbol_name);
/* Override the library name and C name, if appropriate. */
Lisp_Object override_name;
@@ -945,7 +955,7 @@ treesit_check_buffer_size (struct buffer *buffer)
ptrdiff_t buffer_size_bytes = (BUF_Z_BYTE (buffer) - BUF_BEG_BYTE (buffer));
if (buffer_size_bytes > UINT32_MAX)
xsignal2 (Qtreesit_buffer_too_large,
- build_pure_c_string ("Buffer size cannot be larger than 4GB"),
+ build_string ("Buffer size cannot be larger than 4GB"),
make_fixnum (buffer_size_bytes));
}
@@ -1200,7 +1210,7 @@ treesit_compose_query_signal_data (uint32_t error_offset,
return list4 (build_string (treesit_query_error_to_string (error_type)),
make_fixnum (error_offset + 1),
query_source,
- build_pure_c_string ("Debug the query with `treesit-query-validate'"));
+ build_string ("Debug the query with `treesit-query-validate'"));
}
/* Ensure the QUERY is compiled. Return the TSQuery. It could be
@@ -1498,8 +1508,8 @@ treesit_check_range_argument (Lisp_Object ranges)
EMACS_INT end = XFIXNUM (XCDR (range));
if (!(last_point <= beg && beg <= end && end <= point_max))
xsignal2 (Qtreesit_range_invalid,
- build_pure_c_string ("RANGE is either overlapping,"
- " out-of-order or out-of-range"),
+ build_string ("RANGE is either overlapping,"
+ " out-of-order or out-of-range"),
ranges);
last_point = end;
}
@@ -1607,7 +1617,7 @@ buffer. */)
if (!success)
xsignal2 (Qtreesit_range_invalid,
- build_pure_c_string ("Something went wrong when setting ranges"),
+ build_string ("Something went wrong when setting ranges"),
ranges);
XTS_PARSER (parser)->need_reparse = true;
@@ -2077,6 +2087,41 @@ return nil. */)
return make_treesit_node (XTS_NODE (node)->parser, sibling);
}
+/* Our reimplementation of ts_node_first_child_for_byte. The current
+ implementation of that function has problems (see bug#60127), so
+ before it's fixed upstream, we use our own reimplementation of it.
+ Return true if there is a valid sibling, return false otherwise.
+ If the return value is false, the position of the cursor is
+ undefined. (We use cursor because technically we can't make a null
+ node for ourselves, also, using cursor is more convenient.)
+
+ TODO: Remove this function once tree-sitter fixed the bug. */
+static bool treesit_cursor_first_child_for_byte
+(TSTreeCursor *cursor, ptrdiff_t pos, bool named)
+{
+ if (!ts_tree_cursor_goto_first_child (cursor))
+ return false;
+
+ TSNode node = ts_tree_cursor_current_node (cursor);
+ while (ts_node_end_byte (node) <= pos)
+ {
+ if (ts_tree_cursor_goto_next_sibling (cursor))
+ node = ts_tree_cursor_current_node (cursor);
+ else
+ /* Reached the end and still can't find a valid sibling. */
+ return false;
+ }
+ while (named && (!ts_node_is_named (node)))
+ {
+ if (ts_tree_cursor_goto_next_sibling (cursor))
+ node = ts_tree_cursor_current_node (cursor);
+ else
+ /* Reached the end and still can't find a named sibling. */
+ return false;
+ }
+ return true;
+}
+
DEFUN ("treesit-node-first-child-for-pos",
Ftreesit_node_first_child_for_pos,
Streesit_node_first_child_for_pos, 2, 3, 0,
@@ -2101,16 +2146,17 @@ Note that this function returns an immediate child, not the smallest
ptrdiff_t byte_pos = buf_charpos_to_bytepos (buf, XFIXNUM (pos));
TSNode treesit_node = XTS_NODE (node)->node;
- TSNode child;
- if (NILP (named))
- child = ts_node_first_child_for_byte (treesit_node, byte_pos - visible_beg);
- else
- child = ts_node_first_named_child_for_byte (treesit_node,
- byte_pos - visible_beg);
- if (ts_node_is_null (child))
- return Qnil;
+ TSTreeCursor cursor = ts_tree_cursor_new (treesit_node);
+ ptrdiff_t treesit_pos = byte_pos - visible_beg;
+ bool success;
+ success = treesit_cursor_first_child_for_byte (&cursor, treesit_pos,
+ !NILP (named));
+ TSNode child = ts_tree_cursor_current_node (&cursor);
+ ts_tree_cursor_delete (&cursor);
+ if (!success)
+ return Qnil;
return make_treesit_node (XTS_NODE (node)->parser, child);
}
@@ -2154,11 +2200,24 @@ If NODE is nil, return nil. */)
return make_treesit_node (XTS_NODE (node)->parser, child);
}
+/* Return true if NODE1 and NODE2 are the same node. Assumes they are
+ TS_NODE type. */
+bool treesit_node_eq (Lisp_Object node1, Lisp_Object node2)
+{
+ treesit_initialize ();
+ TSNode treesit_node_1 = XTS_NODE (node1)->node;
+ TSNode treesit_node_2 = XTS_NODE (node2)->node;
+ return ts_node_eq (treesit_node_1, treesit_node_2);
+}
+
DEFUN ("treesit-node-eq",
Ftreesit_node_eq,
Streesit_node_eq, 2, 2, 0,
- doc: /* Return non-nil if NODE1 and NODE2 are the same node.
-If any one of NODE1 and NODE2 is nil, return nil. */)
+ doc: /* Return non-nil if NODE1 and NODE2 refer to the same node.
+If any one of NODE1 and NODE2 is nil, return nil.
+This function uses the same equivalence metric as `equal', and returns
+non-nil if NODE1 and NODE2 refer to the same node in a syntax tree
+produced by tree-sitter. */)
(Lisp_Object node1, Lisp_Object node2)
{
if (NILP (node1) || NILP (node2))
@@ -2166,12 +2225,7 @@ If any one of NODE1 and NODE2 is nil, return nil. */)
CHECK_TS_NODE (node1);
CHECK_TS_NODE (node2);
- treesit_initialize ();
-
- TSNode treesit_node_1 = XTS_NODE (node1)->node;
- TSNode treesit_node_2 = XTS_NODE (node2)->node;
-
- bool same_node = ts_node_eq (treesit_node_1, treesit_node_2);
+ bool same_node = treesit_node_eq (node1, node2);
return same_node ? Qt : Qnil;
}
@@ -2202,30 +2256,32 @@ See Info node `(elisp)Pattern Matching' for detailed explanation. */)
(Lisp_Object pattern)
{
if (EQ (pattern, QCanchor))
- return build_pure_c_string (".");
+ return Vtreesit_str_dot;
if (EQ (pattern, intern_c_string (":?")))
- return build_pure_c_string ("?");
+ return Vtreesit_str_question_mark;
if (EQ (pattern, intern_c_string (":*")))
- return build_pure_c_string ("*");
+ return Vtreesit_str_star;
if (EQ (pattern, intern_c_string (":+")))
- return build_pure_c_string ("+");
+ return Vtreesit_str_plus;
if (EQ (pattern, QCequal))
- return build_pure_c_string ("#equal");
+ return Vtreesit_str_pound_equal;
if (EQ (pattern, QCmatch))
- return build_pure_c_string ("#match");
+ return Vtreesit_str_pound_match;
if (EQ (pattern, QCpred))
- return build_pure_c_string ("#pred");
+ return Vtreesit_str_pound_pred;
Lisp_Object opening_delimeter
- = build_pure_c_string (VECTORP (pattern) ? "[" : "(");
+ = VECTORP (pattern)
+ ? Vtreesit_str_open_bracket : Vtreesit_str_open_paren;
Lisp_Object closing_delimiter
- = build_pure_c_string (VECTORP (pattern) ? "]" : ")");
+ = VECTORP (pattern)
+ ? Vtreesit_str_close_bracket : Vtreesit_str_close_paren;
if (VECTORP (pattern) || CONSP (pattern))
return concat3 (opening_delimeter,
Fmapconcat (Qtreesit_pattern_expand,
pattern,
- build_pure_c_string (" ")),
+ Vtreesit_str_space),
closing_delimiter);
- return CALLN (Fformat, build_pure_c_string ("%S"), pattern);
+ return Fprin1_to_string (pattern, Qnil, Qt);
}
DEFUN ("treesit-query-expand",
@@ -2252,8 +2308,7 @@ A PATTERN in QUERY can be
See Info node `(elisp)Pattern Matching' for detailed explanation. */)
(Lisp_Object query)
{
- return Fmapconcat (Qtreesit_pattern_expand,
- query, build_pure_c_string (" "));
+ return Fmapconcat (Qtreesit_pattern_expand, query, Vtreesit_str_space);
}
/* This struct is used for passing captures to be check against
@@ -2333,10 +2388,10 @@ treesit_predicate_capture_name_to_node (Lisp_Object name,
if (NILP (node))
xsignal3 (Qtreesit_query_error,
- build_pure_c_string ("Cannot find captured node"),
- name, build_pure_c_string ("A predicate can only refer"
- " to captured nodes in the "
- "same pattern"));
+ build_string ("Cannot find captured node"),
+ name, build_string ("A predicate can only refer"
+ " to captured nodes in the "
+ "same pattern"));
return node;
}
@@ -2365,8 +2420,8 @@ treesit_predicate_equal (Lisp_Object args, struct capture_range captures)
{
if (XFIXNUM (Flength (args)) != 2)
xsignal2 (Qtreesit_query_error,
- build_pure_c_string ("Predicate `equal' requires "
- "two arguments but only given"),
+ build_string ("Predicate `equal' requires "
+ "two arguments but only given"),
Flength (args));
Lisp_Object arg1 = XCAR (args);
@@ -2391,8 +2446,8 @@ treesit_predicate_match (Lisp_Object args, struct capture_range captures)
{
if (XFIXNUM (Flength (args)) != 2)
xsignal2 (Qtreesit_query_error,
- build_pure_c_string ("Predicate `equal' requires two "
- "arguments but only given"),
+ build_string ("Predicate `equal' requires two "
+ "arguments but only given"),
Flength (args));
Lisp_Object regexp = XCAR (args);
@@ -2404,12 +2459,12 @@ treesit_predicate_match (Lisp_Object args, struct capture_range captures)
string-match does.) */
if (!STRINGP (regexp))
xsignal1 (Qtreesit_query_error,
- build_pure_c_string ("The first argument to `match' should "
- "be a regexp string, not a capture name"));
+ build_string ("The first argument to `match' should "
+ "be a regexp string, not a capture name"));
if (!SYMBOLP (capture_name))
xsignal1 (Qtreesit_query_error,
- build_pure_c_string ("The second argument to `match' should "
- "be a capture name, not a string"));
+ build_string ("The second argument to `match' should "
+ "be a capture name, not a string"));
Lisp_Object text = treesit_predicate_capture_name_to_text (capture_name,
captures);
@@ -2428,9 +2483,9 @@ treesit_predicate_pred (Lisp_Object args, struct capture_range captures)
{
if (XFIXNUM (Flength (args)) < 2)
xsignal2 (Qtreesit_query_error,
- build_pure_c_string ("Predicate `pred' requires "
- "at least two arguments, "
- "but was only given"),
+ build_string ("Predicate `pred' requires "
+ "at least two arguments, "
+ "but was only given"),
Flength (args));
Lisp_Object fn = Fintern (XCAR (args), Qnil);
@@ -2458,18 +2513,18 @@ treesit_eval_predicates (struct capture_range captures, Lisp_Object predicates)
Lisp_Object predicate = XCAR (tail);
Lisp_Object fn = XCAR (predicate);
Lisp_Object args = XCDR (predicate);
- if (!NILP (Fstring_equal (fn, build_pure_c_string ("equal"))))
+ if (!NILP (Fstring_equal (fn, Vtreesit_str_equal)))
pass &= treesit_predicate_equal (args, captures);
- else if (!NILP (Fstring_equal (fn, build_pure_c_string ("match"))))
+ else if (!NILP (Fstring_equal (fn, Vtreesit_str_match)))
pass &= treesit_predicate_match (args, captures);
- else if (!NILP (Fstring_equal (fn, build_pure_c_string ("pred"))))
+ else if (!NILP (Fstring_equal (fn, Vtreesit_str_pred)))
pass &= treesit_predicate_pred (args, captures);
else
xsignal3 (Qtreesit_query_error,
- build_pure_c_string ("Invalid predicate"),
- fn, build_pure_c_string ("Currently Emacs only supports"
- " equal, match, and pred"
- " predicate"));
+ build_string ("Invalid predicate"),
+ fn, build_string ("Currently Emacs only supports"
+ " equal, match, and pred"
+ " predicate"));
}
/* If all predicates passed, add captures to result list. */
return pass;
@@ -3243,9 +3298,9 @@ a regexp. */)
Lisp_Object parser = XTS_NODE (root)->parser;
Lisp_Object parent = Fcons (Qnil, Qnil);
- TSTreeCursor cursor;
- if (!treesit_cursor_helper (&cursor, XTS_NODE (root)->node, parser))
- return Qnil;
+ /* In this function we never traverse above NODE, so we don't need
+ to use treesit_cursor_helper. */
+ TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (root)->node);
treesit_build_sparse_tree (&cursor, parent, predicate, process_fn,
the_limit, parser);
@@ -3369,6 +3424,41 @@ then in the `tree-sitter' subdirectory of `user-emacs-directory', and
then in the system default locations for dynamic libraries, in that order. */);
Vtreesit_extra_load_path = Qnil;
+ staticpro (&Vtreesit_str_libtree_sitter);
+ Vtreesit_str_libtree_sitter = build_pure_c_string ("libtree-sitter-");
+ staticpro (&Vtreesit_str_tree_sitter);
+ Vtreesit_str_tree_sitter = build_pure_c_string ("tree-sitter-");
+ staticpro (&Vtreesit_str_dot);
+ Vtreesit_str_dot = build_pure_c_string (".");
+ staticpro (&Vtreesit_str_question_mark);
+ Vtreesit_str_question_mark = build_pure_c_string ("?");
+ staticpro (&Vtreesit_str_star);
+ Vtreesit_str_star = build_pure_c_string ("*");
+ staticpro (&Vtreesit_str_plus);
+ Vtreesit_str_plus = build_pure_c_string ("+");
+ staticpro (&Vtreesit_str_pound_equal);
+ Vtreesit_str_pound_equal = build_pure_c_string ("#equal");
+ staticpro (&Vtreesit_str_pound_match);
+ Vtreesit_str_pound_match = build_pure_c_string ("#match");
+ staticpro (&Vtreesit_str_pound_pred);
+ Vtreesit_str_pound_pred = build_pure_c_string ("#pred");
+ staticpro (&Vtreesit_str_open_bracket);
+ Vtreesit_str_open_bracket = build_pure_c_string ("[");
+ staticpro (&Vtreesit_str_close_bracket);
+ Vtreesit_str_close_bracket = build_pure_c_string ("]");
+ staticpro (&Vtreesit_str_open_paren);
+ Vtreesit_str_open_paren = build_pure_c_string ("(");
+ staticpro (&Vtreesit_str_close_paren);
+ Vtreesit_str_close_paren = build_pure_c_string (")");
+ staticpro (&Vtreesit_str_space);
+ Vtreesit_str_space = build_pure_c_string (" ");
+ staticpro (&Vtreesit_str_equal);
+ Vtreesit_str_equal = build_pure_c_string ("equal");
+ staticpro (&Vtreesit_str_match);
+ Vtreesit_str_match = build_pure_c_string ("match");
+ staticpro (&Vtreesit_str_pred);
+ Vtreesit_str_pred = build_pure_c_string ("pred");
+
defsubr (&Streesit_language_available_p);
defsubr (&Streesit_library_abi_version);
defsubr (&Streesit_language_abi_version);
diff --git a/src/treesit.h b/src/treesit.h
index 909609737d3..5382bc58817 100644
--- a/src/treesit.h
+++ b/src/treesit.h
@@ -191,6 +191,7 @@ extern bool treesit_node_uptodate_p (Lisp_Object);
extern void treesit_delete_parser (struct Lisp_TS_Parser *);
extern void treesit_delete_query (struct Lisp_TS_Query *);
extern bool treesit_named_node_p (TSNode);
+extern bool treesit_node_eq (Lisp_Object, Lisp_Object);
#endif /* HAVE_TREE_SITTER */
diff --git a/src/w32.c b/src/w32.c
index 47d79abc5b0..8d344d2e6da 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -10509,10 +10509,13 @@ init_ntproc (int dumping)
}
}
-/*
- shutdown_handler ensures that buffers' autosave files are
- up to date when the user logs off, or the system shuts down.
-*/
+/* shutdown_handler ensures that buffers' autosave files are up to
+ date when the user logs off, or the system shuts down. It also
+ shuts down Emacs when we get killed by another Emacs process, in
+ which case we get the CTRL_CLOSE_EVENT. */
+
+extern DWORD dwMainThreadId;
+
static BOOL WINAPI
shutdown_handler (DWORD type)
{
@@ -10521,15 +10524,31 @@ shutdown_handler (DWORD type)
|| type == CTRL_LOGOFF_EVENT /* User logs off. */
|| type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */
{
- /* If we are being shut down in noninteractive mode, we don't
- care about the message stack, so clear it to avoid abort in
- shut_down_emacs. This happens when an noninteractive Emacs
- is invoked as a subprocess of Emacs, and the parent wants to
- kill us, e.g. because it's about to exit. */
- if (noninteractive)
- clear_message_stack ();
- /* Shut down cleanly, making sure autosave files are up to date. */
- shut_down_emacs (0, Qnil);
+ if (GetCurrentThreadId () == dwMainThreadId)
+ {
+ /* If we are being shut down in noninteractive mode, we don't
+ care about the message stack, so clear it to avoid abort in
+ shut_down_emacs. This happens when an noninteractive Emacs
+ is invoked as a subprocess of Emacs, and the parent wants to
+ kill us, e.g. because it's about to exit. */
+ if (noninteractive)
+ clear_message_stack ();
+ /* Shut down cleanly, making sure autosave files are up to date. */
+ shut_down_emacs (0, Qnil);
+ }
+ else
+ {
+ /* This handler is run in a thread different from the main
+ thread. (This is the normal situation when we are killed
+ by Emacs, for example, which sends us the WM_CLOSE
+ message). We cannot possibly call functions like
+ shut_down_emacs or clear_message_stack in that case,
+ since the main (a.k.a. "Lisp") thread could be in the
+ middle of some Lisp program. So instead we arrange for
+ maybe_quit to kill Emacs. */
+ Vquit_flag = Qkill_emacs;
+ Vinhibit_quit = Qnil;
+ }
}
/* Allow other handlers to handle this signal. */
diff --git a/src/w32fns.c b/src/w32fns.c
index 192d3ddf27a..745f561e6b1 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -10396,8 +10396,8 @@ to be converted to forward slashes by the caller. */)
#endif /* WINDOWSNT */
/* Query a value from the Windows Registry (under HKCU and HKLM),
- where `key` is the registry key, `name` is the name, and `lpdwtype`
- is a pointer to the return value's type. `lpwdtype` can be NULL if
+ where `key' is the registry key, `name' is the name, and `lpdwtype'
+ is a pointer to the return value's type. `lpwdtype' can be NULL if
you do not care about the type.
Returns: pointer to the value, or null pointer if the key/name does
@@ -10664,7 +10664,7 @@ pops up the Windows Run dialog, <lwindow>-<Pause> pops up the "System
Properties" dialog, etc. On Windows 10, no \"Windows\" key
combinations are normally handed to applications. To enable Emacs to
process \"Windows\" key combinations, use the function
-`w32-register-hot-key`.
+`w32-register-hot-key'.
For Windows 98/ME, see the doc string of `w32-phantom-key-code'. */);
Vw32_pass_lwindow_to_system = Qt;
@@ -10683,7 +10683,7 @@ pops up the Windows Run dialog, <rwindow>-<Pause> pops up the "System
Properties" dialog, etc. On Windows 10, no \"Windows\" key
combinations are normally handed to applications. To enable Emacs to
process \"Windows\" key combinations, use the function
-`w32-register-hot-key`.
+`w32-register-hot-key'.
For Windows 98/ME, see the doc string of `w32-phantom-key-code'. */);
Vw32_pass_rwindow_to_system = Qt;
@@ -10698,7 +10698,7 @@ acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
`w32-pass-rwindow-to-system' is nil.
This variable is only used on Windows 98 and ME. For other Windows
-versions, see the documentation of the `w32-register-hot-key`
+versions, see the documentation of the `w32-register-hot-key'
function. */);
/* Although 255 is technically not a valid key code, it works and
means that this hack won't interfere with any real key code. */
@@ -10732,7 +10732,7 @@ The value can be hyper, super, meta, alt, control or shift for the
respective modifier, or nil to appear as the `lwindow' key.
Any other value will cause the key to be ignored.
-Also see the documentation of the `w32-register-hot-key` function. */);
+Also see the documentation of the `w32-register-hot-key' function. */);
Vw32_lwindow_modifier = Qnil;
DEFVAR_LISP ("w32-rwindow-modifier",
@@ -10742,7 +10742,7 @@ The value can be hyper, super, meta, alt, control or shift for the
respective modifier, or nil to appear as the `rwindow' key.
Any other value will cause the key to be ignored.
-Also see the documentation of the `w32-register-hot-key` function. */);
+Also see the documentation of the `w32-register-hot-key' function. */);
Vw32_rwindow_modifier = Qnil;
DEFVAR_LISP ("w32-apps-modifier",
@@ -11112,20 +11112,24 @@ emacs_abort (void)
abort ();
int button;
- button = MessageBox (NULL,
- "A fatal error has occurred!\n\n"
- "Would you like to attach a debugger?\n\n"
- "Select:\n"
- "YES -- to debug Emacs, or\n"
- "NO -- to abort Emacs and produce a backtrace\n"
- " (emacs_backtrace.txt in current directory)."
+
+ if (noninteractive)
+ button = IDNO;
+ else
+ button = MessageBox (NULL,
+ "A fatal error has occurred!\n\n"
+ "Would you like to attach a debugger?\n\n"
+ "Select:\n"
+ "YES -- to debug Emacs, or\n"
+ "NO -- to abort Emacs and produce a backtrace\n"
+ " (emacs_backtrace.txt in current directory)."
#if __GNUC__
- "\n\n(type \"gdb -p <emacs-PID>\" and\n"
- "\"continue\" inside GDB before clicking YES.)"
+ "\n\n(Before clicking YES, type\n"
+ "\"gdb -p <emacs-PID>\", then \"continue\" inside GDB.)"
#endif
- , "Emacs Abort Dialog",
- MB_ICONEXCLAMATION | MB_TASKMODAL
- | MB_SETFOREGROUND | MB_YESNO);
+ , "Emacs Abort Dialog",
+ MB_ICONEXCLAMATION | MB_TASKMODAL
+ | MB_SETFOREGROUND | MB_YESNO);
switch (button)
{
case IDYES:
@@ -11271,7 +11275,7 @@ globals_of_w32fns (void)
get_proc_addr (hm_kernel32, "SetThreadDescription");
/* Support OS dark mode on Windows 10 version 1809 and higher.
- See `w32_applytheme` which uses appropriate APIs per version of Windows.
+ See `w32_applytheme' which uses appropriate APIs per version of Windows.
For future wretches who may need to understand Windows build numbers:
https://docs.microsoft.com/en-us/windows/release-health/release-information
*/
diff --git a/src/xdisp.c b/src/xdisp.c
index 6c88846e7a8..d2c91e5847b 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -23322,8 +23322,9 @@ extend_face_to_end_of_line (struct it *it)
it->avoid_cursor_p = true;
it->object = Qnil;
- const int stretch_ascent = (((it->ascent + it->descent)
- * FONT_BASE (font)) / FONT_HEIGHT (font));
+ const int stretch_height = it->ascent + it->descent;
+ const int stretch_ascent =
+ (stretch_height * FONT_BASE (font)) / FONT_HEIGHT (font);
if (indicator_column >= 0
&& indicator_column > it->current_x
@@ -23343,8 +23344,7 @@ extend_face_to_end_of_line (struct it *it)
if (stretch_width > 0)
{
append_stretch_glyph (it, Qnil, stretch_width,
- it->ascent + it->descent,
- stretch_ascent);
+ stretch_height, stretch_ascent);
}
/* Generate the glyph indicator only if
@@ -23352,6 +23352,8 @@ extend_face_to_end_of_line (struct it *it)
if (it->current_x < indicator_column)
{
const int save_face_id = it->face_id;
+ const int save_ascent = it->ascent;
+ const int save_descent = it->descent;
it->char_to_display
= XFIXNAT (Vdisplay_fill_column_indicator_character);
it->face_id
@@ -23359,6 +23361,8 @@ extend_face_to_end_of_line (struct it *it)
0, extend_face_id);
PRODUCE_GLYPHS (it);
it->face_id = save_face_id;
+ it->ascent = save_ascent;
+ it->descent = save_descent;
}
}
@@ -23372,8 +23376,7 @@ extend_face_to_end_of_line (struct it *it)
{
clear_position (it);
append_stretch_glyph (it, Qnil, stretch_width,
- it->ascent + it->descent,
- stretch_ascent);
+ stretch_height, stretch_ascent);
}
}
diff --git a/test/lisp/erc/erc-scenarios-base-association.el b/test/lisp/erc/erc-scenarios-base-association.el
index 1e280d0fdd7..a40a4cb7550 100644
--- a/test/lisp/erc/erc-scenarios-base-association.el
+++ b/test/lisp/erc/erc-scenarios-base-association.el
@@ -26,7 +26,9 @@
(declare-function erc-network-name "erc-networks")
(declare-function erc-network "erc-networks")
+(declare-function erc-track-get-active-buffer "erc-track" (arg))
(defvar erc-autojoin-channels-alist)
+(defvar erc-track-mode)
(defvar erc-network)
;; Two networks, same channel name, no confusion (no bouncer). Some
@@ -190,4 +192,51 @@
(with-current-buffer "#chan@barnet"
(erc-d-t-search-for 10 "I'll bid adieu")))))
+;; Some modules may need to perform housekeeping when a newly
+;; connected server buffer is deemed a duplicate after its persistent
+;; network context is discovered on MOTD end. One such module is
+;; `track', which needs to rid its list of modified channels of the
+;; buffer being killed. Without this, a user may encounter an
+;; "Attempt to display deleted buffer" error when they try switching
+;; to it.
+
+(ert-deftest erc-scenarios-networks-merge-server-track ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "networks/merge-server")
+ (dumb-server (erc-d-run "localhost" t 'track 'track))
+ (port (process-contact dumb-server :service))
+ (erc-server-flood-penalty 0.1)
+ (expect (erc-d-t-make-expecter)))
+
+ (ert-info ("Connect")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester")
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (should erc-track-mode)
+ (funcall expect 5 "changed mode for tester")
+ (erc-cmd-JOIN "#chan")))
+
+ (ert-info ("Join channel and quit")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+ (funcall expect 5 "The hour that fools should ask")
+ (erc-cmd-QUIT ""))
+ (with-current-buffer "FooNet"
+ (funcall expect 5 "finished")))
+
+ (ert-info ("Reconnect")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester")
+ (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+ (funcall expect 5 "changed mode for tester")))
+
+ (with-current-buffer "#chan"
+ (funcall expect 5 "The hour that fools should ask")
+ ;; Simulate the old `erc-track-switch-buffer'
+ (switch-to-buffer (erc-track-get-active-buffer 1))
+ (erc-d-t-wait-for 10 (eq (get-buffer "FooNet") (current-buffer)))
+ (erc-cmd-QUIT ""))))
+
;;; erc-scenarios-base-association.el ends here
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 @@
;;; Commentary:
-;; These tests all use `sasl' because, as of ERC 5.5, it's the one
-;; and only local module.
+;; A local module doubles as a minor mode whose mode variable and
+;; associated local data can withstand service disruptions.
+;; Unfortunately, the current implementation is too unwieldy to be
+;; made public because it doesn't perform any of the boiler plate
+;; needed to save and restore buffer-local and "network-local" copies
+;; of user options. Ultimately, a user-friendly framework must fill
+;; this void if third-party local modules are ever to become
+;; practical.
+;;
+;; The following tests all use `sasl' because, as of ERC 5.5, it's the
+;; only local module.
;;; Code:
@@ -206,7 +215,7 @@
(erc-cmd-QUIT "")
(funcall expect 10 "finished")))
- (ert-info ("Disabling works from a target buffer.")
+ (ert-info ("Disabling works from a target buffer")
(with-current-buffer "#chan"
(should erc-sasl-mode)
(call-interactively #'erc-sasl-disable)
@@ -214,10 +223,9 @@
(should (local-variable-p 'erc-sasl-mode))
(should-not (buffer-local-value 'erc-sasl-mode (get-buffer "foonet")))
(erc-cmd-RECONNECT)
- (with-current-buffer "#chan"
- (funcall expect 10 "Some enigma, some riddle")
- (should-not erc-sasl-mode) ; regression
- (should (local-variable-p 'erc-sasl-mode))))
+ (funcall expect 10 "Some enigma, some riddle")
+ (should-not erc-sasl-mode) ; regression
+ (should (local-variable-p 'erc-sasl-mode)))
(with-current-buffer "foonet"
(should (local-variable-p 'erc-sasl-mode))
@@ -239,4 +247,82 @@
(should erc-sasl-mode)
(funcall expect 10 "User modes for tester")))))
+(defvar-local erc-scenarios-base-local-modules--local-var nil)
+
+(define-erc-module -phony-sblm- nil
+ "Test module for `erc-scenarios-base-local-modules--var-persistence'."
+ ((when-let ((vars (or erc--server-reconnecting erc--target-priors)))
+ (should (assq 'erc--phony-sblm--mode vars))
+ (setq erc-scenarios-base-local-modules--local-var
+ (alist-get 'erc-scenarios-base-local-modules--local-var vars)))
+ (setq erc-scenarios-base-local-modules--local-var
+ (or erc-scenarios-base-local-modules--local-var
+ (if erc--target 100 0))))
+ ((kill-local-variable 'erc-scenarios-base-local-modules--local-var))
+ 'local)
+
+;; Note: this file has grown too expensive (time-wise) and must be
+;; split up. When that happens, this test should be rewritten without
+;; any time-saving hacks, namely, server-initiated JOINs and an
+;; absence of QUITs. (That said, three connections in under 2 seconds
+;; is pretty nice.)
+
+(ert-deftest erc-scenarios-base-local-modules--var-persistence ()
+ :tags '(:expensive-test)
+ (erc-scenarios-common-with-cleanup
+ ((erc-scenarios-common-dialog "base/reconnect")
+ (erc-server-flood-penalty 0.1)
+ (dumb-server (erc-d-run "localhost" t 'options 'options 'options))
+ (port (process-contact dumb-server :service))
+ (erc-modules (cons '-phony-sblm- (remq 'autojoin erc-modules)))
+ (expect (erc-d-t-make-expecter))
+ (server-buffer-name (format "127.0.0.1:%d" port)))
+
+ (ert-info ("Initial authentication succeeds as expected")
+ (with-current-buffer (erc :server "127.0.0.1"
+ :port port
+ :nick "tester"
+ :password "changeme"
+ :full-name "tester")
+ (should (string= (buffer-name) server-buffer-name)))
+
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "FooNet"))
+ (funcall expect 10 "This server is in debug mode")
+ (should erc--phony-sblm--mode)
+ (should (eql erc-scenarios-base-local-modules--local-var 0))
+ (setq erc-scenarios-base-local-modules--local-var 1)))
+
+ (ert-info ("Save module's local var in target buffer")
+ (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+ (should (eql erc-scenarios-base-local-modules--local-var 100))
+ (setq erc-scenarios-base-local-modules--local-var 101)
+ (funcall expect 20 "welcome")))
+
+ (with-current-buffer "FooNet" (funcall expect 20 "terminated"))
+
+ (ert-info ("Vars reused when mode was left enabled")
+ (with-current-buffer "#chan"
+ (erc-cmd-RECONNECT)
+ (funcall expect 20 "welcome")
+ (should (eql erc-scenarios-base-local-modules--local-var 101))
+ (erc--phony-sblm--mode -1))
+
+ (with-current-buffer "FooNet"
+ (funcall expect 10 "User modes for tester")
+ (should (eql erc-scenarios-base-local-modules--local-var 1))))
+
+ (with-current-buffer "FooNet" (funcall expect 20 "terminated"))
+
+ (ert-info ("Local binding gone when mode disabled in target")
+ (with-current-buffer "#chan"
+ (erc-cmd-RECONNECT)
+ (funcall expect 20 "welcome")
+ (should-not erc--phony-sblm--mode)
+ (should-not erc-scenarios-base-local-modules--local-var))
+
+ ;; But value retained in server buffer, where mode is active.
+ (with-current-buffer "FooNet"
+ (funcall expect 10 "User modes for tester")
+ (should (eql erc-scenarios-base-local-modules--local-var 1))))))
+
;;; erc-scenarios-local-modules.el ends here
diff --git a/test/lisp/erc/erc-services-tests.el b/test/lisp/erc/erc-services-tests.el
index b1d36d868eb..9181a47ee3b 100644
--- a/test/lisp/erc/erc-services-tests.el
+++ b/test/lisp/erc/erc-services-tests.el
@@ -248,7 +248,8 @@
(let ((auth-sources (list plstore-file))
(auth-source-do-cache nil))
(erc-services-tests--auth-source-standard
- #'erc-services-test--call-with-plstore))))
+ #'erc-services-test--call-with-plstore))
+ (kill-buffer (get-file-buffer plstore-file))))
(ert-deftest erc--auth-source-search--plstore-announced ()
(ert-with-temp-file plstore-file
@@ -264,7 +265,8 @@
(let ((auth-sources (list plstore-file))
(auth-source-do-cache nil))
(erc-services-tests--auth-source-announced
- #'erc-services-test--call-with-plstore))))
+ #'erc-services-test--call-with-plstore))
+ (kill-buffer (get-file-buffer plstore-file))))
(ert-deftest erc--auth-source-search--plstore-overrides ()
(ert-with-temp-file plstore-file
@@ -296,7 +298,8 @@
(let ((auth-sources (list plstore-file))
(auth-source-do-cache nil))
(erc-services-tests--auth-source-overrides
- #'erc-services-test--call-with-plstore))))
+ #'erc-services-test--call-with-plstore))
+ (kill-buffer (get-file-buffer plstore-file))))
;; auth-source JSON backend
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 @@
(setq calls nil)))))
(ert-deftest erc--merge-local-modes ()
-
- (ert-info ("No existing modes")
- (let ((old '((a) (b . t)))
- (new '(erc-c-mode erc-d-mode)))
- (should (equal (erc--merge-local-modes new old)
- '((erc-c-mode erc-d-mode))))))
-
- (ert-info ("Active existing added, inactive existing removed, deduped")
- (let ((old '((a) (erc-b-mode) (c . t) (erc-d-mode . t) (erc-e-mode . t)))
- (new '(erc-b-mode erc-d-mode)))
- (should (equal (erc--merge-local-modes new old)
- '((erc-d-mode erc-e-mode) . (erc-b-mode)))))))
+ (cl-letf (((get 'erc-b-mode 'erc-module) 'b)
+ ((get 'erc-c-mode 'erc-module) 'c)
+ ((get 'erc-d-mode 'erc-module) 'd)
+ ((get 'erc-e-mode 'erc-module) 'e))
+
+ (ert-info ("No existing modes")
+ (let ((old '((a) (b . t)))
+ (new '(erc-c-mode erc-d-mode)))
+ (should (equal (erc--merge-local-modes new old)
+ '((erc-c-mode erc-d-mode))))))
+
+ (ert-info ("Active existing added, inactive existing removed, deduped")
+ (let ((old '((a) (erc-b-mode) (c . t) (erc-d-mode . t) (erc-e-mode . t)))
+ (new '(erc-b-mode erc-d-mode)))
+ (should (equal (erc--merge-local-modes new old)
+ '((erc-d-mode erc-e-mode) . (erc-b-mode))))))
+
+ (ert-info ("Non-module erc-prefixed mode ignored")
+ (let ((old '((erc-b-mode) (erc-f-mode . t) (erc-d-mode . t)))
+ (new '(erc-b-mode)))
+ (should (equal (erc--merge-local-modes new old)
+ '((erc-d-mode) . (erc-b-mode))))))))
(ert-deftest define-erc-module--global ()
(let ((global-module '(define-erc-module mname malias
@@ -1300,13 +1310,15 @@ Some docstring"
(ignore c) (ignore d))
(defalias 'erc-malias-mode #'erc-mname-mode)
+ (put 'erc-malias-mode 'erc-module 'mname)
+ (put 'erc-mname-mode 'erc-module 'mname)
(put 'erc-mname-mode 'definition-name 'mname)
(put 'erc-mname-enable 'definition-name 'mname)
(put 'erc-mname-disable 'definition-name 'mname))))))
(ert-deftest define-erc-module--local ()
- (let* ((global-module '(define-erc-module mname malias
+ (let* ((global-module '(define-erc-module mname nil ; no alias
"Some docstring"
((ignore a) (ignore b))
((ignore c) (ignore d))
@@ -1353,8 +1365,7 @@ When called interactively, do so in all buffers for the current connection."
(setq erc-mname-mode nil)
(ignore c) (ignore d))))
- (defalias 'erc-malias-mode #'erc-mname-mode)
-
+ (put 'erc-mname-mode 'erc-module 'mname)
(put 'erc-mname-mode 'definition-name 'mname)
(put 'erc-mname-enable 'definition-name 'mname)
(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 @@
;; -*- mode: lisp-data; -*-
((pass 10 "PASS :barnet:changeme"))
-((nick 3 "NICK tester"))
-((user 3 "USER user 0 * :tester")
+((nick 10 "NICK tester"))
+((user 10 "USER user 0 * :tester")
(0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
(0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version oragono-2.6.0-7481bf0385b95b16")
(0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021 07:41:08 UTC")
@@ -17,7 +17,7 @@
(0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.barnet.org 422 tester :MOTD File is missing"))
-((mode-user 10.2 "MODE tester +i")
+((mode-user 10 "MODE tester +i")
;; No mode answer ^
(0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #chan")
@@ -36,9 +36,9 @@
(0 ":irc.znc.in 306 tester :You have been marked as being away")
(0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
-((~join 3 "JOIN #chan"))
+((~join 10 "JOIN #chan"))
-((mode 5 "MODE #chan")
+((mode 10 "MODE #chan")
(0 ":irc.barnet.org 324 tester #chan +nt")
(0 ":irc.barnet.org 329 tester #chan 1620805269")
(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 @@
;; -*- mode: lisp-data; -*-
((pass 10 "PASS :foonet:changeme"))
-((nick 3 "NICK tester"))
-((user 3 "USER user 0 * :tester")
+((nick 10 "NICK tester"))
+((user 10 "USER user 0 * :tester")
(0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
(0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.0-7481bf0385b95b16")
(0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021 07:41:09 UTC")
@@ -17,7 +17,7 @@
(0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
(0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-((mode-user 10.2 "MODE tester +i")
+((mode-user 10 "MODE tester +i")
;; No mode answer ^
(0 ":tester!~u@nvfhxvqm92rm6.irc JOIN #chan")
(0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
@@ -36,9 +36,9 @@
(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.")
(0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
-((~join 3 "JOIN #chan"))
+((~join 10 "JOIN #chan"))
-((mode 8 "MODE #chan")
+((mode 10 "MODE #chan")
(0 ":irc.foonet.org 324 tester #chan +nt")
(0 ":irc.foonet.org 329 tester #chan 1620805271")
(0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: Grows, lives, and dies, in single blessedness.")
diff --git a/test/lisp/erc/resources/erc-d/erc-d-t.el b/test/lisp/erc/resources/erc-d/erc-d-t.el
index 282c193b707..7b2adf4f07b 100644
--- a/test/lisp/erc/resources/erc-d/erc-d-t.el
+++ b/test/lisp/erc/resources/erc-d/erc-d-t.el
@@ -32,7 +32,7 @@
(dolist (buf (buffer-list))
(with-current-buffer buf
(when (or erc-d-u--process-buffer
- (derived-mode-p 'erc-mode))
+ (derived-mode-p 'erc-mode 'erc-dcc-chat-mode))
(push buf buflist))))
(dolist (buf buflist)
(when (and (boundp 'erc-server-flood-timer)
diff --git a/test/lisp/erc/resources/networks/merge-server/track.eld b/test/lisp/erc/resources/networks/merge-server/track.eld
new file mode 100644
index 00000000000..19c37aaf40b
--- /dev/null
+++ b/test/lisp/erc/resources/networks/merge-server/track.eld
@@ -0,0 +1,44 @@
+;; -*- mode: lisp-data; -*-
+((nick 10 "NICK tester"))
+((user 10 "USER user 0 * :unknown")
+ (0.00 ":irc.example.net NOTICE * :*** Looking up your hostname...")
+ (0.01 ":irc.example.net NOTICE tester :*** Could not resolve your hostname: Domain not found; using your IP address (10.0.2.100) instead.")
+ (0.10 ":irc.example.net 001 tester :Welcome to the FooNet IRC Network tester!user@10.0.2.100")
+ (0.02 ":irc.example.net 002 tester :Your host is irc.example.net, running version InspIRCd-3")
+ (0.02 ":irc.example.net 003 tester :This server was created 05:58:57 Jan 04 2023")
+ (0.01 ":irc.example.net 004 tester irc.example.net InspIRCd-3 BIRcgikorsw ACHIKMORTXabcefghijklmnopqrstvz :HIXabefghjkloqv")
+ (0.00 ":irc.example.net 005 tester ACCEPT=30 AWAYLEN=200 BOT=B CALLERID=g CASEMAPPING=ascii CHANLIMIT=#:20 CHANMODES=IXbeg,k,Hfjl,ACKMORTcimnprstz CHANNELLEN=64 CHANTYPES=# ELIST=CMNTU ESILENCE=CcdiNnPpTtx EXCEPTS=e :are supported by this server")
+ (0.02 ":irc.example.net 005 tester EXTBAN=,ACORTUacjrwz HOSTLEN=64 INVEX=I KEYLEN=32 KICKLEN=255 LINELEN=512 MAXLIST=I:100,X:100,b:100,e:100,g:100 MAXTARGETS=20 MODES=20 MONITOR=30 NAMELEN=128 NAMESX NETWORK=FooNet :are supported by this server")
+ (0.01 ":irc.example.net 005 tester NICKLEN=30 PREFIX=(qaohv)~&@%+ SAFELIST SILENCE=32 STATUSMSG=~&@%+ TOPICLEN=307 UHNAMES USERIP USERLEN=10 USERMODES=,,s,BIRcgikorw WHOX :are supported by this server")
+ (0.01 ":irc.example.net 251 tester :There are 2 users and 0 invisible on 2 servers")
+ (0.01 ":irc.example.net 253 tester 1 :unknown connections")
+ (0.01 ":irc.example.net 254 tester 1 :channels formed")
+ (0.00 ":irc.example.net 255 tester :I have 2 clients and 1 servers")
+ (0.00 ":irc.example.net 265 tester :Current local users: 2 Max: 3")
+ (0.00 ":irc.example.net 266 tester :Current global users: 2 Max: 3")
+ (0.00 ":irc.example.net 375 tester :irc.example.net message of the day")
+ (0.00 ":irc.example.net 372 tester : Have fun with the image!")
+ (0.00 ":irc.example.net 376 tester :End of message of the day."))
+
+((mode 10 "MODE tester +i")
+ (0.00 ":irc.example.net 501 tester x :is not a recognized user mode.")
+ (0.00 ":NickServ!NickServ@services.int NOTICE tester :Welcome to FooNet, tester! Here on FooNet, we provide services to enable the registration of nicknames and channels! For details, type \2/msg NickServ help\2 and \2/msg ChanServ help\2.")
+ (0.02 ":tester!user@10.0.2.100 MODE tester :+i"))
+
+((join 10 "JOIN #chan")
+ (0.01 ":tester!user@10.0.2.100 JOIN :#chan"))
+
+((mode 10 "MODE #chan")
+ (0.01 ":irc.example.net 353 tester = #chan :@alice bob tester")
+ (0.01 ":irc.example.net 366 tester #chan :End of /NAMES list.")
+ (0.00 ":alice!alice@0::1 PRIVMSG #chan :tester, welcome!")
+ (0.02 ":bob!bob@0::1 PRIVMSG #chan :tester, welcome!")
+ (0.02 ":irc.example.net 324 tester #chan :+nt")
+ (0.01 ":irc.example.net 329 tester #chan :1672811954")
+ (0.07 ":alice!alice@0::1 PRIVMSG #chan :bob: This afternoon, sir ? well, she shall be there.")
+ (0.05 ":bob!bob@0::1 PRIVMSG #chan :alice: The hour that fools should ask."))
+
+((quit 10 "QUIT :\2ERC\2")
+ (0.04 "ERROR :Closing link: (user@10.0.2.100) [Quit: \2ERC\2]"))
+
+((drop 1 DROP))
diff --git a/test/lisp/international/mule-tests.el b/test/lisp/international/mule-tests.el
index 4f70b275848..6e23d8c5421 100644
--- a/test/lisp/international/mule-tests.el
+++ b/test/lisp/international/mule-tests.el
@@ -70,6 +70,72 @@
;; The chinese-hz encoding is not ASCII compatible.
(should-not (coding-system-get 'chinese-hz :ascii-compatible-p)))
+;;; Testing `sgml-html-meta-auto-coding-function'.
+
+(defconst sgml-html-meta-pre "<!doctype html><html><head>"
+ "The beginning of a minimal HTML document.")
+
+(defconst sgml-html-meta-post "</head></html>"
+ "The end of a minimal HTML document.")
+
+(defun sgml-html-meta-run (coding-system)
+ "Run `sgml-html-meta-auto-coding-function' on a minimal HTML.
+When CODING-SYSTEM is not nil, insert it, wrapped in a '<meta>'
+element. When CODING-SYSTEM contains HTML meta characters or
+white space, insert it as-is, without additional formatting. Use
+the variables `sgml-html-meta-pre' and `sgml-html-meta-post' to
+provide HTML fragments. Some tests override those variables."
+ (with-temp-buffer
+ (insert sgml-html-meta-pre
+ (cond ((not coding-system)
+ "")
+ ((string-match "[<>'\"\n ]" coding-system)
+ coding-system)
+ (t
+ (format "<meta charset='%s'>" coding-system)))
+ sgml-html-meta-post)
+ (goto-char (point-min))
+ (sgml-html-meta-auto-coding-function (- (point-max) (point-min)))))
+
+(ert-deftest sgml-html-meta-utf-8 ()
+ "Baseline: UTF-8."
+ (should (eq 'utf-8 (sgml-html-meta-run "utf-8"))))
+
+(ert-deftest sgml-html-meta-windows-hebrew ()
+ "A non-Unicode charset."
+ (should (eq 'windows-1255 (sgml-html-meta-run "windows-1255"))))
+
+(ert-deftest sgml-html-meta-none ()
+ (should (eq nil (sgml-html-meta-run nil))))
+
+(ert-deftest sgml-html-meta-unknown-coding ()
+ (should (eq nil (sgml-html-meta-run "XXX"))))
+
+(ert-deftest sgml-html-meta-no-pre ()
+ "Without the prefix, so not HTML."
+ (let ((sgml-html-meta-pre ""))
+ (should (eq nil (sgml-html-meta-run "utf-8")))))
+
+(ert-deftest sgml-html-meta-no-post-less-than-10lines ()
+ "No '</head>', detect charset in the first 10 lines."
+ (let ((sgml-html-meta-post ""))
+ (should (eq 'utf-8 (sgml-html-meta-run
+ (concat "\n\n\n\n\n\n\n\n\n"
+ "<meta charset='utf-8'>"))))))
+
+(ert-deftest sgml-html-meta-no-post-10lines ()
+ "No '</head>', do not detect charset after the first 10 lines."
+ (let ((sgml-html-meta-post ""))
+ (should (eq nil (sgml-html-meta-run
+ (concat "\n\n\n\n\n\n\n\n\n\n"
+ "<meta charset='utf-8'>"))))))
+
+(ert-deftest sgml-html-meta-utf-8-with-bom ()
+ "Requesting 'UTF-8' does not override `utf-8-with-signature'.
+Check fix for Bug#20623."
+ (let ((buffer-file-coding-system 'utf-8-with-signature))
+ (should (eq 'utf-8-with-signature (sgml-html-meta-run "utf-8")))))
+
;; Stop "Local Variables" above causing confusion when visiting this file.
diff --git a/test/lisp/net/tramp-archive-tests.el b/test/lisp/net/tramp-archive-tests.el
index 96c1e78e37a..b28b32bc7d3 100644
--- a/test/lisp/net/tramp-archive-tests.el
+++ b/test/lisp/net/tramp-archive-tests.el
@@ -694,6 +694,7 @@ This tests also `access-file', `file-readable-p' and `file-regular-p'."
;; Symlink.
(should (file-exists-p tmp-name2))
(should (file-symlink-p tmp-name2))
+ (should (file-regular-p tmp-name2))
(setq attr (file-attributes tmp-name2))
(should (string-equal (car attr) (file-name-nondirectory tmp-name1)))
@@ -784,12 +785,14 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
(unwind-protect
(progn
(should (file-exists-p tmp-name1))
+ (should (file-regular-p tmp-name1))
(should (string-equal tmp-name1 (file-truename tmp-name1)))
;; `make-symbolic-link' is not implemented.
(should-error
(make-symbolic-link tmp-name1 tmp-name2)
:type 'file-error)
(should (file-symlink-p tmp-name2))
+ (should (file-regular-p tmp-name2))
(should
(string-equal
;; This is "/foo.txt".
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index a3d7d9f656b..ff0fc56043e 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -3495,6 +3495,9 @@ This tests also `access-file', `file-readable-p',
(access-file tmp-name1 "error")
:type 'file-missing)
+ (should-not (file-exists-p tmp-name1))
+ (should-not (file-readable-p tmp-name1))
+ (should-not (file-regular-p tmp-name1))
;; `file-ownership-preserved-p' should return t for
;; non-existing files.
(when test-file-ownership-preserved-p
@@ -3579,7 +3582,7 @@ This tests also `access-file', `file-readable-p',
(should (file-exists-p tmp-name1))
(should (file-readable-p tmp-name1))
(should-not (file-regular-p tmp-name1))
- (should-not (access-file tmp-name1 ""))
+ (should-not (access-file tmp-name1 "error"))
(when test-file-ownership-preserved-p
(should (file-ownership-preserved-p tmp-name1 'group)))
(setq attr (file-attributes tmp-name1))
@@ -3927,7 +3930,10 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(tramp--test-ignore-make-symbolic-link-error
(write-region "foo" nil tmp-name1)
(should (file-exists-p tmp-name1))
+ (should (file-regular-p tmp-name1))
(make-symbolic-link tmp-name1 tmp-name2)
+ (should (file-exists-p tmp-name2))
+ (should (file-regular-p tmp-name2))
(should
(string-equal
(funcall
@@ -3978,6 +3984,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(string-equal tmp-name1 (file-symlink-p tmp-name3))))
;; Check directory as newname.
(make-directory tmp-name4)
+ (should (file-directory-p tmp-name4))
+ (should-not (file-regular-p tmp-name4))
(when (tramp--test-expensive-test-p)
(should-error
(make-symbolic-link tmp-name1 tmp-name4)
@@ -3991,6 +3999,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(file-symlink-p tmp-name5)))
;; Check, that files in symlinked directories still work.
(make-symbolic-link tmp-name4 tmp-name6)
+ (should (file-symlink-p tmp-name6))
+ (should-not (file-regular-p tmp-name6))
(write-region "foo" nil (expand-file-name "foo" tmp-name6))
(delete-file (expand-file-name "foo" tmp-name6))
(should-not (file-exists-p (expand-file-name "foo" tmp-name4)))
@@ -4052,9 +4062,11 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(tramp--test-ignore-make-symbolic-link-error
(write-region "foo" nil tmp-name1)
(should (file-exists-p tmp-name1))
+ (should (file-regular-p tmp-name1))
(should (string-equal tmp-name1 (file-truename tmp-name1)))
(make-symbolic-link tmp-name1 tmp-name2)
(should (file-symlink-p tmp-name2))
+ (should (file-regular-p tmp-name2))
(should-not (string-equal tmp-name2 (file-truename tmp-name2)))
(should
(string-equal (file-truename tmp-name1) (file-truename tmp-name2)))
@@ -4064,6 +4076,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(let ((default-directory ert-remote-temporary-file-directory))
(make-symbolic-link (file-name-nondirectory tmp-name1) tmp-name2))
(should (file-symlink-p tmp-name2))
+ (should (file-regular-p tmp-name2))
(should-not (string-equal tmp-name2 (file-truename tmp-name2)))
(should
(string-equal (file-truename tmp-name1) (file-truename tmp-name2)))
@@ -4079,6 +4092,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(if quoted #'tramp-compat-file-name-unquote #'identity) penguin)
tmp-name2)
(should (file-symlink-p tmp-name2))
+ (should-not (file-regular-p tmp-name2))
(should
(string-equal
(file-truename tmp-name2)
@@ -4089,6 +4103,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(unless (tramp--test-windows-nt-p)
(make-symbolic-link tmp-name1 tmp-name3)
(should (file-symlink-p tmp-name3))
+ (should-not (file-regular-p tmp-name3))
(should-not (string-equal tmp-name3 (file-truename tmp-name3)))
;; `file-truename' returns a quoted file name for `tmp-name3'.
;; We must unquote it.
@@ -4117,6 +4132,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(make-symbolic-link
tmp-name3
(setq tmp-name3 (tramp--test-make-temp-name nil quoted))))
+ (should-not (file-regular-p tmp-name2))
+ (should-not (file-regular-p tmp-name3))
(should
(string-equal
(file-truename tmp-name2)
@@ -4147,6 +4164,8 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(tramp--test-ignore-make-symbolic-link-error
(make-symbolic-link tmp-name2 tmp-name1)
(should (file-symlink-p tmp-name1))
+ (should-not (file-regular-p tmp-name1))
+ (should-not (file-regular-p tmp-name2))
(if (tramp--test-smb-p)
;; The symlink command of "smbclient" detects the
;; cycle already.
@@ -4155,6 +4174,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
:type 'file-error)
(make-symbolic-link tmp-name1 tmp-name2)
(should (file-symlink-p tmp-name2))
+ (should-not (file-regular-p tmp-name2))
(should-error
(file-truename tmp-name1)
:type 'file-error))))
@@ -5504,7 +5524,7 @@ INPUT, if non-nil, is a string sent to the process."
(format "%s\n" (file-name-nondirectory tmp-name)))
(should
(string-match-p
- ;; Some shells echo, for example the "adb" or "docker" methods.
+ ;; Some shells echo, for example the "adb" or container methods.
(tramp-compat-rx
bos (** 1 2 (literal (file-name-nondirectory tmp-name)) "\n")
eos)
@@ -6637,11 +6657,12 @@ This is used in tests which we don't want to tag
"Check, whether the remote directory is encrypted."
(tramp-crypt-file-name-p ert-remote-temporary-file-directory))
-(defun tramp--test-docker-p ()
- "Check, whether the docker method is used.
+(defun tramp--test-container-p ()
+ "Check, whether a container method is used.
This does not support some special file names."
- (string-equal
- "docker" (file-remote-p ert-remote-temporary-file-directory 'method)))
+ (string-match-p
+ (rx bol (| "docker" "podman") eol)
+ (file-remote-p ert-remote-temporary-file-directory 'method)))
(defun tramp--test-expensive-test-p ()
"Whether expensive tests are run.
@@ -7026,7 +7047,7 @@ This requires restrictions of file name syntax."
(let ((files
(list
(cond ((or (tramp--test-ange-ftp-p)
- (tramp--test-docker-p)
+ (tramp--test-container-p)
(tramp--test-gvfs-p)
(tramp--test-rclone-p)
(tramp--test-sudoedit-p)
@@ -7084,7 +7105,7 @@ This requires restrictions of file name syntax."
"Check UTF8 encoding in file names and file contents."
(skip-unless (tramp--test-enabled))
(skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 620s
- (skip-unless (not (tramp--test-docker-p)))
+ (skip-unless (not (tramp--test-container-p)))
(skip-unless (not (tramp--test-rsync-p)))
(skip-unless (not (tramp--test-windows-nt-and-out-of-band-p)))
(skip-unless (not (tramp--test-ksh-p)))
@@ -7213,7 +7234,7 @@ process sentinels. They shall not disturb each other."
;; remote processes in Emacs. That doesn't work for tramp-adb.el.
(when (tramp--test-adb-p)
(skip-unless (tramp--test-emacs27-p)))
- (skip-unless (not (tramp--test-docker-p)))
+ (skip-unless (not (tramp--test-container-p)))
(skip-unless (not (tramp--test-telnet-p)))
(skip-unless (not (tramp--test-sshfs-p)))
(skip-unless (not (tramp--test-windows-nt-p)))
@@ -7703,6 +7724,8 @@ If INTERACTIVE is non-nil, the tests are run interactively."
;; * file-equal-p (partly done in `tramp-test21-file-links')
;; * file-in-directory-p
;; * file-name-case-insensitive-p
+;; * memory-info
+;; * tramp-get-home-directory
;; * tramp-get-remote-gid
;; * tramp-get-remote-groups
;; * tramp-get-remote-uid
diff --git a/test/lisp/progmodes/c-ts-mode-resources/filling.erts b/test/lisp/progmodes/c-ts-mode-resources/filling.erts
new file mode 100644
index 00000000000..e51e3658c83
--- /dev/null
+++ b/test/lisp/progmodes/c-ts-mode-resources/filling.erts
@@ -0,0 +1,198 @@
+Code:
+ (lambda ()
+ (c-ts-mode)
+ (setq-local indent-tabs-mode nil)
+ (fill-paragraph))
+
+Point-Char: |
+
+Name: Type 1
+
+=-=
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ */
+=-=
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ */
+=-=-=
+
+Name: Type 2
+
+=-=
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ */
+=-=
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ */
+=-=-=
+
+Name: Type 3
+
+=-=
+/*================================================================
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ ================================================================*/
+=-=
+/*================================================================
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ ================================================================*/
+=-=-=
+
+Name: Type 4
+
+=-=
+/*================================================================
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy
+ * ================================================================*/
+=-=
+/*================================================================
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy
+ * ================================================================*/
+=-=-=
+
+Name: Type 5
+
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ */
+=-=
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ * woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ */
+=-=-=
+
+Name: Type 6
+
+=-=
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ */
+=-=
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ */
+=-=-=
+
+Name: Type 6
+
+=-=
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ */
+=-=
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ */
+=-=-=
+
+Name: Type 7
+
+=-=
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+=-=
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+=-=-=
+
+Name: Type 8
+
+=-=
+// ================================================================
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// ================================================================
+=-=
+// ================================================================
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// ================================================================
+=-=-=
+
+Name: Type 9
+
+=-=
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomyyy */
+=-=
+/* woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ woooomyyy */
+=-=-=
+
+Name: Not Over Fill 1
+
+=-=
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+
+// |woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+=-=-=
+
+Name: Not Over Fill 2
+
+=-=
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+return; // woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+//| woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+return; // woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+=-=
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+return; // woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+return; // woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+=-=-=
+
+Name: Not Over Fill 3
+
+=-=
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+return; //| woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+return; // woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+=-=
+// woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+return; // woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ // woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ // woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+ // woooomy woooomy
+return; // woooomy woooomy woooomy woooomy woooomy woooomy woooomy woooomy
+=-=-=
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts b/test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts
new file mode 100644
index 00000000000..07698077ffc
--- /dev/null
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts
@@ -0,0 +1,93 @@
+Code:
+ (lambda ()
+ (setq indent-tabs-mode nil)
+ (setq c-ts-mode-indent-offset 2)
+ (setq c-ts-mode-indent-style 'bsd)
+ (c-ts-mode)
+ (indent-region (point-min) (point-max)))
+
+Point-Char: |
+
+Name: Basic
+
+=-=
+int
+main (void)
+{
+ return 0;
+}
+=-=-=
+
+Name: Hanging Braces
+
+=-=
+int
+main (void)
+{
+ if (true)
+ {
+ |
+ }
+}
+=-=-=
+
+Name: Labels
+
+=-=
+int
+main (void)
+{
+ label:
+ return 0;
+ if (true)
+ {
+ label:
+ return 0;
+ }
+ else
+ {
+ if (true)
+ {
+ label:
+ return 0;
+ }
+ }
+}
+=-=-=
+
+Name: If-Else
+
+=-=
+int main()
+{
+ if (true)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+=-=-=
+
+Name: Empty Line
+=-=
+int main()
+{
+ |
+}
+=-=-=
+
+Name: Consecutive blocks (bug#60873)
+
+=-=
+int
+main (int argc,
+ char *argv[])
+{
+ {
+ int i = 0;
+ }
+}
+=-=-=
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent.erts b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
new file mode 100644
index 00000000000..b8524432d02
--- /dev/null
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
@@ -0,0 +1,190 @@
+Code:
+ (lambda ()
+ (setq indent-tabs-mode nil)
+ (setq c-ts-mode-indent-offset 2)
+ (setq c-ts-mode-indent-style 'gnu)
+ (c-ts-mode)
+ (indent-region (point-min) (point-max)))
+
+Point-Char: |
+
+Name: Basic
+
+=-=
+int
+main (void)
+{
+ return 0;
+}
+=-=-=
+
+Name: Hanging Braces (GNU Style)
+
+=-=
+int
+main (void)
+{
+ if (true)
+ {
+ }
+}
+=-=-=
+
+Name: Labels (GNU Style)
+
+=-=
+int
+main (void)
+{
+ label:
+ return 0;
+ if (true)
+ {
+ label:
+ return 0;
+ }
+ else
+ {
+ if (true)
+ {
+ label:
+ return 0;
+ }
+ }
+}
+=-=-=
+
+Name: For Loop with Multi-line Condition (GNU Style)
+
+=-=
+int main()
+{
+ for (int i = 0;
+ i < b;
+ i++)
+ {
+ return 0;
+ }
+}
+=-=-=
+
+Name: If-Else (GNU Style)
+
+=-=
+int main()
+{
+ if (true)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+=-=-=
+
+Name: Empty Line
+=-=
+int main()
+{
+ |
+}
+=-=-=
+
+Name: Concecutive blocks (GNU Style) (bug#60873)
+
+=-=
+int
+main (int argc,
+ char *argv[])
+{
+ {
+ int i = 0;
+ }
+}
+=-=-=
+
+Name: Multiline Parameter List (bug#60398)
+
+=-=
+int f2(int x,
+ int y) {
+ return x + y;
+};
+=-=-=
+
+Name: Multiline Block Comments 1 (bug#60270)
+
+=-=
+/**
+ * @some_func:
+ * @arg1:
+ */
+=-=-=
+
+Name: Multiline Block Comments 2 (bug#60270)
+
+=-=
+/*
+ some comment
+ */
+=-=-=
+
+Name: Multiline Block Comments 3 (bug#60270)
+
+=-=
+/* some comment
+ */
+=-=-=
+
+Name: Multiline Block Comments 4 (bug#60270)
+
+=-=
+/*
+ * Some comment
+ */
+=-=-=
+
+Name: Multiline Block Comments 5 (bug#60270)
+
+=-=
+/*
+line one
+line 2
+ */
+=-=
+/*
+ line one
+ line 2
+ */
+=-=-=
+
+
+Code:
+ (lambda ()
+ (setq indent-tabs-mode nil)
+ (setq c-ts-mode-indent-offset 8)
+ (setq c-ts-mode-indent-style 'linux)
+ (c-ts-mode)
+ (indent-region (point-min) (point-max)))
+
+Name: Labels (Linux Style)
+
+=-=-=
+int main (void)
+{
+label:
+ return 0;
+ if (true) {
+label:
+ return 0;
+ }
+ else {
+ if (true) {
+label:
+ return 0;
+ }
+ }
+}
+=-=-=
diff --git a/test/lisp/progmodes/c-ts-mode-tests.el b/test/lisp/progmodes/c-ts-mode-tests.el
new file mode 100644
index 00000000000..ddf64b40736
--- /dev/null
+++ b/test/lisp/progmodes/c-ts-mode-tests.el
@@ -0,0 +1,39 @@
+;;; c-ts-mode-tests.el --- Tests for Tree-sitter-based C mode -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'ert-x)
+(require 'treesit)
+
+(ert-deftest c-ts-mode-test-indentation ()
+ (skip-unless (treesit-ready-p 'c))
+ (ert-test-erts-file (ert-resource-file "indent.erts")))
+
+(ert-deftest c-ts-mode-test-indentation-bsd ()
+ (skip-unless (treesit-ready-p 'c))
+ (ert-test-erts-file (ert-resource-file "indent-bsd.erts")))
+
+(ert-deftest c-ts-mode-test-filling ()
+ (skip-unless (treesit-ready-p 'c))
+ (ert-test-erts-file (ert-resource-file "filling.erts")))
+
+(provide 'c-ts-mode-tests)
+;;; c-ts-mode-tests.el ends here
diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el
index eac558db10f..df71990278e 100644
--- a/test/lisp/progmodes/python-tests.el
+++ b/test/lisp/progmodes/python-tests.el
@@ -4520,6 +4520,16 @@ def foo():
(python-tests-look-at "\"\"\""))
"# -*- coding: utf-8 -*-\n\nif True:\n a = 1\n b = 2\n\n"))))
+(ert-deftest python-shell-buffer-substring-18 ()
+ "Check substring from the part of the first line."
+ (python-tests-with-temp-buffer
+ "s = 'test'
+"
+ (should (string= (python-shell-buffer-substring
+ (python-tests-look-at "'test'")
+ (pos-eol))
+ "'test'"))))
+
;;; Shell completion
diff --git a/test/lisp/progmodes/ruby-mode-resources/ruby-method-call-indent.rb b/test/lisp/progmodes/ruby-mode-resources/ruby-method-call-indent.rb
index 1a8285ee919..624a6caafe5 100644
--- a/test/lisp/progmodes/ruby-mode-resources/ruby-method-call-indent.rb
+++ b/test/lisp/progmodes/ruby-mode-resources/ruby-method-call-indent.rb
@@ -1,3 +1,8 @@
+foo = subject
+ .update(
+ 1
+ )
+
foo2 =
subject.
update(
@@ -10,6 +15,10 @@ foo3 =
2
)
+my_array.select { |str| str.size > 5 }
+ .map { |str| str.downcase }
+
# Local Variables:
# ruby-method-call-indent: nil
+# ruby-align-chained-calls: nil
# End:
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 @@
+variable = foo(
+ [
+ qwe
+ ], [
+ rty
+ ], {
+ a: 3
+ }
+)
+
+tee = [
+ qwe
+]
+
+qux = [1,
+ 2]
+
+att = {a: 1,
+ b: 2}
+
+a = 1 ? 2 :(
+ 2 + 3
+)
+
+unless bismark
+ sink += 12
+else
+ dog = 99
+end
+
+foo1 =
+ subject.update(
+ 1
+ )
+
+foo2 =
+ subject.
+ update(
+ # Might make sense to indent this to 'subject' instead; but this
+ # style seems more popular.
+ 2
+ )
+
+foo > bar &&
+ tee < qux
+
+1 .. 2 &&
+ 3
+
+a = foo(j, k) -
+ bar_tee
+
+qux = foo.fee ?
+ bar :
+ tee
+
+with_paren = (a + b *
+ c * d +
+ 12)
+
+without_paren = a + b *
+ c * d +
+ 12
+
+{'a' => {
+ 'b' => 'c',
+ 'd' => %w(e f)
+ }
+}
+
+[1, 2, {
+ 'b' => 'c',
+ 'd' => %w(e f)
+ }
+]
+
+foo(a, {
+ a: b,
+ c: d
+ })
+
+foo(foo, bar:
+ tee)
+
+foo(foo, :bar =>
+ tee)
+
+# Local Variables:
+# mode: ruby-ts
+# ruby-after-operator-indent: t
+# ruby-block-indent: t
+# ruby-method-call-indent: t
+# ruby-method-params-indent: t
+# End:
diff --git a/test/lisp/progmodes/ruby-mode-resources/ruby.rb b/test/lisp/progmodes/ruby-mode-resources/ruby.rb
index bfae948b259..3f0dfdf68ba 100644
--- a/test/lisp/progmodes/ruby-mode-resources/ruby.rb
+++ b/test/lisp/progmodes/ruby-mode-resources/ruby.rb
@@ -513,7 +513,7 @@ foo bar, {
case translation
in ['th', orig_text, 'en', trans_text]
puts "English translation: #{orig_text} => #{trans_text}"
-in {'th' => orig_text, 'ja' => trans_text}
+in {th: orig_text, ja: trans_text} => whole
puts "Japanese translation: #{orig_text} => #{trans_text}"
end
diff --git a/test/lisp/progmodes/ruby-mode-tests.el b/test/lisp/progmodes/ruby-mode-tests.el
index 9687231dbfa..8a75c83d2c3 100644
--- a/test/lisp/progmodes/ruby-mode-tests.el
+++ b/test/lisp/progmodes/ruby-mode-tests.el
@@ -537,9 +537,12 @@ VALUES-PLIST is a list with alternating index and value elements."
| def foo
| end
| _
+ | def bar
+ | end
| end
|end")
(search-backward "_")
+ (delete-char 1)
(should (string= (ruby-add-log-current-method)"M::C"))))
(ert-deftest ruby-add-log-current-method-in-singleton-class ()
diff --git a/test/lisp/progmodes/ruby-ts-mode-tests.el b/test/lisp/progmodes/ruby-ts-mode-tests.el
index aa1ab1e2605..18e3e60a04a 100644
--- a/test/lisp/progmodes/ruby-ts-mode-tests.el
+++ b/test/lisp/progmodes/ruby-ts-mode-tests.el
@@ -110,6 +110,18 @@ The whitespace before and including \"|\" on each line is removed."
| 42
| end")))
+
+(ert-deftest ruby-ts-indent-call-no-args ()
+ (skip-unless (treesit-ready-p 'ruby t))
+ (ruby-ts-with-temp-buffer
+ "variable = foo(
+
+)"
+ (goto-char (point-min))
+ (forward-line 1)
+ (funcall indent-line-function)
+ (should (= (current-indentation) ruby-indent-level))))
+
(ert-deftest ruby-ts-add-log-current-method-examples ()
(skip-unless (treesit-ready-p 'ruby t))
(let ((pairs '(("foo" . "#foo")
@@ -141,9 +153,12 @@ The whitespace before and including \"|\" on each line is removed."
| def foo
| end
| _
+ | def bar
+ | end
| end
|end")
(search-backward "_")
+ (delete-char 1)
(should (string= (ruby-ts-add-log-current-function) "M::C"))))
(ert-deftest ruby-ts-add-log-current-method-in-singleton-class ()
@@ -247,7 +262,12 @@ The whitespace before and including \"|\" on each line is removed."
(should (equal (buffer-string) orig))))
(kill-buffer buf)))))
+(ruby-ts-deftest-indent "ruby-ts.rb")
+(ruby-ts-deftest-indent "ruby-after-operator-indent.rb")
+(ruby-ts-deftest-indent "ruby-block-indent.rb")
+(ruby-ts-deftest-indent "ruby-method-call-indent.rb")
(ruby-ts-deftest-indent "ruby-method-params-indent.rb")
+(ruby-ts-deftest-indent "ruby-parenless-call-arguments-indent.rb")
(provide 'ruby-ts-mode-tests)
diff --git a/test/lisp/wid-edit-tests.el b/test/lisp/wid-edit-tests.el
index 3f5fcea0c33..b379c7c91a8 100644
--- a/test/lisp/wid-edit-tests.el
+++ b/test/lisp/wid-edit-tests.el
@@ -267,6 +267,22 @@ return nil, even with a non-nil bubblep argument."
(should child)
(should (equal (widget-value widget) '(1 "One"))))))
+;; Bug#60501
+(ert-deftest widget-test-handle-spurious-inline ()
+ "Test the we can create a menu widget with an unnecessary :inline"
+ (with-temp-buffer
+ (widget-insert "Testing.\n\n")
+ (let* ((widget (widget-create 'menu-choice
+ :inline t
+ :value "*scratch*"
+ '(choice-item "*scratch*")))
+ (child (car (widget-get widget :children))))
+ (widget-insert "\n")
+ (use-local-map widget-keymap)
+ (widget-setup)
+ (should child)
+ (should (string-equal (widget-value widget) "*scratch*")))))
+
(ert-deftest widget-test-option-can-handle-choice ()
"Test that we can create a option widget with a choice correctly."
(with-temp-buffer
diff --git a/test/manual/indent/octave.m b/test/manual/indent/octave.m
index 76cad09ad1e..08b7fa58d59 100644
--- a/test/manual/indent/octave.m
+++ b/test/manual/indent/octave.m
@@ -1517,7 +1517,7 @@ function copy_files (desc, packdir, global_install)
if (exist (fullfile (desc.dir, getarch ()), "dir") &&
! strcmp (fullfile (desc.dir, getarch ()), octfiledir))
if (! exist (octfiledir, "dir"))
- ## Can be required to create upto three levels of dirs.
+ ## Can be required to create up to three levels of dirs.
octm1 = fileparts (octfiledir);
if (! exist (octm1, "dir"))
octm2 = fileparts (octm1);
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. "))
(remove-hook 'buffer-list-update-hook bluh))))
(ert-deftest buffer-tests-inhibit-buffer-hooks-indirect ()
- "Indirect buffers do not call `get-buffer-create'."
- (dolist (inhibit '(nil t))
- (let ((base (get-buffer-create "foo" inhibit)))
+ "Test `make-indirect-buffer' argument INHIBIT-BUFFER-HOOKS."
+ (let* ( base run-bluh run-kbh run-kbqf
+ (bluh (lambda () (setq run-bluh t)))
+ (kbh (lambda () (setq run-kbh t)))
+ (kbqf (lambda () (setq run-kbqf t))))
+ (dolist (inhibit-base '(nil t))
(unwind-protect
- (dotimes (_i 11)
- (let* (flag*
- (flag (lambda () (prog1 t (setq flag* t))))
- (indirect (make-indirect-buffer base "foo[indirect]" nil
- inhibit)))
- (unwind-protect
- (progn
- (with-current-buffer indirect
- (add-hook 'kill-buffer-query-functions flag nil t))
- (kill-buffer indirect)
- (if inhibit
- (should-not flag*)
- (should flag*)))
- (let (kill-buffer-query-functions)
+ (let (indirect)
+ (setq base (generate-new-buffer " base" inhibit-base))
+ (dolist (inhibit-indirect '(nil t))
+ (dotimes (_ 11)
+ (unwind-protect
+ (let ((name (generate-new-buffer-name " indirect")))
+ (setq run-bluh nil run-kbh nil run-kbqf nil)
+ (add-hook 'buffer-list-update-hook bluh)
+ (with-current-buffer
+ (setq indirect (make-indirect-buffer
+ base name nil inhibit-indirect))
+ (add-hook 'kill-buffer-hook kbh nil t)
+ (add-hook 'kill-buffer-query-functions kbqf nil t)
+ (kill-buffer))
+ (should (xor inhibit-indirect run-bluh))
+ (should (xor inhibit-indirect run-kbh))
+ (should (xor inhibit-indirect run-kbqf)))
+ (remove-hook 'buffer-list-update-hook bluh)
(when (buffer-live-p indirect)
(kill-buffer indirect))))))
- (let (kill-buffer-query-functions)
- (when (buffer-live-p base)
- (kill-buffer base)))))))
+ (when (buffer-live-p base)
+ (kill-buffer base))))))
(ert-deftest zero-length-overlays-and-not ()
(with-temp-buffer
diff --git a/test/src/coding-tests.el b/test/src/coding-tests.el
index 6bd8d1ae6c4..b27907027ba 100644
--- a/test/src/coding-tests.el
+++ b/test/src/coding-tests.el
@@ -148,21 +148,21 @@
(defun coding-tests (content-type write-coding read-coding detected-coding
&optional translator)
- (prefer-coding-system 'utf-8-auto)
- (let ((filename (coding-tests-filename content-type write-coding)))
- (with-temp-buffer
- (let ((coding-system-for-read read-coding)
- (contents (coding-tests-file-contents content-type))
- (disable-ascii-optimization nil))
- (if translator
- (setq contents (funcall translator contents)))
- (insert-file-contents filename)
- (if (and (coding-system-equal buffer-file-coding-system detected-coding)
- (string= (buffer-string) contents))
- nil
- (list buffer-file-coding-system
- (string-to-list (buffer-string))
- (string-to-list contents)))))))
+ (with-coding-priority '(utf-8-auto)
+ (let ((filename (coding-tests-filename content-type write-coding)))
+ (with-temp-buffer
+ (let ((coding-system-for-read read-coding)
+ (contents (coding-tests-file-contents content-type))
+ (disable-ascii-optimization nil))
+ (if translator
+ (setq contents (funcall translator contents)))
+ (insert-file-contents filename)
+ (if (and (coding-system-equal buffer-file-coding-system detected-coding)
+ (string= (buffer-string) contents))
+ nil
+ (list buffer-file-coding-system
+ (string-to-list (buffer-string))
+ (string-to-list contents))))))))
(ert-deftest ert-test-coding-ascii ()
(unwind-protect
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
index b7715a280a6..aa710519825 100644
--- a/test/src/keymap-tests.el
+++ b/test/src/keymap-tests.el
@@ -226,6 +226,7 @@ commit 86c19714b097aa477d339ed99ffb5136c755a046."
(defun keymap-tests--command-1 () (interactive) nil)
(defun keymap-tests--command-2 () (interactive) nil)
+(defun keymap-tests--command-3 () (interactive) nil)
(put 'keymap-tests--command-1 :advertised-binding [?y])
(ert-deftest keymap-where-is-internal ()
@@ -430,6 +431,38 @@ g .. h foo
(make-non-key-event 'keymap-tests-event)
(should (equal (where-is-internal 'keymap-tests-command) '([3 103]))))
+(ert-deftest keymap-set-consistency ()
+ (let ((k (make-sparse-keymap)))
+ ;; `keymap-set' returns the binding, `keymap-set-after' doesn't,
+ ;; so we need to check for nil. <sigh>
+ (should (keymap-set k "a" "a"))
+ (should (equal (keymap-lookup k "a") (key-parse "a")))
+ (should-not (keymap-set-after k "b" "b"))
+ (should (equal (keymap-lookup k "b") (key-parse "b")))
+ (should-not (keymap-set-after k "d" "d" t))
+ (should (equal (keymap-lookup k "d") (key-parse "d")))
+ (should-not (keymap-set-after k "e" "e" nil))
+ (should (equal (keymap-lookup k "e") (key-parse "e")))
+ ;; This doesn't fail, but it does not add the 'f' binding after 'a'
+ (should-not (keymap-set-after k "f" "f" "a"))
+ (should (equal (keymap-lookup k "f") (key-parse "f")))))
+
+(ert-deftest keymap-set-after-menus ()
+ (let ((map (make-sparse-keymap)))
+ (keymap-set map "<cmd1>"
+ '(menu-item "Run Command 1" keymap-tests--command-1
+ :help "Command 1 Help"))
+ (keymap-set-after map "<cmd2>"
+ '(menu-item "Run Command 2" keymap-tests--command-2
+ :help "Command 2 Help"))
+ (keymap-set-after map "<cmd3>"
+ '(menu-item "Run Command 3" keymap-tests--command-3
+ :help "Command 3 Help")
+ 'cmd1)
+ (should (equal (caadr map) 'cmd1))
+ (should (equal (caaddr map) 'cmd3))
+ (should (equal (caar (last map)) 'cmd2))))
+
(ert-deftest keymap-test-duplicate-definitions ()
"Check that defvar-keymap rejects duplicate key definitions."
(should-error