zbelial / lspce

LSP Client for Emacs implemented as a module using rust.
GNU General Public License v3.0
154 stars 11 forks source link

[Feature request] Support imenu #2

Closed theFool32 closed 1 year ago

theFool32 commented 1 year ago

Thanks for your effort on lspce. I wonder if there is any plan to support imenu.

I have made a simple try with the help of eglot as below (no robustness considered):

(defun lspce-imenu-create ()
       (mapcar
        (lambda (obj)
          (cons
           (cdr (assoc (car obj) lspce--symbol-kind-names))
           (mapcar
            (lambda (obj)
              (let ((content
                     (cons (gethash "name" obj)
                           (lspce--lsp-position-to-point
                            (gethash "start"
                                     (gethash "range"
                                              (gethash "location"
                                                       obj))))))
                    (container (gethash "containerName" obj)))
                (if container
                    (list container content)
                  content)))
            (cdr obj))))

        (seq-group-by
         (lambda (obj) (gethash "kind" obj))
         (lspce--request "textDocument/documentSymbol" (list :textDocument (lspce--textDocumentIdenfitier (lspce--uri)))))))

(add-function :before-until (local 'imenu-create-index-function)  #'lspce-imenu-create)

It works like image

However, it remains two problems:

  1. lspce--request returns range without selectRange (compared with eglot), which leads to jumping to "|class CLS" instead of "class |CLS" (| denotes for the cursor)
  2. containerName only includes the direct father node. So just fun::var instead of CLS::fun::var.

Do you have any suggestions for them? Or maybe the whole part can be written in the rust part? (Sorry I haven't learned the rust)

theFool32 commented 1 year ago

Fixed by adding below to clientCapabilities:

                       :documentSymbol     (list
                                            :dynamicRegistration :json-false
                                            :hierarchicalDocumentSymbolSupport t
                                            :symbolKind `(:valueSet
                                                          [,@(mapcar
                                                              #'car lspce--symbol-kind-names)]))

and changing the imenu function as:

(defun lspce-imenu-create ()
       (cl-labels
           ((unfurl (obj)
              (if-let ((children (gethash "children" obj))
                       (name (gethash "name" obj)))
                  (cons obj
                        (mapcar (lambda (c)
                                  (puthash
                                   "containerName"
                                   (let ((existing (gethash "containerName" c)))
                                     (if existing (format "%s::%s" name existing)
                                       name)) c) c)
                                (mapcan #'unfurl children)))
                (list obj))))
         (mapcar
          (lambda (obj)
            (cons
             (cdr (assoc (car obj) lspce--symbol-kind-names))
             (mapcar
              (lambda (obj)
                (let ((content
                       (cons (gethash "name" obj)
                             (lspce--lsp-position-to-point
                              (gethash "start"
                                       (if-let ((range (gethash "selectionRange" obj)))
                                           range
                                         (gethash "range" (gethash "location" obj)))))))
                      (container (gethash "containerName" obj)))
                  (if container (list container content)
                    content)))
              (cdr obj))))

          (seq-group-by
           (lambda (obj) (gethash "kind" obj))
           (mapcan #'unfurl
                   (lspce--request "textDocument/documentSymbol" (list :textDocument (lspce--textDocumentIdenfitier (lspce--uri)))))))))