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

Add breadcrumb on headerline #1799

Merged
merged 8 commits into from
Jun 14, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.org
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
* Changelog
** Master branch
* Add ~lsp-headerline-breadcrumb-mode~ which shows a breadcrumb with the document symbols on headerline when enabled.
* Add ~lsp-modeline-code-actions-mode~ which shows code actions on modeline when enabled.
* Support for Theia-based semantic highlighting has been removed in favor of the semanticTokens protocol specified by LSP 3.16. To enable it, set ~lsp-enable-semantic-highlighting~ to ~t~.
* ~lsp-metals~ moved into a separate repo https://github.com/emacs-lsp/lsp-metals
* Breaking change: use alist instead of hast-tables for =lsp-gopls-env= and =lsp-yaml-schemas=.
Expand Down
12 changes: 12 additions & 0 deletions docs/page/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ To see all error statistics in the modeline you can enable `lsp-diagnostics-mode

_Tip:_ To find out the global errors you might use `lsp-treemacs-errors-list`.

## Code actions on modeline

For a UI feedback of the available code actions, you can enable `lsp-modeline-code-actions-mode` which shows available code actions on modeline:

![](../examples/modeline-code-actions.png)

## Breadcrumb on headerline

For a UI feedback on headerline of the document symbol at point, you can enable `lsp-headerline-breadcrumb-mode` which shows a breadcrumb on top of window:

![](../examples/headerline-breadcrumb.png)

## Limitations

### File watches
Expand Down
Binary file added examples/headerline-breadcrumb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/modeline-code-actions.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
112 changes: 111 additions & 1 deletion lsp-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,21 @@ If this is set to nil, `eldoc' will show only the symbol information."
:type 'face
:group 'lsp-faces)

