1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-21 06:55:39 +00:00

Merge from origin/emacs-30

9b299dd79c Revert a recent change that caused redisplay slowdown
4eaab54896 ; * doc/lispref/display.texi (Low-Level Font): Fix wordin...
0a50019308 Indent ERT failure explanations rigidly
713069dd7a [Eglot] Stricter "expand common" behavior
096730510c eglot-tests.el: New tests for existing completion behavior
969498c25d Remove dangerous HTML edit from admin.el

# Conflicts:
#	etc/EGLOT-NEWS
This commit is contained in:
Eli Zaretskii 2024-08-25 14:54:03 -04:00
commit d4bd5a3cba
8 changed files with 220 additions and 25 deletions

View File

@ -613,9 +613,7 @@ style=\"text-align:left\">")
;; item is not there anymore. So for HTML manuals produced by ;; item is not there anymore. So for HTML manuals produced by
;; those newer versions of Texinfo we punt and leave the menu in ;; those newer versions of Texinfo we punt and leave the menu in
;; its original form. ;; its original form.
(when (or (search-forward "<ul class=\"menu\">" nil t) (when (or (search-forward "<ul class=\"menu\">" nil t))
;; FIXME? The following search seems dangerously lax.
(search-forward "<ul>" nil t))
;; Convert the list that Makeinfo made into a table. ;; Convert the list that Makeinfo made into a table.
(replace-match "<table style=\"float:left\" width=\"100%\">") (replace-match "<table style=\"float:left\" width=\"100%\">")
(forward-line 1) (forward-line 1)

View File

@ -4374,9 +4374,10 @@ should be equal to the value of @var{height} above.
The width, in pixels, of the font's space character. The width, in pixels, of the font's space character.
@item average-width @item average-width
The average width of the font characters. If this is zero, Emacs uses The average width of the font characters. Emacs uses this for
the value of @var{space-width} instead, when it calculates text layout calculating text layout on display; if the value of @var{average-width}
on display. is zero, Emacs uses the value of @var{space-width} instead for those
purposes.
@item filename @item filename
The file name of the font as a string. This can be @code{nil} if the The file name of the font as a string. This can be @code{nil} if the

View File

@ -26,6 +26,36 @@ Eglot will now try to not register $/progress messages from the server
when the defcustom is set to nil. This requires a restart of the server when the defcustom is set to nil. This requires a restart of the server
for the change to take effect. for the change to take effect.
** LSP MarkedString interface is now supported (bug#71353)
Some servers still use this deprecated interface for communicating
documentation snippets.
** Fixes to completion logic (bug#68699, github#1339, github#1349)
These affect mostly the "vanilla" frontend to completions (invoked with
C-M-i).
** More strict completion expansion (bug#72705).
It ensures that "expand common" commands (such as C-M-i or TAB in
third-party frontends) don't result in fewer completions than before
they are called.
** Experimental support for Eglot-only subprojects (github#1337)
Useful for complex projects with subprojects needing different language
servers. See associated github issue
https://github.com/joaotavora/eglot/discussions/1337 for examples.
** New servers have been added to 'eglot-server-programs'.
- blueprint (bug#70015)
- BasedPyright (bug#69925)
- move-analyzer (bug#69796)
- millet
- nushell (bug#68823)
* Changes in Eglot 1.17 (25/1/2024) * Changes in Eglot 1.17 (25/1/2024)

View File

@ -1317,13 +1317,12 @@ empty string."
"Pretty-print OBJECT, indenting it to the current column of point. "Pretty-print OBJECT, indenting it to the current column of point.
Ensures a final newline is inserted." Ensures a final newline is inserted."
(let ((begin (point)) (let ((begin (point))
(cols (current-column))
(pp-escape-newlines t) (pp-escape-newlines t)
(print-escape-control-characters t)) (print-escape-control-characters t))
(pp object (current-buffer)) (pp object (current-buffer))
(unless (bolp) (insert "\n")) (unless (bolp) (insert "\n"))
(save-excursion (indent-rigidly begin (point) cols)))
(goto-char begin)
(indent-sexp))))
(defun ert--insert-infos (result) (defun ert--insert-infos (result)
"Insert `ert-info' infos from RESULT into current buffer. "Insert `ert-info' infos from RESULT into current buffer.

View File

@ -3142,8 +3142,18 @@ for which LSP on-type-formatting should be requested."
(defun eglot--dumb-tryc (pat table pred point) (defun eglot--dumb-tryc (pat table pred point)
(let ((probe (funcall table pat pred nil))) (let ((probe (funcall table pat pred nil)))
(cond ((eq probe t) t) (cond ((eq probe t) t)
(probe (cons probe (length probe))) (probe
(t (cons pat point))))) (if (and (not (equal probe pat))
(cl-every
(lambda (s) (string-prefix-p probe s completion-ignore-case))
(funcall table pat pred t)))
(cons probe (length probe))
(cons pat point)))
(t
;; Match ignoring suffix: if there are any completions for
;; the current prefix at least, keep the current input.
(and (funcall table (substring pat 0 point) pred t)
(cons pat point))))))
(add-to-list 'completion-category-defaults '(eglot-capf (styles eglot--dumb-flex))) (add-to-list 'completion-category-defaults '(eglot-capf (styles eglot--dumb-flex)))
(add-to-list 'completion-styles-alist '(eglot--dumb-flex eglot--dumb-tryc eglot--dumb-allc)) (add-to-list 'completion-styles-alist '(eglot--dumb-flex eglot--dumb-tryc eglot--dumb-allc))

View File

@ -736,11 +736,6 @@ recompute_basic_faces (struct frame *f)
clear_face_cache (false); clear_face_cache (false);
if (!realize_basic_faces (f)) if (!realize_basic_faces (f))
emacs_abort (); emacs_abort ();
/* Force complete face recalculation next time we use the display
code, because realize_basic_faces could free the fontset used
by non-ASCII faces corresponding to ASCII faces of the basic
faces, and attempt to use that fontset might segfault. */
f->face_change = true;
} }
} }

View File

@ -876,6 +876,60 @@ This macro is used to test if macroexpansion in `should' works."
(should (eq (ert--get-explainer 'string-equal) 'ert--explain-string-equal)) (should (eq (ert--get-explainer 'string-equal) 'ert--explain-string-equal))
(should (eq (ert--get-explainer 'string=) 'ert--explain-string-equal))) (should (eq (ert--get-explainer 'string=) 'ert--explain-string-equal)))
(ert-deftest ert--pp-with-indentation-and-newline ()
:tags '(:causes-redisplay)
(let ((failing-test (make-ert-test
:name 'failing-test
:body (lambda ()
(should (equal '((:one "1" :three "3" :two "2"))
'((:one "1")))))))
(want-body "\
Selector: <failing-test>
Passed: 0
Failed: 1 (1 unexpected)
Skipped: 0
Total: 1/1
Started at: @@TIMESTAMP@@
Finished.
Finished at: @@TIMESTAMP@@
F
F failing-test
(ert-test-failed
((should (equal '((:one \"1\" :three \"3\" :two \"2\")) '((:one \"1\"))))
:form (equal ((:one \"1\" :three \"3\" :two \"2\")) ((:one \"1\"))) :value
nil :explanation
(list-elt 0
(proper-lists-of-different-length 6 2
(:one \"1\" :three \"3\"
:two \"2\")
(:one \"1\")
first-mismatch-at 2))))
\n\n")
(want-msg "Ran 1 tests, 0 results were as expected, 1 unexpected")
(buffer-name (generate-new-buffer-name " *ert-test-run-tests*")))
(cl-letf* ((ert-debug-on-error nil)
(ert--output-buffer-name buffer-name)
(messages nil)
((symbol-function 'message)
(lambda (format-string &rest args)
(push (apply #'format format-string args) messages)))
((symbol-function 'ert--format-time-iso8601)
(lambda (_) "@@TIMESTAMP@@")))
(save-window-excursion
(unwind-protect
(let ((fill-column 70))
(ert-run-tests-interactively failing-test)
(should (equal (list want-msg) messages))
(should (equal (string-replace "\t" " "
(with-current-buffer buffer-name
(buffer-string)))
want-body)))
(when noninteractive
(kill-buffer buffer-name)))))))
(provide 'ert-tests) (provide 'ert-tests)
;;; ert-tests.el ends here ;;; ert-tests.el ends here

View File

@ -587,6 +587,18 @@ directory hierarchy."
(eglot--wait-for (s-notifs 20) (&key method &allow-other-keys) (eglot--wait-for (s-notifs 20) (&key method &allow-other-keys)
(string= method "textDocument/publishDiagnostics")))) (string= method "textDocument/publishDiagnostics"))))
(defun eglot--wait-for-rust-analyzer ()
(eglot--sniffing (:server-notifications s-notifs)
(should (eglot--tests-connect))
(eglot--wait-for (s-notifs 20) (&key method params &allow-other-keys)
(and
(string= method "$/progress")
"rustAnalyzer/Indexing"
(equal params
'(:token "rustAnalyzer/Indexing" :value
;; Could wait for :kind "end" instead, but it's 2 more seconds.
(:kind "begin" :title "Indexing" :cancellable :json-false :percentage 0)))))))
(ert-deftest eglot-test-basic-completions () (ert-deftest eglot-test-basic-completions ()
"Test basic autocompletion in a clangd LSP." "Test basic autocompletion in a clangd LSP."
(skip-unless (executable-find "clangd")) (skip-unless (executable-find "clangd"))
@ -600,6 +612,20 @@ directory hierarchy."
(message (buffer-string)) (message (buffer-string))
(should (looking-back "fprintf.?"))))) (should (looking-back "fprintf.?")))))
(ert-deftest eglot-test-common-prefix-completion ()
"Test completion appending the common prefix."
(skip-unless (executable-find "clangd"))
(eglot--with-fixture
`(("project" . (("coiso.c" .
,(concat "int foo_bar; int foo_bar_baz;"
"int main() {foo")))))
(with-current-buffer
(eglot--find-file-noselect "project/coiso.c")
(eglot--wait-for-clangd)
(goto-char (point-max))
(completion-at-point)
(should (looking-back "{foo_bar")))))
(ert-deftest eglot-test-non-unique-completions () (ert-deftest eglot-test-non-unique-completions ()
"Test completion resulting in 'Complete, but not unique'." "Test completion resulting in 'Complete, but not unique'."
(skip-unless (executable-find "clangd")) (skip-unless (executable-find "clangd"))
@ -619,19 +645,101 @@ directory hierarchy."
(forward-line -1) (forward-line -1)
(should (looking-at "Complete, but not unique"))))))) (should (looking-at "Complete, but not unique")))))))
(ert-deftest eglot-test-stop-completion-on-nonprefix ()
"Test completion also resulting in 'Complete, but not unique'."
(skip-unless (executable-find "clangd"))
(eglot--with-fixture
`(("project" . (("coiso.c" .
,(concat "int foot; int footer; int fo_obar;"
"int main() {foo")))))
(with-current-buffer
(eglot--find-file-noselect "project/coiso.c")
(eglot--wait-for-clangd)
(goto-char (point-max))
(completion-at-point)
(should (looking-back "foo")))))
(ert-deftest eglot-test-try-completion-nomatch ()
"Test completion table with non-matching input, returning nil."
(skip-unless (executable-find "clangd"))
(eglot--with-fixture
`(("project" . (("coiso.c" .
,(concat "int main() {abc")))))
(with-current-buffer
(eglot--find-file-noselect "project/coiso.c")
(eglot--wait-for-clangd)
(goto-char (point-max))
(should
(null
(completion-try-completion
"abc"
(nth 2 (eglot-completion-at-point)) nil 3))))))
(ert-deftest eglot-test-try-completion-inside-symbol ()
"Test completion table inside symbol, with only prefix matching."
(skip-unless (executable-find "clangd"))
(eglot--with-fixture
`(("project" . (("coiso.c" .
,(concat
"int foobar;"
"int main() {foo123")))))
(with-current-buffer
(eglot--find-file-noselect "project/coiso.c")
(eglot--wait-for-clangd)
(goto-char (- (point-max) 3))
(when (buffer-live-p "*Completions*")
(kill-buffer "*Completions*"))
(completion-at-point)
(should (looking-back "foo"))
(should (looking-at "123"))
(should (get-buffer "*Completions*"))
)))
(ert-deftest eglot-test-rust-completion-exit-function ()
"Ensure that the rust-analyzer exit function creates the expected contents."
(skip-unless (executable-find "rust-analyzer"))
(skip-unless (executable-find "cargo"))
(eglot--with-fixture
'(("cmpl-project" .
(("main.rs" .
"fn test() -> i32 { let v: usize = 1; v.count_on1234.1234567890;"))))
(with-current-buffer
(eglot--find-file-noselect "cmpl-project/main.rs")
(should (zerop (shell-command "cargo init")))
(eglot--tests-connect)
(goto-char (point-min))
(search-forward "v.count_on")
(let ((minibuffer-message-timeout 0)
;; Fail at (ding) if completion fails.
(executing-kbd-macro t))
(when (buffer-live-p "*Completions*")
(kill-buffer "*Completions*"))
;; The design is pretty brittle, we'll need to monitor the
;; language server for changes in behavior.
(eglot--wait-for-rust-analyzer)
(completion-at-point)
(should (looking-back "\\.count_on"))
(should (get-buffer "*Completions*"))
(minibuffer-next-completion 1)
(minibuffer-choose-completion t))
(should
(equal
"fn test() -> i32 { let v: usize = 1; v.count_ones().1234567890;"
(buffer-string))))))
(ert-deftest eglot-test-basic-xref () (ert-deftest eglot-test-basic-xref ()
"Test basic xref functionality in a clangd LSP." "Test basic xref functionality in a clangd LSP."
(skip-unless (executable-find "clangd")) (skip-unless (executable-find "clangd"))
(eglot--with-fixture (eglot--with-fixture
`(("project" . (("coiso.c" . `(("project" . (("coiso.c" .
,(concat "int foo=42; int fooey;" ,(concat "int foo=42; int fooey;"
"int main() {foo=82;}"))))) "int main() {foo=82;}")))))
(with-current-buffer (with-current-buffer
(eglot--find-file-noselect "project/coiso.c") (eglot--find-file-noselect "project/coiso.c")
(should (eglot--tests-connect)) (should (eglot--tests-connect))
(search-forward "{foo") (search-forward "{foo")
(call-interactively 'xref-find-definitions) (call-interactively 'xref-find-definitions)
(should (looking-at "foo=42"))))) (should (looking-at "foo=42")))))
(defvar eglot--test-c-buffer (defvar eglot--test-c-buffer
"\ "\