tigersoldier / company-lsp

Company completion backend for lsp-mode
GNU General Public License v3.0
251 stars 26 forks source link

Is there a way to utilize `lsp-find-definition` and `lsp-find-references` in the popup? #138

Closed johndebord closed 4 years ago

johndebord commented 4 years ago

I can't seem to figure out a way for company-mode or company-lsp or lsp-mode to jump to the definition or show the references of the current symbol on which the cursor is on in the popup. Is this possible?


I envision it to be something close to this:

(defun jd:lsp-find-definitions ()
  (interactive)
  (if (company--active-p)
      (progn
        ;; Logic for jumping to definition at the symbol at point.
        )
    (progn
      (lsp-find-definition))))

image

yyoncho commented 4 years ago

There is do direct API that matches what you are looking for but you could try to simulate it using 1) workspace/symbol search for global 2) textDocument/documentSymbol for local methods.

johndebord commented 4 years ago

Ok, thanks. But that now brings up several questions that I'm not quite sure of:

  1. How do I search for workspace/symbol?
  2. How do I search for textDocument/documentSymbol?
  3. How do I know if it's a local method in the context of the popup?
  4. How do I know if it's a global method in the context of the popup?
  5. How could the simulation of said functionality be achieved using the above at my disposal?
yyoncho commented 4 years ago

Alternative solution:

(defun my/company-go-to-def ()
  ""
  (interactive)
  (let ((buf (current-buffer))
        (line (buffer-substring (point-at-bol) (point-at-eol)))
        (point (point)))
    (company-complete-selection)
    (backward-char)
    (lsp-find-definition)
    (let ((b (current-buffer)))
      (switch-to-buffer buf)
      (delete-region (point-at-bol)
                     (point-at-eol))
      (insert line)
      (set-window-point (get-buffer-window) point)
      (switch-to-buffer b))))

(define-key company-active-map (kbd "C-o") 'my/company-go-to-def)
johndebord commented 4 years ago

Thanks for the help. Here's the solution I came up with; using yours as a start (using a few custom external functions):

;; Find lsp declaration in either the `company` popup or in a normal fashion.
(defun jd:lsp-find-declaration ()
  (interactive)
  (if (and (company--active-p) (jd:lsp-backend-p))
      (progn
        (jd:lsp-dispatch 'declaration))
    (progn
      (lsp-find-declaration))))

;; Find lsp definitions in either the `company` popup or in a normal fashion.
(defun jd:lsp-find-definition ()
  (interactive)
  (if (and (company--active-p) (jd:lsp-backend-p))
      (progn
        (jd:lsp-dispatch 'definition))
    (progn
      (lsp-find-definition))))

;; Find lsp references in either the `company` popup or in a normal fashion.
(defun jd:lsp-find-references ()
  (interactive)
  (if (and (company--active-p) (jd:lsp-backend-p))
      (progn
        (jd:lsp-dispatch 'references))
    (progn
      (lsp-find-references))))

(defun jd:lsp-backend-p ()
  (let ((backend (company--group-lighter
                  (nth company-selection
                       company-candidates)
                  company-lighter-base)))
    (if (not (string-equal backend "company-<lsp>"))
        (error "`jd:lsp-backend-p`")
      t)))

(defun jd:lsp-dispatch (tag)
  (let ((current-company-index company-selection)
        (line (buffer-substring (point-at-bol) (point-at-eol)))
        (saved-position (point))
        (source-buffer (current-buffer))
        (result-buffer))

    (company-complete-selection)
    (if (eq (char-before) #x28) ; '('
        (progn
          (backward-char 1)
          (while (not (eq (char-after) #x29))
            (delete-char 1))
          (delete-char 1)))
    (if (eq (char-before) #x29) ; ')'
        (progn
          (backward-char 2)
          (delete-char 2)))
    (backward-char 1)

    (cond
     ((eq tag 'declaration)
      (if (null (lsp-find-declaration))
          (progn
            (jd:lsp-dispatch-reset)
            (error "`jd:lsp-dispatch`::declaration"))))
     ((eq tag 'definition)
      (if (null (lsp-find-definition))
          (progn
            (jd:lsp-dispatch-reset)
            (error "`jd:lsp-dispatch`::definition"))))
     ((eq tag 'references)
      (if (null (lsp-find-references))
          (progn
            (jd:lsp-dispatch-reset)
            (error "`jd:lsp-dispatch`::references")))))

    (setq result-buffer (current-buffer))
    (switch-to-buffer source-buffer)
    (xref-pop-marker-stack)
    (jd:lsp-dispatch-reset)
    (xref-push-marker-stack)
    (switch-to-buffer result-buffer)))

(defun jd:lsp-dispatch-reset ()
  (delete-region (point-at-bol)
                 (point-at-eol))
  (insert line)
  (set-window-point (get-buffer-window) saved-position)

  ;; To fake that we actually make a completion.
  (jd:recently-finished-completion-nil)

  (jd:incredibly-smart-tab 'progmode)
  (company-set-selection current-company-index))