summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2023-04-10 01:17:26 -0400
committerEli Zaretskii <eliz@gnu.org>2023-04-10 01:17:26 -0400
commit671abd0cc406ec45898fdc2d27d09ce449023540 (patch)
tree0081d8d30f6216eb0eae8863b5ba361535d86829
parent4bc678ec9f4c05f7b26ea85b60e86ac0fc971afa (diff)
parentdb8f207e52fc969e0dcf30e197bcfaa4fa1d2b6e (diff)
downloademacs-671abd0cc406ec45898fdc2d27d09ce449023540.tar.gz
Merge branch 'emacs-29' of git.sv.gnu.org:/srv/git/emacs into emacs-29
Pull in latest changes.
-rw-r--r--doc/lispref/windows.texi2
-rw-r--r--lisp/progmodes/c-ts-mode.el17
-rw-r--r--lisp/progmodes/project.el5
-rw-r--r--test/lisp/progmodes/c-ts-mode-resources/indent.erts14
-rw-r--r--test/lisp/progmodes/eglot-tests.el197
5 files changed, 121 insertions, 114 deletions
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 01ac6fb901a..0196ed0e813 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -3216,7 +3216,7 @@ any window it creates as dedicated to its buffer (@pxref{Dedicated
Windows}). It does that by calling @code{set-window-dedicated-p} with
the chosen window as first argument and the entry's value as second.
Side windows are by default dedicated with the value @code{side}
-((@pxref{Side Window Options and Functions}).
+(@pxref{Side Window Options and Functions}).
@vindex preserve-size@r{, a buffer display action alist entry}
@item preserve-size
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 981c7766375..83e89c3a335 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -859,6 +859,18 @@ the semicolon. This function skips the semicolon."
(goto-char (match-end 0)))
(treesit-default-defun-skipper))
+(defun c-ts-base--before-indent (args)
+ (pcase-let ((`(,node ,parent ,bol) args))
+ (when (null node)
+ (let ((smallest-node (treesit-node-at (point))))
+ ;; "Virtual" closer curly added by the
+ ;; parser's error recovery.
+ (when (and (equal (treesit-node-type smallest-node) "}")
+ (equal (treesit-node-end smallest-node)
+ (treesit-node-start smallest-node)))
+ (setq parent (treesit-node-parent smallest-node)))))
+ (list node parent bol)))
+
(defun c-ts-mode-indent-defun ()
"Indent the current top-level declaration syntactically.
@@ -904,6 +916,11 @@ the semicolon. This function skips the semicolon."
;; function_definitions, so we need to find the top-level node.
(setq-local treesit-defun-prefer-top-level t)
+ ;; When the code is in incomplete state, try to make a better guess
+ ;; about which node to indent against.
+ (add-function :filter-args (local 'treesit-indent-function)
+ #'c-ts-base--before-indent)
+
;; Indent.
(when (eq c-ts-mode-indent-style 'linux)
(setq-local indent-tabs-mode t))
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 11228226592..a18b918db62 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1216,7 +1216,10 @@ To continue searching for the next match, use the
command \\[fileloop-continue]."
(interactive "sSearch (regexp): ")
(fileloop-initialize-search
- regexp (project-files (project-current t)) 'default)
+ regexp
+ ;; XXX: See the comment in project-query-replace-regexp.
+ (cl-delete-if-not #'file-regular-p (project-files (project-current t)))
+ 'default)
(fileloop-continue))
;;;###autoload
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent.erts b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
index 5cdefe2122c..221b3d809af 100644
--- a/test/lisp/progmodes/c-ts-mode-resources/indent.erts
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
@@ -464,3 +464,17 @@ main (void)
|
}
=-=-=
+
+Name: Empty Line (Block Start)
+
+=-=
+int
+main (void)
+{
+|
+=-=
+int
+main (void)
+{
+ |
+=-=-=
diff --git a/test/lisp/progmodes/eglot-tests.el b/test/lisp/progmodes/eglot-tests.el
index 2388cf9ef51..984c1bf9916 100644
--- a/test/lisp/progmodes/eglot-tests.el
+++ b/test/lisp/progmodes/eglot-tests.el
@@ -50,7 +50,6 @@
(require 'tramp) ; must be prior ert-x
(require 'ert-x) ; ert-simulate-command
(require 'edebug)
-(require 'python) ; some tests use pylsp
(require 'cc-mode) ; c-mode-hook
(require 'company nil t)
(require 'yasnippet nil t)
@@ -119,8 +118,6 @@ then restored."
,(format "HOME=%s"
(expand-file-name (format "~%s" (user-login-name)))))
process-environment))
- ;; Prevent "Can't guess python-indent-offset ..." messages.
- (python-indent-guess-indent-offset-verbose . nil)
(eglot-server-initialized-hook
(lambda (server) (push server new-servers))))
(setq created-files (mapcan #'eglot--make-file-or-dir file-specs))
@@ -533,90 +530,101 @@ Pass TIMEOUT to `eglot--with-timeout'."
(should (equal (buffer-string)
"int bar() {return 42;} int main() {return bar();}")))))
+(defun eglot--wait-for-clangd ()
+ (eglot--sniffing (:server-notifications s-notifs)
+ (should (eglot--tests-connect))
+ (eglot--wait-for (s-notifs 20) (&key method &allow-other-keys)
+ (string= method "textDocument/publishDiagnostics"))))
+
(ert-deftest eglot-test-basic-completions ()
- "Test basic autocompletion in a python LSP."
- (skip-unless (executable-find "pylsp"))
+ "Test basic autocompletion in a clangd LSP."
+ (skip-unless (executable-find "clangd"))
(eglot--with-fixture
- `(("project" . (("something.py" . "import sys\nsys.exi"))))
+ `(("project" . (("coiso.c" . "#include <stdio.h>\nint main () {fprin"))))
(with-current-buffer
- (eglot--find-file-noselect "project/something.py")
- (should (eglot--tests-connect))
+ (eglot--find-file-noselect "project/coiso.c")
+ (eglot--sniffing (:server-notifications s-notifs)
+ (eglot--wait-for-clangd)
+ (eglot--wait-for (s-notifs 20) (&key method &allow-other-keys)
+ (string= method "textDocument/publishDiagnostics")))
(goto-char (point-max))
(completion-at-point)
- (should (looking-back "sys.exit")))))
+ (message (buffer-string))
+ (should (looking-back "fprintf.?")))))
(ert-deftest eglot-test-non-unique-completions ()
"Test completion resulting in 'Complete, but not unique'."
- (skip-unless (executable-find "pylsp"))
+ (skip-unless (executable-find "clangd"))
(eglot--with-fixture
- '(("project" . (("something.py" . "foo=1\nfoobar=2\nfoo"))))
+ `(("project" . (("coiso.c" .
+ ,(concat "int foo; int fooey;"
+ "int main() {foo")))))
(with-current-buffer
- (eglot--find-file-noselect "project/something.py")
- (should (eglot--tests-connect))
+ (eglot--find-file-noselect "project/coiso.c")
+ (eglot--wait-for-clangd)
(goto-char (point-max))
- (completion-at-point))
- ;; FIXME: `current-message' doesn't work here :-(
+ (completion-at-point)
+ ;; FIXME: `current-message' doesn't work here :-(
(with-current-buffer (messages-buffer)
(save-excursion
(goto-char (point-max))
(forward-line -1)
- (should (looking-at "Complete, but not unique"))))))
+ (should (looking-at "Complete, but not unique")))))))
(ert-deftest eglot-test-basic-xref ()
- "Test basic xref functionality in a python LSP."
- (skip-unless (executable-find "pylsp"))
+ "Test basic xref functionality in a clangd LSP."
+ (skip-unless (executable-find "clangd"))
(eglot--with-fixture
- `(("project" . (("something.py" . "def foo(): pass\ndef bar(): foo()"))))
+ `(("project" . (("coiso.c" .
+ ,(concat "int foo=42; int fooey;"
+ "int main() {foo=82;}")))))
(with-current-buffer
- (eglot--find-file-noselect "project/something.py")
+ (eglot--find-file-noselect "project/coiso.c")
(should (eglot--tests-connect))
- (search-forward "bar(): f")
+ (search-forward "{foo")
(call-interactively 'xref-find-definitions)
- (should (looking-at "foo(): pass")))))
+ (should (looking-at "foo=42")))))
-(defvar eglot--test-python-buffer
+(defvar eglot--test-c-buffer
"\
-def foobarquux(a, b, c=True): pass
-def foobazquuz(d, e, f): pass
+void foobarquux(int a, int b, int c){};
+void foobazquuz(int a, int b, int f){};
+int main() {
")
(declare-function yas-minor-mode nil)
(ert-deftest eglot-test-snippet-completions ()
- "Test simple snippet completion in a python LSP."
- (skip-unless (and (executable-find "pylsp")
+ "Test simple snippet completion in a clangd LSP."
+ (skip-unless (and (executable-find "clangd")
(functionp 'yas-minor-mode)))
(eglot--with-fixture
- `(("project" . (("something.py" . ,eglot--test-python-buffer))))
+ `(("project" . (("coiso.c" . ,eglot--test-c-buffer))))
(with-current-buffer
- (eglot--find-file-noselect "project/something.py")
+ (eglot--find-file-noselect "project/coiso.c")
(yas-minor-mode 1)
- (let ((eglot-workspace-configuration
- `((:pylsp . (:plugins (:jedi_completion (:include_params t)))))))
- (should (eglot--tests-connect)))
+ (eglot--wait-for-clangd)
(goto-char (point-max))
(insert "foobar")
(completion-at-point)
(should (looking-back "foobarquux("))
- (should (looking-at "a, b)")))))
+ (should (looking-at "int a, int b, int c)")))))
(defvar company-candidates)
(declare-function company-mode nil)
(declare-function company-complete nil)
(ert-deftest eglot-test-snippet-completions-with-company ()
- "Test simple snippet completion in a python LSP."
- (skip-unless (and (executable-find "pylsp")
+ "Test simple snippet completion in a clangd LSP."
+ (skip-unless (and (executable-find "clangd")
(functionp 'yas-minor-mode)
(functionp 'company-complete)))
(eglot--with-fixture
- `(("project" . (("something.py" . ,eglot--test-python-buffer))))
+ `(("project" . (("coiso.c" . ,eglot--test-c-buffer))))
(with-current-buffer
- (eglot--find-file-noselect "project/something.py")
+ (eglot--find-file-noselect "project/coiso.c")
(yas-minor-mode 1)
- (let ((eglot-workspace-configuration
- `((:pylsp . (:plugins (:jedi_completion (:include_params t)))))))
- (should (eglot--tests-connect)))
+ (eglot--wait-for-clangd)
(goto-char (point-max))
(insert "foo")
(company-mode)
@@ -624,98 +632,63 @@ def foobazquuz(d, e, f): pass
(should (looking-back "fooba"))
(should (= 2 (length company-candidates)))
;; this last one is brittle, since there it is possible that
- ;; pylsp will change the representation of this candidate
- (should (member "foobazquuz(d, e, f)" company-candidates)))))
+ ;; clangd will change the representation of this candidate
+ (should (member "foobazquuz(int a, int b, int f)" company-candidates)))))
(ert-deftest eglot-test-eldoc-after-completions ()
- "Test documentation echo in a python LSP."
- (skip-unless (executable-find "pylsp"))
+ "Test documentation echo in a clangd LSP."
+ (skip-unless (executable-find "clangd"))
(eglot--with-fixture
- `(("project" . (("something.py" . "import sys\nsys.exi"))))
+ `(("project" . (("coiso.c" . "#include <stdio.h>\nint main () {fprin"))))
(with-current-buffer
- (eglot--find-file-noselect "project/something.py")
- (should (eglot--tests-connect))
+ (eglot--find-file-noselect "project/coiso.c")
+ (eglot--wait-for-clangd)
(goto-char (point-max))
(completion-at-point)
- (should (looking-back "sys.exit"))
- (should (string-match "^exit" (eglot--tests-force-full-eldoc))))))
+ (message (buffer-string))
+ (should (looking-back "fprintf(?"))
+ (unless (= (char-before) ?\() (insert "()") (backward-char))
+ (eglot--signal-textDocument/didChange)
+ (should (string-match "^fprintf" (eglot--tests-force-full-eldoc))))))
(ert-deftest eglot-test-multiline-eldoc ()
- "Test if suitable amount of lines of hover info are shown."
- (skip-unless (executable-find "pylsp"))
+ "Test Eldoc documentation from multiple osurces."
+ (skip-unless (executable-find "clangd"))
(eglot--with-fixture
- `(("project" . (("hover-first.py" . "from datetime import datetime"))))
+ `(("project" . (("coiso.c" .
+ "#include <stdio.h>\nint main () {fprintf(blergh);}"))))
(with-current-buffer
- (eglot--find-file-noselect "project/hover-first.py")
- (should (eglot--tests-connect))
- (goto-char (point-max))
- ;; one-line
- (let* ((eldoc-echo-area-use-multiline-p t)
- (captured-message (eglot--tests-force-full-eldoc)))
- (should (string-match "datetim" captured-message))
+ (eglot--find-file-noselect "project/coiso.c")
+ (search-forward "fprintf(ble")
+ (eglot--wait-for-clangd)
+ (flymake-start nil t) ;; thing brings in the "unknown identifier blergh"
+ (let* ((captured-message (eglot--tests-force-full-eldoc)))
+ ;; check for signature and error message in the result
+ (should (string-match "fprintf" captured-message))
+ (should (string-match "blergh" captured-message))
(should (cl-find ?\n captured-message))))))
-(ert-deftest eglot-test-single-line-eldoc ()
- "Test if suitable amount of lines of hover info are shown."
- (skip-unless (executable-find "pylsp"))
- (eglot--with-fixture
- `(("project" . (("hover-first.py" . "from datetime import datetime"))))
- (with-current-buffer
- (eglot--find-file-noselect "project/hover-first.py")
- (should (eglot--tests-connect))
- (goto-char (point-max))
- ;; one-line
- (let* ((eldoc-echo-area-use-multiline-p nil)
- (captured-message (eglot--tests-force-full-eldoc)))
- (should (string-match "datetim" captured-message))
- (should (not (cl-find ?\n eldoc-last-message)))))))
-
-(ert-deftest eglot-test-python-autopep-formatting ()
- "Test formatting in the pylsp python LSP.
-pylsp prefers autopep over yafp, despite its README stating the contrary."
+(ert-deftest eglot-test-formatting ()
+ "Test formatting in the clangd server."
;; Beware, default autopep rules can change over time, which may
;; affect this test.
- (skip-unless (and (executable-find "pylsp")
- (executable-find "autopep8")))
- (eglot--with-fixture
- `(("project" . (("something.py" . "def a():pass\n\ndef b():pass"))))
- (with-current-buffer
- (eglot--find-file-noselect "project/something.py")
- (should (eglot--tests-connect))
- ;; Try to format just the second line
- (search-forward "b():pa")
- (eglot-format (line-beginning-position) (line-end-position))
- (should (looking-at "ss"))
- (should
- (or (string= (buffer-string) "def a():pass\n\n\ndef b(): pass\n")
- ;; autopep8 2.0.0 (pycodestyle: 2.9.1)
- (string= (buffer-string) "def a():pass\n\ndef b(): pass")))
- ;; now format the whole buffer
- (eglot-format-buffer)
- (should
- (string= (buffer-string) "def a(): pass\n\n\ndef b(): pass\n")))))
-
-(ert-deftest eglot-test-python-yapf-formatting ()
- "Test formatting in the pylsp python LSP."
- (skip-unless (and (executable-find "pylsp")
- (not (executable-find "autopep8"))
- (or (executable-find "yapf")
- (executable-find "yapf3"))))
+ (skip-unless (executable-find "clangd"))
(eglot--with-fixture
- `(("project" . (("something.py" . "def a():pass\ndef b():pass"))))
+ `(("project" . (("coiso.c" . ,(concat "#include <stdio.h>\n"
+ "int main(){fprintf(blergh);}"
+ "int ble{\n\nreturn 0;}")))))
(with-current-buffer
- (eglot--find-file-noselect "project/something.py")
- (should (eglot--tests-connect))
+ (eglot--find-file-noselect "project/coiso.c")
+ (eglot--wait-for-clangd)
+ (forward-line)
;; Try to format just the second line
- (search-forward "b():pa")
(eglot-format (line-beginning-position) (line-end-position))
- (should (looking-at "ss"))
- (should
- (string= (buffer-string) "def a():pass\n\n\ndef b():\n pass\n"))
- ;; now format the whole buffer
+ (should (looking-at "int main() { fprintf(blergh); }"))
+ ;; ;; now format the whole buffer
(eglot-format-buffer)
(should
- (string= (buffer-string) "def a():\n pass\n\n\ndef b():\n pass\n")))))
+ (string= (buffer-string)
+ "#include <stdio.h>\nint main() { fprintf(blergh); }\nint ble { return 0; }")))))
(ert-deftest eglot-test-rust-on-type-formatting ()
"Test textDocument/onTypeFormatting against rust-analyzer."