[elpa] externals/exwm e689221: Only call exwm-randr-screen-change-hook on new event sequence number
branch: externals/exwm commit e6892216a6851307c822a71841ad2dc986facb77 Author: James Ferguson Commit: James Ferguson Only call exwm-randr-screen-change-hook on new event sequence number Multiple event callbacks are triggered per physical monitor plug event. This de-duplicates the events triggering the running of the hook. --- exwm-randr.el | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/exwm-randr.el b/exwm-randr.el index a0fe959..59b2912 100644 --- a/exwm-randr.el +++ b/exwm-randr.el @@ -95,6 +95,8 @@ corresponding monitors whenever the monitors are active. (defvar exwm-workspace--fullscreen-frame-count) (defvar exwm-workspace--list) +(defvar exwm-randr--prev-screen-change-seqnum nil + "The most recent ScreenChangeNotify sequence number.") (declare-function exwm-workspace--count "exwm-workspace.el") (declare-function exwm-workspace--set-active "exwm-workspace.el" (frame active)) @@ -193,12 +195,17 @@ corresponding monitors whenever the monitors are active. (define-obsolete-function-alias 'exwm-randr--refresh #'exwm-randr-refresh "27.1") -(defun exwm-randr--on-ScreenChangeNotify (_data _synthetic) +(defun exwm-randr--on-ScreenChangeNotify (data _synthetic) "Handle `ScreenChangeNotify' event. Run `exwm-randr-screen-change-hook' (usually user scripts to configure RandR)." (exwm--log) - (run-hooks 'exwm-randr-screen-change-hook)) + (let ((evt (make-instance 'xcb:randr:ScreenChangeNotify))) +(xcb:unmarshal evt data) +(let ((seqnum (slot-value evt '~sequence))) + (unless (equal seqnum exwm-randr--prev-screen-change-seqnum) +(setq exwm-randr--prev-screen-change-seqnum seqnum) +(run-hooks 'exwm-randr-screen-change-hook) (defun exwm-randr--on-Notify (data _synthetic) "Handle `CrtcChangeNotify' and `OutputChangeNotify' events.
[elpa] master 7f3698b: [el-search] Stop for problematic comments
branch: master commit 7f3698bf32137998560182a534195a1f772cf19b Author: Michael Heerdegen Commit: Michael Heerdegen [el-search] Stop for problematic comments Make automatic replacing stop when comments can't be placed automatically. Bump version to 1.8. * packages/el-search/el-search.el (el-search-query-replace-stop-for-comments): New user option. (el-search-query-replace--comments-preserved-p): New helper function. (el-search--search-and-replace-pattern): Change to make it respect the value of 'el-search-query-replace-stop-for-comments'. --- packages/el-search/NEWS | 20 + packages/el-search/el-search.el | 160 +++- 2 files changed, 130 insertions(+), 50 deletions(-) diff --git a/packages/el-search/NEWS b/packages/el-search/NEWS index cc5d877..cf1b425 100644 --- a/packages/el-search/NEWS +++ b/packages/el-search/NEWS @@ -1,6 +1,26 @@ Some of the user visible news were: +Version: 1.8 + + Several improvements in `el-search-query-replace': + + It's now possible to edit the replacement in a separate buffer + without interrupting `el-search-query-replace', and to ediff the + current replacement with the current match (new keys 'o' and 'e'). + + Hitting the 'r' key now toggles between replacing a match without + moving and restoring the match. + + After replacing a match with 'r', the key to go to the next match + changed from 'n' to 'y' which should feel more natural. + + Depending on the value of the new user option + `el-search-query-replace-stop-for-comments', + `el-search-query-replace' can now interrupt automatic replacement + when it's not able to unumbigously assign comments in the current + match to the replacement. + Version: 1.7.15 *El Occur* buffers are now initially unfolded. diff --git a/packages/el-search/el-search.el b/packages/el-search/el-search.el index 6f64f1c..9012a5f 100644 --- a/packages/el-search/el-search.el +++ b/packages/el-search/el-search.el @@ -7,7 +7,7 @@ ;; Created: 29 Jul 2015 ;; Keywords: lisp ;; Compatibility: GNU Emacs 25 -;; Version: 1.7.15 +;; Version: 1.8 ;; Package-Requires: ((emacs "25") (stream "2.2.4") (cl-print "1.0")) @@ -393,18 +393,6 @@ ;; to reading-printing. "Some" because we can handle this problem ;; in most cases. ;; -;; - Similar: comments are normally preserved (where it makes sense). -;; But when replacing like `(foo ,a ,b) -> `(foo ,b ,a) -;; -;; in a content like -;; -;; (foo -;; a -;; ;; comment -;; b) -;; -;; the comment will be lost. -;; ;; - Something like (1 #1#) is unmatchable (because it is un`read'able ;; without context). ;; @@ -437,10 +425,6 @@ ;; already suffice using only syntax tables, sexp scanning and ;; font-lock? ;; -;; - Replace: pause and warn when replacement might be wrong -;; (ambiguous reader syntaxes; lost comments, comments that can't -;; non-ambiguously be assigned to rewritten code) -;; ;; - There could be something much better than pp to format the ;; replacement, or pp should be improved. ;; @@ -552,6 +536,32 @@ The default value is ask-multi." (const :tag "Ask" ask) (const :tag "Ask when multibuffer" ask-multi))) +(defcustom el-search-query-replace-stop-for-comments 'ask + "Whether `el-search-query-replace' should stop for problematic comments. + +It's not always clear how comments in a match should be mapped to +the replacement. If it can't be done automatically, the value of this +option decides how to proceed. + +When nil, comments will likely be messed up or lost. You should +then check the results after finishing `el-search-query-replace'. + +A non-nil value means to interrupt when encountering problematic +comments. When the non-nil value is the symbol ask (that's the +default), a prompt will appear that will ask how to proceed for +the current match. You may then choose to edit the replacement +manually, or ignore the problem for this case to fix it later. + +Any other non-nil value will not prompt and just directly pop to +a buffer where you can edit the replacement to adjust the +comments. + +When the value is ask, you can still choose the answer for all +following cases from the prompt." + :type '(choice (const :tag "Off" nil) + (const :tag "On" t) + (const :tag "Ask" ask))) + (defvar el-search-use-transient-map nil "Whether el-search should make commands repeatable." ;; I originally wanted to make commands repeatable by looking at the @@ -3668,6 +3678,22 @@ exactly you did? Thanks!" hook-funs) 'ediff-regions-linewise nil nil) +(defun el-search-query-replace--comments-preserved-p (from to) + (cl-flet ((get-comments + (lambda (text) + (let ((comments '())) + (with-temp-buffer + (insert text) + (goto-char (point-min))
[elpa] master 188d50d: [el-search] Enhancements to my last two commits
branch: master commit 188d50d717e2c11f7c791b5312898cf5c983fe2b Author: Michael Heerdegen Commit: Michael Heerdegen [el-search] Enhancements to my last two commits Also bump version to 1.8.1. * packages/el-search/el-search.el (el-search--search-and-replace-pattern): Use the modified flag of the buffer to edit the replacement to decide if the user modified the contents. Some more minor tweaks. --- packages/el-search/el-search.el | 35 ++- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/packages/el-search/el-search.el b/packages/el-search/el-search.el index 9012a5f..c56e42a 100644 --- a/packages/el-search/el-search.el +++ b/packages/el-search/el-search.el @@ -7,7 +7,7 @@ ;; Created: 29 Jul 2015 ;; Keywords: lisp ;; Compatibility: GNU Emacs 25 -;; Version: 1.8 +;; Version: 1.8.1 ;; Package-Requires: ((emacs "25") (stream "2.2.4") (cl-print "1.0")) @@ -3798,8 +3798,7 @@ exactly you did? Thanks!" (edit-replacement (lambda (&optional ediff-only) (save-excursion ;user may copy stuff from base buffer etc. - (let* ((buffer (get-buffer-create - (generate-new-buffer-name "*Replacement*"))) + (let* ((buffer (generate-new-buffer "*Replacement*")) (window (display-buffer buffer))) (select-window window) (emacs-lisp-mode) @@ -3817,6 +3816,8 @@ exactly you did? Thanks!" 'front-sticky t 'rear-nonsticky t) "\n\n")) (save-excursion (insert to-insert)) + (let ((inhibit-message t)) + (indent-region (point) (point-max))) (let* ((owconf (current-window-configuration)) (make-cleanup-fun (lambda (&optional do) @@ -3834,8 +3835,7 @@ exactly you did? Thanks!" (abort (funcall make-cleanup-fun (lambda () -(let ((inhibit-read-only t)) - (delete-region (point-min) (point-max))) +(set-buffer-modified-p nil) (exit-recursive-edit) (set-keymap-parent map (current-local-map)) (define-key map [(control ?c) (control ?c)] @@ -3865,19 +3865,19 @@ exactly you did? Thanks!" (el-search-query-replace-ediff-replacement (funcall make-ediff-startup-hook-fun #'exit-recursive-edit))) + (set-buffer-modified-p nil) (recursive-edit))) - (let ((content-now -(with-current-buffer buffer - (goto-char (point-min)) - (while (and (not (eobp)) - (looking-at "^;;\\|^$")) -(forward-line)) - (buffer-substring (point) (point-max) - (when (and (not (or (string= to-insert content-now) - (string-match-p (rx bos (* space) eos) - content-now))) + (let ((new-to-insert +(and (buffer-modified-p buffer) + (with-current-buffer buffer + (goto-char (point-min)) + (while (and (not (eobp)) + (looking-at "^;;\\|^$")) + (forward-line)) + (buffer-substring (point) (point-max)) + (when (and new-to-inse
[elpa] master 5ed8901 1/2: Fixed stacking multiple conditions
branch: master commit 5ed8901691b26eb5847f9522d20fa93a4fbaace8 Author: Ian Dunn Commit: Ian Dunn Fixed stacking multiple conditions * org-edna.el (org-edna--normalize-sexp-form): Only set state if not breaking. (org-edna--expand-sexp-form): Properly handle blocking-var. * org-edna-tests.el (org-edna-expand-sexp-form): (org-edna-expand-sexp-form-multiple): (org-edna-expand-sexp-form-if-else): (org-edna-expand-sexp-form-if-no-else): Removed buggy expansion tests. (org-edna-doc-test/multiple-blockers): Added test for multiple blockers. * org-edna.org (Multiple Blockers): Added section. --- org-edna-tests.el | 204 +++-- org-edna-tests.org | 13 org-edna.el| 25 +-- org-edna.info | 198 ++- org-edna.org | 28 +++- 5 files changed, 202 insertions(+), 266 deletions(-) diff --git a/org-edna-tests.el b/org-edna-tests.el index b6adf15..331438f 100644 --- a/org-edna-tests.el +++ b/org-edna-tests.el @@ -336,183 +336,6 @@ This avoids org-id digging into its internal database." ;; Error should point to the start of the if-statement (should (eq (plist-get data :error-pos) 45 -(ert-deftest org-edna-expand-sexp-form () - ;; Override cl-gentemp so we have a repeatable test - (cl-letf* (((symbol-function 'cl-gentemp) (lambda (&optional prefix) (intern (format "%s1" prefix - (input-sexp '((self) - (!done?))) - (output-form (org-edna--expand-sexp-form input-sexp))) -(should (equal - output-form - '(let ((targets1 nil) -(consideration1 nil) -(blocking-entry1 nil)) -(setq targets1 (org-edna--add-targets targets1 (org-edna--handle-finder 'org-edna-finder/self 'nil))) -(setq blocking-entry1 - (or blocking-entry1 - (org-edna--handle-condition 'org-edna-condition/done? - '! 'nil targets1 - consideration1 - -(ert-deftest org-edna-expand-sexp-form-multiple () - (cl-letf* ((target-ctr 0) - (consideration-ctr 0) - (blocking-entry-ctr 0) - ((symbol-function 'cl-gentemp) - (lambda (&optional prefix) -(let ((ctr (pcase prefix - ("targets" (cl-incf target-ctr)) - ("consideration" (cl-incf consideration-ctr)) - ("blocking-entry" (cl-incf blocking-entry-ctr)) - (_ 0 - (intern (format "%s%s" prefix ctr) - (input-sexp '(((match "checklist") -(todo! DONE)) - ((siblings) -(todo! TODO - (expected-form - '(let ((targets1 nil) - (consideration1 nil) - (blocking-entry1 nil)) - ;; Don't need a new set of variables - (let ((targets2 targets1) - (consideration2 consideration1) - (blocking-entry2 blocking-entry1)) - (setq targets2 - (org-edna--add-targets targets2 -(org-edna--handle-finder 'org-edna-finder/match '("checklist" - (org-edna--handle-action 'org-edna-action/todo! -targets2 -(point-marker) -'(DONE))) - (let ((targets5 targets1) - (consideration5 consideration1) - (blocking-entry5 blocking-entry1)) - (setq targets5 - (org-edna--add-targets targets5 -(org-edna--handle-finder 'org-edna-finder/siblings 'nil))) - (org-edna--handle-action 'org-edna-action/todo! -targets5 -(point-marker) -'(TODO) - (output-form (org-edna--expand-sexp-form input-sexp))) -(should (equal output-form expected-form - -(ert-deftest org-edna-expand-sexp-form-if-else () - (cl-letf* ((target-ctr 0) - (consideration-ctr 0) - (blocking-entry-ctr 0) - ((symbol-function 'cl-gentemp) - (lambda (&optional prefix) -(let ((ctr (pcase prefix - ("targets" (cl-incf target-ctr)) - ("consideration" (cl-incf consideration-ctr)) -
[elpa] master 88f1900 2/2: Merge commit '5ed8901691b26eb5847f9522d20fa93a4fbaace8'
branch: master commit 88f190092ceb56200cbafcd072bb970500f2205e Merge: 188d50d 5ed8901 Author: Ian Dunn Commit: Ian Dunn Merge commit '5ed8901691b26eb5847f9522d20fa93a4fbaace8' --- packages/org-edna/org-edna-tests.el | 204 +-- packages/org-edna/org-edna-tests.org | 13 +++ packages/org-edna/org-edna.el| 25 +++-- packages/org-edna/org-edna.info | 198 -- packages/org-edna/org-edna.org | 28 - 5 files changed, 202 insertions(+), 266 deletions(-) diff --git a/packages/org-edna/org-edna-tests.el b/packages/org-edna/org-edna-tests.el index b6adf15..331438f 100644 --- a/packages/org-edna/org-edna-tests.el +++ b/packages/org-edna/org-edna-tests.el @@ -336,183 +336,6 @@ This avoids org-id digging into its internal database." ;; Error should point to the start of the if-statement (should (eq (plist-get data :error-pos) 45 -(ert-deftest org-edna-expand-sexp-form () - ;; Override cl-gentemp so we have a repeatable test - (cl-letf* (((symbol-function 'cl-gentemp) (lambda (&optional prefix) (intern (format "%s1" prefix - (input-sexp '((self) - (!done?))) - (output-form (org-edna--expand-sexp-form input-sexp))) -(should (equal - output-form - '(let ((targets1 nil) -(consideration1 nil) -(blocking-entry1 nil)) -(setq targets1 (org-edna--add-targets targets1 (org-edna--handle-finder 'org-edna-finder/self 'nil))) -(setq blocking-entry1 - (or blocking-entry1 - (org-edna--handle-condition 'org-edna-condition/done? - '! 'nil targets1 - consideration1 - -(ert-deftest org-edna-expand-sexp-form-multiple () - (cl-letf* ((target-ctr 0) - (consideration-ctr 0) - (blocking-entry-ctr 0) - ((symbol-function 'cl-gentemp) - (lambda (&optional prefix) -(let ((ctr (pcase prefix - ("targets" (cl-incf target-ctr)) - ("consideration" (cl-incf consideration-ctr)) - ("blocking-entry" (cl-incf blocking-entry-ctr)) - (_ 0 - (intern (format "%s%s" prefix ctr) - (input-sexp '(((match "checklist") -(todo! DONE)) - ((siblings) -(todo! TODO - (expected-form - '(let ((targets1 nil) - (consideration1 nil) - (blocking-entry1 nil)) - ;; Don't need a new set of variables - (let ((targets2 targets1) - (consideration2 consideration1) - (blocking-entry2 blocking-entry1)) - (setq targets2 - (org-edna--add-targets targets2 -(org-edna--handle-finder 'org-edna-finder/match '("checklist" - (org-edna--handle-action 'org-edna-action/todo! -targets2 -(point-marker) -'(DONE))) - (let ((targets5 targets1) - (consideration5 consideration1) - (blocking-entry5 blocking-entry1)) - (setq targets5 - (org-edna--add-targets targets5 -(org-edna--handle-finder 'org-edna-finder/siblings 'nil))) - (org-edna--handle-action 'org-edna-action/todo! -targets5 -(point-marker) -'(TODO) - (output-form (org-edna--expand-sexp-form input-sexp))) -(should (equal output-form expected-form - -(ert-deftest org-edna-expand-sexp-form-if-else () - (cl-letf* ((target-ctr 0) - (consideration-ctr 0) - (blocking-entry-ctr 0) - ((symbol-function 'cl-gentemp) - (lambda (&optional prefix) -(let ((ctr (pcase prefix - ("targets" (cl-incf target-ctr)) - ("consideration" (cl-incf consideration-ctr)) - ("blocking-entry" (cl-incf blocking-entry-ctr)) - (_ 0 - (intern (format "%s%s" prefix ctr) - (input-sexp '((if - ((match "checklist") -(done\?)) - ((self) -
[elpa] externals/eglot 9fb5f0c 05/26: Per #52, #127: Improve performance of xref summary line collection
branch: externals/eglot commit 9fb5f0cb5de73c4ca221ec8865fe7677fb29b2da Author: João Távora Commit: João Távora Per #52, #127: Improve performance of xref summary line collection * eglot.el (eglot--temp-location-buffers): New variable. (eglot--handling-xrefs): New macro. (eglot--xref-make): Use eglot--temp-location-buffers. (xref-backend-definitions, xref-backend-references) (xref-backend-apropos): Use eglot--handling-xrefs. --- eglot.el | 38 -- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/eglot.el b/eglot.el index 8ba483b..1522935 100644 --- a/eglot.el +++ b/eglot.el @@ -1478,13 +1478,26 @@ DUMMY is ignored." (advice-add 'xref-find-definitions :after #'eglot--xref-reset-known-symbols) (advice-add 'xref-find-references :after #'eglot--xref-reset-known-symbols) +(defvar eglot--temp-location-buffers (make-hash-table :test #'equal) + "Helper variable for `eglot--handling-xrefs'.") + +(defmacro eglot--handling-xrefs (&rest body) + "Properly sort and handle xrefs produced and returned by BODY." + `(unwind-protect + (sort (progn ,@body) + (lambda (a b) + (< (xref-location-line (xref-item-location a)) + (xref-location-line (xref-item-location b) + (maphash (lambda (_uri buf) (kill-buffer buf)) eglot--temp-location-buffers) + (clrhash eglot--temp-location-buffers))) + (defun eglot--xref-make (name uri range) "Like `xref-make' but with LSP's NAME, URI and RANGE. Try to visit the target file for a richer summary line." (pcase-let* - ((`(,beg . ,end) (eglot--range-region range)) - (file (eglot--uri-to-path uri)) - (visiting (find-buffer-visiting file)) + ((file (eglot--uri-to-path uri)) + (visiting (or (find-buffer-visiting file) + (gethash uri eglot--temp-location-buffers))) (collect (lambda () (eglot--widening (pcase-let* ((`(,beg . ,end) (eglot--range-region range)) @@ -1497,19 +1510,16 @@ Try to visit the target file for a richer summary line." (`(,summary ,line ,column) (cond (visiting (with-current-buffer visiting (funcall collect))) - ((file-readable-p file) (with-temp-buffer (insert-file-contents file) - (funcall collect))) + ((file-readable-p file) (with-current-buffer + (puthash uri (generate-new-buffer " *temp*") + eglot--temp-location-buffers) + (insert-file-contents file) + (funcall collect))) (t ;; fall back to the "dumb strategy" (let ((start (cl-getf range :start))) (list name (1+ (cl-getf start :line)) (cl-getf start :character))) (xref-make summary (xref-make-file-location file line column -(defun eglot--sort-xrefs (xrefs) - (sort xrefs -(lambda (a b) - (< (xref-location-line (xref-item-location a)) - (xref-location-line (xref-item-location b)) - (cl-defmethod xref-backend-identifier-completion-table ((_backend (eql eglot))) (when (eglot--server-capable :documentSymbolProvider) (let ((server (eglot--current-server-or-lose)) @@ -1553,7 +1563,7 @@ Try to visit the target file for a richer summary line." (locations (and definitions (if (vectorp definitions) definitions (vector definitions) -(eglot--sort-xrefs +(eglot--handling-xrefs (mapcar (jsonrpc-lambda (&key uri range) (eglot--xref-make identifier uri range)) locations @@ -1567,7 +1577,7 @@ Try to visit the target file for a richer summary line." (and rich (get-text-property 0 :textDocumentPositionParams rich)) (unless params (eglot--error "Don' know where %s is in the workspace!" identifier)) -(eglot--sort-xrefs +(eglot--handling-xrefs (mapcar (jsonrpc-lambda (&key uri range) (eglot--xref-make identifier uri range)) @@ -1580,7 +1590,7 @@ Try to visit the target file for a richer summary line." (cl-defmethod xref-backend-apropos ((_backend (eql eglot)) pattern) (when (eglot--server-capable :workspaceSymbolProvider) -(eglot--sort-xrefs +(eglot--handling-xrefs (mapcar (jsonrpc-lambda (&key name location &allow-other-keys) (cl-destructuring-bind (&key uri range) location
[elpa] externals/eglot e2200ce 09/26: Simplify interface of eglot--dbind macro
branch: externals/eglot commit e2200ce0735155d7f26d09b49569dd5501086826 Author: João Távora Commit: João Távora Simplify interface of eglot--dbind macro * eglot.el (eglot--dbind): Use new interface. (eglot--lambda): Use new eglot--dbind interface. (eglot--lsp-interface-alist): Fix docstring. (eglot--call-with-interface): Simplify. (eglot--plist-keys): New helper. * eglot-tests.el (eglot-strict-interfaces): Add a new test clause. --- eglot-tests.el | 22 + eglot.el | 98 -- 2 files changed, 63 insertions(+), 57 deletions(-) diff --git a/eglot-tests.el b/eglot-tests.el index 5d69dcf..8b91317 100644 --- a/eglot-tests.el +++ b/eglot-tests.el @@ -608,32 +608,42 @@ Pass TIMEOUT to `eglot--with-timeout'." (ert-deftest eglot-strict-interfaces () (let ((eglot--lsp-interface-alist `((FooObject . ((:foo :bar) (:baz)) +(should + (equal '("foo" . "bar") +(let ((eglot-strict-mode nil)) + (eglot--dbind (foo bar) `(:foo "foo" :bar "bar") +(cons foo bar) (should-error (let ((eglot-strict-mode '(disallow-non-standard-keys))) - (eglot--dbind nil (&key foo bar) `(:foo "foo" :bar "bar" :fotrix bargh) + (eglot--dbind (foo bar) `(:foo "foo" :bar "bar" :fotrix bargh) (cons foo bar (should (equal '("foo" . "bar") (let ((eglot-strict-mode nil)) - (eglot--dbind nil (&key foo bar) `(:foo "foo" :bar "bar" :fotrix bargh) + (eglot--dbind (foo bar) `(:foo "foo" :bar "bar" :fotrix bargh) (cons foo bar) (should-error (let ((eglot-strict-mode '(disallow-non-standard-keys))) - (eglot--dbind FooObject (&key foo bar) `(:foo "foo" :bar "bar" :fotrix bargh) + (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :bar "bar" :fotrix bargh) (cons foo bar (should (equal '("foo" . "bar") (let ((eglot-strict-mode '(disallow-non-standard-keys))) - (eglot--dbind FooObject (&key foo bar) `(:foo "foo" :bar "bar" :baz bargh) + (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :bar "bar" :baz bargh) +(cons foo bar) +(should + (equal '("foo" . nil) +(let ((eglot-strict-mode nil)) + (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :baz bargh) (cons foo bar) (should (equal '("foo" . "bar") (let ((eglot-strict-mode '(enforce-required-keys))) - (eglot--dbind FooObject (&key foo bar) `(:foo "foo" :bar "bar" :baz bargh) + (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :bar "bar" :baz bargh) (cons foo bar) (should-error (let ((eglot-strict-mode '(enforce-required-keys))) - (eglot--dbind FooObject (&key foo bar) `(:foo "foo" :baz bargh) + (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :baz bargh) (cons foo bar)) (provide 'eglot-tests) diff --git a/eglot.el b/eglot.el index 2519189..594a638 100644 --- a/eglot.el +++ b/eglot.el @@ -204,8 +204,8 @@ let the buffer grow forever." (defvar eglot--lsp-interface-alist `() "Alist (INTERFACE-NAME . INTERFACE) of known external LSP interfaces. -INTERFACE-NAME is a symbol designated by the spec as \"export -interface\". INTERFACE is a list (REQUIRED OPTIONAL) where +INTERFACE-NAME is a symbol designated by the spec as +\"interface\". INTERFACE is a list (REQUIRED OPTIONAL) where REQUIRED and OPTIONAL are lists of keyword symbols designating field names that must be, or may be, respectively, present in a message adhering to that interface. @@ -230,60 +230,56 @@ If the list is empty, any non-standard fields sent by the server and missing required fields are accepted (which may or may not cause problems in Eglot's functioning later on).") +(defun eglot--plist-keys (plist) + (cl-loop for (k _v) on plist by #'cddr collect k)) + (defun eglot--call-with-interface (interface object fn) - "Call FN, but first check that OBJECT conforms to INTERFACE. - -INTERFACE is a key to `eglot--lsp-interface-alist' and OBJECT is - a plist representing an LSP message." - (let* ((entry (assoc interface eglot--lsp-interface-alist)) - (required (car (cdr entry))) - (optional (cadr (cdr entry -(when (memq 'enforce-required-keys eglot-strict-mode) - (cl-loop for req in required - when (eq 'eglot--not-present -(cl-getf object req 'eglot--not-present)) - collect req into missing - finally (when missing - (eglot--error - "A `%s' must have %s" interface missing -(when (and entry (memq 'disallow-non-standard-keys eglot-strict-mode)) - (cl-loop - with allowed = (append required optional) - for (key _val) on
[elpa] externals/eglot 444a8c3 16/26: Per #173: robustify previous fix against non-standard insertion bindings
branch: externals/eglot commit 444a8c3b3ec29eceeda26b72493a60c44a9bd951 Author: João Távora Commit: João Távora Per #173: robustify previous fix against non-standard insertion bindings * eglot.el (eglot--managed-mode): Manage post-self-insert-hook. (eglot--last-inserted-char): New variable. (eglot--post-self-insert-hook): Set it. (eglot--before-change): Reset it. (eglot--CompletionParams): Use it. --- eglot.el | 27 +++ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/eglot.el b/eglot.el index 86db5ea..e4547c5 100644 --- a/eglot.el +++ b/eglot.el @@ -1052,6 +1052,7 @@ and just return it. PROMPT shouldn't end with a question mark." (add-hook 'xref-backend-functions 'eglot-xref-backend nil t) (add-hook 'completion-at-point-functions #'eglot-completion-at-point nil t) (add-hook 'change-major-mode-hook 'eglot--managed-mode-onoff nil t) +(add-hook 'post-self-insert-hook 'eglot--post-self-insert-hook nil t) (add-function :before-until (local 'eldoc-documentation-function) #'eglot-eldoc-function) (add-function :around (local 'imenu-create-index-function) #'eglot-imenu) @@ -1068,6 +1069,7 @@ and just return it. PROMPT shouldn't end with a question mark." (remove-hook 'xref-backend-functions 'eglot-xref-backend t) (remove-hook 'completion-at-point-functions #'eglot-completion-at-point t) (remove-hook 'change-major-mode-hook #'eglot--managed-mode-onoff t) +(remove-hook 'post-self-insert-hook 'eglot--post-self-insert-hook t) (remove-function (local 'eldoc-documentation-function) #'eglot-eldoc-function) (remove-function (local 'imenu-create-index-function) #'eglot-imenu) @@ -1383,12 +1385,18 @@ THINGS are either registrations or unregisterations." (list :textDocument (eglot--TextDocumentIdentifier) :position (eglot--pos-to-lsp-position))) +(defvar-local eglot--last-inserted-char nil + "If non-nil, value of the last inserted character in buffer.") + +(defun eglot--post-self-insert-hook () + "Set `eglot--last-inserted-char.'" + (setq eglot--last-inserted-char last-input-event)) + (defun eglot--CompletionParams () (append (eglot--TextDocumentPositionParams) `(:context - ,(if-let (trigger (and (eq last-command 'self-insert-command) -(characterp last-input-event) + ,(if-let (trigger (and (characterp eglot--last-inserted-char) (cl-find last-input-event (eglot--server-capable :completionProvider :triggerCharacters) @@ -1406,15 +1414,18 @@ THINGS are either registrations or unregisterations." (defvar-local eglot--change-idle-timer nil "Idle timer for didChange signals.") (defun eglot--before-change (start end) - "Hook onto `before-change-functions'. -Records START and END, crucially convert them into -LSP (line/char) positions before that information is -lost (because the after-change thingy doesn't know if newlines -were deleted/added)" + "Hook onto `before-change-functions'." + ;; Records START and END, crucially convert them into LSP + ;; (line/char) positions before that information is lost (because + ;; the after-change thingy doesn't know if newlines were + ;; deleted/added) (when (listp eglot--recent-changes) (push `(,(eglot--pos-to-lsp-position start) ,(eglot--pos-to-lsp-position end)) - eglot--recent-changes))) + eglot--recent-changes)) + ;; Also, reset `eglot--last-inserted-char' which might be set later + ;; by `eglot--post-self-insert-hook'. + (setq eglot--last-inserted-char nil)) (defun eglot--after-change (start end pre-change-length) "Hook onto `after-change-functions'.
[elpa] externals/eglot cddab30 06/26: * eglot.el (eglot--current-column): New helper.
branch: externals/eglot commit cddab30728e91a9c3b201087467662a567e95f6f Author: MichaÅ Krzywkowski Commit: MichaÅ Krzywkowski * eglot.el (eglot--current-column): New helper. (eglot-current-column-function): Set to eglot--current-column. (eglot--pos-to-lsp-position): Don't bind tab-width anymore. (eglot--xref-make): Use eglot--current-column. --- eglot.el | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eglot.el b/eglot.el index 1522935..94de8d1 100644 --- a/eglot.el +++ b/eglot.el @@ -811,7 +811,9 @@ CONNECT-ARGS are passed as additional arguments to (let ((warning-minimum-level :error)) (display-warning 'eglot (apply #'format format args) :warning))) -(defvar eglot-current-column-function #'current-column +(defun eglot--current-column () (- (point) (point-at-bol))) + +(defvar eglot-current-column-function #'eglot--current-column "Function to calculate the current column. This is the inverse operation of @@ -833,8 +835,7 @@ for all others.") (eglot--widening (list :line (1- (line-number-at-pos pos t)) ; F!@$CKING OFF-BY-ONE :character (progn (when pos (goto-char pos)) - (let ((tab-width 1)) - (funcall eglot-current-column-function)) + (funcall eglot-current-column-function) (defvar eglot-move-to-column-function #'move-to-column "Function to move to a column reported by the LSP server. @@ -1502,11 +1503,10 @@ Try to visit the target file for a richer summary line." (eglot--widening (pcase-let* ((`(,beg . ,end) (eglot--range-region range)) (bol (progn (goto-char beg) (point-at-bol))) -(substring (buffer-substring bol (point-at-eol))) -(tab-width 1)) +(substring (buffer-substring bol (point-at-eol (add-face-text-property (- beg bol) (- end bol) 'highlight t substring) - (list substring (1+ (current-line)) (current-column)) + (list substring (1+ (current-line)) (eglot--current-column)) (`(,summary ,line ,column) (cond (visiting (with-current-buffer visiting (funcall collect)))
[elpa] externals/eglot 3922cf3 01/26: Per #144, #156: control strictness towards incoming LSP messages
branch: externals/eglot commit 3922cf323ca700046ed0507fa4d534e3d5413297 Author: João Távora Commit: João Távora Per #144, #156: control strictness towards incoming LSP messages A new variable, eglot-strict-mode controls whether Eglot is strict or lax with regard to incoming LSP messages. 1. Bug reports should be tested with eglot-strict-mode set to '(disallow-non-standard-keys enforce-required-keys) 2. Users struggling to get non-standard servers working set this variable to '(), nil. For now, by popular demand, this is the default value. Note that this commit in particular introduces a new infrastructure, but does not yet alter any code in Eglot to use it. Neither is the variable eglot--lsp-interface-alist populated. * eglot-tests.el (eglot-strict-interfaces): New test. * eglot.el (eglot--lsp-interface-alist): New variable. (eglot-strict-mode): New variable. (eglot--call-with-interface): New helper. (eglot--dbind): New macro. (eglot--lambda): New macro. --- eglot-tests.el | 36 eglot.el | 88 ++ 2 files changed, 124 insertions(+) diff --git a/eglot-tests.el b/eglot-tests.el index 6cea929..5d69dcf 100644 --- a/eglot-tests.el +++ b/eglot-tests.el @@ -578,6 +578,10 @@ Pass TIMEOUT to `eglot--with-timeout'." `((python-mode . ("sh" "-c" "sleep 2 && pyls") (should-error (apply #'eglot--connect (eglot--guess-contact))) + + +;;; Unit tests +;;; (ert-deftest eglot-capabilities () "Unit test for `eglot--server-capable'." (cl-letf (((symbol-function 'eglot--capabilities) @@ -600,6 +604,38 @@ Pass TIMEOUT to `eglot--with-timeout'." (should-not (eglot--server-capable :foobarbaz)) (should-not (eglot--server-capable :textDocumentSync :foobarbaz + +(ert-deftest eglot-strict-interfaces () + (let ((eglot--lsp-interface-alist + `((FooObject . ((:foo :bar) (:baz)) +(should-error + (let ((eglot-strict-mode '(disallow-non-standard-keys))) + (eglot--dbind nil (&key foo bar) `(:foo "foo" :bar "bar" :fotrix bargh) + (cons foo bar +(should + (equal '("foo" . "bar") +(let ((eglot-strict-mode nil)) + (eglot--dbind nil (&key foo bar) `(:foo "foo" :bar "bar" :fotrix bargh) +(cons foo bar) +(should-error + (let ((eglot-strict-mode '(disallow-non-standard-keys))) + (eglot--dbind FooObject (&key foo bar) `(:foo "foo" :bar "bar" :fotrix bargh) + (cons foo bar +(should + (equal '("foo" . "bar") +(let ((eglot-strict-mode '(disallow-non-standard-keys))) + (eglot--dbind FooObject (&key foo bar) `(:foo "foo" :bar "bar" :baz bargh) +(cons foo bar) +(should + (equal '("foo" . "bar") +(let ((eglot-strict-mode '(enforce-required-keys))) + (eglot--dbind FooObject (&key foo bar) `(:foo "foo" :bar "bar" :baz bargh) +(cons foo bar) +(should-error + (let ((eglot-strict-mode '(enforce-required-keys))) + (eglot--dbind FooObject (&key foo bar) `(:foo "foo" :baz bargh) + (cons foo bar)) + (provide 'eglot-tests) ;;; eglot-tests.el ends here diff --git a/eglot.el b/eglot.el index 365b5d2..4996f5b 100644 --- a/eglot.el +++ b/eglot.el @@ -197,6 +197,94 @@ let the buffer grow forever." (13 . "Enum") (14 . "Keyword") (15 . "Snippet") (16 . "Color") (17 . "File") (18 . "Reference"))) + + +;;; Message verification helpers +;;; +(defvar eglot--lsp-interface-alist `() + "Alist (INTERFACE-NAME . INTERFACE) of known external LSP interfaces. + +INTERFACE-NAME is a symbol designated by the spec as \"export +interface\". INTERFACE is a list (REQUIRED OPTIONAL) where +REQUIRED and OPTIONAL are lists of keyword symbols designating +field names that must be, or may be, respectively, present in a +message adhering to that interface. + +Here's what an element of this alist might look like: + +(CreateFile . ((:kind :uri) (:options)))") + +(defvar eglot-strict-mode '() + "How strictly Eglot vetoes LSP messages from server. + +Value is a list of symbols: + +If a list containing the symbol `disallow-non-standard-keys', an +error is raised if any non-standard fields are sent by the +server. + +If the list containing the symbol `enforce-required-keys', an error +is raised if any required fields are missing from the message. + +If the list is empty, any non-standard fields sent by the server +and missing required fields are accepted (which may or may not +cause problems in Eglot's functioning later on).") + +(defun eglot--call-with-interface (interface object fn) + "Call FN, but first check that OBJECT conforms to INTERFACE. + +INTERFACE is a key to `eglot--lsp-interface-alist' and OBJECT is + a plist representing an LSP message." + (let* ((entry (a
[elpa] externals/eglot updated (f291816 -> 23accee)
capitaomorte pushed a change to branch externals/eglot. from f291816 * eglot.el (Version): Bump to 1.2 new 3922cf3 Per #144, #156: control strictness towards incoming LSP messages new 11eb256 Fix #164: CodeAction command can be a Command object (#165) new 10b238b Revert "Fix #164: CodeAction command can be a Command object (#165)" new 81d035f Fix #52: Use entire line as xref summary when available new 9fb5f0c Per #52, #127: Improve performance of xref summary line collection new cddab30 * eglot.el (eglot--current-column): New helper. new 8140be5 Touch up last commit new 95ef9e1 Robustify tests against (M)ELPA eglot installations new e2200ce Simplify interface of eglot--dbind macro new 6de3d9c Per #171,#156: Introduce eglot--dcase new 5bbf884 Use eglot--dbind for destructuring new a1f2033 Fix #116, #150: don't break in indirect buffers new 1d42be4 Close #173: support completionContext to help servers like ccls new 4874c22 Use javascript-typescript-langserver for typescript-mode (#174) new 38da3d3 Fix #159: Properly clear old diagnostics when making new ones new 444a8c3 Per #173: robustify previous fix against non-standard insertion bindings new a46f003 Fix #164: handle CodeAction/Command polymorphism with eglot--dcase new 96169d8 Per #173: fix bug introduced by previous fix new 53bfdb7 Per #173: adjust previous fix new f63bedb Fix #144: Use eglot--dbind and eglot--lambda throughout new 37706af Warn about suspicious interface usage at compile-time new 66a1704 Scratch/use elpa flymake (#178) new c1848c3 Handle array params to server notification or requests new 6b0b1b7 Be lenient by default to unknown methods or notifications new 973cd81 Close #180: Add preamble to comparison to lsp-mode.el new 23accee * eglot.el (Version): Bump to 1.3 Summary of changes: Makefile | 16 +- README.md | 23 +-- eglot-tests.el | 75 eglot.el | 575 + 4 files changed, 512 insertions(+), 177 deletions(-)
[elpa] externals/eglot 95ef9e1 08/26: Robustify tests against (M)ELPA eglot installations
branch: externals/eglot commit 95ef9e1197a12002fd83a9c3a4c3f1a7039435df Author: João Távora Commit: João Távora Robustify tests against (M)ELPA eglot installations * Makefile (eglot-check, %.elc): Setup load-path after package-initialize. --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index fcff632..637deb7 100644 --- a/Makefile +++ b/Makefile @@ -19,15 +19,16 @@ all: compile # Compilation # %.elc: %.el - $(EMACS) -Q $(LOAD_PATH) $(JSONRPC) --batch -f batch-byte-compile $< + $(EMACS) -Q $(JSONRPC) $(LOAD_PATH) --batch -f batch-byte-compile $< compile: $(ELCFILES) # Automated tests # eglot-check: compile - $(EMACS) -Q --batch $(LOAD_PATH)\ + $(EMACS) -Q --batch \ $(JSONRPC) \ + $(LOAD_PATH)\ -l eglot\ -l eglot-tests \ --eval '(setq ert-batch-backtrace-right-margin 200)'\
[elpa] externals/eglot 38da3d3 15/26: Fix #159: Properly clear old diagnostics when making new ones
branch: externals/eglot commit 38da3d3b31ee19a5cea03951f5c535750858aaac Author: MichaÅ Krzywkowski Commit: MichaÅ Krzywkowski Fix #159: Properly clear old diagnostics when making new ones * eglot.el (eglot-handle-notification textDocument/publishDiagnostics): Call flymake report function with :region. --- eglot.el | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/eglot.el b/eglot.el index 2e99fc0..86db5ea 100644 --- a/eglot.el +++ b/eglot.el @@ -1313,7 +1313,13 @@ COMMAND is a symbol naming the command." message `((eglot-lsp-diag . ,diag-spec) into diags finally (cond ((and flymake-mode eglot--current-flymake-report-fn) -(funcall eglot--current-flymake-report-fn diags) +(funcall eglot--current-flymake-report-fn diags + ;; If the buffer hasn't changed since last + ;; call to the report function, flymake won't + ;; delete old diagnostics. Using :region + ;; keyword forces flymake to delete + ;; them (github#159). + :region (cons (point-min) (point-max))) (setq eglot--unreported-diagnostics nil)) (t (setq eglot--unreported-diagnostics (cons t diags))
[elpa] externals/eglot 5bbf884 11/26: Use eglot--dbind for destructuring
branch: externals/eglot commit 5bbf88459b78205ece715af3b074cc046294e478 Author: MichaŠKrzywkowski Commit: João Távora Use eglot--dbind for destructuring * eglot.el (eglot--lsp-interface-alist): Add CodeAction, FileSystemWatcher, Registration, TextDocumentEdit, WorkspaceEdit. (eglot-handle-notification): Use eglot--dbind. (eglot--apply-workspace-edit): Use eglot--dbind and eglot--lambda. (eglot-code-actions): Use eglot--lambda. (eglot--register-workspace/didChangeWatchedFiles): Use eglot--lambda. --- eglot.el | 22 +++--- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/eglot.el b/eglot.el index 61f9b70..8d39770 100644 --- a/eglot.el +++ b/eglot.el @@ -201,7 +201,14 @@ let the buffer grow forever." ;;; Message verification helpers ;;; -(defvar eglot--lsp-interface-alist `() +(defvar eglot--lsp-interface-alist + `( +(CodeAction (:title) (:kind :diagnostics :edit :command)) +(FileSystemWatcher (:globPattern) (:kind)) +(Registration (:id :method) (:registerOptions)) +(TextDocumentEdit (:textDocument :edits) ()) +(WorkspaceEdit () (:changes :documentChanges)) +) "Alist (INTERFACE-NAME . INTERFACE) of known external LSP interfaces. INTERFACE-NAME is a symbol designated by the spec as @@ -1314,7 +1321,7 @@ COMMAND is a symbol naming the command." THINGS are either registrations or unregisterations." (cl-loop for thing in (cl-coerce things 'list) - collect (cl-destructuring-bind (&key id method registerOptions) thing + collect (eglot--dbind ((Registration) id method registerOptions) thing (apply (intern (format "eglot--%s-%s" how method)) server :id id registerOptions)) into results @@ -1990,9 +1997,9 @@ If SKIP-SIGNATURE, don't try to send textDocument/signatureHelp." (defun eglot--apply-workspace-edit (wedit &optional confirm) "Apply the workspace edit WEDIT. If CONFIRM, ask user first." - (cl-destructuring-bind (&key changes documentChanges) wedit + (eglot--dbind ((WorkspaceEdit) changes documentChanges) wedit (let ((prepared - (mapcar (jsonrpc-lambda (&key textDocument edits) + (mapcar (eglot--lambda ((TextDocumentEdit) textDocument edits) (cl-destructuring-bind (&key uri version) textDocument (list (eglot--uri-to-path uri) edits version))) documentChanges)) @@ -2057,8 +2064,7 @@ If SKIP-SIGNATURE, don't try to send textDocument/signatureHelp." (eglot--diag-data diag (flymake-diagnostics beg end))] (menu-items - (or (mapcar (jsonrpc-lambda (&key title command arguments -edit _kind _diagnostics) + (or (mapcar (eglot--lambda ((CodeAction) title edit command arguments) `(,title . (:command ,command :arguments ,arguments :edit ,edit))) actions) @@ -2098,7 +2104,9 @@ If SKIP-SIGNATURE, don't try to send textDocument/signatureHelp." "Handle dynamic registration of workspace/didChangeWatchedFiles" (eglot--unregister-workspace/didChangeWatchedFiles server :id id) (let* (success - (globs (mapcar (lambda (w) (plist-get w :globPattern)) watchers))) + (globs (mapcar (eglot--lambda ((FileSystemWatcher) globPattern) + globPattern) +watchers))) (cl-labels ((handle-event (event)
[elpa] externals/eglot 973cd81 25/26: Close #180: Add preamble to comparison to lsp-mode.el
branch: externals/eglot commit 973cd8130b92b0c50c50763469be135fc5724cd4 Author: João Távora Commit: João Távora Close #180: Add preamble to comparison to lsp-mode.el * README.md (Differences to lsp-mode.el): Add preamble. --- README.md | 23 --- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ad6730c..cefccad 100644 --- a/README.md +++ b/README.md @@ -237,17 +237,18 @@ eglot-shutdown`. # Differences to lsp-mode.el -Eglot and [lsp-mode.el][emacs-lsp] share a common goal, which is to -bring LSP to Emacs. lsp-mode.el is a more mature extension with a -host of [plugins][emacs-lsp-plugins] for bells and whistles. Eglot -may still lag it in some aspects, but the gap is closing as more -features make it into Eglot and more servers are supported -out-of-the-box. - -Conversely, you may find Eglot surpasses lsp-mode.el in other aspects, -namely simplicity. Eglot is considerably less code and hassle than -lsp-mode.el. In most cases, there's nothing to configure. It's a -minimalist approach focused on user experience and performance. +Around May 2018, I wrote a comparison of Eglot to `lsp-mode.el`, and +was discussed with its then-maintainer. That mode has since been +refactored/rewritten and now +[purports to support](https://github.com/joaotavora/eglot/issues/180) +a lot of features that differentiated Eglot from it. It may now be +very different or very similar to Eglot, or even sing with the birds +in the trees, so [go check it out](emacs-lsp). That said, here's the +original comparison, which I will not be updating any more. + +Eglot is considerably less code and hassle than lsp-mode.el. In most +cases, there's nothing to configure. It's a minimalist approach +focused on user experience and performance. User-visible differences:
[elpa] externals/eglot 4874c22 14/26: Use javascript-typescript-langserver for typescript-mode (#174)
branch: externals/eglot commit 4874c22767ef9b8fb4f168a159c86b71193d865c Author: Mario Rodas Commit: João Távora Use javascript-typescript-langserver for typescript-mode (#174) Copyright-paperwork-exempt: Yes * eglot.el (eglot-server-programs): add typescript-mode to javascript-typescript-langserver's contact --- eglot.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/eglot.el b/eglot.el index ac10b43..2e99fc0 100644 --- a/eglot.el +++ b/eglot.el @@ -82,7 +82,9 @@ (python-mode . ("pyls")) ((js-mode js2-mode - rjsx-mode) . ("javascript-typescript-stdio")) + rjsx-mode + typescript-mode) + . ("javascript-typescript-stdio")) (sh-mode . ("bash-language-server" "start")) ((c++-mode c-mode) . ("ccls")) ((caml-mode tuareg-mode reason-mode)
[elpa] externals/eglot 23accee 26/26: * eglot.el (Version): Bump to 1.3
branch: externals/eglot commit 23accee6dbf2eb7580fbb10f7ca09c13ba5700e8 Author: João Távora Commit: João Távora * eglot.el (Version): Bump to 1.3 --- eglot.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eglot.el b/eglot.el index f442b2f..db4fbb4 100644 --- a/eglot.el +++ b/eglot.el @@ -2,7 +2,7 @@ ;; Copyright (C) 2018 Free Software Foundation, Inc. -;; Version: 1.2 +;; Version: 1.3 ;; Author: João Távora ;; Maintainer: João Távora ;; URL: https://github.com/joaotavora/eglot
[elpa] externals/eglot a1f2033 12/26: Fix #116, #150: don't break in indirect buffers
branch: externals/eglot commit a1f20331f3ecd9c8c2e92482103f17eb30adab01 Author: João Távora Commit: João Távora Fix #116, #150: don't break in indirect buffers Indirect buffers, such as the ones created by ediff-regions-wordwise, have eglot enabled but not buffer-file-name. Resort to the finding the file-name of the original buffer for these. * eglot.el (eglot--TextDocumentIdentifier): Work in indirect buffers. --- eglot.el | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/eglot.el b/eglot.el index 8d39770..b240e0e 100644 --- a/eglot.el +++ b/eglot.el @@ -1345,7 +1345,10 @@ THINGS are either registrations or unregisterations." (defun eglot--TextDocumentIdentifier () "Compute TextDocumentIdentifier object for current buffer." - `(:uri ,(eglot--path-to-uri buffer-file-name))) + `(:uri ,(eglot--path-to-uri (or buffer-file-name + (ignore-errors +(buffer-file-name + (buffer-base-buffer))) (defvar-local eglot--versioned-identifier 0)
[elpa] externals/eglot 10b238b 03/26: Revert "Fix #164: CodeAction command can be a Command object (#165)"
branch: externals/eglot commit 10b238b20202cf919402f162137166924187cd7f Author: João Távora Commit: João Távora Revert "Fix #164: CodeAction command can be a Command object (#165)" This reverts commit 11eb25678b2f32a3496bd7efb95b90941c9ae5ea. The spec doesn't define Command as implemented in the commit. --- eglot.el | 7 +-- 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/eglot.el b/eglot.el index bc89cd2..4996f5b 100644 --- a/eglot.el +++ b/eglot.el @@ -2011,12 +2011,7 @@ If SKIP-SIGNATURE, don't try to send textDocument/signatureHelp." (when edit (eglot--apply-workspace-edit edit)) (when command -(cond ((stringp command) - (eglot-execute-command server (intern command) arguments)) - ((listp command) - (eglot-execute-command server - (intern (plist-get command :command)) - (plist-get command :arguments +(eglot-execute-command server (intern command) arguments)
[elpa] externals/eglot 11eb256 02/26: Fix #164: CodeAction command can be a Command object (#165)
branch: externals/eglot commit 11eb25678b2f32a3496bd7efb95b90941c9ae5ea Author: mkcms Commit: João Távora Fix #164: CodeAction command can be a Command object (#165) * eglot.el (eglot-code-actions): Handle case when the :command field is not a string. --- eglot.el | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/eglot.el b/eglot.el index 4996f5b..bc89cd2 100644 --- a/eglot.el +++ b/eglot.el @@ -2011,7 +2011,12 @@ If SKIP-SIGNATURE, don't try to send textDocument/signatureHelp." (when edit (eglot--apply-workspace-edit edit)) (when command -(eglot-execute-command server (intern command) arguments) +(cond ((stringp command) + (eglot-execute-command server (intern command) arguments)) + ((listp command) + (eglot-execute-command server + (intern (plist-get command :command)) + (plist-get command :arguments
[elpa] externals/eglot 1d42be4 13/26: Close #173: support completionContext to help servers like ccls
branch: externals/eglot commit 1d42be42f46119164743c56dba95f715893c6a98 Author: João Távora Commit: João Távora Close #173: support completionContext to help servers like ccls * eglot.el (eglot-client-capabilities): Annouce textDocument/completion/contextSupport. (eglot--CompletionParams): New helper. (eglot-completion-at-point): Use it. --- eglot.el | 18 -- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/eglot.el b/eglot.el index b240e0e..ac10b43 100644 --- a/eglot.el +++ b/eglot.el @@ -374,7 +374,8 @@ treated as in `eglot-dbind'." `(:snippetSupport ,(if (eglot--snippet-expansion-fn) t - :json-false))) + :json-false)) +:contextSupport t) :hover `(:dynamicRegistration :json-false) :signatureHelp `(:dynamicRegistration :json-false) :references `(:dynamicRegistration :json-false) @@ -1374,6 +1375,19 @@ THINGS are either registrations or unregisterations." (list :textDocument (eglot--TextDocumentIdentifier) :position (eglot--pos-to-lsp-position))) +(defun eglot--CompletionParams () + (append + (eglot--TextDocumentPositionParams) + `(:context + ,(if-let (trigger (and (eq last-command 'self-insert-command) +(characterp last-input-event) +(cl-find last-input-event + (eglot--server-capable :completionProvider +:triggerCharacters) + :key (lambda (str) (aref str 0)) + :test #'char-equal))) + `(:triggerKind 2 :triggerCharacter ,trigger) `(:triggerKind 1) + (defvar-local eglot--recent-changes nil "Recent buffer changes as collected by `eglot--before-change'.") @@ -1693,7 +1707,7 @@ is not active." (lambda (_ignored) (let* ((resp (jsonrpc-request server :textDocument/completion -(eglot--TextDocumentPositionParams) +(eglot--CompletionParams) :deferred :textDocument/completion :cancel-on-input t)) (items (if (vectorp resp) resp (plist-get resp :items
[elpa] tag 1.3 created (now 23accee)
capitaomorte pushed a change to tag 1.3. at 23accee (commit) This tag includes the following new commits: new 3922cf3 Per #144, #156: control strictness towards incoming LSP messages new 11eb256 Fix #164: CodeAction command can be a Command object (#165) new 10b238b Revert "Fix #164: CodeAction command can be a Command object (#165)" new 81d035f Fix #52: Use entire line as xref summary when available new 9fb5f0c Per #52, #127: Improve performance of xref summary line collection new cddab30 * eglot.el (eglot--current-column): New helper. new 8140be5 Touch up last commit new 95ef9e1 Robustify tests against (M)ELPA eglot installations new e2200ce Simplify interface of eglot--dbind macro new 6de3d9c Per #171,#156: Introduce eglot--dcase new 5bbf884 Use eglot--dbind for destructuring new a1f2033 Fix #116, #150: don't break in indirect buffers new 1d42be4 Close #173: support completionContext to help servers like ccls new 4874c22 Use javascript-typescript-langserver for typescript-mode (#174) new 38da3d3 Fix #159: Properly clear old diagnostics when making new ones new 444a8c3 Per #173: robustify previous fix against non-standard insertion bindings new a46f003 Fix #164: handle CodeAction/Command polymorphism with eglot--dcase new 96169d8 Per #173: fix bug introduced by previous fix new 53bfdb7 Per #173: adjust previous fix new f63bedb Fix #144: Use eglot--dbind and eglot--lambda throughout new 37706af Warn about suspicious interface usage at compile-time new 66a1704 Scratch/use elpa flymake (#178) new c1848c3 Handle array params to server notification or requests new 6b0b1b7 Be lenient by default to unknown methods or notifications new 973cd81 Close #180: Add preamble to comparison to lsp-mode.el new 23accee * eglot.el (Version): Bump to 1.3
[elpa] externals/eglot 37706af 21/26: Warn about suspicious interface usage at compile-time
branch: externals/eglot commit 37706af9b7579bdb7ce75e36008d217252ccf51d Author: João Távora Commit: João Távora Warn about suspicious interface usage at compile-time For fun, set eglot-strict-mode to '(disallow-non-standard-keys enforce-required-keys enforce-optional-keys) when compiling, or just use flymake-mode in eglot.el. * eglot.el (eglot--lsp-interface-alist): Use in compile-time. Order alphabetically. Fix a few bugs. (eglot-strict-mode): Disallow non-standard-keys when compiling. Update docstring. (eglot--keywordize-vars, eglot--check-interface): New compile-time-helpers. (eglot--dbind, eglot--dcase): Use new helpers. --- eglot.el | 189 +-- 1 file changed, 122 insertions(+), 67 deletions(-) diff --git a/eglot.el b/eglot.el index ba61de9..0286f75 100644 --- a/eglot.el +++ b/eglot.el @@ -203,40 +203,41 @@ let the buffer grow forever." ;;; Message verification helpers ;;; -(defvar eglot--lsp-interface-alist - `((CodeAction (:title) (:kind :diagnostics :edit :command)) -(Command (:title :command) (:arguments)) -(FileSystemWatcher (:globPattern) (:kind)) -(Registration (:id :method) (:registerOptions)) -(Hover (:contents) (:range)) -(SymbolInformation - (:name :kind :location) - (:deprecated :containerName)) -(Position (:line :character)) -(Range (:start :end)) -(Location (:uri :range)) -(Diagnostic (:range :message) -(:severity :code :source :relatedInformation)) -(TextEdit (:range :newText)) -(TextDocumentEdit (:textDocument :edits) ()) -(VersionedTextDocumentIdentifier (:uri :version) ()) -(WorkspaceEdit () (:changes :documentChanges)) -(MarkupContent (:kind :value)) -(InitializeResult (:capabilities)) -(ShowMessageParams (:type :message)) -(ShowMessageRequestParams (:type :message) (:actions)) -(LogMessageParams (:type :message)) -(Registration (:id :method) (:registerOptions)) -(CompletionItem - (:label ) - (:kind :detail :documentation :deprecated :preselect :sortText :filterText -:insertText :insertTextFormat :textEdit :additionalTextEdits? -:commitCharacters :command :data)) -(SignatureHelp (:signatures) (:activeSignature :activeParameter)) -(SignatureInformation (:label) (:documentation :parameters)) -(ParameterInformation (:label) (:documentation)) -(DocumentHighlight) (:range) (:kind)) - "Alist (INTERFACE-NAME . INTERFACE) of known external LSP interfaces. +(eval-and-compile + (defvar eglot--lsp-interface-alist +`( + (CodeAction (:title) (:kind :diagnostics :edit :command)) + (Command (:title :command) (:arguments)) + (CompletionItem (:label) + (:kind :detail :documentation :deprecated :preselect + :sortText :filterText :insertText :insertTextFormat + :textEdit :additionalTextEdits :commitCharacters + :command :data)) + (Diagnostic (:range :message) (:severity :code :source :relatedInformation)) + (DocumentHighlight (:range) (:kind)) + (FileSystemWatcher (:globPattern) (:kind)) + (Hover (:contents) (:range)) + (InitializeResult (:capabilities)) + (Location (:uri :range)) + (LogMessageParams (:type :message)) + (MarkupContent (:kind :value)) + (ParameterInformation (:label) (:documentation)) + (Position (:line :character)) + (Range (:start :end)) + (Registration (:id :method) (:registerOptions)) + (Registration (:id :method) (:registerOptions)) + (ResponseError (:code :message) (:data)) + (ShowMessageParams (:type :message)) + (ShowMessageRequestParams (:type :message) (:actions)) + (SignatureHelp (:signatures) (:activeSignature :activeParameter)) + (SignatureInformation (:label) (:documentation :parameters)) + (SymbolInformation (:name :kind :location) (:deprecated :containerName)) + (TextDocumentEdit (:textDocument :edits) ()) + (TextEdit (:range :newText)) + (VersionedTextDocumentIdentifier (:uri :version) ()) + (WorkspaceEdit () (:changes :documentChanges)) + ) +"Alist (INTERFACE-NAME . INTERFACE) of known external LSP interfaces. INTERFACE-NAME is a symbol designated by the spec as \"interface\". INTERFACE is a list (REQUIRED OPTIONAL) where @@ -246,23 +247,38 @@ message adhering to that interface. Here's what an element of this alist might look like: -(CreateFile . ((:kind :uri) (:options)))") +(CreateFile . ((:kind :uri) (:options)))")) -(defvar eglot-strict-mode '() - "How strictly Eglot vetoes LSP messages from server. +(eval-and-compile + (defvar eglot-strict-mode (if load-file-name '() + '(disallow-non-standard-keys +;; Uncomment these two for fun at +
[elpa] externals/eglot c1848c3 23/26: Handle array params to server notification or requests
branch: externals/eglot commit c1848c3052429e52406ce585411b8c79b28e40cc Author: João Távora Commit: João Távora Handle array params to server notification or requests * eglot.el (eglot-handle-notification): Remove extraneous id (eglot--connect): If params is an array, make it a list. --- eglot.el | 8 +++- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/eglot.el b/eglot.el index 4552930..05971e1 100644 --- a/eglot.el +++ b/eglot.el @@ -429,7 +429,7 @@ treated as in `eglot-dbind'." (cl-defgeneric eglot-handle-request (server method &rest params) "Handle SERVER's METHOD request with PARAMS.") -(cl-defgeneric eglot-handle-notification (server method id &rest params) +(cl-defgeneric eglot-handle-notification (server method &rest params) "Handle SERVER's METHOD notification with PARAMS.") (cl-defgeneric eglot-execute-command (server command arguments) @@ -783,10 +783,8 @@ This docstring appeases checkdoc, that's all." :noquery t :stderr (get-buffer-create (format "*%s stderr*" readable-name - (spread - (lambda (fn) -(lambda (&rest args) - (apply fn (append (butlast args) (car (last args))) + (spread (lambda (fn) (lambda (server method params) +(apply fn server method (append params nil) (server (apply #'make-instance class
[elpa] externals/eglot 81d035f 04/26: Fix #52: Use entire line as xref summary when available
branch: externals/eglot commit 81d035fa216de25801ac94f2a7127c86ecfe96ee Author: João Távora Commit: João Távora Fix #52: Use entire line as xref summary when available After an original implementation by Michael Livshin. Also close #127. * eglot.el (eglot--xref-make): Rework. (xref-backend-definitions, xref-backend-references) (xref-backend-apropos): Simplify call to `eglot--xref-make'. --- eglot.el | 38 -- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/eglot.el b/eglot.el index 4996f5b..8ba483b 100644 --- a/eglot.el +++ b/eglot.el @@ -1478,13 +1478,31 @@ DUMMY is ignored." (advice-add 'xref-find-definitions :after #'eglot--xref-reset-known-symbols) (advice-add 'xref-find-references :after #'eglot--xref-reset-known-symbols) -(defun eglot--xref-make (name uri position) - "Like `xref-make' but with LSP's NAME, URI and POSITION." - (cl-destructuring-bind (&key line character) position -(xref-make name (xref-make-file-location - (eglot--uri-to-path uri) - ;; F!@(#*$)CKING OFF-BY-ONE again - (1+ line) character +(defun eglot--xref-make (name uri range) + "Like `xref-make' but with LSP's NAME, URI and RANGE. +Try to visit the target file for a richer summary line." + (pcase-let* + ((`(,beg . ,end) (eglot--range-region range)) + (file (eglot--uri-to-path uri)) + (visiting (find-buffer-visiting file)) + (collect (lambda () + (eglot--widening + (pcase-let* ((`(,beg . ,end) (eglot--range-region range)) +(bol (progn (goto-char beg) (point-at-bol))) +(substring (buffer-substring bol (point-at-eol))) +(tab-width 1)) + (add-face-text-property (- beg bol) (- end bol) 'highlight + t substring) + (list substring (1+ (current-line)) (current-column)) + (`(,summary ,line ,column) +(cond + (visiting (with-current-buffer visiting (funcall collect))) + ((file-readable-p file) (with-temp-buffer (insert-file-contents file) + (funcall collect))) + (t ;; fall back to the "dumb strategy" + (let ((start (cl-getf range :start))) +(list name (1+ (cl-getf start :line)) (cl-getf start :character))) +(xref-make summary (xref-make-file-location file line column (defun eglot--sort-xrefs (xrefs) (sort xrefs @@ -1537,7 +1555,7 @@ DUMMY is ignored." (if (vectorp definitions) definitions (vector definitions) (eglot--sort-xrefs (mapcar (jsonrpc-lambda (&key uri range) - (eglot--xref-make identifier uri (plist-get range :start))) + (eglot--xref-make identifier uri range)) locations (cl-defmethod xref-backend-references ((_backend (eql eglot)) identifier) @@ -1552,7 +1570,7 @@ DUMMY is ignored." (eglot--sort-xrefs (mapcar (jsonrpc-lambda (&key uri range) -(eglot--xref-make identifier uri (plist-get range :start))) +(eglot--xref-make identifier uri range)) (jsonrpc-request (eglot--current-server-or-lose) :textDocument/references (append @@ -1566,7 +1584,7 @@ DUMMY is ignored." (mapcar (jsonrpc-lambda (&key name location &allow-other-keys) (cl-destructuring-bind (&key uri range) location - (eglot--xref-make name uri (plist-get range :start + (eglot--xref-make name uri range))) (jsonrpc-request (eglot--current-server-or-lose) :workspace/symbol `(:query ,pattern))
[elpa] externals/eglot 53bfdb7 19/26: Per #173: adjust previous fix
branch: externals/eglot commit 53bfdb7087b9b4a7c79abc3863c90b6d06ecca1f Author: João Távora Commit: João Távora Per #173: adjust previous fix * eglot.el (eglot--before-change): Don't reset eglot--last-inserted-char here. (eglot--pre-command-hook): Do it here. (eglot--managed-mode): Add/remove eglot--pre-command-hook to/from pre-command-hook. --- eglot.el | 11 +++ 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/eglot.el b/eglot.el index 3bb93dc..727b761 100644 --- a/eglot.el +++ b/eglot.el @@ -1055,6 +1055,7 @@ and just return it. PROMPT shouldn't end with a question mark." (add-hook 'completion-at-point-functions #'eglot-completion-at-point nil t) (add-hook 'change-major-mode-hook 'eglot--managed-mode-onoff nil t) (add-hook 'post-self-insert-hook 'eglot--post-self-insert-hook nil t) +(add-hook 'pre-command-hook 'eglot--pre-command-hook nil t) (add-function :before-until (local 'eldoc-documentation-function) #'eglot-eldoc-function) (add-function :around (local 'imenu-create-index-function) #'eglot-imenu) @@ -1072,6 +1073,7 @@ and just return it. PROMPT shouldn't end with a question mark." (remove-hook 'completion-at-point-functions #'eglot-completion-at-point t) (remove-hook 'change-major-mode-hook #'eglot--managed-mode-onoff t) (remove-hook 'post-self-insert-hook 'eglot--post-self-insert-hook t) +(remove-hook 'pre-command-hook 'eglot--pre-command-hook t) (remove-function (local 'eldoc-documentation-function) #'eglot-eldoc-function) (remove-function (local 'imenu-create-index-function) #'eglot-imenu) @@ -1394,6 +1396,10 @@ THINGS are either registrations or unregisterations." "Set `eglot--last-inserted-char.'" (setq eglot--last-inserted-char last-input-event)) +(defun eglot--pre-command-hook () + "Reset `eglot--last-inserted-char.'" + (setq eglot--last-inserted-char nil)) + (defun eglot--CompletionParams () (append (eglot--TextDocumentPositionParams) @@ -1424,10 +1430,7 @@ THINGS are either registrations or unregisterations." (when (listp eglot--recent-changes) (push `(,(eglot--pos-to-lsp-position start) ,(eglot--pos-to-lsp-position end)) - eglot--recent-changes)) - ;; Also, reset `eglot--last-inserted-char' which might be set later - ;; by `eglot--post-self-insert-hook'. - (setq eglot--last-inserted-char nil)) + eglot--recent-changes))) (defun eglot--after-change (start end pre-change-length) "Hook onto `after-change-functions'.
[elpa] externals/eglot 8140be5 07/26: Touch up last commit
branch: externals/eglot commit 8140be53094dfdd7d590f50413a3c715f6fc4923 Author: MichaÅ Krzywkowski Commit: MichaÅ Krzywkowski Touch up last commit * eglot.el (eglot-current-column): Rename from eglot--current-column. (eglot-current-column-function): Use it as value and mention in docstring. (eglot--xref-make): Use eglot-current-column. --- eglot.el | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/eglot.el b/eglot.el index 94de8d1..2519189 100644 --- a/eglot.el +++ b/eglot.el @@ -811,16 +811,16 @@ CONNECT-ARGS are passed as additional arguments to (let ((warning-minimum-level :error)) (display-warning 'eglot (apply #'format format args) :warning))) -(defun eglot--current-column () (- (point) (point-at-bol))) +(defun eglot-current-column () (- (point) (point-at-bol))) -(defvar eglot-current-column-function #'eglot--current-column +(defvar eglot-current-column-function #'eglot-current-column "Function to calculate the current column. This is the inverse operation of `eglot-move-to-column-function' (which see). It is a function of no arguments returning a column number. For buffers managed by fully LSP-compliant servers, this should be set to -`eglot-lsp-abiding-column', and `current-column' (the default) +`eglot-lsp-abiding-column', and `eglot-current-column' (the default) for all others.") (defun eglot-lsp-abiding-column () @@ -1506,7 +1506,7 @@ Try to visit the target file for a richer summary line." (substring (buffer-substring bol (point-at-eol (add-face-text-property (- beg bol) (- end bol) 'highlight t substring) - (list substring (1+ (current-line)) (eglot--current-column)) + (list substring (1+ (current-line)) (eglot-current-column)) (`(,summary ,line ,column) (cond (visiting (with-current-buffer visiting (funcall collect)))
[elpa] externals/eglot 6b0b1b7 24/26: Be lenient by default to unknown methods or notifications
branch: externals/eglot commit 6b0b1b75948abe1f42f4f676c1379adc4372ec9b Author: João Távora Commit: João Távora Be lenient by default to unknown methods or notifications * eglot.el (eglot-strict-mode): Describe meaning of disallow-non-standard-keys. (eglot-handle-notification, eglot-handle-request): Check eglot-strict-mode. --- eglot.el | 15 +-- 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/eglot.el b/eglot.el index 05971e1..f442b2f 100644 --- a/eglot.el +++ b/eglot.el @@ -260,7 +260,8 @@ Here's what an element of this alist might look like: )) "How strictly to check LSP interfaces at compile- and run-time. -Value is a list of symbols: +Value is a list of symbols (if the list is empty, no checks are +performed). If the symbol `disallow-non-standard-keys' is present, an error is raised if any extraneous fields are sent by the server. At @@ -276,9 +277,9 @@ If the symbol `enforce-optional-keys' is present, nothing special happens at run-time. At compile-time, a warning is raised if a destructuring spec doesn't use all optional fields. -If the list is empty, any non-standard fields sent by the server -and missing required fields are accepted (which may or may not -cause problems in Eglot's functioning later on).")) +If the symbol `disallow-unknown-methods' is present, Eglot warns +on unknown notifications and errors on unknown requests. +")) (defun eglot--plist-keys (plist) (cl-loop for (k _v) on plist by #'cddr collect k)) @@ -1316,13 +1317,15 @@ Uses THING, FACE, DEFS and PREPEND." (cl-defmethod eglot-handle-notification (_server method &key &allow-other-keys) "Handle unknown notification" - (unless (string-prefix-p "$" (format "%s" method)) + (unless (or (string-prefix-p "$" (format "%s" method)) + (not (memq 'disallow-unknown-methods eglot-strict-mode))) (eglot--warn "Server sent unknown notification method `%s'" method))) (cl-defmethod eglot-handle-request (_server method &key &allow-other-keys) "Handle unknown request" - (jsonrpc-error "Unknown request method `%s'" method)) + (when (memq 'disallow-unknown-methods eglot-strict-mode) +(jsonrpc-error "Unknown request method `%s'" method))) (cl-defmethod eglot-execute-command (server command arguments)
[elpa] externals/eglot f63bedb 20/26: Fix #144: Use eglot--dbind and eglot--lambda throughout
branch: externals/eglot commit f63bedb15f9f8c43aefe50604bf2f0f0ce9647fb Author: João Távora Commit: João Távora Fix #144: Use eglot--dbind and eglot--lambda throughout The default behaviour of these macros is to be lenient towards servers sending unknown keys, which should fix the issue. * eglot.el (eglot--lsp-interface-alist): Add a bunch of new interfaces. (eglot--connect, eglot-handle-notification) (xref-backend-identifier-completion-table) (xref-backend-definitions, xref-backend-apropos) (xref-backend-references, eglot-completion-at-point) (eglot--sig-info, eglot-help-at-point, eglot-eldoc-function) (eglot-imenu, eglot--apply-text-edits) (eglot--apply-workspace-edit) (eglot--register-workspace/didChangeWatchedFiles): Use eglot--dbind and eglot--lambda to destructure LSP objects. --- eglot.el | 173 +-- 1 file changed, 101 insertions(+), 72 deletions(-) diff --git a/eglot.el b/eglot.el index 727b761..ba61de9 100644 --- a/eglot.el +++ b/eglot.el @@ -208,8 +208,34 @@ let the buffer grow forever." (Command (:title :command) (:arguments)) (FileSystemWatcher (:globPattern) (:kind)) (Registration (:id :method) (:registerOptions)) +(Hover (:contents) (:range)) +(SymbolInformation + (:name :kind :location) + (:deprecated :containerName)) +(Position (:line :character)) +(Range (:start :end)) +(Location (:uri :range)) +(Diagnostic (:range :message) +(:severity :code :source :relatedInformation)) +(TextEdit (:range :newText)) (TextDocumentEdit (:textDocument :edits) ()) -(WorkspaceEdit () (:changes :documentChanges))) +(VersionedTextDocumentIdentifier (:uri :version) ()) +(WorkspaceEdit () (:changes :documentChanges)) +(MarkupContent (:kind :value)) +(InitializeResult (:capabilities)) +(ShowMessageParams (:type :message)) +(ShowMessageRequestParams (:type :message) (:actions)) +(LogMessageParams (:type :message)) +(Registration (:id :method) (:registerOptions)) +(CompletionItem + (:label ) + (:kind :detail :documentation :deprecated :preselect :sortText :filterText +:insertText :insertTextFormat :textEdit :additionalTextEdits? +:commitCharacters :command :data)) +(SignatureHelp (:signatures) (:activeSignature :activeParameter)) +(SignatureInformation (:label) (:documentation :parameters)) +(ParameterInformation (:label) (:documentation)) +(DocumentHighlight) (:range) (:kind)) "Alist (INTERFACE-NAME . INTERFACE) of known external LSP interfaces. INTERFACE-NAME is a symbol designated by the spec as @@ -741,7 +767,7 @@ This docstring appeases checkdoc, that's all." server) :capabilities (eglot-client-capabilities server)) :success-fn - (jsonrpc-lambda (&key capabilities) + (eglot--lambda ((InitializeResult) capabilities) (unless cancelled (push server (gethash project eglot--servers-by-project)) @@ -769,7 +795,7 @@ in project `%s'." (eglot--project-nickname server)) (when tag (throw tag t :timeout eglot-connect-timeout - :error-fn (jsonrpc-lambda (&key code message _data) + :error-fn (eglot--lambda ((ResponseError) code message) (unless cancelled (jsonrpc-shutdown server) (let ((msg (format "%s: %s" code message))) @@ -1288,13 +1314,12 @@ COMMAND is a symbol naming the command." (with-current-buffer buffer (cl-loop for diag-spec across diagnostics - collect (cl-destructuring-bind (&key range ((:severity sev)) _group - _code source message - &allow-other-keys) + collect (eglot--dbind ((Diagnostic) range message severity source) diag-spec (setq message (concat source ": " message)) (pcase-let - ((`(,beg . ,end) (eglot--range-region range))) + ((sev severity) +(`(,beg . ,end) (eglot--range-region range))) ;; Fallback to `flymake-diag-region' if server ;; botched the range (when (= beg end) @@ -1613,8 +1638,8 @@ Try to visit the target file for a richer summary line." (lambda (string) (setq eglot--xref-known-symbols (mapcar -(jsonrpc-lambda -(&key name kind location containerName _de
[elpa] externals/eglot 96169d8 18/26: Per #173: fix bug introduced by previous fix
branch: externals/eglot commit 96169d8182f5ff79c349287c48a52a16de90f659 Author: João Távora Commit: João Távora Per #173: fix bug introduced by previous fix * eglot.el (eglot--CompletionParams): Don't use last-input-event. --- eglot.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eglot.el b/eglot.el index 578a90d..3bb93dc 100644 --- a/eglot.el +++ b/eglot.el @@ -1399,7 +1399,7 @@ THINGS are either registrations or unregisterations." (eglot--TextDocumentPositionParams) `(:context ,(if-let (trigger (and (characterp eglot--last-inserted-char) -(cl-find last-input-event +(cl-find eglot--last-inserted-char (eglot--server-capable :completionProvider :triggerCharacters) :key (lambda (str) (aref str 0)) @@ -2116,8 +2116,8 @@ If SKIP-SIGNATURE, don't try to send textDocument/signatureHelp." (keyboard-quit) retval) (eglot--dcase action - (((Command) command arguments) - (eglot-execute-command server (intern command) arguments)) +(((Command) command arguments) + (eglot-execute-command server (intern command) arguments)) (((CodeAction) edit command) (when edit (eglot--apply-workspace-edit edit)) (when command
[elpa] externals/eglot 66a1704 22/26: Scratch/use elpa flymake (#178)
branch: externals/eglot commit 66a170468757dca70d2788ac89bd69d3a346 Author: João Távora Commit: GitHub Scratch/use elpa flymake (#178) Use GNU ELPA's Flymake * eglot.el (Package-Requires): require Flymake 1.0.2. (version< emacs-version "27.0"): Remove horrible hack * Makefile (ELPADEPS): Renamed from JSONRPC. (%.elc): Use it. (eglot-check): Use it. --- Makefile | 13 - eglot.el | 36 +--- 2 files changed, 9 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index 637deb7..9f4ed1a 100644 --- a/Makefile +++ b/Makefile @@ -10,16 +10,19 @@ LOAD_PATH=-L . ELFILES := eglot.el eglot-tests.el ELCFILES := $(ELFILES:.el=.elc) -JSONRPC ?=--eval '(package-initialize)'\ - --eval '(package-refresh-contents)' \ - --eval '(package-install (quote jsonrpc))' +ELPADEPS ?=--eval '(package-initialize)' \ + --eval '(package-refresh-contents)' \ + --eval '(package-install (quote jsonrpc))' \ + --eval '(package-install\ + (cadr (assoc (quote flymake) \ + package-archive-contents)))' all: compile # Compilation # %.elc: %.el - $(EMACS) -Q $(JSONRPC) $(LOAD_PATH) --batch -f batch-byte-compile $< + $(EMACS) -Q $(ELPADEPS) $(LOAD_PATH) --batch -f batch-byte-compile $< compile: $(ELCFILES) @@ -27,7 +30,7 @@ compile: $(ELCFILES) # eglot-check: compile $(EMACS) -Q --batch \ - $(JSONRPC) \ + $(ELPADEPS) \ $(LOAD_PATH)\ -l eglot\ -l eglot-tests \ diff --git a/eglot.el b/eglot.el index 0286f75..4552930 100644 --- a/eglot.el +++ b/eglot.el @@ -7,7 +7,7 @@ ;; Maintainer: João Távora ;; URL: https://github.com/joaotavora/eglot ;; Keywords: convenience, languages -;; Package-Requires: ((emacs "26.1") (jsonrpc "1.0.6")) +;; Package-Requires: ((emacs "26.1") (jsonrpc "1.0.6") (flymake "1.0.2")) ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -2400,40 +2400,6 @@ If SKIP-SIGNATURE, don't try to send textDocument/signatureHelp." "Eclipse JDT breaks spec and replies with edits as arguments." (mapc #'eglot--apply-workspace-edit arguments)) - -;; FIXME: A horrible hack of Flymake's insufficient API that must go -;; into Emacs master, or better, 26.2 -(when (version< emacs-version "27.0") - (cl-defstruct (eglot--diag (:include flymake--diag) - (:constructor eglot--make-diag-1)) -data-1) - (defsubst eglot--make-diag (buffer beg end type text data) -(let ((sym (alist-get type eglot--diag-error-types-to-old-types))) - (eglot--make-diag-1 :buffer buffer :beg beg :end end :type sym - :text text :data-1 data))) - (defsubst eglot--diag-data (diag) -(and (eglot--diag-p diag) (eglot--diag-data-1 diag))) - (defvar eglot--diag-error-types-to-old-types -'((eglot-error . :error) - (eglot-warning . :warning) - (eglot-note . :note))) - (advice-add - 'flymake--highlight-line :after - (lambda (diag) - (when (eglot--diag-p diag) - (let ((ov (cl-find diag - (overlays-at (flymake-diagnostic-beg diag)) - :key (lambda (ov) - (overlay-get ov 'flymake-diagnostic - (overlay-properties - (get (car (rassoc (flymake-diagnostic-type diag) -eglot--diag-error-types-to-old-types)) - 'flymake-overlay-control))) - (cl-loop for (k . v) in overlay-properties - do (overlay-put ov k v) - '((name . eglot-hacking-in-some-per-diag-overlay-properties - - (provide 'eglot) ;;; eglot.el ends here
[elpa] externals/eglot a46f003 17/26: Fix #164: handle CodeAction/Command polymorphism with eglot--dcase
branch: externals/eglot commit a46f0032ec4bb6d5e7faea1c5c8d1592649703cc Author: João Távora Commit: MichaŠKrzywkowski Fix #164: handle CodeAction/Command polymorphism with eglot--dcase * eglot-tests.el (eglot-dcase): Augment test. * eglot.el (eglot--lsp-interface-alist): Add Command interface. (eglot--dcase): Fix indentation. When given interface, always assume strict mode. (eglot-code-actions): Use eglot--dcase. --- eglot-tests.el | 25 ++--- eglot.el | 40 ++-- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/eglot-tests.el b/eglot-tests.el index 37184d0..8a9aba6 100644 --- a/eglot-tests.el +++ b/eglot-tests.el @@ -648,13 +648,31 @@ Pass TIMEOUT to `eglot--with-timeout'." (ert-deftest eglot-dcase () (let ((eglot--lsp-interface-alist - `((FooObject . ((:foo :bar) (:baz)) + `((FooObject . ((:foo :bar) (:baz))) + (CodeAction (:title) (:kind :diagnostics :edit :command)) + (Command (:title :command) (:arguments) (should (equal "foo" (eglot--dcase `(:foo "foo" :bar "bar") - (((FooObject) foo) - foo)) +(((FooObject) foo) + foo +(should + (equal + (list "foo" "some command" "some edit") + (eglot--dcase '(:title "foo" :command "some command" :edit "some edit") +(((Command) _title _command _arguments) + (ert-fail "Shouldn't have destructured this object as a Command")) +(((CodeAction) title edit command) + (list title command edit) +(should + (equal + (list "foo" "some command" nil) + (eglot--dcase '(:title "foo" :command "some command") +(((Command) title command arguments) + (list title command arguments)) +(((CodeAction) _title _edit _command) + (ert-fail "Shouldn't have destructured this object as a CodeAction"))) (provide 'eglot-tests) ;;; eglot-tests.el ends here @@ -662,3 +680,4 @@ Pass TIMEOUT to `eglot--with-timeout'." ;; Local Variables: ;; checkdoc-force-docstrings-flag: nil ;; End: + diff --git a/eglot.el b/eglot.el index e4547c5..578a90d 100644 --- a/eglot.el +++ b/eglot.el @@ -204,13 +204,12 @@ let the buffer grow forever." ;;; Message verification helpers ;;; (defvar eglot--lsp-interface-alist - `( -(CodeAction (:title) (:kind :diagnostics :edit :command)) + `((CodeAction (:title) (:kind :diagnostics :edit :command)) +(Command (:title :command) (:arguments)) (FileSystemWatcher (:globPattern) (:kind)) (Registration (:id :method) (:registerOptions)) (TextDocumentEdit (:textDocument :edits) ()) -(WorkspaceEdit () (:changes :documentChanges)) -) +(WorkspaceEdit () (:changes :documentChanges))) "Alist (INTERFACE-NAME . INTERFACE) of known external LSP interfaces. INTERFACE-NAME is a symbol designated by the spec as @@ -294,6 +293,7 @@ Honour `eglot-strict-mode'." "Like `pcase', but for the LSP object OBJ. CLAUSES is a list (DESTRUCTURE FORMS...) where DESTRUCTURE is treated as in `eglot-dbind'." + (declare (indent 1)) (let ((obj-once (make-symbol "obj-once"))) `(let ((,obj-once ,obj)) (cond @@ -306,19 +306,21 @@ treated as in `eglot-dbind'." (car (pop vars))) for condition = (if interface-name + ;; In this mode, we assume `eglot-strict-mode' is fully + ;; on, otherwise we can't disambiguate between certain + ;; types. `(let* ((interface (or (assoc ',interface-name eglot--lsp-interface-alist) (eglot--error "Unknown interface %s"))) (object-keys (eglot--plist-keys ,obj-once)) (required-keys (car (cdr interface (and (null (cl-set-difference required-keys object-keys)) - (or (null (memq 'disallow-non-standard-keys - eglot-strict-mode)) - (null (cl-set-difference - (cl-set-difference object-keys required-keys) - (cadr (cdr interface))) + (null (cl-set-difference + (cl-set-difference object-keys required-keys) + (cadr (cdr interface)) ;; In this interface-less mode we don't check - ;; `eglot-strict-mode' at all. + ;; `eglot-strict-mode' at all: just check that the object + ;; has all the keys the user wants to destructure. `(null (cl-set-difference ',vars-as-keywords (eglot--plist-keys ,obj-once @@ -2100,9 +2102,8 @@ If SKIP-SIGNATURE, don't try to send textDocument/signatureHelp."
[elpa] externals/eglot 6de3d9c 10/26: Per #171, #156: Introduce eglot--dcase
branch: externals/eglot commit 6de3d9cf9cdf9f21fb4bf637d98f97738dbb12e5 Author: João Távora Commit: João Távora Per #171,#156: Introduce eglot--dcase * eglot.el (eglot--dcase): New macro. * eglot-tests.el (eglot-dcase-with-interface) (eglot-dcase-no-interface): New tests. --- eglot-tests.el | 10 ++ eglot.el | 41 + 2 files changed, 51 insertions(+) diff --git a/eglot-tests.el b/eglot-tests.el index 8b91317..37184d0 100644 --- a/eglot-tests.el +++ b/eglot-tests.el @@ -646,6 +646,16 @@ Pass TIMEOUT to `eglot--with-timeout'." (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :baz bargh) (cons foo bar)) +(ert-deftest eglot-dcase () + (let ((eglot--lsp-interface-alist + `((FooObject . ((:foo :bar) (:baz)) +(should + (equal + "foo" + (eglot--dcase `(:foo "foo" :bar "bar") + (((FooObject) foo) + foo)) + (provide 'eglot-tests) ;;; eglot-tests.el ends here diff --git a/eglot.el b/eglot.el index 594a638..61f9b70 100644 --- a/eglot.el +++ b/eglot.el @@ -281,6 +281,47 @@ Honour `eglot-strict-mode'." (let ((e (cl-gensym "jsonrpc-lambda-elem"))) `(lambda (,e) (eglot--dbind ,cl-lambda-list ,e ,@body +(cl-defmacro eglot--dcase (obj &rest clauses) + "Like `pcase', but for the LSP object OBJ. +CLAUSES is a list (DESTRUCTURE FORMS...) where DESTRUCTURE is +treated as in `eglot-dbind'." + (let ((obj-once (make-symbol "obj-once"))) +`(let ((,obj-once ,obj)) + (cond +,@(cl-loop + for (vars . body) in clauses + for vars-as-keywords = (mapcar (lambda (var) +(intern (format ":%s" var))) + vars) + for interface-name = (if (consp (car vars)) +(car (pop vars))) + for condition = + (if interface-name + `(let* ((interface +(or (assoc ',interface-name eglot--lsp-interface-alist) +(eglot--error "Unknown interface %s"))) + (object-keys (eglot--plist-keys ,obj-once)) + (required-keys (car (cdr interface + (and (null (cl-set-difference required-keys object-keys)) + (or (null (memq 'disallow-non-standard-keys + eglot-strict-mode)) + (null (cl-set-difference + (cl-set-difference object-keys required-keys) + (cadr (cdr interface))) + ;; In this interface-less mode we don't check + ;; `eglot-strict-mode' at all. + `(null (cl-set-difference + ',vars-as-keywords + (eglot--plist-keys ,obj-once + collect `(,condition + (cl-destructuring-bind (&key ,@vars &allow-other-keys) + ,obj-once + ,@body))) +(t + (eglot--error "%s didn't match any of %s" + ,obj-once + ',(mapcar #'car clauses))) + ;;; API (WORK-IN-PROGRESS!) ;;;
[elpa] master 8309dc8: * nhexl-mode.el: Add isearch and highlight to hex area
branch: master commit 8309dc86c5ca0d11be3620e908bf157422654627 Author: Stefan Monnier Commit: Stefan Monnier * nhexl-mode.el: Add isearch and highlight to hex area (nhexl-isearch-hex-addresses, nhexl-isearch-hex-bytes) (nhexl-isearch-hex-highlight): New vars. (nhexl--make-line): Copy isearch highlighting from the buffer when applicable. (nhexl--isearch-match-hex-bytes): New function. (nhexl--isearch-match-hex-address): New function, extracted from nhexl--isearch-search-fun. Match the whole corresponding line. (nhexl--isearch-search-fun): Use them. (nhexl--isearch-highlight-cleanup, nhexl--isearch-highlight-match): New functions. (lazy-highlight-cleanup, isearch-lazy-highlight-match): Use them as advice to propagate isearch highlight to the hex area. --- packages/nhexl-mode/nhexl-mode.el | 204 +++--- 1 file changed, 147 insertions(+), 57 deletions(-) diff --git a/packages/nhexl-mode/nhexl-mode.el b/packages/nhexl-mode/nhexl-mode.el index b58b81d..89d9118 100644 --- a/packages/nhexl-mode/nhexl-mode.el +++ b/packages/nhexl-mode/nhexl-mode.el @@ -4,7 +4,7 @@ ;; Author: Stefan Monnier ;; Keywords: data -;; Version: 1.0 +;; Version: 1.1 ;; Package-Requires: ((emacs "24.4") (cl-lib "0.5")) ;; This program is free software; you can redistribute it and/or modify @@ -44,9 +44,10 @@ ;; - it overrides C-u to use hexadecimal, so you can do C-u a 4 C-f ;; to advance by #xa4 characters. -;; Even though the hex addresses displayed by this mode aren't actually -;; part of the buffer's text (contrary to hexl-mode, for example), you can -;; search them with Isearch. +;; Even though the hex addresses and hex data displayed by this mode aren't +;; actually part of the buffer's text (contrary to hexl-mode, for example, +;; they're only added to the display), you can search them with Isearch, +;; according to nhexl-isearch-hex-addresses and nhexl-isearch-hex-bytes. Known bugs: ;; @@ -89,6 +90,18 @@ Otherwise they are applied unconditionally." "If non-nil `nhexl-mode' won't ask before converting the buffer to unibyte." :type 'boolean) +(defcustom nhexl-isearch-hex-addresses t + "If non-nil, hex search terms will look for matching addresses." + :type 'boolean) + +(defcustom nhexl-isearch-hex-bytes t + "If non-nil, hex search terms will look for matching bytes." + :type 'boolean) + +(defcustom nhexl-isearch-hex-highlight t + "If non-nil, nhexl will highlight Isearch matches in the hex areas as well." + :type 'boolean) + (defvar nhexl--display-table (let ((dt (make-display-table))) (unless nhexl-display-unprintables @@ -611,10 +624,16 @@ Return the corresponding nibble, if applicable." (eval-when-compile (propertize " " 'display '(space :align-to 12))) (mapconcat (lambda (c) (setq i (1+ i)) - ;; FIXME: In multibyte buffers, - ;; do something clever about - ;; non-ascii chars. - (let ((s (format "%02x" c))) + ;; FIXME: In multibyte buffers, do something clever + ;; about non-ascii chars. + (let ((s (format "%02x" c)) +face) +(when (and isearch-mode + (memq (setq face (get-char-property + (+ i from) 'face)) + '(lazy-highlight isearch))) + (put-text-property 0 (length s) 'face + `(,face default) s)) (when (and point (eq point (+ from i))) (if nhexl-nibble-edit-mode (let ((nib (min (nhexl--nibble point) @@ -626,6 +645,9 @@ Return the corresponding nibble, if applicable." 'face '(highlight default) s))) (if (zerop (mod i 2)) +;; FIXME: If this char and the next are both +;; covered by isearch highlight, we should +;; also highlight the space. s (concat s " " bufstr "") @@ -775,61 +797,129 @@ Return the corresponding nibble, if applicable." (truncate (- oldpoint zero) lw)) (nhexl--refresh-cursor oldpoint) +(defun nhexl--isearch-match-hex-bytes (string bound noerror) + ;; "57a" can be taken as "57a." or ".57a", but we currently + ;; only handle "57a." + ;; TODO: Maybe we could support hex regexps as well? + (let ((i 0) +(chars ())) +(while (< (1+ i) (l