(defcustom lsp-headerline-breadcrumb-enable t
"Wheter to enable breadcrumb on headerline."
:type 'boolean
:group 'lsp-mode)

(defcustom lsp-headerline-breadcrumb-face 'font-lock-doc-face
"Face used on breadcrumb text on modeline."
:type 'face
:group 'lsp-faces)

(defface lsp-headerline-breadcrumb-deprecated-face '((t :inherit font-lock-doc-face
:strike-through t))
"Face used on breadcrumb deprecated text on modeline."
:group 'lsp-faces)

(defcustom lsp-after-diagnostics-hook nil
"Hooks to run after diagnostics are received.
Note: it runs only if the receiving buffer is open. Use
Expand Down Expand Up @@ -1968,7 +1983,96 @@ WORKSPACE is the workspace that contains the progress token."
(lsp-modeline-code-actions-mode
(add-hook 'lsp-on-idle-hook 'lsp--modeline-check-code-actions nil t))
(t
(remove-hook 'lsp-on-idle-hook 'lsp--modeline-check-code-actions t))))
(remove-hook 'lsp-on-idle-hook 'lsp--modeline-check-code-actions t)
(setq-local global-mode-string (remove '(t (:eval lsp--modeline-code-actions-string)) global-mode-string)))))


;; headerline breadcrumb

(defvar-local lsp--headerline-breadcrumb-string nil
"Holds the current breadcrumb string on headerline.")

(declare-function all-the-icons-material "ext:all-the-icons" t t)
(declare-function treemacs-get-icon-value "ext:treemacs" t t)
(declare-function lsp-treemacs-symbol-kind->icon "ext:lsp-treemacs" t t)

(defun lsp--headerline-breadcrumb-arrow-icon ()
"Build the arrow icon for headerline breadcrumb."
(if (require 'all-the-icons nil t)
(all-the-icons-material "chevron_right"
:face lsp-headerline-breadcrumb-face)
(propertize "›" 'face lsp-headerline-breadcrumb-face)))

(lsp-defun lsp--headerline-breadcrumb-symbol-icon ((&DocumentSymbol :kind))
"Build the SYMBOL icon for headerline breadcrumb."
(when (require 'lsp-treemacs t t)
(treemacs-get-icon-value (lsp-treemacs-symbol-kind->icon kind))))

(defun lsp--headerline-build-string (symbols-hierarchy)
"Build the header-line from SYMBOLS-HIERARCHY."
(seq-reduce (lambda (last-symbol-name symbol-to-append)
(let ((symbol2-name (if (lsp:document-symbol-deprecated? symbol-to-append)
(propertize (lsp:document-symbol-name symbol-to-append)
'font-lock-face 'lsp-headerline-breadcrumb-deprecated-face)
(propertize (lsp:document-symbol-name symbol-to-append)
'font-lock-face lsp-headerline-breadcrumb-face)))
(symbol2-icon (lsp--headerline-breadcrumb-symbol-icon symbol-to-append))
(arrow-icon (lsp--headerline-breadcrumb-arrow-icon)))
(format "%s %s %s"
last-symbol-name
arrow-icon
(if symbol2-icon
(concat symbol2-icon symbol2-name)
symbol2-name))))
symbols-hierarchy ""))

(defun lsp--headerline-document-symbols->symbols-hierarchy (document-symbols)
"Convert DOCUMENT-SYMBOLS to symbols hierarchy."
(-let (((symbol &as &DocumentSymbol? :children?) (seq-some (-lambda ((symbol &as &DocumentSymbol :range))
(-let (((beg . end) (lsp--range-to-region range)))
(and (<= beg (point) end)
symbol)))
document-symbols)))
(if children?
(append (list symbol) (lsp--headerline-document-symbols->symbols-hierarchy children?))
(when symbol
(list symbol)))))

(defun lsp--headerline-symbols-informations->symbols-hierarchy (symbols-informations)
"Convert SYMBOL-INFORMATIONS to symbols hierarchy."
(seq-some (-lambda ((symbol &as &SymbolInformation :location (&Location :range)))
(-let (((beg . end) (lsp--range-to-region range)))
(and (<= beg (point) end)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when tested manually, when I move outside of an element with one char it still stays the same, so probably something here is off by one.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't get this problem with lsp-dart, could you provide more details? Maybe the dart or other server is sending different ranges?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it, seems like the issue is lack of refresh mentioned bellow.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, so I guess it's fixed now after adding (force-modeline-update)

symbol)))
symbols-informations))

(defun lsp--headerline-symbols->symbols-hierarchy (symbols)
"Convert SYMBOLS to symbols-hierarchy."
(when-let (first-symbol (lsp-seq-first symbols))
(if (lsp-symbol-information? first-symbol)
(lsp--headerline-symbols-informations->symbols-hierarchy symbols)
(lsp--headerline-document-symbols->symbols-hierarchy symbols))))

(defun lsp--headerline-check-breadcrumb (&rest _)
"Request for document symbols to build the breadcrumb."
(when (lsp-feature? "textDocument/documentSymbol")
(-if-let* ((lsp--document-symbols-request-async t)
(symbols (lsp--get-document-symbols))
(symbols-hierarchy (lsp--headerline-symbols->symbols-hierarchy symbols)))
(setq lsp--headerline-breadcrumb-string (lsp--headerline-build-string symbols-hierarchy))
(setq lsp--headerline-breadcrumb-string nil))))

(define-minor-mode lsp-headerline-breadcrumb-mode
"Toggle breadcrumb on headerline."
:group 'lsp-mode
:global nil
(cond
(lsp-headerline-breadcrumb-mode
(add-to-list 'header-line-format '(t (:eval lsp--headerline-breadcrumb-string)))
(add-hook 'lsp-on-idle-hook 'lsp--headerline-check-breadcrumb nil t))
(t
(remove-hook 'lsp-on-idle-hook 'lsp--headerline-check-breadcrumb t)
(setq-local header-line-format (remove '(t (:eval lsp--headerline-breadcrumb-string)) header-line-format)))))



Expand Down Expand Up @@ -2628,6 +2732,7 @@ BINDINGS is a list of (key def cond)."
"Tl" lsp-lens-mode (lsp-feature? "textDocument/codeLens")
"TL" lsp-toggle-trace-io t
"Th" lsp-toggle-symbol-highlight (lsp-feature? "textDocument/documentHighlight")
"Tb" lsp-headerline-breadcrumb-mode (lsp-feature? "textDocument/documentSymbol")
"Ta" lsp-modeline-code-actions-mode (lsp-feature? "textDocument/codeAction")
"TS" lsp-ui-sideline-mode (featurep 'lsp-ui-sideline)
"Td" lsp-ui-doc-mode (featurep 'lsp-ui-doc)
Expand Down Expand Up @@ -2817,6 +2922,7 @@ active `major-mode', or for all major modes when ALL-MODES is t."
["Remove" lsp-workspace-folders-remove]
["Open" lsp-workspace-folders-open])
["Toggle Lenses" lsp-lens-mode]
["Toggle headerline breadcrumb" lsp-headerline-breadcrumb-mode]
["Toggle modeline code actions" lsp-modeline-code-actions-mode]))
"Menu for lsp-mode.")

Expand Down Expand Up @@ -6960,6 +7066,10 @@ returns the command to execute."
(lsp--capability "codeActionProvider"))
(lsp-modeline-code-actions-mode 1))

(when (and lsp-headerline-breadcrumb-enable
(lsp--capability "documentSymbolProvider"))
(lsp-headerline-breadcrumb-mode 1))

(cond
((or
(and (eq lsp-diagnostic-package :auto)
Expand Down