emacs-elpa-diffs
[Top][All Lists]
Advanced

[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)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]