* bug#41531: 27.0.91; Better handle asynchronous eldoc backends @ 2020-05-25 17:04 João Távora 2020-05-25 23:52 ` Dmitry Gutov ` (2 more replies) 0 siblings, 3 replies; 84+ messages in thread From: João Távora @ 2020-05-25 17:04 UTC (permalink / raw) To: 41531; +Cc: Stefan Monnier, andreyk.mad, Dmitry Gutov [-- Attachment #1: Type: text/plain, Size: 827 bytes --] 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. It makes eldoc-diagnostic-functions have a very similar interface to flymake-diagnostic-functions. Flymake's handling of the multiple backends and async is more sophisticated, and we could extend eldoc to try similarly heroic stuff, if we do find there's a demand for it. The main thing you probably want to read if `eldoc-documentation-functions`'s new docstring. This was tested summarily with Eglot, by the way, and seems to work OK. Enjoy! João PS: How do I mark that the bug report contains a patch in the mail message itself? [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Better-handle-asynchronously-produced-eldoc-docstrin.patch --] [-- Type: text/x-diff, Size: 6825 bytes --] From 9ca84e5482b2e7ef40f80679ec508afb008293ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= <joaotavora@gmail.com> 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. Use eldoc--handle-multiline. (eldoc-print-current-symbol-info): Honour non-nil, non-string values returned by eldoc-documentation-callback. (eldoc--handle-multiline): New helper. (Version): Bump to 1.1.0. --- lisp/emacs-lisp/eldoc.el | 73 ++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index ef5dbf8103..f5dcdb4ea0 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. 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 hook +function should save the value bound to +`eldoc-documentation-callback', and arrange for that callback +function 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. + +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'. + +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,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. @@ -408,6 +424,12 @@ 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-documentation-callback nil + "Dynamically bound. Accessible to `eldoc-documentation-functions'. +See that function for details.") + (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 +439,28 @@ 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 nil) + (eldoc-documentation-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 + (eldoc-message (eldoc--handle-multiline string)) + (setq waiting-for-callback nil))))) + (res + (funcall eldoc-documentation-function))) + (cond ((stringp res) (eldoc-message res)) + (res (setq waiting-for-callback t)) + (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 -- 2.20.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-Adjust-eldoc-documentation-functions-protocol-for-be.patch --] [-- Type: text/x-diff, Size: 8347 bytes --] From a6ba9972ee0e3305c7b41fd380a88dd18a6626a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= <joaotavora@gmail.com> Date: Mon, 25 May 2020 17:38:23 +0100 Subject: [PATCH 2/2] Adjust eldoc-documentation-functions protocol for better async Instead of exposing a eldoc-documentation-callback variable to clients, just pass it the callback as the first argument. * lisp/emacs-lisp/eldoc.el (eldoc-documentation-functions): Rewrite docstring. (eldoc-documentation-default, eldoc-documentation-compose): Use internal eldoc--callback. (eldoc-documentation-callback). (eldoc---callback): Rename from eldoc-documentation-callback. (eldoc-print-current-symbol-info): Bind eldoc--callback. * 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 | 45 ++++++++++++++++++------------------ 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, 32 insertions(+), 29 deletions(-) diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index f5dcdb4ea0..a4e1e460ac 100644 --- a/lisp/emacs-lisp/eldoc.el +++ b/lisp/emacs-lisp/eldoc.el @@ -339,22 +339,22 @@ eldoc-display-message-no-interference-p \f (defvar eldoc-documentation-functions nil "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. 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 hook -function should save the value bound to -`eldoc-documentation-callback', and arrange for that callback -function 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. - -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'. +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. Furthermore, the asynchronous +mechanism described above is only guaranteed to work correctly if +that value is `eldoc-documentation-default'. Typically doc is returned if point is on a function-like name or in its arg list. @@ -374,7 +374,9 @@ eldoc--handle-multiline (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))) + (let ((res (run-hook-with-args-until-success + 'eldoc-documentation-functions + eldoc--callback))) (cond ((stringp res) (eldoc--handle-multiline res)) (t res)))) @@ -385,7 +387,7 @@ eldoc-documentation-compose (run-hook-wrapped 'eldoc-documentation-functions (lambda (f) - (let ((str (funcall f))) + (let ((str (funcall f eldoc--callback))) (when (stringp str) (push str res)) nil))) (when res @@ -426,9 +428,8 @@ eldoc--supported-p ;; this variable should be unbound, but that confuses ;; `describe-symbol' for some reason. -(defvar eldoc-documentation-callback nil - "Dynamically bound. Accessible to `eldoc-documentation-functions'. -See that function for details.") +(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'." @@ -446,7 +447,7 @@ eldoc-print-current-symbol-info (while-no-input (let* ((waiting-for-callback nil) - (eldoc-documentation-callback + (eldoc--callback (lambda (string) (with-current-buffer buffer ;; JT@2020-05-25: Currently, we expect one single 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 ^ permalink raw reply related [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 2020-05-26 1:21 ` João Távora 2020-05-26 2:38 ` Stefan Monnier 2020-06-03 18:56 ` bug#41531: 28.0.50; proper Eldoc async support João Távora 2020-06-30 11:31 ` bug#41531: 27.0.91; Better handle asynchronous eldoc backends João Távora 2 siblings, 2 replies; 84+ messages in thread From: Dmitry Gutov @ 2020-05-25 23:52 UTC (permalink / raw) To: João Távora, 41531; +Cc: Stefan Monnier, andreyk.mad [-- 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 ^ permalink raw reply related [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-25 23:52 ` Dmitry Gutov @ 2020-05-26 1:21 ` João Távora 2020-05-26 13:57 ` Dmitry Gutov 2020-05-26 2:38 ` Stefan Monnier 1 sibling, 1 reply; 84+ messages in thread From: João Távora @ 2020-05-26 1:21 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: > On 25.05.2020 20:04, João Távora wrote: > (add-hook 'eldoc-documentation-functions > #'test-eldoc-async 0 t) > > (defun test-eldoc-async () > (cons :async > (lambda (cb) > (funcall cb "doc here!")))) Thanks. As I told you, it's not bad. These aren't exactly "futures" though, they're a way to simulate argument passing. I prefer my version, which matches what flymake.el, url.el, jsonrpc.el, sly.el and others do. > 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. Yes, if we do go with your version, I'd like that. The latter is hard to read and understand from the docstring. Before I go any further I'd like Stefan and Andrey (or others) to weigh in. I don't have a lot of time to invest here, so if there is another vote for your proposal, I'm not going to wrestle here. To simplify, hopefully you agree that your proposal can be summarized as: "return a function that receives a function that you should call with the docstring" whereas my proposal can be summarized as: "receive a function that you should call with the docstring" > 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. Yes, that's independent of the shape of the callback we want to use. I'll leave that for later. Specifically, eldoc--handle-multiline has to do quite a bit more handling (to satisfy Andrey's expectations). Replying to parts from the other discussion in the Github tracker now. > OK, another question: if the result still /valid/? ^^ Assuming you mean "is". Well, if the client discovers the result to be invalid, it can not call the callback, or signal an error. If it is valid, call the callback. > No idea, a hypothetical one. It's an open API, not everybody is or > will be using LSP until the end of time. And it doesn't really have to > be huge. A saving is a saving. There's no free lunch. A very small saving in time for more complexity is bad. That's what overengineered means. > You can certainly kill the external process outside of it. Saving on > CPU expenses in general. The future's creditor is the only one who could do that to any useful effect. Does it have access to the process? Probably not. You would have to return a complex future with a kill switch. That's possible, but tricky, because you'd then have to be ready in the sentinel for another source of unexpected kills. > > For a poor man's async primitive, I prefer my version > So even the code savings didn't convince you? Both in eldoc.el, I do see minimal code savings in eldoc. You do remove a special variable (which is _not_ the same as a global variable, btw). I do see a much more complicated docstring, where the reader has to wrap his head around a 2-deep functional conundrum, whereas my version was 1-deep. Nothing special, but a VERY common source of headaches. Let's take your trivial example: (defun test-eldoc-async () (cons :async (lambda (cb) (funcall cb "doc here!")))) It isn't really representative of what a function that needs async would have to do, is it? Because, if you really wanted this very example, then it's much better to do the one-liner: (defun test-eldoc-async () "doc here!") Rather, presumably you would use this to fetch something from an HTTP server or so: (defun test-eldoc-async () (cons :async (lambda (cb) (url-retrieve-thingy "http://test-signature" cb)))) Where url-retrieve-thingy is very similar to our url-retrieve. Right? But why have that awkward :async there when a function is a first class object that we can identify with the functionp predicate? Let's just: (defun test-eldoc-async () (lambda (cb) (url-retrieve-thingy "http://test-signature" cb))) And at this point one wonders why the heck not (defun test-eldoc-async (cb) (url-retrieve-thingy "http://test-signature" cb)) ? > and likely in doc functions as well No. Unless I am completely mistaken (I might be), in the "doc function" not only are there no savings, but complication. This makes sense because you just inverted the responsibility: the doc function now has to "beg" for the argument that used to be given to it naturally. So, it's just a functional gimmick. As good as the next one, but a gimmick all the same. Until the "futures" are here, people will potentially bang heads in an anguished "WHY??". Why indeed? Your other argument, that this makes the transition to proper futures (such as the ones in https://github.com/skeeto/emacs-aio) easier, is questionable, too. There are two scenarios here: - You want to keep backward compatibility to this API published in eldoc 1.1.0 until the time of the Emacs 28 release: This is something that I -- and Stefan, if I'm not mistaken, -- don't think we should worry about. Just because a package is :core GNU ELPA doesn't necessarily mean we guarantee stability of its API. But if we do, then we'll have to explain in the docstring that there is a fourth return value for the hook functions. In my version we'll have to do exactly the same. - You don't want to keep backward compatibility until Emacs 28: Then, when the super-futures are here, you can just kill the CALLBACK arg if we find it doesn't fit and rewrite the docstring without concerns. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-05-26 13:57 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, andreyk.mad On 26.05.2020 04:21, João Távora wrote: > Dmitry Gutov <dgutov@yandex.ru> writes: > >> On 25.05.2020 20:04, João Távora wrote: >> (add-hook 'eldoc-documentation-functions >> #'test-eldoc-async 0 t) >> >> (defun test-eldoc-async () >> (cons :async >> (lambda (cb) >> (funcall cb "doc here!")))) > > Thanks. As I told you, it's not bad. These aren't exactly "futures" > though, they're a way to simulate argument passing. It's a simple stand-in, easy to replace. > I prefer my > version, which matches what flymake.el, url.el, jsonrpc.el, sly.el and > others do. They also use *special* variables? Flymake's API looks fairly clean (you call back to REPORTER-FN, that's very reasonable), but I haven't looked under the covers yet. >> 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. > > Yes, if we do go with your version, I'd like that. The latter is hard > to read and understand from the docstring. I think it's more explicit, and once you understand it, it clicks. But that choice is not important to me. > To simplify, hopefully you agree that your proposal can be summarized > as: > > "return a function that receives a function that you > should call with the docstring" > > whereas my proposal can be summarized as: > > "receive a function that you should call with the docstring" To clarify, you actually included two proposals (behavior with patch 1, and with both patch 1 and patch 2 applied). The first one is the one I really didn't like. The second one is better, API-wise, but will conflict with the futures-based approach. >> 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. > > Yes, that's independent of the shape of the callback we want to use. > I'll leave that for later. Specifically, eldoc--handle-multiline has to > do quite a bit more handling (to satisfy Andrey's expectations). I'm not so such it's independent. The complexity of implementing that would certainly vary. BTW, maybe eldoc-message should handle this after all? Since it's the last link in the chain. Or even do that in the default value of eldoc-message-function (create a wrapper for minibuffer-message). > Replying to parts from the other discussion in the Github tracker now. > >> OK, another question: if the result still /valid/? > ^^ Assuming you mean "is". > > Well, if the client discovers the result to be invalid, ... So the client will have to save and then compare the current buffer, the value of point and buffer-chars-modification-tick now? >> No idea, a hypothetical one. It's an open API, not everybody is or >> will be using LSP until the end of time. And it doesn't really have to >> be huge. A saving is a saving. > > There's no free lunch. A very small saving in time for more complexity > is bad. That's what overengineered means. Futures are not particularly more complex to use. >> You can certainly kill the external process outside of it. Saving on >> CPU expenses in general. > > The future's creditor is the only one who could do that to any useful > effect. Does it have access to the process? Probably not. It can (barring any complex abstractions). It created the process, after all. > You would > have to return a complex future with a kill switch. That's possible, > but tricky, because you'd then have to be ready in the sentinel for > another source of unexpected kills. That would be none of ElDoc's business, though. But the implementation will get to be as complex as it needs. > Why indeed? Your other argument, that this makes the transition to > proper futures (such as the ones in https://github.com/skeeto/emacs-aio) > easier, is questionable, too. There are two scenarios here: > > - You want to keep backward compatibility to this API published in eldoc > 1.1.0 until the time of the Emacs 28 release: The one thing I want to avoid doing is changing the callsig of every documentation function, and then changing them back when we switch to futures. > This is something that I -- and Stefan, if I'm not mistaken, -- don't > think we should worry about. Just because a package is :core GNU ELPA > doesn't necessarily mean we guarantee stability of its API. Um, I'm pretty sure we guarantee a fair amount of stability. > But if we do, then we'll have to explain in the docstring that there > is a fourth return value for the hook functions. In my version we'll > have to do exactly the same. > > - You don't want to keep backward compatibility until Emacs 28: > > Then, when the super-futures are here, you can just kill the CALLBACK > arg if we find it doesn't fit and rewrite the docstring without > concerns. Kill the arg in all built-in functions, as well as in external consumers? ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-26 13:57 ` Dmitry Gutov @ 2020-05-26 16:03 ` João Távora 2020-05-26 19:14 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-05-26 16:03 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: > On 26.05.2020 04:21, João Távora wrote: >> Dmitry Gutov <dgutov@yandex.ru> writes: > They also use *special* variables? Flymake's API looks fairly clean > (you call back to REPORTER-FN, that's very reasonable), but I haven't > looked under the covers yet. REPORTER-FN, is just another name for CALLBACK. Flymake doesn't need these special variables because its API doesn't go through an old, argless shim like eldoc-documentation-function, singular. If it did, it would need a special variable, which is not such a ghoulish thing either. >> To simplify, hopefully you agree that your proposal can be summarized >> as: >> "return a function that receives a function that you >> should call with the docstring" >> whereas my proposal can be summarized as: >> "receive a function that you should call with the docstring" > > To clarify, you actually included two proposals (behavior with patch > 1, and with both patch 1 and patch 2 applied). The first one is the > one I really didn't like. The second one is better, API-wise, but will > conflict with the futures-based approach. It's not a conflict at all. When you do the futures-based approach you're going to rewrite the docstring to augment the API. You do the same here: just add this to the docstring: "If you prefer, ignore CALBACK and return a `future-future' object from this function". How is that different from: "If you prefer, instead of returning a (:ASYNC . FUNCTION) cons, return a `future-future' object from this function"" ??? >> I'll leave that for later. Specifically, eldoc--handle-multiline has to >> do quite a bit more handling (to satisfy Andrey's expectations). > I'm not so such it's independent. The complexity of implementing that > would certainly vary. It is quite independent. Just look at the last patch I sent Stefan. There's only one call to eldoc--handle-multiline (in fact we could ditch it entirely). > BTW, maybe eldoc-message should handle this after all? Since it's the > last link in the chain. Or even do that in the default value of > eldoc-message-function (create a wrapper for minibuffer-message). Doesn't work well becasue eldoc-message is called by both the produced _and_ the backend, as I showed you earlier. And it certainly doesn't work with eldoc-documentation-compose. >> Replying to parts from the other discussion in the Github tracker now. >> >>> OK, another question: if the result still /valid/? >> ^^ Assuming you mean "is". >> Well, if the client discovers the result to be invalid, ... > > So the client will have to save and then compare the current buffer, > the value of point and buffer-chars-modification-tick now? Ah, _that_ validity. No, no, never do that. The client should have no idea of it. In the framework you either make the callback a noop, or you set it aborted for the client to save some work. Or both. >>> No idea, a hypothetical one. It's an open API, not everybody is or >>> will be using LSP until the end of time. And it doesn't really have to >>> be huge. A saving is a saving. >> There's no free lunch. A very small saving in time for more >> complexity >> is bad. That's what overengineered means. > > Futures are not particularly more complex to use. Sure, but they are _more_ complex. And you're mixing up two things: futures _aren't_ the only way -- or even a particularly easy way -- to signal to the clients that thety can give up their efforts. All the client needs to have is access to an object that's shared between it and the framework. That object _needn't_ be a first-class CLOS object or struct. It can be a function. >>> You can certainly kill the external process outside of it. Saving on >>> CPU expenses in general. >> The future's creditor is the only one who could do that to any >> useful >> effect. Does it have access to the process? Probably not. > > It can (barring any complex abstractions). It created the process, > after all. Not really, it asked a client to solve a problem, doesn't know how the client if the client is doing by async process or cointoss. >> You would have to return a complex future with a kill switch. That's >> possible, but tricky, because you'd then have to be ready in the >> sentinel for another source of unexpected kills. > > That would be none of ElDoc's business, though. But the implementation > will get to be as complex as it needs. _That's_ why an abort switch whose contract is "kill this immediately" is a bad idea. An abort switch whose contract is "just letting you know I don't need this anymore" is better. But again, in eldoc, not so useful. And again, nothing to do with futures here. >> Why indeed? Your other argument, that this makes the transition to >> proper futures (such as the ones in https://github.com/skeeto/emacs-aio) >> easier, is questionable, too. There are two scenarios here: >> - You want to keep backward compatibility to this API published in >> eldoc >> 1.1.0 until the time of the Emacs 28 release: > > The one thing I want to avoid doing is changing the callsig of every > documentation function, and then changing them back when we switch to > futures. So _don't_ change the "callsig". If you implement futures you _are_ going to change the protocol anyway, i.e. write new stuff in the docstring. >> This is something that I -- and Stefan, if I'm not mistaken, -- don't >> think we should worry about. Just because a package is :core GNU ELPA >> doesn't necessarily mean we guarantee stability of its API. > > Um, I'm pretty sure we guarantee a fair amount of stability. That's not what Stefan said here: https://github.com/joaotavora/eglot/pull/459#issuecomment-633634034 And that's not what the Dmitry from 2016 wrote in xref.el +;; NOTE: The xref API is still experimental and can change in major, +;; backward-incompatible ways. Everyone is encouraged to try it, and +;; report to us any problems or use cases we hadn't anticiated, by +;; sending an email to emacs-devel, or `M-x report-emacs-bug'. That has been sitting there for almost three Emacs major versions (in fact you added it after the initial 25 release). All I'm asking is for a little such flexibility with eldoc. >> But if we do, then we'll have to explain in the docstring that there >> is a fourth return value for the hook functions. In my version we'll >> have to do exactly the same. >> - You don't want to keep backward compatibility until Emacs 28: >> Then, when the super-futures are here, you can just kill the >> CALLBACK >> arg if we find it doesn't fit and rewrite the docstring without >> concerns. > > Kill the arg in all built-in functions, as well as in external > consumers? Yes, if we discover there aren't so many. Currently there are 5 users in Emacs proper, 0 in GNU ELPA and quite sure 0 elsewhere in the world. So 0 external consumers. Do you really think if I push my patch there will be hordes of eldoc-documentation-functions users out there using this horrible futureless API that I'm proposing? There won't, and I'm happy to add a big disclaimer to the top of the eldoc.el file. But if you really think we wouldn't be able to bring ourselves to kill the arg, then just reintroduce eldoc-documentation-callback, and kill _that_ later on. Or just don't kill the arg, period. It just looks like you're holding this problem hostage to introducing some kind of rushed futures solution. I don't agree with either of these things. I think this particular problem shouldn't be held hostage to rearchitecting async in Emacs, laudable and useful a goal as that might be. And I think a futures library should be well thought out: I'd like to discuss this in emacs-devel, at least get some opinions on Christopher Wellon's solution, which seems very elegant. In the meantime, I have a working patch that follows current coding practice, solves this problem and in no way prevents or interferes with future work. Anyway, see the patch I sent to Stefan. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-05-26 19:14 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, andreyk.mad On 26.05.2020 19:03, João Távora wrote: >>> To simplify, hopefully you agree that your proposal can be summarized >>> as: >>> "return a function that receives a function that you >>> should call with the docstring" >>> whereas my proposal can be summarized as: >>> "receive a function that you should call with the docstring" >> >> To clarify, you actually included two proposals (behavior with patch >> 1, and with both patch 1 and patch 2 applied). The first one is the >> one I really didn't like. The second one is better, API-wise, but will >> conflict with the futures-based approach. > > It's not a conflict at all. When you do the futures-based approach > you're going to rewrite the docstring to augment the API. You do the > same here: just add this to the docstring: > > "If you prefer, ignore CALBACK and return a `future-future' object from > this function". > > How is that different from: > > "If you prefer, instead of returning a (:ASYNC . FUNCTION) cons, > return a `future-future' object from this function"" > > ??? We're not going to do either. The :async option is only for those tho need async _right this second_. It would be fully replaced by the "futures" option. Or we can implement it right now. And hopefully we won't have to maintain the eldoc-specific futures "forever" either. >> BTW, maybe eldoc-message should handle this after all? Since it's the >> last link in the chain. Or even do that in the default value of >> eldoc-message-function (create a wrapper for minibuffer-message). > > Doesn't work well becasue eldoc-message is called by both the produced > _and_ the backend, as I showed you earlier. And it certainly doesn't > work with eldoc-documentation-compose. We could split it apart, I guess. Or make two versions. >>> Replying to parts from the other discussion in the Github tracker now. >>> >>>> OK, another question: if the result still /valid/? >>> ^^ Assuming you mean "is". >>> Well, if the client discovers the result to be invalid, ... >> >> So the client will have to save and then compare the current buffer, >> the value of point and buffer-chars-modification-tick now? > > Ah, _that_ validity. No, no, never do that. The client should have no > idea of it. In the framework you either make the callback a noop, or > you set it aborted for the client to save some work. Or both. So the abort thing. In pre-command-hook? >>>> No idea, a hypothetical one. It's an open API, not everybody is or >>>> will be using LSP until the end of time. And it doesn't really have to >>>> be huge. A saving is a saving. >>> There's no free lunch. A very small saving in time for more >>> complexity >>> is bad. That's what overengineered means. >> >> Futures are not particularly more complex to use. > > Sure, but they are _more_ complex. And you're mixing up two things: > futures _aren't_ the only way -- or even a particularly easy way -- to > signal to the clients that thety can give up their efforts. All the > client needs to have is access to an object that's shared between it and > the framework. That object _needn't_ be a first-class CLOS object or > struct. It can be a function. It's good to have a well-documented contract. Functions do _everything_. They can't be optimal for everything. And this way we don't add extra arguments, so whoever doesn't need async, doesn't need to change a thing. >>>> You can certainly kill the external process outside of it. Saving on >>>> CPU expenses in general. >>> The future's creditor is the only one who could do that to any >>> useful >>> effect. Does it have access to the process? Probably not. >> >> It can (barring any complex abstractions). It created the process, >> after all. > > Not really, it asked a client to solve a problem, doesn't know how the > client if the client is doing by async process or cointoss. Seems like we're miscommunicating. >>> You would have to return a complex future with a kill switch. That's >>> possible, but tricky, because you'd then have to be ready in the >>> sentinel for another source of unexpected kills. >> >> That would be none of ElDoc's business, though. But the implementation >> will get to be as complex as it needs. > > _That's_ why an abort switch whose contract is "kill this immediately" > is a bad idea. An abort switch whose contract is "just letting you know > I don't need this anymore" is better. But again, in eldoc, not so > useful. And again, nothing to do with futures here. Here as well. >>> Why indeed? Your other argument, that this makes the transition to >>> proper futures (such as the ones in https://github.com/skeeto/emacs-aio) >>> easier, is questionable, too. There are two scenarios here: >>> - You want to keep backward compatibility to this API published in >>> eldoc >>> 1.1.0 until the time of the Emacs 28 release: >> >> The one thing I want to avoid doing is changing the callsig of every >> documentation function, and then changing them back when we switch to >> futures. > > So _don't_ change the "callsig". If you implement futures you _are_ > going to change the protocol anyway, i.e. write new stuff in the > docstring. See above about not having to change anything. >>> This is something that I -- and Stefan, if I'm not mistaken, -- don't >>> think we should worry about. Just because a package is :core GNU ELPA >>> doesn't necessarily mean we guarantee stability of its API. >> >> Um, I'm pretty sure we guarantee a fair amount of stability. > > That's not what Stefan said here: > > https://github.com/joaotavora/eglot/pull/459#issuecomment-633634034 > > And that's not what the Dmitry from 2016 wrote in xref.el > > +;; NOTE: The xref API is still experimental and can change in major, > +;; backward-incompatible ways. Everyone is encouraged to try it, and > +;; report to us any problems or use cases we hadn't anticiated, by > +;; sending an email to emacs-devel, or `M-x report-emacs-bug'. > > That has been sitting there for almost three Emacs major versions (in > fact you added it after the initial 25 release). All I'm asking is for > a little such flexibility with eldoc. I wrote that for xref.el because that was the state of affairs, and xref was relatively new. Especially compared to eldoc. But we're probably miscommunicating here as well. >>> But if we do, then we'll have to explain in the docstring that there >>> is a fourth return value for the hook functions. In my version we'll >>> have to do exactly the same. >>> - You don't want to keep backward compatibility until Emacs 28: >>> Then, when the super-futures are here, you can just kill the >>> CALLBACK >>> arg if we find it doesn't fit and rewrite the docstring without >>> concerns. >> >> Kill the arg in all built-in functions, as well as in external >> consumers? > > Yes, if we discover there aren't so many. Currently there are 5 users > in Emacs proper, 0 in GNU ELPA and quite sure 0 elsewhere in the world. OK, I see your point: eldoc-documentation-functions is new. And apparently you don't intend to add this feature to the variable without "s". > It just looks like you're holding this problem hostage to introducing > some kind of rushed futures solution. I don't agree with either of > these things. Who's holding what hostage? I showed a smoother approach, you didn't like it. No big surprise about that. > I think this particular problem shouldn't be held hostage > to rearchitecting async in Emacs, laudable and useful a goal as that > might be. And I think a futures library should be well thought out: I'd > like to discuss this in emacs-devel, at least get some opinions on > Christopher Wellon's solution, which seems very elegant. We should certainly take a look at it. But the built-in futures don't have to provide all the options. Just be functionally compatible. Christopher could pick up from that. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-26 19:14 ` Dmitry Gutov @ 2020-05-26 20:00 ` João Távora 2020-05-27 21:14 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-05-26 20:00 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: >> no idea of it. In the framework you either make the callback a noop, >> or you set it aborted for the client to save some work. Or both. > > So the abort thing. In pre-command-hook? No, the creditor of the future or issuer of the callback aborts or invalidates the previous version just before issuing a new one. Nothing pre-command-hook here. Invalidation may or may not entail letting the holder of the callback know that the previous call became invalid. Flymake does this: by invoking a backend again with a new callback instance it is signalling that the preceding one became invalid. If the backend tries to call the previous callback, it is an error and the backend is disabled. > It's good to have a well-documented contract. Functions do > _everything_. They can't be optimal for everything. You're missing a Lisp point here. It doesn't matter if it's an CLOS object, a struct, a function or my beautiful singing voice: it just has to be an object which you can make unique instances of and can respond to funcall, still-wanted-p, (setf still-wanted-p), errored-p, and (setf errored-p). That's the contract. A function fits perfectly. >>>> The future's creditor is the only one who could do that to any >>>> useful effect. Does it have access to the process? Probably not. >>> It can (barring any complex abstractions). It created the process, >>> after all. >> Not really, it asked a client to solve a problem, doesn't know how >> the client if the client is doing by async process or cointoss. > Seems like we're miscommunicating. Well you implied that the creditor of the future (the caller who received) created the process. It does not. See the patch to Stefan. >> is a bad idea. An abort switch whose contract is "just letting you know >> I don't need this anymore" is better. But again, in eldoc, not so >> useful. And again, nothing to do with futures here. > > Here as well. OK. The takeaway is that "aborting a future" doesn't need any constructs specific to futures, is all. > See above about not having to change anything. But then we don't have to change anything in any case! I already changed EVERY user of eldoc-documentation-functions: every single one of the 5 in existence in the entire world. So we're all good. >> +;; NOTE: The xref API is still experimental and can change in >> major, >> +;; backward-incompatible ways. Everyone is encouraged to try it, and >> +;; report to us any problems or use cases we hadn't anticiated, by >> +;; sending an email to emacs-devel, or `M-x report-emacs-bug'. >> That has been sitting there for almost three Emacs major versions >> (in >> fact you added it after the initial 25 release). All I'm asking is for >> a little such flexibility with eldoc. > > I wrote that for xref.el because that was the state of affairs, and > xref was relatively new. Especially compared to eldoc. This part of eldoc.el is probably newer than xref.el was when you wrote that. > But we're probably miscommunicating here as well. Doubt it. > OK, I see your point: eldoc-documentation-functions is new. And > apparently you don't intend to add this feature to the variable > without "s". Yes, exactly. eldoc-documentation-function should be obsoleted IMO. >> It just looks like you're holding this problem hostage to introducing >> some kind of rushed futures solution. I don't agree with either of >> these things. > > Who's holding what hostage? I showed a smoother approach, you didn't > like it. No big surprise about that. Let me explain. First: it's clearly not "smoother", your're asking users to wrap their heads around a function that returns a function taking a function. That's not what I want to present to Eglot contributors, for instance. And I'm not too crazy with presenting them this "future thing" that is completely different from Eglot's use of Flymake, jsonrpc.el, completion-at-point, etc... In other words, my ambition is consistency and you seem to be denying it for reasons I can't understand, because nothing in the steps I am taking denies _your_ ambitions, which seem to be futures. That's why I speak of "hostage". João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-05-27 21:14 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, andreyk.mad On 26.05.2020 23:00, João Távora wrote: > Dmitry Gutov <dgutov@yandex.ru> writes: > >>> no idea of it. In the framework you either make the callback a noop, >>> or you set it aborted for the client to save some work. Or both. >> >> So the abort thing. In pre-command-hook? > > No, the creditor of the future or issuer of the callback aborts or > invalidates the previous version just before issuing a new one. Nothing > pre-command-hook here. Where/when would eldoc-mode do it? > Invalidation may or may not entail letting the > holder of the callback know that the previous call became invalid. Letting know the issuer of the future, you mean. > Flymake does this: by invoking a backend again with a new callback > instance it is signalling that the preceding one became invalid. If the > backend tries to call the previous callback, it is an error and the > backend is disabled. Worse is sometimes better, we know. >> It's good to have a well-documented contract. Functions do >> _everything_. They can't be optimal for everything. > > You're missing a Lisp point here. It doesn't matter if it's an CLOS > object, a struct, a function or my beautiful singing voice: it just has > to be an object which you can make unique instances of and can respond > to funcall, still-wanted-p, (setf still-wanted-p), errored-p, and (setf > errored-p). That's the contract. A function fits perfectly. That would be my "alternative" suggestion: for eldoc-documentation-functions elements to return a function (denoted as FETCHER in the docstring) if they want the async convention. >>>>> The future's creditor is the only one who could do that to any >>>>> useful effect. Does it have access to the process? Probably not. >>>> It can (barring any complex abstractions). It created the process, >>>> after all. >>> Not really, it asked a client to solve a problem, doesn't know how >>> the client if the client is doing by async process or cointoss. >> Seems like we're miscommunicating. > > Well you implied that the creditor of the future (the caller who > received) created the process. It does not. See the patch to Stefan. Okay, creditor != creator. But what you've said a few messages back (seen at the top of the quotes chain above) doesn't make sense: the creditor will call (future-abort fut), and the issuer of the future can make sure that this operation will indeed kill the process. That's the main idea behind aborting futures. Or canceling. Whatever term we're going to pick. >> See above about not having to change anything. > > But then we don't have to change anything in any case! I already > changed EVERY user of eldoc-documentation-functions: every single one of > the 5 in existence in the entire world. So we're all good. And then we'll need to change them back. And in the meantime, the new convention could get external users (some people do live on the bleeding edge), and this will get messier. >> OK, I see your point: eldoc-documentation-functions is new. And >> apparently you don't intend to add this feature to the variable >> without "s". > > Yes, exactly. eldoc-documentation-function should be obsoleted IMO. Perhaps. I'm also not buying the usefulness of eldoc-documentation-compose. >>> It just looks like you're holding this problem hostage to introducing >>> some kind of rushed futures solution. I don't agree with either of >>> these things. >> >> Who's holding what hostage? I showed a smoother approach, you didn't >> like it. No big surprise about that. > > Let me explain. First: it's clearly not "smoother", your're asking users > to wrap their heads around a function that returns a function taking a > function. That's not what I want to present to Eglot contributors, for > instance. Would they need to? As soon as an existing Eglot's implementation is in place, that exact part of the code wouldn't need to be touched often. In any case, you are over-exaggerating. This exact design has been a part of "asynchronous" backend calling convention in Company for years. And not once have I seen a complaint that it's overly complex. > And I'm not too crazy with presenting them this "future > thing" that is completely different from Eglot's use of Flymake, > jsonrpc.el, completion-at-point, etc... Didn't you say that Flymake could use futures as well? > In other words, my ambition is > consistency and you seem to be denying it for reasons I can't > understand, because nothing in the steps I am taking denies _your_ > ambitions, which seem to be futures. That's why I speak of "hostage". See above. But perhaps we should after all suspend this discussion until we had a chance to reach a better mutual understanding of the futures API, and how we expect it to help (or not). I promise to show some proposals in the near future. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-27 21:14 ` Dmitry Gutov @ 2020-05-27 22:13 ` João Távora 2020-05-27 23:35 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-05-27 22:13 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, Andrii Kolomoiets On Wed, May 27, 2020 at 10:14 PM Dmitry Gutov <dgutov@yandex.ru> wrote: > > No, the creditor of the future or issuer of the callback aborts or > > invalidates the previous version just before issuing a new one. Nothing > > pre-command-hook here. > > Where/when would eldoc-mode do it? In the idle timer function. That's when it decides it wants new info, and so any old info that hasn't arrived yet is probably out of date. But I think I understnad what you mean pre-command-hook. You suggested pre-command-hook because that's where you can check if point is far enough away from the place where the original request originated? That could work, but I'd prefer that the info to _do_ come in, because after that info is about the last time my point hung out at a particular position long enough to trigger a request. This is how Eglot, SLY and SLIME work, btw. > > Invalidation may or may not entail letting the > > holder of the callback know that the previous call became invalid. > > Letting know the issuer of the future, you mean. Or the holder of the callback depending on which abstraction we're talking about. I define the holder of the callback as he who is about to call it. > > Flymake does this: by invoking a backend again with a new callback > > instance it is signalling that the preceding one became invalid. If the > > backend tries to call the previous callback, it is an error and the > > backend is disabled. > > Worse is sometimes better, we know. That is a very confusing statement. > >> It's good to have a well-documented contract. Functions do > >> _everything_. They can't be optimal for everything. > > > > You're missing a Lisp point here. It doesn't matter if it's an CLOS > > object, a struct, a function or my beautiful singing voice: it just has > > to be an object which you can make unique instances of and can respond > > to funcall, still-wanted-p, (setf still-wanted-p), errored-p, and (setf > > errored-p). That's the contract. A function fits perfectly. > > That would be my "alternative" suggestion: for > eldoc-documentation-functions elements to return a function (denoted as > FETCHER in the docstring) if they want the async convention. They need to _receive_ an object produced externally, somhow. If they return a function as youv suggest, they are only doing so they can later _receive_ another object. This is needlessly complicated. To receive objects in some place, just use argument the argument list of that place. > > >>>>> The future's creditor is the only one who could do that to any > >>>>> useful effect. Does it have access to the process? Probably not. > >>>> It can (barring any complex abstractions). It created the process, > >>>> after all. > >>> Not really, it asked a client to solve a problem, doesn't know how > >>> the client if the client is doing by async process or cointoss. > >> Seems like we're miscommunicating. > > > > Well you implied that the creditor of the future (the caller who > > received) created the process. It does not. See the patch to Stefan. > > Okay, creditor != creator. But what you've said a few messages back > (seen at the top of the quotes chain above) doesn't make sense: the > creditor will call (future-abort fut), and the issuer of the future can > make sure that this operation will indeed kill the process. No, it does make sense. Read it again. What you're saying is what I meant. But that still means that the process sentinel will have to deal with out-of-band kills that it must distinguish from other out-of-band kills (such as, say, a kill -9 from the shell). That is added complexity. It is better, in my opinion, to make this softer. Let the creditor signal, I don't need this anymore, and the issuer will take appropriate measures synchronously, i.e. in the process filter and not in the process sentinel. > That's the main idea behind aborting futures. Or canceling. Whatever > term we're going to pick. But, again, nothing you're describing here can't be implemented with passing a callback in the arglist. It's independent. Futures particularly the versions you and Stefan are proposing are just other places to type basically the same sexps. They're a stylistic change over callbacks, but nothing more, fundamentally. > >> See above about not having to change anything. > > > > But then we don't have to change anything in any case! I already > > changed EVERY user of eldoc-documentation-functions: every single one of > > the 5 in existence in the entire world. So we're all good. > > And then we'll need to change them back. Nothing of the sort. > And in the meantime, the new > convention could get external users (some people do live on the bleeding > edge), and this will get messier. That's only if you assume you'll break compatibility, because you dislike callbacks so much that you want to close off the arglist forever. But not only may users may not dislike them, they may even prefer them. And keeping the arglist open, not closed, is a very good idea for extensibility functional API's anyway. > >> OK, I see your point: eldoc-documentation-functions is new. And > >> apparently you don't intend to add this feature to the variable > >> without "s". > > > > Yes, exactly. eldoc-documentation-function should be obsoleted IMO. > > Perhaps. I'm also not buying the usefulness of eldoc-documentation-compose. Yeah,I don't get it particularly, either. I mean, I can see its uses. but I'm glad you're finally getting the overengineered feeling :-) And it's waay more useful than futures here. > >>> It just looks like you're holding this problem hostage to introducing > >>> some kind of rushed futures solution. I don't agree with either of > >>> these things. > >> > >> Who's holding what hostage? I showed a smoother approach, you didn't > >> like it. No big surprise about that. > > > > Let me explain. First: it's clearly not "smoother", your're asking users > > to wrap their heads around a function that returns a function taking a > > function. That's not what I want to present to Eglot contributors, for > > instance. > > Would they need to? As soon as an existing Eglot's implementation is in > place, that exact part of the code wouldn't need to be touched often. Code is read much, much more than is is written. And WTF per minute _are_ a measure of code quality. I would like to avoid this particular WTF please. > In any case, you are over-exaggerating. This exact design has been a "over-exaggerating". Very meta. > part of "asynchronous" backend calling convention in Company for years. People will use what you give them, if you they have no other option. > And not once have I seen a complaint that it's overly complex. Anyway, count one now. Or don't. I mean, I really dislike company-backends throughout, but I don't use it, either. I mean I know you inherited it and I had to hack on it to add flex support for the capf thing, but it's a strange re-implementation of functions to have one single function that does wildly different things based on one argument. I guess at the time there weren't generic functions. And the cons :async thing is equally confusing to me. Sorry to be frank. But I guess some people will love it, for some equally legitimate reason: it will seem "right" to them, or "clever". > > And I'm not too crazy with presenting them this "future > > thing" that is completely different from Eglot's use of Flymake, > > jsonrpc.el, completion-at-point, etc... > > Didn't you say that Flymake could use futures as well? It could, sure, especially if you have a thousand futuristic devs itching to write backends but not grokking callbacks. But let's not kill the existing API, please. > > In other words, my ambition is > > consistency and you seem to be denying it for reasons I can't > > understand, because nothing in the steps I am taking denies _your_ > > ambitions, which seem to be futures. That's why I speak of "hostage". > > See above. But perhaps we should after all suspend this discussion until > we had a chance to reach a better mutual understanding of the futures > API, and how we expect it to help (or not). I promise to show some > proposals in the near future. Suspend this discussion? Sure, this discussion yes, if your want. But not this bugfix: that would be exactly what "holding hostage" means. Don't hold this bugfix hostage: it has nothing to do with futures. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-05-27 23:35 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, Andrii Kolomoiets On 28.05.2020 01:13, João Távora wrote: > On Wed, May 27, 2020 at 10:14 PM Dmitry Gutov <dgutov@yandex.ru> wrote: >>> No, the creditor of the future or issuer of the callback aborts or >>> invalidates the previous version just before issuing a new one. Nothing >>> pre-command-hook here. >> >> Where/when would eldoc-mode do it? > > In the idle timer function. That's when it decides it wants > new info, and so any old info that hasn't arrived yet is probably > out of date. Then eldoc might shows some info when it's no longer pertaining to the context around the point. > But I think I understnad what you mean pre-command-hook. > You suggested pre-command-hook because that's where you > can check if point is far enough away from the place where > the original request originated? Or always abort, as soon as the user invokes the next command. >>> Flymake does this: by invoking a backend again with a new callback >>> instance it is signalling that the preceding one became invalid. If the >>> backend tries to call the previous callback, it is an error and the >>> backend is disabled. >> >> Worse is sometimes better, we know. > > That is a very confusing statement. It's a somewhat incorrect behavior that is, however, easier to implement. Which is fully along the lines of Richard P. Gabriel's "The Rise of Worse Is Better". >> That would be my "alternative" suggestion: for >> eldoc-documentation-functions elements to return a function (denoted as >> FETCHER in the docstring) if they want the async convention. > > They need to _receive_ an object produced externally, somhow. > If they return a function as youv suggest, they are only doing so > they can later _receive_ another object. This is needlessly > complicated. To receive objects in some place, just use argument > the argument list of that place. "Returning a value" is meaningful semantic. Even when that value is a function. >> Okay, creditor != creator. But what you've said a few messages back >> (seen at the top of the quotes chain above) doesn't make sense: the >> creditor will call (future-abort fut), and the issuer of the future can >> make sure that this operation will indeed kill the process. > > No, it does make sense. Read it again. What you're saying is what I > meant. Perhaps you could have agreed then. > But that still means that the process sentinel will have to deal > with out-of-band kills that it must distinguish from other out-of-band > kills (such as, say, a kill -9 from the shell). That is added complexity. It's their choice. Some processes might run too long in certain cases. So that would be a safeguard. > It is better, in my opinion, to make this softer. Let the creditor > signal, I don't need this anymore, and the issuer will take appropriate > measures synchronously, i.e. in the process filter and not in the > process sentinel. Either way, that would require an additional way to signal. Try to fit this into your proposal. It won't match so well. >> That's the main idea behind aborting futures. Or canceling. Whatever >> term we're going to pick. > > But, again, nothing you're describing here can't be implemented > with passing a callback in the arglist. It's independent. Futures > particularly the versions you and Stefan are proposing are just > other places to type basically the same sexps. They're a stylistic > change over callbacks, but nothing more, fundamentally. Hence my request to wait a little. Stefan suggested the simplest version because it both fits your current requirements, and it can be extended without breaking that usage. >> Perhaps. I'm also not buying the usefulness of eldoc-documentation-compose. > > Yeah,I don't get it particularly, either. I mean, I can see its uses. > but I'm glad you're finally getting the overengineered feeling :-) No "finally", that was my opinion of it from the outset. > And it's waay more useful than futures here. Way to extend the bridge and then kick it down. >> Would they need to? As soon as an existing Eglot's implementation is in >> place, that exact part of the code wouldn't need to be touched often. > > Code is read much, much more than is is written. And WTF per minute > _are_ a measure of code quality. I would like to avoid this particular > WTF please. Okay, here's another argument: "Promise", or a "Future", or "Deferred" or whatever, are common notions across many programming languages now. When a programmer encounters an idea familiar to them, they understand a program more easily. No WTFs. >> In any case, you are over-exaggerating. This exact design has been a > > "over-exaggerating". Very meta. Plain English. >> And not once have I seen a complaint that it's overly complex. > > Anyway, count one now. Or don't. I mean, I really dislike > company-backends throughout, but I don't use it, either. Noted. > I mean > I know you inherited it and I had to hack on it to add flex support > for the capf thing, but it's a strange re-implementation of functions > to have one single function that does wildly different things based > on one argument. I guess at the time there weren't generic > functions. And the cons :async thing is equally confusing to me. > Sorry to be frank. But I guess some people will love it, for some > equally legitimate reason: it will seem "right" to them, or "clever". It's very simple. Much simpler than generic functions or c-a-p-f. So I'm surprised to see you disparage both ideas (one simpler than what you do, another a tiny bit more complex) as complex and outlandish. >> Didn't you say that Flymake could use futures as well? > > It could, sure, especially if you have a thousand futuristic devs > itching to write backends but not grokking callbacks. But let's > not kill the existing API, please. Probably not. Unless we find a good use in it for the extra capabilities provided by futures. > Suspend this discussion? Sure, this discussion yes, if your want. > But not this bugfix: that would be exactly what "holding hostage" > means. Don't hold this bugfix hostage: it has nothing to do with > futures. It's a new feature, not a bugfix. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-27 23:35 ` Dmitry Gutov @ 2020-05-27 23:57 ` João Távora 0 siblings, 0 replies; 84+ messages in thread From: João Távora @ 2020-05-27 23:57 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, Andrii Kolomoiets On Thu, May 28, 2020 at 12:35 AM Dmitry Gutov <dgutov@yandex.ru> wrote: > It's a somewhat incorrect behavior that is, however, easier to implement. In the futures, how would you prevent a client from giving you a stale future? You have the very same problem. Callbacks aren't "easier" to implement than futures, either. I'm not saying they are "superior", as you seem to be pretending with futures, They just happen to be the style that's most used in Emacs. Futures are really good when you bring in continuations: i.e. functions that can halt and resume their processing, so you can write normally, as if there was no async, but still have it happen automatically. But that requires an evaluator, which is what generator.el does, and that's what enables proper futures like the ones in emacs-aio. Anything other than that is just moving objects and funcalls around, for style (or lack thereof, to some people) > Either way, that would require an additional way to signal. Try to fit > this into your proposal. It won't match so well. I've already shown you're mistaken. > > Suspend this discussion? Sure, this discussion yes, if your want. > > But not this bugfix: that would be exactly what "holding hostage" > > means. Don't hold this bugfix hostage: it has nothing to do with > > futures. > > It's a new feature, not a bugfix. No it's not. Async clients are using internal functions. eldoc-message is an internal function. eldoc is broken for async clients, always has been. You know this, of course. I worked on a fix and your're holding it up because of a longing for an abstraction that you kinda like but are still having doubts about. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-25 23:52 ` Dmitry Gutov 2020-05-26 1:21 ` João Távora @ 2020-05-26 2:38 ` Stefan Monnier 2020-05-26 11:22 ` João Távora 2020-05-26 13:32 ` Dmitry Gutov 1 sibling, 2 replies; 84+ messages in thread From: Stefan Monnier @ 2020-05-26 2:38 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, João Távora, andreyk.mad > Here's a modified approach that doesn't use a global var and should make it > easier to transition to using futures. I think at this stage, we should either start using futures or we should forget about ever using them. Stefan ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 13:32 ` Dmitry Gutov 1 sibling, 1 reply; 84+ messages in thread From: João Távora @ 2020-05-26 11:22 UTC (permalink / raw) To: Stefan Monnier; +Cc: 41531, andreyk.mad, Dmitry Gutov Stefan Monnier <monnier@iro.umontreal.ca> writes: >> Here's a modified approach that doesn't use a global var and should make it >> easier to transition to using futures. > I think at this stage, we should either start using futures or we should > forget about ever using them. <DRAMATIC MUSIC PLAYS> But really: now we have deadlock too? I just want to solve this problem: please let's commit something, and move on to the next bug. It can be functions that return functions that receive functions with the airplane. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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-06-06 1:57 ` Dmitry Gutov 0 siblings, 2 replies; 84+ messages in thread From: Stefan Monnier @ 2020-05-26 14:53 UTC (permalink / raw) To: João Távora; +Cc: 41531, andreyk.mad, Dmitry Gutov > But really: now we have deadlock too? I just want to solve this > problem: please let's commit something, and move on to the next bug. Can you use the sample `eldoc-future-*` code I sent earlier? Stefan ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-26 14:53 ` Stefan Monnier @ 2020-05-26 15:19 ` João Távora 2020-05-26 15:56 ` Stefan Monnier 2020-06-06 1:57 ` Dmitry Gutov 1 sibling, 1 reply; 84+ messages in thread From: João Távora @ 2020-05-26 15:19 UTC (permalink / raw) To: Stefan Monnier; +Cc: 41531, andreyk.mad, Dmitry Gutov [-- Attachment #1: Type: text/plain, Size: 902 bytes --] Stefan Monnier <monnier@iro.umontreal.ca> writes: >> But really: now we have deadlock too? I just want to solve this >> problem: please let's commit something, and move on to the next bug. > > Can you use the sample `eldoc-future-*` code I sent earlier? > > Stefan It's not complete, is it? And how to I use it to solve the eldoc-documentation-compose problem? I suppose it's possible, anything is. But do we really want to hand-roll futures in eldoc.el when we got this nice https://github.com/skeeto/emacs-aio/commits/master that we could be looking into? Also the latest patch I attach solves the eldoc-documentation-compose problem decently (should actually be less LOC than previous versions). I suggest we go with this tried-and-tested well-understood solution and then adjust as more sophisticated solutions come along and we evaluate their merits. João [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-eldoc-async-v3.patch --] [-- Type: text/x-diff, Size: 11759 bytes --] From 0227a048cc7f88c5e4d773eac2ec8366056f3a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= <joaotavora@gmail.com> Date: Mon, 25 May 2020 16:39:40 +0100 Subject: [PATCH] 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..dcd28fb082 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,24 @@ 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 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) + (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 ^ permalink raw reply related [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Stefan Monnier @ 2020-05-26 15:56 UTC (permalink / raw) To: João Távora; +Cc: 41531, andreyk.mad, Dmitry Gutov > It's not complete, is it? Don't know. I have the impression that it's complete enough to give you the same "power" as the callback argument. I.e. instead of (funcall BACKEND CALLBACK) you (eldoc-future-set-callback (funcall BACKEND) CALLBACK) and instead of (funcall CALLBACK VALUE) you (eldoc-future-set-value FUT VALUE). > And how to I use it to solve the > eldoc-documentation-compose problem? AFAIK this is orthogonal to the technique we use for the backend to run eldoc's callback code. > I suppose it's possible, anything > is. But do we really want to hand-roll futures in eldoc.el when we got > this nice https://github.com/skeeto/emacs-aio/commits/master that we > could be looking into? I'm not familiar with that package, so I can't judge. It might be an even better option, indeed. > Also the latest patch I attach solves the eldoc-documentation-compose > problem decently (should actually be less LOC than previous versions). > I suggest we go with this tried-and-tested well-understood solution and > then adjust as more sophisticated solutions come along and we evaluate > their merits. The use of futures has been discussed forever in the context of several packages. That's why at this stage, I think either we decide to drop the idea or to start using it. I'm OK with either option. Stefan ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-26 15:56 ` Stefan Monnier @ 2020-05-26 16:26 ` João Távora 2020-05-26 17:39 ` Stefan Monnier 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-05-26 16:26 UTC (permalink / raw) To: Stefan Monnier; +Cc: Christopher Wellons, Dmitry Gutov, andreyk.mad, 41531 [ Christopher, I'm CC-ing you in this discussion becasue we've been discussing adding futures to Emacs, and I came across your aio.el library which seems very promising. (I am, however, proposing a pragmatic intermediate solution to the particular problem in the subject) ] Stefan Monnier <monnier@iro.umontreal.ca> writes: >> It's not complete, is it? > > Don't know. I have the impression that it's complete enough to give you > the same "power" as the callback argument. > I.e. instead of (funcall BACKEND CALLBACK) > you (eldoc-future-set-callback (funcall BACKEND) CALLBACK) and instead > of (funcall CALLBACK VALUE) you (eldoc-future-set-value FUT VALUE). 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? >> And how to I use it to solve the >> eldoc-documentation-compose problem? > > AFAIK this is orthogonal to the technique we use for the backend to run > eldoc's callback code. Not really. A "proper" futures library will have primitives that handle this very elegantly. I.e. a future that depends on multiple futures, a future that applies a function to the first available future. The kind of stuff I'm sure you'll love, academically. That would be the thing to use there, otherwise we're just playing legos with structs and functions. >> I suppose it's possible, anything >> is. But do we really want to hand-roll futures in eldoc.el when we got >> this nice https://github.com/skeeto/emacs-aio/commits/master that we >> could be looking into? > > I'm not familiar with that package, so I can't judge. It might be an > even better option, indeed. I believe it has such functionality that I mentioned before. And then some. I don't understand it filly but it seems nicely coded, has two authors that have (99% sure) assigned copyright. The library calls futures "promises", by the way. >> Also the latest patch I attach solves the eldoc-documentation-compose >> problem decently (should actually be less LOC than previous versions). >> I suggest we go with this tried-and-tested well-understood solution and >> then adjust as more sophisticated solutions come along and we evaluate >> their merits. > The use of futures has been discussed forever in the context of > several packages. That's why at this stage, I think either we decide > to drop the idea or to start using it. > I'm OK with either option. Black and white, do or die? Nah, I don't buy it :-) Let me be honest: the thing I'm not crazy about in futures is that if we go the handrolled eldoc.el route that creates another distraction to maintain separately. Eldoc's problem lie elsewhere. Let's use futures in the new completion API thingy, or in an elisp json library, where they might brutally speed up parsing, by doing parsing only parts of the document that users access. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Stefan Monnier @ 2020-05-26 17:39 UTC (permalink / raw) To: João Távora Cc: Christopher Wellons, Dmitry Gutov, andreyk.mad, 41531 > 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 ;-) [ 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 docstrings). ] > I believe it has such functionality that I mentioned before. And then > some. I don't understand it filly but it seems nicely coded, has two > authors that have (99% sure) assigned copyright. The library calls > futures "promises", by the way. I'm willing to tweak my vocabulary. Stefan ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-26 17:39 ` Stefan Monnier @ 2020-05-26 18:49 ` João Távora 2020-06-03 2:45 ` Stefan Monnier 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-05-26 18:49 UTC (permalink / raw) To: Stefan Monnier; +Cc: Christopher Wellons, Dmitry Gutov, andreyk.mad, 41531 [-- Attachment #1: Type: text/plain, Size: 2565 bytes --] Stefan Monnier <monnier@iro.umontreal.ca> 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))) (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 docstrings). ] Yes, it's called cascade dev, and it gets a bad rep nowadays. Tho the person who writes the docstrings usually goes first ;-) João [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Better-handle-asynchronously-produced-eldoc-docstrin.patch --] [-- Type: text/x-diff, Size: 11774 bytes --] From b97c0cfb0cbfea20cbf75ad7ea8abf9f4c51ec54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= <joaotavora@gmail.com> 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 <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,24 @@ 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 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 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-Reimplement-funcall-but-in-the-future.patch --] [-- Type: text/x-diff, Size: 3905 bytes --] From c039a4356fa363ef10b8320c3856eb3466eb32f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= <joaotavora@gmail.com> 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)))) \f +;;;; Futuristic interlude +(cl-defstruct (eldoc-future + (:conc-name eldoc-future--) + (:constructor eldoc-future-make ())) ; become Yoda we? + "<WORLD CLASS DOCSTRING>" + (value 'eldoc-future--unset) + callback) + +(defun eldoc-future-set (f v) + "<WORLD CLASS DOCSTRING>" + (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) + "<WORLD CLASS DOCSTRING>" + (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)))) + +\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. +<WORLD CLASS DOCSTRING GOES HERE> 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 ^ permalink raw reply related [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Stefan Monnier @ 2020-06-03 2:45 UTC (permalink / raw) To: João Távora Cc: Christopher Wellons, Dmitry Gutov, andreyk.mad, 41531 > --- 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)))) > > \f > +;;;; Futuristic interlude > +(cl-defstruct (eldoc-future > + (:conc-name eldoc-future--) > + (:constructor eldoc-future-make ())) ; become Yoda we? > + "<WORLD CLASS DOCSTRING>" "Future object." > + (value 'eldoc-future--unset) > + callback) > + > +(defun eldoc-future-set (f v) > + "<WORLD CLASS DOCSTRING>" > + (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) > + "<WORLD CLASS DOCSTRING>" > + (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)))) > + > +\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. > +<WORLD CLASS DOCSTRING GOES HERE> "Special hook run to get the documentation string at point. Each function is called with no argument and should return either nil or an `eldoc-future` object that should have its `value` set as soon as possible via `eldoc-future-set-value` (it can be set before returning the future or at a later time). This value should be a string, typically occupying only a single line. In case the function ends up finding no information it is allowed not to `eldoc-future-set-value` at all." > + (let ((x (run-hook-with-args-until-success 'eldoc-documentation-functions))) > + (if (eldoc-future-p x) (eldoc-future-set-callback x eldoc--callback) > + x))) I'd simplify this to: (let ((x (run-hook-with-args-until-success 'eldoc-documentation-functions))) (when x (eldoc-future-set-callback x eldoc--callback))) But I'd expect that there would be no `eldoc--callback` and that it's each `eldoc-documentation-function` which chooses its own callback rather than being chosen by their caller. Stefan ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 21:28 ` Dmitry Gutov 0 siblings, 2 replies; 84+ messages in thread From: João Távora @ 2020-06-03 18:07 UTC (permalink / raw) To: Stefan Monnier; +Cc: Christopher Wellons, Dmitry Gutov, andreyk.mad, 41531 Stefan Monnier <monnier@iro.umontreal.ca> writes: > "Future object." >> + (value 'eldoc-future--unset) >> + callback) >> + >> +(defun eldoc-future-set (f v) >> + "<WORLD CLASS DOCSTRING>" Ahem. >> + (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) >> + "<WORLD CLASS DOCSTRING>" Ahem hem :-) >> +<WORLD CLASS DOCSTRING GOES HERE> > > "Special hook run to get the documentation string at point. > Each function is called with no argument and should return either nil > or an `eldoc-future` object that should have its `value` set as soon > as possible via `eldoc-future-set-value` (it can be set before > returning the future or at a later time). > This value should be a string, typically occupying only a single line. Sometimes clients want to return more than one value, i.e. set more than one value. In this case it would be, for instance, the type of the docstring being returns (function signature, value of a variable, etc). The callback strategy makes it easy because there are lambda lists of all shapes and sizes. How does the future approach handle this? Do clients return structured lists of things? > In case the function ends up finding no information it is allowed > not to `eldoc-future-set-value` at all." This is problematic. In the eldoc-documentation-compose situation we need to wait for every backend to reply before composing. In other situation, indeed we can be greedy. But I don't think you can just say to clients they dont'need to do anything. If they returned the future they are making _a promise_. If they don't fullfil it something goes wrong. The callback case is the same, if you return non-nil non-string, you, the eldoc function, are _required_, by Eldoc law, to call it, even if with nil. The equivalent in futures is just to say clients can set the value nil, or some other application-specific indication of "sorry, I failed". > each `eldoc-documentation-function` which chooses its own callback > rather than being chosen by their caller. For this to work, i.e. to be able to handle multiple responses, I think it has to be set by their caller, i.e. eldoc-print-current-symbol-info: that's the central "hub" that maintains information about how many backends have responded and how many haven't. But indeed that's only an implementation detail. If you can make the defined behaviour work work in some other simpler way, I have no objections, of course. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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:28 ` Dmitry Gutov 1 sibling, 1 reply; 84+ messages in thread From: Stefan Monnier @ 2020-06-03 20:22 UTC (permalink / raw) To: João Távora Cc: Christopher Wellons, Dmitry Gutov, andreyk.mad, 41531 >>> + "<WORLD CLASS DOCSTRING>" > Ahem. >>> + "<WORLD CLASS DOCSTRING>" > Ahem hem :-) Not sure what you mean ;-) >> "Special hook run to get the documentation string at point. >> Each function is called with no argument and should return either nil >> or an `eldoc-future` object that should have its `value` set as soon >> as possible via `eldoc-future-set-value` (it can be set before >> returning the future or at a later time). >> This value should be a string, typically occupying only a single line. > Sometimes clients want to return more than one value, i.e. set more than > one value. You mean a single call could return first a function signature and a while later a docstring? Or at the same time. If at the same time, then it should return them combined into a single value (concatenation of strings, list, you name it). The infrastructure so far only accepts strings as far as I know, so until that is changed the question seems moot. > The callback strategy makes it easy because there are lambda lists of > all shapes and sizes. It's trivial to use a list to bring the number back down to 1, so it's not much of a difference. > How does the future approach handle this? > Do clients return structured lists of things? If we want to extend it that way, that would be the natural thing to do, I guess. Tho without knowing what the different elements represent (i.e. some kind of semantic information about that list), I'm not sure what the callback can do with it other than presume that all elements are strings and concatenate them. >> In case the function ends up finding no information it is allowed >> not to `eldoc-future-set-value` at all." > This is problematic. In the eldoc-documentation-compose situation we > need to wait for every backend to reply before composing. We definitely don't want to wait: if a backend responds quickly we should show that info immediately, and update the info if/when another backend gives additional info. OTOH indeed for the non-composing situation, we'd need to know that the 1st backend finished unsuccessfully before being able to use the second backend. So I guess you're right: we shouldn't allow backends to drop requests :-( >> each `eldoc-documentation-function` which chooses its own callback >> rather than being chosen by their caller. > For this to work, i.e. to be able to handle multiple responses, I think > it has to be set by their caller, i.e. eldoc-print-current-symbol-info: > that's the central "hub" that maintains information about how many > backends have responded and how many haven't. I don't think this structure can work well: the "hub" needs to work differently for compose than for "return first". Stefan ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-06-03 20:22 ` Stefan Monnier @ 2020-06-03 20:36 ` João Távora 2020-06-03 21:21 ` Stefan Monnier 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-06-03 20:36 UTC (permalink / raw) To: Stefan Monnier; +Cc: Christopher Wellons, Dmitry Gutov, andreyk.mad, 41531 Stefan Monnier <monnier@iro.umontreal.ca> writes: >>>> + "<WORLD CLASS DOCSTRING>" >> Ahem. >>>> + "<WORLD CLASS DOCSTRING>" >> Ahem hem :-) > > Not sure what you mean ;-) > >>> "Special hook run to get the documentation string at point. >>> Each function is called with no argument and should return either nil >>> or an `eldoc-future` object that should have its `value` set as soon >>> as possible via `eldoc-future-set-value` (it can be set before >>> returning the future or at a later time). >>> This value should be a string, typically occupying only a single line. >> Sometimes clients want to return more than one value, i.e. set more than >> one value. > > You mean a single call could return first a function signature and > a while later a docstring? No, that's not what I mean. Those should be two different members of eldoc-documentation-functions (plural). I meant producing metadata about the string just returned. Much like string properties, I suppose, but not specifically attached to regions of the string. > The infrastructure so far only accepts strings as far as I know, so > until that is changed the question seems moot. Very soon that might change, but yes. >> The callback strategy makes it easy because there are lambda lists of >> all shapes and sizes. > It's trivial to use a list to bring the number back down to 1, so it's > not much of a difference. Yes, I agree, but it's IMO easier to read (funcall cb :foo 42 :baz 23) than (set-value fut (list :foo 42 :baz 23)). >> How does the future approach handle this? >> Do clients return structured lists of things? > > If we want to extend it that way, that would be the natural thing to do, > I guess. Tho without knowing what the different elements represent > (i.e. some kind of semantic information about that list), I'm not sure > what the callback can do with it other than presume that all elements > are strings and concatenate them. See my most recent patches, there are many ways to handle differently formated and differently timed reports. >>> In case the function ends up finding no information it is allowed >>> not to `eldoc-future-set-value` at all." >> This is problematic. In the eldoc-documentation-compose situation we >> need to wait for every backend to reply before composing. > > We definitely don't want to wait: if a backend responds quickly we > should show that info immediately, and update the info if/when another > backend gives additional info. That depends. Depends on the strategy. I don't take eldoc-documentation-compose to mean that, for example. But we could easily have eldoc-documentation-compose-wait and eldoc-documentation-compose-eager. > OTOH indeed for the non-composing situation, we'd need to know that the > 1st backend finished unsuccessfully before being able to use the > second backend. So I guess you're right: we shouldn't allow backends to > drop requests :-( I also don't take eldoc-documentation-default to mean that. I take it to mean: focus on the first guy that promised he would produce something. But we could indeed have a "focus on the first guy that actually produced something". >>> each `eldoc-documentation-function` which chooses its own callback >>> rather than being chosen by their caller. >> For this to work, i.e. to be able to handle multiple responses, I think >> it has to be set by their caller, i.e. eldoc-print-current-symbol-info: >> that's the central "hub" that maintains information about how many >> backends have responded and how many haven't. > > I don't think this structure can work well: the "hub" needs to work > differently for compose than for "return first". Yes, of course it works differently. How "well" is another question, whose details I don't fuilly understand. In the last patches I showed it works decently well, i.e. I don't see anything wrong with it. I implemented eldoc-documentation-default, eldoc-documentation-compose, and something eldoc-documentation-eager which is like "default" but will show the first one, and potentially replace with a slower, but more important one. These were all done "in the hub", without lots of code. I'm fairly confident other strategies can be implemented "in the hub" easily. In fact, a much better name for eldoc-documentation-function (singular) is eldoc-documentation-strategy, not least because it relieves us from this silly singular/plural confusion. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Stefan Monnier @ 2020-06-03 21:21 UTC (permalink / raw) To: João Távora Cc: Christopher Wellons, Dmitry Gutov, andreyk.mad, 41531 >> You mean a single call could return first a function signature and >> a while later a docstring? > No, that's not what I mean. Those should be two different members of > eldoc-documentation-functions (plural). Great. >>> The callback strategy makes it easy because there are lambda lists of >>> all shapes and sizes. >> It's trivial to use a list to bring the number back down to 1, so it's >> not much of a difference. > Yes, I agree, but it's IMO easier to read (funcall cb :foo 42 :baz 23) > than (set-value fut (list :foo 42 :baz 23)). I find the difference largely irrelevant. Much more important is what kinds of :foo and bar are allowed and what they do. > In fact, a much better name for eldoc-documentation-function (singular) > is eldoc-documentation-strategy, not least because it relieves us from > this silly singular/plural confusion. Sounds very good. Changing its name will make it possible to fix the current backward-incompatibility (which we'd fix by re-introducing a(n obsolete) eldoc-documentation-function). Stefan ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-06-03 21:21 ` Stefan Monnier @ 2020-06-05 11:26 ` João Távora 0 siblings, 0 replies; 84+ messages in thread From: João Távora @ 2020-06-05 11:26 UTC (permalink / raw) To: Stefan Monnier; +Cc: Christopher Wellons, Dmitry Gutov, andreyk.mad, 41531 Stefan Monnier <monnier@iro.umontreal.ca> writes: >>> You mean a single call could return first a function signature and >>> a while later a docstring? >> No, that's not what I mean. Those should be two different members of >> eldoc-documentation-functions (plural). > Great. Indeed, I can see 3 eldoc sources for emacs-lisp mode, in this order: - function signature - docstring - special variable value If emacs-lisp-mode one uses the default display strategy (eldoc-documentation-default or some rename of that) and sets eldoc-echo-area-use-multiline-p to 1, it should be fully backward compatible to the current behaviour. Alternatively, we can have emacs-lisp-mode keep out of eldoc-echo-area-use-multiline-p and use 4 sources: - function signature - one-line docstring - special variable value - remaining paragraphs of docstring ( At some point, if we compose all of these bits of information in the volatile *eldoc* buffer, it will start looking a lot like *Help* for C-h o, There's some integration work to do there, but I'd rather not open that can of worms just now. ) >>>> The callback strategy makes it easy because there are lambda lists of >>>> all shapes and sizes. >>> It's trivial to use a list to bring the number back down to 1, so it's >>> not much of a difference. >> Yes, I agree, but it's IMO easier to read (funcall cb :foo 42 :baz 23) >> than (set-value fut (list :foo 42 :baz 23)). > > I find the difference largely irrelevant. Much more important is > what kinds of :foo and bar are allowed and what they do. I agree. Content is more important than style. Of course style matters, too. Occasionally, it matters overwhelmingly. But not here. I'd say. The promises-vs-callbacks discussion is a matter of style. >> In fact, a much better name for eldoc-documentation-function (singular) >> is eldoc-documentation-strategy, not least because it relieves us from >> this silly singular/plural confusion. > > Sounds very good. Changing its name will make it possible to fix the > current backward-incompatibility (which we'd fix by re-introducing a(n > obsolete) eldoc-documentation-function). Yes, that's the plan. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-06-03 18:07 ` João Távora 2020-06-03 20:22 ` Stefan Monnier @ 2020-06-03 21:28 ` Dmitry Gutov 1 sibling, 0 replies; 84+ messages in thread From: Dmitry Gutov @ 2020-06-03 21:28 UTC (permalink / raw) To: João Távora, Stefan Monnier Cc: Christopher Wellons, andreyk.mad, 41531 On 03.06.2020 21:07, João Távora wrote: > The equivalent in futures is just to say clients can set the value nil, > or some other application-specific indication of "sorry, I failed". They should call 'eldoc-future-set-error'. One design point I'm not sure of, is whether the argument should be a string (coming from the error message), or a "proper" exception/error object, previous captured inside a condition-case. We might make that choice just based on whether url-retrieve passes the same kind of data as, say, error-message-string expects. The same "proper" object, that is. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-26 14:53 ` Stefan Monnier 2020-05-26 15:19 ` João Távora @ 2020-06-06 1:57 ` Dmitry Gutov 1 sibling, 0 replies; 84+ messages in thread From: Dmitry Gutov @ 2020-06-06 1:57 UTC (permalink / raw) To: Stefan Monnier, João Távora; +Cc: 41531, andreyk.mad [-- Attachment #1: Type: text/plain, Size: 1504 bytes --] Hi! On 26.05.2020 17:53, Stefan Monnier wrote: >> But really: now we have deadlock too? I just want to solve this >> problem: please let's commit something, and move on to the next bug. > Can you use the sample `eldoc-future-*` code I sent earlier? How about the attached file for a rough, but a largely feature complete first version of futures? To remind from previous discussions, we wanted futures: - To be cancelable, so that the issuer could abort their calculations, if they so desire. - Force-able, meaning the consumer should be able to "realize" the future synchronously, with the future's creator being able to support their, most optimal, version of that logic. The default needs to be useful and reliable enough, though, that callers could use it in 99% of cases anyway. The error callback probably wasn't mentioned, but it seems logical to have it anyway. For the first two features, I also considered using cl-generic, but result might turn out to be clunkier, and we need overridability only for two of these functions. But suggestions welcome. TBD: - Probably rename to "promises" in the end. - It would be nice to have a certain degree of compatibility with Christopher Wellons's emacs-aio, so that its promises could be accepted by code that expects "our" futures/promises. Not sure if we can do that without making the API more complex (aio-resolve's signature comes to mind), or if we adopt its approach, importing the package wholesale might make more sense. [-- Attachment #2: future.el --] [-- Type: text/x-emacs-lisp, Size: 2549 bytes --] ;;; future.el --- Futures, a concurrency primitive -*- lexical-binding: t; -*- ;; Copyright (C) 2020 Dmitry Gutov ;; Author: Dmitry Gutov <dgutov@yandex.ru> ;; Keywords: lisp ;; 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 ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: ;; ;;; Code: (require 'cl-lib) (cl-defstruct (future (:conc-name future--) (:constructor future-make (&key force-fn cancel-fn))) "This structure represents a \"future\" value." value error (status 'pending) (force-fn #'future-force--apo) (cancel-fn #'ignore) callback errback) (defun future-force (f) (funcall (future--force-fn f))) (defun future-force--apo (f) (while (eq (future--status f) 'pending) (accept-process-output nil 0.05))) (defun future-cancel (f) (when (eq (future--status f) 'pending) (setf (future--status f) 'canceled) (funcall (future--cancel-fn f)))) (defun future-set (f v) ;; FIXME: Probably shouldn't error on 'canceled'. (cl-assert (eq (future--status f) 'pending)) (setf (future--value f) v (future--status f) 'success) (when (future--callback f) (funcall (future--callback f) v))) (defun future-error (f e) ;; FIXME: Probably shouldn't error on 'canceled'. (cl-assert (eq (future--status f) 'pending)) (setf (future--error f) e (future--status f) 'error) (when (future--errback f) (funcall (future--errback f) e))) ;; Or we can make these both lists of functions... (defun future-set-callback (f c) (cl-assert (null (future--callback f))) (setf (future--callback f) c) (when (eq (future--status f) 'success) (funcall c (future--value f)))) ;; ...and rename to -add-callback/-add-errback. (defun future-set-errback (f c) (cl-assert (null (future--errback f))) (setf (future--errback f) c) (when (eq (future--status f) 'error) (funcall c (future--error f)))) (provide 'future) ;;; future.el ends here ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-26 2:38 ` Stefan Monnier 2020-05-26 11:22 ` João Távora @ 2020-05-26 13:32 ` Dmitry Gutov 2020-05-26 16:56 ` João Távora 1 sibling, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-05-26 13:32 UTC (permalink / raw) To: Stefan Monnier; +Cc: 41531, João Távora, andreyk.mad On 26.05.2020 05:38, Stefan Monnier wrote: >> Here's a modified approach that doesn't use a global var and should make it >> easier to transition to using futures. > > I think at this stage, we should either start using futures or we should > forget about ever using them. We should certainly do it before Emacs 28 is released (so we won't have to support whatever ad-hoc option is currently being proposed). I just don't have the time to work on futures right now. If this bug can wait until this weekend, at least, we can reconvene after. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-05-26 13:32 ` Dmitry Gutov @ 2020-05-26 16:56 ` João Távora 0 siblings, 0 replies; 84+ messages in thread From: João Távora @ 2020-05-26 16:56 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, Andrii Kolomoiets On Tue, May 26, 2020 at 2:32 PM Dmitry Gutov <dgutov@yandex.ru> wrote: > On 26.05.2020 05:38, Stefan Monnier wrote: > >> Here's a modified approach that doesn't use a global var and should make it > >> easier to transition to using futures. > > I think at this stage, we should either start using futures or we should > > forget about ever using them. > We should certainly do it before Emacs 28 is released (so we won't have > to support whatever ad-hoc option is currently being proposed). Agree. By my estimate we have ~2 years to go, tho. And ad-hoc is a value judgement that you could apply to every part of Emacs could be improved (then someone else might call _that_ ad-hoc). João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 28.0.50; proper Eldoc async support 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 @ 2020-06-03 18:56 ` João Távora 2020-06-04 16:20 ` Andrii Kolomoiets 2020-06-30 11:31 ` bug#41531: 27.0.91; Better handle asynchronous eldoc backends João Távora 2 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-06-03 18:56 UTC (permalink / raw) To: Stefan Monnier, andreyk.mad, Dmitry Gutov, mvoteiza; +Cc: 41531 Hello again gang, As you might have seen in emacs-diffs, I have pushed a new scratch/eldoc-async branch to the Savannah repo. If you don't have this repo setup you can find the commits here in the meantime: https://github.com/emacs-mirror/emacs/tree/scratch/eldoc-async The code, which touches mostly lisp/emacs-lisp/eldoc.el contains the logical continuation of the improvements I started building two weeks ago. When applied, these improvements result in a substantial reduction of Eglot's documentation handling code. Yes, Andrii, that means all our hand-crafted, hard work of doc handling functions is soon gone, including the awkward eglot-put-doc-in-help-buffer, eglot-auto-display-help-buffer and the *eglot-help* buffer. Feels sad but also good, because deleted code is good code. And it's not in vain because your feedback and testing was fundamental here. And the good news is that the logic problems about blinking and giving priority to some docs is gone. There are 6 commits in total, that build on top of each other. In reverse order 10834f20ec * lisp/emacs-lisp/eldoc.el (Version): Bump to 1.1.0 fe93e5b9d5 Make eldoc-print-current-symbol-info a command 0612bb7ab5 Introduce eldoc-prefer-doc-buffer defcustom 40d45067ba Overhaul and handle (most of) eldoc-echo-area-use-multiline-p in Eldoc itself 600b9c0a71 New eldoc-documentation-eager value for eldoc-documentation-function cde8a6ab98 Better handle asynchronously produced eldoc docstrings And the new version of Eglot that makes uses of this eldoc is here. https://github.com/joaotavora/eglot/tree/scratch/work-with-new-eldoc It's important to note that Eldoc remains backward-compatible to all its previous users. In eldoc.el, things build on top of existing work, which includes the reasonably new eldoc-documentation-functions (plural). Earlier, I thought of this variable somewhat useless, but it's really not. In fact, it's exactly what Eglot, SLY and other modes are after. Even emacs-lisp-mode itself could benefit as it's often the case that one loses the documentation for a special variable just because one happen to be inside a function call, or vice versa. eldoc-documentation-functions allows us to split up these two competing sources of documentation, so thank you Mark, or whomever had this great idea. An orthogonal question is how to display the documentation we gather from multiple sources. That is handled by eldoc-documentation-function (singular), another variable I had underestimated. In my changes, I have added a third option to the two already existing ones. :type '(radio (function-item eldoc-documentation-default) (function-item eldoc-documentation-compose) (function-item eldoc-documentation-eager) (function :tag "Other function")) :version "28.1") Eglot defaults to eldoc-documentation-eager, which simulates its previous behavior. I suggest you see the docstring for each. Certainly we can have more strategies to combine documentation sources. Another important development is that now that the display is centralized, the formatiing can also be. Thus a big part of eldoc-echo-area-use-multiline-p can be easily honoured in eldoc.el itself. But the most complex changes pertain to async backends, such as Eglot's and some (but not all) of SLY. This is also covered. On this point, it is also extremely super-important to note that even though I have NOT used "futures" or "promises" in these patches, the very same things can be achieved with them, give or take some code here and there and some head-wrapping around different debugging techniques. I have NOT focused on the particular async programming technique: I just used the simplest and most commonly used in Emacs. Finally, there is a bit of future-proof unused API. Backends can call the documentation-reporting callback with keyword arguments, such as `:hint`. But they're not really used yet for anything yet. Some more sophisticated text formatting in the *eldoc doc* buffer, including renaming it like Eglot used to do to its *Eglot doc* buffer, is a possibility. Another possibility yet, also left unexplored, is for Flymake diagnostic messages at point to be reported as independent documentation sources. This is a frequent complain about Eglot. But in fact I think it should be Flymake-mode itself that adds some function to eldoc-documentation-functions. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 28.0.50; proper Eldoc async support 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-05 11:00 ` João Távora 0 siblings, 2 replies; 84+ messages in thread From: Andrii Kolomoiets @ 2020-06-04 16:20 UTC (permalink / raw) To: João Távora; +Cc: mvoteiza, 41531, Stefan Monnier, Dmitry Gutov João Távora <joaotavora@gmail.com> writes: > Hello again gang, Hi João, > When applied, these improvements result in a substantial reduction of > Eglot's documentation handling code. Yes, Andrii, that means all our > hand-crafted, hard work of doc handling functions is soon gone, > including the awkward eglot-put-doc-in-help-buffer, > eglot-auto-display-help-buffer and the *eglot-help* buffer. > > Feels sad but also good, because deleted code is good code. And it's > not in vain because your feedback and testing was fundamental here. And > the good news is that the logic problems about blinking and giving > priority to some docs is gone. I for one completely support moving documentation handling code to eldoc. I was planning to remove the eglot-put-doc-in-help-buffer variable in the near future PR as well as the use of the eglot--message function for the documentation display ;-) However, after briefly using new Eldoc and Eglot I found some issues that, I hope, we can fix: 1. Display only first line of the hover info. Again :-) 2. The hover info is sometimes displayed right before the signature info making the echo area to "blink". I suppose this must be fixed on Eglot side by not requesting both the hover and the signature infos at the same time. 3. That IMO useless "...truncated, see *help* buffer" message is moved to Eldoc. Do we really need to show this message every time? That one last line can be used to show additional documentation. Hadn't a chance to take a closer look at the code, so reporting those issues is the most I can do for now. Thanks! ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 28.0.50; proper Eldoc async support 2020-06-04 16:20 ` Andrii Kolomoiets @ 2020-06-04 18:22 ` Dmitry Gutov 2020-06-04 19:00 ` Andrii Kolomoiets 2020-06-05 11:00 ` João Távora 1 sibling, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-06-04 18:22 UTC (permalink / raw) To: Andrii Kolomoiets, João Távora; +Cc: mvoteiza, 41531, Stefan Monnier On 04.06.2020 19:20, Andrii Kolomoiets wrote: > 3. That IMO useless "...truncated, see*help* buffer" message is moved > to Eldoc. Do we really need to show this message every time? That one > last line can be used to show additional documentation. The truncation can be indicated as ellipsis at the end of the (first) line. Maybe ellipsis in parentheses (...). Whether to use multiple lines of not, seems like individual preference. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 28.0.50; proper Eldoc async support 2020-06-04 18:22 ` Dmitry Gutov @ 2020-06-04 19:00 ` Andrii Kolomoiets 2020-06-05 22:53 ` João Távora 0 siblings, 1 reply; 84+ messages in thread From: Andrii Kolomoiets @ 2020-06-04 19:00 UTC (permalink / raw) To: Dmitry Gutov; +Cc: mvoteiza, 41531, João Távora, Stefan Monnier Dmitry Gutov <dgutov@yandex.ru> writes: > On 04.06.2020 19:20, Andrii Kolomoiets wrote: >> 3. That IMO useless "...truncated, see*help* buffer" message is moved >> to Eldoc. Do we really need to show this message every time? That one >> last line can be used to show additional documentation. > > The truncation can be indicated as ellipsis at the end of the (first) > line. Maybe ellipsis in parentheses (...). Good idea. > Whether to use multiple lines of not, seems like individual preference. Absolutely. That's why there are customizable variables so anyone can tweak behavior to their likes. Current version of Eglot pays attention to the eldoc-echo-area-use-multiline-p variable and proposed one do not. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 28.0.50; proper Eldoc async support 2020-06-04 19:00 ` Andrii Kolomoiets @ 2020-06-05 22:53 ` João Távora 0 siblings, 0 replies; 84+ messages in thread From: João Távora @ 2020-06-05 22:53 UTC (permalink / raw) To: Andrii Kolomoiets; +Cc: mvoteiza, 41531, Stefan Monnier, Dmitry Gutov Andrii Kolomoiets <andreyk.mad@gmail.com> writes: > Dmitry Gutov <dgutov@yandex.ru> writes: >> On 04.06.2020 19:20, Andrii Kolomoiets wrote: >>> 3. That IMO useless "...truncated, see*help* buffer" message is moved >>> to Eldoc. Do we really need to show this message every time? That one >>> last line can be used to show additional documentation. >> The truncation can be indicated as ellipsis at the end of the (first) >> line. Maybe ellipsis in parentheses (...). > > Good idea. I think is is easily missed, and will not inform of the keybinding for `eldoc-doc-buffer'. But it's clearly better than nothing for the strictly-one-line people. >> Whether to use multiple lines of not, seems like individual preference. > > Absolutely. That's why there are customizable variables so anyone can > tweak behavior to their likes. Current version of Eglot pays attention > to the eldoc-echo-area-use-multiline-p variable and proposed one do > not. It does not because most of that variable (except for the very special "truncate-sym-name-if-fit" value) is now handled in eldoc.el. Modulo bugs, of course, which I will endeavour to fix. I also agree, of course this is individual preference. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 28.0.50; proper Eldoc async support 2020-06-04 16:20 ` Andrii Kolomoiets 2020-06-04 18:22 ` Dmitry Gutov @ 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-11 11:11 ` Andrii Kolomoiets 1 sibling, 2 replies; 84+ messages in thread From: João Távora @ 2020-06-05 11:00 UTC (permalink / raw) To: Andrii Kolomoiets Cc: 41531, theothornhill, mvoteiza, Stefan Monnier, Dmitry Gutov, Fredrik Bergroth [ Theodor and Fredrik, adding you since you were also interested in this Eglot/Eldoc matter. You can review the messages in the bug list if you're interested: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=41531] Andrii Kolomoiets <andreyk.mad@gmail.com> writes: > I was planning to remove the eglot-put-doc-in-help-buffer variable in > the near future PR as well as the use of the eglot--message function for > the documentation display ;-) I'm guess I'm happy to have shot these plans into the depths of the ocean ;-) > However, after briefly using new Eldoc and Eglot I found some issues > that, I hope, we can fix: > > 1. Display only first line of the hover info. Again :-) You should be able to do this with either (setq eldoc-echo-area-use-multiline-p 1) or (setq eldoc-echo-area-use-multiline-p nil) Did you try this? If so, what exactly didn't work for you when you did? I'm sorry if you've already given me this information in the multiple PR's you opened about this, but let's have it again. > 2. The hover info is sometimes displayed right before the signature info > making the echo area to "blink". I suppose this must be fixed on Eglot > side by not requesting both the hover and the signature infos at the > same time. Not something to be fixed in Eglot, definitely, it's not its fault or responsibility: it just reports whatever it has. I've fixed this in Eldoc, in the last commit. It only affected the "eager" strategy (which should really be called the "enthusiast" strategy). I'll post a commit soon using better names for strategies, I'm thinking: eldoc-documentation-function -> eldoc-strategy (with obsolete alias) eldoc-documentation-functions -> eldoc-functions (maybe) eldoc-documentation-default -> eldoc-patient eldoc-documentation-compose -> eldoc-compose-patiently eldoc-documentation-eager -> eldoc-enthusiast (Eglot uses this) <doesn't exist yet> -> eldoc-compose-eagerly (Stefan mentioned this) > 3. That IMO useless "...truncated, see *help* buffer" message is moved > to Eldoc. Do we really need to show this message every time? I see. Maybe not _every time_ but at least _once_, I'd say. Once per Eldoc session (but what is an Eldoc session)? Once per x truncated messages? Customization variable? (I hate those, but maybe). Or maybe never show it? > That one last line can be used to show additional documentation. > Hadn't a chance to take a closer look at the code, so reporting those > issues is the most I can do for now. Yes, and that's fine for now, though a second pair of eyes in the code is certainly appreciated too. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 28.0.50; proper Eldoc async support 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 1 sibling, 2 replies; 84+ messages in thread From: Theodor Thornhill via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2020-06-05 17:50 UTC (permalink / raw) To: João Távora, Andrii Kolomoiets Cc: mvoteiza, 41531, Fredrik Bergroth, Stefan Monnier, Dmitry Gutov Hello! Thanks for pinging me - I tried it, and it looks pretty cool. However, I noticed a few bugs. (When using both the new eldoc and eglot): Bug 1: 1. Open a file 2. Start eglot 3. Hover something with "C-h ." 4. Switch to the new window that popped up. 5. C-x k (kill buffer) 6. Repeat step 3. 7. "invalid buffer" and eldoc is dead. 8. Starting and stopping eldoc doesn't work This seems to happen since it uses the new buffer and updates it. When that buffer is deleted, it gets confused. Bug 2: 1. (setq eldoc-echo-area-use-multiline-p nil) 2. eglot spits the whole thing on one line. This looks a bit weird since it uses both the signature and the documentation. This may not be a bug, but right now IMO it looks a bit strange. Bug 3: 1. "M-:" 2. Type "(" 3. Minibuffer shows: eldoc-error: (wrong number of arguments (0 . 0) 1) I think the first bug is the most problematic one though :) However, I've started to take a liking to the no options set, with this version. I think I like the "truncate, press M-x ..." message more than the previous one. All the best, Theodor João Távora <joaotavora@gmail.com> writes: > [ Theodor and Fredrik, adding you since you were also interested in this > Eglot/Eldoc matter. You can review the messages in the bug list if > you're interested: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=41531] > > Andrii Kolomoiets <andreyk.mad@gmail.com> writes: > >> I was planning to remove the eglot-put-doc-in-help-buffer variable in >> the near future PR as well as the use of the eglot--message function for >> the documentation display ;-) > > I'm guess I'm happy to have shot these plans into the depths of the > ocean ;-) > >> However, after briefly using new Eldoc and Eglot I found some issues >> that, I hope, we can fix: >> >> 1. Display only first line of the hover info. Again :-) > > You should be able to do this with either > > (setq eldoc-echo-area-use-multiline-p 1) > > or > > (setq eldoc-echo-area-use-multiline-p nil) > > Did you try this? If so, what exactly didn't work for you when you did? > I'm sorry if you've already given me this information in the multiple > PR's you opened about this, but let's have it again. > >> 2. The hover info is sometimes displayed right before the signature info >> making the echo area to "blink". I suppose this must be fixed on Eglot >> side by not requesting both the hover and the signature infos at the >> same time. > > Not something to be fixed in Eglot, definitely, it's not its fault or > responsibility: it just reports whatever it has. I've fixed this in > Eldoc, in the last commit. It only affected the "eager" strategy (which > should really be called the "enthusiast" strategy). I'll post a commit > soon using better names for strategies, I'm thinking: > > eldoc-documentation-function -> eldoc-strategy (with obsolete alias) > eldoc-documentation-functions -> eldoc-functions (maybe) > > eldoc-documentation-default -> eldoc-patient > eldoc-documentation-compose -> eldoc-compose-patiently > eldoc-documentation-eager -> eldoc-enthusiast (Eglot uses this) > <doesn't exist yet> -> eldoc-compose-eagerly (Stefan mentioned this) > >> 3. That IMO useless "...truncated, see *help* buffer" message is moved >> to Eldoc. Do we really need to show this message every time? > > I see. Maybe not _every time_ but at least _once_, I'd say. Once per > Eldoc session (but what is an Eldoc session)? Once per x truncated > messages? Customization variable? (I hate those, but maybe). > > Or maybe never show it? > >> That one last line can be used to show additional documentation. >> Hadn't a chance to take a closer look at the code, so reporting those >> issues is the most I can do for now. > > Yes, and that's fine for now, though a second pair of eyes in the code > is certainly appreciated too. > > João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 28.0.50; proper Eldoc async support 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 1 sibling, 0 replies; 84+ messages in thread From: João Távora @ 2020-06-05 23:25 UTC (permalink / raw) To: Theodor Thornhill Cc: 41531, Andrii Kolomoiets, mvoteiza, Stefan Monnier, Dmitry Gutov, Fredrik Bergroth Theodor Thornhill <theothornhill@pm.me> writes: > Bug 1: > 1. Open a file > 2. Start eglot > 3. Hover something with "C-h ." > 4. Switch to the new window that popped up. > 5. C-x k (kill buffer) > 6. Repeat step 3. > 7. "invalid buffer" and eldoc is dead. > 8. Starting and stopping eldoc doesn't work > > This seems to happen since it uses the new buffer and updates it. When that buffer is deleted, it gets confused. Thanks. This is easy to fix. It's a buffer-live-p call somewhere. > Bug 2: > 1. (setq eldoc-echo-area-use-multiline-p nil) > 2. eglot spits the whole thing on one line. This looks a bit weird since it uses both the signature and the documentation. > > This may not be a bug, but right now IMO it looks a bit strange. It was intended. But I agree it's not good. I will change it: instead of joining all lines, then trucating, I will just truncate the first line if needed. > Bug 3: > 1. "M-:" > 2. Type "(" > 3. Minibuffer shows: eldoc-error: (wrong number of arguments (0 . 0) 1) I couldn't reproduce this one. > I think the first bug is the most problematic one though :) > > However, I've started to take a liking to the no options set, with > this version. I think I like the "truncate, press M-x ..." message > more than the previous one. Yes, and if `eldoc-doc-buffer` is bound to something shorter, then it will be even simpler to read. I will eventually recommend we rebind `C-h .` (display-local-help) to it. But in the meantime, I think I will make Eglot bind it to that key, as an exception to Eglot's no-keybindings policy. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 28.0.50; proper Eldoc async support 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 1 sibling, 0 replies; 84+ messages in thread From: João Távora @ 2020-06-05 23:28 UTC (permalink / raw) To: Theodor Thornhill Cc: 41531, Andrii Kolomoiets, mvoteiza, Stefan Monnier, Dmitry Gutov, Fredrik Bergroth Theodor Thornhill <theothornhill@pm.me> writes: > Bug 1: > 1. Open a file > 2. Start eglot > 3. Hover something with "C-h ." > 4. Switch to the new window that popped up. > 5. C-x k (kill buffer) > 6. Repeat step 3. > 7. "invalid buffer" and eldoc is dead. > 8. Starting and stopping eldoc doesn't work > > This seems to happen since it uses the new buffer and updates it. When that buffer is deleted, it gets confused. Thanks. This is easy to fix. It's a buffer-live-p call somewhere. > Bug 2: > 1. (setq eldoc-echo-area-use-multiline-p nil) > 2. eglot spits the whole thing on one line. This looks a bit weird since it uses both the signature and the documentation. > > This may not be a bug, but right now IMO it looks a bit strange. It was intended. But I agree it's not good. I will change it: instead of joining all lines, then trucating, I will just truncate the first line if needed. > Bug 3: > 1. "M-:" > 2. Type "(" > 3. Minibuffer shows: eldoc-error: (wrong number of arguments (0 . 0) 1) I couldn't reproduce this one. > I think the first bug is the most problematic one though :) > > However, I've started to take a liking to the no options set, with > this version. I think I like the "truncate, press M-x ..." message > more than the previous one. Yes, and if `eldoc-doc-buffer` is bound to something shorter, then it will be even simpler to read. I will eventually recommend we rebind `C-h .` (display-local-help) to it. But in the meantime, I think I will make Eglot bind it to that key, as an exception to Eglot's no-keybindings policy. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 28.0.50; proper Eldoc async support 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-11 11:11 ` Andrii Kolomoiets 1 sibling, 0 replies; 84+ messages in thread From: Andrii Kolomoiets @ 2020-06-11 11:11 UTC (permalink / raw) To: João Távora Cc: 41531, theothornhill, mvoteiza, Stefan Monnier, Dmitry Gutov, Fredrik Bergroth Sorry for the late reply. João Távora <joaotavora@gmail.com> writes: >> 1. Display only first line of the hover info. Again :-) > > You should be able to do this with either > > (setq eldoc-echo-area-use-multiline-p 1) > > or > > (setq eldoc-echo-area-use-multiline-p nil) > > Did you try this? If so, what exactly didn't work for you when you > did? This way the signature info is truncated. For the function with many parameters the info of the last parameters is not visible. >> 2. The hover info is sometimes displayed right before the signature info >> making the echo area to "blink". I suppose this must be fixed on Eglot >> side by not requesting both the hover and the signature infos at the >> same time. > > Not something to be fixed in Eglot, definitely, it's not its fault or > responsibility: it just reports whatever it has. According to specification, server may send `triggerCharacters` in the `SignatureHelpOptions`: the characters that trigger signature help automatically. Maybe Eglot should not always request the signature info. Though I like the current implementation. >> 3. That IMO useless "...truncated, see *help* buffer" message is moved >> to Eldoc. Do we really need to show this message every time? > > I see. Maybe not _every time_ but at least _once_, I'd say. Once per > Eldoc session (but what is an Eldoc session)? Once per x truncated > messages? Customization variable? (I hate those, but maybe). > > Or maybe never show it? Yep. Just like no additional message like "Press C-h v for the full documentation" is shown hovering the variable in the `emacs-lisp-mode`. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 2020-06-03 18:56 ` bug#41531: 28.0.50; proper Eldoc async support João Távora @ 2020-06-30 11:31 ` João Távora 2020-07-04 7:45 ` Eli Zaretskii 2020-07-04 10:04 ` Dmitry Gutov 2 siblings, 2 replies; 84+ messages in thread From: João Távora @ 2020-06-30 11:31 UTC (permalink / raw) To: 41531; +Cc: Stefan Monnier, andreyk.mad, Dmitry Gutov João Távora <joaotavora@gmail.com> writes: > 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. Hello again, The work that started with this discussion is now mostly complete. It has been sitting in the scratch/eldoc-async branch of the Savannah repo for a while, but I've been very busy and didn't have time to annouce it. I've cleaned it up to to a four commit effort which. 99fd115a8c Make more parts of Emacs use new Eldoc capabilities aaf5dfc71e * lisp/emacs-lisp/eldoc.el (Version): Bump to 1.1.0 62dc1d4824 New M-x eldoc for on-demand and interactive documentation requests 6c54414d5f Better handle asynchronous Eldoc sources I had good feedback on and off-list about it. It works with a version of Eglot in its scratch/work-with-new-eldoc branch. There is of course a lot that can still be fixed or added, especially in the domain of controlling the outlets for documentation (which now are restricted to the echo area, and poorly formatted buffer). Anyway I think my efforts are ready to push to master. I'll do so soon unless someone raises a serious problem about it. Dmitry has expressed his intent to make the new eldoc.el work with a new futures/promises library. He prototyped one of those libraries. I have nothing against that in the future. However, 1. I don't have the resources to make the eldoc.el prototype work with Dmitry's or other libraries; 2. We should revisit the purpose and the details of that and other libraries in a separate discussion. For now it's high time we advance the Eldoc libray;. Thanks, João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 ` (2 more replies) 2020-07-04 10:04 ` Dmitry Gutov 1 sibling, 3 replies; 84+ messages in thread From: Eli Zaretskii @ 2020-07-04 7:45 UTC (permalink / raw) To: João Távora; +Cc: 41531, monnier, andreyk.mad, dgutov > From: João Távora <joaotavora@gmail.com> > Date: Tue, 30 Jun 2020 12:31:10 +0100 > Cc: Stefan Monnier <monnier@iro.umontreal.ca>, andreyk.mad@gmail.com, > Dmitry Gutov <dgutov@yandex.ru> > > The work that started with this discussion is now mostly complete. It > has been sitting in the scratch/eldoc-async branch of the Savannah repo > for a while, but I've been very busy and didn't have time to annouce it. Thanks. > Anyway I think my efforts are ready to push to master. I'll do so soon > unless someone raises a serious problem about it. Not a serious problem, but some comments: > -(defun eldoc-message (&optional string) > +(make-obsolete > + 'eldoc-message "use `eldoc-documentation-functions' instead." "1.1.0") Isn't the version part of the obsolete message supposed to tell the version of Emacs? The change to the number of arguments of the functions in the eldoc-documentation-functions hook is backward-incompatible, isn't it? I see you've changed the relevant functions in our sources, but what about 3rd-party packages? Also, the doc string of this hook needs clarification regarding the arguments: it first says that CALLBACK is the only mandatory argument to the hook functions, but then, out of the blue, appear additional arguments DOCSTRING and a list of key-value pairs. Confusing. The doc strings have some words in UK English spelling "(e.g., "honour"), please fix that. Also, please make sure comments all start with a capital letter, end with a period, and comprise full English sentences. The doc string of eldoc-documentation-compose doesn't say a word about the function's argument. In the doc string of eldoc-documentation-strategy, you use the phrase "queries the special hook for all functions that produce doc strings" to mean, AFAIU, that the specified functions in the hook-variable list are called. IMO, this wording could be confusing; suggest to use this instead: `eldoc-documentation-compose': calls all the functions in the hook, and displays all of the resulting doc strings ... This doc string doesn't explain the use of the timer, it explains the reason for its existence. It should also describe the use: > +(defvar eldoc--enthusiasm-curbing-timer nil > + "Timer used by `eldoc-documentation-enthusiast' to avoid blinking.") Last, but not least: the "async" part of the branch's name hints on some advanced and extremely useful functionality that these changes are supposed to allow, but I see no mention of that in NEWS and in the manual bits. What did I miss? ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 11:00 ` João Távora 2020-07-05 12:03 ` João Távora 2 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-07-04 9:21 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 41531, Stefan Monnier, andreyk.mad, dgutov [-- Attachment #1: Type: text/plain, Size: 2935 bytes --] Thanks for the feedback, Eli. I'll get to each point later on. But I'm surprised the NEWS entry I had written got lost. In the git rebasing, maybe. João On Sat, Jul 4, 2020, 08:45 Eli Zaretskii <eliz@gnu.org> wrote: > > From: João Távora <joaotavora@gmail.com> > > Date: Tue, 30 Jun 2020 12:31:10 +0100 > > Cc: Stefan Monnier <monnier@iro.umontreal.ca>, andreyk.mad@gmail.com, > > Dmitry Gutov <dgutov@yandex.ru> > > > > The work that started with this discussion is now mostly complete. It > > has been sitting in the scratch/eldoc-async branch of the Savannah repo > > for a while, but I've been very busy and didn't have time to annouce it. > > Thanks. > > > Anyway I think my efforts are ready to push to master. I'll do so soon > > unless someone raises a serious problem about it. > > Not a serious problem, but some comments: > > > -(defun eldoc-message (&optional string) > > +(make-obsolete > > + 'eldoc-message "use `eldoc-documentation-functions' instead." "1.1.0") > > Isn't the version part of the obsolete message supposed to tell the > version of Emacs? > > The change to the number of arguments of the functions in the > eldoc-documentation-functions hook is backward-incompatible, isn't it? > I see you've changed the relevant functions in our sources, but what > about 3rd-party packages? > > Also, the doc string of this hook needs clarification regarding the > arguments: it first says that CALLBACK is the only mandatory argument > to the hook functions, but then, out of the blue, appear additional > arguments DOCSTRING and a list of key-value pairs. Confusing. > > The doc strings have some words in UK English spelling "(e.g., > "honour"), please fix that. Also, please make sure comments all start > with a capital letter, end with a period, and comprise full English > sentences. > > The doc string of eldoc-documentation-compose doesn't say a word about > the function's argument. > > In the doc string of eldoc-documentation-strategy, you use the phrase > "queries the special hook for all functions that produce doc strings" > to mean, AFAIU, that the specified functions in the hook-variable list > are called. IMO, this wording could be confusing; suggest to use this > instead: > > `eldoc-documentation-compose': calls all the functions in the hook, > and displays all of the resulting doc strings ... > > This doc string doesn't explain the use of the timer, it explains the > reason for its existence. It should also describe the use: > > > +(defvar eldoc--enthusiasm-curbing-timer nil > > + "Timer used by `eldoc-documentation-enthusiast' to avoid blinking.") > > Last, but not least: the "async" part of the branch's name hints on > some advanced and extremely useful functionality that these changes > are supposed to allow, but I see no mention of that in NEWS and in the > manual bits. What did I miss? > [-- Attachment #2: Type: text/html, Size: 3912 bytes --] ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Eli Zaretskii @ 2020-07-04 9:31 UTC (permalink / raw) To: João Távora; +Cc: 41531, monnier, andreyk.mad, dgutov > From: João Távora <joaotavora@gmail.com> > Date: Sat, 4 Jul 2020 10:21:43 +0100 > Cc: 41531@debbugs.gnu.org, Stefan Monnier <monnier@iro.umontreal.ca>, andreyk.mad@gmail.com, > dgutov@yandex.ru > > I'm surprised the NEWS entry I had written got lost. In the git rebasing, > maybe. There is a NEWS entry in the branch, but it only says this: -*** 'eldoc-documentation-function' is now a user option. -Modes should use the new hook instead of this user option to register -their backends. +*** New user option 'eldoc-documentation-strategy' +The built-in choices available for this user option let users compose +the results of 'eldoc-documentation-functions' in various ways. The +user option replaces 'eldoc-documentation-function', which is now +obsolete. I don't see how by reading this anyone could understand that the change allows significant new functionality. maybe you wrote more than that, and it did get lost somehow? (FTR, I did "git diff ...origin/scratch/eldoc-async" to see the changes on the branch.) ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-04 9:31 ` Eli Zaretskii @ 2020-07-04 9:37 ` João Távora 2020-07-04 9:44 ` Eli Zaretskii 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-07-04 9:37 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 41531, Stefan Monnier, andreyk.mad, dgutov [-- Attachment #1: Type: text/plain, Size: 1414 bytes --] Ah, ok I see what you mean. I didn't feel it was necessary to enter into details since it is backwards compatible. But I can add some things to mention that async is now supported in a "first class" sense. João On Sat, Jul 4, 2020, 10:31 Eli Zaretskii <eliz@gnu.org> wrote: > > From: João Távora <joaotavora@gmail.com> > > Date: Sat, 4 Jul 2020 10:21:43 +0100 > > Cc: 41531@debbugs.gnu.org, Stefan Monnier <monnier@iro.umontreal.ca>, > andreyk.mad@gmail.com, > > dgutov@yandex.ru > > > > I'm surprised the NEWS entry I had written got lost. In the git rebasing, > > maybe. > > There is a NEWS entry in the branch, but it only says this: > > -*** 'eldoc-documentation-function' is now a user option. > -Modes should use the new hook instead of this user option to register > -their backends. > +*** New user option 'eldoc-documentation-strategy' > +The built-in choices available for this user option let users compose > +the results of 'eldoc-documentation-functions' in various ways. The > +user option replaces 'eldoc-documentation-function', which is now > +obsolete. > > I don't see how by reading this anyone could understand that the > change allows significant new functionality. maybe you wrote more > than that, and it did get lost somehow? > > (FTR, I did "git diff ...origin/scratch/eldoc-async" to see the > changes on the branch.) > [-- Attachment #2: Type: text/html, Size: 2314 bytes --] ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-04 9:37 ` João Távora @ 2020-07-04 9:44 ` Eli Zaretskii 0 siblings, 0 replies; 84+ messages in thread From: Eli Zaretskii @ 2020-07-04 9:44 UTC (permalink / raw) To: João Távora; +Cc: 41531, monnier, andreyk.mad, dgutov > From: João Távora <joaotavora@gmail.com> > Date: Sat, 4 Jul 2020 10:37:50 +0100 > Cc: 41531@debbugs.gnu.org, Stefan Monnier <monnier@iro.umontreal.ca>, andreyk.mad@gmail.com, > dgutov@yandex.ru > > I can add some things to mention that async is now supported in a > "first class" sense. Please do, I think it's important. You don't have to tell too many details in NEWS about that, just mention it, and say that the details are in the ELisp manual and the doc strings of this-and-that. TIA ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-04 7:45 ` Eli Zaretskii 2020-07-04 9:21 ` João Távora @ 2020-07-04 11:00 ` João Távora 2020-07-04 21:06 ` Dmitry Gutov 2020-07-05 12:03 ` João Távora 2 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-07-04 11:00 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 41531, monnier, andreyk.mad, dgutov Eli Zaretskii <eliz@gnu.org> writes: >> Anyway I think my efforts are ready to push to master. I'll do so soon >> unless someone raises a serious problem about it. > > Not a serious problem, but some comments: > >> -(defun eldoc-message (&optional string) >> +(make-obsolete >> + 'eldoc-message "use `eldoc-documentation-functions' instead." "1.1.0") > > Isn't the version part of the obsolete message supposed to tell the > version of Emacs? Yes, but eldoc.el is its own versioned piece of software now, because it is a GNU Elpa :core package. So I opted to use that versioning instead. Maybe I shouldn't have? Don't know if there's prior art for this situation, but I'm reasonably confident I personally have taken this decision before. > The change to the number of arguments of the functions in the > eldoc-documentation-functions hook is backward-incompatible, isn't it? > I see you've changed the relevant functions in our sources, but what > about 3rd-party packages? I've checked and there were none. The eldoc-documentation-functions variable came to be in Emacs master: it's not in Emacs 27. I myself "released" eldoc.el to GNU Elpa almost 2 months ago (see 9ebf51999ce58cccc2a228fd07a18c7b472dd3fd). I had intended to streamline that release together with these async-related developments, but reality (and mostly Dmitry :-) intervened. So indeed there is the danger that, in the intervening 2 months, some 3rd party package depending on GNU Elpa's Eldoc, started using the argless eldoc-documentation-functions, and will be surprised by this backwards-incompatible change. However, I think the changes of that are unlikely. I searched Github and Google for such references and couldn't find any. So I think it's safe. (But even if it weren't, I'd still argue for the change + fallout ). > Also, the doc string of this hook needs clarification regarding the > arguments: it first says that CALLBACK is the only mandatory argument > to the hook functions, but then, out of the blue, appear additional > arguments DOCSTRING and a list of key-value pairs. Confusing. Understood. > The doc strings have some words in UK English spelling "(e.g., > "honour"), please fix that. Also, please make sure comments all start > with a capital letter, end with a period, and comprise full English > sentences. OK. > The doc string of eldoc-documentation-compose doesn't say a word about > the function's argument. That function isn't meant to be called by users, and the EAGERLYP is a code-saving trick. But of course I should document it. > In the doc string of eldoc-documentation-strategy, you use the phrase > "queries the special hook for all functions that produce doc strings" > to mean, AFAIU, that the specified functions in the hook-variable list > are called. IMO, this wording could be confusing; suggest to use this > instead: > > `eldoc-documentation-compose': calls all the functions in the hook, > and displays all of the resulting doc strings ... This of course, assumes that people know that "functions in the hook" aren't like "functions in a list". The symbol `t` may be in "in the hook". But it's better for practical purposed, I admit. Because "result" is often conflated with "return value", and that's only _one_ of the ways the functions can produce doc strings, I'd modify that to: `eldoc-documentation-compose': calls all the functions in the hook, and displays the doc strings that they produce... > > This doc string doesn't explain the use of the timer, it explains the > reason for its existence. It should also describe the use: > >> +(defvar eldoc--enthusiasm-curbing-timer nil >> + "Timer used by `eldoc-documentation-enthusiast' to avoid >blinking.") OK. > Last, but not least: the "async" part of the branch's name hints on > some advanced and extremely useful functionality that these changes > are supposed to allow, but I see no mention of that in NEWS and in the > manual bits. What did I miss? Not much, we talked about this. Will change NEWS according to what we discussed. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-04 21:06 UTC (permalink / raw) To: João Távora, Eli Zaretskii; +Cc: 41531, monnier, andreyk.mad On 04.07.2020 14:00, João Távora wrote: > I had intended to streamline > that release together with these async-related developments, but reality > (and mostly Dmitry:-) intervened. To be fair to yours truly, though, AFAIK we are the only two people in this discussion who maintain third-party eldoc clients, or work on integrated development experience in general. That's a pretty sad state of affairs, BTW. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-04 21:06 ` Dmitry Gutov @ 2020-07-04 23:12 ` João Távora 2020-07-07 0:43 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-07-04 23:12 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: > On 04.07.2020 14:00, João Távora wrote: >> I had intended to streamline >> that release together with these async-related developments, but reality >> (and mostly Dmitry:-) intervened. > > To be fair to yours truly, though, AFAIK we are the only two people in > this discussion who maintain third-party eldoc clients, or work on > integrated development experience in general. > > That's a pretty sad state of affairs, BTW. I actually have multiple people working with me in Eglot, potentially eager to see how things in Emacs core can be solved properly and effectively, and being utterly disappointed by your opposition in this eldoc.el case. That's the sad state of affairs IMO. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-07 0:43 UTC (permalink / raw) To: João Távora; +Cc: 41531, monnier, andreyk.mad On 05.07.2020 02:12, João Távora wrote: > I actually have multiple people working with me in Eglot, potentially > eager to see how things in Emacs core can be solved properly and > effectively, and being utterly disappointed by your opposition in this > eldoc.el case. That's the sad state of affairs IMO. A part of "solving things properly" is listening to feedback. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 0:43 ` Dmitry Gutov @ 2020-07-07 10:58 ` João Távora 2020-07-07 14:18 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-07-07 10:58 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: > On 05.07.2020 02:12, João Távora wrote: >> I actually have multiple people working with me in Eglot, potentially >> eager to see how things in Emacs core can be solved properly and >> effectively, and being utterly disappointed by your opposition in this >> eldoc.el case. That's the sad state of affairs IMO. > > A part of "solving things properly" is listening to feedback. I've told you this before: you mistake attention for obedience. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-07 14:18 UTC (permalink / raw) To: João Távora; +Cc: 41531, monnier, andreyk.mad On 07.07.2020 13:58, João Távora wrote: > I've told you this before: you mistake attention for obedience. Most of the time I feel you're not even addressing my points. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 14:18 ` Dmitry Gutov @ 2020-07-07 14:34 ` João Távora 0 siblings, 0 replies; 84+ messages in thread From: João Távora @ 2020-07-07 14:34 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: > On 07.07.2020 13:58, João Távora wrote: >> I've told you this before: you mistake attention for obedience. > > Most of the time I feel you're not even addressing my points. I try my best, but I don't have any control over your feelings :-) ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-04 7:45 ` Eli Zaretskii 2020-07-04 9:21 ` João Távora 2020-07-04 11:00 ` 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 2 siblings, 2 replies; 84+ messages in thread From: João Távora @ 2020-07-05 12:03 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 41531, monnier, andreyk.mad, dgutov Eli Zaretskii <eliz@gnu.org> writes: >> -(defun eldoc-message (&optional string) >> +(make-obsolete >> + 'eldoc-message "use `eldoc-documentation-functions' instead." "1.1.0") > > Isn't the version part of the obsolete message supposed to tell the > version of Emacs? Stuck with "1.1.0", because of the GNU ELPA criterion. But maybe the string could be "1.1.0-elpa" or something like that. > The change to the number of arguments of the functions in the > eldoc-documentation-functions hook is backward-incompatible, isn't it? > I see you've changed the relevant functions in our sources, but what > about 3rd-party packages? Answered this already. > Also, the doc string of this hook needs clarification regarding the > arguments: it first says that CALLBACK is the only mandatory argument > to the hook functions, but then, out of the blue, appear additional > arguments DOCSTRING and a list of key-value pairs. Confusing. Changed that paragraph to To call the CALLBACK function, the hook function must pass it an obligatory argument DOCSTRING, a string containing the documentation, followed by an optional list of keyword-value pairs of the form (:KEY VALUE :KEY2 VALUE2...). KEY can be: The situation is very similar to Flymake's flymake-diagnostic-functions. If you still find this docstring confusing, maybe I should copy that docstring's structure. > The doc strings have some words in UK English spelling "(e.g., > "honour"), please fix that. Also, please make sure comments all start > with a capital letter, end with a period, and comprise full English > sentences. I fixed all I could find, but is this a a hard rule? I like to break it once in a while: ;; We have to foo bar separately ... (foo bar) ;; ... because the bazness might be too quuxy. (if (quux) (foo baz)) I ended up not doing that this time, though. > The doc string of eldoc-documentation-compose doesn't say a word about > the function's argument. I fixed that by creating a helper eldoc--documentation-compose-1 that both eldoc-documentation-compose and eldoc-documentation-compose-eagerly call. I describe the arg in the helper. > This doc string doesn't explain the use of the timer, it explains the > reason for its existence. It should also describe the use: See the new version below. I think it is sufficient. Be aware this is an internal variable, we don't even let the user customize the time (we could though, but I think it's overcomplicating, for now). (defvar eldoc--enthusiasm-curbing-timer nil "Timer used by the `eldoc-documentation-enthusiast' strategy. When a doc string is encountered, it must endure a certain amount of time unchallenged until it is displayed to the user. This prevents blinking if a lower priority docstring comes in shortly before a higher priority one.") > Last, but not least: the "async" part of the branch's name hints on > some advanced and extremely useful functionality that these changes > are supposed to allow, but I see no mention of that in NEWS and in the > manual bits. What did I miss? I reworded it, caught a bug, and mentioned eldoc-echo-area-use-multiline-p. Let me know it if you're missing anything. João PS: Actually a proper section for Eldoc in the Emacs manual is probably missing, but I don't have time to work on it straight away. Or at least I think the fix should go in first. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-05 12:03 ` João Távora @ 2020-07-05 15:09 ` Eli Zaretskii 2020-07-05 15:13 ` Stefan Monnier 1 sibling, 0 replies; 84+ messages in thread From: Eli Zaretskii @ 2020-07-05 15:09 UTC (permalink / raw) To: João Távora; +Cc: 41531, monnier, andreyk.mad, dgutov > From: João Távora <joaotavora@gmail.com> > Cc: 41531@debbugs.gnu.org, monnier@iro.umontreal.ca, > andreyk.mad@gmail.com, dgutov@yandex.ru > Date: Sun, 05 Jul 2020 13:03:48 +0100 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> -(defun eldoc-message (&optional string) > >> +(make-obsolete > >> + 'eldoc-message "use `eldoc-documentation-functions' instead." "1.1.0") > > > > Isn't the version part of the obsolete message supposed to tell the > > version of Emacs? > > Stuck with "1.1.0", because of the GNU ELPA criterion. But maybe the > string could be "1.1.0-elpa" or something like that. AFAIK, the obsolescence message we display says "since N.M.X", and the intent is always to an Emacs version, right? How can the user understand that in this case you are talking about the version of some other package? > > The doc strings have some words in UK English spelling "(e.g., > > "honour"), please fix that. Also, please make sure comments all start > > with a capital letter, end with a period, and comprise full English > > sentences. > > I fixed all I could find, but is this a a hard rule? I like to break it > once in a while: > > ;; We have to foo bar separately ... > (foo bar) > ;; ... because the bazness might be too quuxy. > (if (quux) (foo baz)) This is fine. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-05 12:03 ` João Távora 2020-07-05 15:09 ` Eli Zaretskii @ 2020-07-05 15:13 ` Stefan Monnier 1 sibling, 0 replies; 84+ messages in thread From: Stefan Monnier @ 2020-07-05 15:13 UTC (permalink / raw) To: João Távora; +Cc: 41531, andreyk.mad, dgutov >>> -(defun eldoc-message (&optional string) >>> +(make-obsolete >>> + 'eldoc-message "use `eldoc-documentation-functions' instead." "1.1.0") >> >> Isn't the version part of the obsolete message supposed to tell the >> version of Emacs? > > Stuck with "1.1.0", because of the GNU ELPA criterion. But maybe the > string could be "1.1.0-elpa" or something like that. I recommend "eldoc-1.1.0" to clarify which version number we're talking about. Stefan ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 10:04 ` Dmitry Gutov 2020-07-04 11:48 ` João Távora 1 sibling, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-04 10:04 UTC (permalink / raw) To: João Távora, 41531; +Cc: Stefan Monnier, andreyk.mad On 30.06.2020 14:31, João Távora wrote: > Dmitry has expressed his intent to make the new eldoc.el work with a new > futures/promises library. He prototyped one of those libraries. I have > nothing against that in the future. However, > > 1. I don't have the resources to make the eldoc.el prototype work with > Dmitry's or other libraries; > > 2. We should revisit the purpose and the details of that and other > libraries in a separate discussion. For now it's high time we > advance the Eldoc libray;. Unsurprisingly, I object to this approach. We should have better async support in multiple Emacs facilities, and that means standardizing on some particular async primitives and functions that can manipulate them. There is no need to release support for ad-hoc async values (you didn't like mine, so it's only fair play that I object to yours) when we can transition to full futures right away. I'll get into a little more detail in the more full review, tonight or tomorrow, but for now my impression is that, in the absence of such standard library and async manipulation functions, you decided to implement them specially in Eldoc. Even though most of that logic should be extracted to general purpose code that manipulates async objects (futures/promises or the like). And I wonder how the desire not to have such logic in Eglot has influenced your total vision of the API. Because with futures in standard library, it could look fairly different, and could need fewer changes compared to its current shape. Regarding #1, it should be trivial to reimplement on top of futures. I could do this myself, as long as everybody is fine with the proposed shape of futures on standardize on. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-04 10:04 ` Dmitry Gutov @ 2020-07-04 11:48 ` João Távora 2020-07-04 21:27 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-07-04 11:48 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: > On 30.06.2020 14:31, João Távora wrote: >> Dmitry has expressed his intent to make the new eldoc.el work with a new >> futures/promises library. He prototyped one of those libraries. I have >> nothing against that in the future. However, >> 1. I don't have the resources to make the eldoc.el prototype work >> with >> Dmitry's or other libraries; >> 2. We should revisit the purpose and the details of that and other >> libraries in a separate discussion. For now it's high time we >> advance the Eldoc libray;. > > Unsurprisingly, I object to this approach. We should have better async > support in multiple Emacs facilities, and that means standardizing on > some particular async primitives and functions that can manipulate > them. There is no need to release support for ad-hoc async values (you > didn't like mine, so it's only fair play that I object to yours) when > we can transition to full futures right away. I haven't seen a consistent plan "for transitioning to futures". All I've seen is (complicated, IMO) ideas on how to avoid the callback-calling style by hiding the callback in an object. I've seen little argument or discussion of what futures are supposed to do or fix or improve. And I've seen no feedback from the author of what seems to be the most promising futures library, aio.el which uses the generator.el library, to provide, presumably, more elegant "language-level" futures (i.e. futures that aren't only hiding the callback in some other object). Despite that, I've stated here repeatedly, tiringly: In principle, I don't object to futures at all. I just think it has to be a thought-through change. Propose your library to emacs-devel and let's iterate it there. > I'll get into a little more detail in the more full review, tonight or > tomorrow, but for now my impression is that, in the absence of such > standard library and async manipulation functions, you decided to > implement them specially in Eldoc. Of course, and that's what engineering is about. For the most trivial of changes X there is _always_ a refactoring R that will make implementing X and a possible Y and Z much simpler, more elegant, more "meta". Knowing where to stop is what this game is about. In this case, there is only a vision what Y and Z might be, and a foggier vision of how bad/good design decisions in R might affect them. So I fixed the real, actual problem in Eldoc using the async paradigm that is widely used in Emacs and most widely understood by programmers of all (most?) trades: callbacks. And, again, for the nth time, there is nothing in my code that prevents your -- or someone else's -- "futures" library to be the nec plus ultra of async in Emacs. But, in the meantime, I won't let you make these Eldoc changes hostage to your predilection for futures. It's quite a legitimate inclination, of course, it musn't be needlessly put it in the way of other's work. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 2 replies; 84+ messages in thread From: Dmitry Gutov @ 2020-07-04 21:27 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, andreyk.mad On 04.07.2020 14:48, João Távora wrote: >> Unsurprisingly, I object to this approach. We should have better async >> support in multiple Emacs facilities, and that means standardizing on >> some particular async primitives and functions that can manipulate >> them. There is no need to release support for ad-hoc async values (you >> didn't like mine, so it's only fair play that I object to yours) when >> we can transition to full futures right away. > > I haven't seen a consistent plan "for transitioning to futures". Do you want to see the patch based on your code? It's the only "transition" I meant here. If you have other questions, please ask. > All > I've seen is (complicated, IMO) ideas on how to avoid the > callback-calling style by hiding the callback in an object. Hiding is absolutely not the point. > I've seen > little argument or discussion of what futures are supposed to do or fix > or improve. I think I have described at length the very simple idea of what it is supposed to improve: provide a standard primitive and a library of composition/manipulation functions that would make these operations simpler. Which can be used in Emacs core, and in clients of the various facilities and expose future-based interfaces. > And I've seen no feedback from the author of what seems to > be the most promising futures library, aio.el which uses the > generator.el library, to provide, presumably, more elegant > "language-level" futures (i.e. futures that aren't only hiding the > callback in some other object). I'm very curious to know Christopher's opinion myself. Based on my experience, this will result in a much longer, protracted discussion, if it will result in one at all. You seem to be in a hurry to get this in for some reason, but I'm fine with waiting a little more, if we get a better result. > Despite that, I've stated here repeatedly, tiringly: In principle, I > don't object to futures at all. I just think it has to be a > thought-through change. Propose your library to emacs-devel and let's > iterate it there. If you think emacs-devel will bring more feedback, no problem. >> I'll get into a little more detail in the more full review, tonight or >> tomorrow, but for now my impression is that, in the absence of such >> standard library and async manipulation functions, you decided to >> implement them specially in Eldoc. > > Of course, and that's what engineering is about. For the most trivial > of changes X there is _always_ a refactoring R that will make > implementing X and a possible Y and Z much simpler, more elegant, more > "meta". Knowing where to stop is what this game is about. In this > case, there is only a vision what Y and Z might be, and a foggier vision > of how bad/good design decisions in R might affect them. The thing about refactoring, is it doesn't change observable behavior. Refactoring would keep the stable interface (and e.g. reuse future-based utility functions under the covers). Whereas the improvement I would like to see here, would change it. So it's not something that could be simply moved to backlog. And as I intent to explain later, I believe you will need future-manipulating functions inside eldoc client code anyway, for best user experience. So we might as well bite the bullet and introduce futures at the API level. > So I fixed the real, actual problem in Eldoc using the async paradigm > that is widely used in Emacs and most widely understood by programmers > of all (most?) trades: callbacks. Please recall how you rejected my proposal along the same lines. And it's fine. We can do better. > And, again, for the nth time, there is nothing in my code that prevents > your -- or someone else's -- "futures" library to be the nec plus ultra > of async in Emacs. But, in the meantime, I won't let you make these > Eldoc changes hostage to your predilection for futures. "won't let you" is not exactly how things work here. We usually try hard to reach a consensus. In any case, I have considered this for some time, and my arguments for "let's work on this some more" won't be limited to futures-vs-callbacks. > It's quite a > legitimate inclination, of course, it musn't be needlessly put it in the > way of other's work. I agree that there are improvements to be made in documentation-related code (whether it's in Eldoc, or not), and I also think that you might not be going far enough in some respects. But the problem you seem to be urgent to fix (having eldoc-message called from client code) is not so terrible that we can't wait until the future-related discussion at least has had a chance to happen. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-04 21:27 ` Dmitry Gutov @ 2020-07-04 21:30 ` Dmitry Gutov 2020-07-04 23:07 ` João Távora 1 sibling, 0 replies; 84+ messages in thread From: Dmitry Gutov @ 2020-07-04 21:30 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, andreyk.mad Sorry, On 05.07.2020 00:27, Dmitry Gutov wrote: >> And I've seen no feedback from the author of what seems to >> be the most promising futures library, aio.el which uses the >> generator.el library, to provide, presumably, more elegant >> "language-level" futures (i.e. futures that aren't only hiding the >> callback in some other object). > > I'm very curious to know Christopher's opinion myself. Based on my ^ But > experience, this will result in a much longer, protracted discussion, if ^ [moving it to emacs-devel] > it will result in one at all. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 1 sibling, 1 reply; 84+ messages in thread From: João Távora @ 2020-07-04 23:07 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: > [that is the] "transition" I meant here. > > If you have other questions, please ask. If it wasn't clear, my suggestion is that you send your earlier dimtry-futures.el (as I am temporarily dubbing it, for clarity) to emacs-devel, along with a rationale for why it is needed and where it can be useful, not only in eldoc.el but in other places in Emacs that use callbacks like like url.el, flymake.el, jsonrpc.rl, timers, completion, processes, etc. You may want to include a short comparison to Christopher Wellon's aio.el, if you have studied it. > I think I have described at length the very simple idea of what it is > supposed to improve: provide a standard primitive and a library of > composition/manipulation functions that would make these operations > simpler. Which can be used in Emacs core, and in clients of the > various facilities and expose future-based interfaces. Maybe I missed something, but I don't consider our discussion an at-length discussion. It might have been verbose, but it wasn't in-depth at all. And certainly it didn't involve anywhere enough people for such an ambitious feature. I have some comments to your last proposed dmitry-futures.el, but this bug report is not the place to make them. >> And I've seen no feedback from the author of what seems to >> be the most promising futures library, aio.el which uses the >> generator.el library, to provide, presumably, more elegant >> "language-level" futures (i.e. futures that aren't only hiding the >> callback in some other object). > > I'm very curious to know Christopher's opinion myself. Based on my > experience, this will result in a much longer, protracted discussion, > if it will result in one at all. > > You seem to be in a hurry to get this in for some reason, but I'm fine > with waiting a little more, if we get a better result. I want to fix longstanding problems in Eglot. I have limited resources, mainly time. It is you who seem intent on not letting this go in, as if you won't be able to prove that "better result" after it does. This is absurd: if you do show it to be better, then we should migrate eldoc.el etc to futures. ...as I've said a trillion times already at this point. > Please recall how you rejected my proposal along the same lines. I don't remember your proposal fixing anything in eldoc.el, you merely suggested I experimented with a technique. Which I actually did, and I didn't see any advantage in it. > And it's fine. We can do better. I'm sorry you don't like my work. I had good feedback about it. If _you_ can do better, I'm not stopping you. >> And, again, for the nth time, there is nothing in my code that prevents >> your -- or someone else's -- "futures" library to be the nec plus ultra >> of async in Emacs. But, in the meantime, I won't let you make these >> Eldoc changes hostage to your predilection for futures. > > "won't let you" is not exactly how things work here. We usually try > hard to reach a consensus. In my book, there's nothing legitimate in vetoing a bugfix because of some yearning for some particular abstraction or programming paradigm. That's as absurd as demanding Emacs be rewritten in my paradigm/language of choice before anyone else commits anything. Especially when, for the quadrillionth time, there is nothing stopping you from making your case for futures after the bug is fixed. > In any case, I have considered this for some time, and my arguments > for "let's work on this some more" won't be limited to > futures-vs-callbacks. In that case, if indeed they are not futures-vs-callbacks, are they _serious_ objections? Can they not be fixed afterwards? I would have expected some manifestation of them already, but you seem to waste all your energy on your proclivity for futures. But very well then, let's have those non-futures objections in this bug report, the sooner the better. >> legitimate inclination, of course, it musn't be needlessly put it in the >> way of other's work. > > I agree that there are improvements to be made in > documentation-related code (whether it's in Eldoc, or not), and I also > think that you might not be going far enough in some respects. > > But the problem you seem to be urgent to fix (having eldoc-message > called from client code) is not so terrible that we can't wait until > the future-related discussion at least has had a chance to happen. I've explained repeatedly: this is holding up multiple things in Eglot. I want Eglot to serve diagnostic messages, and various kinds of automatically gathered information about the "things at point" all through eldoc.el. Then move on to better stuff, of which there is a lot in LSP, as you well know. Also, this fixes SLY and SLIME too, both hacking their way through eldoc.el. Possibly the same for CIDER and other such extensions. This also opens up eldoc.el in non-async situations as well, such as elisp-mode.el. Just read the patch. Look, Dmitry, think clearly: I'm going to fix eldoc.el and you can have your futures.el discussion when you want, a discussion where don't know if I'll be able to participate, but that shouldn't prevent it from happening. After that discussion, whatever conclusion you, possibly me, and other interested parties arrive at, as long as you/we keep Eglot and SLY functional, or suggest improvements to them, I'll abide. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-07 3:01 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, andreyk.mad On 05.07.2020 02:07, João Távora wrote: > Dmitry Gutov <dgutov@yandex.ru> writes: > >> [that is the] "transition" I meant here. >> >> If you have other questions, please ask. I meant questions about futures as pertaining to eldoc, of course. I have other uses in mind, but redoing existing features is a less urgent endeavor. E.g., Flymake is stable, and I don't have any particular bugs in mind that need solving. So I'd be fine with keeping it as is. Unless someone wanted to take advantage of extra features that futures provide. > If it wasn't clear, my suggestion is that you send your earlier > dimtry-futures.el (as I am temporarily dubbing it, for clarity) to > emacs-devel, along with a rationale for why it is needed and where it > can be useful, not only in eldoc.el but in other places in Emacs that > use callbacks like like url.el, flymake.el, jsonrpc.rl, timers, > completion, processes, etc. You may want to include a short comparison > to Christopher Wellon's aio.el, if you have studied it. Yes, will do. But note that when I argue for futures, it's for basically any implementation that has a container for such values, and a set of common functions for manipulating them. Christopher's version would serve that just fine (with copyright assignment signed). Which exact version to choose, however, can indeed be discussed separately. >> I think I have described at length the very simple idea of what it is >> supposed to improve: provide a standard primitive and a library of >> composition/manipulation functions that would make these operations >> simpler. Which can be used in Emacs core, and in clients of the >> various facilities and expose future-based interfaces. > > Maybe I missed something, but I don't consider our discussion an > at-length discussion. It also wasn't a discussion really. Too one-sided. >> You seem to be in a hurry to get this in for some reason, but I'm fine >> with waiting a little more, if we get a better result. > > I want to fix longstanding problems in Eglot. I have limited resources, > mainly time. It is you who seem intent on not letting this go in, as if > you won't be able to prove that "better result" after it does. This is > absurd: if you do show it to be better, then we should migrate eldoc.el > etc to futures. ...as I've said a trillion times already at this point. Please don't make it sound as if I'm the only one here having a strong opinion about proposed code. You disregarded the simple solution in https://debbugs.gnu.org/cgi/bugreport.cgi?bug=41531#8, and then went on with your own vision of of "simple" function based async, full on with extra features and additional incompatible API changes. >> Please recall how you rejected my proposal along the same lines. > > I don't remember your proposal fixing anything in eldoc.el, you merely > suggested I experimented with a technique. Which I actually did, and I > didn't see any advantage in it. It certainly did away with clients having to call eldoc-message. And if shorter code and better backward compatibility are not advantages, we might disagree hard on the meaning of the word. >> But the problem you seem to be urgent to fix (having eldoc-message >> called from client code) is not so terrible that we can't wait until >> the future-related discussion at least has had a chance to happen. > > I've explained repeatedly: this is holding up multiple things in Eglot. > I want Eglot to serve diagnostic messages, and various kinds of > automatically gathered information about the "things at point" all > through eldoc.el. Then move on to better stuff, of which there is a lot > in LSP, as you well know. Also, this fixes SLY and SLIME too, both > hacking their way through eldoc.el. Possibly the same for CIDER and > other such extensions. This also opens up eldoc.el in non-async > situations as well, such as elisp-mode.el. Just read the patch. Aside: given that this discussion has user interface in mind, it needs more consideration of actual user experiences we'd want to allow. Ones not provided by eldoc itself as well. For instance, I think we sooner or later should have a callsig floating popup (in the vein of MS's editors) as an alternative to showing the signature in the echo area only. > But very well then, let's > have those non-futures objections in this bug report, the sooner the > better. To be sure, they will also contain the "how we could do this better" kind of arguments. Let's start with the basics: The new API is incompatible with the previous one, it requires changing a lot of functions (though admittedly in a minor way). Which is easy to miss, as evidenced by describe-char-eldoc which still doesn't accept any arguments. Whereas we could limit ourselves to the change which would only make the clients use the different hook (or keep using the old one, for compatibility with older Flymake/Emacs versions). The choice to require a return of a non-nil value if the callback is going to be used is also kinda odd (+1 control flow to test). What's the problem with using the callback synchronously if the doc is available right away? The decision to double down on having different eldoc-documentation-strategy values seems odd to me in several respects. First of all, if I understand the main motivation behind it, it's to delegate the implementation of asynchronous primitives to Eldoc. We don't want to bother with that in Eglot, etc. But you mentioned "a type of docstring" to be returned in the discussion (and the callbacks have the plist argument as a future proofing). If the type is a buffer, its contents might as well be created from several async calls, which would require the same async primitives (though rather in general purpose form) available on the client anyway. Though it doesn't seem to be necessary for LSP in common operations, it's unlikely to be the only such protocol we'd ever want to support. The strategies themselves: - eldoc-documentation-enthusiast: What's the difference compared to the 'default' one? Sacrificing CPU load for lower latency? It's an odd choice to force the user to make. The only people who can make an ideal decision regarding this are probably the authors of eldoc-documentation-functions, but it wouldn't help if eldoc-documentation-functions has functions coming from different authors, facilities, etc. - eldoc-documentation-compose: Okay, this is kinda interesting (though not essential), and the implementation is not working as well as I'd hoped it would. It makes the echo area blink up and down as I move the cursor around. There's no expected truncation of individual docstrings when they don't fit in the window's width. And I don't understand what you expect it to do if several docstrings are multiline, and as an aggregate they don't fit the target height. I think the only reasonably predictable behavior would be to truncate each of them to one line, always. - eldoc-documentation-compose-eagerly: Ooh, now I think I see why documentation functions have to return these non-nil, non-string values. Is it that this particular strategy wouldn't have to wait too long for documentation functions that never intended to call back? Returning futures instead (when async is needed) would provide this kind of guarantee without the seeming duplication of signals. On a related note, I believe some facilities might want to use only certain "kinds" of documentation functions (as indicated by the plist arguments). If the plist is only provided together with the response, there is no way to avoid unnecessary computations (e.g. making HTTP requests that return some other kinds of values). If the plist was returned together with a future value, however, it would be easy to do, as long as we document that the futures should start the computation until a callback is provided (if possible, at least). And in a different high-level argument: you stated that you intend to have Eglot use a non-default value of eldoc-documentation-strategy. Which would basically have you use Eldoc as a library, controlling both the list of documentation functions and how they are composed. Whereas having the eldoc-documentation-strategy defcustom at all makes it seem like the user's choice, and that all Eldoc clients must be able to perform well under any strategy chosen by the user. We might want to think twice before introducing such responsibility. Next, eldoc-print-current-symbol-info is a mess, very hard to follow. I am frankly offended that you argued that both ad-hoc futures I showed, or any potential "proper" ones would make backtraces hard to read and debug, and then introduced this kind of control flow with callbacks calling dynamically generated callbacks, retrieved from a variable dynamically set in a caller function up the stack (to be clear: I think having eldoc--make-callback variable at all is a bad idea). This should very well be possible to untangle in the future, but I'd rather not have code like this in Emacs if we can help it. Further, having all strategies basically delegate to hardcoded options inside eldoc-print-current-symbol-info seems to confirm that the set of available strategies is a closed one. Which is not what I would expect from a variable called eldoc-documentation-strategy. These are my objections, for now. I'll have to study eldoc--handle-docs a bit later, but any problems it has are probably orthogonal to the rest of the list. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 ` (3 more replies) 0 siblings, 4 replies; 84+ messages in thread From: João Távora @ 2020-07-07 10:56 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: > Please don't make it sound as if I'm the only one here having a strong > opinion about proposed code. You disregarded the simple solution in > https://debbugs.gnu.org/cgi/bugreport.cgi?bug=41531#8, and then went Are you in any way trying to say that you presented a "simple solution" that somehow magically solves the problems of Eldoc? If you do, you're living in conflict with reality. There is the problem to be solved. And then there are techniques for solving the problem. These are two entirely separate things. To be absolutely clear: you have not, ever, proposed an alternate solution to the Eldoc async _problem_. You talked and talked and presented your favourite async handling techniques, like having functions return functions that return functions. You contented that I -- not you -- should work with it to solve the problem. Callbacks, futures, promises, ad-hoc or proper, are just techniques. I tried a couple techniques, including a basic futures-based one proposed by Stefan. I didn't find any as compelling as the simplest and most widely used in Emacs: callbacks. For the quintillionth time: I AM NOT AGAINST FUTURES IN PRINCIPLE: I just don't use these Eldoc fixes to shoehorn something rushedly into Emacs. Make a new thread, or join the existing one: https://lists.gnu.org/archive/html/emacs-devel/2020-03/msg00935.html Afterwards, propose a change to the technique, not only in Eldoc but elsewhere, too. This idea is so simple that it boggles the mind that you don't grasp it. > urgent endeavor. E.g., Flymake is stable, and I don't have any > particular bugs in mind that need solving. Great. I'll just note here that it uses exactly the same technique I'm proposing in Eldoc to communicate with multiple backends: it's curious how that doesn't bother you. I would reasonably expect "futures" or something else its implementation much simpler too. > Aside: given that this discussion has user interface in mind, it needs > more consideration of actual user experiences we'd want to allow. Ones > not provided by eldoc itself as well. For instance, I think we sooner > or later should have a callsig floating popup (in the vein of MS's > editors) as an alternative to showing the signature in the echo area > only. That is addressed in a comment in eldoc-docs ;; Finally, output to the echo area. We handle the ;; `truncate-sym-name-if-fit' special case first, by selecting a ;; top-section of the `*eldoc' buffer. I'm pretty sure nicer ;; strategies can be used here, probably by splitting this ;; function into some `eldoc-display-functions' special hook. I agree there is ample space for improvement, including a "floating popup" (which I wouldn't limit to callsigs though). Make another bug report to study this. > The new API is incompatible with the previous one, it requires > changing a lot of functions (though admittedly in a minor way). This is demonstrably false. As I've explained to Eli there is no incompatibility in practice. 0 (zero) third-party extensions make use of the protocol being changed from Eldoc 1.0.0 to Eldoc 1.1.0, unless you're stalling here to secretly work on one. But if we really, really wanted to, it's easy to get rid of the arguments, too, with a variation to the callback technique. I just don't think it's worth it: a technique is a technique. > is easy to miss, as evidenced by describe-char-eldoc which still > doesn't accept any arguments. Oh, an actual useful comment! Easily solved, thanks. And it was only "missed" because it wasn't used anywhere. > Whereas we could limit ourselves to the change which would only make > the clients use the different hook (or keep using the old one, for > compatibility with older Flymake/Emacs versions). Compatibility to the old `eldoc-documentation-function' protocol is fully guaranteed. > The choice to require a return of a non-nil value if the callback is > going to be used is also kinda odd (+1 control flow to test). What's > the problem with using the callback synchronously if the doc is > available right away? Nothing, you can do it. As long as you return non-nil, non-string. But if you are are going to synchronously call the callback on a string, you might as well return that string, just seems simpler. > The decision to double down on having different > eldoc-documentation-strategy values seems odd to me in several > respects. > > First of all, if I understand the main motivation behind it, it's to > delegate the implementation of asynchronous primitives to Eldoc. It's rather to make clients don't worry about the synchronization. Not specifically to make Eldoc worry about it. As soon as you and others come up with the uber-async library, I think Eldoc and Flymake and many others will be very pleased to delegate work to it. > We don't want to bother with that in Eglot, etc. But you mentioned "a > type of docstring" to be returned in the discussion (and the callbacks > have the plist argument as a future proofing). If the type is a > buffer, its contents might as well be created from several async calls If you want to support "buffers" as a "type of docstring", just do that: make buffers a type of docstring. The obvious way is to have multiple sources produce multiple buffers. Thing: why would you ever want to put buffer-joining complexity in the client? They're not in the business of doing async gymnastics, they're in the business of serving things coming from servers as efficiently and effectively as possible. > , which would require the same async primitives (though rather in > general purpose form) available on the client anyway. Though it > doesn't seem to be necessary for LSP in common operations, it's > unlikely to be the only such protocol we'd ever want to support. I don't know about that, but if we did, the current mechanism work nicely for the example you presented. > The strategies themselves: > > - eldoc-documentation-enthusiast: What's the difference compared to > the 'default' one? Sacrificing CPU load for lower latency? It's an odd > choice to force the user to make. The only people who can make an > ideal decision regarding this are probably the authors of > eldoc-documentation-functions, but it wouldn't help if > eldoc-documentation-functions has functions coming from different > authors, facilities, etc. Has nothing to do with CPU. This is the way Eglot works now, or at least tries to: there are two delayed doc-producing backends, and neither is guaranteed to complete. One has priority over the other (and special hooks are a decent, standard Emacs way to manage priority) Eglot shows the lower-priority one if it shows it can survive for more than x seconds (currently x = 0.3, uncustomizable). No more doc blinking. > - eldoc-documentation-compose: Okay, this is kinda interesting (though > not essential), > I think the only reasonably predictable behavior would be to truncate > each of them to one line, always. That's a display problem, not a composition problem For now it works OK for one liners and also multiple multi-liners. Displaying doc is not the main goal of these patches, there is certainly room for improvement, as I said above. > - eldoc-documentation-compose-eagerly: Ooh, now I think I see why > Returning futures instead (when async is needed) would provide this > kind of guarantee without the seeming duplication of signals. Can't let go of that futures drum, can you? It'd be a pleasure to see you walk the walk. > On a related note, I believe some facilities might want to use only > certain "kinds" of documentation functions (as indicated by the plist > arguments). If the plist is only provided together with the response, > there is no way to avoid unnecessary computations (e.g. making HTTP > requests that return some other kinds of values). If the plist was > returned together with a future value, however, it would be easy to > do, as long as we document that the futures should start the > computation until a callback is provided (if possible, at least). Save it for your future futures implementation. > And in a different high-level argument: you stated that you intend to > have Eglot use a non-default value of eldoc-documentation-strategy. OK, but this has nothing to do with Eldoc, does it? Make a bug report for Eglot, I'll explain why it does this, and maybe I'll change it.. > Next, eldoc-print-current-symbol-info is a mess, very hard to > follow. I am frankly offended that you argued that both ad-hoc futures I meant no effense. > idea). This should very well be possible to untangle in the future, > but I'd rather not have code like this in Emacs if we can help it. You're such an ace programmer that you code alternatives that are so brief that they occupy no code at all! > Further, having all strategies basically delegate to hardcoded options > inside eldoc-print-current-symbol-info seems to confirm that the set > of available strategies is a closed one. Which is not what I would > expect from a variable called eldoc-documentation-strategy. There are four strategies to choose from but you can make more. What did you have in mind? > These are my objections, for now. I'll have to study > eldoc--handle-docs a bit later, but any problems it has are probably > orthogonal to the rest of the list. Thanks. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 ` (2 subsequent siblings) 3 siblings, 0 replies; 84+ messages in thread From: João Távora @ 2020-07-07 12:23 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, andreyk.mad João Távora <joaotavora@gmail.com> writes: > For the quintillionth time: I AM NOT AGAINST FUTURES IN PRINCIPLE: > just don't use these Eldoc fixes to shoehorn something rushedly into > Emacs. Just a further note: not only am I NOT "against" futures, I don't even disagree with you that a good async library CAN improve Eldoc and other async code. The question is, like it always is: how much of an effect and at what cost. João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 14:45 ` João Távora 2020-07-07 14:40 ` Dmitry Gutov 2020-07-07 22:24 ` Dmitry Gutov 3 siblings, 2 replies; 84+ messages in thread From: Stefan Monnier @ 2020-07-07 13:38 UTC (permalink / raw) To: João Távora; +Cc: 41531, andreyk.mad, Dmitry Gutov [ Sorry I can't really take part in the discussion, 'cause it's a rather busy time here. ] [ The discussion is becoming too tense for my taste. Please take a break and think whether all this is important enough to warrant criticizing each other this way. I think you're both great hackers whose opinion and expertise I value very much. ] I think getting async support for eldoc is more important than *how* we get it. I suggest we install the current eldoc-async code into `master` and in parallel work quickly on a futures/promises/aio/... package for `master`. As long as it's done before we cut the `emacs-28` branch, I can't see any reason why we couldn't change the new (and hence not yet released, except for the GNU ELPA package) API in a backward-incompatible way (just like the eldoc-async already does). Stefan João Távora [2020-07-07 11:56:01] wrote: > Dmitry Gutov <dgutov@yandex.ru> writes: > >> Please don't make it sound as if I'm the only one here having a strong >> opinion about proposed code. You disregarded the simple solution in >> https://debbugs.gnu.org/cgi/bugreport.cgi?bug=41531#8, and then went > > Are you in any way trying to say that you presented a "simple solution" > that somehow magically solves the problems of Eldoc? If you do, you're > living in conflict with reality. > > There is the problem to be solved. And then there are techniques for > solving the problem. These are two entirely separate things. To be > absolutely clear: you have not, ever, proposed an alternate solution to > the Eldoc async _problem_. > > You talked and talked and presented your favourite async handling > techniques, like having functions return functions that return > functions. You contented that I -- not you -- should work with it to > solve the problem. > > Callbacks, futures, promises, ad-hoc or proper, are just techniques. I > tried a couple techniques, including a basic futures-based one proposed > by Stefan. I didn't find any as compelling as the simplest and most > widely used in Emacs: callbacks. > > For the quintillionth time: I AM NOT AGAINST FUTURES IN PRINCIPLE: I > just don't use these Eldoc fixes to shoehorn something rushedly into > Emacs. Make a new thread, or join the existing one: > > https://lists.gnu.org/archive/html/emacs-devel/2020-03/msg00935.html > > Afterwards, propose a change to the technique, not only in Eldoc but > elsewhere, too. This idea is so simple that it boggles the mind that > you don't grasp it. > >> urgent endeavor. E.g., Flymake is stable, and I don't have any >> particular bugs in mind that need solving. > > Great. I'll just note here that it uses exactly the same technique I'm > proposing in Eldoc to communicate with multiple backends: it's curious > how that doesn't bother you. I would reasonably expect "futures" or > something else its implementation much simpler too. > >> Aside: given that this discussion has user interface in mind, it needs >> more consideration of actual user experiences we'd want to allow. Ones >> not provided by eldoc itself as well. For instance, I think we sooner >> or later should have a callsig floating popup (in the vein of MS's >> editors) as an alternative to showing the signature in the echo area >> only. > > That is addressed in a comment in eldoc-docs > > ;; Finally, output to the echo area. We handle the > ;; `truncate-sym-name-if-fit' special case first, by selecting a > ;; top-section of the `*eldoc' buffer. I'm pretty sure nicer > ;; strategies can be used here, probably by splitting this > ;; function into some `eldoc-display-functions' special hook. > > I agree there is ample space for improvement, including a > "floating popup" (which I wouldn't limit to callsigs though). Make > another bug report to study this. > >> The new API is incompatible with the previous one, it requires >> changing a lot of functions (though admittedly in a minor way). > > This is demonstrably false. As I've explained to Eli there is no > incompatibility in practice. 0 (zero) third-party extensions make use > of the protocol being changed from Eldoc 1.0.0 to Eldoc 1.1.0, unless > you're stalling here to secretly work on one. > > But if we really, really wanted to, it's easy to get rid of the > arguments, too, with a variation to the callback technique. I just > don't think it's worth it: a technique is a technique. > >> is easy to miss, as evidenced by describe-char-eldoc which still >> doesn't accept any arguments. > > Oh, an actual useful comment! Easily solved, thanks. And it was only > "missed" because it wasn't used anywhere. > >> Whereas we could limit ourselves to the change which would only make >> the clients use the different hook (or keep using the old one, for >> compatibility with older Flymake/Emacs versions). > > Compatibility to the old `eldoc-documentation-function' protocol is > fully guaranteed. > >> The choice to require a return of a non-nil value if the callback is >> going to be used is also kinda odd (+1 control flow to test). What's >> the problem with using the callback synchronously if the doc is >> available right away? > > Nothing, you can do it. As long as you return non-nil, non-string. But > if you are are going to synchronously call the callback on a string, you > might as well return that string, just seems simpler. > >> The decision to double down on having different >> eldoc-documentation-strategy values seems odd to me in several >> respects. >> >> First of all, if I understand the main motivation behind it, it's to >> delegate the implementation of asynchronous primitives to Eldoc. > > It's rather to make clients don't worry about the synchronization. Not > specifically to make Eldoc worry about it. As soon as you and others > come up with the uber-async library, I think Eldoc and Flymake and many > others will be very pleased to delegate work to it. > >> We don't want to bother with that in Eglot, etc. But you mentioned "a >> type of docstring" to be returned in the discussion (and the callbacks >> have the plist argument as a future proofing). If the type is a >> buffer, its contents might as well be created from several async calls > > If you want to support "buffers" as a "type of docstring", just do that: > make buffers a type of docstring. The obvious way is to have multiple > sources produce multiple buffers. > > Thing: why would you ever want to put buffer-joining complexity in the > client? They're not in the business of doing async gymnastics, they're > in the business of serving things coming from servers as efficiently and > effectively as possible. > >> , which would require the same async primitives (though rather in >> general purpose form) available on the client anyway. Though it >> doesn't seem to be necessary for LSP in common operations, it's >> unlikely to be the only such protocol we'd ever want to support. > > I don't know about that, but if we did, the current mechanism work > nicely for the example you presented. > >> The strategies themselves: >> >> - eldoc-documentation-enthusiast: What's the difference compared to >> the 'default' one? Sacrificing CPU load for lower latency? It's an odd >> choice to force the user to make. The only people who can make an >> ideal decision regarding this are probably the authors of >> eldoc-documentation-functions, but it wouldn't help if >> eldoc-documentation-functions has functions coming from different >> authors, facilities, etc. > > Has nothing to do with CPU. This is the way Eglot works now, or at > least tries to: there are two delayed doc-producing backends, and > neither is guaranteed to complete. One has priority over the other (and > special hooks are a decent, standard Emacs way to manage priority) > > Eglot shows the lower-priority one if it shows it can survive for more > than x seconds (currently x = 0.3, uncustomizable). No more doc > blinking. > >> - eldoc-documentation-compose: Okay, this is kinda interesting (though >> not essential), > >> I think the only reasonably predictable behavior would be to truncate >> each of them to one line, always. > > That's a display problem, not a composition problem For now it works OK > for one liners and also multiple multi-liners. Displaying doc is not > the main goal of these patches, there is certainly room for improvement, > as I said above. > >> - eldoc-documentation-compose-eagerly: Ooh, now I think I see why >> Returning futures instead (when async is needed) would provide this >> kind of guarantee without the seeming duplication of signals. > > Can't let go of that futures drum, can you? It'd be a pleasure to see > you walk the walk. > >> On a related note, I believe some facilities might want to use only >> certain "kinds" of documentation functions (as indicated by the plist >> arguments). If the plist is only provided together with the response, >> there is no way to avoid unnecessary computations (e.g. making HTTP >> requests that return some other kinds of values). If the plist was >> returned together with a future value, however, it would be easy to >> do, as long as we document that the futures should start the >> computation until a callback is provided (if possible, at least). > > Save it for your future futures implementation. > >> And in a different high-level argument: you stated that you intend to >> have Eglot use a non-default value of eldoc-documentation-strategy. > > OK, but this has nothing to do with Eldoc, does it? Make a bug report > for Eglot, I'll explain why it does this, and maybe I'll change it.. > >> Next, eldoc-print-current-symbol-info is a mess, very hard to >> follow. I am frankly offended that you argued that both ad-hoc futures > > I meant no effense. > >> idea). This should very well be possible to untangle in the future, >> but I'd rather not have code like this in Emacs if we can help it. > > You're such an ace programmer that you code alternatives that are so > brief that they occupy no code at all! > >> Further, having all strategies basically delegate to hardcoded options >> inside eldoc-print-current-symbol-info seems to confirm that the set >> of available strategies is a closed one. Which is not what I would >> expect from a variable called eldoc-documentation-strategy. > > There are four strategies to choose from but you can make more. What > did you have in mind? > >> These are my objections, for now. I'll have to study >> eldoc--handle-docs a bit later, but any problems it has are probably >> orthogonal to the rest of the list. > > Thanks. > > João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 13:38 ` Stefan Monnier @ 2020-07-07 14:24 ` Dmitry Gutov 2020-07-07 16:07 ` Stefan Monnier 2020-07-07 14:45 ` João Távora 1 sibling, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-07 14:24 UTC (permalink / raw) To: Stefan Monnier, João Távora; +Cc: 41531, andreyk.mad On 07.07.2020 16:38, Stefan Monnier wrote: > As long as it's done before we cut the `emacs-28` branch, I can't see > any reason why we couldn't change the new (and hence not yet released, > except for the GNU ELPA package) API in a backward-incompatible way > (just like the eldoc-async already does). It's a good point, and if that was all that we'd need to agree on, I'd be fine to proceed. But if we just wanted to get async into Eglot, that's what my simple patch did: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=41531#8, proposed months ago. With minimal backward compatibility issues. The current discussion, and the current eldoc-async branch adds some more design decisions, as well as breaking changes. And those decisions seem to be informed and made necessary by the lack of standard functions for combining async computations that eldoc clients could use. As soon as we get futures/promises/aio into the core, that will cease to be the case. But I fear we wouldn't be able to roll back the related decisions so easily, however. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 14:24 ` Dmitry Gutov @ 2020-07-07 16:07 ` Stefan Monnier 2020-07-07 23:11 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: Stefan Monnier @ 2020-07-07 16:07 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, João Távora, andreyk.mad > The current discussion, and the current eldoc-async branch adds some more > design decisions, as well as breaking changes. I don't see any breaking changes (other than to things which haven't yet been released IMO). > As soon as we get futures/promises/aio into the core, that will cease to be > the case. Then let's get moving on that. No need to wait. > But I fear we wouldn't be able to roll back the related decisions > so easily, however. I don't see any reason to fear that. The more time we spend discussing what the ideal should look like, the less time we have to actually get there. The current eldoc-async branch doesn't get us further from the ideal, I believe, unless `emacs-28` gets cut before we get our act together. But if we don't get our act together before `emacs-28` then the alternative is to have Emacs-28 without support for async eldoc, which I think is even worse. I recommend we try and be pragmatic. Especially since it will make us all happier (instead of arguing against each other, we get to work on improving the code). Stefan ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 16:07 ` Stefan Monnier @ 2020-07-07 23:11 ` Dmitry Gutov 2020-07-08 3:58 ` Stefan Monnier 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-07 23:11 UTC (permalink / raw) To: Stefan Monnier; +Cc: 41531, João Távora, andreyk.mad On 07.07.2020 19:07, Stefan Monnier wrote: >> But I fear we wouldn't be able to roll back the related decisions >> so easily, however. > I don't see any reason to fear that. The more time we spend discussing > what the ideal should look like, the less time we have to actually > get there. Given we can't even agree on the acceptance criteria, how would the rollback process look? Another "let's get it merged, folks"? With nobody particular in charge of Eldoc except maybe for Joao now? Who will of course be ecstatic to change the API to one he explicitly disliked in the beginning. > The current eldoc-async branch doesn't get us further from the ideal, > I believe, unless `emacs-28` gets cut before we get our act together. > > But if we don't get our act together before `emacs-28` then the > alternative is to have Emacs-28 without support for async eldoc, which > I think is even worse. Why you don't consider the alternative with less invasive changes, is beyond my understanding. > I recommend we try and be pragmatic. Especially since it will make us > all happier (instead of arguing against each other, we get to work on > improving the code). I wouldn't call the definition of eldoc-print-current-symbol-info in this branch an improvement over anything. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 23:11 ` Dmitry Gutov @ 2020-07-08 3:58 ` Stefan Monnier 2020-07-08 11:20 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: Stefan Monnier @ 2020-07-08 3:58 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, João Távora, andreyk.mad > Why you don't consider the alternative with less invasive changes, is beyond > my understanding. [ It's the same old maintainer's conundrum, trying to balance the need to stay in control of the code and make sure it's coherent etc.. while at the same time delegating and encouraging participation. ] To a large extent, I tend to give a lot of weight to existing code. I don't have the time or energy to work on eldoc myself, and apparently neither do you, so the one who writes the code gets to take most of the decisions. From what I remember the last time I looked at the branch, there were things I didn't much like, but not more so than in the rest of Emacs ;-) I can't ask everyone to code what I would write (and it's often for the better since what I'd write would likely not work because I'm not aware of the underlying difficulties that would make it fail). Stefan ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-08 3:58 ` Stefan Monnier @ 2020-07-08 11:20 ` Dmitry Gutov 2020-07-08 13:25 ` Stefan Monnier 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-08 11:20 UTC (permalink / raw) To: Stefan Monnier; +Cc: 41531, João Távora, andreyk.mad On 08.07.2020 06:58, Stefan Monnier wrote: > I don't have the time or energy to work on eldoc myself, and apparently > neither do you, so the one who writes the code gets to take most of > the decisions. I have offered to do a rewrite multiple times now. The only encouragement in that direction I have received was "can't stop you". > From what I remember the last time I looked at the branch, there were > things I didn't much like, but not more so than in the rest of Emacs;-) I thought we were more into detailed reviews and good code. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 2 replies; 84+ messages in thread From: Stefan Monnier @ 2020-07-08 13:25 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, João Távora, andreyk.mad >> I don't have the time or energy to work on eldoc myself, and apparently >> neither do you, so the one who writes the code gets to take most of >> the decisions. > I have offered to do a rewrite multiple times now. Feel free to do so. But it does mean that one of you two will be frustrated because your/his code won't be accepted. Maybe a better option, then is to: - do a quick version of the code for yourself. - then compare that with Joao's version. - then do a mix of: - argue to change or remove some parts of his code (those that would make it difficult for you to install your code on top of his) - keep the other changes to apply them after he installs his WDYT? Stefan ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-08 13:25 ` Stefan Monnier @ 2020-07-08 13:41 ` João Távora 2020-07-08 14:21 ` Dmitry Gutov 1 sibling, 0 replies; 84+ messages in thread From: João Távora @ 2020-07-08 13:41 UTC (permalink / raw) To: Stefan Monnier; +Cc: 41531, andreyk.mad, Dmitry Gutov Stefan Monnier <monnier@iro.umontreal.ca> writes: >>> I don't have the time or energy to work on eldoc myself, and apparently >>> neither do you, so the one who writes the code gets to take most of >>> the decisions. >> I have offered to do a rewrite multiple times now. > > Feel free to do so. But it does mean that one of you two will > be frustrated because your/his code won't be accepted. > > Maybe a better option, then is to: > > - do a quick version of the code for yourself. > - then compare that with Joao's version. > - then do a mix of: > - argue to change or remove some parts of his code (those that would > make it difficult for you to install your code on top of his) > - keep the other changes to apply them after he installs his > > WDYT? Fine with this plan. Would even dare to call it "development" ;-) ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 1 sibling, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-08 14:21 UTC (permalink / raw) To: Stefan Monnier; +Cc: 41531, João Távora, andreyk.mad On 08.07.2020 16:25, Stefan Monnier wrote: > - do a quick version of the code for yourself. > - then compare that with Joao's version. > - then do a mix of: > - argue to change or remove some parts of his code (those that would > make it difficult for you to install your code on top of his) > - keep the other changes to apply them after he installs his Since he went ahead, ignored the review and pushed the changes, apparently I can just do the same now. That just leaves the buggy new features which went in without proper justification. Can I go ahead and remove them, then? ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-08 14:21 ` Dmitry Gutov @ 2020-07-08 15:12 ` João Távora 2020-07-08 18:32 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-07-08 15:12 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: > On 08.07.2020 16:25, Stefan Monnier wrote: >> - do a quick version of the code for yourself. >> - then compare that with Joao's version. >> - then do a mix of: >> - argue to change or remove some parts of his code (those that would >> make it difficult for you to install your code on top of his) >> - keep the other changes to apply them after he installs his > > Since he went ahead, ignored the review and pushed the changes, > apparently I can just do the same now. > > That just leaves the buggy new features which went in without proper > justification. Can I go ahead and remove them, then? I think you should M-x report-emacs-bug and explain the bug. Please stop falsely claiming I "ignored" you review. This is distateful and offensive. I replied to both emails: neither were a code review like Eli's and Stefan's were, which were much easier to follow. For the first one I replied diligently to each point as I could, especially when direct mentions to code that weren't related to futures and when I could understand your question. While the first email was already quite full of tension and off-hand remarks about my code being offensive and undemonstrated claims about code being bad in general, the second one was worse in that respect, it was purely opinative and again conflated most issues with your penchant for an implementation based on futures, making it extremely hard to follow your point, as I already told you. Therefore, I suggest you describe the issues with M-x report-emacs-bug for bugs and for features that you don't understand the value of. Make a separate bug report for each problem. Again, I promise to reply to those. Here are suggestions for subject lines of those bug reports, as I gathered them from my reading of your emails: - No purpose in `eldoc-documentation-enthusiast` - `eldoc-documentation-compose` causes blinking - `eldoc-documentation-functions` should use futures library - `eldoc-print-current-symbol-info` is extremely complicated - This much simpler patch would solve all of Eldoc's asynchronous problems - Eldoc now eats my homework Etc, etc. Hopefully some progress can be made in those discussions. Thank you very much, João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-08 15:12 ` João Távora @ 2020-07-08 18:32 ` Dmitry Gutov 2020-07-08 19:12 ` Eli Zaretskii 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-08 18:32 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, andreyk.mad On 08.07.2020 18:12, João Távora wrote: > Please stop falsely claiming I "ignored" you review. This is distateful > and offensive. Not as offensive as having one's writing ignored. > I replied to both emails: neither were a code review like Eli's and Stefan's were, which were much easier to follow. Both Stefan and Eli were too busy to do an in-depth review. And I now know better than to do one for you either. > While the first email was already quite full of tension and off-hand remarks about my code being offensive and undemonstrated claims about code being bad in general, the second one was worse in that respect, There was a lot of different issues discussed in those emails. You ignoring most of them and retelling the contents now in this simplistic way is offensive (but about on par with your other messages in this discussion). I'm not going to describe the same things again and again, in many different ways. I have wasted enough time on this already. And if you didn't want reviews this long, you shouldn't have submitted a branch with multiple orthogonal features intermixed. You should have picked a proper solution to the issue #1, then filed a bug for the next one. Then we could have had much easier, targeted reviews. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-08 18:32 ` Dmitry Gutov @ 2020-07-08 19:12 ` Eli Zaretskii 0 siblings, 0 replies; 84+ messages in thread From: Eli Zaretskii @ 2020-07-08 19:12 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, joaotavora, andreyk.mad, monnier > From: Dmitry Gutov <dgutov@yandex.ru> > Date: Wed, 8 Jul 2020 21:32:33 +0300 > Cc: 41531@debbugs.gnu.org, Stefan Monnier <monnier@iro.umontreal.ca>, > andreyk.mad@gmail.com > > Both Stefan and Eli were too busy to do an in-depth review. Actually, busy or not, I did the best review I could. I'm sure Stefan did the same. And next time you'd like to know whether I did an in-depth review or was too busy to afford that, you can ask me. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 13:38 ` Stefan Monnier 2020-07-07 14:24 ` Dmitry Gutov @ 2020-07-07 14:45 ` João Távora 1 sibling, 0 replies; 84+ messages in thread From: João Távora @ 2020-07-07 14:45 UTC (permalink / raw) To: Stefan Monnier; +Cc: 41531, andreyk.mad, Dmitry Gutov Stefan Monnier <monnier@iro.umontreal.ca> writes: > I suggest we install the current eldoc-async code into `master` and in > parallel work quickly on a futures/promises/aio/... package for > `master`. That's the point I've been making all along, indeed! Finally progress! Thanks, João PS: I for one will try to invest some effort in some more modular/powerful eldoc-display-functions... let's hope that's less contentious. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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:40 ` Dmitry Gutov 2020-07-07 22:24 ` Dmitry Gutov 3 siblings, 0 replies; 84+ messages in thread From: Dmitry Gutov @ 2020-07-07 14:40 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, andreyk.mad On 07.07.2020 13:56, João Távora wrote: > Are you in any way trying to say that you presented a "simple solution" > that somehow magically solves the problems of Eldoc? If you do, you're > living in conflict with reality. > > There is the problem to be solved. And then there are techniques for > solving the problem. These are two entirely separate things. To be > absolutely clear: you have not, ever, proposed an alternate solution to > the Eldoc async_problem_. Perhaps there is a misunderstanding here. What would it take for you to say that "the problem" is indeed "solved" to a sufficient degree that your work on Eglot can continue? If you could mention both the strictly minimum conditions, as well as the "bonus round", that would be great. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 10:56 ` João Távora ` (2 preceding siblings ...) 2020-07-07 14:40 ` Dmitry Gutov @ 2020-07-07 22:24 ` Dmitry Gutov 2020-07-07 22:49 ` João Távora 3 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-07 22:24 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, andreyk.mad On 07.07.2020 13:56, João Távora wrote: > You talked and talked and presented your favourite async handling > techniques, like having functions return functions that return > functions. You contented that I -- not you -- should work with it to > solve the problem. I showed a solution to the part of the problem that we managed to define at that time. You added some more features now. If you like, I can rewrite your branch in terms of that proposal. Or in terms of eldoc-future (as suggested by Stefan). Your pick. (But we still need to discuss the extra changes in this branch). > For the quintillionth time: I AM NOT AGAINST FUTURES IN PRINCIPLE: I > just don't use these Eldoc fixes to shoehorn something rushedly into > Emacs. Make a new thread, or join the existing one: > > https://lists.gnu.org/archive/html/emacs-devel/2020-03/msg00935.html Thanks for the link. I seem to have missed it. Not exactly the discussion to join, but the projects mentioned there could be helpful. > Afterwards, propose a change to the technique, not only in Eldoc but > elsewhere, too. This idea is so simple that it boggles the mind that > you don't grasp it. Sure. As long as this discussion waits. >> urgent endeavor. E.g., Flymake is stable, and I don't have any >> particular bugs in mind that need solving. > > Great. I'll just note here that it uses exactly the same technique I'm > proposing in Eldoc to communicate with multiple backends: it's curious > how that doesn't bother you. I would reasonably expect "futures" or > something else its implementation much simpler too. It doesn't have existing clients that return results synchronously. It almost always works with external processes. It doesn't care if a checker never calls back. It doesn't compose results from multiple checkers. Basically: it's simple, and whatever legacy it did have, you cordoned that behind flymake-proc (which everybody promptly migrated off). And as you can note, the interface you proposed here is not exactly the same: due to some of the requirements above, it's slightly different. A flymake backend is considered running whenever it didn't signal an error. The convention you proposed here involves returning a non-string, non-nil value. I imagine having different interfaces between facilities is better than having similar-by-subtly-different ones. >> Aside: given that this discussion has user interface in mind, it needs >> more consideration of actual user experiences we'd want to allow. Ones >> not provided by eldoc itself as well. For instance, I think we sooner >> or later should have a callsig floating popup (in the vein of MS's >> editors) as an alternative to showing the signature in the echo area >> only. > > That is addressed in a comment in eldoc-docs > > ;; Finally, output to the echo area. We handle the > ;; `truncate-sym-name-if-fit' special case first, by selecting a > ;; top-section of the `*eldoc' buffer. I'm pretty sure nicer > ;; strategies can be used here, probably by splitting this > ;; function into some `eldoc-display-functions' special hook. I think the first question to ask here, is whether the eldoc clients are not ultimately the best place to decide how the doc should be formatted and displayed. So the alternative to your current proposal (with composing strategies) would be for us to provide a set of utility functions to clients: ones to manipulate async computations, ones to truncate the doc to desired dimensions, ones to combine several docs in one, etc, while honoring the value of eldoc-echo-area-use-multiline-p. The advantage to that approach is that we don't limit the display to particular format (e.g. the truncate-sym-name-if-fit requires the symbol to be at the beginning of the line, and for it to be specified as the :thing property as well). The downside: mainly being unable to compose eldoc results from multiple clients. But I wonder how well we can manage to handle that anyway. > I agree there is ample space for improvement, including a > "floating popup" (which I wouldn't limit to callsigs though). Make > another bug report to study this. Callsigs are a whole other matter, actually. The best experience seems impossible to implement through eldoc. The LSP protocol shows an example of a good data structure required for it (a list of overloads, the number of the current guessed one, and a documentation string for the function). Eldoc can be used in the absence of other options, but a different hook which requires richer values seems more appropriate. >> The new API is incompatible with the previous one, it requires >> changing a lot of functions (though admittedly in a minor way). > > This is demonstrably false. As I've explained to Eli there is no > incompatibility in practice. 0 (zero) third-party extensions make use > of the protocol being changed from Eldoc 1.0.0 to Eldoc 1.1.0, unless > you're stalling here to secretly work on one. So what happens if we merge this to master now? Either you expect no clients, and there is no need to hurry, or we expect some new eldoc clients to use this interface. But then the same clients will experience breakage as soon as we switch over to "proper" futures. > But if we really, really wanted to, it's easy to get rid of the > arguments, too, with a variation to the callback technique. I just > don't think it's worth it: a technique is a technique. The variation that I showed in my little patch a month ago? >> is easy to miss, as evidenced by describe-char-eldoc which still >> doesn't accept any arguments. > > Oh, an actual useful comment! Easily solved, thanks. And it was only > "missed" because it wasn't used anywhere. Well, you corrected its docstring in this branch. >> The choice to require a return of a non-nil value if the callback is >> going to be used is also kinda odd (+1 control flow to test). What's >> the problem with using the callback synchronously if the doc is >> available right away? > > Nothing, you can do it. As long as you return non-nil, non-string. But > if you are are going to synchronously call the callback on a string, you > might as well return that string, just seems simpler. Seems like a missed opportunity to simplify (or not). >> First of all, if I understand the main motivation behind it, it's to >> delegate the implementation of asynchronous primitives to Eldoc. > > It's rather to make clients don't worry about the synchronization. Because it's fairly difficult, right? Especially in the absence of helpful standard libraries. >> We don't want to bother with that in Eglot, etc. But you mentioned "a >> type of docstring" to be returned in the discussion (and the callbacks >> have the plist argument as a future proofing). If the type is a >> buffer, its contents might as well be created from several async calls > > If you want to support "buffers" as a "type of docstring", just do that: > make buffers a type of docstring. The obvious way is to have multiple > sources produce multiple buffers. That doesn't really jive with what I imagined. If I want to produce a "pretty" buffer in a client, I will print to it. Possibly making several HTTP calls in the process, if that's not hard to do. I would also probably prefer not to worry about some other eldoc client leaving its documentation function in the list before mine. Or having them later in the list, leaving some unrelated stuff in the resulting buffer. As a client, I would probably know which calls are made, which data is returned, and how I want it to be rendered. > Thing: why would you ever want to put buffer-joining complexity in the > client? Because it knows in which order to put them? Or how to render the seams best? Or it could mix the HTTP responses in other ways than simply joining them with "\n\n". Having generic code do that seems limiting. Having individual clients do that should encourage more attention to detail. >> The strategies themselves: >> >> - eldoc-documentation-enthusiast: What's the difference compared to >> the 'default' one? Sacrificing CPU load for lower latency? It's an odd >> choice to force the user to make. The only people who can make an >> ideal decision regarding this are probably the authors of >> eldoc-documentation-functions, but it wouldn't help if >> eldoc-documentation-functions has functions coming from different >> authors, facilities, etc. > > Has nothing to do with CPU. This is the way Eglot works now, or at > least tries to: there are two delayed doc-producing backends, and > neither is guaranteed to complete. Why not? HTTP responses normally arrive reliably. > One has priority over the other (and > special hooks are a decent, standard Emacs way to manage priority) > > Eglot shows the lower-priority one if it shows it can survive for more > than x seconds (currently x = 0.3, uncustomizable). No more doc > blinking. Why not just wait for the first one, if its documentation function returned non-nil? I considered commenting on the 0.3 magic number, but dropped it in the first review. >> - eldoc-documentation-compose: Okay, this is kinda interesting (though >> not essential), > >> I think the only reasonably predictable behavior would be to truncate >> each of them to one line, always. > > That's a display problem, not a composition problem For now it works OK > for one liners and also multiple multi-liners. Displaying doc is not > the main goal of these patches, there is certainly room for improvement, > as I said above. Whether we can reliably display these docs in a "composed" way, from any sources, or not, should probably factor into the design. Because if not, do we really need different strategies? >> - eldoc-documentation-compose-eagerly: Ooh, now I think I see why >> Returning futures instead (when async is needed) would provide this >> kind of guarantee without the seeming duplication of signals. > > Can't let go of that futures drum, can you? It'd be a pleasure to see > you walk the walk. There's not much inherent difficulty in extracting the future-merge code from here or elsewhere. The actual problems I mentioned in the email with the (tiny) future.el come from elsewhere (e.g. from requirements for using them for completion), but they need to be decided on, in order to minimize breakage later. >> On a related note, I believe some facilities might want to use only >> certain "kinds" of documentation functions (as indicated by the plist >> arguments). If the plist is only provided together with the response, >> there is no way to avoid unnecessary computations (e.g. making HTTP >> requests that return some other kinds of values). If the plist was >> returned together with a future value, however, it would be easy to >> do, as long as we document that the futures should start the >> computation until a callback is provided (if possible, at least). > > Save it for your future futures implementation. My point was, again, adopting futures here would create a structural change. A more incompatible one than if we adopted a more compatible API. Or straight away used eldoc-local futures. >> And in a different high-level argument: you stated that you intend to >> have Eglot use a non-default value of eldoc-documentation-strategy. > > OK, but this has nothing to do with Eldoc, does it? Make a bug report > for Eglot, I'll explain why it does this, and maybe I'll change it.. It does, if the actual requirements here mean that Eglot could just as fine perform combining its documentation results itself, in its documentation function. Then Eldoc could eventually do away with the eldoc-documentation-function/strategy variable altogether. And the current change to the API would be minimal. >> idea). This should very well be possible to untangle in the future, >> but I'd rather not have code like this in Emacs if we can help it. > > You're such an ace programmer that you code alternatives that are so > brief that they occupy no code at all! Nice punch. I hope you haven't missed the implication that it's _hard_ for me to make heads or tails of your code there. But I could take a shot. >> Further, having all strategies basically delegate to hardcoded options >> inside eldoc-print-current-symbol-info seems to confirm that the set >> of available strategies is a closed one. Which is not what I would >> expect from a variable called eldoc-documentation-strategy. > > There are four strategies to choose from but you can make more. What > did you have in mind? Well... if I were thinking further in the direction of strategies, perhaps some would first request/wait the documentation from sources that return buffers, and then if none of those return any, then query the rest of functions. Or order the sources based on their kind before doing the calls, using user-supplied algo. Or perhaps skip buffers which are already displayed in some window. My point here was, though, that a strategy sounds like something customizable and extensible. So their semantics, docstrings and implementations will need to be more accessible to an average Lisp developer. >> These are my objections, for now. I'll have to study >> eldoc--handle-docs a bit later, but any problems it has are probably >> orthogonal to the rest of the list. > > Thanks. Having looked at it, the only problems there I can report on are practical, the same as I described when talking about eldoc-documentation-compose in the previous email: blinking after every user command, missing truncation when composing several docstrings, and undefined behavior with multiple multiline docstrings. Is it at all possible to get rid of blinking? One-line eldoc doesn't blink. Also, umm... it seems to truncate the contents of a long doc buffer to its bottom part. At least that's what I get when trying the related branch of Eglot. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 22:24 ` Dmitry Gutov @ 2020-07-07 22:49 ` João Távora 2020-07-07 23:00 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-07-07 22:49 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: >> But if we really, really wanted to, it's easy to get rid of the >> arguments, too, with a variation to the callback technique. I just >> don't think it's worth it: a technique is a technique. > > The variation that I showed in my little patch a month ago? No, to be clear that was not a variation to the callback technique. One way is simply to passing the callback as a special variable (and there are more ways.) The rest of your long email hints that you've misunderstood what this change to Eldoc is accomplishing. I'm afraid I've done all I can to explain it, including docstrings, NEWS entries, commit messages and going through your previous very long code review. I understand you expected a futures library would come with this change, but it does not, not for now. I've explained that is only a technique, but in this last email you conflate every issue with it again. My position is: if there really is value in them, futures will soon be in Emacs. Let's follow Stefan advice, it's good advice. I might even work a bit on futures myself. Best, João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-07 23:00 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, andreyk.mad On 08.07.2020 01:49, João Távora wrote: > The rest of your long email hints that you've misunderstood what this > change to Eldoc is accomplishing. So basically you even refuse to discuss the design choices in the branch, or the shortcomings of the implementation, its current bugs, etc? And just merge the branch wholesale? Thanks, Stefan! > I might even work a bit on futures myself. Knock yourself out. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 23:00 ` Dmitry Gutov @ 2020-07-07 23:24 ` João Távora 2020-07-07 23:42 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-07-07 23:24 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, andreyk.mad Dmitry Gutov <dgutov@yandex.ru> writes: > On 08.07.2020 01:49, João Távora wrote: >> The rest of your long email hints that you've misunderstood what this >> change to Eldoc is accomplishing. > > So basically you even refuse to discuss the design choices in the > branch, or the shortcomings of the implementation, its current bugs, > etc? I read your email, but it's very hard to follow your verbal conjectures that this here or that there will fail catastrophically. I suggest you make a bug report for each bug, describe a recipe for reproducing the bug. Likewise, if there are shortcomings in the design, state clearly what you wanted do, but can't. I promise to attend to them, time permitting. It's important to disconnect these reports from your fondness for futures, which is a technique for which we don't have a library or consensus for. That in particular makes your otherwise extremely valuable feedback very hard to follow. Let's take Stefan's advice on the futures front, is my recommendation. Also, I agree with Stefan that things have become tense and agressive, and no good progress can be made in these conditions. Best, João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 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 0 siblings, 1 reply; 84+ messages in thread From: Dmitry Gutov @ 2020-07-07 23:42 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, andreyk.mad On 08.07.2020 02:24, João Távora wrote: > I read your email, but it's very hard to follow your verbal conjectures > that this here or that there will fail catastrophically. No such conjectures there. > I suggest you make a bug report for each bug, describe a recipe for > reproducing the bug. Likewise, if there are shortcomings in the design, > state clearly what you wanted do, but can't. I promise to attend to > them, time permitting. How about you reply to the email I already wrote and ask questions where something is hard to understand? > It's important to disconnect these reports from your fondness for > futures, which is a technique for which we don't have a library or > consensus for. You're ducking away from your previous statements. One message, you accuse me of not implementing everything myself. In the next one, after I offer to do just that, you cut the discussion short and accuse me of fearmongering or something. > Also, I agree with Stefan that things have become tense and agressive, > and no good progress can be made in these conditions. Let's tone it down, then. ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 23:42 ` Dmitry Gutov @ 2020-07-07 23:46 ` João Távora 2020-07-08 0:10 ` Dmitry Gutov 0 siblings, 1 reply; 84+ messages in thread From: João Távora @ 2020-07-07 23:46 UTC (permalink / raw) To: Dmitry Gutov; +Cc: 41531, Stefan Monnier, Andrii Kolomoiets On Wed, Jul 8, 2020 at 12:42 AM Dmitry Gutov <dgutov@yandex.ru> wrote: > One message, you > accuse me of not implementing everything myself. In the next one, after > I offer to do just that, you cut the discussion short You're confused, but by all means code away, you don't need my permission for that. Good luck! João ^ permalink raw reply [flat|nested] 84+ messages in thread
* bug#41531: 27.0.91; Better handle asynchronous eldoc backends 2020-07-07 23:46 ` João Távora @ 2020-07-08 0:10 ` Dmitry Gutov 0 siblings, 0 replies; 84+ messages in thread From: Dmitry Gutov @ 2020-07-08 0:10 UTC (permalink / raw) To: João Távora; +Cc: 41531, Stefan Monnier, Andrii Kolomoiets On 08.07.2020 02:46, João Távora wrote: > You're confused, but by all means code away, you don't need my > permission for that. Good luck! So I spend a few hours coding, and you wave the result away just as promptly as you did with the code review? Or with my previous patch? I asked what you actually need here in terms of functionality to go on with your work on Eglot. No response came to that either. ^ permalink raw reply [flat|nested] 84+ messages in thread
end of thread, other threads:[~2020-07-08 19:12 UTC | newest] Thread overview: 84+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 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 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
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).