From: Dmitry Gutov <dgutov@yandex.ru>
To: "João Távora" <joaotavora@gmail.com>, 41531@debbugs.gnu.org
Cc: Stefan Monnier <monnier@iro.umontreal.ca>, andreyk.mad@gmail.com
Subject: bug#41531: 27.0.91; Better handle asynchronous eldoc backends
Date: Tue, 26 May 2020 02:52:58 +0300 [thread overview]
Message-ID: <4987863b-d390-5f87-eb1c-2cca4f4b7262@yandex.ru> (raw)
In-Reply-To: <875zckuet9.fsf@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1027 bytes --]
On 25.05.2020 20:04, João Távora wrote:
> Hi Stefan, Dmitry, Andrii and maintainers,
>
> Moving the discussion that started in
> https://github.com/joaotavora/eglot/pull/459 to the bug tracker, and
> attaching the two patches that contain what I think is a decent
> short-term solution to the eldoc/async problems.
Here's a modified approach that doesn't use a global var and should make
it easier to transition to using futures.
Patch attached. Example of usage:
(add-hook 'eldoc-documentation-functions
#'test-eldoc-async 0 t)
(defun test-eldoc-async ()
(cons :async
(lambda (cb)
(funcall cb "doc here!"))))
If you like, we could simplify the returned objects to be just FETCHER
(as documented in the patch) rather than (:async . FETCHER). But the
latter seems more explicit.
There also exist a possible modification of this patch with a bit of
functional programming where both calls to eldoc--handle-multiline
happen from inside of eldoc-documentation-default's definition.
[-- Attachment #2: eldoc-async-with-lexical-callback.diff --]
[-- Type: text/x-patch, Size: 5129 bytes --]
diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index ef5dbf8103..8909e8d431 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -5,7 +5,7 @@
;; Author: Noah Friedman <friedman@splode.com>
;; Keywords: extensions
;; Created: 1995-10-06
-;; Version: 1.0.0
+;; Version: 1.1.0
;; Package-Requires: ((emacs "26.3"))
;; This is a GNU ELPA :core package. Avoid functionality that is not
@@ -338,12 +338,26 @@ eldoc-display-message-no-interference-p
\f
(defvar eldoc-documentation-functions nil
- "Hook for functions to call to return doc string.
-Each function should accept no arguments and return a one-line
-string for displaying doc about a function etc. appropriate to
-the context around point. It should return nil if there's no doc
-appropriate for the context. Typically doc is returned if point
-is on a function-like name or in its arg list.
+ "Hook of functions that produce doc strings.
+Each hook function should accept no arguments and decide whether
+to display a doc short string about the context around point.
+
+Typically doc is returned if point is on a function-like name or
+in its arg list.
+
+If the decision and the doc string can be produced quickly, the
+hook function should immediately return the doc string, or nil if
+there's no doc appropriate for the context. Otherwise, if its
+computation is expensive or can't be performed directly, the
+function can instead return a cons (:async . FETCHER) where where
+FETCHER is a function of one argument, CALLBACK. When the result
+arrives, FETCHER must call CALLBACK and pass it the doc string to
+be displayed.
+
+A current limitation of the asynchronous case is that it is only
+guaranteed to work correctly if the value of
+`eldoc-documentation-function' (notice the singular) is
+`eldoc-documentation-default'.
Major modes should modify this hook locally, for example:
(add-hook \\='eldoc-documentation-functions #\\='foo-mode-eldoc nil t)
@@ -351,14 +365,18 @@ eldoc-documentation-functions
taken into account if the major mode specific function does not
return any documentation.")
+(defun eldoc--handle-multiline (res)
+ "Helper for handling a bit of `eldoc-echo-area-use-multiline-p'."
+ (if eldoc-echo-area-use-multiline-p res
+ (truncate-string-to-width
+ res (1- (window-width (minibuffer-window))))))
+
(defun eldoc-documentation-default ()
"Show first doc string for item at point.
Default value for `eldoc-documentation-function'."
(let ((res (run-hook-with-args-until-success 'eldoc-documentation-functions)))
- (when res
- (if eldoc-echo-area-use-multiline-p res
- (truncate-string-to-width
- res (1- (window-width (minibuffer-window))))))))
+ (cond ((stringp res) (eldoc--handle-multiline res))
+ (t res))))
(defun eldoc-documentation-compose ()
"Show multiple doc string results at once.
@@ -368,13 +386,11 @@ eldoc-documentation-compose
'eldoc-documentation-functions
(lambda (f)
(let ((str (funcall f)))
- (when str (push str res))
+ (when (stringp str) (push str res))
nil)))
(when res
(setq res (mapconcat #'identity (nreverse res) ", "))
- (if eldoc-echo-area-use-multiline-p res
- (truncate-string-to-width
- res (1- (window-width (minibuffer-window))))))))
+ (eldoc--handle-multiline res))))
(defcustom eldoc-documentation-function #'eldoc-documentation-default
"Function to call to return doc string.
@@ -417,11 +433,30 @@ eldoc-print-current-symbol-info
;; Erase the last message if we won't display a new one.
(when eldoc-last-message
(eldoc-message nil))
- (let ((non-essential t))
+ (let ((non-essential t)
+ (buffer (current-buffer)))
;; Only keep looking for the info as long as the user hasn't
;; requested our attention. This also locally disables inhibit-quit.
(while-no-input
- (eldoc-message (funcall eldoc-documentation-function)))))))
+ (let*
+ ((waiting-for-callback t)
+ (callback
+ (lambda (string)
+ (with-current-buffer buffer
+ ;; JT@2020-05-25: Currently, we expect one single
+ ;; docstring from the client, we silently swallow
+ ;; anything the client unexpectedly gives us,
+ ;; including updates. This could change.
+ (when waiting-for-callback
+ (setq waiting-for-callback nil)
+ (eldoc-message (eldoc--handle-multiline string))))))
+ (res
+ (funcall eldoc-documentation-function)))
+ (cond ((stringp res) (eldoc-message res))
+ ((and (consp res)
+ (eq (car res) :async))
+ (funcall (cdr res) callback))
+ (t (eldoc-message nil)))))))))
;; If the entire line cannot fit in the echo area, the symbol name may be
;; truncated or eliminated entirely from the output to make room for the
next prev parent reply other threads:[~2020-05-25 23:52 UTC|newest]
Thread overview: 84+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-05-25 17:04 bug#41531: 27.0.91; Better handle asynchronous eldoc backends João Távora
2020-05-25 23:52 ` Dmitry Gutov [this message]
2020-05-26 1:21 ` João Távora
2020-05-26 13:57 ` Dmitry Gutov
2020-05-26 16:03 ` João Távora
2020-05-26 19:14 ` Dmitry Gutov
2020-05-26 20:00 ` João Távora
2020-05-27 21:14 ` Dmitry Gutov
2020-05-27 22:13 ` João Távora
2020-05-27 23:35 ` Dmitry Gutov
2020-05-27 23:57 ` João Távora
2020-05-26 2:38 ` Stefan Monnier
2020-05-26 11:22 ` João Távora
2020-05-26 14:53 ` Stefan Monnier
2020-05-26 15:19 ` João Távora
2020-05-26 15:56 ` Stefan Monnier
2020-05-26 16:26 ` João Távora
2020-05-26 17:39 ` Stefan Monnier
2020-05-26 18:49 ` João Távora
2020-06-03 2:45 ` Stefan Monnier
2020-06-03 18:07 ` João Távora
2020-06-03 20:22 ` Stefan Monnier
2020-06-03 20:36 ` João Távora
2020-06-03 21:21 ` Stefan Monnier
2020-06-05 11:26 ` João Távora
2020-06-03 21:28 ` Dmitry Gutov
2020-06-06 1:57 ` Dmitry Gutov
2020-05-26 13:32 ` Dmitry Gutov
2020-05-26 16:56 ` João Távora
2020-06-03 18:56 ` bug#41531: 28.0.50; proper Eldoc async support João Távora
2020-06-04 16:20 ` Andrii Kolomoiets
2020-06-04 18:22 ` Dmitry Gutov
2020-06-04 19:00 ` Andrii Kolomoiets
2020-06-05 22:53 ` João Távora
2020-06-05 11:00 ` João Távora
2020-06-05 17:50 ` Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors
2020-06-05 23:25 ` João Távora
2020-06-05 23:28 ` João Távora
2020-06-11 11:11 ` Andrii Kolomoiets
2020-06-30 11:31 ` bug#41531: 27.0.91; Better handle asynchronous eldoc backends João Távora
2020-07-04 7:45 ` Eli Zaretskii
2020-07-04 9:21 ` João Távora
2020-07-04 9:31 ` Eli Zaretskii
2020-07-04 9:37 ` João Távora
2020-07-04 9:44 ` Eli Zaretskii
2020-07-04 11:00 ` João Távora
2020-07-04 21:06 ` Dmitry Gutov
2020-07-04 23:12 ` João Távora
2020-07-07 0:43 ` Dmitry Gutov
2020-07-07 10:58 ` João Távora
2020-07-07 14:18 ` Dmitry Gutov
2020-07-07 14:34 ` João Távora
2020-07-05 12:03 ` João Távora
2020-07-05 15:09 ` Eli Zaretskii
2020-07-05 15:13 ` Stefan Monnier
2020-07-04 10:04 ` Dmitry Gutov
2020-07-04 11:48 ` João Távora
2020-07-04 21:27 ` Dmitry Gutov
2020-07-04 21:30 ` Dmitry Gutov
2020-07-04 23:07 ` João Távora
2020-07-07 3:01 ` Dmitry Gutov
2020-07-07 10:56 ` João Távora
2020-07-07 12:23 ` João Távora
2020-07-07 13:38 ` Stefan Monnier
2020-07-07 14:24 ` Dmitry Gutov
2020-07-07 16:07 ` Stefan Monnier
2020-07-07 23:11 ` Dmitry Gutov
2020-07-08 3:58 ` Stefan Monnier
2020-07-08 11:20 ` Dmitry Gutov
2020-07-08 13:25 ` Stefan Monnier
2020-07-08 13:41 ` João Távora
2020-07-08 14:21 ` Dmitry Gutov
2020-07-08 15:12 ` João Távora
2020-07-08 18:32 ` Dmitry Gutov
2020-07-08 19:12 ` Eli Zaretskii
2020-07-07 14:45 ` João Távora
2020-07-07 14:40 ` Dmitry Gutov
2020-07-07 22:24 ` Dmitry Gutov
2020-07-07 22:49 ` João Távora
2020-07-07 23:00 ` Dmitry Gutov
2020-07-07 23:24 ` João Távora
2020-07-07 23:42 ` Dmitry Gutov
2020-07-07 23:46 ` João Távora
2020-07-08 0:10 ` Dmitry Gutov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4987863b-d390-5f87-eb1c-2cca4f4b7262@yandex.ru \
--to=dgutov@yandex.ru \
--cc=41531@debbugs.gnu.org \
--cc=andreyk.mad@gmail.com \
--cc=joaotavora@gmail.com \
--cc=monnier@iro.umontreal.ca \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).