emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master b1f8d98a119 1/2: Eglot: rework eglot-imenu


From: João Távora
Subject: master b1f8d98a119 1/2: Eglot: rework eglot-imenu
Date: Fri, 7 Apr 2023 09:55:53 -0400 (EDT)

branch: master
commit b1f8d98a119ab8845d25d80c480cde6e385d8749
Author: João Távora <joaotavora@gmail.com>
Commit: João Távora <joaotavora@gmail.com>

    Eglot: rework eglot-imenu
    
    Most newer servers return a vector of 'DocumentSymbol' as a response
    to 'textDocument/documentSymbol'.  It's not worth trying to dumb this
    down to imenu format of 'SymbolInformation' vectors.
    
    This lays groundwork for the forthcoming "breadcrumb" feature of
    bug#58431.
    
    * lisp/progmodes/eglot.el
    (eglot--imenu-SymbolInformation, eglot--imenu-DocumentSymbol): New
    helpers.
    (eglot-imenu): Rework.
---
 lisp/electric.el        |  4 +--
 lisp/progmodes/eglot.el | 82 +++++++++++++++++++++++++------------------------
 2 files changed, 43 insertions(+), 43 deletions(-)

diff --git a/lisp/electric.el b/lisp/electric.el
index bac3f5a2b3c..cef5326852c 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -409,9 +409,7 @@ If multiple rules match, only first one is executed.")
                                 (goto-char pos)
                                 (funcall probe last-command-event))))
                          (when res (throw 'done res))))))))))
-    (when (and rule
-               ;; Not in a string or comment.
-               (not (nth 8 (save-excursion (syntax-ppss pos)))))
+    (when rule
       (goto-char pos)
       (when (functionp rule) (setq rule (funcall rule)))
       (dolist (sym (if (symbolp rule) (list rule) rule))
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index f3b806e5613..db57b122a94 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -486,9 +486,7 @@ This can be useful when using docker to run a language 
server.")
       (SymbolInformation (:name :kind :location)
                          (:deprecated :containerName))
       (DocumentSymbol (:name :range :selectionRange :kind)
-                      ;; `:containerName' isn't really allowed , but
-                      ;; it simplifies the impl of `eglot-imenu'.
-                      (:detail :deprecated :children :containerName))
+                      (:detail :deprecated :children))
       (TextDocumentEdit (:textDocument :edits) ())
       (TextEdit (:range :newText))
       (VersionedTextDocumentIdentifier (:uri :version) ())
@@ -3235,49 +3233,53 @@ for which LSP on-type-formatting should be requested."
        :deferred :textDocument/documentHighlight)
       nil)))
 
+(defun eglot--imenu-SymbolInformation (res)
+  "Compute `imenu--index-alist' for RES vector of SymbolInformation."
+  (mapcar
+   (pcase-lambda (`(,kind . ,objs))
+     (cons
+      (alist-get kind eglot--symbol-kind-names "Unknown")
+      (mapcan
+       (pcase-lambda (`(,container . ,objs))
+         (let ((elems (mapcar
+                       (eglot--lambda ((SymbolInformation) kind name location)
+                         (let ((reg (eglot--range-region
+                                     (plist-get location :range))))
+                           (cons (propertize name
+                                             'breadcrumb-region reg
+                                             'breadcrumb-kind kind)
+                                 (car reg))))
+                       objs)))
+           (if container (list (cons container elems)) elems)))
+       (seq-group-by
+        (eglot--lambda ((SymbolInformation) containerName) containerName) 
objs))))
+   (seq-group-by (eglot--lambda ((SymbolInformation) kind) kind) res)))
+
+(defun eglot--imenu-DocumentSymbol (res)
+  "Compute `imenu--index-alist' for RES vector of DocumentSymbol."
+  (cl-labels ((dfs (&key name children range kind &allow-other-keys)
+                (let* ((reg (eglot--range-region range))
+                       (name (propertize name
+                                         'breadcrumb-region reg
+                                         'breadcrumb-kind kind)))
+                  (if children
+                      (cons name
+                            (mapcar (lambda (c) (apply #'dfs c)) children))
+                    (cons name (car reg))))))
+    (mapcar (lambda (s) (apply #'dfs s)) res)))
+
 (defun eglot-imenu ()
   "Eglot's `imenu-create-index-function'.
 Returns a list as described in docstring of `imenu--index-alist'."
-  (cl-labels
-      ((unfurl (obj)
-         (eglot--dcase obj
-           (((SymbolInformation)) (list obj))
-           (((DocumentSymbol) name children)
-            (cons obj
-                  (mapcar
-                   (lambda (c)
-                     (plist-put
-                      c :containerName
-                      (let ((existing (plist-get c :containerName)))
-                        (if existing (format "%s::%s" name existing)
-                          name))))
-                   (mapcan #'unfurl children)))))))
-    (mapcar
-     (pcase-lambda (`(,kind . ,objs))
-       (cons
-        (alist-get kind eglot--symbol-kind-names "Unknown")
-        (mapcan (pcase-lambda (`(,container . ,objs))
-                  (let ((elems (mapcar
-                                (lambda (obj)
-                                  (cons (plist-get obj :name)
-                                        (car (eglot--range-region
-                                              (eglot--dcase obj
-                                                (((SymbolInformation) location)
-                                                 (plist-get location :range))
-                                                (((DocumentSymbol) 
selectionRange)
-                                                 selectionRange))))))
-                                objs)))
-                    (if container (list (cons container elems)) elems)))
-                (seq-group-by
-                 (lambda (e) (plist-get e :containerName)) objs))))
-     (seq-group-by
-      (lambda (obj) (plist-get obj :kind))
-      (mapcan #'unfurl
-              (eglot--request (eglot--current-server-or-lose)
+  (let* ((res (eglot--request (eglot--current-server-or-lose)
                               :textDocument/documentSymbol
                               `(:textDocument
                                 ,(eglot--TextDocumentIdentifier))
-                              :cancel-on-input non-essential))))))
+                              :cancel-on-input non-essential))
+         (head (and res (elt res 0))))
+    (eglot--dcase head
+      (((SymbolInformation)) (eglot--imenu-SymbolInformation res))
+      (((DocumentSymbol)) (eglot--imenu-DocumentSymbol res)))))
 
 (cl-defun eglot--apply-text-edits (edits &optional version)
   "Apply EDITS for current buffer if at VERSION, or if it's nil."



reply via email to

[Prev in Thread] Current Thread [Next in Thread]