From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: =?UTF-8?Q?Jo=C3=A3o_?= =?UTF-8?Q?T=C3=A1vora?= Newsgroups: gmane.emacs.bugs Subject: bug#41531: 27.0.91; Better handle asynchronous eldoc backends Date: Tue, 26 May 2020 19:49:04 +0100 Message-ID: <871rn6r0pr.fsf@gmail.com> References: <875zckuet9.fsf@gmail.com> <4987863b-d390-5f87-eb1c-2cca4f4b7262@yandex.ru> <87blmbrlda.fsf@gmail.com> <87pnaqrae9.fsf@gmail.com> <877dwyr7b9.fsf@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="100177"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.91 (gnu/linux) Cc: Christopher Wellons , Dmitry Gutov , andreyk.mad@gmail.com, 41531@debbugs.gnu.org To: Stefan Monnier Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Tue May 26 20:50:18 2020 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jdeeX-000Q0Z-OU for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 26 May 2020 20:50:17 +0200 Original-Received: from localhost ([::1]:50392 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jdeeW-0007qr-Lu for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 26 May 2020 14:50:16 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:35920) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jdeeK-0007qW-19 for bug-gnu-emacs@gnu.org; Tue, 26 May 2020 14:50:04 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:34835) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1jdeeI-0006jp-B9 for bug-gnu-emacs@gnu.org; Tue, 26 May 2020 14:50:03 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1jdeeI-0001oG-97 for bug-gnu-emacs@gnu.org; Tue, 26 May 2020 14:50:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: =?UTF-8?Q?Jo=C3=A3o_?= =?UTF-8?Q?T=C3=A1vora?= Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 26 May 2020 18:50:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 41531 X-GNU-PR-Package: emacs Original-Received: via spool by 41531-submit@debbugs.gnu.org id=B41531.15905189636904 (code B ref 41531); Tue, 26 May 2020 18:50:02 +0000 Original-Received: (at 41531) by debbugs.gnu.org; 26 May 2020 18:49:23 +0000 Original-Received: from localhost ([127.0.0.1]:46381 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jdeda-0001nE-SB for submit@debbugs.gnu.org; Tue, 26 May 2020 14:49:23 -0400 Original-Received: from mail-wm1-f45.google.com ([209.85.128.45]:51398) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1jdedW-0001my-QD for 41531@debbugs.gnu.org; Tue, 26 May 2020 14:49:17 -0400 Original-Received: by mail-wm1-f45.google.com with SMTP id u13so622593wml.1 for <41531@debbugs.gnu.org>; Tue, 26 May 2020 11:49:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=qKDBWxM5ME9WV0JKLHRjiPEUyHxSlaspu6+8OnRo83E=; b=ub5lbg9otsw8uTPDkuHd1EaEGblIvZt8cYkwWtw2lQD1Rz7rfN68a2bJHFCTNQFP4L vDD3E6+tP7XjCUA2JqSZTZN0lrbWQQ0vkiWZIB97r/kG8YTdBT83DzsCA/C5hldois5M oNw5agIUxNIe6PDBqgUUMf+5QDCkhyt7/jTydiT0m73EKD2K6DtRl5+5vz4lI2J/2IQh o3+W4H+LjKCyl/XY74gSCHO9IIJVtdrm/MZZs15bj3Ig3WVhwtTnjRpsp4+yqVAzUayK cIGLkeJK+3d4PocCTS2Intn+EN4vJjUi+iK+hxc6dlQOuAdtfMaANljXz+2oB9oqqy8Q zztA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=qKDBWxM5ME9WV0JKLHRjiPEUyHxSlaspu6+8OnRo83E=; b=neDY4h+PDDJyZW/STN0PPJA9E1PboIHtkFl4mZaOLN4XW8z2Iu2x9H6boy8ENUdqGg kGjG6TOevah6xdAZteYzX98WfyTjyHAMOFZS2Jbq0jFKqvfqaLkjXbHOxOpAvrioqWHJ h1+tEBvNdZWISMv0/rXHvexgizgz9p5G2jeQk0wf4IqvGgFy54/Qa5AMRjlq4ciJUorZ H8a6fg44foT9nUKoBlvhCUktjcnakHXwga8KYWmUlEjFwC8pCp7X1B17kaxVGiz3JhzE 1b9EJyWJDC4FoeJ+rAWnM4dwV3MhW+oS2y5AHa86rFMyAFh+rJSDAVC6PnkbgzXsAOH/ 4FHQ== X-Gm-Message-State: AOAM530ePQE8ZOIdjDjtShHr23dlaR3Mp4UgNCe1+6+KDpu6byFot2Vh JpbeRF3Y0yHmYhlHujtufJw= X-Google-Smtp-Source: ABdhPJz2Eu2NW9XgG0G3QUjxyTZKsy0ybbQZ8EnW9zdYFXo7vkXCEUa8/mwg0bVQVOmzjl/JJPUDCA== X-Received: by 2002:a1c:f301:: with SMTP id q1mr519221wmq.109.1590518947774; Tue, 26 May 2020 11:49:07 -0700 (PDT) Original-Received: from krug ([89.180.149.243]) by smtp.gmail.com with ESMTPSA id 190sm387910wmb.23.2020.05.26.11.49.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2020 11:49:06 -0700 (PDT) In-Reply-To: (Stefan Monnier's message of "Tue, 26 May 2020 13:39:34 -0400") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:181065 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Stefan Monnier writes: >> It is, yes. The code is clear, not transcendental at all. But writing >> docstrings is hard. In fact, it's possibly the hardest part of the >> game. Tell you what: you write the docstring for >> eldoc-documentation-functions, I'll do the implementation. >> >> Deal? > > Deal, at the condition that the code comes before I write the docstrings = ;-) Okay. 2 patches attached (my version + your futures). Just search for 'WORLD CLASS DOCSTRING' and fill in your part. For my part, really feels like I've reimplemented funcall. Anyway both approaches lightly tested on this foo.el file: ;;; foo.el --- foobarbaz -*- lexical-binding:t; -*- (setq-local eldoc-documentation-function #'eldoc-documentation-compose) ;; Callback approach ;; (setq-local eldoc-documentation-functions nil) (defun eldoc-cback-0 (cback &rest _) (run-with-timer 0.22 nil (lambda () (funcall cback (symbol-name (gensym "cback-0-"= )))))) (defun eldoc-cback-1 (&rest _) (symbol-name (gensym "cback-1-"))) (defun eldoc-cback-2 (cback &rest _) (run-with-timer 2.22 nil (lambda () (funcall cback (symbol-name (gensym "cback-2-"= )))))) (add-hook 'eldoc-documentation-functions #'eldoc-cback-0 00 t) (add-hook 'eldoc-documentation-functions #'eldoc-cback-1 10 t) (add-hook 'eldoc-documentation-functions #'eldoc-cback-2 20 t) ;; Very futuristic approach ;; (setq-local eldoc-documentation-functions nil) (defun eldoc-future-0 () (let ((f (eldoc-future-make)))=20 (run-with-timer 0.22 nil (lambda () (eldoc-future-set f (symbol-name (gensym "future-0-"= ))))) f)) (defun eldoc-future-1 () (symbol-name (gensym "future-1-"))) (defun eldoc-future-2 () (let ((f (eldoc-future-make))) (run-with-timer 2.22 nil (lambda () (eldoc-future-set f (symbol-name (gensym "future-2-"= ))))) f)) (add-hook 'eldoc-documentation-functions #'eldoc-future-0 00 t) (add-hook 'eldoc-documentation-functions #'eldoc-future-1 10 t) (add-hook 'eldoc-documentation-functions #'eldoc-future-2 20 t) > [ I like this deal: it's always better for someone else to write the > docstrings, so at least 2 persons need to agree on what they think the > code does (assuming the author of the code checks the resulting docstri= ngs). ] Yes, it's called cascade dev, and it gets a bad rep nowadays. Tho the person who writes the docstrings usually goes first ;-) Jo=C3=A3o --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=0001-Better-handle-asynchronously-produced-eldoc-docstrin.patch >From b97c0cfb0cbfea20cbf75ad7ea8abf9f4c51ec54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Mon, 25 May 2020 16:39:40 +0100 Subject: [PATCH 1/2] Better handle asynchronously produced eldoc docstrings No longer do clients of eldoc need to call eldoc-message (an internal function) directly. They may return any non-nil, non-string value and call a callback afterwards. This enables eldoc.el to exert control over how (and crucially also when) to display the docstrings to the user. * lisp/emacs-lisp/eldoc.el (eldoc-documentation-functions): Overhaul docstring. (eldoc-documentation-compose, eldoc-documentation-default): Handle non-nil, non-string values of elements of eldoc-documentation-functions. (eldoc-print-current-symbol-info): Redesign. (eldoc--handle-multiline): New helper. (eldoc--callback): New internal special var. (Version): Bump to 1.1.0. * lisp/hexl.el (hexl-print-current-point-info): Adjust to new eldoc-documentation-functions protocol. * lisp/progmodes/cfengine.el (cfengine3-documentation-function): Adjust to new eldoc-documentation-functions protocol. * lisp/progmodes/elisp-mode.el (elisp-eldoc-documentation-function): Adjust to new eldoc-documentation-functions protocol. * lisp/progmodes/octave.el (octave-eldoc-function): Adjust to new eldoc-documentation-functions protocol. * lisp/progmodes/python.el (python-eldoc-function): Adjust to new eldoc-documentation-functions protocol. --- lisp/emacs-lisp/eldoc.el | 101 ++++++++++++++++++++++++++--------- lisp/hexl.el | 2 +- lisp/progmodes/cfengine.el | 2 +- lisp/progmodes/elisp-mode.el | 6 ++- lisp/progmodes/octave.el | 4 +- lisp/progmodes/python.el | 2 +- 6 files changed, 84 insertions(+), 33 deletions(-) diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index ef5dbf8103..fa36987014 100644 --- a/lisp/emacs-lisp/eldoc.el +++ b/lisp/emacs-lisp/eldoc.el @@ -5,7 +5,7 @@ ;; Author: Noah Friedman ;; 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,24 @@ eldoc-display-message-no-interference-p (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 at least one argument CALLBACK +and decide whether to display a doc short string about the +context around point. If the decision and the doc string can be +produced quickly, the hook function can ignore CALLBACK and +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 hook function +should arrange for CALLBACK to be asynchronously called at a +later time, passing it either nil or the desired doc string. The +hook function should then return a non-nil, non-string value. + +Note that this hook is only in effect if the value of +`eldoc-documentation-function' (notice the singular) is bound to +one of its pre-set values. + +Typically doc is returned if point is on a function-like name or +in its arg list. Major modes should modify this hook locally, for example: (add-hook \\='eldoc-documentation-functions #\\='foo-mode-eldoc nil t) @@ -351,30 +363,30 @@ 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)))))))) + (run-hook-with-args-until-success 'eldoc-documentation-functions + eldoc--callback)) (defun eldoc-documentation-compose () "Show multiple doc string results at once. Meant as a value for `eldoc-documentation-function'." - (let (res) - (run-hook-wrapped - 'eldoc-documentation-functions - (lambda (f) - (let ((str (funcall f))) - (when 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)))))))) + (let ((res 0)) + (run-hook-wrapped 'eldoc-documentation-functions + (lambda (f) + (let ((str (funcall f eldoc--callback))) + (if (stringp str) (funcall eldoc--callback str) + (when str (setq res (1+ res)))) + nil))) + ;; play ball with `eldoc-print-current-symbol-info' + (if (plusp res) (1- res) ""))) (defcustom eldoc-documentation-function #'eldoc-documentation-default "Function to call to return doc string. @@ -408,6 +420,11 @@ eldoc--supported-p ;; there's some eldoc support in the current buffer. (local-variable-p 'eldoc-documentation-function)))) +;; this variable should be unbound, but that confuses +;; `describe-symbol' for some reason. +(defvar eldoc--callback nil + "Dynamically bound. Passed to `eldoc-documentation-functions'.") + (defun eldoc-print-current-symbol-info () "Print the text produced by `eldoc-documentation-function'." ;; This is run from post-command-hook or some idle timer thing, @@ -417,11 +434,43 @@ 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* (;; `wanted' and `received' keep track of how many + ;; docstrings we expect from the clients. negative + ;; `wanted' means store docstring for later but don't + ;; message yet; likewise for a positive value, but we + ;; decrease it by one. Any other value (including 0) + ;; means the next time the callback is called we're + ;; composing and outputting whatever we got. + (wanted -1) (received '()) + (eldoc--callback + (lambda (string) + (with-current-buffer buffer + (cond ((and (numberp wanted) (not (zerop wanted))) + (if (plusp wanted) + (setq wanted (1- wanted))) ; decf where art thou? + (push string received)) + (wanted + (unless (string= string "") (push string received)) + (setq wanted nil) + (eldoc-message + (eldoc--handle-multiline + (mapconcat #'identity (nreverse received) ", ")))) + (t + ;; For now, silently swallow anything the + ;; client unexpectedly gives us + ))))) + (res (funcall eldoc-documentation-function))) + (cond (;; we got a string, we should output immediately + (stringp res) (setq wanted t) (funcall eldoc--callback res)) + (;; got something else, trust eldoc--callback will be called + res (setq wanted res)) + (;; got nil, clear the echo area + 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 diff --git a/lisp/hexl.el b/lisp/hexl.el index cf7118f208..38eca77e26 100644 --- a/lisp/hexl.el +++ b/lisp/hexl.el @@ -515,7 +515,7 @@ hexl-current-address (message "Current address is %d/0x%08x" hexl-address hexl-address)) hexl-address)) -(defun hexl-print-current-point-info () +(defun hexl-print-current-point-info (&rest _ignored) "Return current hexl-address in string. This function is intended to be used as eldoc callback." (let ((addr (hexl-current-address))) diff --git a/lisp/progmodes/cfengine.el b/lisp/progmodes/cfengine.el index f25b3cb9e2..9a6d81ce06 100644 --- a/lisp/progmodes/cfengine.el +++ b/lisp/progmodes/cfengine.el @@ -1294,7 +1294,7 @@ cfengine3-make-syntax-cache 'symbols)) syntax))) -(defun cfengine3-documentation-function () +(defun cfengine3-documentation-function (&rest _ignored) "Document CFengine 3 functions around point. Intended as the value of `eldoc-documentation-function', which see. Use it by enabling `eldoc-mode'." diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index d37eb8c152..d7865a7319 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -1402,8 +1402,10 @@ elisp--eldoc-last-data or argument string for functions. 2 - `function' if function args, `variable' if variable documentation.") -(defun elisp-eldoc-documentation-function () - "`eldoc-documentation-function' (which see) for Emacs Lisp." +(defun elisp-eldoc-documentation-function (_ignored &rest _also-ignored) + "Contextual documentation function for Emacs Lisp. +Intended to be placed in `eldoc-documentation-functions' (which +see)." (let ((current-symbol (elisp--current-symbol)) (current-fnsym (elisp--fnsym-in-current-sexp))) (cond ((null current-fnsym) diff --git a/lisp/progmodes/octave.el b/lisp/progmodes/octave.el index 352c1810d1..2cf305c404 100644 --- a/lisp/progmodes/octave.el +++ b/lisp/progmodes/octave.el @@ -1639,8 +1639,8 @@ octave-eldoc-function-signatures (nreverse result))))) (cdr octave-eldoc-cache)) -(defun octave-eldoc-function () - "A function for `eldoc-documentation-function' (which see)." +(defun octave-eldoc-function (&rest _ignored) + "A function for `eldoc-documentation-functions' (which see)." (when (inferior-octave-process-live-p) (let* ((ppss (syntax-ppss)) (paren-pos (cadr ppss)) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 1ca9f01963..404a67ba9f 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -4571,7 +4571,7 @@ python-eldoc-function-timeout-permanent :type 'boolean :version "25.1") -(defun python-eldoc-function () +(defun python-eldoc-function (&rest _ignored) "`eldoc-documentation-function' for Python. For this to work as best as possible you should call `python-shell-send-buffer' from time to time so context in -- 2.20.1 --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=0002-Reimplement-funcall-but-in-the-future.patch >From c039a4356fa363ef10b8320c3856eb3466eb32f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Tue, 26 May 2020 19:38:08 +0100 Subject: [PATCH 2/2] Reimplement funcall, but in the future * lisp/emacs-lisp/eldoc.el (eldoc-future, eldoc-future-set) (eldoc-future-set-call): New functions. (eldoc-documentation-functions): Prepare for Stefan's genius docstring. (eldoc-documentation-default, eldoc-documentation-compose): Use futuristic stuff. --- lisp/emacs-lisp/eldoc.el | 54 ++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index fa36987014..e015076c4d 100644 --- a/lisp/emacs-lisp/eldoc.el +++ b/lisp/emacs-lisp/eldoc.el @@ -337,18 +337,32 @@ eldoc-display-message-no-interference-p (not (or executing-kbd-macro (bound-and-true-p edebug-active)))) +;;;; Futuristic interlude +(cl-defstruct (eldoc-future + (:conc-name eldoc-future--) + (:constructor eldoc-future-make ())) ; become Yoda we? + "" + (value 'eldoc-future--unset) + callback) + +(defun eldoc-future-set (f v) + "" + (cl-assert (eq (eldoc-future--value f) 'eldoc-future--unset)) + (setf (eldoc-future--value f) v) + (when (eldoc-future--callback f) + (funcall (eldoc-future--callback f) v))) + +(defun eldoc-future-set-callback (f c) + "" + (cl-assert (null (eldoc-future--callback f))) + (setf (eldoc-future--callback f) c) + (unless (eq (eldoc-future--value f) 'eldoc-future--unset) + (funcall c (eldoc-future--value f)))) + + (defvar eldoc-documentation-functions nil "Hook of functions that produce doc strings. -Each hook function should accept at least one argument CALLBACK -and decide whether to display a doc short string about the -context around point. If the decision and the doc string can be -produced quickly, the hook function can ignore CALLBACK and -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 hook function -should arrange for CALLBACK to be asynchronously called at a -later time, passing it either nil or the desired doc string. The -hook function should then return a non-nil, non-string value. + Note that this hook is only in effect if the value of `eldoc-documentation-function' (notice the singular) is bound to @@ -372,19 +386,23 @@ eldoc--handle-multiline (defun eldoc-documentation-default () "Show first doc string for item at point. Default value for `eldoc-documentation-function'." - (run-hook-with-args-until-success 'eldoc-documentation-functions - eldoc--callback)) + (let ((x (run-hook-with-args-until-success 'eldoc-documentation-functions))) + (if (eldoc-future-p x) (eldoc-future-set-callback x eldoc--callback) + x))) (defun eldoc-documentation-compose () "Show multiple doc string results at once. Meant as a value for `eldoc-documentation-function'." (let ((res 0)) - (run-hook-wrapped 'eldoc-documentation-functions - (lambda (f) - (let ((str (funcall f eldoc--callback))) - (if (stringp str) (funcall eldoc--callback str) - (when str (setq res (1+ res)))) - nil))) + (run-hook-wrapped + 'eldoc-documentation-functions + (lambda (f) + (let ((x (funcall f))) + (cond ((stringp x) (funcall eldoc--callback x)) + ((eldoc-future-p x) + (eldoc-future-set-callback x eldoc--callback) + (setq res (1+ res)))) + nil))) ;; play ball with `eldoc-print-current-symbol-info' (if (plusp res) (1- res) ""))) -- 2.20.1 --=-=-=--