[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/elpa a044dec 47/71: Delegate "hover" and "signature" do
From: |
João Távora |
Subject: |
[elpa] externals/elpa a044dec 47/71: Delegate "hover" and "signature" doc synchronization efforts to Eldoc |
Date: |
Wed, 16 Dec 2020 11:42:23 -0500 (EST) |
branch: externals/elpa
commit a044dec7f94d0d21bd65cf8a04f09cc63324db18
Author: João Távora <joaotavora@gmail.com>
Commit: João Távora <joaotavora@gmail.com>
Delegate "hover" and "signature" doc synchronization efforts to Eldoc
Uses Eldoc's eldoc-documentation-functions variable. In Eldoc v1.0.0
that variable was already available as a way of handling/composing
multiple docstrings from different sources, but it didn't work
practically with mutiple concurrent async sources. This was fixed in
1.1.0, which Eglot now requires.
This fixes the synchronization problems reported in #494 and also
issue #439. It is likely that some of the exact doc-composing
functionality in Eglot, (developed during those issues) was lost, and
has to be remade, quite likely in Eldoc itself.
Flymake is now also an Eldoc producer, and therefore the problems of
github issues #481 and #454 will also soon be fixed as soon as Eglot
starts using the upcoming Flymake 1.0.9.
* NEWS.md: New entry.
* README.md (eglot-put-doc-in-help-buffer)
(eglot-auto-display-help-buffer): Remove mention to these options.
* eglot.el
(Package-Requires:) Require eldoc.el 1.1.0.
(eglot--when-live-buffer): Rename from eglot--with-live-buffer.
(eglot--when-buffer-window): New macro.
(eglot--after-change, eglot--on-shutdown, eglot-ensure): Use
eglot--when-live-buffer.
(eglot--managed-mode): Use eglot-documentation-functions and
eldoc-documentation-strategy.
(eglot--highlights): Move down.
(eglot-signature-eldoc-function, eglot-hover-eldoc-function)
(eglot--highlight-piggyback): New eldoc functions.
(eglot--help-buffer, eglot--update-doc)
(eglot-auto-display-help-buffer, eglot-put-doc-in-help-buffer)
(eglot--truncate-string, eglot-doc-too-large-for-echo-area)
(eglot-help-at-point): Remove all of this.
(eglot--apply-workspace-edit): Call eldoc manually after an edit.
(eglot-mode-map): Remap display-local-help to eldoc-doc-buffer
---
NEWS.md | 11 +++
README.md | 6 --
eglot.el | 259 +++++++++++++++++++-------------------------------------------
3 files changed, 91 insertions(+), 185 deletions(-)
diff --git a/NEWS.md b/NEWS.md
index 9be8588..cb72ba3 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -4,6 +4,17 @@
Thanks to Ingo Lohmar for the original implementation.
+##### Handle multiple "documentation at point" sources ([#439][github#439],
[#494][github#494], [#481][github#481], [#454][github#454])
+
+Such sources include as LSP's signature, hover and also the Flymake
+diagnostic messages. They can all be presented in the echo area
+(space permitting), or via `C-h .`. For now, composition of different
+sources can be customized using `eldoc-documentation-strategy`,
+`eldoc-echo-area-use-multiline-p` and `eldoc-prefer-doc-buffer`.
+
+The variables `eglot-put-doc-in-help-buffer` and
+`eglot-auto-display-help-buffer` have been removed.
+
# 1.6 (16/04/2020)
##### Column offset calculation is now LSP-conform ([#361][github#361])
diff --git a/README.md b/README.md
index edbc779..caf03ba 100644
--- a/README.md
+++ b/README.md
@@ -264,12 +264,6 @@ documentation on what these do.
- `eglot-ignored-server-capabilites`: LSP server capabilities that
Eglot could use, but won't;
-- `eglot-put-doc-in-help-buffer`: If non-nil, put eldoc docstrings in
- separate `*eglot-help*` buffer;
-
-- `eglot-auto-display-help-buffer`: If non-nil, automatically display
- `*eglot-help*` buffer;
-
- `eglot-confirm-server-initiated-edits`: If non-nil, ask for confirmation
before allowing server to edit the source buffer's text;
diff --git a/eglot.el b/eglot.el
index 733b69c..b94fcc3 100644
--- a/eglot.el
+++ b/eglot.el
@@ -7,7 +7,7 @@
;; Maintainer: João Távora <joaotavora@gmail.com>
;; URL: https://github.com/joaotavora/eglot
;; Keywords: convenience, languages
-;; Package-Requires: ((emacs "26.1") (jsonrpc "1.0.9") (flymake "1.0.8")
(project "0.3.0") (xref "1.0.1") (eldoc "1.0.0"))
+;; Package-Requires: ((emacs "26.1") (jsonrpc "1.0.9") (flymake "1.0.8")
(project "0.3.0") (xref "1.0.1") (eldoc "1.1.0"))
;; 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
@@ -470,11 +470,19 @@ treated as in `eglot-dbind'."
;;; API (WORK-IN-PROGRESS!)
;;;
-(cl-defmacro eglot--with-live-buffer (buf &rest body)
+(cl-defmacro eglot--when-live-buffer (buf &rest body)
"Check BUF live, then do BODY in it." (declare (indent 1) (debug t))
(let ((b (cl-gensym)))
`(let ((,b ,buf)) (if (buffer-live-p ,b) (with-current-buffer ,b
,@body)))))
+(cl-defmacro eglot--when-buffer-window (buf &body body)
+ "Check BUF showing somewhere, then do BODY in it" (declare (indent 1) (debug
t))
+ (let ((b (cl-gensym)))
+ `(let ((,b ,buf))
+ ;;notice the exception when testing with `ert'
+ (when (or (get-buffer-window ,b) (ert-running-test))
+ (with-current-buffer ,b ,@body)))))
+
(cl-defmacro eglot--widening (&rest body)
"Save excursion and restriction. Widen. Then run BODY." (declare (debug t))
`(save-excursion (save-restriction (widen) ,@body)))
@@ -642,7 +650,7 @@ SERVER. ."
(dolist (buffer (eglot--managed-buffers server))
(let (;; Avoid duplicate shutdowns (github#389)
(eglot-autoshutdown nil))
- (eglot--with-live-buffer buffer (eglot--managed-mode-off))))
+ (eglot--when-live-buffer buffer (eglot--managed-mode-off))))
;; Kill any expensive watches
(maphash (lambda (_id watches)
(mapcar #'file-notify-rm-watch watches))
@@ -806,7 +814,7 @@ INTERACTIVE is t if called interactively."
((maybe-connect
()
(remove-hook 'post-command-hook #'maybe-connect nil)
- (eglot--with-live-buffer buffer
+ (eglot--when-live-buffer buffer
(unless eglot--managed-mode
(apply #'eglot--connect (eglot--guess-contact))))))
(when buffer-file-name
@@ -1253,7 +1261,7 @@ and just return it. PROMPT shouldn't end with a question
mark."
;;;
(defvar eglot-mode-map
(let ((map (make-sparse-keymap)))
- (define-key map [remap display-local-help] 'eglot-help-at-point)
+ (define-key map [remap display-local-help] 'eldoc-doc-buffer)
map))
(defvar-local eglot--current-flymake-report-fn nil
@@ -1325,7 +1333,11 @@ Use `eglot-managed-p' to determine if current buffer is
managed.")
(add-hook 'change-major-mode-hook #'eglot--managed-mode-off 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)
- (eglot--setq-saving eldoc-documentation-function #'eglot-eldoc-function)
+ (eglot--setq-saving eldoc-documentation-functions
+ '(eglot-signature-eldoc-function
+ eglot-hover-eldoc-function))
+ (eglot--setq-saving eldoc-documentation-strategy
+ #'eldoc-documentation-enthusiast)
(eglot--setq-saving xref-prompt-for-identifier nil)
(eglot--setq-saving flymake-diagnostic-functions '(eglot-flymake-backend
t))
(eglot--setq-saving company-backends '(company-capf))
@@ -1733,7 +1745,7 @@ Records BEG, END and PRE-CHANGE-LENGTH locally."
(setq eglot--change-idle-timer
(run-with-idle-timer
eglot-send-changes-idle-time
- nil (lambda () (eglot--with-live-buffer buf
+ nil (lambda () (eglot--when-live-buffer buf
(when eglot--managed-mode
(eglot--signal-textDocument/didChange)
(setq eglot--change-idle-timer nil))))))))
@@ -2189,9 +2201,7 @@ is not active."
(delete-region (- (point) (length proxy)) (point))
(funcall snippet-fn (or insertText label)))))
(eglot--signal-textDocument/didChange)
- (eglot-eldoc-function)))))))
-
-(defvar eglot--highlights nil "Overlays for textDocument/documentHighlight.")
+ (eldoc)))))))
(defun eglot--hover-info (contents &optional range)
(let ((heading (and range (pcase-let ((`(,beg . ,end) (eglot--range-region
range)))
@@ -2256,177 +2266,68 @@ is not active."
(buffer-string))))
when moresigs concat "\n"))
-(defvar eglot--help-buffer nil)
+(defun eglot-signature-eldoc-function (cb)
+ "A member of `eldoc-documentation-functions', for signatures."
+ (when (eglot--server-capable :signatureHelpProvider)
+ (let ((buf (current-buffer)))
+ (jsonrpc-async-request
+ (eglot--current-server-or-lose)
+ :textDocument/signatureHelp (eglot--TextDocumentPositionParams)
+ :success-fn
+ (eglot--lambda ((SignatureHelp)
+ signatures activeSignature activeParameter)
+ (eglot--when-buffer-window buf
+ (funcall cb
+ (unless (seq-empty-p signatures)
+ (eglot--sig-info signatures
+ activeSignature
+ activeParameter)))))
+ :deferred :textDocument/signatureHelp))
+ t))
-(defun eglot--help-buffer ()
- (or (and (buffer-live-p eglot--help-buffer)
- eglot--help-buffer)
- (setq eglot--help-buffer (generate-new-buffer "*eglot-help*"))))
+(defun eglot-hover-eldoc-function (cb)
+ "A member of `eldoc-documentation-functions', for hover."
+ (when (eglot--server-capable :hoverProvider)
+ (let ((buf (current-buffer)))
+ (jsonrpc-async-request
+ (eglot--current-server-or-lose)
+ :textDocument/hover (eglot--TextDocumentPositionParams)
+ :success-fn (eglot--lambda ((Hover) contents range)
+ (eglot--when-buffer-window buf
+ (let ((info (unless (seq-empty-p contents)
+ (eglot--hover-info contents range))))
+ (funcall cb info :buffer t))))
+ :deferred :textDocument/hover))
+ (eglot--highlight-piggyback cb)
+ t))
-(defun eglot-help-at-point ()
- "Request documentation for the thing at point."
- (interactive)
- (eglot--dbind ((Hover) contents range)
- (jsonrpc-request (eglot--current-server-or-lose) :textDocument/hover
- (eglot--TextDocumentPositionParams))
- (let ((blurb (and (not (seq-empty-p contents))
- (eglot--hover-info contents range)))
- (hint (thing-at-point 'symbol)))
- (if blurb
- (with-current-buffer (eglot--help-buffer)
- (with-help-window (current-buffer)
- (rename-buffer (format "*eglot-help for %s*" hint))
- (with-current-buffer standard-output (insert blurb))
- (setq-local nobreak-char-display nil)))
- (display-local-help)))))
-
-(cl-defun eglot-doc-too-large-for-echo-area
- (string &optional (height max-mini-window-height))
- "Return non-nil if STRING won't fit in echo area of height HEIGHT.
-HEIGHT defaults to `max-mini-window-height' (which see) and is
-interpreted like that variable. If non-nil, the return value is
-the number of lines available."
- (let ((available-lines (cl-typecase height
- (float (truncate (* (frame-height) height)))
- (integer height)
- (t 1))))
- (when (> (1+ (cl-count ?\n string)) available-lines)
- available-lines)))
-
-(cl-defun eglot--truncate-string (string height &optional (width
(frame-width)))
- "Return as much from STRING as fits in HEIGHT and WIDTH.
-WIDTH, if non-nil, truncates last line to those columns."
- (cl-flet ((maybe-trunc
- (str) (if width (truncate-string-to-width str width
- nil nil "...")
- str)))
- (cl-loop
- repeat height
- for i from 1
- for break-pos = (cl-position ?\n string)
- for (line . rest) = (and break-pos
- (cons (substring string 0 break-pos)
- (substring string (1+ break-pos))))
- concat (cond (line (if (= i height) (maybe-trunc line) (concat line
"\n")))
- (t (maybe-trunc string)))
- while rest do (setq string rest))))
-
-(defcustom eglot-put-doc-in-help-buffer
- ;; JT@2020-05-21: TODO: this variable should be renamed and the
- ;; decision somehow be in eldoc.el itself.
- #'eglot-doc-too-large-for-echo-area
- "If non-nil, put \"hover\" documentation in separate `*eglot-help*' buffer.
-If nil, use whatever `eldoc-message-function' decides, honouring
-`eldoc-echo-area-use-multiline-p'. If t, use `*eglot-help*'
-unconditionally. If a function, it is called with the
-documentation string to display and returns a generalized boolean
-interpreted as one of the two preceding values."
- :type '(choice (const :tag "Never use `*eglot-help*'" nil)
- (const :tag "Always use `*eglot-help*'" t)
- (function :tag "Ask a function")))
-
-(defcustom eglot-auto-display-help-buffer nil
- "If non-nil, automatically display `*eglot-help*' buffer.
-Buffer is displayed with `display-buffer', which obeys
-`display-buffer-alist' & friends."
- :type 'boolean)
+(defvar eglot--highlights nil "Overlays for textDocument/documentHighlight.")
-(defun eglot--update-doc (string hint)
- "Put updated documentation STRING where it belongs.
-HINT is used to potentially rename EGLOT's help buffer. If
-STRING is nil, the echo area cleared of any previous
-documentation. Honour `eglot-put-doc-in-help-buffer',
-`eglot-auto-display-help-buffer' and
-`eldoc-echo-area-use-multiline-p'."
- (cond ((null string) (eldoc-message nil))
- ((or (eq t eglot-put-doc-in-help-buffer)
- (and eglot-put-doc-in-help-buffer
- (funcall eglot-put-doc-in-help-buffer string)))
- (with-current-buffer (eglot--help-buffer)
- (let ((inhibit-read-only t)
- (name (format "*eglot-help for %s*" hint)))
- (unless (string= name (buffer-name))
- (rename-buffer (format "*eglot-help for %s*" hint))
- (erase-buffer)
- (insert string)
- (goto-char (point-min)))
- (help-mode)))
- (if eglot-auto-display-help-buffer
- (display-buffer eglot--help-buffer)
- (unless (get-buffer-window eglot--help-buffer t)
- ;; Hand-tweaked to print two lines. Should it print
- ;; 1? Or honour max-mini-window-height?
- (eglot--message
- "%s\n(Truncated, %sfull help in buffer %s)"
- (eglot--truncate-string string 1 (- (frame-width) 9))
- (if-let (key (car (where-is-internal 'eglot-help-at-point)))
- (format "use %s to see " (key-description key)) "")
- (buffer-name eglot--help-buffer)))))
- ((eq eldoc-echo-area-use-multiline-p t)
- (if-let ((available (eglot-doc-too-large-for-echo-area string)))
- (eldoc-message (eglot--truncate-string string available))
- (eldoc-message string)))
- ((eq eldoc-echo-area-use-multiline-p 'truncate-sym-name-if-fit)
- (eldoc-message (eglot--truncate-string string 1 nil)))
- (t
- ;; Can't (yet?) honour non-t non-nil values of this var
- (eldoc-message (eglot--truncate-string string 1)))))
-
-(defun eglot-eldoc-function ()
- "EGLOT's `eldoc-documentation-function' function."
- (let* ((buffer (current-buffer))
- (server (eglot--current-server-or-lose))
- (position-params (eglot--TextDocumentPositionParams))
- sig-showing
- (thing-at-point (thing-at-point 'symbol)))
- (cl-macrolet ((when-buffer-window
- (&body body) ; notice the exception when testing with `ert'
- `(when (or (get-buffer-window buffer) (ert-running-test))
- (with-current-buffer buffer ,@body))))
- (when (eglot--server-capable :signatureHelpProvider)
- (jsonrpc-async-request
- server :textDocument/signatureHelp position-params
- :success-fn
- (eglot--lambda ((SignatureHelp)
- signatures activeSignature activeParameter)
- (when-buffer-window
- (when (cl-plusp (length signatures))
- (setq sig-showing t)
- (eglot--update-doc (eglot--sig-info signatures
- activeSignature
- activeParameter)
- thing-at-point))))
- :deferred :textDocument/signatureHelp))
- (when (eglot--server-capable :hoverProvider)
- (jsonrpc-async-request
- server :textDocument/hover position-params
- :success-fn (eglot--lambda ((Hover) contents range)
- (unless sig-showing
- (when-buffer-window
- (eglot--update-doc (and (not (seq-empty-p contents))
- (eglot--hover-info contents
- range))
- thing-at-point))))
- :deferred :textDocument/hover))
- (when (eglot--server-capable :documentHighlightProvider)
- (jsonrpc-async-request
- server :textDocument/documentHighlight position-params
- :success-fn
- (lambda (highlights)
- (mapc #'delete-overlay eglot--highlights)
- (setq eglot--highlights
- (when-buffer-window
- (mapcar
- (eglot--lambda ((DocumentHighlight) range)
- (pcase-let ((`(,beg . ,end)
- (eglot--range-region range)))
- (let ((ov (make-overlay beg end)))
- (overlay-put ov 'face 'highlight)
- (overlay-put ov 'evaporate t)
- ov)))
- highlights))))
- :deferred :textDocument/documentHighlight))))
- eldoc-last-message)
+(defun eglot--highlight-piggyback (_cb)
+ "Request and handle `:textDocument/documentHighlight'"
+ ;; FIXME: Obviously, this is just piggy backing on eldoc's calls for
+ ;; convenience, as shown by the fact that we just ignore cb.
+ (let ((buf (current-buffer)))
+ (when (eglot--server-capable :documentHighlightProvider)
+ (jsonrpc-async-request
+ (eglot--current-server-or-lose)
+ :textDocument/documentHighlight (eglot--TextDocumentPositionParams)
+ :success-fn
+ (lambda (highlights)
+ (mapc #'delete-overlay eglot--highlights)
+ (setq eglot--highlights
+ (eglot--when-buffer-window buf
+ (mapcar
+ (eglot--lambda ((DocumentHighlight) range)
+ (pcase-let ((`(,beg . ,end)
+ (eglot--range-region range)))
+ (let ((ov (make-overlay beg end)))
+ (overlay-put ov 'face 'highlight)
+ (overlay-put ov 'evaporate t)
+ ov)))
+ highlights))))
+ :deferred :textDocument/documentHighlight)
+ nil)))
(defun eglot-imenu ()
"EGLOT's `imenu-create-index-function'."
@@ -2549,7 +2450,7 @@ documentation. Honour `eglot-put-doc-in-help-buffer',
(unwind-protect
(if prepared (eglot--warn "Caution: edits of files %s failed."
(mapcar #'car prepared))
- (eglot-eldoc-function)
+ (eldoc)
(eglot--message "Edit successful!"))))))
(defun eglot-rename (newname)
- [elpa] externals/elpa 1cfcef4 37/71: Close #471: add support for erlang_ls, (continued)
- [elpa] externals/elpa 1cfcef4 37/71: Close #471: add support for erlang_ls, João Távora, 2020/12/16
- [elpa] externals/elpa da7ff48 31/71: Fix #468: don't call flymake report function if flymake is disabled, João Távora, 2020/12/16
- [elpa] externals/elpa e514f9e 29/71: Close #461: make CI fail if byte compiler warns, João Távora, 2020/12/16
- [elpa] externals/elpa ffe79b9 34/71: Pin pyls to 0.31.10, João Távora, 2020/12/16
- [elpa] externals/elpa b0bfbfb 38/71: Fix #488: fix type error in eglot--xref-make-match, João Távora, 2020/12/16
- [elpa] externals/elpa 3634402 36/71: Fix #479: correctly place diagnostics in narrowed buffers, João Távora, 2020/12/16
- [elpa] externals/elpa e7a43e2 40/71: Fix #480: also consider label of a CompletionItem for snippets, João Távora, 2020/12/16
- [elpa] externals/elpa a807b4f 43/71: Some test-related cleanup, João Távora, 2020/12/16
- [elpa] externals/elpa 9874456 42/71: Close #482: use filter-buffer-substring to get buffer text, João Távora, 2020/12/16
- [elpa] externals/elpa b34447c 45/71: Close #473: simplify eglot-code-actions, João Távora, 2020/12/16
- [elpa] externals/elpa a044dec 47/71: Delegate "hover" and "signature" doc synchronization efforts to Eldoc,
João Távora <=
- [elpa] externals/elpa a04b826 48/71: Update tests after update to newer Eldoc, João Távora, 2020/12/16
- [elpa] externals/elpa 2b7ec0e 51/71: Expect eglot-multiline-eldoc to fail on Travis, João Távora, 2020/12/16
- [elpa] externals/elpa 6d96601 52/71: Closes #509: fix sorting of completion items, João Távora, 2020/12/16
- [elpa] externals/elpa 4e82f53 53/71: Reload Eldoc if needed on Emacs < 28, João Távora, 2020/12/16
- [elpa] externals/elpa 8c9219d 55/71: Unbreak tests after changes to eldoc.el, João Távora, 2020/12/16
- [elpa] externals/elpa ea82b4b 57/71: Close #505: ensure completion terminates in correct buffer, João Távora, 2020/12/16
- [elpa] externals/elpa fb6b17e 58/71: New 'make interactive' target for debuggable M-x ert, João Távora, 2020/12/16
- [elpa] externals/elpa 5f873d2 60/71: Fix #521: Correct paren mismatch blunder introduced by earlier commit, João Távora, 2020/12/16
- [elpa] externals/elpa 209b227 61/71: Fix #524: provide suitable default to M-x eglot-rename, João Távora, 2020/12/16
- [elpa] externals/elpa 61b71ea 62/71: Fix #528: unbreak Haskell's hie-wrapper built-in incantation, João Távora, 2020/12/16