aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2023-04-10 01:17:26 -0400
committerEli Zaretskii2023-04-10 01:17:26 -0400
commit671abd0cc406ec45898fdc2d27d09ce449023540 (patch)
tree0081d8d30f6216eb0eae8863b5ba361535d86829
parent4bc678ec9f4c05f7b26ea85b60e86ac0fc971afa (diff)
parentdb8f207e52fc969e0dcf30e197bcfaa4fa1d2b6e (diff)
downloademacs-671abd0cc406ec45898fdc2d27d09ce449023540.tar.gz
emacs-671abd0cc406ec45898fdc2d27d09ce449023540.zip
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
3216Windows}). It does that by calling @code{set-window-dedicated-p} with 3216Windows}). It does that by calling @code{set-window-dedicated-p} with
3217the chosen window as first argument and the entry's value as second. 3217the chosen window as first argument and the entry's value as second.
3218Side windows are by default dedicated with the value @code{side} 3218Side windows are by default dedicated with the value @code{side}
3219((@pxref{Side Window Options and Functions}). 3219(@pxref{Side Window Options and Functions}).
3220 3220
3221@vindex preserve-size@r{, a buffer display action alist entry} 3221@vindex preserve-size@r{, a buffer display action alist entry}
3222@item preserve-size 3222@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."
859 (goto-char (match-end 0))) 859 (goto-char (match-end 0)))
860 (treesit-default-defun-skipper)) 860 (treesit-default-defun-skipper))
861 861
862(defun c-ts-base--before-indent (args)
863 (pcase-let ((`(,node ,parent ,bol) args))
864 (when (null node)
865 (let ((smallest-node (treesit-node-at (point))))
866 ;; "Virtual" closer curly added by the
867 ;; parser's error recovery.
868 (when (and (equal (treesit-node-type smallest-node) "}")
869 (equal (treesit-node-end smallest-node)
870 (treesit-node-start smallest-node)))
871 (setq parent (treesit-node-parent smallest-node)))))
872 (list node parent bol)))
873
862(defun c-ts-mode-indent-defun () 874(defun c-ts-mode-indent-defun ()
863 "Indent the current top-level declaration syntactically. 875 "Indent the current top-level declaration syntactically.
864 876
@@ -904,6 +916,11 @@ the semicolon. This function skips the semicolon."
904 ;; function_definitions, so we need to find the top-level node. 916 ;; function_definitions, so we need to find the top-level node.
905 (setq-local treesit-defun-prefer-top-level t) 917 (setq-local treesit-defun-prefer-top-level t)
906 918
919 ;; When the code is in incomplete state, try to make a better guess
920 ;; about which node to indent against.
921 (add-function :filter-args (local 'treesit-indent-function)
922 #'c-ts-base--before-indent)
923
907 ;; Indent. 924 ;; Indent.
908 (when (eq c-ts-mode-indent-style 'linux) 925 (when (eq c-ts-mode-indent-style 'linux)
909 (setq-local indent-tabs-mode t)) 926 (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
1216command \\[fileloop-continue]." 1216command \\[fileloop-continue]."
1217 (interactive "sSearch (regexp): ") 1217 (interactive "sSearch (regexp): ")
1218 (fileloop-initialize-search 1218 (fileloop-initialize-search
1219 regexp (project-files (project-current t)) 'default) 1219 regexp
1220 ;; XXX: See the comment in project-query-replace-regexp.
1221 (cl-delete-if-not #'file-regular-p (project-files (project-current t)))
1222 'default)
1220 (fileloop-continue)) 1223 (fileloop-continue))
1221 1224
1222;;;###autoload 1225;;;###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)
464 | 464 |
465} 465}
466=-=-= 466=-=-=
467
468Name: Empty Line (Block Start)
469
470=-=
471int
472main (void)
473{
474|
475=-=
476int
477main (void)
478{
479 |
480=-=-=
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 @@
50(require 'tramp) ; must be prior ert-x 50(require 'tramp) ; must be prior ert-x
51(require 'ert-x) ; ert-simulate-command 51(require 'ert-x) ; ert-simulate-command
52(require 'edebug) 52(require 'edebug)
53(require 'python) ; some tests use pylsp
54(require 'cc-mode) ; c-mode-hook 53(require 'cc-mode) ; c-mode-hook
55(require 'company nil t) 54(require 'company nil t)
56(require 'yasnippet nil t) 55(require 'yasnippet nil t)
@@ -119,8 +118,6 @@ then restored."
119 ,(format "HOME=%s" 118 ,(format "HOME=%s"
120 (expand-file-name (format "~%s" (user-login-name))))) 119 (expand-file-name (format "~%s" (user-login-name)))))
121 process-environment)) 120 process-environment))
122 ;; Prevent "Can't guess python-indent-offset ..." messages.
123 (python-indent-guess-indent-offset-verbose . nil)
124 (eglot-server-initialized-hook 121 (eglot-server-initialized-hook
125 (lambda (server) (push server new-servers)))) 122 (lambda (server) (push server new-servers))))
126 (setq created-files (mapcan #'eglot--make-file-or-dir file-specs)) 123 (setq created-files (mapcan #'eglot--make-file-or-dir file-specs))
@@ -533,90 +530,101 @@ Pass TIMEOUT to `eglot--with-timeout'."
533 (should (equal (buffer-string) 530 (should (equal (buffer-string)
534 "int bar() {return 42;} int main() {return bar();}"))))) 531 "int bar() {return 42;} int main() {return bar();}")))))
535 532
533(defun eglot--wait-for-clangd ()
534 (eglot--sniffing (:server-notifications s-notifs)
535 (should (eglot--tests-connect))
536 (eglot--wait-for (s-notifs 20) (&key method &allow-other-keys)
537 (string= method "textDocument/publishDiagnostics"))))
538
536(ert-deftest eglot-test-basic-completions () 539(ert-deftest eglot-test-basic-completions ()
537 "Test basic autocompletion in a python LSP." 540 "Test basic autocompletion in a clangd LSP."
538 (skip-unless (executable-find "pylsp")) 541 (skip-unless (executable-find "clangd"))
539 (eglot--with-fixture 542 (eglot--with-fixture
540 `(("project" . (("something.py" . "import sys\nsys.exi")))) 543 `(("project" . (("coiso.c" . "#include <stdio.h>\nint main () {fprin"))))
541 (with-current-buffer 544 (with-current-buffer
542 (eglot--find-file-noselect "project/something.py") 545 (eglot--find-file-noselect "project/coiso.c")
543 (should (eglot--tests-connect)) 546 (eglot--sniffing (:server-notifications s-notifs)
547 (eglot--wait-for-clangd)
548 (eglot--wait-for (s-notifs 20) (&key method &allow-other-keys)
549 (string= method "textDocument/publishDiagnostics")))
544 (goto-char (point-max)) 550 (goto-char (point-max))
545 (completion-at-point) 551 (completion-at-point)
546 (should (looking-back "sys.exit"))))) 552 (message (buffer-string))
553 (should (looking-back "fprintf.?")))))
547 554
548(ert-deftest eglot-test-non-unique-completions () 555(ert-deftest eglot-test-non-unique-completions ()
549 "Test completion resulting in 'Complete, but not unique'." 556 "Test completion resulting in 'Complete, but not unique'."
550 (skip-unless (executable-find "pylsp")) 557 (skip-unless (executable-find "clangd"))
551 (eglot--with-fixture 558 (eglot--with-fixture
552 '(("project" . (("something.py" . "foo=1\nfoobar=2\nfoo")))) 559 `(("project" . (("coiso.c" .
560 ,(concat "int foo; int fooey;"
561 "int main() {foo")))))
553 (with-current-buffer 562 (with-current-buffer
554 (eglot--find-file-noselect "project/something.py") 563 (eglot--find-file-noselect "project/coiso.c")
555 (should (eglot--tests-connect)) 564 (eglot--wait-for-clangd)
556 (goto-char (point-max)) 565 (goto-char (point-max))
557 (completion-at-point)) 566 (completion-at-point)
558 ;; FIXME: `current-message' doesn't work here :-( 567 ;; FIXME: `current-message' doesn't work here :-(
559 (with-current-buffer (messages-buffer) 568 (with-current-buffer (messages-buffer)
560 (save-excursion 569 (save-excursion
561 (goto-char (point-max)) 570 (goto-char (point-max))
562 (forward-line -1) 571 (forward-line -1)
563 (should (looking-at "Complete, but not unique")))))) 572 (should (looking-at "Complete, but not unique")))))))
564 573
565(ert-deftest eglot-test-basic-xref () 574(ert-deftest eglot-test-basic-xref ()
566 "Test basic xref functionality in a python LSP." 575 "Test basic xref functionality in a clangd LSP."
567 (skip-unless (executable-find "pylsp")) 576 (skip-unless (executable-find "clangd"))
568 (eglot--with-fixture 577 (eglot--with-fixture
569 `(("project" . (("something.py" . "def foo(): pass\ndef bar(): foo()")))) 578 `(("project" . (("coiso.c" .
579 ,(concat "int foo=42; int fooey;"
580 "int main() {foo=82;}")))))
570 (with-current-buffer 581 (with-current-buffer
571 (eglot--find-file-noselect "project/something.py") 582 (eglot--find-file-noselect "project/coiso.c")
572 (should (eglot--tests-connect)) 583 (should (eglot--tests-connect))
573 (search-forward "bar(): f") 584 (search-forward "{foo")
574 (call-interactively 'xref-find-definitions) 585 (call-interactively 'xref-find-definitions)
575 (should (looking-at "foo(): pass"))))) 586 (should (looking-at "foo=42")))))
576 587
577(defvar eglot--test-python-buffer 588(defvar eglot--test-c-buffer
578 "\ 589 "\
579def foobarquux(a, b, c=True): pass 590void foobarquux(int a, int b, int c){};
580def foobazquuz(d, e, f): pass 591void foobazquuz(int a, int b, int f){};
592int main() {
581") 593")
582 594
583(declare-function yas-minor-mode nil) 595(declare-function yas-minor-mode nil)
584 596
585(ert-deftest eglot-test-snippet-completions () 597(ert-deftest eglot-test-snippet-completions ()
586 "Test simple snippet completion in a python LSP." 598 "Test simple snippet completion in a clangd LSP."
587 (skip-unless (and (executable-find "pylsp") 599 (skip-unless (and (executable-find "clangd")
588 (functionp 'yas-minor-mode))) 600 (functionp 'yas-minor-mode)))
589 (eglot--with-fixture 601 (eglot--with-fixture
590 `(("project" . (("something.py" . ,eglot--test-python-buffer)))) 602 `(("project" . (("coiso.c" . ,eglot--test-c-buffer))))
591 (with-current-buffer 603 (with-current-buffer
592 (eglot--find-file-noselect "project/something.py") 604 (eglot--find-file-noselect "project/coiso.c")
593 (yas-minor-mode 1) 605 (yas-minor-mode 1)
594 (let ((eglot-workspace-configuration 606 (eglot--wait-for-clangd)
595 `((:pylsp . (:plugins (:jedi_completion (:include_params t)))))))
596 (should (eglot--tests-connect)))
597 (goto-char (point-max)) 607 (goto-char (point-max))
598 (insert "foobar") 608 (insert "foobar")
599 (completion-at-point) 609 (completion-at-point)
600 (should (looking-back "foobarquux(")) 610 (should (looking-back "foobarquux("))
601 (should (looking-at "a, b)"))))) 611 (should (looking-at "int a, int b, int c)")))))
602 612
603(defvar company-candidates) 613(defvar company-candidates)
604(declare-function company-mode nil) 614(declare-function company-mode nil)
605(declare-function company-complete nil) 615(declare-function company-complete nil)
606 616
607(ert-deftest eglot-test-snippet-completions-with-company () 617(ert-deftest eglot-test-snippet-completions-with-company ()
608 "Test simple snippet completion in a python LSP." 618 "Test simple snippet completion in a clangd LSP."
609 (skip-unless (and (executable-find "pylsp") 619 (skip-unless (and (executable-find "clangd")
610 (functionp 'yas-minor-mode) 620 (functionp 'yas-minor-mode)
611 (functionp 'company-complete))) 621 (functionp 'company-complete)))
612 (eglot--with-fixture 622 (eglot--with-fixture
613 `(("project" . (("something.py" . ,eglot--test-python-buffer)))) 623 `(("project" . (("coiso.c" . ,eglot--test-c-buffer))))
614 (with-current-buffer 624 (with-current-buffer
615 (eglot--find-file-noselect "project/something.py") 625 (eglot--find-file-noselect "project/coiso.c")
616 (yas-minor-mode 1) 626 (yas-minor-mode 1)
617 (let ((eglot-workspace-configuration 627 (eglot--wait-for-clangd)
618 `((:pylsp . (:plugins (:jedi_completion (:include_params t)))))))
619 (should (eglot--tests-connect)))
620 (goto-char (point-max)) 628 (goto-char (point-max))
621 (insert "foo") 629 (insert "foo")
622 (company-mode) 630 (company-mode)
@@ -624,98 +632,63 @@ def foobazquuz(d, e, f): pass
624 (should (looking-back "fooba")) 632 (should (looking-back "fooba"))
625 (should (= 2 (length company-candidates))) 633 (should (= 2 (length company-candidates)))
626 ;; this last one is brittle, since there it is possible that 634 ;; this last one is brittle, since there it is possible that
627 ;; pylsp will change the representation of this candidate 635 ;; clangd will change the representation of this candidate
628 (should (member "foobazquuz(d, e, f)" company-candidates))))) 636 (should (member "foobazquuz(int a, int b, int f)" company-candidates)))))
629 637
630(ert-deftest eglot-test-eldoc-after-completions () 638(ert-deftest eglot-test-eldoc-after-completions ()
631 "Test documentation echo in a python LSP." 639 "Test documentation echo in a clangd LSP."
632 (skip-unless (executable-find "pylsp")) 640 (skip-unless (executable-find "clangd"))
633 (eglot--with-fixture 641 (eglot--with-fixture
634 `(("project" . (("something.py" . "import sys\nsys.exi")))) 642 `(("project" . (("coiso.c" . "#include <stdio.h>\nint main () {fprin"))))
635 (with-current-buffer 643 (with-current-buffer
636 (eglot--find-file-noselect "project/something.py") 644 (eglot--find-file-noselect "project/coiso.c")
637 (should (eglot--tests-connect)) 645 (eglot--wait-for-clangd)
638 (goto-char (point-max)) 646 (goto-char (point-max))
639 (completion-at-point) 647 (completion-at-point)
640 (should (looking-back "sys.exit")) 648 (message (buffer-string))
641 (should (string-match "^exit" (eglot--tests-force-full-eldoc)))))) 649 (should (looking-back "fprintf(?"))
650 (unless (= (char-before) ?\() (insert "()") (backward-char))
651 (eglot--signal-textDocument/didChange)
652 (should (string-match "^fprintf" (eglot--tests-force-full-eldoc))))))
642 653
643(ert-deftest eglot-test-multiline-eldoc () 654(ert-deftest eglot-test-multiline-eldoc ()
644 "Test if suitable amount of lines of hover info are shown." 655 "Test Eldoc documentation from multiple osurces."
645 (skip-unless (executable-find "pylsp")) 656 (skip-unless (executable-find "clangd"))
646 (eglot--with-fixture 657 (eglot--with-fixture
647 `(("project" . (("hover-first.py" . "from datetime import datetime")))) 658 `(("project" . (("coiso.c" .
659 "#include <stdio.h>\nint main () {fprintf(blergh);}"))))
648 (with-current-buffer 660 (with-current-buffer
649 (eglot--find-file-noselect "project/hover-first.py") 661 (eglot--find-file-noselect "project/coiso.c")
650 (should (eglot--tests-connect)) 662 (search-forward "fprintf(ble")
651 (goto-char (point-max)) 663 (eglot--wait-for-clangd)
652 ;; one-line 664 (flymake-start nil t) ;; thing brings in the "unknown identifier blergh"
653 (let* ((eldoc-echo-area-use-multiline-p t) 665 (let* ((captured-message (eglot--tests-force-full-eldoc)))
654 (captured-message (eglot--tests-force-full-eldoc))) 666 ;; check for signature and error message in the result
655 (should (string-match "datetim" captured-message)) 667 (should (string-match "fprintf" captured-message))
668 (should (string-match "blergh" captured-message))
656 (should (cl-find ?\n captured-message)))))) 669 (should (cl-find ?\n captured-message))))))
657 670
658(ert-deftest eglot-test-single-line-eldoc () 671(ert-deftest eglot-test-formatting ()
659 "Test if suitable amount of lines of hover info are shown." 672 "Test formatting in the clangd server."
660 (skip-unless (executable-find "pylsp"))
661 (eglot--with-fixture
662 `(("project" . (("hover-first.py" . "from datetime import datetime"))))
663 (with-current-buffer
664 (eglot--find-file-noselect "project/hover-first.py")
665 (should (eglot--tests-connect))
666 (goto-char (point-max))
667 ;; one-line
668 (let* ((eldoc-echo-area-use-multiline-p nil)
669 (captured-message (eglot--tests-force-full-eldoc)))
670 (should (string-match "datetim" captured-message))
671 (should (not (cl-find ?\n eldoc-last-message)))))))
672
673(ert-deftest eglot-test-python-autopep-formatting ()
674 "Test formatting in the pylsp python LSP.
675pylsp prefers autopep over yafp, despite its README stating the contrary."
676 ;; Beware, default autopep rules can change over time, which may 673 ;; Beware, default autopep rules can change over time, which may
677 ;; affect this test. 674 ;; affect this test.
678 (skip-unless (and (executable-find "pylsp") 675 (skip-unless (executable-find "clangd"))
679 (executable-find "autopep8")))
680 (eglot--with-fixture
681 `(("project" . (("something.py" . "def a():pass\n\ndef b():pass"))))
682 (with-current-buffer
683 (eglot--find-file-noselect "project/something.py")
684 (should (eglot--tests-connect))
685 ;; Try to format just the second line
686 (search-forward "b():pa")
687 (eglot-format (line-beginning-position) (line-end-position))
688 (should (looking-at "ss"))
689 (should
690 (or (string= (buffer-string) "def a():pass\n\n\ndef b(): pass\n")
691 ;; autopep8 2.0.0 (pycodestyle: 2.9.1)
692 (string= (buffer-string) "def a():pass\n\ndef b(): pass")))
693 ;; now format the whole buffer
694 (eglot-format-buffer)
695 (should
696 (string= (buffer-string) "def a(): pass\n\n\ndef b(): pass\n")))))
697
698(ert-deftest eglot-test-python-yapf-formatting ()
699 "Test formatting in the pylsp python LSP."
700 (skip-unless (and (executable-find "pylsp")
701 (not (executable-find "autopep8"))
702 (or (executable-find "yapf")
703 (executable-find "yapf3"))))
704 (eglot--with-fixture 676 (eglot--with-fixture
705 `(("project" . (("something.py" . "def a():pass\ndef b():pass")))) 677 `(("project" . (("coiso.c" . ,(concat "#include <stdio.h>\n"
678 "int main(){fprintf(blergh);}"
679 "int ble{\n\nreturn 0;}")))))
706 (with-current-buffer 680 (with-current-buffer
707 (eglot--find-file-noselect "project/something.py") 681 (eglot--find-file-noselect "project/coiso.c")
708 (should (eglot--tests-connect)) 682 (eglot--wait-for-clangd)
683 (forward-line)
709 ;; Try to format just the second line 684 ;; Try to format just the second line
710 (search-forward "b():pa")
711 (eglot-format (line-beginning-position) (line-end-position)) 685 (eglot-format (line-beginning-position) (line-end-position))
712 (should (looking-at "ss")) 686 (should (looking-at "int main() { fprintf(blergh); }"))
713 (should 687 ;; ;; now format the whole buffer
714 (string= (buffer-string) "def a():pass\n\n\ndef b():\n pass\n"))
715 ;; now format the whole buffer
716 (eglot-format-buffer) 688 (eglot-format-buffer)
717 (should 689 (should
718 (string= (buffer-string) "def a():\n pass\n\n\ndef b():\n pass\n"))))) 690 (string= (buffer-string)
691 "#include <stdio.h>\nint main() { fprintf(blergh); }\nint ble { return 0; }")))))
719 692
720(ert-deftest eglot-test-rust-on-type-formatting () 693(ert-deftest eglot-test-rust-on-type-formatting ()
721 "Test textDocument/onTypeFormatting against rust-analyzer." 694 "Test textDocument/onTypeFormatting against rust-analyzer."