Get ts-plugin working with Emacs and LSP

This commit is contained in:
Tony Garnock-Jones 2021-12-03 15:37:41 +01:00
parent 78834dfb07
commit edbe7bcdac
3 changed files with 85 additions and 5 deletions

View File

@ -1,6 +1,17 @@
((typescript-mode
. ((eval . (setq tide-tsserver-executable
. ((eval
. (progn
;; For TIDE:
(setq tide-tsserver-executable
(concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/typescript/lib/tsserver.js"))))))
"node_modules/typescript/lib/tsserver.js"))
;; For LSP:
(require 'lsp-javascript)
(lsp-dependency 'typescript
`(:system ,(concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/typescript/lib/tsserver.js"))))
))))

View File

@ -45,7 +45,7 @@ a `typescript/` subdirectory.
If no such `typescript/` subdirectory exists in `node_modules`, then
because
[tsserver loads plugins from relative to tsserver.js rather than tsconfig.json](https://github.com/microsoft/TypeScript/issues/42688),
[tsserver loads plugins from relative to tsserver.js rather than tsconfig.json][tsserver-plugin-loading-problem],
you will have to tell `tide-mode` about where your project's
`tsserver` lives.
@ -82,6 +82,52 @@ If you use the `.dir-locals.el` methods, you may need to run
`tide-restart-server` once after opening the first TypeScript file in
your project (and then close and re-open that TypeScript file).
### Emacs with LSP
LSP will, by default, use its own `tsserver`, no matter what is in the
local `node_modules`. Because of the [issue with tsserver's approach
to plugin loading][tsserver-plugin-loading-problem], this means that
by default it will not load the Syndicate plugin.
Overriding the `tsserver` location is similar to the way it's done for
Tide, but instead of a variable value change, a function has to be
called. One good way to do it is to use `.dir-locals.el`, as above:
```elisp
((typescript-mode
. ((eval . (progn
(require 'lsp-javascript)
(lsp-dependency
'typescript
`(:system ,(concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/typescript/lib/tsserver.js"))))))))
```
And, of course, you can make changes for both Tide and LSP at once, if
you like:
```elisp
((typescript-mode
. ((eval
. (progn
;; For TIDE:
(setq tide-tsserver-executable
(concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/typescript/lib/tsserver.js"))
;; For LSP:
(require 'lsp-javascript)
(lsp-dependency 'typescript
`(:system ,(concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/typescript/lib/tsserver.js"))))
))))
```
### Visual Studio Code
After `yarn install`, if you have a `node_modules/typescript`
@ -106,6 +152,8 @@ file containing:
## Debugging
### Emacs with Tide
You can get verbose logs from Tide's tsserver by setting the Emacs
variable `tide-tsserver-process-environment`:
@ -125,3 +173,12 @@ Finally, you can set these options in a `.dir-locals.el` file, too:
((typescript-mode
. ((tide-tsserver-process-environment . ("TSS_LOG=-level verbose -file /tmp/tss.log")))))
```
### Emacs with LSP
`lsp-mode` helpfully puts logs in a `.log/` directory in your project
root! So you can follow `.log/tsserver.log`. There are also `lsp-mode`
options for changing the `tsserver` logging level, but I haven't
explored them yet.
[tsserver-plugin-loading-problem]: https://github.com/microsoft/TypeScript/issues/42688

View File

@ -50,6 +50,9 @@ const boot: tslib.server.PluginModuleFactory = ({ typescript: ts }) => {
return p.firstItem.start.pos + p.offset;
}
span(s: ts.TextSpan): ts.TextSpan;
span(s: undefined): undefined;
span(s: ts.TextSpan | undefined): ts.TextSpan | undefined;
span(s: ts.TextSpan | undefined): ts.TextSpan | undefined {
if (s !== void 0) {
const newStart = this.loc(s.start);
@ -485,7 +488,16 @@ const boot: tslib.server.PluginModuleFactory = ({ typescript: ts }) => {
}
getNavigationTree(fileName: string): ts.NavigationTree {
throw new Error('Method not implemented.');
const t = this.inner.getNavigationTree(fileName);
return withFileName(fileName, () => t, (fixup) => {
function fixupNavigationTree(t: ts.NavigationTree) {
fixup.span(t.nameSpan);
t.spans.forEach(s => fixup.span(s));
t.childItems?.forEach(fixupNavigationTree);
}
fixupNavigationTree(t);
return t;
});
}
prepareCallHierarchy(fileName: string, position: number): ts.CallHierarchyItem | ts.CallHierarchyItem[] | undefined {
@ -610,7 +622,7 @@ const boot: tslib.server.PluginModuleFactory = ({ typescript: ts }) => {
}
getApplicableRefactors(fileName: string, positionOrRange: number | ts.TextRange, preferences: ts.UserPreferences | undefined, triggerReason?: ts.RefactorTriggerReason): ts.ApplicableRefactorInfo[] {
throw new Error('Method not implemented.');
return this.inner.getApplicableRefactors(fileName, positionOrRange, preferences, triggerReason);
}
getEditsForRefactor(fileName: string, formatOptions: ts.FormatCodeSettings, positionOrRange: number | ts.TextRange, refactorName: string, actionName: string, preferences: ts.UserPreferences | undefined): ts.RefactorEditInfo | undefined {