[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/eglot 06ff65d 52/69: Rework and correct major part of x
From: |
João Távora |
Subject: |
[elpa] externals/eglot 06ff65d 52/69: Rework and correct major part of xref glue code |
Date: |
Sun, 20 Oct 2019 08:21:52 -0400 (EDT) |
branch: externals/eglot
commit 06ff65dd91003a22d3a44f8d7120a105acccdf89
Author: João Távora <address@hidden>
Commit: João Távora <address@hidden>
Rework and correct major part of xref glue code
See comments of https://github.com/joaotavora/eglot/pull/314. Up to
now, xref-backend-indentifier-completion-table was a gross hack that
only worked sometimes. It relied on some fugly gymnastics to cache a
response from :textDocument/documentSymbol and somehow used that
information to build a completion table. But it doesn't work well.
Summarily, LSP doesn't lend itself well to the xref interface of
prompting for an arbitrary identifier and then go look for whichever
type of references of that identifier. All the LSP
:textDocument/{definition,references,implementation,...} methods
expect to know the exact context of the search the user is about to
perform, in the form of a document location. That conflicts with the
xref "arbitrary string" requirement.
Therefore, the slightly limited, but much more correct way, for Eglot
to function is to override the user's preference of
xref-prompt-for-identifier, temporarily setting it to nil in
eglot--managed-mode (ideally, though, xref-prompt-for-identifier
should be a function of the backend.)
Later on, a possibly better behaved identifier completion table can be
built on top of the :workspace/symbol LSP method.
* eglot.el (xref-backend-identifier-at-point): Rewrite.
(eglot--lsp-xrefs-for-method): New helper.
(eglot--lsp-xref-helper): Use eglot--lsp-xrefs-for-method.
(eglot--xref-definitions-method): Delete.
(eglot--lsp-xref-refs): New variable.
(xref-backend-references, xref-backend-definitions): Use
eglot--lsp-xrefs-for-method.
(eglot--managed-mode): Set xref-prompt-for-identifier
to nil.
(eglot--xref-reset-known-symbols, eglot--xref-known-symbols): Delete
(xref-backend-identifier-completion-table): Nullify.
(eglot-find-declaration, eglot-find-implementation)
(eglot-find-typeDefinition): Use eglot--lsp-xref-helper.
---
eglot.el | 143 +++++++++++++++++++++------------------------------------------
1 file changed, 48 insertions(+), 95 deletions(-)
diff --git a/eglot.el b/eglot.el
index e3ead96..51914d9 100644
--- a/eglot.el
+++ b/eglot.el
@@ -1193,6 +1193,7 @@ and just return it. PROMPT shouldn't end with a question
mark."
(add-hook 'post-self-insert-hook 'eglot--post-self-insert-hook nil t)
(add-hook 'pre-command-hook 'eglot--pre-command-hook nil t)
(eglot--setq-saving eldoc-documentation-function #'eglot-eldoc-function)
+ (eglot--setq-saving xref-prompt-for-identifier nil)
(eglot--setq-saving flymake-diagnostic-functions '(eglot-flymake-backend
t))
(add-function :around (local 'imenu-create-index-function) #'eglot-imenu)
(flymake-mode 1)
@@ -1717,16 +1718,6 @@ Calls REPORT-FN maybe if server publishes diagnostics in
time."
"EGLOT xref backend."
(when (eglot--server-capable :definitionProvider) 'eglot))
-(defvar eglot--xref-known-symbols nil)
-
-(defun eglot--xref-reset-known-symbols (&rest _dummy)
- "Reset `eglot--xref-reset-known-symbols'.
-DUMMY is ignored."
- (setq eglot--xref-known-symbols nil))
-
-(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'.")
@@ -1771,102 +1762,64 @@ Try to visit the target file for a richer summary
line."
(xref-make summary (xref-make-file-location file line column))))
(cl-defmethod xref-backend-identifier-completion-table ((_backend (eql eglot)))
- (when (eglot--server-capable :documentSymbolProvider)
- (let ((server (eglot--current-server-or-lose))
- (text-id (eglot--TextDocumentIdentifier)))
- (completion-table-with-cache
- (lambda (string)
- (setq eglot--xref-known-symbols
- (mapcar
- (eglot--lambda
- ((SymbolInformation) name kind location containerName)
- (propertize name
- :textDocumentPositionParams
- (list :textDocument text-id
- :position (plist-get
- (plist-get location :range)
- :start))
- :locations (vector location)
- :kind kind
- :containerName containerName))
- (jsonrpc-request server
- :textDocument/documentSymbol
- `(:textDocument ,text-id))))
- (all-completions string eglot--xref-known-symbols))))))
+ (eglot--error "cannot (yet) provide reliable completion table for LSP
symbols"))
(cl-defmethod xref-backend-identifier-at-point ((_backend (eql eglot)))
- (when-let ((symatpt (symbol-at-point)))
- (propertize (symbol-name symatpt)
- :textDocumentPositionParams
- (eglot--TextDocumentPositionParams))))
-
-(defvar eglot--xref-definitions-method :textDocument/definition
- "The LSP method to map xref-find-definitions call.")
+ ;; JT@19/10/09: This is a totally dummy identifier that isn't even
+ ;; passed to LSP. The reason for this particular wording is to
+ ;; construct a readable message "No references for LSP identifier at
+ ;; point.". See http://github.com/joaotavora/eglot/issues/314
+ "LSP identifier at point.")
+
+(defvar eglot--lsp-xref-refs nil
+ "`xref' objects for overriding `xref-backend-references''s.")
+
+(cl-defun eglot--lsp-xrefs-for-method (method &key extra-params capability)
+ "Make `xref''s for METHOD, EXTRA-PARAMS, check CAPABILITY."
+ (unless (eglot--server-capable
+ (or capability
+ (intern
+ (format ":%sProvider"
+ (cadr (split-string (symbol-name method)
+ "/"))))))
+ (eglot--error "Sorry, this server doesn't do %s" method))
+ (eglot--handling-xrefs
+ (mapcar
+ (eglot--lambda ((Location) uri range)
+ (eglot--xref-make (symbol-at-point) uri range))
+ (jsonrpc-request
+ (eglot--current-server-or-lose) method (append
+
(eglot--TextDocumentPositionParams)
+ extra-params)))))
+
+(defun eglot--lsp-xref-helper (method)
+ "Helper for `eglot-find-declaration' & friends."
+ (let ((eglot--lsp-xref-refs (eglot--lsp-xrefs-for-method method)))
+ (xref-find-references "LSP identifier at point.")))
(defun eglot-find-declaration ()
- "Find the declaration for the identifier at point.
-See `xref-find-definitions' and `xref-prompt-for-identifier'."
+ "Find declaration for SYM, the identifier at point."
(interactive)
- (eglot--find-location 'declaration))
+ (eglot--lsp-xref-helper :textDocument/declaration))
(defun eglot-find-implementation ()
- "Find the implementation for the identifier at point.
-See `xref-find-definitions' and `xref-prompt-for-identifier'."
+ "Find implementation for SYM, the identifier at point."
(interactive)
- (eglot--find-location 'implementation))
+ (eglot--lsp-xref-helper :textDocument/implementation))
(defun eglot-find-typeDefinition ()
- "Find the type definition for the identifier at point.
-See `xref-find-definitions' and `xref-prompt-for-identifier'."
+ "Find type definition for SYM, the identifier at point."
(interactive)
- (eglot--find-location 'typeDefinition))
-
-(defun eglot--find-location (kind)
- (let* ((method-name (symbol-name kind))
- (method (intern (concat ":textDocument/" method-name)))
- (capability (intern (concat ":" method-name "Provider"))))
- (if (eglot--server-capable capability)
- (let ((eglot--xref-definitions-method method))
- (call-interactively #'xref-find-definitions))
- (eglot--error "Server is not a %sProvider" method-name))))
-
-(cl-defmethod xref-backend-definitions ((_backend (eql eglot)) identifier)
- (let* ((rich-identifier
- (car (member identifier eglot--xref-known-symbols)))
- (definitions
- (if rich-identifier
- (get-text-property 0 :locations rich-identifier)
- (jsonrpc-request (eglot--current-server-or-lose)
- eglot--xref-definitions-method
- (get-text-property
- 0 :textDocumentPositionParams identifier))))
- (locations
- (and definitions
- (if (vectorp definitions) definitions (vector definitions)))))
- (eglot--handling-xrefs
- (mapcar (eglot--lambda ((Location) uri range)
- (eglot--xref-make identifier uri range))
- locations))))
-
-(cl-defmethod xref-backend-references ((_backend (eql eglot)) identifier)
- (when (eglot--server-capable :referencesProvider)
- (let ((params
- (or (get-text-property 0 :textDocumentPositionParams identifier)
- (let ((rich (car (member identifier eglot--xref-known-symbols))))
- (and rich
- (get-text-property 0 :textDocumentPositionParams rich))))))
- (unless params
- (eglot--error "Don' know where %s is in the workspace!" identifier))
- (eglot--handling-xrefs
- (mapcar
- (eglot--lambda ((Location) uri range)
- (eglot--xref-make identifier uri range))
- (jsonrpc-request (eglot--current-server-or-lose)
- :textDocument/references
- (append
- params
- (list :context
- (list :includeDeclaration t)))))))))
+ (eglot--lsp-xref-helper :textDocument/typeDefinition))
+
+(cl-defmethod xref-backend-definitions ((_backend (eql eglot)) _identifier)
+ (eglot--lsp-xrefs-for-method :textDocument/definition))
+
+(cl-defmethod xref-backend-references ((_backend (eql eglot)) _identifier)
+ (or
+ eglot--lsp-xref-refs
+ (eglot--lsp-xrefs-for-method
+ :textDocument/references :extra-params `(:context (:includeDeclaration
t)))))
(cl-defmethod xref-backend-apropos ((_backend (eql eglot)) pattern)
(when (eglot--server-capable :workspaceSymbolProvider)
- [elpa] externals/eglot 28ecd5d 34/69: Change the default of eglot-move-to-column-function, (continued)
- [elpa] externals/eglot 28ecd5d 34/69: Change the default of eglot-move-to-column-function, João Távora, 2019/10/20
- [elpa] externals/eglot 7a70c97 33/69: Require array package to use current-line (#294), João Távora, 2019/10/20
- [elpa] externals/eglot f7a1bf6 49/69: Fix #236: much less noisy mode line, João Távora, 2019/10/20
- [elpa] externals/eglot 4c5d0d4 53/69: Misc improvements to the xref glue code, João Távora, 2019/10/20
- [elpa] externals/eglot 5ea4049 68/69: Fix #324: let user keep control of some variables during Eglot sessions, João Távora, 2019/10/20
- [elpa] externals/eglot 33a4f86 69/69: * eglot.el (Version): Bump to 1.5, João Távora, 2019/10/20
- [elpa] externals/eglot cf161b0 41/69: Test with emacs master on Travis, João Távora, 2019/10/20
- [elpa] externals/eglot 9e70cd2 40/69: * eglot-tests.el (python-autopep-formatting): Attempt to fix test., João Távora, 2019/10/20
- [elpa] externals/eglot c3bae0a 44/69: New test for the eglot-autoshutdown defcustom, João Távora, 2019/10/20
- [elpa] externals/eglot 28d8ffe 48/69: Fix #285: unbreak Elm language server which does use :triggerCharacters, João Távora, 2019/10/20
- [elpa] externals/eglot 06ff65d 52/69: Rework and correct major part of xref glue code,
João Távora <=
- [elpa] externals/eglot 9951dc5 62/69: Add a test for vscode-json-languageserver's completions, João Távora, 2019/10/20
- [elpa] externals/eglot 124a833 56/69: Add a test for #311 and #279, João Távora, 2019/10/20
- [elpa] externals/eglot d774754 37/69: Merge pull request #298 from jorams/nil-capabilities-as-false, João Távora, 2019/10/20
- [elpa] externals/eglot 20195e5 42/69: On buffer kill, first send didClose then teardown local structures, João Távora, 2019/10/20
- [elpa] externals/eglot 5a98c5a 55/69: Fix eglot-completion-at-point to work with bare completion-at-point, João Távora, 2019/10/20
- [elpa] externals/eglot 6a7ce66 32/69: Expand directory watcher globs containing ** (#293), João Távora, 2019/10/20
- [elpa] externals/eglot f45fdc6 31/69: Fix invalid guess for php language Server (#288), João Távora, 2019/10/20
- [elpa] externals/eglot 05c68c2 45/69: Don't send dummy JSON object in "initialized" notification (#312), João Távora, 2019/10/20
- [elpa] externals/eglot bff921e 60/69: Per #319: always filter completions client-side by prefix, João Távora, 2019/10/20
- [elpa] externals/eglot 260f152 65/69: Fix #321: don't choke on single-location reply to tD/definition, João Távora, 2019/10/20