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 support for inlay hints from TypeScript language server #3455

Merged
merged 1 commit into from
Apr 9, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.org
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
* Add [[https://github.com/aca/emmet-ls][emmet-ls]]
* Support all ~initializationOptions~ in ~typescript-language-server~
* Update rust-analyzer's inlay hint protocol support.
* Add support for ~typescript-language-server~’s inlay hints.
** Release 8.0.0
* Add ~lsp-clients-angular-node-get-prefix-command~ to get the Angular server from another location which is still has ~/lib/node_modules~ in it.
* Set ~lsp-clients-angular-language-server-command~ after the first connection to speed up subsequent connections.
Expand Down
145 changes: 144 additions & 1 deletion clients/lsp-javascript.el
Original file line number Diff line number Diff line change
Expand Up @@ -600,12 +600,88 @@ TypeScript 3.0 or newer in the workspace."
:type 'boolean
:package-version '(lsp-mode . "6.1"))

;; inlay hints

(defface lsp-javascript-inlay-face
'((t :inherit font-lock-comment-face))
"The face to use for the JavaScript inlays."
:group 'lsp-javascript
:package-version '(lsp-mode . "8.0.1"))

(defface lsp-javascript-inlay-type-face
'((t :inherit lsp-javascript-inlay-face))
"Face for inlay type hints (e.g. inferred variable types)."
:group 'lsp-javascript
:package-version '(lsp-mode . "8.0.1"))

(defcustom lsp-javascript-inlay-type-format ": %s"
"Format string for variable inlays (part of the inlay face)."
:type '(string :tag "String")
:group 'lsp-javascript
:package-version '(lsp-mode . "8.0.1"))

(defface lsp-javascript-inlay-parameter-face
'((t :inherit lsp-javascript-inlay-face))
"Face for inlay parameter hints (e.g. function parameter names at
call-site)."
:group 'lsp-javascript
:package-version '(lsp-mode . "8.0.1"))

(defcustom lsp-javascript-inlay-param-format "%s:"
"Format string for parameter inlays (part of the inlay face)."
:type '(string :tag "String")
:group 'lsp-javascript
:package-version '(lsp-mode . "8.0.1"))

(defcustom lsp-typescript-surveys-enabled t
"Enabled/disable occasional surveys that help us improve VS
Code's JavaScript and TypeScript support."
:type 'boolean
:package-version '(lsp-mode . "6.1"))

(defcustom lsp-javascript-display-inlay-hints nil
"Whether to display inlay hints."
:type 'boolean
:package-version '(lsp-mode . "8.0.1"))

(defcustom lsp-javascript-display-enum-member-value-hints nil
"Show inlay hints for enum member values."
:type 'boolean
:package-version '(lsp-mode . "8.0.1"))

(defcustom lsp-javascript-display-return-type-hints nil
"Show inlay hints for function return types."
:type 'boolean
:package-version '(lsp-mode . "8.0.1"))

(defcustom lsp-javascript-display-parameter-type-hints nil
"Show inlay hints for function parameters."
:type 'boolean
:package-version '(lsp-mode . "8.0.1"))

(defcustom lsp-javascript-display-parameter-name-hints "none"
"Level of hinting for parameter types."
:type '(choice (const :tag "none" "none")
(const :tag "literals" "literals")
(const :tag "all" "all"))
:package-version '(lsp-mode . "8.0.1"))

(defcustom lsp-javascript-display-parameter-name-hints-when-argument-matches-name nil
"Show inlay hints for function parameters even when argument matches
name (e.g. `data' variable passed as `data' parameter)."
:type 'boolean
:package-version '(lsp-mode . "8.0.1"))

(defcustom lsp-javascript-display-property-declaration-type-hints nil
"Show inlay hints for property declaration types."
:type 'boolean
:package-version '(lsp-mode . "8.0.1"))

(defcustom lsp-javascript-display-variable-type-hints nil
"Show inlay hints for variable types."
:type 'boolean
:package-version '(lsp-mode . "8.0.1"))

(lsp-register-custom-settings
'(("javascript.autoClosingTags" lsp-javascript-auto-closing-tags t)
("javascript.implicitProjectConfig.checkJs" lsp-javascript-implicit-project-config-check-js t)
Expand Down Expand Up @@ -678,7 +754,21 @@ Code's JavaScript and TypeScript support."
("typescript.format.insertSpaceBeforeAndAfterBinaryOperators" lsp-typescript-format-insert-space-before-and-after-binary-operators t)
("typescript.format.insertSpaceBeforeFunctionParenthesis" lsp-typescript-format-insert-space-before-function-parenthesis t)
("typescript.format.placeOpenBraceOnNewLineForControlBlocks" lsp-typescript-format-place-open-brace-on-new-line-for-control-blocks t)
("typescript.format.placeOpenBraceOnNewLineForFunctions" lsp-typescript-format-place-open-brace-on-new-line-for-functions t)))
("typescript.format.placeOpenBraceOnNewLineForFunctions" lsp-typescript-format-place-open-brace-on-new-line-for-functions t)
("typescript.inlayHints.includeInlayEnumMemberValueHints" lsp-javascript-display-enum-member-value-hints t)
("typescript.inlayHints.includeInlayFunctionLikeReturnTypeHints" lsp-javascript-display-return-type-hints t)
("typescript.inlayHints.includeInlayFunctionParameterTypeHints" lsp-javascript-display-parameter-type-hints t)
("typescript.inlayHints.includeInlayParameterNameHints" lsp-javascript-display-parameter-name-hints nil)
("typescript.inlayHints.includeInlayParameterNameHintsWhenArgumentMatchesName" lsp-javascript-display-parameter-name-hints-when-argument-matches-name t)
("typescript.inlayHints.includeInlayPropertyDeclarationTypeHints" lsp-javascript-display-property-declaration-type-hints t)
("typescript.inlayHints.includeInlayVariableTypeHints" lsp-javascript-display-variable-type-hints t)
("javascript.inlayHints.includeInlayEnumMemberValueHints" lsp-javascript-display-enum-member-value-hints t)
("javascript.inlayHints.includeInlayFunctionLikeReturnTypeHints" lsp-javascript-display-return-type-hints t)
("javascript.inlayHints.includeInlayFunctionParameterTypeHints" lsp-javascript-display-parameter-type-hints t)
("javascript.inlayHints.includeInlayParameterNameHints" lsp-javascript-display-parameter-name-hints nil)
("javascript.inlayHints.includeInlayParameterNameHintsWhenArgumentMatchesName" lsp-javascript-display-parameter-name-hints-when-argument-matches-name t)
("javascript.inlayHints.includeInlayPropertyDeclarationTypeHints" lsp-javascript-display-property-declaration-type-hints t)
("javascript.inlayHints.includeInlayVariableTypeHints" lsp-javascript-display-variable-type-hints t)))

(lsp-dependency 'typescript-language-server
'(:system lsp-clients-typescript-tls-path)
Expand Down Expand Up @@ -727,6 +817,56 @@ Code's JavaScript and TypeScript support."
(lsp)
(lsp--info "Renamed '%s' to '%s'." name (file-name-nondirectory new)))))

(defun lsp-javascript-update-inlay-hints ()
(if (lsp-javascript-initialized?)
(lsp-request-async
"typescript/inlayHints"
(lsp-make-javascript-inlay-hints-params
:text-document (lsp--text-document-identifier))
(lambda (res)
(lsp--remove-overlays 'lsp-javascript-inlay-hint)
(-each (gethash "inlayHints" res)
#'(lambda (hint)
(-let* (((&javascript:InlayHint :text :position :kind :whitespace-before? :whitespace-after?) hint)
(pos (lsp--position-to-point position))
(overlay (make-overlay pos pos nil 'front-advance 'end-advance)))
(overlay-put overlay 'lsp-javascript-inlay-hint t)
(overlay-put overlay 'before-string
(format "%s%s%s"
(if (and whitespace-before? (not (string= kind lsp/javascript-inlay-hint-kind-type-hint))) " " "")
(propertize (lsp-javascript-format-inlay text kind)
'font-lock-face (lsp-javascript-face-for-inlay kind))
(if whitespace-after? " " ""))))))))
:mode 'tick))

(defun lsp-javascript-format-inlay (text kind)
(cond
((eql kind lsp/javascript-inlay-hint-kind-type-hint) (format lsp-javascript-inlay-type-format text))
((eql kind lsp/javascript-inlay-hint-kind-parameter-hint) (format lsp-javascript-inlay-param-format text))
;; ((eql kind lsp/javascript-inlay-hint-kind-enum-hint) (format lsp-javascript-inlay-enum-format text))
(t text)))

(defun lsp-javascript-face-for-inlay (kind)
(cond
((eql kind lsp/javascript-inlay-hint-kind-type-hint) 'lsp-javascript-inlay-type-face)
((eql kind lsp/javascript-inlay-hint-kind-parameter-hint) 'lsp-javascript-inlay-parameter-face)
(t 'lsp-javascript-inlay-face)))

(defun lsp-javascript-initialized? ()
(when-let ((workspace (lsp-find-workspace 'ts-ls (buffer-file-name))))
(eq 'initialized (lsp--workspace-status workspace))))

(define-minor-mode lsp-javascript-inlay-hints-mode
"Mode for displaying inlay hints."
:lighter nil
(cond
(lsp-javascript-inlay-hints-mode
(lsp-javascript-update-inlay-hints)
(add-hook 'lsp-on-idle-hook #'lsp-javascript-update-inlay-hints nil t))
(t
(lsp--remove-overlays 'lsp-javascript-inlay-hint)
(remove-hook 'lsp-on-idle-hook #'lsp-javascript-update-inlay-hints t))))

(lsp-register-client
(make-lsp-client :new-connection (lsp-stdio-connection (lambda ()
`(,(lsp-package-path 'typescript-language-server)
Expand All @@ -748,6 +888,9 @@ Code's JavaScript and TypeScript support."
(lsp--set-configuration
(ht-merge (lsp-configuration-section "javascript")
(lsp-configuration-section "typescript")))))
:after-open-fn (lambda ()
(when lsp-javascript-display-inlay-hints
(lsp-javascript-inlay-hints-mode)))
:ignore-messages '("readFile .*? requested by TypeScript but content not available")
:server-id 'ts-ls
:request-handlers (ht ("_typescript.rename" #'lsp-javascript--rename))
Expand Down
6 changes: 6 additions & 0 deletions lsp-protocol.el
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,12 @@ See `-let' for a description of the destructuring mechanism."
(rust-analyzer:CommandLink (:title :command) (:arguments :tooltip))
(rust-analyzer:CommandLinkGroup (:commands) (:title)))

(defconst lsp/javascript-inlay-hint-kind-type-hint "Type")
(defconst lsp/javascript-inlay-hint-kind-parameter-hint "Parameter")
(defconst lsp/javascript-inlay-hint-kind-enum-hint "Enum")
(lsp-interface (javascript:InlayHint (:text :position :kind) (:whitespaceBefore :whitespaceAfter))
(javascript:InlayHintsParams (:textDocument) (:range)))

(lsp-interface (clojure-lsp:TestTreeParams (:uri :tree) nil)
(clojure-lsp:TestTreeNode (:name :range :nameRange :kind) (:children)))

Expand Down