]> git.eshelyaron.com Git - emacs.git/commitdiff
Eglot: use Eldoc in eglot-hierarchy-mode
authorJoão Távora <joaotavora@gmail.com>
Tue, 11 Feb 2025 16:50:23 +0000 (16:50 +0000)
committerEshel Yaron <me@eshelyaron.com>
Wed, 12 Feb 2025 10:52:19 +0000 (11:52 +0100)
Use it to show details of the thing at point, like the full
signature and the locus of the definition.

* lisp/progmodes/eglot.el: Add optional arg MODE.
(eglot--hierarchy-source-major-mode): New defvar.
(eglot--hierarchy-1): Adjust.
(eglot-hierarchy-mode): Set eldoc stuff.
(eglot-hierarchy-center-on-node): Cosmetic fix.
(eglot-hierarchy-detail-eldoc-function)
(eglot-hierarchy-locus-eldoc-function): New eldoc functions.

(cherry picked from commit 3fd0b802de20dc83b5d5236b6d458df73c9d4e77)

lisp/progmodes/eglot.el

index fd94e91828c05be686103bc395dc5c4b7169950b..b5f3afa5d544d6e025fa84d3978df5ed7e1a967d 100644 (file)
@@ -1955,32 +1955,34 @@ Doubles as an indicator of snippet support."
            (unless (bound-and-true-p yas-minor-mode) (yas-minor-mode 1))
            (apply #'yas-expand-snippet args)))))
 
- (defun eglot--format-markup (markup)
+ (defun eglot--format-markup (markup &optional mode)
   "Format MARKUP according to LSP's spec.
 MARKUP is either an LSP MarkedString or MarkupContent object."
-  (let (string mode language)
+  (let (string render-mode language)
     (cond ((stringp markup)
            (setq string markup
-                 mode 'gfm-view-mode))
+                 render-mode (or mode 'gfm-view-mode)))
           ((setq language (plist-get markup :language))
            ;; Deprecated MarkedString
            (setq string (concat "```" language "\n"
                                 (plist-get markup :value) "\n```")
-                 mode 'gfm-view-mode))
+                 render-mode (or mode 'gfm-view-mode)))
           (t
            ;; MarkupContent
            (setq string (plist-get markup :value)
-                 mode (pcase (plist-get markup :kind)
-                        ("markdown" 'gfm-view-mode)
-                        ("plaintext" 'text-mode)
-                        (_ major-mode)))))
+                 render-mode
+                 (or mode
+                     (pcase (plist-get markup :kind)
+                       ("markdown" 'gfm-view-mode)
+                       ("plaintext" 'text-mode)
+                       (_ major-mode))))))
     (with-temp-buffer
       (setq-local markdown-fontify-code-blocks-natively t)
       (insert string)
       (let ((inhibit-message t)
             (message-log-max nil)
             match)
-        (ignore-errors (delay-mode-hooks (funcall mode)))
+        (ignore-errors (delay-mode-hooks (funcall render-mode)))
         (font-lock-ensure)
         (goto-char (point-min))
         (let ((inhibit-read-only t))
@@ -3527,8 +3529,7 @@ for which LSP on-type-formatting should be requested."
                         (ensure-resolved (get-text-property 0 'eglot--lsp-item proxy))
                         :detail)))
            (when (and (stringp detail) (not (string= detail "")))
-             ;; Forces major-mode based fontification
-             (eglot--format-markup (list :value detail)))))
+             (eglot--format-markup detail major-mode))))
        :company-doc-buffer
        (lambda (proxy)
          (let* ((resolved
@@ -4530,6 +4531,7 @@ If NOERROR, return predicate, else erroring function."
 
 (defvar-local eglot--hierarchy-roots nil)
 (defvar-local eglot--hierarchy-specs nil)
+(defvar-local eglot--hierarchy-source-major-mode nil)
 
 (defun eglot--hierarchy-children (node)
   (cl-flet ((get-them (method node)
@@ -4601,6 +4603,7 @@ If NOERROR, return predicate, else erroring function."
 (defun eglot--hierarchy-1 (name provider preparer specs)
   (eglot-server-capable-or-lose provider)
   (let* ((server (eglot-current-server))
+         (mode major-mode)
          (roots (jsonrpc-request
                  server
                  preparer
@@ -4613,6 +4616,7 @@ If NOERROR, return predicate, else erroring function."
        eglot--hierarchy-roots roots
        eglot--hierarchy-specs specs
        eglot--cached-server server
+       eglot--hierarchy-source-major-mode mode
        buffer-read-only t
        revert-buffer-function
        (lambda (&rest _ignore)
@@ -4650,16 +4654,40 @@ If NOERROR, return predicate, else erroring function."
 (define-derived-mode eglot-hierarchy-mode special-mode
   "Eglot special" "Eglot mode for viewing hierarchies.
 \\{eglot-hierarchy-mode-map}"
-  :interactive nil)
+  :interactive nil
+  (setq eldoc-documentation-strategy
+        #'eldoc-documentation-compose)
+  (add-hook 'eldoc-documentation-functions
+            #'eglot-hierarchy-detail-eldoc-function
+            nil t)
+  (add-hook 'eldoc-documentation-functions
+            #'eglot-hierarchy-locus-eldoc-function
+            t t))
 
 (defun eglot-hierarchy-center-on-node ()
   "Refresh hierarchy, centering on node at point."
   (interactive)
   (setq-local eglot--hierarchy-roots
               (list (get-text-property (point)
-                                 'eglot--hierarchy-node)))
+                                       'eglot--hierarchy-node)))
   (eglot--hierarchy-2))
 
+(defun eglot-hierarchy-detail-eldoc-function (_cb &rest _ignored)
+  (when-let* ((detail
+               (plist-get (get-text-property (point) 'eglot--hierarchy-node)
+                          :detail)))
+    (eglot--format-markup detail eglot--hierarchy-source-major-mode)))
+
+(defun eglot-hierarchy-locus-eldoc-function (_cb &rest _ignored)
+  (let* ((node (get-text-property (point) 'eglot--hierarchy-node))
+         (uri (plist-get node :uri))
+         (loc (plist-get (plist-get node :range) :start)))
+    (and uri loc
+         ;; maybe use `file-relative-name'?
+         (format "%s:%s:%s" (eglot-uri-to-path uri)
+                 (1+ (plist-get loc :line))
+                 (plist-get loc :character)))))
+
 \f
 ;;; Hacks
 ;;;