Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support the which-func package, i.e. which-function-mode #758

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 16 additions & 0 deletions eglot-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,22 @@ Pass TIMEOUT to `eglot--with-timeout'."
(forward-line -1)
(should (looking-at "Complete, but not unique"))))))

(ert-deftest basic-which-func ()
"Test basic which-func functionality in a python LSP"
(skip-unless (executable-find "pyls"))
(eglot--with-fixture
`(("project" . (("something.py" . "def foo(): pass\ndef bar(): foo()\n"))))
(with-current-buffer
(eglot--find-file-noselect "project/something.py")
(should (eglot--tests-connect))
(which-function-mode t)
(goto-char (point-min)) ; def foo():
(should (string= (which-function) "foo"))
(goto-char (point-max)) ; end of file
(should (null (which-function)))
(forward-line -1) ; def bar():
(should (string= (which-function) "bar")))))

(ert-deftest basic-xref ()
"Test basic xref functionality in a python LSP"
(skip-unless (executable-find "pyls"))
Expand Down
52 changes: 51 additions & 1 deletion eglot.el
Original file line number Diff line number Diff line change
Expand Up @@ -1555,7 +1555,8 @@ Use `eglot-managed-p' to determine if current buffer is managed.")
(eglot--setq-saving company-tooltip-align-annotations t)
(unless (eglot--stay-out-of-p 'imenu)
(add-function :before-until (local 'imenu-create-index-function)
#'eglot-imenu))
#'eglot-imenu)
(add-hook 'which-func-functions #'eglot-which-func nil t))
(unless (eglot--stay-out-of-p 'flymake) (flymake-mode 1))
(unless (eglot--stay-out-of-p 'eldoc) (eldoc-mode 1))
(cl-pushnew (current-buffer) (eglot--managed-buffers (eglot-current-server))))
Expand All @@ -1576,6 +1577,7 @@ Use `eglot-managed-p' to determine if current buffer is managed.")
(cl-loop for (var . saved-binding) in eglot--saved-bindings
do (set (make-local-variable var) saved-binding))
(remove-function (local 'imenu-create-index-function) #'eglot-imenu)
(remove-hook 'which-func-functions #'eglot-which-func t)
(when eglot--current-flymake-report-fn
(eglot--report-to-flymake nil)
(setq eglot--current-flymake-report-fn nil))
Expand Down Expand Up @@ -2642,6 +2644,54 @@ is not active."
,(eglot--TextDocumentIdentifier))
:cancel-on-input non-essential))))))

(defun eglot-which-func ()
"EGLOT's hook for `which-func-functions'."
(let ((name) container)
(when (boundp 'imenu--index-alist)
(let ((alist imenu--index-alist)
entry pos imstack region)
;; Elements of alist are either ("name" [pos] ...),
;; or ("submenu" ("name" [pos] ...) ...).
;; The list can be arbitrarily nested.
(while (or alist imstack)
(if (null alist)
(setq alist (car imstack)
imstack (cdr imstack))

(setq entry (car-safe alist)
alist (cdr-safe alist))

(cond
((atom entry)) ; Skip anything not a cons.

((imenu--subalist-p entry)
(setq imstack (cons alist imstack)
alist (cdr entry)))

;; entry is ("name" [pos] ...)
((and (consp (setq pos (cdr entry)))
(vectorp (setq pos (car pos)))
(listp (setq pos (aref pos 0)))
;; pos is (:name "name" :location (...) ...)
(consp (setq region
(eglot--range-region
(eglot--dcase pos
(((SymbolInformation) location)
(plist-get location :range))
(((DocumentSymbol) range)
range)))))
;; region is (start . end)
(>= (point) (car region))
(<= (point) (cdr region)))
(setq name (plist-get pos :name))
;; pos can also contain a :containerName
(when (and (boundp 'which-func-imenu-joiner-function)
which-func-imenu-joiner-function
(setq container (plist-get pos :containerName)))
(setq name (funcall which-func-imenu-joiner-function
(list container name))))))))))
name))

(defun eglot--apply-text-edits (edits &optional version)
"Apply EDITS for current buffer if at VERSION, or if it's nil."
(unless (or (not version) (equal version eglot--versioned-identifier))
Expand Down