casouri / eldoc-box

childframe doc for eglot and anything that uses eldoc
359 stars 26 forks source link

Is it possible to choose which eldoc-documentation-functions are applied when displaying the documentation? #90

Closed lassemaatta closed 1 year ago

lassemaatta commented 1 year ago

I like eldoc-box a lot. But what I'd really like is to fine-tune which eldoc-documentation-functions are consulted when building the contents of the documentation buffer for eldoc-box, while other function(s) are used for the echo area.

For example, some documentation functions (like eglot-signature-eldoc-function) provide a concise one-line explanation, suitable for the echo area, while others provide a wall-of-text description (e.g. eglot-hover-eldoc-function). I'd like to use only the latter with eldoc-box. However, if I use something like the eldoc-documentation-compose strategy to compose multiple documentation sources (for the echo area), these also apply to the eldoc-box output.

I tried something like

(defun my-help-at-point ()
    (interactive)
    (let ((eldoc-documentation-functions '(eglot-hover-eldoc-function))
          (eldoc-display-functions '(eldoc-display-in-buffer)))
      (eldoc--invoke-strategy nil)
      (eldoc-box-help-at-point)))

but it didn't work reliably. I guess this has something to do with the one and only eldoc--doc-buffer shared by eldoc and eldoc-buffer. Or the fact that I have no idea what I'm doing when it comes to elisp.

casouri commented 1 year ago

So you want the childframe only show the output of eglot-hover-eldoc-function, and leave the output of eglot-signature-eldoc-function in the mode-line, when you call eldoc-box-help-at-point?

I guess you can use a custom function for eldoc-documentation-strategy that pass the output of eglot-signature-eldoc-function to eldoc-display-in-echo-area, and the output of eglot-hover-eldoc-function to eldoc-display-in-buffer?

lassemaatta commented 1 year ago

I tried to figure out how to implement a custom eldoc-documentation-strategy but couldn't really figure it out.

I also tried creating wrapping functions for the various documentation generating functions (like eglot-hover-eldoc-function) with the idea I could somehow filter the result. But the eldoc callback handler just takes the docstring and the :echo parameter and always prints the docstring in the buffer and optionally filters the echo area based on the :echo value.

What I eventually ended up with was to wrap the display functions (eldoc-display-in-echo-area & eldoc-display-in-buffer), so that I could look at the generated documentation data and the :origin and choose whether to display it or not.

(defun my-filter-by-source (display-fn &rest source-fns)
  "Wrap DISPLAY-FN such that only docs from SOURCE-FNS are shown."
  (lambda (docs interactive)
    (let ((docs (->> docs
                     (-filter (lambda (doc)
                                (let* ((plist (cdr doc))
                                       (origin (plist-get plist :origin)))
                                  (-contains? source-fns origin)))))))
      (funcall display-fn docs interactive))))

(defun my-remove-by-source (display-fn &rest source-fns)
  "Wrap DISPLAY-FN such that any docs from SOURCE-FNS are ignored."
  (lambda (docs interactive)
    (let ((docs (->> docs
                     (-remove (lambda (doc)
                                (let* ((plist (cdr doc))
                                       (origin (plist-get plist :origin)))
                                  (-contains? source-fns origin)))))))
      (funcall display-fn docs interactive))))

;; Don't show hover documentation in echo area
(defalias 'my-display-in-echo-area (my-remove-by-source 'eldoc-display-in-echo-area
                                                        'eglot-hover-eldoc-function))
;; Only show hover documentation in doc buffer
(defalias 'my-display-in-buffer (my-filter-by-source 'eldoc-display-in-buffer
                                                     'eglot-hover-eldoc-function))

(setq eldoc-display-functions (list 'my-display-in-echo-area 'my-display-in-buffer))

(There's probably a better way to do that defalias thing, but as I said, I don't know elisp enough.)