Yuan Fu [Mon, 27 Feb 2023 08:14:32 +0000 (00:14 -0800)]
Adjust tree-sitter defun navigation (bug#61617)
Before this change, when you use a tree-sitter navigation function to
move to the next beginning of a thing, it jumps over the immediate
next thing and lands you at the beginning of the next-next thing.
Eg, when point is at the "|", and we evaluate
(treesit--navigate-thing pos 1 'beg), we go from
| (thing) (thing)
to
(thing) |(thing)
But some might expect point to go to
|(thing) (thing)
instead, which makes sense. Also, that's how Emacs expect defun
navigation functions to work. The discrepancy in expectation causes
bug#61617.
In this change I made tree-sitter navigation functions to work as what
Emacs expects. And what I described for moving to the next beginning
of thing is similarly applicable to moving to the end of previous end
of thing.
* lisp/treesit.el (treesit-beginning-of-defun)
(treesit-end-of-defun): Handle the case where defun-skipper moves
point back to where we started, by adding a retry.
(treesit--navigate-thing): Add a single condition checking for
progress to the condition form responsible for checking whether to
skip the next defun. Namely (eq pos (funcall advance next)))).
* test/src/treesit-tests.el:
(treesit--ert-defun-navigation-nested-master)
(treesit--ert-defun-navigation-top-level-master): Change tests to
reflect the new expectation.
Yuan Fu [Mon, 27 Feb 2023 02:05:13 +0000 (18:05 -0800)]
New tree-sitter indent anchor standalone-parent used by c-ts-mode
When writing c-ts-mode Theo used parent-bol which works well except
one case:
1 for (int i=0;
2 i < 5;
3 i++) {
4 func(i);
5 }
In this case, when indenting "func(i)", parent-bol returns the start
of "i++" on line 3, instead of the "correct" anchor, the start of
"for" on line 1. parent-bol would have worked if the "for (...) {"
part is in one line.
To support this case I tried numerous things and added a bunch of
stuff, culminating in c-ts-common-statement-offset. It's complicated,
requires extra setup, and slow.
Not anymore! I think the new anchor standalone-parent really captures
the logic behind how people expect indentation to work. It's simple
and fast, and requires no setup.
Eli Zaretskii [Sun, 26 Feb 2023 17:51:59 +0000 (19:51 +0200)]
; Improve documentation of loading *.eln files
* doc/lispref/loading.texi (How Programs Do Loading):
* doc/emacs/building.texi (Lisp Libraries): Some additional
details about what happens with natively-compiled files.
Augusto Stoffel [Sun, 26 Feb 2023 11:47:32 +0000 (11:47 +0000)]
Eglot: support positionEncoding LSP capability (bug#61726)
* lisp/progmodes/eglot.el(eglot-client-capabilities): Announce the
new capability.
(eglot-bytewise-column, eglot-move-to-bytewise-column): New functions.
(eglot--managed-mode): Set 'eglot-current-column-function' and
'eglot-move-to-bytewise-column' appropriately.
Eli Zaretskii [Sat, 25 Feb 2023 15:19:15 +0000 (17:19 +0200)]
Fix infloop in bidi.c
* src/bidi.c (bidi_set_paragraph_end): Reset the isolate_level to
zero. Whenever stack_idx is reset to zero, the isolate_level must
also be reset, since there cannot be any isolate status outside of
embeddings. Failure to reset isolate_level will cause us infloop
when we see a PDI. Reported by Matt Beshara <m@mfa.pw>.
Yuan Fu [Sat, 25 Feb 2023 02:40:52 +0000 (18:40 -0800)]
Align to prev sibling for c-ts-mode indentation
As requested by a discussion on emacs-devel.
* lisp/progmodes/c-ts-mode.el:
(c-ts-mode--anchor-prev-sibling): New function.
(c-ts-mode--indent-styles): Indent first child as before, indent the
rest to their previous sibling. Remove bracketless statement rules
that I forgot to remove previously.
Yuan Fu [Sat, 25 Feb 2023 03:31:34 +0000 (19:31 -0800)]
Fix c-ts-common-statement-offset and c-ts-common--node-is
* lisp/progmodes/c-ts-common.el:
(c-ts-common--node-is): Guard against case where the node has no field
name.
(c-ts-common-statement-offset): Do indent a level if the "if" in the
"else if" is on an independent line.
* lisp/font-lock.el (font-lock-function-call-face)
(font-lock-variable-ref-face, font-lock-property-ref-face):
New faces.
(font-lock-property-name-face):
Rename from 'font-lock-property-face'.
* lisp/progmodes/c-ts-mode.el (c-ts-mode--font-lock-settings):
Use new faces. More 'enumerator' query to 'definition' feature.
(c-ts-mode--fontify-declarator, c-ts-mode--fontify-variable):
Use new faces.
* lisp/progmodes/cmake-ts-mode.el
(cmake-ts-mode--font-lock-settings): Use new faces.
* lisp/progmodes/csharp-mode.el
(csharp-ts-mode--font-lock-settings): Use new faces.
* lisp/progmodes/go-ts-mode.el (go-ts-mode--font-lock-settings):
Use new faces.
* lisp/progmodes/java-ts-mode.el
(java-ts-mode--font-lock-settings): Use new faces.
* lisp/progmodes/js.el (js--treesit-fontify-assignment-lhs)
(js--treesit-font-lock-settings): Use new faces. Highlight
variable definitions inside array and object destructuring
patterns.
* lisp/progmodes/python.el (python--treesit-variable-p):
Exclude identifiers in parameters.
(python--treesit-settings): Use new faces. Highlight function
parameters. Move 'keyword' up to still highlight 'self' as
keyword.
* lisp/progmodes/ruby-ts-mode.el (ruby-ts--font-lock-settings):
Use new faces.
* lisp/progmodes/rust-ts-mode.el
(rust-ts-mode--font-lock-settings): Use new faces.
* lisp/progmodes/typescript-ts-mode.el
(typescript-ts-mode--font-lock-settings): Use new faces.
* lisp/textmodes/css-mode.el (css--treesit-settings):
Use font-lock-property-ref-face.
* lisp/textmodes/toml-ts-mode.el
(toml-ts-mode--font-lock-settings):
Use font-lock-property-ref-face.
João Távora [Fri, 24 Feb 2023 14:48:01 +0000 (14:48 +0000)]
Eglot: fix jit-lock inlay hint bugs
One of the bugs was straightforward. The timer function of
eglot--update-hints must set the correct buffer.
The other is much more odd. When using Eglot on Emacs's own
src/coding.c, the jit-lock code starts calling its jit-functions over
and over again with the same sequence of arguments, like so:
This continues forever at a very fast rate and saturates the LSP
channel.
At first I thought that it was because eglot--update-hints-1 is
actually causing the buffer to be modified with overlays sometime in
the future, but it is not so! It seems that merely calling
Robert Pluim [Fri, 24 Feb 2023 10:12:24 +0000 (11:12 +0100)]
Fix insertion of keyboard macro containing named keys
* lisp/kmacro.el: Autoload `macro--string-to-vector'.
(kmacro-ring-head): Convert `last-kbd-macro' to a vector if it's a
string, since `kmacro' uses `key-parse' on it.
(kmacro-lambda-form): Remove require for 'macros
* test/lisp/kmacro-tests.el
(kmacro-tests-name-last-macro-key-parse-syntax):
Test that insertion of macros that contain strings that look
like named keys works correctly.
João Távora [Thu, 23 Feb 2023 23:51:09 +0000 (23:51 +0000)]
Eglot: simplify inlay hints implementation with jit-lock
This implementation is much simpler than the one based on
windows-scroll-functions. It's also supposedly safer, as long as
jit-lock guarantees refontification of affected regions.
It's not _trivially_ simple though, as simply adding
'eglot--update-hints-1' to jit-lock-functions, while possible, is
going to request inlay hints from the LSP server for many small
regions of the buffer, depending on what jit-lock thinks is best. So
we keep coalescing these into a larger region until the time is
suitable for a more bandwidth-efficient request.
To do this, we use a jit-lock implementation detail,
jit-lock-context-unfontify-pos, which is a proxy for knowing that the
jit-lock-context-timer has run. Not sure how brittle it is, but it
seems to work reasonably.
We also get rid of the previous "get hints for entire buffer"
implementation.
* doc/misc/eglot.texi (Eglot Variables): Remove mention
to deleted eglot-lazy-inlay-hints.
Eli Zaretskii [Thu, 23 Feb 2023 15:45:52 +0000 (17:45 +0200)]
; Clarify documentation of 'file-modes-number-to-symbolic'
* doc/lispref/files.texi (Changing Files):
* lisp/files.el (file-modes-number-to-symbolic): Clarify the
confusion with "symbolic" forms of file modes. (Bug#61709)
João Távora [Thu, 23 Feb 2023 13:58:38 +0000 (13:58 +0000)]
Eglot: display completion label when safe
Originally reported in
https://github.com/joaotavora/eglot/discussions/1141 by "Mintsoup".
Eglot doesn't always show the LSP :label property of a CompletionItem
in the completion candidates. That is because label is sometimes not
what should be inserted in the buffer in the end, the :insertText
property supercedes it.
But the label is usually more suitable for display nevertheless and if
the LSP CompletionItem contains either a snippet or a textEdit, it's
safe to display the label, since :exit-function will guarantee that a
suitable buffer insertion is performed.
This change reflects that awareness that when a textEdit is available,
it's acceptable to show the label.
Inlay hints are small text annotations to specific parts of the whole
buffer, not unlike diagnostics, but designed to help readability
instead of indicating problems. For example, a C++ LSP server can
serve hints about positional parameter names in function calls and a
variable's automatically deduced type. Emacs can display these hints
in many little 0-length overlays with an 'before-string property, thus
helping the user remember those types and parameter names.
Since inlay hints are potentially a large amount of data to request
from the LSP server, the implementation strives to be as parsimonious
as possible with these requests.
So, by default, inlay hints are only requested for the visible
portions of the buffer across windows showing this buffer. This is
done by leveraging the 'window-scroll-functions' variable, making for
a reasonably complex implementation involving per-window timers. When
scrolling a window, it may take a short amount of time for inlay hints
to "pop in". The new user variable 'eglot-lazy-inlay-hints' can be
used to exert some control over this.
Specifically, if the variable's value is set to 'nil', then inlay
hints are greedily fetched for the whole buffer every time a change
occurs. This is a much simpler mode of operation which may avoid
problems, but is also likely much slower in large buffers.
Also, because the inlay feature is probably visually suprising to
some, it is turned OFF by default, which is not the usual practice of
Eglot (at least not when the necessary infrastructure is present).
This decision may be changed soon. Here's a good one-liner for
enabling it by default in every Eglot-managed buffer:
I haven't tested inlay hints extensively across many LSP servers, so I
would appreciate any testing, both for functional edge cases and
regarding performance. There are possibly more optimization
oportunities in the "lazy" mode of operation, like more aggressively
deleting buffer overlays that are not in visible parts of the buffer.
Though I ended up writing this one from scratch, I want to thank
Dimitry Bolopopsky <dimitri@belopopsky.com> and Chinmay Dala
<dalal.chinmay.0101@gmail.com> for suggestions and early patches.
* lisp/progmodes/eglot.el (eglot--lsp-interface-alist): Define
InlayHint.
(eglot-client-capabilities): Announce 'inlayHint' capability.
(eglot-ignored-server-capabilities): Add :inlayHintProvider.
(eglot--document-changed-hook): New helper hook.
(eglot--after-change): Use it.
(eglot-inlay-hint-face, eglot-type-hint-face)
(eglot-parameter-hint-face): New faces.
(eglot--update-hints-1, eglot--inlay-hints-after-scroll)
(eglot--inlay-hints-fully, eglot--inlay-hints-lazily): New helpers.
(eglot-lazy-inlay-hints): New user variable.
(eglot-inlay-hints-mode): New minor mode.
(eglot--maybe-activate-editing-mode): Try to activate
eglot-inlay-hints-mode.
(eglot--before-change): Remove overlays immediately in the
area being changed.
(eglot--managed-mode-off): Remove overlays.
João Távora [Wed, 22 Feb 2023 18:44:39 +0000 (18:44 +0000)]
Eglot: run eglot-managed-mode-hook after LSP didOpen
This allows using the hook for interacting with the LSP server using
the current buffer as the subject of that interaction ("document" in
LSP parlance).
* lisp/progmodes/eglot.el (eglot--maybe-activate-editing-mode):
Run eglot-managed-mode-hook here.
(eglot--managed-mode): Not here.
Eglot: respect user's Eldoc configuration by default
In that commit, I did what many longstanding issues and users were
suggesting and removed Eglot's override of two Eldoc user
configuration varibles.
I verified that Eglot's behaviour would stay mostly unaltered but my
tests were very incomplete. In short there is no way that Eglot can
work acceptably with the default setting of
'eldoc-documentation-strategy', which is
'eldoc-documentation-default'. So it must be changed, either globally
or locally in Eglot's minor mode.
This is true for any situation where both synchronous and asynchronous
documentation sources are present. In Eglot's case there are two
asynchronous sources which have more importance than the synchronous
source. So any other strategy except the
'eldoc-documentation-default' makes sense.
* lisp/progmodes/eglot.el (eglot--managed-mode): Set
eldoc-documentation-strategy to eldoc-documentation-compose.
F. Jason Park [Wed, 22 Feb 2023 14:24:17 +0000 (06:24 -0800)]
Yield to erc-move-to-prompt before unhiding prompt
* lisp/erc/erc-backend.el (erc--hide-prompt): Change hook depth from 0
to 91 to allow the `move-to-prompt' module to do its thing. This
feature was added by bug#54826 and first appeared in Emacs 29.
* lisp/erc/erc-common.el (erc-server-user): Remove erroneous comment.
The `buffers' field is a list of buffers.
* test/lisp/erc/erc-tests.el (erc-hide-prompt): Use `erc--target'
instead of `erc-default-recipients' because this is new code.
Eli Zaretskii [Wed, 22 Feb 2023 13:16:25 +0000 (15:16 +0200)]
Explain effect of variable-pitch fonts on fill-column
* doc/emacs/text.texi (Fill Commands):
* doc/emacs/display.texi (Displaying Boundaries):
* lisp/display-fill-column-indicator.el
(display-fill-column-indicator-mode): Document caveats of using
variable-pitch fonts with 'fill-column' and its indicator.
(Bug#61677)
Robert Pluim [Tue, 21 Feb 2023 14:20:56 +0000 (15:20 +0100)]
Make 'emacs-news-cycle-tag' work at all levels
* lisp/textmodes/emacs-news-mode.el (emacs-news-cycle-tag): Search for
a heading starting with 2 or more '*' rather than exactly 3.
* test/lisp/textmodes/emacs-news-mode-resources/cycle-tag.erts
(Point-Char): Add tests for 2 and 4 '*' levels.
In one form or another, the reports point out that the multiple pieces
of information about the "thing at point" made available by the LSP
server are not all being considered by the ElDoc system.
The reason for this is Eglot setting/trampling the variables
'eldoc-documentation-strategy' and 'eldoc-documentation-functions' in
its minor more entry function.
The reason it did that is historical and is partially described in the
issues above. But, evidently, it never made much sense, because so
many people want to override it, which requires setting
'eldoc-documentation-strategy' to the non-default value
'eldoc-documentation-compose'.
The problem was made worse by the fact that setting it as usual in
either the Customize menu or their init file didn't work, requiring a
fairly complex Elisp snippet. That is now solved as of this commit.
If the user does not do any setting, then Eglot works basically the
same as before (i.e. shows only one piece of information).
It is arguable that the default value for
'eldoc-documentation-strategy' should change globally to
'eldoc-documentation-compose', but that has other subtle implications
and is not part of this commit.
* lisp/progmodes/eglot.el (eglot--managed-mode): Don't set Eldoc
variables greedily.
Daniel Martín [Sun, 19 Feb 2023 21:57:54 +0000 (22:57 +0100)]
Add declaration_list to c-ts-common-indent-type-regexp-alist
* lisp/progmodes/c-ts-mode.el (c-ts-base-mode): Consider a
"declaration_list" a block. (Bug#61635)
* test/lisp/progmodes/c-ts-mode-resources/indent.erts (Code): Add a
test case.
Now prev-adaptive-prefix looks at the current line and checks if it
begins with a prefix itself. If it does, prev-adaptive-prefix tries
to place the anchor before the prefix on the previous line, rather
than after it.
- prev line
- this line -> This line starts with a "-", i.e., begins with a
prefix, so we place the anchor at the beginning of the
"-" of the previous line, rather than after it
- prev line
this line -> This line doesn't start with a prefix, so the anchor
is placed after the previous line's "-".
* doc/lispref/modes.texi (Parser-based Indentation): Update manual.
* lisp/treesit.el:
(treesit-simple-indent-presets): Add local variable
this-line-has-prefix, base what anchor to return on the value of
this-line-has-prefix and whether the prev line has a prefix.
We can use the fact that 'treesit-indent-1' uses 'treesit-node-on'
when on a whitespace to set the actual current node as parent. Now we
can correctly indent the 'jsx_text' nodes. We also add some more
electric-indent-chars so that auto-indenting of jsx behaves a little
more fluently.
* lisp/progmodes/js.el (js--treesit-indent-rules): Add new rules.
(js-ts-mode): Add more indent-chars.
* lisp/progmodes/typescript-ts-mode.el
(typescript-ts-mode--indent-rules): Add new rules.
* lisp/progmodes/typescript-ts-mode.el
(typescript-ts-base-mode): Add more indent-chars and layout rules.
* lisp/progmodes/c-ts-mode.el (c-ts-mode--indent-styles): Make sure we
indent to great-grand-parent if inside an #ifdef...#endif block. If
grand-parent is root node, then don't indent one step.
(c-ts-mode--preproc-offset): New helper anchor function to calculate
indent offset.
Add comment style toggle for c-ts-mode (bug#61550)
* lisp/progmodes/c-ts-mode.el (c-ts-mode-toggle-comment-style): New
command.
(c-ts-base-mode-map): Add binding.
(c-ts-mode-set-modeline): New function.
(c-ts-mode): Set modeline.
(c++-ts-mode): Set modeline.
Dmitry Gutov [Sun, 19 Feb 2023 17:18:19 +0000 (19:18 +0200)]
rust-ts-mode--font-lock-settings: Avoid the explicit 'default' face
* lisp/progmodes/rust-ts-mode.el (rust-ts-mode--fontify-scope)
(rust-ts-mode--fontify-tail): New functions.
(rust-ts-mode--font-lock-settings): Use them instead of a lot of
more complex queries (bug#61302). Thus avoid having to create
block fontification by other features using the 'default' face.
Replace the catch-all query for 'variable' with an enumeration of
possible parent nodes.
Eglot: improve treatment of completion items without :sortText (bug#61532)
Previously, defaulting to the empty string put candidates without
:sortText to the top of the list. since string-lessp is safe with nil
arguments, this makes them sort to the end instead.