Merge branch 'neoclide:master' into master
This commit is contained in:
commit
7d076e2bf2
44 changed files with 2237 additions and 876 deletions
78
Readme.md
78
Readme.md
|
@ -41,7 +41,7 @@ tsserver understand your code.
|
|||
installation.
|
||||
|
||||
**Note:** tsserver could be quite slow to initialize on big project, exclude
|
||||
unneunnecessary files in your jsconfig.json/tsconfig.json.
|
||||
unnecessary files in your jsconfig.json/tsconfig.json.
|
||||
|
||||
**Note:** if you're using WSL, copy you project files from mounted dirs to linux home otherwise tsserver will not work properly.
|
||||
|
||||
|
@ -100,10 +100,19 @@ Almost the same as VSCode.
|
|||
- Code refactor using code actions.
|
||||
- Find references.
|
||||
- Signature help.
|
||||
- Call hierarchy.
|
||||
- Selection range.
|
||||
- Semantic tokens.
|
||||
- Rename symbols support.
|
||||
- Automatic tag closing.
|
||||
- Rename imports on file rename, require
|
||||
[watchman](https://facebook.github.io/watchman/) installed in your \$PATH.
|
||||
- Search for workspace symbols.
|
||||
- Inlay hints support using virtual text feature of neovim, which requires:
|
||||
- TypeScript >= 4.4.0
|
||||
- Neovim >= 0.4.0
|
||||
- Enabled by options starts with `typescript.inlayHints` or
|
||||
`javascript.inlayHints`.
|
||||
|
||||
Tsserver module first resolved from your local workspace. If it's not found, use
|
||||
tsserver from `tsserver.tsdk` configuration or use bundled tsserver with this
|
||||
|
@ -117,6 +126,8 @@ for guide of coc.nvim's configuration.
|
|||
|
||||
- `tsserver.enable`:Enable tsserver extension, default: `true`
|
||||
- `tsserver.locale`:Locale of tsserver, default: `""`
|
||||
- `tsserver.ignoreLocalTsserver`:Always use tsserver module from tsserver.tsdk
|
||||
or coc-tsserver extension.
|
||||
- `tsserver.typingsCacheLocation`:Folder path for cache typings, default: `""`
|
||||
- `tsserver.formatOnType`:Run format on type special characters., default:
|
||||
`true`
|
||||
|
@ -128,10 +139,9 @@ for guide of coc.nvim's configuration.
|
|||
- `tsserver.log`:Log level of tsserver, default: `"off"`
|
||||
- `tsserver.trace.server`:Trace level of tsserver, default: `"off"`
|
||||
- `tsserver.pluginPaths`:Folders contains tsserver plugins, default: `[]`
|
||||
- `tsserver.debugPort`:Debug port number of tsserver
|
||||
- `tsserver.watchOptions`:Configure which watching strategies should be used to
|
||||
keep track of files and directories. Requires using TypeScript 3.8+ in the
|
||||
workspace, default: undefined.
|
||||
workspace, default: `undefined`
|
||||
- `tsserver.reportStyleChecksAsWarnings` default: `true`
|
||||
- `tsserver.implicitProjectConfig.checkJs`:Enable checkJs for implicit project,
|
||||
default: `false`
|
||||
|
@ -139,27 +149,38 @@ for guide of coc.nvim's configuration.
|
|||
experimentalDecorators for implicit project, default: `false`
|
||||
- `tsserver.disableAutomaticTypeAcquisition`:Disable download of typings,
|
||||
default: `false`
|
||||
- `tsserver.useBatchedBufferSync`: use batched buffer synchronize support.
|
||||
- `tsserver.useBatchedBufferSync`: use batched buffer synchronize support, default: `true`
|
||||
- `tsserver.enableTracing`: Enables tracing TS server performance to a
|
||||
directory. These trace files can be used to diagnose TS Server performance
|
||||
issues. The log may contain file paths, source code, and other potentially
|
||||
sensitive information from your project, default: `false`
|
||||
- `typescript.check.npmIsInstalled`: Check if npm is installed for [Automatic
|
||||
Type
|
||||
Acquisition](https://code.visualstudio.com/docs/nodejs/working-with-javascript#_typings-and-automatic-type-acquisition).
|
||||
- `typescript.updateImportsOnFileMove.enable`:Enable update imports on file
|
||||
move., default: `true`
|
||||
- `typescript.implementationsCodeLens.enable`:Enable codeLens for
|
||||
implementations, default: `true`
|
||||
- `typescript.referencesCodeLens.enable`:Enable codeLens for references,
|
||||
default: `true`
|
||||
- `typescript.preferences.importModuleSpecifier` default: `"auto"`
|
||||
- `typescript.referencesCodeLens.showOnAllFunctions`: Enable/disable references CodeLens on all functions in typescript files. Default: `false`
|
||||
- `typescript.preferences.importModuleSpecifier` default: `"shortest"`
|
||||
- `typescript.preferences.importModuleSpecifierEnding` default: `"auto"`
|
||||
- `typescript.preferences.quoteStyle` default: `"single"`
|
||||
- `typescript.preferences.includePackageJsonAutoImports`: Enable/disable
|
||||
searching `package.json` dependencies for available auto imports, default:
|
||||
`"auto"`
|
||||
- `typescript.suggestionActions.enabled`:Enable/disable suggestion diagnostics
|
||||
for TypeScript files in the editor. Requires using TypeScript 2.8 or newer in
|
||||
the workspace., default: `true`
|
||||
- `typescript.validate.enable`:Enable/disable TypeScript validation., default:
|
||||
`true`
|
||||
- `typescript.showUnused`: show unused variable hint, default: `true`.
|
||||
- `typescript.autoClosingTags`: Enable/disable autoClosing of JSX tags, default: `false`.
|
||||
- `typescript.autoClosingTags`: Enable/disable autoClosing of JSX tags, default: `true`
|
||||
- `typescript.suggest.enabled` default: `true`
|
||||
- `typescript.suggest.paths`:Enable/disable suggest paths in import statement
|
||||
and require calls, default: `true`
|
||||
- `typescript.suggest.autoImports`:Enable/disable auto import suggests.,
|
||||
- `typescript.suggest.autoImports`:Enable/disable auto import suggests,
|
||||
default: `true`
|
||||
- `typescript.suggest.completeFunctionCalls`:Enable snippet for method
|
||||
suggestion, default: `true`
|
||||
|
@ -168,6 +189,13 @@ for guide of coc.nvim's configuration.
|
|||
TypeScript 4.3+ in the workspace, default: `true`
|
||||
- `typescript.suggest.includeCompletionsWithSnippetText`: Enable snippet completions
|
||||
from TS Server. Requires using TypeScript 4.3+ in the workspace, default: `true`
|
||||
- `typescript.suggest.classMemberSnippets.enabled`: Enable/disable
|
||||
snippet completions for class members. Requires using TypeScript 4.5+ in the
|
||||
workspace, default: `true`
|
||||
- `typescript.suggest.jsdoc.generateReturns`: Enable/disable generating
|
||||
`@return` annotations for JSDoc templates. Requires using TypeScript 4.2+ in
|
||||
the workspace. default: `true`
|
||||
- `typescript.suggest.includeAutomaticOptionalChainCompletions`: default: `true`
|
||||
- `typescript.format.enabled`:Enable/disable format of typescript files.
|
||||
- `typescript.format.insertSpaceAfterCommaDelimiter` default: `true`
|
||||
- `typescript.format.insertSpaceAfterConstructor` default: `false`
|
||||
|
@ -193,14 +221,15 @@ for guide of coc.nvim's configuration.
|
|||
- `typescript.format.insertSpaceAfterTypeAssertion` default: `false`
|
||||
- `typescript.format.placeOpenBraceOnNewLineForFunctions` default: `false`
|
||||
- `typescript.format.placeOpenBraceOnNewLineForControlBlocks` default: `false`
|
||||
- `typescript.suggest.includeAutomaticOptionalChainCompletions`: default: `true`
|
||||
- `javascript.format.enabled`: Enable/disable format for javascript files.
|
||||
- `javascript.showUnused`: show unused variable hint.
|
||||
- `javascript.autoClosingTags`: Enable/disable autoClosing of JSX tags, default: `false`.
|
||||
- `typescript.inlayHints`: inlayHints related options.
|
||||
- `javascript.format.enabled`: Enable/disable format for javascript files, default: `true`
|
||||
- `javascript.showUnused`: show unused variable hint, default: `true`
|
||||
- `javascript.autoClosingTags`: Enable/disable autoClosing of JSX tags, default: `true`
|
||||
- `javascript.updateImportsOnFileMove.enable` default: `true`
|
||||
- `javascript.implementationsCodeLens.enable` default: `true`
|
||||
- `javascript.referencesCodeLens.enable` default: `true`
|
||||
- `javascript.preferences.importModuleSpecifier` default: `"auto"`
|
||||
- `javascript.referencesCodeLens.showOnAllFunctions`: Enable/disable references CodeLens on all functions in JavaScript files default: `false`
|
||||
- `javascript.preferences.importModuleSpecifier` default: `"shortest"`
|
||||
- `javascript.preferences.importModuleSpecifierEnding` default: `"auto"`
|
||||
- `javascript.preferences.quoteStyle` default: `"single"`
|
||||
- `javascript.validate.enable`: Enable/disable JavaScript validation., default:
|
||||
|
@ -219,6 +248,13 @@ for guide of coc.nvim's configuration.
|
|||
- `javascript.suggest.includeCompletionsForImportStatements`: Enable/disable
|
||||
auto-import-style completions on partially-typed import statements. Requires
|
||||
using TypeScript 4.3+ in the workspace, default: `true`
|
||||
- `javascript.suggest.jsdoc.generateReturns`: Enable/disable generating
|
||||
`@return` annotations for JSDoc templates. Requires using TypeScript 4.2+ in
|
||||
the workspace. default: `true`
|
||||
- `javascript.suggest.classMemberSnippets.enabled`: Enable/disable
|
||||
snippet completions for class members. Requires using TypeScript 4.5+ in the
|
||||
workspace, default: `true`
|
||||
- `javascript.suggest.includeAutomaticOptionalChainCompletions`: default: `true`
|
||||
- `javascript.format.insertSpaceAfterCommaDelimiter` default: `true`
|
||||
- `javascript.format.insertSpaceAfterConstructor` default: `false`
|
||||
- `javascript.format.insertSpaceAfterSemicolonInForStatements` default: `true`
|
||||
|
@ -243,10 +279,22 @@ for guide of coc.nvim's configuration.
|
|||
- `javascript.format.insertSpaceAfterTypeAssertion` default: `false`
|
||||
- `javascript.format.placeOpenBraceOnNewLineForFunctions` default: `false`
|
||||
- `javascript.format.placeOpenBraceOnNewLineForControlBlocks` default: `false`
|
||||
- `javascript.suggest.includeAutomaticOptionalChainCompletions`: default: `true`
|
||||
- `javascript.inlayHints`: inlayHints related options.
|
||||
|
||||
Configurations are the same as with VSCode. Try completion with `tsserver`,
|
||||
`typescript` or `javascript` in your `coc-settings.json`.
|
||||
### Added on 1.10.0
|
||||
|
||||
- `javascript.suggest.completeJSDocs` `typescript.suggest.completeJSDocs`:
|
||||
Enable/disable suggestion to complete JSDoc comments. default: `true`
|
||||
|
||||
### Added on 1.10.1
|
||||
- `typescript.suggest.objectLiteralMethodSnippets.enabled`
|
||||
`javascript.suggest.objectLiteralMethodSnippets.enabled`:
|
||||
Enable/disable snippet completions for methods in object literals. Requires using TypeScript 4.7+ in the workspace
|
||||
|
||||
Configurations are the same as with VSCode. Install
|
||||
[coc-json](https://github.com/neoclide/coc-json) and try completion with
|
||||
`tsserver`, `typescript` or `javascript` in your
|
||||
`coc-settings.json`.
|
||||
|
||||
## Related extensions
|
||||
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
let net = require('net');
|
||||
let fs = require('fs');
|
||||
let ENABLE_LOGGING = false;
|
||||
let log = (function () {
|
||||
if (!ENABLE_LOGGING) {
|
||||
return function () { }; // tslint:disable-line
|
||||
}
|
||||
let isFirst = true;
|
||||
let LOG_LOCATION = 'C:\\stdFork.log';
|
||||
return function log(str) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
fs.writeFileSync(LOG_LOCATION, str + '\n');
|
||||
return;
|
||||
}
|
||||
fs.appendFileSync(LOG_LOCATION, str + '\n');
|
||||
};
|
||||
})();
|
||||
let stdInPipeName = process.env['STDIN_PIPE_NAME']; // tslint:disable-line
|
||||
let stdOutPipeName = process.env['STDOUT_PIPE_NAME']; // tslint:disable-line
|
||||
let stdErrPipeName = process.env['STDERR_PIPE_NAME']; // tslint:disable-line
|
||||
log('STDIN_PIPE_NAME: ' + stdInPipeName);
|
||||
log('STDOUT_PIPE_NAME: ' + stdOutPipeName);
|
||||
log('STDERR_PIPE_NAME: ' + stdErrPipeName);
|
||||
(function () {
|
||||
log('Beginning stdout redirection...');
|
||||
// Create a writing stream to the stdout pipe
|
||||
let stdOutStream = net.connect(stdOutPipeName);
|
||||
// unref stdOutStream to behave like a normal standard out
|
||||
stdOutStream.unref();
|
||||
process.__defineGetter__('stdout', function () {
|
||||
return stdOutStream;
|
||||
});
|
||||
// Create a writing stream to the stderr pipe
|
||||
let stdErrStream = net.connect(stdErrPipeName);
|
||||
// unref stdErrStream to behave like a normal standard out
|
||||
stdErrStream.unref();
|
||||
process.__defineGetter__('stderr', function () {
|
||||
return stdErrStream;
|
||||
});
|
||||
let fsWriteSyncString = function (// tslint:disable-line
|
||||
fd, str, _position, encoding) {
|
||||
// fs.writeSync(fd, string[, position[, encoding]])
|
||||
let buf = Buffer.from(str, encoding || 'utf8');
|
||||
return fsWriteSyncBuffer(fd, buf, 0, buf.length); // tslint:disable-line
|
||||
};
|
||||
let fsWriteSyncBuffer = function (// tslint:disable-line
|
||||
fd, buffer, off, len) {
|
||||
off = Math.abs(off | 0);
|
||||
len = Math.abs(len | 0);
|
||||
// fs.writeSync(fd, buffer, offset, length[, position])
|
||||
let buffer_length = buffer.length;
|
||||
if (off > buffer_length) {
|
||||
throw new Error('offset out of bounds');
|
||||
}
|
||||
if (len > buffer_length) {
|
||||
throw new Error('length out of bounds');
|
||||
}
|
||||
if (((off + len) | 0) < off) {
|
||||
throw new Error('off + len overflow');
|
||||
}
|
||||
if (buffer_length - off < len) {
|
||||
// Asking for more than is left over in the buffer
|
||||
throw new Error('off + len > buffer.length');
|
||||
}
|
||||
let slicedBuffer = buffer;
|
||||
if (off !== 0 || len !== buffer_length) {
|
||||
slicedBuffer = buffer.slice(off, off + len);
|
||||
}
|
||||
if (fd === 1) {
|
||||
stdOutStream.write(slicedBuffer);
|
||||
}
|
||||
else {
|
||||
stdErrStream.write(slicedBuffer);
|
||||
}
|
||||
return slicedBuffer.length;
|
||||
};
|
||||
// handle fs.writeSync(1, ...)
|
||||
let originalWriteSync = fs.writeSync;
|
||||
fs.writeSync = function (// tslint:disable-line
|
||||
fd, data, _position, _encoding) {
|
||||
if (fd !== 1 && fd !== 2) {
|
||||
return originalWriteSync.apply(fs, arguments);
|
||||
}
|
||||
// usage:
|
||||
// fs.writeSync(fd, buffer, offset, length[, position])
|
||||
// OR
|
||||
// fs.writeSync(fd, string[, position[, encoding]])
|
||||
if (data instanceof Buffer) {
|
||||
return fsWriteSyncBuffer.apply(null, arguments);
|
||||
}
|
||||
// For compatibility reasons with fs.writeSync, writing null will write "null", etc
|
||||
if (typeof data !== 'string') {
|
||||
data += '';
|
||||
}
|
||||
return fsWriteSyncString.apply(null, arguments);
|
||||
};
|
||||
log('Finished defining process.stdout, process.stderr and fs.writeSync');
|
||||
})();
|
||||
(function () {
|
||||
// Begin listening to stdin pipe
|
||||
let server = net.createServer(function (stream) {
|
||||
// Stop accepting new connections, keep the existing one alive
|
||||
server.close();
|
||||
log('Parent process has connected to my stdin. All should be good now.');
|
||||
process.__defineGetter__('stdin', function () {
|
||||
return stream;
|
||||
});
|
||||
// Remove myself from process.argv
|
||||
process.argv.splice(1, 1);
|
||||
// Load the actual program
|
||||
let program = process.argv[1];
|
||||
log('Loading program: ' + program);
|
||||
// Unset the custom environmental variables that should not get inherited
|
||||
delete process.env['STDIN_PIPE_NAME']; // tslint:disable-line
|
||||
delete process.env['STDOUT_PIPE_NAME']; // tslint:disable-line
|
||||
delete process.env['STDERR_PIPE_NAME']; // tslint:disable-line
|
||||
require(program);
|
||||
log('Finished loading program.');
|
||||
let stdinIsReferenced = true;
|
||||
let timer = setInterval(function () {
|
||||
let listenerCount = stream.listeners('data').length +
|
||||
stream.listeners('end').length +
|
||||
stream.listeners('close').length +
|
||||
stream.listeners('error').length;
|
||||
// log('listenerCount: ' + listenerCount)
|
||||
if (listenerCount <= 1) {
|
||||
// No more "actual" listeners, only internal node
|
||||
if (stdinIsReferenced) {
|
||||
stdinIsReferenced = false;
|
||||
// log('unreferencing stream!!!')
|
||||
stream.unref();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// There are "actual" listeners
|
||||
if (!stdinIsReferenced) {
|
||||
stdinIsReferenced = true;
|
||||
stream.ref();
|
||||
}
|
||||
}
|
||||
// log(
|
||||
// '' + stream.listeners('data').length +
|
||||
// ' ' + stream.listeners('end').length +
|
||||
// ' ' + stream.listeners('close').length +
|
||||
// ' ' + stream.listeners('error').length
|
||||
// )
|
||||
}, 1000);
|
||||
if (timer.unref) { // tslint:disable-line
|
||||
timer.unref(); // tslint:disable-line
|
||||
}
|
||||
});
|
||||
server.listen(stdInPipeName, function () {
|
||||
// signal via stdout that the parent process can now begin writing to stdin pipe
|
||||
process.stdout.write('ready');
|
||||
});
|
||||
})();
|
260
history.md
Normal file
260
history.md
Normal file
|
@ -0,0 +1,260 @@
|
|||
# 1.10.5
|
||||
|
||||
- Fix a fold issue #380
|
||||
|
||||
# 1.10.2
|
||||
|
||||
- Fix snippet completion not work for optional complete item.
|
||||
|
||||
# 1.10.1
|
||||
|
||||
- Avoid unnecessary fetch of format option.
|
||||
- Add `typescript.suggest.objectLiteralMethodSnippets.enabled`
|
||||
|
||||
# 1.10.0
|
||||
|
||||
- Support jsdoc completion.
|
||||
- Add configurations `javascript.suggest.completeJSDocs` and `typescript.suggest.completeJSDocs`.
|
||||
|
||||
# 1.9.15
|
||||
|
||||
- Fix uri for `zipfile`.
|
||||
|
||||
# 1.9.14
|
||||
|
||||
- Add javascript snippets
|
||||
- Fix command `tsserver.restart` not work
|
||||
|
||||
# 1.9.11
|
||||
|
||||
- Resued resolved tsserver path after `:CocRestart`
|
||||
|
||||
# 1.9.10
|
||||
|
||||
- Watch for `tsserver.enable` configuration to change service state.
|
||||
- Fix tsserver not work well with `:CocList services`
|
||||
|
||||
# 1.9.9
|
||||
|
||||
- Use documentChanges for workspaceEdit.
|
||||
|
||||
# 1.9.8
|
||||
|
||||
- Log to output when document content exceed limit of semantic tokens.
|
||||
|
||||
# 1.9.7
|
||||
|
||||
- Change default of `javascript.autoClosingTags` and `typescript.autoClosingTags` to `true`.
|
||||
|
||||
# 1.9.6
|
||||
|
||||
- Rework codeLens related.
|
||||
|
||||
# 1.9.5
|
||||
|
||||
- Change 'allImportsAreUnused' diagnostic kind to warning.
|
||||
|
||||
# 1.9.4
|
||||
|
||||
- Improve file pattern for config file.
|
||||
|
||||
# 1.9.2
|
||||
|
||||
- Inlay hints support (#335)
|
||||
|
||||
# 1.9.1
|
||||
|
||||
- use `TSS_DEBUG` & `TSS_DEBUG_BRK` for debug port
|
||||
|
||||
# 1.9.0
|
||||
|
||||
- Add semanticTokens support #313
|
||||
- Add jsxAttributeCompletionStyle settings #319
|
||||
- Add command `tsserver.sortImports` #322
|
||||
- Add suggest.classMemberSnippets.enabled configuration cd16da8
|
||||
- Add suggest.jsdoc.generateReturns configuration 5a8c68f
|
||||
- Add typescript.preferences.includePackageJsonAutoImports configuration 4d78b61
|
||||
- Add tsserver.enableTracing configuration 43e6f62
|
||||
- Add typescript.check.npmIsInstalled configuration 3bd84b1
|
||||
|
||||
# 1.8.3
|
||||
|
||||
- Support deprecated tag for document symbols, diagnostic, workspace symbols.
|
||||
|
||||
# 1.8.2
|
||||
|
||||
- Support call hierarchy.
|
||||
- Support `tags` and access modifier for document symbols.
|
||||
- Support return `DefinitionLink[]` for definition provider.
|
||||
|
||||
# 1.8.1
|
||||
|
||||
- Support `tsserver.tsconfigPath` configuration.
|
||||
|
||||
# 1.8.0
|
||||
|
||||
- Support [Import Statement Completions](https://devblogs.microsoft.com/typescript/announcing-typescript-4-3/#import-statement-completions)
|
||||
|
||||
# 1.7.0
|
||||
|
||||
- Support tag closing for JSX
|
||||
|
||||
# 1.6.4
|
||||
|
||||
- Support `typescript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces` and `ypescript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces`
|
||||
|
||||
# 1.6.2
|
||||
|
||||
- Support languages from plugins.
|
||||
|
||||
# 1.5.5
|
||||
|
||||
- Support `typescript.preferences.useAliasesForRenames` and `javascript.preferences.useAliasesForRenames`
|
||||
|
||||
# 1.5.3
|
||||
|
||||
- Support the new path of Yarn v2 pnpify SDK.
|
||||
- Us `tsserver.pluginPaths` replace `tsserver.pluginRoot`.
|
||||
|
||||
# 1.5.0
|
||||
|
||||
- Support @ts-expect-error directive on tsserver v390.
|
||||
- Support `tsserver.watchOptions` configuration.
|
||||
|
||||
# 1.4.13
|
||||
|
||||
- Add `preferences.importModuleSpecifierEnding` configuration.
|
||||
- Change `preferences.importModuleSpecifier` default to `auto`.
|
||||
|
||||
# 1.4.12
|
||||
|
||||
- Support `tsserver.maxTsServerMemory` configuration.
|
||||
|
||||
# 1.4.9
|
||||
|
||||
- Support semicolons format option.
|
||||
|
||||
# 1.4.8
|
||||
|
||||
- support `format.enabled` configuration
|
||||
|
||||
# 1.4.3
|
||||
|
||||
- Use global tsc when local tsc not foun
|
||||
|
||||
# 1.4.0
|
||||
|
||||
- remove noSemicolons preferences
|
||||
|
||||
# 1.3.15
|
||||
|
||||
- Add missing option "auto" to importModuleSpecifier
|
||||
|
||||
# 1.3.11
|
||||
|
||||
- Add `tsserver.ignoreLocalTsserver` configuration.
|
||||
|
||||
# 1.3.6
|
||||
|
||||
- Support `b:coc_tsserver_disable`
|
||||
|
||||
# 1.3.2
|
||||
|
||||
- fix suggestionActions.enabled configuration not working
|
||||
|
||||
# 1.3.1
|
||||
|
||||
- fix validate.enable not work sometimes
|
||||
|
||||
# 1.3.0
|
||||
|
||||
- Loading status.
|
||||
- Batched buffer synchronize.
|
||||
- Configuration for showUnused variable.
|
||||
- Smart selection support.
|
||||
- Support 'auto' as quoteStyle.
|
||||
- Support 'validateDefaultNpmLocation'.
|
||||
|
||||
# 1.1.30
|
||||
|
||||
- rework of typescriptService, support interuptGetErr
|
||||
|
||||
# 1.1.29
|
||||
|
||||
- Support plugin feature.
|
||||
|
||||
# 1.1.28
|
||||
|
||||
- add codeAction provider for import missing node builtin modules.
|
||||
|
||||
# 1.1.26
|
||||
|
||||
- Add install module codeAction for module not found diagnostic.
|
||||
- Rework `tsserver.watchBuild`, use background process, support statusline.
|
||||
|
||||
# 1.1.25
|
||||
|
||||
- Support autofix of node modules import
|
||||
|
||||
# 1.1.23
|
||||
|
||||
- Add command `tsserver.executeAutofix`
|
||||
|
||||
# 1.1.13
|
||||
|
||||
- Add triggerCharacters for SignatureHelp
|
||||
|
||||
# 1.1.12
|
||||
|
||||
- Add typescript snippets from VSCode
|
||||
|
||||
# 1.1.11
|
||||
|
||||
- Fix throw error of "No content available" on completion.
|
||||
|
||||
# 1.1.10
|
||||
|
||||
- Support projectRootPath for document
|
||||
|
||||
# 1.1.9
|
||||
|
||||
- Support commitCharacters of completion items
|
||||
|
||||
# 1.1.8
|
||||
|
||||
- Add status bar support.
|
||||
|
||||
# 1.1.7
|
||||
|
||||
- Add settings `javascript.validate.enable` and `typescript.validate.enable`
|
||||
|
||||
# 1.1.6
|
||||
|
||||
- Fix suggestionActions.enabled not works
|
||||
|
||||
# 1.1.5
|
||||
|
||||
- Use quickfix list for watchBuild errors
|
||||
|
||||
# 1.1.4
|
||||
|
||||
- Fix organizeImports not working sometimes
|
||||
|
||||
# 1.1.3
|
||||
|
||||
- Remove settings with `commaAfterImport`, use `typescript.preferences.noSemicolons` and `javasscript.preferences.noSemicolons` instead.
|
||||
|
||||
# 1.1.2
|
||||
|
||||
- Support diagnostic of config file.
|
||||
|
||||
# 1.1.1
|
||||
|
||||
- Remove unnecessary use of workspace terminal.
|
||||
|
||||
# 1.1.0
|
||||
|
||||
- Support rename import path: https://code.visualstudio.com/updates/v1_28#_rename-import-path
|
||||
- Use new `suggest` for completion configuration: https://code.visualstudio.com/updates/v1_28#_new-settings-for-jsts-suggestions
|
||||
- Convert to async function: https://code.visualstudio.com/updates/v1_28#_convert-to-async-function
|
||||
- Remove semicolons on format: set `typescript.preferences.noSemicolons` to true
|
254
package.json
254
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "coc-tsserver",
|
||||
"version": "1.8.6",
|
||||
"version": "1.10.5",
|
||||
"description": "tsserver extension for coc.nvim",
|
||||
"main": "lib/index.js",
|
||||
"publisher": "chemzqm",
|
||||
|
@ -224,6 +224,12 @@
|
|||
],
|
||||
"description": "Trace level of tsserver"
|
||||
},
|
||||
"tsserver.enableTracing": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enables tracing TS server performance to a directory. These trace files can be used to diagnose TS Server performance issues. The log may contain file paths, source code, and other potentially sensitive information from your project.",
|
||||
"scope": "window"
|
||||
},
|
||||
"tsserver.pluginPaths": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
|
@ -232,10 +238,6 @@
|
|||
},
|
||||
"description": "Folders contains tsserver plugins"
|
||||
},
|
||||
"tsserver.debugPort": {
|
||||
"type": "number",
|
||||
"description": "Debug port number of tsserver"
|
||||
},
|
||||
"tsserver.reportStyleChecksAsWarnings": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
|
@ -260,6 +262,12 @@
|
|||
"default": true,
|
||||
"description": "Use batched buffer sync support."
|
||||
},
|
||||
"typescript.check.npmIsInstalled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"markdownDescription": "Check if npm is installed for [Automatic Type Acquisition](https://code.visualstudio.com/docs/nodejs/working-with-javascript#_typings-and-automatic-type-acquisition).",
|
||||
"scope": "window"
|
||||
},
|
||||
"typescript.showUnused": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
|
@ -285,6 +293,12 @@
|
|||
"default": true,
|
||||
"description": "Enable codeLens for references"
|
||||
},
|
||||
"typescript.referencesCodeLens.showOnAllFunctions": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable references CodeLens on all functions in typescript files.",
|
||||
"scope": "window"
|
||||
},
|
||||
"typescript.preferences.importModuleSpecifier": {
|
||||
"type": "string",
|
||||
"default": "shortest",
|
||||
|
@ -314,6 +328,38 @@
|
|||
"description": "Preferred path ending for auto imports.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.preferences.jsxAttributeCompletionStyle": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auto",
|
||||
"braces",
|
||||
"none"
|
||||
],
|
||||
"markdownEnumDescriptions": [
|
||||
"Insert `={}` or `=\"\"` after attribute names based on the prop type.",
|
||||
"Insert `={}` after attribute names.",
|
||||
"Only insert attribute names."
|
||||
],
|
||||
"default": "auto",
|
||||
"description": "Preferred style for JSX attribute completions.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.preferences.includePackageJsonAutoImports": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auto",
|
||||
"on",
|
||||
"off"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Search dependencies based on estimated performance impact.",
|
||||
"Always search dependencies.",
|
||||
"Never search dependencies."
|
||||
],
|
||||
"default": "auto",
|
||||
"markdownDescription": "Enable/disable searching `package.json` dependencies for available auto imports.",
|
||||
"scope": "window"
|
||||
},
|
||||
"typescript.preferences.quoteStyle": {
|
||||
"type": "string",
|
||||
"default": "auto",
|
||||
|
@ -374,6 +420,18 @@
|
|||
"description": "Enable/disable snippet completions from TS Server. Requires using TypeScript 4.3+ in the workspace.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.suggest.classMemberSnippets.enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable/disable snippet completions for class members. Requires using TypeScript 4.5+ in the workspace",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.suggest.jsdoc.generateReturns": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"markdownDescription": "Enable/disable generating `@return` annotations for JSDoc templates. Requires using TypeScript 4.2+ in the workspace.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.format.enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
|
@ -471,7 +529,8 @@
|
|||
},
|
||||
"typescript.autoClosingTags": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
"default": true,
|
||||
"description": "Enable/disable automatic closing of JSX tags."
|
||||
},
|
||||
"javascript.showUnused": {
|
||||
"type": "boolean",
|
||||
|
@ -495,6 +554,12 @@
|
|||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"javascript.referencesCodeLens.showOnAllFunctions": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable references CodeLens on all functions in JavaScript files.",
|
||||
"scope": "window"
|
||||
},
|
||||
"javascript.preferences.importModuleSpecifier": {
|
||||
"type": "string",
|
||||
"default": "shortest",
|
||||
|
@ -524,6 +589,22 @@
|
|||
"description": "Preferred path ending for auto imports.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.preferences.jsxAttributeCompletionStyle": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auto",
|
||||
"braces",
|
||||
"none"
|
||||
],
|
||||
"markdownEnumDescriptions": [
|
||||
"Insert `={}` or `=\"\"` after attribute names based on the prop type.",
|
||||
"Insert `={}` after attribute names.",
|
||||
"Only insert attribute names."
|
||||
],
|
||||
"default": "auto",
|
||||
"description": "Preferred style for JSX attribute completions.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.preferences.quoteStyle": {
|
||||
"type": "string",
|
||||
"default": "auto",
|
||||
|
@ -578,6 +659,18 @@
|
|||
"description": "Enable/disable auto-import-style completions on partially-typed import statements. Requires using TypeScript 4.3+ in the workspace.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.suggest.classMemberSnippets.enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable/disable snippet completions for class members. Requires using TypeScript 4.5+ in the workspace",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.suggest.jsdoc.generateReturns": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"markdownDescription": "Enable/disable generating `@return` annotations for JSDoc templates. Requires using TypeScript 4.2+ in the workspace.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.format.enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
|
@ -650,12 +743,117 @@
|
|||
"javascript.suggest.includeAutomaticOptionalChainCompletions": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "%configuration.suggest.includeAutomaticOptionalChainCompletions%",
|
||||
"description": "Enable/disable showing completions on potentially undefined values that insert an optional chain call. Requires TS 3.7+ and strict null checks to be enabled.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.parameterNames.enabled": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"literals",
|
||||
"all"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Disable parameter name hints.",
|
||||
"Enable parameter name hints only for literal arguments.",
|
||||
"Enable parameter name hints for literal and non-literal arguments."
|
||||
],
|
||||
"default": "none",
|
||||
"description": "Enable/disable inlay hints of parameter names.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Suppress parameter name hints on arguments whose text is identical to the parameter name.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.parameterTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable inlay hints of parameter types.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.variableTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable inlay hints of variable types.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.propertyDeclarationTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable inlay hints of property declarations.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.functionLikeReturnTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable inlay hints of return type for function signatures.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.inlayHints.enumMemberValues.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable inlay hints of enum member values.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.parameterNames.enabled": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"none",
|
||||
"literals",
|
||||
"all"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Disable parameter name hints.",
|
||||
"Enable parameter name hints only for literal arguments.",
|
||||
"Enable parameter name hints for literal and non-literal arguments."
|
||||
],
|
||||
"default": "none",
|
||||
"description": "Enable/disable inlay hints of parameter names.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Suppress parameter name hints on arguments whose text is identical to the parameter name.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.parameterTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable inlay hints of parameter types.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.variableTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable inlay hints of variable types.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.propertyDeclarationTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable inlay hints of property declarations.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.functionLikeReturnTypes.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable inlay hints of return type for function signatures.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.inlayHints.enumMemberValues.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable/disable inlay hints of enum member values.",
|
||||
"scope": "resource"
|
||||
},
|
||||
"javascript.autoClosingTags": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
"default": true,
|
||||
"description": "Enable/disable automatic closing of JSX tags."
|
||||
},
|
||||
"javascript.format.semicolons": {
|
||||
"type": "string",
|
||||
|
@ -667,6 +865,28 @@
|
|||
"insert",
|
||||
"remove"
|
||||
]
|
||||
},
|
||||
"javascript.suggest.completeJSDocs": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable/disable suggestion to complete JSDoc comments."
|
||||
},
|
||||
"typescript.suggest.completeJSDocs": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable/disable suggestion to complete JSDoc comments."
|
||||
},
|
||||
"javascript.suggest.objectLiteralMethodSnippets.enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable/disable snippet completions for methods in object literals. Requires using TypeScript 4.7+ in the workspace",
|
||||
"scope": "resource"
|
||||
},
|
||||
"typescript.suggest.objectLiteralMethodSnippets.enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable/disable snippet completions for methods in object literals. Requires using TypeScript 4.7+ in the workspace",
|
||||
"scope": "resource"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -678,20 +898,28 @@
|
|||
{
|
||||
"language": "typescriptreact",
|
||||
"path": "./snippets/typescript.json"
|
||||
},
|
||||
{
|
||||
"language": "javascript",
|
||||
"path": "./snippets/javascript.json"
|
||||
},
|
||||
{
|
||||
"language": "javascriptreact",
|
||||
"path": "./snippets/javascript.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"author": "chemzqm@gmail.com",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^10.12.0",
|
||||
"coc.nvim": "^0.0.81-next.6",
|
||||
"esbuild": "^0.8.29",
|
||||
"semver": "^7.3.2",
|
||||
"@types/node": "^12.12.12",
|
||||
"coc.nvim": "^0.0.81-next.25",
|
||||
"esbuild": "^0.14.11",
|
||||
"semver": "^7.3.5",
|
||||
"vscode-languageserver-protocol": "^3.16.0",
|
||||
"which": "^2.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"typescript": "^4.3.5"
|
||||
"typescript": "^4.7.2"
|
||||
}
|
||||
}
|
||||
|
|
194
snippets/javascript.json
Normal file
194
snippets/javascript.json
Normal file
|
@ -0,0 +1,194 @@
|
|||
{
|
||||
"define module": {
|
||||
"prefix": "define",
|
||||
"body": [
|
||||
"define([",
|
||||
"\t'require',",
|
||||
"\t'${1:dependency}'",
|
||||
"], function(require, ${2:factory}) {",
|
||||
"\t'use strict';",
|
||||
"\t$0",
|
||||
"});"
|
||||
],
|
||||
"description": "define module"
|
||||
},
|
||||
"For Loop": {
|
||||
"prefix": "for",
|
||||
"body": [
|
||||
"for (let ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {",
|
||||
"\tconst ${3:element} = ${2:array}[${1:index}];",
|
||||
"\t$TM_SELECTED_TEXT$0",
|
||||
"}"
|
||||
],
|
||||
"description": "For Loop"
|
||||
},
|
||||
"For-Each Loop": {
|
||||
"prefix": "foreach",
|
||||
"body": [
|
||||
"${1:array}.forEach(${2:element} => {",
|
||||
"\t$TM_SELECTED_TEXT$0",
|
||||
"});"
|
||||
],
|
||||
"description": "For-Each Loop"
|
||||
},
|
||||
"For-In Loop": {
|
||||
"prefix": "forin",
|
||||
"body": [
|
||||
"for (const ${1:key} in ${2:object}) {",
|
||||
"\tif (Object.hasOwnProperty.call(${2:object}, ${1:key})) {",
|
||||
"\t\tconst ${3:element} = ${2:object}[${1:key}];",
|
||||
"\t\t$TM_SELECTED_TEXT$0",
|
||||
"\t}",
|
||||
"}"
|
||||
],
|
||||
"description": "For-In Loop"
|
||||
},
|
||||
"For-Of Loop": {
|
||||
"prefix": "forof",
|
||||
"body": [
|
||||
"for (const ${1:iterator} of ${2:object}) {",
|
||||
"\t$TM_SELECTED_TEXT$0",
|
||||
"}"
|
||||
],
|
||||
"description": "For-Of Loop"
|
||||
},
|
||||
"Function Statement": {
|
||||
"prefix": "function",
|
||||
"body": [
|
||||
"function ${1:name}(${2:params}) {",
|
||||
"\t$TM_SELECTED_TEXT$0",
|
||||
"}"
|
||||
],
|
||||
"description": "Function Statement"
|
||||
},
|
||||
"If Statement": {
|
||||
"prefix": "if",
|
||||
"body": [
|
||||
"if (${1:condition}) {",
|
||||
"\t$TM_SELECTED_TEXT$0",
|
||||
"}"
|
||||
],
|
||||
"description": "If Statement"
|
||||
},
|
||||
"If-Else Statement": {
|
||||
"prefix": "ifelse",
|
||||
"body": [
|
||||
"if (${1:condition}) {",
|
||||
"\t$TM_SELECTED_TEXT$0",
|
||||
"} else {",
|
||||
"\t",
|
||||
"}"
|
||||
],
|
||||
"description": "If-Else Statement"
|
||||
},
|
||||
"New Statement": {
|
||||
"prefix": "new",
|
||||
"body": [
|
||||
"const ${1:name} = new ${2:type}(${3:arguments});$0"
|
||||
],
|
||||
"description": "New Statement"
|
||||
},
|
||||
"Switch Statement": {
|
||||
"prefix": "switch",
|
||||
"body": [
|
||||
"switch (${1:key}) {",
|
||||
"\tcase ${2:value}:",
|
||||
"\t\t$0",
|
||||
"\t\tbreak;",
|
||||
"",
|
||||
"\tdefault:",
|
||||
"\t\tbreak;",
|
||||
"}"
|
||||
],
|
||||
"description": "Switch Statement"
|
||||
},
|
||||
"While Statement": {
|
||||
"prefix": "while",
|
||||
"body": [
|
||||
"while (${1:condition}) {",
|
||||
"\t$TM_SELECTED_TEXT$0",
|
||||
"}"
|
||||
],
|
||||
"description": "While Statement"
|
||||
},
|
||||
"Do-While Statement": {
|
||||
"prefix": "dowhile",
|
||||
"body": [
|
||||
"do {",
|
||||
"\t$TM_SELECTED_TEXT$0",
|
||||
"} while (${1:condition});"
|
||||
],
|
||||
"description": "Do-While Statement"
|
||||
},
|
||||
"Try-Catch Statement": {
|
||||
"prefix": "trycatch",
|
||||
"body": [
|
||||
"try {",
|
||||
"\t$TM_SELECTED_TEXT$0",
|
||||
"} catch (${1:error}) {",
|
||||
"\t",
|
||||
"}"
|
||||
],
|
||||
"description": "Try-Catch Statement"
|
||||
},
|
||||
"Set Timeout Function": {
|
||||
"prefix": "settimeout",
|
||||
"body": [
|
||||
"setTimeout(() => {",
|
||||
"\t$TM_SELECTED_TEXT$0",
|
||||
"}, ${1:timeout});"
|
||||
],
|
||||
"description": "Set Timeout Function"
|
||||
},
|
||||
"Set Interval Function": {
|
||||
"prefix": "setinterval",
|
||||
"body": [
|
||||
"setInterval(() => {",
|
||||
"\t$TM_SELECTED_TEXT$0",
|
||||
"}, ${1:interval});"
|
||||
],
|
||||
"description": "Set Interval Function"
|
||||
},
|
||||
"Import external module.": {
|
||||
"prefix": "import statement",
|
||||
"body": [
|
||||
"import { $0 } from \"${1:module}\";"
|
||||
],
|
||||
"description": "Import external module."
|
||||
},
|
||||
"Region Start": {
|
||||
"prefix": "#region",
|
||||
"body": [
|
||||
"//#region $0"
|
||||
],
|
||||
"description": "Folding Region Start"
|
||||
},
|
||||
"Region End": {
|
||||
"prefix": "#endregion",
|
||||
"body": [
|
||||
"//#endregion"
|
||||
],
|
||||
"description": "Folding Region End"
|
||||
},
|
||||
"Log to the console": {
|
||||
"prefix": "log",
|
||||
"body": [
|
||||
"console.log($1);"
|
||||
],
|
||||
"description": "Log to the console"
|
||||
},
|
||||
"Log warning to console": {
|
||||
"prefix": "warn",
|
||||
"body": [
|
||||
"console.warn($1);"
|
||||
],
|
||||
"description": "Log warning to the console"
|
||||
},
|
||||
"Log error to console": {
|
||||
"prefix": "error",
|
||||
"body": [
|
||||
"console.error($1);"
|
||||
],
|
||||
"description": "Log error to the console"
|
||||
}
|
||||
}
|
39
src/index.ts
39
src/index.ts
|
@ -1,7 +1,5 @@
|
|||
import { commands, ExtensionContext, services, workspace } from 'coc.nvim'
|
||||
import { ExtensionContext, services } from 'coc.nvim'
|
||||
import TsserverService from './server'
|
||||
import { AutoFixCommand, Command, ConfigurePluginCommand, FileReferencesCommand, OpenTsServerLogCommand, ReloadProjectsCommand, TypeScriptGoToProjectConfigCommand } from './server/commands'
|
||||
import { OrganizeImportsCommand } from './server/organizeImports'
|
||||
import { PluginManager } from './utils/plugins'
|
||||
|
||||
interface API {
|
||||
|
@ -9,39 +7,10 @@ interface API {
|
|||
}
|
||||
|
||||
export async function activate(context: ExtensionContext): Promise<API> {
|
||||
let { subscriptions, logger } = context
|
||||
const config = workspace.getConfiguration().get<any>('tsserver', {})
|
||||
if (!config.enable) return
|
||||
let { subscriptions } = context
|
||||
const pluginManager = new PluginManager()
|
||||
const service = new TsserverService(pluginManager)
|
||||
function registCommand(cmd: Command): void {
|
||||
let { id, execute } = cmd
|
||||
subscriptions.push(commands.registerCommand(id as string, execute, cmd))
|
||||
}
|
||||
registCommand(new ConfigurePluginCommand(pluginManager))
|
||||
registCommand(new AutoFixCommand(service))
|
||||
registCommand(new ReloadProjectsCommand(service))
|
||||
registCommand(new FileReferencesCommand(service))
|
||||
registCommand(new OpenTsServerLogCommand(service))
|
||||
registCommand(new TypeScriptGoToProjectConfigCommand(service))
|
||||
registCommand(new OrganizeImportsCommand(service))
|
||||
registCommand({
|
||||
id: 'tsserver.restart',
|
||||
execute: (): void => {
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
service.stop().then(() => {
|
||||
setTimeout(() => {
|
||||
service.restart()
|
||||
}, 100)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
service.start().then(() => {
|
||||
subscriptions.push(services.regist(service))
|
||||
}, e => {
|
||||
logger.error(`Error on service start:`, e)
|
||||
})
|
||||
const service = new TsserverService(pluginManager, context.subscriptions)
|
||||
subscriptions.push(services.regist(service))
|
||||
|
||||
return {
|
||||
configurePlugin: (pluginId: string, configuration: {}): void => {
|
||||
|
|
|
@ -46,7 +46,8 @@ export abstract class TypeScriptBaseCodeLensProvider implements CodeLensProvider
|
|||
|
||||
public constructor(
|
||||
protected client: ITypeScriptServiceClient,
|
||||
private cachedResponse: CachedNavTreeResponse
|
||||
private cachedResponse: CachedNavTreeResponse,
|
||||
protected modeId: string
|
||||
) {}
|
||||
|
||||
public get onDidChangeCodeLenses(): Event<void> {
|
||||
|
@ -116,38 +117,31 @@ export abstract class TypeScriptBaseCodeLensProvider implements CodeLensProvider
|
|||
)
|
||||
}
|
||||
}
|
||||
protected getSymbolRange(
|
||||
document: TextDocument,
|
||||
item: Proto.NavigationTree
|
||||
): Range | null {
|
||||
if (!item) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// TS 3.0+ provides a span for just the symbol
|
||||
if ((item as any).nameSpan) {
|
||||
return typeConverters.Range.fromTextSpan((item as any).nameSpan)
|
||||
}
|
||||
export function getSymbolRange(
|
||||
document: TextDocument,
|
||||
item: Proto.NavigationTree
|
||||
): Range | null {
|
||||
if (item.nameSpan) {
|
||||
return typeConverters.Range.fromTextSpan(item.nameSpan)
|
||||
}
|
||||
|
||||
// In older versions, we have to calculate this manually. See #23924
|
||||
const span = item.spans && item.spans[0]
|
||||
if (!span) {
|
||||
return null
|
||||
}
|
||||
// In older versions, we have to calculate this manually. See #23924
|
||||
const span = item.spans && item.spans[0]
|
||||
if (!span) {
|
||||
return null
|
||||
}
|
||||
|
||||
const range = typeConverters.Range.fromTextSpan(span)
|
||||
const text = document.getText(range)
|
||||
const range = typeConverters.Range.fromTextSpan(span)
|
||||
const text = document.getText(range)
|
||||
|
||||
const identifierMatch = new RegExp(
|
||||
`^(.*?(\\b|\\W))${escapeRegExp(item.text || '')}(\\b|\\W)`,
|
||||
'gm'
|
||||
)
|
||||
const match = identifierMatch.exec(text)
|
||||
const prefixLength = match ? match.index + match[1].length : 0
|
||||
const startOffset = document.offsetAt(range.start) + prefixLength
|
||||
return {
|
||||
start: document.positionAt(startOffset),
|
||||
end: document.positionAt(startOffset + item.text.length)
|
||||
}
|
||||
const identifierMatch = new RegExp(`^(.*?(\\b|\\W))${escapeRegExp(item.text || '')}(\\b|\\W)`, 'gm')
|
||||
const match = identifierMatch.exec(text)
|
||||
const prefixLength = match ? match.index + match[1].length : 0
|
||||
const startOffset = document.offsetAt(range.start) + prefixLength
|
||||
return {
|
||||
start: document.positionAt(startOffset),
|
||||
end: document.positionAt(startOffset + item.text.length)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -345,9 +345,7 @@ export default class BufferSyncSupport {
|
|||
}
|
||||
|
||||
public listen(): void {
|
||||
if (this.listening) {
|
||||
return
|
||||
}
|
||||
if (this.listening) return
|
||||
this.listening = true
|
||||
workspace.onDidOpenTextDocument(
|
||||
this.openTextDocument,
|
||||
|
|
|
@ -251,7 +251,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
|||
}
|
||||
const detail = details[0]
|
||||
if (!item.detail && detail.displayParts.length) {
|
||||
item.detail = Previewer.plain(detail.displayParts)
|
||||
item.detail = Previewer.plainWithLinks(detail.displayParts)
|
||||
}
|
||||
item.documentation = this.getDocumentation(detail)
|
||||
const { command, additionalTextEdits } = this.getCodeActions(detail, filepath)
|
||||
|
@ -259,7 +259,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
|||
item.additionalTextEdits = additionalTextEdits
|
||||
if (detail && item.insertTextFormat == InsertTextFormat.Snippet) {
|
||||
const shouldCompleteFunction = await this.isValidFunctionCompletionContext(filepath, position, token)
|
||||
if (shouldCompleteFunction) {
|
||||
if (shouldCompleteFunction && !item.insertText) {
|
||||
this.createSnippetOfFunctionCall(item, detail)
|
||||
}
|
||||
}
|
||||
|
@ -354,12 +354,12 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP
|
|||
private getDocumentation(detail: Proto.CompletionEntryDetails): MarkupContent | undefined {
|
||||
let documentation = ''
|
||||
if (detail.source) {
|
||||
const importPath = `'${Previewer.plain(detail.source)}'`
|
||||
const importPath = `'${Previewer.plainWithLinks(detail.source)}'`
|
||||
const autoImportLabel = `Auto import from ${importPath}`
|
||||
documentation += `${autoImportLabel}\n`
|
||||
}
|
||||
let parts = [
|
||||
Previewer.plain(detail.documentation),
|
||||
Previewer.plainWithLinks(detail.documentation),
|
||||
Previewer.tagsMarkdownPreview(detail.tags)
|
||||
]
|
||||
parts = parts.filter(s => s && s.trim() != '')
|
||||
|
|
|
@ -38,6 +38,7 @@ const getSymbolKind = (kind: string): SymbolKind => {
|
|||
return SymbolKind.Variable
|
||||
case PConst.Kind.constructSignature:
|
||||
case PConst.Kind.constructorImplementation:
|
||||
return SymbolKind.Constructor
|
||||
case PConst.Kind.function:
|
||||
case PConst.Kind.localFunction:
|
||||
return SymbolKind.Function
|
||||
|
|
|
@ -40,6 +40,9 @@ export interface SuggestOptions {
|
|||
readonly importStatementSuggestions: boolean
|
||||
readonly includeCompletionsForImportStatements: boolean
|
||||
readonly includeCompletionsWithSnippetText: boolean
|
||||
readonly includeCompletionsWithClassMemberSnippets: boolean
|
||||
readonly generateReturnInDocTemplate: boolean
|
||||
readonly includeCompletionsWithObjectLiteralMethodSnippets: boolean
|
||||
}
|
||||
|
||||
export default class FileConfigurationManager {
|
||||
|
@ -85,7 +88,13 @@ export default class FileConfigurationManager {
|
|||
}
|
||||
|
||||
public async ensureConfigurationForDocument(document: TextDocument, token: CancellationToken): Promise<void> {
|
||||
let opts = await workspace.getFormatOptions(document.uri)
|
||||
let opts: { insertSpaces: boolean, tabSize: number }
|
||||
let cached = this.cachedMap.get(document.uri)
|
||||
if (cached) {
|
||||
opts = { insertSpaces: cached.formatOptions.convertTabsToSpaces, tabSize: cached.formatOptions.tabSize }
|
||||
} else {
|
||||
opts = await workspace.getFormatOptions(document.uri)
|
||||
}
|
||||
return this.ensureConfigurationOptions(document, opts.insertSpaces, opts.tabSize, token)
|
||||
}
|
||||
|
||||
|
@ -159,9 +168,12 @@ export default class FileConfigurationManager {
|
|||
paths: config.get<boolean>('paths', true),
|
||||
completeFunctionCalls: config.get<boolean>('completeFunctionCalls', true),
|
||||
autoImports: config.get<boolean>('autoImports', true),
|
||||
includeCompletionsWithObjectLiteralMethodSnippets: config.get<boolean>('suggest.objectLiteralMethodSnippets.enabled', true),
|
||||
generateReturnInDocTemplate: config.get<boolean>('jsdoc.generateReturns', true),
|
||||
importStatementSuggestions: config.get<boolean>('importStatements', true),
|
||||
includeCompletionsForImportStatements: config.get<boolean>('includeCompletionsForImportStatements', true),
|
||||
includeCompletionsWithSnippetText: config.get<boolean>('includeCompletionsWithSnippetText', true),
|
||||
includeCompletionsWithClassMemberSnippets: config.get<boolean>('classMemberSnippets.enabled', true),
|
||||
includeAutomaticOptionalChainCompletions: config.get<boolean>('includeAutomaticOptionalChainCompletions', true)
|
||||
}
|
||||
}
|
||||
|
@ -170,17 +182,31 @@ export default class FileConfigurationManager {
|
|||
if (this.client.apiVersion.lt(API.v290)) {
|
||||
return {}
|
||||
}
|
||||
const config = workspace.getConfiguration(`${language}.preferences`, uri)
|
||||
const config = workspace.getConfiguration(language, uri)
|
||||
const preferencesConfig = workspace.getConfiguration(`${language}.preferences`, uri)
|
||||
const suggestConfig = this.getCompleteOptions(language)
|
||||
// getImportModuleSpecifierEndingPreference available on ts 2.9.0
|
||||
const preferences: Proto.UserPreferences & { importModuleSpecifierEnding?: string } = {
|
||||
quotePreference: this.getQuoteStyle(config),
|
||||
importModuleSpecifierPreference: getImportModuleSpecifier(config) as any,
|
||||
importModuleSpecifierEnding: getImportModuleSpecifierEndingPreference(config),
|
||||
const preferences: Proto.UserPreferences = {
|
||||
quotePreference: this.getQuoteStyle(preferencesConfig),
|
||||
importModuleSpecifierPreference: getImportModuleSpecifier(preferencesConfig) as any,
|
||||
importModuleSpecifierEnding: getImportModuleSpecifierEndingPreference(preferencesConfig),
|
||||
jsxAttributeCompletionStyle: getJsxAttributeCompletionStyle(preferencesConfig),
|
||||
allowTextChangesInNewFiles: uri.startsWith('file:'),
|
||||
allowRenameOfImportPath: true,
|
||||
providePrefixAndSuffixTextForRename: config.get<boolean>('renameShorthandProperties', true) === false ? false : config.get<boolean>('useAliasesForRenames', true),
|
||||
includeCompletionsForImportStatements: this.getCompleteOptions(language).includeCompletionsForImportStatements,
|
||||
includeCompletionsWithSnippetText: this.getCompleteOptions(language).includeCompletionsWithSnippetText,
|
||||
// can't support it with coc.nvim by now.
|
||||
provideRefactorNotApplicableReason: false,
|
||||
providePrefixAndSuffixTextForRename: preferencesConfig.get<boolean>('renameShorthandProperties', true) === false ? false : preferencesConfig.get<boolean>('useAliasesForRenames', true),
|
||||
generateReturnInDocTemplate: suggestConfig.generateReturnInDocTemplate,
|
||||
includeCompletionsForImportStatements: suggestConfig.includeCompletionsForImportStatements,
|
||||
includeCompletionsWithClassMemberSnippets: suggestConfig.includeCompletionsWithClassMemberSnippets,
|
||||
includeCompletionsWithSnippetText: suggestConfig.includeCompletionsWithSnippetText,
|
||||
// @ts-expect-error until 4.7
|
||||
includeCompletionsWithObjectLiteralMethodSnippets: suggestConfig.includeCompletionsWithObjectLiteralMethodSnippets,
|
||||
includeAutomaticOptionalChainCompletions: suggestConfig.includeAutomaticOptionalChainCompletions,
|
||||
useLabelDetailsInCompletionEntries: true,
|
||||
allowIncompleteCompletions: true,
|
||||
displayPartsForJSDoc: true,
|
||||
...getInlayHintsPreferences(config),
|
||||
}
|
||||
return preferences
|
||||
}
|
||||
|
@ -220,3 +246,41 @@ function getImportModuleSpecifierEndingPreference(config: WorkspaceConfiguration
|
|||
default: return 'auto'
|
||||
}
|
||||
}
|
||||
|
||||
function getJsxAttributeCompletionStyle(config: WorkspaceConfiguration) {
|
||||
switch (config.get<string>('jsxAttributeCompletionStyle')) {
|
||||
case 'braces': return 'braces'
|
||||
case 'none': return 'none'
|
||||
default: return 'auto'
|
||||
}
|
||||
}
|
||||
|
||||
export class InlayHintSettingNames {
|
||||
static readonly parameterNamesSuppressWhenArgumentMatchesName = 'inlayHints.parameterNames.suppressWhenArgumentMatchesName'
|
||||
static readonly parameterNamesEnabled = 'inlayHints.parameterTypes.enabled'
|
||||
static readonly variableTypesEnabled = 'inlayHints.variableTypes.enabled'
|
||||
static readonly propertyDeclarationTypesEnabled = 'inlayHints.propertyDeclarationTypes.enabled'
|
||||
static readonly functionLikeReturnTypesEnabled = 'inlayHints.functionLikeReturnTypes.enabled'
|
||||
static readonly enumMemberValuesEnabled = 'inlayHints.enumMemberValues.enabled'
|
||||
}
|
||||
|
||||
export function getInlayHintsPreferences(config: WorkspaceConfiguration) {
|
||||
return {
|
||||
includeInlayParameterNameHints: getInlayParameterNameHintsPreference(config),
|
||||
includeInlayParameterNameHintsWhenArgumentMatchesName: !config.get<boolean>(InlayHintSettingNames.parameterNamesSuppressWhenArgumentMatchesName, true),
|
||||
includeInlayFunctionParameterTypeHints: config.get<boolean>(InlayHintSettingNames.parameterNamesEnabled, false),
|
||||
includeInlayVariableTypeHints: config.get<boolean>(InlayHintSettingNames.variableTypesEnabled, false),
|
||||
includeInlayPropertyDeclarationTypeHints: config.get<boolean>(InlayHintSettingNames.propertyDeclarationTypesEnabled, false),
|
||||
includeInlayFunctionLikeReturnTypeHints: config.get<boolean>(InlayHintSettingNames.functionLikeReturnTypesEnabled, false),
|
||||
includeInlayEnumMemberValueHints: config.get<boolean>(InlayHintSettingNames.enumMemberValuesEnabled, false),
|
||||
} as const
|
||||
}
|
||||
|
||||
function getInlayParameterNameHintsPreference(config: WorkspaceConfiguration) {
|
||||
switch (config.get<string>('inlayHints.parameterNames.enabled')) {
|
||||
case 'none': return 'none'
|
||||
case 'literals': return 'literals'
|
||||
case 'all': return 'all'
|
||||
default: return undefined
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,16 +45,22 @@ export default class TypeScriptFoldingProvider implements FoldingRangeProvider {
|
|||
): FoldingRange | undefined {
|
||||
const range = typeConverters.Range.fromTextSpan(span.textSpan)
|
||||
const kind = TypeScriptFoldingProvider.getFoldingRangeKind(span)
|
||||
let { start, end } = range
|
||||
|
||||
// Workaround for #49904
|
||||
if (span.kind === 'comment') {
|
||||
let doc = workspace.getDocument(document.uri)
|
||||
const line = doc.getline(range.start.line)
|
||||
const line = doc.getline(start.line)
|
||||
if (line.match(/\/\/\s*#endregion/gi)) {
|
||||
return undefined
|
||||
}
|
||||
} else if (span.kind === 'code') {
|
||||
let doc = workspace.getDocument(document.uri)
|
||||
if (end.line > start.line && /^\s*}/.test(doc.getline(end.line))) {
|
||||
end.line -= 1
|
||||
end.character = doc.getline(end.line).length
|
||||
}
|
||||
}
|
||||
let { start, end } = range
|
||||
return FoldingRange.create(start.line, end.line, start.character, end.character, kind)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { HoverProvider } from 'coc.nvim'
|
|||
import { CancellationToken, Hover, MarkedString, Position } from 'vscode-languageserver-protocol'
|
||||
import * as Proto from '../protocol'
|
||||
import { ITypeScriptServiceClient } from '../typescriptService'
|
||||
import { tagsMarkdownPreview } from '../utils/previewer'
|
||||
import { markdownDocumentation } from '../utils/previewer'
|
||||
import * as typeConverters from '../utils/typeConverters'
|
||||
|
||||
export default class TypeScriptHoverProvider implements HoverProvider {
|
||||
|
@ -42,14 +42,16 @@ export default class TypeScriptHoverProvider implements HoverProvider {
|
|||
}
|
||||
|
||||
private static getContents(data: Proto.QuickInfoResponseBody): MarkedString[] { // tslint:disable-line
|
||||
const parts = []
|
||||
|
||||
const parts: MarkedString[] = []
|
||||
if (data.displayString) {
|
||||
// const displayParts: string[] = []
|
||||
parts.push({ language: 'typescript', value: data.displayString })
|
||||
}
|
||||
|
||||
const tags = tagsMarkdownPreview(data.tags)
|
||||
parts.push(data.documentation + (tags ? '\n\n' + tags : ''))
|
||||
const markup = markdownDocumentation(data.documentation, data.tags)
|
||||
parts.push({
|
||||
language: 'markdown',
|
||||
value: markup.value
|
||||
})
|
||||
return parts
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import { TextDocument } from 'coc.nvim'
|
|||
import * as Proto from '../protocol'
|
||||
import * as PConst from '../protocol.const'
|
||||
import * as typeConverters from '../utils/typeConverters'
|
||||
import { TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider'
|
||||
import { TypeScriptBaseCodeLensProvider, getSymbolRange } from './baseCodeLensProvider'
|
||||
|
||||
export default class TypeScriptImplementationsCodeLensProvider extends TypeScriptBaseCodeLensProvider {
|
||||
public async resolveCodeLens(
|
||||
|
@ -21,43 +21,39 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip
|
|||
filepath,
|
||||
codeLens.range.start
|
||||
)
|
||||
try {
|
||||
const response = await this.client.execute('implementation', args, token, { lowPriority: true })
|
||||
if (response && response.type == 'response' && response.body) {
|
||||
const locations = response.body
|
||||
.map(reference => {
|
||||
return {
|
||||
uri: this.client.toResource(reference.file),
|
||||
range: {
|
||||
start: typeConverters.Position.fromLocation(reference.start),
|
||||
end: {
|
||||
line: reference.start.line,
|
||||
character: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
// Exclude original from implementations
|
||||
.filter(
|
||||
location => !(
|
||||
location.uri.toString() === uri &&
|
||||
location.range.start.line === codeLens.range.start.line &&
|
||||
location.range.start.character ===
|
||||
codeLens.range.start.character
|
||||
)
|
||||
)
|
||||
|
||||
codeLens.command = this.getCommand(locations, codeLens)
|
||||
return codeLens
|
||||
const response = await this.client.execute('implementation', args, token, { lowPriority: true })
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
codeLens.command = {
|
||||
title: response.type === 'cancelled'
|
||||
? 'cancelled'
|
||||
: 'could not determine implementation',
|
||||
command: ''
|
||||
}
|
||||
} catch {
|
||||
// noop
|
||||
}
|
||||
|
||||
codeLens.command = {
|
||||
title: '0 implementations',
|
||||
command: ''
|
||||
return codeLens
|
||||
}
|
||||
const locations = response.body
|
||||
.map(reference => {
|
||||
return {
|
||||
uri: this.client.toResource(reference.file),
|
||||
range: {
|
||||
start: typeConverters.Position.fromLocation(reference.start),
|
||||
end: {
|
||||
line: reference.start.line,
|
||||
character: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
// Exclude original from implementations
|
||||
.filter(
|
||||
location => !(
|
||||
location.uri.toString() === uri &&
|
||||
location.range.start.line === codeLens.range.start.line &&
|
||||
location.range.start.character ===
|
||||
codeLens.range.start.character
|
||||
)
|
||||
)
|
||||
codeLens.command = this.getCommand(locations, codeLens)
|
||||
return codeLens
|
||||
}
|
||||
|
||||
|
@ -84,7 +80,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip
|
|||
): Range | null {
|
||||
switch (item.kind) {
|
||||
case PConst.Kind.interface:
|
||||
return super.getSymbolRange(document, item)
|
||||
return getSymbolRange(document, item)
|
||||
|
||||
case PConst.Kind.class:
|
||||
case PConst.Kind.method:
|
||||
|
@ -92,7 +88,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip
|
|||
case PConst.Kind.memberGetAccessor:
|
||||
case PConst.Kind.memberSetAccessor:
|
||||
if (item.kindModifiers.match(/\babstract\b/g)) {
|
||||
return super.getSymbolRange(document, item)
|
||||
return getSymbolRange(document, item)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
92
src/server/features/inlayHints.ts
Normal file
92
src/server/features/inlayHints.ts
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken, Disposable, disposeAll, Emitter, Event, InlayHint, InlayHintKind, InlayHintsProvider, Range, TextDocument, workspace } from 'coc.nvim'
|
||||
import type * as Proto from '../protocol'
|
||||
import { ITypeScriptServiceClient } from '../typescriptService'
|
||||
import API from '../utils/api'
|
||||
import { LanguageDescription } from '../utils/languageDescription'
|
||||
import * as typeConverters from '../utils/typeConverters'
|
||||
import FileConfigurationManager, { getInlayHintsPreferences } from './fileConfigurationManager'
|
||||
|
||||
export default class TypeScriptInlayHintsProvider implements InlayHintsProvider {
|
||||
public static readonly minVersion = API.v440
|
||||
private disposables: Disposable[] = []
|
||||
private readonly _onDidChangeInlayHints = new Emitter<void>()
|
||||
public readonly onDidChangeInlayHints: Event<void> = this._onDidChangeInlayHints.event
|
||||
|
||||
constructor(
|
||||
private readonly language: LanguageDescription,
|
||||
private readonly client: ITypeScriptServiceClient,
|
||||
private readonly fileConfigurationManager: FileConfigurationManager,
|
||||
) {
|
||||
let section = `${language.id}.inlayHints`
|
||||
workspace.onDidChangeConfiguration(async e => {
|
||||
if (e.affectsConfiguration(section)) {
|
||||
this._onDidChangeInlayHints.fire()
|
||||
}
|
||||
}, null, this.disposables)
|
||||
// When a JS/TS file changes, change inlay hints for all visible editors
|
||||
// since changes in one file can effect the hints the others.
|
||||
workspace.onDidChangeTextDocument(e => {
|
||||
let doc = workspace.getDocument(e.textDocument.uri)
|
||||
if (language.languageIds.includes(doc.languageId)) {
|
||||
this._onDidChangeInlayHints.fire()
|
||||
}
|
||||
}, null, this.disposables)
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._onDidChangeInlayHints.dispose()
|
||||
disposeAll(this.disposables)
|
||||
}
|
||||
|
||||
async provideInlayHints(document: TextDocument, range: Range, token: CancellationToken): Promise<InlayHint[]> {
|
||||
const filepath = this.client.toOpenedFilePath(document.uri)
|
||||
if (!filepath) return []
|
||||
|
||||
if (!areInlayHintsEnabledForFile(this.language, document)) {
|
||||
return []
|
||||
}
|
||||
const start = document.offsetAt(range.start)
|
||||
const length = document.offsetAt(range.end) - start
|
||||
await this.fileConfigurationManager.ensureConfigurationForDocument(document, token)
|
||||
const response = await this.client.execute('provideInlayHints', { file: filepath, start, length }, token)
|
||||
if (response.type !== 'response' || !response.success || !response.body) {
|
||||
return []
|
||||
}
|
||||
|
||||
return response.body.map(hint => {
|
||||
return {
|
||||
label: hint.text,
|
||||
position: typeConverters.Position.fromLocation(hint.position),
|
||||
kind: fromProtocolInlayHintKind(hint.kind),
|
||||
paddingLeft: hint.whitespaceBefore,
|
||||
paddingRight: hint.whitespaceAfter,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function fromProtocolInlayHintKind(kind: Proto.InlayHintKind): InlayHintKind {
|
||||
switch (kind) {
|
||||
case 'Parameter': return 2
|
||||
case 'Type': return 1
|
||||
case 'Enum': return undefined
|
||||
default: return undefined
|
||||
}
|
||||
}
|
||||
|
||||
function areInlayHintsEnabledForFile(language: LanguageDescription, document: TextDocument) {
|
||||
const config = workspace.getConfiguration(language.id, document.uri)
|
||||
const preferences = getInlayHintsPreferences(config)
|
||||
return preferences.includeInlayParameterNameHints === 'literals' ||
|
||||
preferences.includeInlayParameterNameHints === 'all' ||
|
||||
preferences.includeInlayEnumMemberValueHints ||
|
||||
preferences.includeInlayFunctionLikeReturnTypeHints ||
|
||||
preferences.includeInlayFunctionParameterTypeHints ||
|
||||
preferences.includeInlayPropertyDeclarationTypeHints ||
|
||||
preferences.includeInlayVariableTypeHints
|
||||
}
|
121
src/server/features/jsDocCompletion.ts
Normal file
121
src/server/features/jsDocCompletion.ts
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken, CompletionItem, CompletionItemKind, CompletionItemProvider, InsertTextFormat, Position, Range, SnippetString, TextDocument, workspace } from 'coc.nvim'
|
||||
import { ITypeScriptServiceClient } from '../typescriptService'
|
||||
import { LanguageDescription } from '../utils/languageDescription'
|
||||
import * as typeConverters from '../utils/typeConverters'
|
||||
import FileConfigurationManager from './fileConfigurationManager'
|
||||
|
||||
const defaultJsDoc = new SnippetString(`/**\n * $0\n */`)
|
||||
|
||||
function createCompleteItem(document: TextDocument, position: Position): CompletionItem {
|
||||
const line = document.lineAt(position.line).text
|
||||
const prefix = line.slice(0, position.character).match(/\/\**\s*$/)
|
||||
const suffix = line.slice(position.character).match(/^\s*\**\//)
|
||||
const start = Position.create(position.line, prefix ? position.character - prefix[0].length : position.character)
|
||||
const range = Range.create(start, Position.create(start.line, start.character + (suffix ? suffix[0].length : 0)))
|
||||
let insert = `/** */`
|
||||
return {
|
||||
label: insert,
|
||||
kind: CompletionItemKind.Text,
|
||||
insertTextFormat: InsertTextFormat.Snippet,
|
||||
detail: 'JSDoc comment',
|
||||
sortText: `\0`,
|
||||
textEdit: {
|
||||
newText: insert,
|
||||
range
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class JsDocCompletionProvider implements CompletionItemProvider {
|
||||
constructor(
|
||||
private readonly client: ITypeScriptServiceClient,
|
||||
private readonly language: LanguageDescription,
|
||||
private readonly fileConfigurationManager: FileConfigurationManager,
|
||||
) {}
|
||||
|
||||
public async provideCompletionItems(
|
||||
document: TextDocument,
|
||||
position: Position,
|
||||
token: CancellationToken
|
||||
): Promise<CompletionItem[] | undefined> {
|
||||
if (!workspace.getConfiguration(this.language.id, document.uri).get('suggest.completeJSDocs')) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const file = this.client.toOpenedFilePath(document.uri)
|
||||
if (!file) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (!this.isPotentiallyValidDocCompletionPosition(document, position)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const response = await this.client.interruptGetErr(async () => {
|
||||
await this.fileConfigurationManager.ensureConfigurationForDocument(document, token)
|
||||
const args = typeConverters.Position.toFileLocationRequestArgs(file, position)
|
||||
return this.client.execute('docCommentTemplate', args, token)
|
||||
})
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const item = createCompleteItem(document, position)
|
||||
|
||||
// Workaround for #43619
|
||||
// docCommentTemplate previously returned undefined for empty jsdoc templates.
|
||||
// TS 2.7 now returns a single line doc comment, which breaks indentation.
|
||||
if (response.body.newText === '/** */') {
|
||||
item.textEdit.newText = defaultJsDoc.value
|
||||
} else {
|
||||
item.textEdit.newText = templateToSnippet(response.body.newText).value
|
||||
}
|
||||
|
||||
return [item]
|
||||
}
|
||||
|
||||
private isPotentiallyValidDocCompletionPosition(
|
||||
document: TextDocument,
|
||||
position: Position
|
||||
): boolean {
|
||||
// Only show the JSdoc completion when the everything before the cursor is whitespace
|
||||
// or could be the opening of a comment
|
||||
const line = document.lineAt(position.line).text
|
||||
const prefix = line.slice(0, position.character)
|
||||
if (!/^\s*$|\/\*\s*$|^\s*\/\*+\s*$/.test(prefix)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// And everything after is possibly a closing comment or more whitespace
|
||||
const suffix = line.slice(position.character)
|
||||
return /^\s*(\*+\/)?\s*$/.test(suffix)
|
||||
}
|
||||
}
|
||||
|
||||
export function templateToSnippet(template: string): SnippetString {
|
||||
// TODO: use append placeholder
|
||||
let snippetIndex = 1
|
||||
template = template.replace(/\*\s$/gm, '*')
|
||||
template = template.replace(/\$/g, '\\$')
|
||||
template = template.replace(/^[ \t]*(?=(\/|[ ]\*))/gm, '')
|
||||
template = template.replace(/^(\/\*\*\s*\*[ ]*)$/m, (x) => x + `\$0`)
|
||||
template = template.replace(/\* @param([ ]\{\S+\})?\s+(\S+)[ \t]*$/gm, (_param, type, post) => {
|
||||
let out = '* @param '
|
||||
if (type === ' {any}' || type === ' {*}') {
|
||||
out += `{\$\{${snippetIndex++}:*\}} `
|
||||
} else if (type) {
|
||||
out += type + ' '
|
||||
}
|
||||
out += post + ` \${${snippetIndex++}}`
|
||||
return out
|
||||
})
|
||||
|
||||
template = template.replace(/\* @returns[ \t]*$/gm, `* @returns \${${snippetIndex++}}`)
|
||||
|
||||
return new SnippetString(template)
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import { CodeActionProvider, CodeActionProviderMetadata, commands, TextDocument, window, workspace } from 'coc.nvim'
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { CodeActionProvider, Uri, CodeActionProviderMetadata, commands, TextDocument, window, workspace } from 'coc.nvim'
|
||||
import { CancellationToken, CodeAction, CodeActionContext, CodeActionKind, Range, WorkspaceEdit } from 'vscode-languageserver-protocol'
|
||||
import { Command, registCommand } from '../commands'
|
||||
import Proto from '../protocol'
|
||||
|
@ -55,13 +55,22 @@ class ApplyRefactoringCommand implements Command {
|
|||
}
|
||||
|
||||
private async toWorkspaceEdit(body: Proto.RefactorEditInfo): Promise<WorkspaceEdit> {
|
||||
for (const edit of body.edits) {
|
||||
await workspace.createFile(edit.fileName, { ignoreIfExists: true })
|
||||
}
|
||||
let workspaceEdit = typeConverters.WorkspaceEdit.fromFileCodeEdits(
|
||||
this.client,
|
||||
body.edits
|
||||
)
|
||||
let documentChanges = workspaceEdit.documentChanges = workspaceEdit.documentChanges || []
|
||||
for (const edit of body.edits) {
|
||||
let resource = this.client.toResource(edit.fileName)
|
||||
if (Uri.parse(resource).scheme === 'file') {
|
||||
// should create file first.
|
||||
documentChanges.unshift({
|
||||
kind: 'create',
|
||||
uri: resource,
|
||||
options: { ignoreIfExists: true }
|
||||
})
|
||||
}
|
||||
}
|
||||
return workspaceEdit
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { CancellationToken, CodeLens, Range } from 'vscode-languageserver-protocol'
|
||||
import { TextDocument } from 'coc.nvim'
|
||||
import { CancellationToken, Position, Range } from 'vscode-languageserver-protocol'
|
||||
import { TextDocument, workspace, CodeLens } from 'coc.nvim'
|
||||
import { ExecutionTarget } from '../typescriptService'
|
||||
import * as Proto from '../protocol'
|
||||
import * as PConst from '../protocol.const'
|
||||
import * as typeConverters from '../utils/typeConverters'
|
||||
import { TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider'
|
||||
import { TypeScriptBaseCodeLensProvider, getSymbolRange } from './baseCodeLensProvider'
|
||||
|
||||
export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLensProvider {
|
||||
public resolveCodeLens(
|
||||
public async resolveCodeLens(
|
||||
codeLens: CodeLens,
|
||||
token: CancellationToken
|
||||
): Promise<CodeLens> {
|
||||
|
@ -20,47 +21,35 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase
|
|||
filepath,
|
||||
codeLens.range.start
|
||||
)
|
||||
return this.client
|
||||
.execute('references', args, token, {
|
||||
lowPriority: true
|
||||
})
|
||||
.then(response => {
|
||||
if (!response || response.type != 'response' || !response.body) {
|
||||
throw codeLens
|
||||
}
|
||||
let response = await this.client.execute('references', args, token, {
|
||||
lowPriority: true,
|
||||
executionTarget: ExecutionTarget.Semantic
|
||||
})
|
||||
if (!response || response.type != 'response' || !response.body) {
|
||||
codeLens.command = {
|
||||
title: response.type === 'cancelled'
|
||||
? 'cancelled'
|
||||
: 'could not determine references',
|
||||
command: ''
|
||||
}
|
||||
return codeLens
|
||||
}
|
||||
|
||||
const locations = response.body.refs
|
||||
.map(reference =>
|
||||
typeConverters.Location.fromTextSpan(
|
||||
this.client.toResource(reference.file),
|
||||
reference
|
||||
)
|
||||
)
|
||||
.filter(
|
||||
location =>
|
||||
// Exclude original definition from references
|
||||
!(
|
||||
location.uri.toString() === uri &&
|
||||
location.range.start.line === codeLens.range.start.line &&
|
||||
location.range.start.character ===
|
||||
codeLens.range.start.character
|
||||
)
|
||||
)
|
||||
const locations = response.body.refs
|
||||
.filter(reference => !reference.isDefinition)
|
||||
.map(reference =>
|
||||
typeConverters.Location.fromTextSpan(
|
||||
this.client.toResource(reference.file),
|
||||
reference
|
||||
)
|
||||
)
|
||||
|
||||
codeLens.command = {
|
||||
title: locations.length === 1 ? '1 reference' : `${locations.length} references`,
|
||||
command: locations.length ? 'editor.action.showReferences' : '',
|
||||
arguments: [uri, codeLens.range.start, locations]
|
||||
}
|
||||
return codeLens
|
||||
})
|
||||
.catch(() => {
|
||||
codeLens.command = {
|
||||
title: '0 references',
|
||||
command: ''
|
||||
}
|
||||
return codeLens
|
||||
})
|
||||
codeLens.command = {
|
||||
title: locations.length === 1 ? '1 reference' : `${locations.length} references`,
|
||||
command: locations.length ? 'editor.action.showReferences' : '',
|
||||
arguments: [uri, codeLens.range.start, locations]
|
||||
}
|
||||
return codeLens
|
||||
}
|
||||
|
||||
protected extractSymbol(
|
||||
|
@ -69,37 +58,68 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase
|
|||
parent: Proto.NavigationTree | null
|
||||
): Range | null {
|
||||
if (parent && parent.kind === PConst.Kind.enum) {
|
||||
return super.getSymbolRange(document, item)
|
||||
return getSymbolRange(document, item)
|
||||
}
|
||||
|
||||
switch (item.kind) {
|
||||
case PConst.Kind.function: {
|
||||
const showOnAllFunctions = workspace.getConfiguration(this.modeId).get<boolean>('referencesCodeLens.showOnAllFunctions')
|
||||
if (showOnAllFunctions) {
|
||||
return getSymbolRange(document, item)
|
||||
}
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case PConst.Kind.const:
|
||||
case PConst.Kind.let:
|
||||
case PConst.Kind.variable:
|
||||
case PConst.Kind.function:
|
||||
// Only show references for exported variables
|
||||
if (!item.kindModifiers.match(/\bexport\b/)) {
|
||||
break
|
||||
if (/\bexport\b/.test(item.kindModifiers)) {
|
||||
return getSymbolRange(document, item)
|
||||
}
|
||||
// fallthrough
|
||||
break
|
||||
|
||||
case PConst.Kind.class:
|
||||
if (item.text === '<class>') {
|
||||
break
|
||||
}
|
||||
// fallthrough
|
||||
return getSymbolRange(document, item)
|
||||
|
||||
case PConst.Kind.method:
|
||||
case PConst.Kind.memberVariable:
|
||||
case PConst.Kind.memberGetAccessor:
|
||||
case PConst.Kind.memberSetAccessor:
|
||||
case PConst.Kind.constructorImplementation:
|
||||
case PConst.Kind.interface:
|
||||
case PConst.Kind.type:
|
||||
case PConst.Kind.enum:
|
||||
return super.getSymbolRange(document, item)
|
||||
return getSymbolRange(document, item)
|
||||
|
||||
case PConst.Kind.method:
|
||||
case PConst.Kind.memberGetAccessor:
|
||||
case PConst.Kind.memberSetAccessor:
|
||||
case PConst.Kind.constructorImplementation:
|
||||
case PConst.Kind.memberVariable:
|
||||
// Don't show if child and parent have same start
|
||||
// For https://github.com/microsoft/vscode/issues/90396
|
||||
if (parent &&
|
||||
comparePosition(typeConverters.Position.fromLocation(parent.spans[0].start), typeConverters.Position.fromLocation(item.spans[0].start)) == 0
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Only show if parent is a class type object (not a literal)
|
||||
switch (parent?.kind) {
|
||||
case PConst.Kind.class:
|
||||
case PConst.Kind.interface:
|
||||
case PConst.Kind.type:
|
||||
return getSymbolRange(document, item)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function comparePosition(position: Position, other: Position): number {
|
||||
if (position.line > other.line) return 1
|
||||
if (other.line == position.line && position.character > other.character) return 1
|
||||
if (other.line == position.line && position.character == other.character) return 0
|
||||
return -1
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ export default class TypeScriptRenameProvider implements RenameProvider {
|
|||
public constructor(
|
||||
private readonly client: ITypeScriptServiceClient,
|
||||
private readonly fileConfigurationManager: FileConfigurationManager
|
||||
) { }
|
||||
) {}
|
||||
|
||||
public async prepareRename(
|
||||
document: TextDocument,
|
||||
|
@ -60,8 +60,8 @@ export default class TypeScriptRenameProvider implements RenameProvider {
|
|||
}
|
||||
|
||||
if (this.client.apiVersion.gte(API.v310)) {
|
||||
if ((renameInfo as any).fileToRename) {
|
||||
const edits = await this.renameFile((renameInfo as any).fileToRename, newName, token)
|
||||
if (renameInfo.fileToRename) {
|
||||
const edits = await this.renameFile(renameInfo.fileToRename, newName, token)
|
||||
if (edits) {
|
||||
return edits
|
||||
} else {
|
||||
|
|
294
src/server/features/semanticTokens.ts
Normal file
294
src/server/features/semanticTokens.ts
Normal file
|
@ -0,0 +1,294 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, Range, SemanticTokens, SemanticTokensBuilder, TextDocument, workspace } from 'coc.nvim'
|
||||
import { SemanticTokensLegend } from 'vscode-languageserver-protocol'
|
||||
import * as Proto from '../protocol'
|
||||
import { ExecConfig, ITypeScriptServiceClient, ServerResponse } from '../typescriptService'
|
||||
import API from '../utils/api'
|
||||
|
||||
// as we don't do deltas, for performance reasons, don't compute semantic tokens for documents above that limit
|
||||
const CONTENT_LENGTH_LIMIT = 100000
|
||||
|
||||
/**
|
||||
* Prototype of a DocumentSemanticTokensProvider, relying on the experimental `encodedSemanticClassifications-full` request from the TypeScript server.
|
||||
* As the results retured by the TypeScript server are limited, we also add a Typescript plugin (typescript-vscode-sh-plugin) to enrich the returned token.
|
||||
* See https://github.com/aeschli/typescript-vscode-sh-plugin.
|
||||
*/
|
||||
export default class TypeScriptDocumentSemanticTokensProvider implements DocumentSemanticTokensProvider, DocumentRangeSemanticTokensProvider {
|
||||
public static readonly minVersion = API.v370
|
||||
|
||||
constructor(private readonly client: ITypeScriptServiceClient) {}
|
||||
|
||||
getLegend(): SemanticTokensLegend {
|
||||
return {
|
||||
tokenTypes,
|
||||
tokenModifiers
|
||||
}
|
||||
}
|
||||
|
||||
private logIgnored(uri: string): void {
|
||||
this.client.logger.warn(`${uri} content length exceed limit 100000`)
|
||||
}
|
||||
|
||||
async provideDocumentSemanticTokens(document: TextDocument, token: CancellationToken): Promise<SemanticTokens | null> {
|
||||
const file = this.client.toOpenedFilePath(document.uri)
|
||||
if (!file || document.getText().length > CONTENT_LENGTH_LIMIT) {
|
||||
this.logIgnored(document.uri)
|
||||
return null
|
||||
}
|
||||
return this._provideSemanticTokens(document, { file, start: 0, length: document.getText().length }, token)
|
||||
}
|
||||
|
||||
async provideDocumentRangeSemanticTokens(document: TextDocument, range: Range, token: CancellationToken): Promise<SemanticTokens | null> {
|
||||
const file = this.client.toOpenedFilePath(document.uri)
|
||||
if (!file || (document.offsetAt(range.end) - document.offsetAt(range.start) > CONTENT_LENGTH_LIMIT)) {
|
||||
this.logIgnored(document.uri)
|
||||
return null
|
||||
}
|
||||
|
||||
const start = document.offsetAt(range.start)
|
||||
const length = document.offsetAt(range.end) - start
|
||||
return this._provideSemanticTokens(document, { file, start, length }, token)
|
||||
}
|
||||
|
||||
async _provideSemanticTokens(document: TextDocument, requestArg: Proto.EncodedSemanticClassificationsRequestArgs, token: CancellationToken): Promise<SemanticTokens | null> {
|
||||
const file = this.client.toOpenedFilePath(document.uri)
|
||||
if (!file) {
|
||||
return null
|
||||
}
|
||||
|
||||
const versionBeforeRequest = document.version
|
||||
|
||||
requestArg.format = '2020'
|
||||
|
||||
const response = await (this.client as ExperimentalProtocol.IExtendedTypeScriptServiceClient).execute('encodedSemanticClassifications-full', requestArg, token, {
|
||||
cancelOnResourceChange: document.uri
|
||||
})
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
return null
|
||||
}
|
||||
|
||||
const versionAfterRequest = document.version
|
||||
if (versionBeforeRequest !== versionAfterRequest) {
|
||||
// cannot convert result's offsets to (linecol) values correctly
|
||||
// a new request will come in soon...
|
||||
//
|
||||
// here we cannot return null, because returning null would remove all semantic tokens.
|
||||
// we must throw to indicate that the semantic tokens should not be removed.
|
||||
// using the string busy here because it is not logged to error telemetry if the error text contains busy.
|
||||
|
||||
// as the new request will come in right after our response, we first wait for the document activity to stop
|
||||
await waitForDocumentChangesToEnd(document)
|
||||
|
||||
throw new Error('Canceled')
|
||||
}
|
||||
|
||||
const doc = workspace.getDocument(document.uri)
|
||||
const tokenSpan = response.body.spans
|
||||
|
||||
const builder = new SemanticTokensBuilder()
|
||||
let i = 0
|
||||
while (i < tokenSpan.length) {
|
||||
const offset = tokenSpan[i++]
|
||||
const length = tokenSpan[i++]
|
||||
const tsClassification = tokenSpan[i++]
|
||||
|
||||
let tokenModifiers = 0
|
||||
let tokenType = getTokenTypeFromClassification(tsClassification)
|
||||
if (tokenType !== undefined) {
|
||||
// it's a classification as returned by the typescript-vscode-sh-plugin
|
||||
tokenModifiers = getTokenModifierFromClassification(tsClassification)
|
||||
} else {
|
||||
// typescript-vscode-sh-plugin is not present
|
||||
tokenType = tokenTypeMap[tsClassification]
|
||||
if (tokenType === undefined) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// we can use the document's range conversion methods because the result is at the same version as the document
|
||||
const startPos = document.positionAt(offset)
|
||||
const endPos = document.positionAt(offset + length)
|
||||
for (let line = startPos.line; line <= endPos.line; line++) {
|
||||
const startCharacter = (line === startPos.line ? startPos.character : 0)
|
||||
const endCharacter = (line === endPos.line ? endPos.character : doc.getline(line).length)
|
||||
builder.push(line, startCharacter, endCharacter - startCharacter, tokenType, tokenModifiers)
|
||||
}
|
||||
}
|
||||
return builder.build()
|
||||
}
|
||||
}
|
||||
|
||||
function waitForDocumentChangesToEnd(document: TextDocument) {
|
||||
let version = document.version
|
||||
return new Promise<void>((s) => {
|
||||
const iv = setInterval(_ => {
|
||||
if (document.version === version) {
|
||||
clearInterval(iv)
|
||||
s()
|
||||
}
|
||||
version = document.version
|
||||
}, 400)
|
||||
})
|
||||
}
|
||||
|
||||
function getTokenTypeFromClassification(tsClassification: number): number | undefined {
|
||||
if (tsClassification > TokenEncodingConsts.modifierMask) {
|
||||
return (tsClassification >> TokenEncodingConsts.typeOffset) - 1
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
function getTokenModifierFromClassification(tsClassification: number) {
|
||||
return tsClassification & TokenEncodingConsts.modifierMask
|
||||
}
|
||||
|
||||
// typescript encodes type and modifiers in the classification:
|
||||
// TSClassification = (TokenType + 1) << 8 + TokenModifier
|
||||
|
||||
const enum TokenType {
|
||||
class = 0,
|
||||
enum = 1,
|
||||
interface = 2,
|
||||
namespace = 3,
|
||||
typeParameter = 4,
|
||||
type = 5,
|
||||
parameter = 6,
|
||||
variable = 7,
|
||||
enumMember = 8,
|
||||
property = 9,
|
||||
function = 10,
|
||||
method = 11,
|
||||
_ = 12
|
||||
}
|
||||
const enum TokenModifier {
|
||||
declaration = 0,
|
||||
static = 1,
|
||||
async = 2,
|
||||
readonly = 3,
|
||||
defaultLibrary = 4,
|
||||
local = 5,
|
||||
_ = 6
|
||||
}
|
||||
const enum TokenEncodingConsts {
|
||||
typeOffset = 8,
|
||||
modifierMask = 255
|
||||
}
|
||||
|
||||
const tokenTypes: string[] = []
|
||||
tokenTypes[TokenType.class] = 'class'
|
||||
tokenTypes[TokenType.enum] = 'enum'
|
||||
tokenTypes[TokenType.interface] = 'interface'
|
||||
tokenTypes[TokenType.namespace] = 'namespace'
|
||||
tokenTypes[TokenType.typeParameter] = 'typeParameter'
|
||||
tokenTypes[TokenType.type] = 'type'
|
||||
tokenTypes[TokenType.parameter] = 'parameter'
|
||||
tokenTypes[TokenType.variable] = 'variable'
|
||||
tokenTypes[TokenType.enumMember] = 'enumMember'
|
||||
tokenTypes[TokenType.property] = 'property'
|
||||
tokenTypes[TokenType.function] = 'function'
|
||||
tokenTypes[TokenType.method] = 'method'
|
||||
|
||||
const tokenModifiers: string[] = []
|
||||
tokenModifiers[TokenModifier.async] = 'async'
|
||||
tokenModifiers[TokenModifier.declaration] = 'declaration'
|
||||
tokenModifiers[TokenModifier.readonly] = 'readonly'
|
||||
tokenModifiers[TokenModifier.static] = 'static'
|
||||
tokenModifiers[TokenModifier.local] = 'local'
|
||||
tokenModifiers[TokenModifier.defaultLibrary] = 'defaultLibrary'
|
||||
|
||||
export namespace ExperimentalProtocol {
|
||||
|
||||
export interface IExtendedTypeScriptServiceClient {
|
||||
execute<K extends keyof ExperimentalProtocol.ExtendedTsServerRequests>(
|
||||
command: K,
|
||||
args: ExperimentalProtocol.ExtendedTsServerRequests[K][0],
|
||||
token: CancellationToken,
|
||||
config?: ExecConfig
|
||||
): Promise<ServerResponse.Response<ExperimentalProtocol.ExtendedTsServerRequests[K][1]>>
|
||||
}
|
||||
|
||||
/**
|
||||
* A request to get encoded semantic classifications for a span in the file
|
||||
*/
|
||||
export interface EncodedSemanticClassificationsRequest extends Proto.FileRequest {
|
||||
arguments: EncodedSemanticClassificationsRequestArgs
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments for EncodedSemanticClassificationsRequest request.
|
||||
*/
|
||||
export interface EncodedSemanticClassificationsRequestArgs extends Proto.FileRequestArgs {
|
||||
/**
|
||||
* Start position of the span.
|
||||
*/
|
||||
start: number
|
||||
/**
|
||||
* Length of the span.
|
||||
*/
|
||||
length: number
|
||||
}
|
||||
|
||||
export const enum EndOfLineState {
|
||||
None,
|
||||
InMultiLineCommentTrivia,
|
||||
InSingleQuoteStringLiteral,
|
||||
InDoubleQuoteStringLiteral,
|
||||
InTemplateHeadOrNoSubstitutionTemplate,
|
||||
InTemplateMiddleOrTail,
|
||||
InTemplateSubstitutionPosition,
|
||||
}
|
||||
|
||||
export const enum ClassificationType {
|
||||
comment = 1,
|
||||
identifier = 2,
|
||||
keyword = 3,
|
||||
numericLiteral = 4,
|
||||
operator = 5,
|
||||
stringLiteral = 6,
|
||||
regularExpressionLiteral = 7,
|
||||
whiteSpace = 8,
|
||||
text = 9,
|
||||
punctuation = 10,
|
||||
className = 11,
|
||||
enumName = 12,
|
||||
interfaceName = 13,
|
||||
moduleName = 14,
|
||||
typeParameterName = 15,
|
||||
typeAliasName = 16,
|
||||
parameterName = 17,
|
||||
docCommentTagName = 18,
|
||||
jsxOpenTagName = 19,
|
||||
jsxCloseTagName = 20,
|
||||
jsxSelfClosingTagName = 21,
|
||||
jsxAttribute = 22,
|
||||
jsxText = 23,
|
||||
jsxAttributeStringLiteralValue = 24,
|
||||
bigintLiteral = 25,
|
||||
}
|
||||
|
||||
export interface EncodedSemanticClassificationsResponse extends Proto.Response {
|
||||
body?: {
|
||||
endOfLineState: EndOfLineState
|
||||
spans: number[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface ExtendedTsServerRequests {
|
||||
'encodedSemanticClassifications-full': [ExperimentalProtocol.EncodedSemanticClassificationsRequestArgs, ExperimentalProtocol.EncodedSemanticClassificationsResponse]
|
||||
}
|
||||
}
|
||||
|
||||
// mapping for the original ExperimentalProtocol.ClassificationType from TypeScript (only used when plugin is not available)
|
||||
const tokenTypeMap: number[] = []
|
||||
tokenTypeMap[ExperimentalProtocol.ClassificationType.className] = TokenType.class
|
||||
tokenTypeMap[ExperimentalProtocol.ClassificationType.enumName] = TokenType.enum
|
||||
tokenTypeMap[ExperimentalProtocol.ClassificationType.interfaceName] = TokenType.interface
|
||||
tokenTypeMap[ExperimentalProtocol.ClassificationType.moduleName] = TokenType.namespace
|
||||
tokenTypeMap[ExperimentalProtocol.ClassificationType.typeParameterName] = TokenType.typeParameter
|
||||
tokenTypeMap[ExperimentalProtocol.ClassificationType.typeAliasName] = TokenType.type
|
||||
tokenTypeMap[ExperimentalProtocol.ClassificationType.parameterName] = TokenType.parameter
|
||||
|
|
@ -60,13 +60,13 @@ export default class TypeScriptSignatureHelpProvider implements SignatureHelpPro
|
|||
private convertSignature(item: Proto.SignatureHelpItem): SignatureInformation {
|
||||
let parameters = item.parameters.map(p => {
|
||||
return {
|
||||
label: Previewer.plain(p.displayParts),
|
||||
label: Previewer.plainWithLinks(p.displayParts),
|
||||
documentation: Previewer.markdownDocumentation(p.documentation, [])
|
||||
}
|
||||
})
|
||||
let label = Previewer.plain(item.prefixDisplayParts)
|
||||
label += parameters.map(parameter => parameter.label).join(Previewer.plain(item.separatorDisplayParts))
|
||||
label += Previewer.plain(item.suffixDisplayParts)
|
||||
let label = Previewer.plainWithLinks(item.prefixDisplayParts)
|
||||
label += parameters.map(parameter => parameter.label).join(Previewer.plainWithLinks(item.separatorDisplayParts))
|
||||
label += Previewer.plainWithLinks(item.suffixDisplayParts)
|
||||
return {
|
||||
label,
|
||||
documentation: Previewer.markdownDocumentation(
|
||||
|
|
|
@ -5,13 +5,10 @@
|
|||
import { CancellationTokenSource, Disposable, disposeAll, Position, Range, snippetManager, events, workspace, InsertChange } from 'coc.nvim'
|
||||
import * as Proto from '../protocol'
|
||||
import { ITypeScriptServiceClient } from '../typescriptService'
|
||||
import API from '../utils/api'
|
||||
import SnippetString from '../utils/SnippetString'
|
||||
import * as typeConverters from '../utils/typeConverters'
|
||||
|
||||
export default class TagClosing implements Disposable {
|
||||
public static readonly minVersion = API.v300
|
||||
|
||||
private static _configurationLanguages: Record<string, string> = {
|
||||
'javascriptreact': 'javascript',
|
||||
'typescriptreact': 'typescript',
|
||||
|
@ -21,27 +18,21 @@ export default class TagClosing implements Disposable {
|
|||
private _disposed = false
|
||||
private _timeout: NodeJS.Timer | undefined = undefined
|
||||
private _cancel: CancellationTokenSource | undefined = undefined
|
||||
private lastInsert: string
|
||||
|
||||
constructor(
|
||||
private readonly client: ITypeScriptServiceClient,
|
||||
private readonly descriptionLanguageId: string
|
||||
) {
|
||||
events.on('InsertCharPre', character => {
|
||||
this.lastInsert = character
|
||||
}, null, this._disposables)
|
||||
events.on('TextChangedI', this.onChange, this, this._disposables)
|
||||
events.on('TextChangedP', this.onChange, this, this._disposables)
|
||||
events.on('TextInsert', this.onInsertChange, this, this._disposables)
|
||||
}
|
||||
|
||||
private async onChange(bufnr: number, change: InsertChange): Promise<void> {
|
||||
private async onInsertChange(bufnr: number, change: InsertChange, lastInsert: string): Promise<void> {
|
||||
let doc = workspace.getDocument((bufnr))
|
||||
if (!doc || !doc.attached) return
|
||||
let enabled = this.isEnabled(doc.filetype, doc.uri)
|
||||
if (!enabled) return
|
||||
let { pre, changedtick, lnum } = change
|
||||
if (!pre.endsWith('/') && !pre.endsWith('>')) return
|
||||
if (!pre.endsWith(this.lastInsert)) return
|
||||
if (lastInsert !== '/' && lastInsert != '>') return
|
||||
if (pre.length > 1 && pre[pre.length - 2] == '>') return
|
||||
const filepath = this.client.toOpenedFilePath(doc.uri)
|
||||
if (!filepath) return
|
||||
|
@ -73,7 +64,6 @@ export default class TagClosing implements Disposable {
|
|||
return
|
||||
}
|
||||
if (this._disposed) return
|
||||
|
||||
const insertion = response.body
|
||||
if (doc.changedtick === changedtick) {
|
||||
snippetManager.insertSnippet(
|
||||
|
@ -82,7 +72,7 @@ export default class TagClosing implements Disposable {
|
|||
Range.create(position, position)
|
||||
)
|
||||
}
|
||||
}, 50)
|
||||
}, 30)
|
||||
}
|
||||
|
||||
private isEnabled(languageId: string, uri: string): boolean {
|
||||
|
|
|
@ -1,24 +1,10 @@
|
|||
import { commands, disposeAll, StatusBarItem, TaskOptions, Uri, window, workspace } from 'coc.nvim'
|
||||
import { commands, Disposable, disposeAll, StatusBarItem, TaskOptions, Uri, window, workspace } from 'coc.nvim'
|
||||
import path from 'path'
|
||||
import { Disposable, Location } from 'vscode-languageserver-protocol'
|
||||
import TypeScriptServiceClient from '../typescriptServiceClient'
|
||||
|
||||
const countRegex = /Found\s+(\d+)\s+error/
|
||||
const errorRegex = /^(.+)\((\d+),(\d+)\):\s(\w+)\sTS(\d+):\s*(.+)$/
|
||||
|
||||
interface ErrorItem {
|
||||
location: Location
|
||||
text: string
|
||||
type: string
|
||||
}
|
||||
|
||||
enum TscStatus {
|
||||
INIT,
|
||||
COMPILING,
|
||||
RUNNING,
|
||||
ERROR,
|
||||
}
|
||||
|
||||
export default class WatchProject implements Disposable {
|
||||
private disposables: Disposable[] = []
|
||||
public static readonly id: string = 'tsserver.watchBuild'
|
||||
|
@ -119,7 +105,7 @@ export default class WatchProject implements Disposable {
|
|||
return
|
||||
}
|
||||
|
||||
const tsconfigPath = workspace.getConfiguration('tsserver').get<string>('tsconfigPath', 'tsconfig.json');
|
||||
const tsconfigPath = workspace.getConfiguration('tsserver').get<string>('tsconfigPath', 'tsconfig.json')
|
||||
let find = await workspace.findUp([tsconfigPath])
|
||||
if (!find) {
|
||||
window.showMessage(`${tsconfigPath} not found!`, 'error')
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { disposeAll, IServiceProvider, ServiceStat, workspace, WorkspaceConfiguration } from 'coc.nvim'
|
||||
import { commands, disposeAll, IServiceProvider, ServiceStat, workspace, WorkspaceConfiguration } from 'coc.nvim'
|
||||
import { Disposable, DocumentSelector, Emitter, Event } from 'vscode-languageserver-protocol'
|
||||
import { PluginManager } from '../utils/plugins'
|
||||
import { AutoFixCommand, Command, ConfigurePluginCommand, FileReferencesCommand, OpenTsServerLogCommand, ReloadProjectsCommand, TypeScriptGoToProjectConfigCommand } from './commands'
|
||||
import { OrganizeImportsCommand, SourceImportsCommand } from './organizeImports'
|
||||
import TypeScriptServiceClientHost from './typescriptServiceClientHost'
|
||||
import { LanguageDescription, standardLanguageDescriptions } from './utils/languageDescription'
|
||||
|
||||
|
@ -10,23 +12,69 @@ export default class TsserverService implements IServiceProvider {
|
|||
public enable: boolean
|
||||
// supported language types
|
||||
public selector: DocumentSelector
|
||||
public state = ServiceStat.Initial
|
||||
public _state = ServiceStat.Initial
|
||||
public clientHost: TypeScriptServiceClientHost
|
||||
private _onDidServiceReady = new Emitter<void>()
|
||||
public readonly onServiceReady: Event<void> = this._onDidServiceReady.event
|
||||
private readonly disposables: Disposable[] = []
|
||||
private descriptions: LanguageDescription[] = []
|
||||
|
||||
constructor(private pluginManager: PluginManager) {
|
||||
constructor(private pluginManager: PluginManager, private readonly subscriptions: Disposable[]) {
|
||||
const config = workspace.getConfiguration('tsserver')
|
||||
const enableJavascript = !!config.get<boolean>('enableJavascript')
|
||||
const enableJavascript = config.get<boolean>('enableJavascript', true)
|
||||
this.enable = config.get<boolean>('enable')
|
||||
this.descriptions = standardLanguageDescriptions.filter(o => {
|
||||
return enableJavascript ? true : o.id != 'javascript'
|
||||
})
|
||||
workspace.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('tsserver')) {
|
||||
const config = workspace.getConfiguration('tsserver')
|
||||
let enable = this.enable
|
||||
this.enable = config.get<boolean>('enable', true)
|
||||
if (enable !== this.enable) {
|
||||
if (this.enable) {
|
||||
void this.start()
|
||||
} else {
|
||||
void this.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
this.selector = this.descriptions.reduce((arr, c) => {
|
||||
return arr.concat(c.modeIds)
|
||||
return arr.concat(c.languageIds)
|
||||
}, [])
|
||||
this.registCommands()
|
||||
}
|
||||
|
||||
// public state = ServiceStat.Initial
|
||||
|
||||
public get state(): ServiceStat {
|
||||
if (this.clientHost) {
|
||||
return this.clientHost.serviceClient.state
|
||||
}
|
||||
return this._state
|
||||
}
|
||||
|
||||
private registCommands(): void {
|
||||
let { subscriptions } = this
|
||||
const registCommand = (cmd: Command): void => {
|
||||
let { id, execute } = cmd
|
||||
subscriptions.push(commands.registerCommand(id as string, execute, cmd))
|
||||
}
|
||||
registCommand(new ConfigurePluginCommand(this.pluginManager))
|
||||
registCommand(new AutoFixCommand(this))
|
||||
registCommand(new ReloadProjectsCommand(this))
|
||||
registCommand(new FileReferencesCommand(this))
|
||||
registCommand(new OpenTsServerLogCommand(this))
|
||||
registCommand(new TypeScriptGoToProjectConfigCommand(this))
|
||||
registCommand(new OrganizeImportsCommand(this))
|
||||
registCommand(new SourceImportsCommand(this))
|
||||
registCommand({
|
||||
id: 'tsserver.restart',
|
||||
execute: (): void => {
|
||||
this.restart()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public get config(): WorkspaceConfiguration {
|
||||
|
@ -51,44 +99,43 @@ export default class TsserverService implements IServiceProvider {
|
|||
})
|
||||
}
|
||||
|
||||
public start(): Promise<void> {
|
||||
if (this.clientHost) return
|
||||
this.state = ServiceStat.Starting
|
||||
this.clientHost = new TypeScriptServiceClientHost(this.descriptions, this.pluginManager)
|
||||
this.disposables.push(this.clientHost)
|
||||
public async start(): Promise<void> {
|
||||
if (!this.enable || this._state == ServiceStat.Starting) return
|
||||
this._state = ServiceStat.Starting
|
||||
if (this.clientHost) {
|
||||
let client = this.clientHost.serviceClient
|
||||
client.restartTsServer()
|
||||
return
|
||||
}
|
||||
let tscPath = await workspace.nvim.getVar('Tsserver_path') as string | null
|
||||
this.clientHost = new TypeScriptServiceClientHost(this.descriptions, this.pluginManager, tscPath)
|
||||
let client = this.clientHost.serviceClient
|
||||
return new Promise(resolve => {
|
||||
let started = false
|
||||
client.onTsServerStarted(() => {
|
||||
Object.defineProperty(this, 'state', {
|
||||
get: () => {
|
||||
return this.clientHost.serviceClient.state
|
||||
}
|
||||
})
|
||||
await new Promise(resolve => {
|
||||
client.onReady(() => {
|
||||
this._onDidServiceReady.fire(void 0)
|
||||
if (!started) {
|
||||
started = true
|
||||
resolve()
|
||||
}
|
||||
resolve(undefined)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
disposeAll(this.disposables)
|
||||
}
|
||||
|
||||
public async restart(): Promise<void> {
|
||||
if (!this.clientHost) return
|
||||
let client = this.clientHost.serviceClient
|
||||
await client.restartTsServer()
|
||||
if (!this.enable) return
|
||||
await this.stop()
|
||||
await this.start()
|
||||
}
|
||||
|
||||
public async stop(): Promise<void> {
|
||||
if (!this.clientHost) return
|
||||
this.clientHost.reset()
|
||||
let client = this.clientHost.serviceClient
|
||||
await client.stop()
|
||||
return
|
||||
this.clientHost?.dispose()
|
||||
this.clientHost = null
|
||||
this._state = ServiceStat.Stopped
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
void this.stop()
|
||||
this._onDidServiceReady.dispose()
|
||||
disposeAll(this.disposables)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,16 +19,19 @@ import FormattingProvider from './features/formatting'
|
|||
import HoverProvider from './features/hover'
|
||||
import ImplementationsCodeLensProvider from './features/implementationsCodeLens'
|
||||
import ImportfixProvider from './features/importFix'
|
||||
import TypeScriptInlayHintsProvider from './features/inlayHints'
|
||||
import InstallModuleProvider from './features/moduleInstall'
|
||||
import QuickfixProvider from './features/quickfix'
|
||||
import RefactorProvider from './features/refactor'
|
||||
import ReferenceProvider from './features/references'
|
||||
import ReferencesCodeLensProvider from './features/referencesCodeLens'
|
||||
import RenameProvider from './features/rename'
|
||||
import SemanticTokensProvider from './features/semanticTokens'
|
||||
import SignatureHelpProvider from './features/signatureHelp'
|
||||
import SmartSelection from './features/smartSelect'
|
||||
import TagClosing from './features/tagClosing'
|
||||
import UpdateImportsOnFileRenameHandler from './features/updatePathOnRename'
|
||||
import { JsDocCompletionProvider } from './features/jsDocCompletion'
|
||||
import { OrganizeImportsCodeActionProvider } from './organizeImports'
|
||||
import TypeScriptServiceClient from './typescriptServiceClient'
|
||||
import API from './utils/api'
|
||||
|
@ -49,13 +52,8 @@ export default class LanguageProvider {
|
|||
) {
|
||||
workspace.onDidChangeConfiguration(this.configurationChanged, this, this.disposables)
|
||||
this.configurationChanged()
|
||||
|
||||
let initialized = false
|
||||
client.onTsServerStarted(async () => { // tslint:disable-line
|
||||
if (!initialized) {
|
||||
initialized = true
|
||||
this.registerProviders(client, typingsStatus)
|
||||
}
|
||||
client.onReady(() => {
|
||||
this.registerProviders(client, typingsStatus)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -77,14 +75,20 @@ export default class LanguageProvider {
|
|||
client: TypeScriptServiceClient,
|
||||
typingsStatus: TypingsStatus
|
||||
): void {
|
||||
let languageIds = this.description.modeIds
|
||||
let clientId = `tsserver-${this.description.id}`
|
||||
let languageIds = this.description.languageIds
|
||||
let clientId = `tsc-${this.description.id}`
|
||||
this._register(
|
||||
languages.registerCompletionItemProvider(clientId, 'TSC', languageIds,
|
||||
new CompletionItemProvider(client, typingsStatus, this.fileConfigurationManager, this.description.id),
|
||||
CompletionItemProvider.triggerCharacters
|
||||
)
|
||||
)
|
||||
this._register(
|
||||
languages.registerCompletionItemProvider(`tsc-${this.description.id}-jsdoc`, 'TSC', languageIds,
|
||||
new JsDocCompletionProvider(client, this.description, this.fileConfigurationManager),
|
||||
['*', ' ']
|
||||
)
|
||||
)
|
||||
if (this.client.apiVersion.gte(API.v230)) {
|
||||
this._register(languages.registerCompletionItemProvider(
|
||||
`${this.description.id}-directive`,
|
||||
|
@ -107,9 +111,18 @@ export default class LanguageProvider {
|
|||
this._register(languages.registerDocumentRangeFormatProvider(languageIds, formatProvider))
|
||||
this._register(languages.registerOnTypeFormattingEditProvider(languageIds, formatProvider, [';', '}', '\n', String.fromCharCode(27)]))
|
||||
this._register(languages.registerCodeActionProvider(languageIds, new InstallModuleProvider(client), 'tsserver'))
|
||||
if (typeof languages['registerCallHierarchyProvider'] === 'function') {
|
||||
if (this.client.apiVersion.gte(API.v380) && typeof languages['registerCallHierarchyProvider'] === 'function') {
|
||||
this._register(languages.registerCallHierarchyProvider(languageIds, new CallHierarchyProvider(client)))
|
||||
}
|
||||
if (this.client.apiVersion.gte(API.v370)) {
|
||||
const provider = new SemanticTokensProvider(client)
|
||||
if (typeof languages['registerDocumentSemanticTokensProvider'] === 'function') {
|
||||
this._register(languages.registerDocumentSemanticTokensProvider(languageIds, provider, provider.getLegend()))
|
||||
}
|
||||
if (typeof languages['registerDocumentRangeSemanticTokensProvider'] === 'function') {
|
||||
this._register(languages.registerDocumentRangeSemanticTokensProvider(languageIds, provider, provider.getLegend()))
|
||||
}
|
||||
}
|
||||
|
||||
let { fileConfigurationManager } = this
|
||||
let conf = fileConfigurationManager.getLanguageConfiguration(this.id)
|
||||
|
@ -145,10 +158,10 @@ export default class LanguageProvider {
|
|||
'tsserver', [CodeActionKind.QuickFix]))
|
||||
let cachedResponse = new CachedNavTreeResponse()
|
||||
if (this.client.apiVersion.gte(API.v206) && conf.get<boolean>('referencesCodeLens.enable')) {
|
||||
this._register(languages.registerCodeLensProvider(languageIds, new ReferencesCodeLensProvider(client, cachedResponse)))
|
||||
this._register(languages.registerCodeLensProvider(languageIds, new ReferencesCodeLensProvider(client, cachedResponse, this.description.id)))
|
||||
}
|
||||
if (this.client.apiVersion.gte(API.v220) && conf.get<boolean>('implementationsCodeLens.enable')) {
|
||||
this._register(languages.registerCodeLensProvider(languageIds, new ImplementationsCodeLensProvider(client, cachedResponse)))
|
||||
this._register(languages.registerCodeLensProvider(languageIds, new ImplementationsCodeLensProvider(client, cachedResponse, this.description.id)))
|
||||
}
|
||||
if (this.client.apiVersion.gte(API.v350)) {
|
||||
this._register(languages.registerSelectionRangeProvider(languageIds, new SmartSelection(this.client)))
|
||||
|
@ -156,16 +169,34 @@ export default class LanguageProvider {
|
|||
if (this.client.apiVersion.gte(API.v300)) {
|
||||
this._register(new TagClosing(this.client, this.description.id))
|
||||
}
|
||||
if (this.client.apiVersion.gte(API.v440)) {
|
||||
if (typeof languages.registerInlayHintsProvider === 'function') {
|
||||
let provider = new TypeScriptInlayHintsProvider(this.description, this.client, this.fileConfigurationManager)
|
||||
this._register(provider)
|
||||
this._register(languages.registerInlayHintsProvider(languageIds, provider))
|
||||
} else {
|
||||
this.client.logger.error(`languages.registerInlayHintsProvider is not a function, inlay hints won't work`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public handles(resource: string, doc: TextDocument): boolean {
|
||||
if (doc && this.description.modeIds.indexOf(doc.languageId) >= 0) {
|
||||
if (doc && this.description.languageIds.includes(doc.languageId)) {
|
||||
return true
|
||||
}
|
||||
const base = path.basename(Uri.parse(resource).fsPath)
|
||||
return this.handlesConfigFile(Uri.parse(resource))
|
||||
}
|
||||
|
||||
private handlesConfigFile(uri: Uri): boolean {
|
||||
const base = path.basename(uri.fsPath)
|
||||
return !!base && (!!this.description.configFilePattern && this.description.configFilePattern.test(base))
|
||||
}
|
||||
|
||||
public handlesUri(resource: Uri): boolean {
|
||||
const ext = path.extname(resource.path).slice(1).toLowerCase()
|
||||
return this.description.standardFileExtensions.includes(ext) || this.handlesConfigFile(resource)
|
||||
}
|
||||
|
||||
private get id(): string { // tslint:disable-line
|
||||
return this.description.id
|
||||
}
|
||||
|
|
|
@ -19,9 +19,10 @@ export class OrganizeImportsCommand implements Command {
|
|||
) {
|
||||
}
|
||||
|
||||
private async _execute(client: TypeScriptServiceClient, document: TextDocument): Promise<WorkspaceEdit | TextEdit[] | null> {
|
||||
private async _execute(client: TypeScriptServiceClient, document: TextDocument, sortOnly = false): Promise<WorkspaceEdit | TextEdit[] | null> {
|
||||
let file = client.toPath(document.uri)
|
||||
const args: Proto.OrganizeImportsRequestArgs = {
|
||||
skipDestructiveCodeActions: sortOnly,
|
||||
scope: {
|
||||
type: 'file',
|
||||
args: {
|
||||
|
@ -38,7 +39,7 @@ export class OrganizeImportsCommand implements Command {
|
|||
client,
|
||||
response.body
|
||||
)
|
||||
let keys = Object.keys(edit.changes)
|
||||
let keys = Object.keys(edit.changes || {})
|
||||
if (keys.length == 1) {
|
||||
let doc = workspace.getDocument(keys[0])
|
||||
if (doc) {
|
||||
|
@ -49,7 +50,7 @@ export class OrganizeImportsCommand implements Command {
|
|||
if (edit) await workspace.applyEdit(edit)
|
||||
}
|
||||
|
||||
public async execute(document?: TextDocument): Promise<void> {
|
||||
public async execute(document?: TextDocument, sortOnly = false): Promise<void> {
|
||||
let client = await this.service.getClientHost()
|
||||
if (!document) {
|
||||
let doc = await workspace.document
|
||||
|
@ -61,10 +62,14 @@ export class OrganizeImportsCommand implements Command {
|
|||
}
|
||||
document = doc.textDocument
|
||||
}
|
||||
await this._execute(client.serviceClient, document)
|
||||
await this._execute(client.serviceClient, document, sortOnly)
|
||||
}
|
||||
}
|
||||
|
||||
export class SourceImportsCommand extends OrganizeImportsCommand {
|
||||
public readonly id = 'tsserver.sortImports'
|
||||
}
|
||||
|
||||
export class OrganizeImportsCodeActionProvider implements CodeActionProvider {
|
||||
// public static readonly minVersion = API.v280
|
||||
|
||||
|
@ -91,11 +96,16 @@ export class OrganizeImportsCodeActionProvider implements CodeActionProvider {
|
|||
}
|
||||
await this.fileConfigManager.ensureConfigurationForDocument(document, token)
|
||||
|
||||
const action = CodeAction.create('Organize Imports', {
|
||||
const organizeImportsAction = CodeAction.create('Organize Imports', {
|
||||
title: '',
|
||||
command: 'tsserver.organizeImports',
|
||||
arguments: [document]
|
||||
}, CodeActionKind.SourceOrganizeImports)
|
||||
return [action]
|
||||
const sortImportsAction = CodeAction.create('Sort Imports', {
|
||||
title: '',
|
||||
command: 'tsserver.sortImports',
|
||||
arguments: [document, true]
|
||||
}, 'source.sortImports')
|
||||
return [organizeImportsAction, sortImportsAction]
|
||||
}
|
||||
}
|
||||
|
|
55
src/server/tsServerProcess.ts
Normal file
55
src/server/tsServerProcess.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import cp from 'child_process'
|
||||
import { Disposable } from 'vscode-languageserver-protocol'
|
||||
import * as Proto from './protocol'
|
||||
import { Reader } from './utils/wireProtocol'
|
||||
|
||||
export interface ToCancelOnResourceChanged {
|
||||
readonly resource: string
|
||||
cancel(): void
|
||||
}
|
||||
|
||||
export default class ForkedTsServerProcess implements Disposable {
|
||||
private readonly _reader: Reader<Proto.Response>
|
||||
|
||||
constructor(private childProcess: cp.ChildProcess) {
|
||||
this._reader = new Reader<Proto.Response>(this.childProcess.stdout)
|
||||
}
|
||||
|
||||
public readonly toCancelOnResourceChange = new Set<ToCancelOnResourceChanged>()
|
||||
|
||||
public onExit(cb: (err: any, signal: string) => void): void {
|
||||
this.childProcess.on('exit', cb)
|
||||
}
|
||||
|
||||
public write(serverRequest: Proto.Request): void {
|
||||
this.childProcess.stdin.write(
|
||||
JSON.stringify(serverRequest) + '\r\n',
|
||||
'utf8'
|
||||
)
|
||||
}
|
||||
|
||||
public onData(handler: (data: Proto.Response) => void): void {
|
||||
this._reader.onData(handler)
|
||||
}
|
||||
|
||||
public onError(handler: (err: Error) => void): void {
|
||||
this.childProcess.on('error', handler)
|
||||
this._reader.onError(handler)
|
||||
}
|
||||
|
||||
public kill(): void {
|
||||
this.toCancelOnResourceChange.clear()
|
||||
this.childProcess.kill()
|
||||
this._reader.dispose()
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.toCancelOnResourceChange.clear()
|
||||
this._reader.dispose()
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ export interface TypeScriptServerPlugin {
|
|||
readonly languages: string[]
|
||||
}
|
||||
|
||||
export enum ExectuionTarget {
|
||||
export enum ExecutionTarget {
|
||||
Semantic,
|
||||
Syntax
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ export type ExecConfig = {
|
|||
readonly lowPriority?: boolean
|
||||
readonly nonRecoverable?: boolean
|
||||
readonly cancelOnResourceChange?: string
|
||||
readonly executionTarget?: ExectuionTarget
|
||||
readonly executionTarget?: ExecutionTarget
|
||||
}
|
||||
|
||||
export interface TypeScriptRequestTypes {
|
||||
|
@ -84,6 +84,7 @@ export interface TypeScriptRequestTypes {
|
|||
'provideCallHierarchyIncomingCalls': [Proto.FileLocationRequestArgs, Proto.ProvideCallHierarchyIncomingCallsResponse]
|
||||
'provideCallHierarchyOutgoingCalls': [Proto.FileLocationRequestArgs, Proto.ProvideCallHierarchyOutgoingCallsResponse]
|
||||
'fileReferences': [Proto.FileRequestArgs, Proto.FileReferencesResponse]
|
||||
'provideInlayHints': [Proto.InlayHintsRequestArgs, Proto.InlayHintsResponse]
|
||||
}
|
||||
|
||||
export interface ITypeScriptServiceClient {
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import cp from 'child_process'
|
||||
import { Document, ServiceStat, Uri, window, workspace } from 'coc.nvim'
|
||||
import fs from 'fs'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import { CancellationToken, CancellationTokenSource, Disposable, Emitter, Event } from 'vscode-languageserver-protocol'
|
||||
import * as fileSchemes from '../utils/fileSchemess'
|
||||
import * as fileSchemes from '../utils/fileSchemes'
|
||||
import { PluginManager } from '../utils/plugins'
|
||||
import { CallbackMap } from './callbackMap'
|
||||
import BufferSyncSupport from './features/bufferSyncSupport'
|
||||
|
@ -20,50 +19,12 @@ import { ExecConfig, ITypeScriptServiceClient, ServerResponse } from './typescri
|
|||
import API from './utils/api'
|
||||
import { TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration'
|
||||
import Logger from './utils/logger'
|
||||
import { fork, getTempDirectory, getTempFile, IForkOptions, makeRandomHexString } from './utils/process'
|
||||
import { fork, getTempDirectory, createTempDirectory, getTempFile, IForkOptions, makeRandomHexString } from './utils/process'
|
||||
import Tracer from './utils/tracer'
|
||||
import { inferredProjectConfig } from './utils/tsconfig'
|
||||
import { TypeScriptVersion, TypeScriptVersionProvider } from './utils/versionProvider'
|
||||
import VersionStatus from './utils/versionStatus'
|
||||
import { ICallback, Reader } from './utils/wireProtocol'
|
||||
|
||||
interface ToCancelOnResourceChanged {
|
||||
readonly resource: string
|
||||
cancel(): void
|
||||
}
|
||||
|
||||
class ForkedTsServerProcess {
|
||||
constructor(private childProcess: cp.ChildProcess) {}
|
||||
|
||||
public readonly toCancelOnResourceChange = new Set<ToCancelOnResourceChanged>()
|
||||
|
||||
public onError(cb: (err: Error) => void): void {
|
||||
this.childProcess.on('error', cb)
|
||||
}
|
||||
|
||||
public onExit(cb: (err: any) => void): void {
|
||||
this.childProcess.on('exit', cb)
|
||||
}
|
||||
|
||||
public write(serverRequest: Proto.Request): void {
|
||||
this.childProcess.stdin.write(
|
||||
JSON.stringify(serverRequest) + '\r\n',
|
||||
'utf8'
|
||||
)
|
||||
}
|
||||
|
||||
public createReader(
|
||||
callback: ICallback<Proto.Response>,
|
||||
onError: (error: any) => void
|
||||
): void {
|
||||
// tslint:disable-next-line:no-unused-expression
|
||||
new Reader<Proto.Response>(this.childProcess.stdout, callback, onError)
|
||||
}
|
||||
|
||||
public kill(): void {
|
||||
this.childProcess.kill()
|
||||
}
|
||||
}
|
||||
import ForkedTsServerProcess, { ToCancelOnResourceChanged } from './tsServerProcess'
|
||||
|
||||
export interface TsDiagnostics {
|
||||
readonly kind: DiagnosticKind
|
||||
|
@ -72,6 +33,8 @@ export interface TsDiagnostics {
|
|||
}
|
||||
|
||||
export default class TypeScriptServiceClient implements ITypeScriptServiceClient {
|
||||
private token: number = 0
|
||||
private noRestart = false
|
||||
public state = ServiceStat.Initial
|
||||
public readonly logger: Logger = new Logger()
|
||||
public readonly bufferSyncSupport: BufferSyncSupport
|
||||
|
@ -84,14 +47,13 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
private versionProvider: TypeScriptVersionProvider
|
||||
private tsServerLogFile: string | null = null
|
||||
private tsServerProcess: ForkedTsServerProcess | undefined
|
||||
private servicePromise: Thenable<ForkedTsServerProcess> | null
|
||||
private lastError: Error | null
|
||||
private lastStart: number
|
||||
private numberRestarts: number
|
||||
private cancellationPipeName: string | null = null
|
||||
private _callbacks = new CallbackMap<Proto.Response>()
|
||||
private _requestQueue = new RequestQueue()
|
||||
private _pendingResponses = new Set<number>()
|
||||
private _onReady?: { promise: Promise<void>; resolve: () => void; reject: () => void }
|
||||
|
||||
private versionStatus: VersionStatus
|
||||
private readonly _onTsServerStarted = new Emitter<API>()
|
||||
|
@ -108,13 +70,20 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
|
||||
constructor(
|
||||
public readonly pluginManager: PluginManager,
|
||||
public readonly modeIds: string[]
|
||||
public readonly modeIds: string[],
|
||||
private readonly tscPathVim: string | undefined
|
||||
) {
|
||||
this.pathSeparator = path.sep
|
||||
this.lastStart = Date.now()
|
||||
this.servicePromise = null
|
||||
this.lastError = null
|
||||
this.numberRestarts = 0
|
||||
let resolve: () => void
|
||||
let reject: () => void
|
||||
const p = new Promise<void>((res, rej) => {
|
||||
resolve = res
|
||||
reject = rej
|
||||
})
|
||||
this._onReady = { promise: p, resolve: resolve!, reject: reject! }
|
||||
|
||||
this.fileConfigurationManager = new FileConfigurationManager(this)
|
||||
this._configuration = TypeScriptServiceConfiguration.loadFromWorkspace()
|
||||
this.versionProvider = new TypeScriptVersionProvider(this._configuration)
|
||||
|
@ -130,7 +99,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
}, null, this.disposables)
|
||||
|
||||
this.bufferSyncSupport = new BufferSyncSupport(this, modeIds)
|
||||
this.onTsServerStarted(() => {
|
||||
this.onReady(() => {
|
||||
this.bufferSyncSupport.listen()
|
||||
})
|
||||
|
||||
|
@ -163,17 +132,20 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
return this._configuration
|
||||
}
|
||||
|
||||
public onReady(f: () => void): Promise<void> {
|
||||
return this._onReady!.promise.then(f)
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this.servicePromise) {
|
||||
this.servicePromise
|
||||
.then(childProcess => {
|
||||
childProcess.kill()
|
||||
})
|
||||
.then(undefined, () => void 0)
|
||||
}
|
||||
this.tsServerProcess.kill()
|
||||
this.diagnosticsManager.dispose()
|
||||
this.bufferSyncSupport.dispose()
|
||||
this.logger.dispose()
|
||||
this._onTsServerStarted.dispose()
|
||||
this._onProjectLanguageServiceStateChanged.dispose()
|
||||
this._onDidBeginInstallTypings.dispose()
|
||||
this._onDidEndInstallTypings.dispose()
|
||||
this._onTypesInstallerInitializationFailed.dispose()
|
||||
this._onResendModelsRequested.dispose()
|
||||
this.versionStatus.dispose()
|
||||
}
|
||||
|
@ -186,40 +158,29 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
this.logger.error(message, data)
|
||||
}
|
||||
|
||||
public restartTsServer(): Promise<any> {
|
||||
const start = () => {
|
||||
this.servicePromise = this.startService(true)
|
||||
return this.servicePromise
|
||||
}
|
||||
|
||||
if (this.servicePromise) {
|
||||
return Promise.resolve(this.servicePromise.then(childProcess => {
|
||||
this.state = ServiceStat.Stopping
|
||||
this.info('Killing TS Server')
|
||||
this.isRestarting = true
|
||||
childProcess.kill()
|
||||
this.servicePromise = null
|
||||
}).then(start))
|
||||
} else {
|
||||
return Promise.resolve(start())
|
||||
public restartTsServer(): void {
|
||||
if (this.tsServerProcess) {
|
||||
this.state = ServiceStat.Stopping
|
||||
this.info('Killing TS Server')
|
||||
this.isRestarting = true
|
||||
this.tsServerProcess.kill()
|
||||
}
|
||||
this.startService(true)
|
||||
}
|
||||
|
||||
public stop(): Promise<void> {
|
||||
if (!this.servicePromise) return
|
||||
return new Promise((resolve, reject) => {
|
||||
this.servicePromise.then(childProcess => {
|
||||
if (this.state == ServiceStat.Running) {
|
||||
this.info('Killing TS Server')
|
||||
childProcess.onExit(() => {
|
||||
resolve()
|
||||
})
|
||||
childProcess.kill()
|
||||
this.servicePromise = null
|
||||
} else {
|
||||
return new Promise(resolve => {
|
||||
let { tsServerProcess } = this
|
||||
if (tsServerProcess && this.state == ServiceStat.Running) {
|
||||
this.info('Killing TS Server')
|
||||
tsServerProcess.onExit(() => {
|
||||
resolve()
|
||||
}
|
||||
}, reject)
|
||||
})
|
||||
this.noRestart = true
|
||||
tsServerProcess.kill()
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -253,125 +214,101 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
return this._tscPath
|
||||
}
|
||||
|
||||
private service(): Thenable<ForkedTsServerProcess> {
|
||||
if (this.servicePromise) {
|
||||
return this.servicePromise
|
||||
}
|
||||
if (this.lastError) {
|
||||
return Promise.reject<ForkedTsServerProcess>(this.lastError)
|
||||
}
|
||||
return this.startService().then(() => {
|
||||
if (this.servicePromise) {
|
||||
return this.servicePromise
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public ensureServiceStarted(): void {
|
||||
if (!this.servicePromise) {
|
||||
this.startService().catch(err => {
|
||||
window.showMessage(`TSServer start failed: ${err.message}`, 'error')
|
||||
this.error(`Service start failed: ${err.stack}`)
|
||||
})
|
||||
if (!this.tsServerProcess) {
|
||||
this.startService()
|
||||
}
|
||||
}
|
||||
|
||||
private async startService(resendModels = false): Promise<ForkedTsServerProcess> {
|
||||
private startService(resendModels = false): ForkedTsServerProcess | undefined {
|
||||
const { ignoreLocalTsserver } = this.configuration
|
||||
let currentVersion: TypeScriptVersion
|
||||
if (!ignoreLocalTsserver) currentVersion = this.versionProvider.getLocalVersion()
|
||||
if (this.tscPathVim) currentVersion = this.versionProvider.getVersionFromTscPath(this.tscPathVim)
|
||||
if (!currentVersion && !ignoreLocalTsserver) currentVersion = this.versionProvider.getLocalVersion()
|
||||
if (!currentVersion || !fs.existsSync(currentVersion.tsServerPath)) {
|
||||
this.info('Local tsserver not found, using bundled tsserver with coc-tsserver.')
|
||||
currentVersion = this.versionProvider.getDefaultVersion()
|
||||
}
|
||||
if (!currentVersion || !currentVersion.isValid) {
|
||||
if (this.configuration.globalTsdk) {
|
||||
window.showMessage(`Can not find typescript module, in 'tsserver.tsdk': ${this.configuration.globalTsdk}`, 'error')
|
||||
window.showErrorMessage(`Can not find typescript module, in 'tsserver.tsdk': ${this.configuration.globalTsdk}`)
|
||||
} else {
|
||||
window.showMessage(`Can not find typescript module, run ':CocInstall coc-tsserver' to fix it!`, 'error')
|
||||
window.showErrorMessage(`Can not find typescript module, run ':CocInstall coc-tsserver' to fix it!`)
|
||||
}
|
||||
return
|
||||
}
|
||||
this._apiVersion = currentVersion.version
|
||||
this._tscPath = currentVersion.tscPath
|
||||
workspace.nvim.setVar('Tsserver_path', this._tscPath, true)
|
||||
this.versionStatus.onDidChangeTypeScriptVersion(currentVersion)
|
||||
this.lastError = null
|
||||
const tsServerForkArgs = await this.getTsServerArgs(currentVersion)
|
||||
const debugPort = this._configuration.debugPort
|
||||
const maxTsServerMemory = this._configuration.maxTsServerMemory
|
||||
const options = {
|
||||
execArgv: [
|
||||
...(debugPort ? [`--inspect=${debugPort}`] : []), // [`--debug-brk=5859`]
|
||||
...(maxTsServerMemory ? [`--max-old-space-size=${maxTsServerMemory}`] : []),
|
||||
],
|
||||
cwd: workspace.root
|
||||
}
|
||||
this.servicePromise = this.startProcess(currentVersion, tsServerForkArgs, options, resendModels)
|
||||
return this.servicePromise
|
||||
const tsServerForkArgs = this.getTsServerArgs(currentVersion)
|
||||
const options = { execArgv: this.getExecArgv() }
|
||||
return this.startProcess(currentVersion, tsServerForkArgs, options, resendModels)
|
||||
}
|
||||
|
||||
private startProcess(currentVersion: TypeScriptVersion, args: string[], options: IForkOptions, resendModels: boolean): Promise<ForkedTsServerProcess> {
|
||||
private getExecArgv(): string[] {
|
||||
const args: string[] = []
|
||||
const debugPort = getDebugPort()
|
||||
if (debugPort) {
|
||||
const isBreak = process.env[process.env.remoteName ? 'TSS_REMOTE_DEBUG_BRK' : 'TSS_DEBUG_BRK'] !== undefined
|
||||
const inspectFlag = isBreak ? '--inspect-brk' : '--inspect'
|
||||
args.push(`${inspectFlag}=${debugPort}`)
|
||||
}
|
||||
const maxTsServerMemory = this._configuration.maxTsServerMemory
|
||||
if (maxTsServerMemory) {
|
||||
args.push(`--max-old-space-size=${maxTsServerMemory}`)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
private startProcess(currentVersion: TypeScriptVersion, args: string[], options: IForkOptions, resendModels: boolean): ForkedTsServerProcess {
|
||||
const myToken = ++this.token
|
||||
this.state = ServiceStat.Starting
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
fork(
|
||||
currentVersion.tsServerPath,
|
||||
args,
|
||||
options,
|
||||
this.logger,
|
||||
(err: any, childProcess: cp.ChildProcess | null) => {
|
||||
if (err || !childProcess) {
|
||||
this.state = ServiceStat.StartFailed
|
||||
this.lastError = err
|
||||
this.error('Starting TSServer failed with error.', err.stack)
|
||||
return
|
||||
}
|
||||
this.state = ServiceStat.Running
|
||||
this.info('Started TSServer', JSON.stringify(currentVersion, null, 2))
|
||||
const handle = new ForkedTsServerProcess(childProcess)
|
||||
this.tsServerProcess = handle
|
||||
this.lastStart = Date.now()
|
||||
|
||||
handle.onError((err: Error) => {
|
||||
this.lastError = err
|
||||
this.error('TSServer errored with error.', err)
|
||||
this.error(`TSServer log file: ${this.tsServerLogFile || ''}`)
|
||||
window.showMessage(`TSServer errored with error. ${err.message}`, 'error')
|
||||
this.serviceExited(false)
|
||||
})
|
||||
handle.onExit((code: any) => {
|
||||
if (code == null) {
|
||||
this.info('TSServer normal exit')
|
||||
} else {
|
||||
this.error(`TSServer exited with code: ${code}`)
|
||||
}
|
||||
this.info(`TSServer log file: ${this.tsServerLogFile || ''}`)
|
||||
this.serviceExited(!this.isRestarting)
|
||||
this.isRestarting = false
|
||||
})
|
||||
|
||||
handle.createReader(
|
||||
msg => {
|
||||
this.dispatchMessage(msg)
|
||||
},
|
||||
error => {
|
||||
this.error('ReaderError', error)
|
||||
}
|
||||
)
|
||||
resolve(handle)
|
||||
this.serviceStarted(resendModels)
|
||||
this._onTsServerStarted.fire(currentVersion.version)
|
||||
}
|
||||
)
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
try {
|
||||
let childProcess = fork(currentVersion.tsServerPath, args, options, this.logger)
|
||||
this.state = ServiceStat.Running
|
||||
this.info('Starting TSServer', JSON.stringify(currentVersion, null, 2))
|
||||
const handle = new ForkedTsServerProcess(childProcess)
|
||||
this.tsServerProcess = handle
|
||||
this.lastStart = Date.now()
|
||||
handle.onError((err: Error) => {
|
||||
if (this.token != myToken) return
|
||||
window.showErrorMessage(`TypeScript language server exited with error. Error message is: ${err.message}`)
|
||||
this.error('TSServer errored with error.', err)
|
||||
this.error(`TSServer log file: ${this.tsServerLogFile || ''}`)
|
||||
window.showMessage(`TSServer errored with error. ${err.message}`, 'error')
|
||||
this.serviceExited(false)
|
||||
})
|
||||
handle.onExit((code: any, signal: string) => {
|
||||
handle.dispose()
|
||||
if (this.token != myToken) return
|
||||
if (code == null) {
|
||||
this.info(`TSServer exited. Signal: ${signal}`)
|
||||
} else {
|
||||
this.error(`TSServer exited with code: ${code}. Signal: ${signal}`)
|
||||
}
|
||||
this.info(`TSServer log file: ${this.tsServerLogFile || ''}`)
|
||||
this.serviceExited(!this.isRestarting)
|
||||
this.isRestarting = false
|
||||
})
|
||||
handle.onData(msg => {
|
||||
this.dispatchMessage(msg)
|
||||
})
|
||||
this.serviceStarted(resendModels)
|
||||
this._onReady!.resolve()
|
||||
this._onTsServerStarted.fire(currentVersion.version)
|
||||
return handle
|
||||
} catch (err) {
|
||||
this.state = ServiceStat.StartFailed
|
||||
this.error('Starting TSServer failed with error.', err.stack)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
public async openTsServerLogFile(): Promise<boolean> {
|
||||
const isRoot = process.getuid && process.getuid() == 0
|
||||
let echoErr = (msg: string) => {
|
||||
window.showMessage(msg, 'error')
|
||||
window.showErrorMessage(msg)
|
||||
}
|
||||
if (isRoot) {
|
||||
echoErr('Log disabled for root user.')
|
||||
|
@ -408,6 +345,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
preferences: {
|
||||
providePrefixAndSuffixTextForRename: true,
|
||||
allowRenameOfImportPath: true,
|
||||
includePackageJsonAutoImports: this._configuration.includePackageJsonAutoImports
|
||||
},
|
||||
watchOptions
|
||||
}
|
||||
|
@ -448,12 +386,15 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
|
||||
private serviceExited(restart: boolean): void {
|
||||
this.state = ServiceStat.Stopped
|
||||
this.servicePromise = null
|
||||
this.tsServerLogFile = null
|
||||
this._callbacks.destroy('Service died.')
|
||||
this._callbacks = new CallbackMap<Proto.Response>()
|
||||
this._requestQueue = new RequestQueue()
|
||||
this._pendingResponses = new Set<number>()
|
||||
if (this.noRestart) {
|
||||
this.noRestart = false
|
||||
return
|
||||
}
|
||||
if (restart) {
|
||||
const diff = Date.now() - this.lastStart
|
||||
this.numberRestarts++
|
||||
|
@ -470,7 +411,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
}
|
||||
}
|
||||
if (startService) {
|
||||
this.startService(true) // tslint:disable-line
|
||||
this.startService(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -482,7 +423,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
public toOpenedFilePath(uri: string, options: { suppressAlertOnFailure?: boolean } = {}): string | undefined {
|
||||
if (!this.bufferSyncSupport.ensureHasBuffer(uri)) {
|
||||
if (!options.suppressAlertOnFailure) {
|
||||
console.error(`Unexpected resource ${uri}`)
|
||||
this.error(`Unexpected resource ${uri}`)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
@ -490,6 +431,9 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
}
|
||||
|
||||
public toResource(filepath: string): string {
|
||||
if (filepath.includes('zipfile:')) {
|
||||
return filepath.replace(/.*zipfile:/, 'zipfile://');
|
||||
}
|
||||
if (this._apiVersion.gte(API.v213)) {
|
||||
if (filepath.startsWith(this.inMemoryResourcePrefix + 'untitled:')) {
|
||||
let resource = Uri.parse(filepath)
|
||||
|
@ -599,13 +543,14 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
}
|
||||
|
||||
private fatalError(command: string, error: any): void {
|
||||
console.error(`A non-recoverable error occured while executing tsserver command: ${command}`)
|
||||
|
||||
this.error(`A non-recoverable error occured while executing tsserver command: ${command}`)
|
||||
if (this.state === ServiceStat.Running) {
|
||||
this.info('Killing TS Server by fatal error:', error)
|
||||
this.service().then(service => {
|
||||
service.kill()
|
||||
})
|
||||
let { tsServerProcess } = this
|
||||
if (tsServerProcess) {
|
||||
this.tsServerProcess = undefined
|
||||
tsServerProcess.kill()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -630,7 +575,7 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined
|
||||
private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise<ServerResponse.Response<Proto.Response>>
|
||||
private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise<ServerResponse.Response<Proto.Response>> | undefined {
|
||||
if (this.servicePromise == null) {
|
||||
if (!this.tsServerProcess) {
|
||||
return Promise.resolve(undefined)
|
||||
}
|
||||
this.bufferSyncSupport.beforeCommand(command)
|
||||
|
@ -678,16 +623,15 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
if (requestItem.expectsResponse && !requestItem.isAsync) {
|
||||
this._pendingResponses.add(requestItem.request.seq)
|
||||
}
|
||||
this.service().then(childProcess => {
|
||||
try {
|
||||
childProcess.write(serverRequest)
|
||||
} catch (err) {
|
||||
const callback = this.fetchCallback(serverRequest.seq)
|
||||
if (callback) {
|
||||
callback.onError(err)
|
||||
}
|
||||
if (!this.tsServerProcess) return
|
||||
try {
|
||||
this.tsServerProcess.write(serverRequest)
|
||||
} catch (err) {
|
||||
const callback = this.fetchCallback(serverRequest.seq)
|
||||
if (callback) {
|
||||
callback.onError(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private tryCancelRequest(seq: number, command: string): boolean {
|
||||
|
@ -722,7 +666,6 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
if (!callback) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
this._pendingResponses.delete(seq)
|
||||
return callback
|
||||
}
|
||||
|
@ -840,8 +783,9 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
}
|
||||
}
|
||||
|
||||
private async getTsServerArgs(currentVersion: TypeScriptVersion): Promise<string[]> {
|
||||
private getTsServerArgs(currentVersion: TypeScriptVersion): string[] {
|
||||
const args: string[] = []
|
||||
|
||||
args.push('--allowLocalPluginLoads')
|
||||
|
||||
if (this.apiVersion.gte(API.v250)) {
|
||||
|
@ -859,10 +803,10 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
args.push('--cancellationPipeName', this.cancellationPipeName + '*')
|
||||
}
|
||||
|
||||
const logDir = getTempDirectory()
|
||||
if (this.apiVersion.gte(API.v222)) {
|
||||
const isRoot = process.getuid && process.getuid() == 0
|
||||
if (this._configuration.tsServerLogLevel !== TsServerLogLevel.Off && !isRoot) {
|
||||
const logDir = getTempDirectory()
|
||||
if (logDir) {
|
||||
this.tsServerLogFile = path.join(logDir, `tsserver.log`)
|
||||
this.info('TSServer log file :', this.tsServerLogFile)
|
||||
|
@ -881,6 +825,16 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
}
|
||||
}
|
||||
|
||||
if (this._configuration.enableTsServerTracing) {
|
||||
let tsServerTraceDirectory = createTempDirectory(`tsserver-trace-${makeRandomHexString(5)}`)
|
||||
if (tsServerTraceDirectory) {
|
||||
args.push('--traceDirectory', tsServerTraceDirectory)
|
||||
this.info('TSServer trace directory :', tsServerTraceDirectory)
|
||||
} else {
|
||||
this.error('Could not create TSServer trace directory')
|
||||
}
|
||||
}
|
||||
|
||||
if (this.apiVersion.gte(API.v230)) {
|
||||
const pluginNames = this.pluginManager.plugins.map(x => x.name)
|
||||
let pluginPaths = this._configuration.tsServerPluginPaths
|
||||
|
@ -954,11 +908,8 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient
|
|||
|
||||
public configurePlugin(pluginName: string, configuration: {}): any {
|
||||
if (this.apiVersion.gte(API.v314)) {
|
||||
if (!this.servicePromise) return
|
||||
this.servicePromise.then(() => {
|
||||
// tslint:disable-next-line: no-floating-promises
|
||||
this.executeWithoutWaitingForResponse('configurePlugin', { pluginName, configuration })
|
||||
})
|
||||
if (!this.tsServerProcess) return
|
||||
this.executeWithoutWaitingForResponse('configurePlugin', { pluginName, configuration })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1001,3 +952,15 @@ function getQueueingType(
|
|||
}
|
||||
return lowPriority ? RequestQueueingType.LowPriority : RequestQueueingType.Normal
|
||||
}
|
||||
|
||||
function getDebugPort(): number | undefined {
|
||||
let debugBrk = process.env[process.env.remoteName ? 'TSS_REMOTE_DEBUG_BRK' : 'TSS_DEBUG_BRK']
|
||||
let value = debugBrk || process.env[process.env.remoteName ? 'TSS_REMOTE_DEBUG_BRK' : 'TSS_DEBUG_BRK']
|
||||
if (value) {
|
||||
const port = parseInt(value)
|
||||
if (!isNaN(port)) {
|
||||
return port
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { disposeAll, languages, TextDocument, Uri, workspace } from 'coc.nvim'
|
||||
import { ConfigurationChangeEvent, disposeAll, languages, TextDocument, Uri, workspace } from 'coc.nvim'
|
||||
import { CancellationToken, Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Disposable, Position, Range } from 'vscode-languageserver-protocol'
|
||||
import { flatten } from '../utils/arrays'
|
||||
import { PluginManager } from '../utils/plugins'
|
||||
|
@ -22,6 +22,7 @@ import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus'
|
|||
const styleCheckDiagnostics = [
|
||||
6133, // variable is declared but never used
|
||||
6138, // property is declared but its value is never read
|
||||
6192, // allImportsAreUnused
|
||||
7027, // unreachable code detected
|
||||
7028, // unused label
|
||||
7029, // fall through case in switch
|
||||
|
@ -37,7 +38,7 @@ export default class TypeScriptServiceClientHost implements Disposable {
|
|||
private readonly fileConfigurationManager: FileConfigurationManager
|
||||
private reportStyleCheckAsWarnings = true
|
||||
|
||||
constructor(descriptions: LanguageDescription[], pluginManager: PluginManager) {
|
||||
constructor(descriptions: LanguageDescription[], pluginManager: PluginManager, tscPath: string | null) {
|
||||
let timer: NodeJS.Timer
|
||||
const handleProjectChange = () => {
|
||||
if (timer) clearTimeout(timer)
|
||||
|
@ -56,7 +57,7 @@ export default class TypeScriptServiceClientHost implements Disposable {
|
|||
packageFileWatcher.onDidChange(handleProjectChange, this, this.disposables)
|
||||
|
||||
const allModeIds = this.getAllModeIds(descriptions, pluginManager)
|
||||
this.client = new TypeScriptServiceClient(pluginManager, allModeIds)
|
||||
this.client = new TypeScriptServiceClient(pluginManager, allModeIds, tscPath)
|
||||
this.disposables.push(this.client)
|
||||
this.client.onDiagnosticsReceived(({ kind, resource, diagnostics }) => {
|
||||
this.diagnosticsReceived(kind, resource, diagnostics).catch(e => {
|
||||
|
@ -102,39 +103,43 @@ export default class TypeScriptServiceClientHost implements Disposable {
|
|||
)
|
||||
this.languagePerId.set(description.id, manager)
|
||||
}
|
||||
const languageIds = new Set<string>()
|
||||
for (const plugin of pluginManager.plugins) {
|
||||
if (plugin.configNamespace && plugin.languages.length) {
|
||||
this.client.ensureServiceStarted()
|
||||
this.client.onReady(() => {
|
||||
const languageIds = new Set<string>()
|
||||
for (const plugin of pluginManager.plugins) {
|
||||
if (plugin.configNamespace && plugin.languages.length) {
|
||||
this.registerExtensionLanguageProvider({
|
||||
id: plugin.configNamespace,
|
||||
languageIds: Array.from(plugin.languages),
|
||||
diagnosticSource: 'ts-plugin',
|
||||
diagnosticLanguage: DiagnosticLanguage.TypeScript,
|
||||
diagnosticOwner: 'typescript',
|
||||
standardFileExtensions: [],
|
||||
isExternal: true
|
||||
})
|
||||
} else {
|
||||
for (const language of plugin.languages) {
|
||||
languageIds.add(language)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (languageIds.size) {
|
||||
this.registerExtensionLanguageProvider({
|
||||
id: plugin.configNamespace,
|
||||
modeIds: Array.from(plugin.languages),
|
||||
id: 'typescript-plugins',
|
||||
languageIds: Array.from(languageIds.values()),
|
||||
diagnosticSource: 'ts-plugin',
|
||||
diagnosticLanguage: DiagnosticLanguage.TypeScript,
|
||||
diagnosticOwner: 'typescript',
|
||||
standardFileExtensions: [],
|
||||
isExternal: true
|
||||
})
|
||||
} else {
|
||||
for (const language of plugin.languages) {
|
||||
languageIds.add(language)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (languageIds.size) {
|
||||
this.registerExtensionLanguageProvider({
|
||||
id: 'typescript-plugins',
|
||||
modeIds: Array.from(languageIds.values()),
|
||||
diagnosticSource: 'ts-plugin',
|
||||
diagnosticLanguage: DiagnosticLanguage.TypeScript,
|
||||
diagnosticOwner: 'typescript',
|
||||
isExternal: true
|
||||
})
|
||||
}
|
||||
|
||||
this.client.ensureServiceStarted()
|
||||
})
|
||||
this.client.onTsServerStarted(() => {
|
||||
this.triggerAllDiagnostics()
|
||||
})
|
||||
|
||||
workspace.onDidChangeConfiguration(this.configurationChanged, this, this.disposables)
|
||||
this.configurationChanged()
|
||||
}
|
||||
|
@ -155,10 +160,6 @@ export default class TypeScriptServiceClientHost implements Disposable {
|
|||
this.ataProgressReporter.dispose()
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
this.fileConfigurationManager.reset()
|
||||
}
|
||||
|
||||
public get serviceClient(): TypeScriptServiceClient {
|
||||
return this.client
|
||||
}
|
||||
|
@ -174,17 +175,20 @@ export default class TypeScriptServiceClientHost implements Disposable {
|
|||
return this.languagePerId.get(languageId)
|
||||
}
|
||||
|
||||
private configurationChanged(): void {
|
||||
const config = workspace.getConfiguration('tsserver')
|
||||
this.reportStyleCheckAsWarnings = config.get('reportStyleChecksAsWarnings', true)
|
||||
private configurationChanged(e?: ConfigurationChangeEvent): void {
|
||||
if (!e || e.affectsConfiguration('tsserver')) {
|
||||
const config = workspace.getConfiguration('tsserver')
|
||||
this.reportStyleCheckAsWarnings = config.get('reportStyleChecksAsWarnings', true)
|
||||
}
|
||||
}
|
||||
|
||||
public async findLanguage(uri: string): Promise<LanguageProvider> {
|
||||
try {
|
||||
let doc = this.client.getDocument(uri)
|
||||
if (!doc) return undefined
|
||||
let languages = Array.from(this.languagePerId.values())
|
||||
return languages.find(language => language.handles(uri, doc.textDocument))
|
||||
// possible not opened
|
||||
if (doc) return languages.find(language => language.handles(uri, doc.textDocument))
|
||||
return languages.find(language => language.handlesUri(Uri.parse(uri)))
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
|
@ -289,7 +293,7 @@ export default class TypeScriptServiceClientHost implements Disposable {
|
|||
|
||||
private getAllModeIds(descriptions: LanguageDescription[], pluginManager: PluginManager): string[] {
|
||||
const allModeIds = flatten([
|
||||
...descriptions.map(x => x.modeIds),
|
||||
...descriptions.map(x => x.languageIds),
|
||||
...pluginManager.plugins.map(x => x.languages)
|
||||
])
|
||||
return allModeIds
|
||||
|
|
|
@ -35,6 +35,7 @@ export default class API {
|
|||
public static readonly v340 = API.fromSimpleString('3.4.0')
|
||||
public static readonly v345 = API.fromSimpleString('3.4.5')
|
||||
public static readonly v350 = API.fromSimpleString('3.5.0')
|
||||
public static readonly v370 = API.fromSimpleString('3.7.0')
|
||||
public static readonly v380 = API.fromSimpleString('3.8.0')
|
||||
public static readonly v381 = API.fromSimpleString('3.8.1')
|
||||
public static readonly v390 = API.fromSimpleString('3.9.0')
|
||||
|
@ -42,6 +43,7 @@ export default class API {
|
|||
public static readonly v401 = API.fromSimpleString('4.0.1')
|
||||
public static readonly v420 = API.fromSimpleString('4.2.0')
|
||||
public static readonly v430 = API.fromSimpleString('4.3.0')
|
||||
public static readonly v440 = API.fromSimpleString('4.4.0')
|
||||
|
||||
public static fromVersionString(versionString: string): API {
|
||||
let version = semver.valid(versionString)
|
||||
|
|
|
@ -59,6 +59,9 @@ export function convertCompletionEntry(
|
|||
insertText = label
|
||||
insertTextFormat = InsertTextFormat.Snippet
|
||||
}
|
||||
if (tsEntry.isSnippet) {
|
||||
insertTextFormat = InsertTextFormat.Snippet
|
||||
}
|
||||
|
||||
let textEdit: TextEdit | null = null
|
||||
if (tsEntry.replacementSpan) {
|
||||
|
@ -73,7 +76,7 @@ export function convertCompletionEntry(
|
|||
if (tsEntry.kindModifiers) {
|
||||
const kindModifiers = new Set(tsEntry.kindModifiers.split(/,|\s+/g))
|
||||
if (kindModifiers.has(PConst.KindModifiers.optional)) {
|
||||
insertText = label
|
||||
insertText = insertText ?? label
|
||||
label += '?'
|
||||
}
|
||||
|
||||
|
@ -136,6 +139,7 @@ function convertKind(kind: string): CompletionItemKind {
|
|||
case PConst.Kind.memberSetAccessor:
|
||||
return CompletionItemKind.Field
|
||||
case PConst.Kind.function:
|
||||
case PConst.Kind.localFunction:
|
||||
return CompletionItemKind.Function
|
||||
case PConst.Kind.method:
|
||||
case PConst.Kind.constructSignature:
|
||||
|
|
|
@ -40,14 +40,25 @@ export namespace TsServerLogLevel {
|
|||
|
||||
export class TypeScriptServiceConfiguration {
|
||||
private _configuration: WorkspaceConfiguration
|
||||
private _includePackageJsonAutoImports: 'auto' | 'on' | 'off'
|
||||
private constructor() {
|
||||
this._configuration = workspace.getConfiguration('tsserver')
|
||||
this._includePackageJsonAutoImports = workspace.getConfiguration('typescript').get<'auto' | 'on' | 'off'>('preferences.includePackageJsonAutoImports')
|
||||
|
||||
workspace.onDidChangeConfiguration(() => {
|
||||
this._configuration = workspace.getConfiguration('tsserver')
|
||||
this._includePackageJsonAutoImports = workspace.getConfiguration('typescript').get<'auto' | 'on' | 'off'>('preferences.includePackageJsonAutoImports')
|
||||
})
|
||||
}
|
||||
|
||||
public get enableTsServerTracing(): boolean {
|
||||
return this._configuration.get<boolean>('enableTracing', false)
|
||||
}
|
||||
|
||||
public get includePackageJsonAutoImports(): 'auto' | 'on' | 'off' {
|
||||
return this._includePackageJsonAutoImports
|
||||
}
|
||||
|
||||
public get locale(): string | null {
|
||||
return this._configuration.get<string | null>('locale', null)
|
||||
}
|
||||
|
@ -97,10 +108,6 @@ export class TypeScriptServiceConfiguration {
|
|||
return this._configuration.get<number>('maxTsServerMemory', 0)
|
||||
}
|
||||
|
||||
public get debugPort(): number | null {
|
||||
return this._configuration.get<number>('debugPort', parseInt(process.env['TSS_DEBUG'], 10))
|
||||
}
|
||||
|
||||
public get npmLocation(): string | null {
|
||||
let path = this._configuration.get<string>('npm', '')
|
||||
if (path) return workspace.expand(path)
|
||||
|
|
|
@ -3,16 +3,18 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as languageModeIds from './languageModeIds'
|
||||
import path from 'path'
|
||||
import { Uri } from 'coc.nvim'
|
||||
|
||||
export interface LanguageDescription {
|
||||
readonly id: string
|
||||
readonly diagnosticSource: string
|
||||
readonly diagnosticLanguage: DiagnosticLanguage
|
||||
readonly modeIds: string[]
|
||||
readonly configFile?: string
|
||||
readonly languageIds: string[]
|
||||
readonly isExternal?: boolean
|
||||
readonly diagnosticOwner: string
|
||||
readonly configFilePattern?: RegExp
|
||||
readonly standardFileExtensions: ReadonlyArray<string>,
|
||||
}
|
||||
|
||||
export const enum DiagnosticLanguage {
|
||||
|
@ -25,19 +27,45 @@ export const standardLanguageDescriptions: LanguageDescription[] = [
|
|||
id: 'typescript',
|
||||
diagnosticSource: 'ts',
|
||||
diagnosticOwner: 'typescript',
|
||||
modeIds: [languageModeIds.typescript, languageModeIds.typescriptreact,
|
||||
languageModeIds.typescripttsx, languageModeIds.typescriptjsx],
|
||||
diagnosticLanguage: DiagnosticLanguage.TypeScript,
|
||||
configFile: 'tsconfig.json',
|
||||
configFilePattern: /^tsconfig(\..*)?\.json$/gi
|
||||
languageIds: [languageModeIds.typescript, languageModeIds.typescriptreact, languageModeIds.typescripttsx, languageModeIds.typescriptjsx],
|
||||
configFilePattern: /^tsconfig(\..*)?\.json$/gi,
|
||||
standardFileExtensions: [
|
||||
'ts',
|
||||
'tsx',
|
||||
'cts',
|
||||
'mts'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'javascript',
|
||||
diagnosticSource: 'ts',
|
||||
diagnosticOwner: 'typescript',
|
||||
modeIds: [languageModeIds.javascript, languageModeIds.javascriptreact, languageModeIds.javascriptjsx],
|
||||
diagnosticLanguage: DiagnosticLanguage.JavaScript,
|
||||
configFile: 'jsconfig.json',
|
||||
configFilePattern: /^jsconfig(\..*)?\.json$/gi
|
||||
languageIds: [languageModeIds.javascript, languageModeIds.javascriptreact, languageModeIds.javascriptjsx], diagnosticLanguage: DiagnosticLanguage.JavaScript,
|
||||
configFilePattern: /^jsconfig(\..*)?\.json$/gi,
|
||||
standardFileExtensions: [
|
||||
'js',
|
||||
'jsx',
|
||||
'cjs',
|
||||
'mjs',
|
||||
'es6',
|
||||
'pac',
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
export function isTsConfigFileName(fileName: string): boolean {
|
||||
return /^tsconfig\.(.+\.)?json$/i.test(path.basename(fileName))
|
||||
}
|
||||
|
||||
export function isJsConfigOrTsConfigFileName(fileName: string): boolean {
|
||||
return /^[jt]sconfig\.(.+\.)?json$/i.test(path.basename(fileName))
|
||||
}
|
||||
|
||||
export function doesResourceLookLikeATypeScriptFile(resource: Uri): boolean {
|
||||
return /\.(tsx?|mts|cts)$/i.test(resource.fsPath)
|
||||
}
|
||||
|
||||
export function doesResourceLookLikeAJavaScriptFile(resource: Uri): boolean {
|
||||
return /\.(jsx?|mjs|cjs)$/i.test(resource.fsPath)
|
||||
}
|
||||
|
|
|
@ -51,12 +51,24 @@ export default class Logger {
|
|||
this.logLevel('Error', message, data)
|
||||
}
|
||||
|
||||
private now(): string {
|
||||
const now = new Date()
|
||||
return padLeft(now.getUTCHours() + '', 2, '0')
|
||||
+ ':' + padLeft(now.getMinutes() + '', 2, '0')
|
||||
+ ':' + padLeft(now.getUTCSeconds() + '', 2, '0') + '.' + now.getMilliseconds()
|
||||
}
|
||||
|
||||
public logLevel(level: string, message: string, data?: any): void {
|
||||
this.output.appendLine(
|
||||
`[${level} - ${new Date().toLocaleTimeString()}] ${message}`
|
||||
`[${level} - ${this.now()}] ${message}`
|
||||
)
|
||||
if (data) {
|
||||
this.output.appendLine(this.data2String(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function padLeft(s: string, n: number, pad = ' ') {
|
||||
return pad.repeat(Math.max(0, n - s.length)) + s
|
||||
}
|
||||
|
|
|
@ -94,20 +94,15 @@ function getTagDocumentation(tag: Proto.JSDocTagInfo): string | undefined {
|
|||
return label + (text.match(/\r\n|\n/g) ? ' \n' + text : ` — ${text}`)
|
||||
}
|
||||
|
||||
export function plain(parts: Proto.SymbolDisplayPart[]): string {
|
||||
if (!parts || !parts.length) return ''
|
||||
return parts.map(part => part.text).join('')
|
||||
}
|
||||
|
||||
export function tagsMarkdownPreview(tags: Proto.JSDocTagInfo[]): string {
|
||||
return (tags || []).map(getTagDocumentation).join(' \n\n')
|
||||
}
|
||||
|
||||
export function markdownDocumentation(
|
||||
documentation: Proto.SymbolDisplayPart[],
|
||||
documentation: Proto.SymbolDisplayPart[] | string,
|
||||
tags: Proto.JSDocTagInfo[]
|
||||
): MarkupContent {
|
||||
let out = plain(documentation)
|
||||
let out = plainWithLinks(documentation)
|
||||
const tagsPreview = tagsMarkdownPreview(tags)
|
||||
if (tagsPreview) {
|
||||
out = out + ('\n\n' + tagsPreview)
|
||||
|
@ -118,6 +113,12 @@ export function markdownDocumentation(
|
|||
}
|
||||
}
|
||||
|
||||
export function plainWithLinks(
|
||||
parts: readonly Proto.SymbolDisplayPart[] | string,
|
||||
): string {
|
||||
return processInlineTags(convertLinkTags(parts))
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert `@link` inline tags to markdown links
|
||||
*/
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import cp from 'child_process'
|
||||
import net from 'net'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
|
@ -24,47 +23,40 @@ export function makeRandomHexString(length: number): string {
|
|||
return result
|
||||
}
|
||||
|
||||
export function getTempDirectory(): string {
|
||||
export function getTempDirectory(): string | undefined {
|
||||
let dir = path.join(os.tmpdir(), `coc.nvim-${process.pid}`)
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir)
|
||||
try {
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir)
|
||||
}
|
||||
} catch (e) {
|
||||
return undefined
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
function generatePipeName(): string {
|
||||
return getPipeName(makeRandomHexString(40))
|
||||
}
|
||||
|
||||
function getPipeName(name: string): string {
|
||||
const fullName = 'coc-tsc-' + name
|
||||
if (process.platform === 'win32') {
|
||||
return '\\\\.\\pipe\\' + fullName + '-sock'
|
||||
}
|
||||
const tmpdir = getTempDirectory()
|
||||
// Mac/Unix: use socket file
|
||||
return path.join(tmpdir, fullName + '.sock')
|
||||
}
|
||||
|
||||
export function getTempFile(name: string): string {
|
||||
export function getTempFile(name: string): string | undefined {
|
||||
const fullName = 'coc-nvim-' + name
|
||||
return path.join(getTempDirectory(), fullName + '.sock')
|
||||
let dir = getTempDirectory()
|
||||
if (!dir) return undefined
|
||||
return path.join(dir, fullName + '.sock')
|
||||
}
|
||||
|
||||
function generatePatchedEnv(
|
||||
env: any,
|
||||
stdInPipeName: string,
|
||||
stdOutPipeName: string,
|
||||
stdErrPipeName: string
|
||||
): any {
|
||||
export function createTempDirectory(name: string) {
|
||||
let dir = getTempDirectory()
|
||||
if (!dir) return undefined
|
||||
let res = path.join(dir, name)
|
||||
try {
|
||||
fs.mkdirSync(res)
|
||||
} catch (e) {
|
||||
return undefined
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function generatePatchedEnv(env: any, modulePath: string): any {
|
||||
const newEnv = Object.assign({}, env)
|
||||
|
||||
// Set the two unique pipe names and the electron flag as process env
|
||||
newEnv['STDIN_PIPE_NAME'] = stdInPipeName // tslint:disable-line
|
||||
newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName // tslint:disable-line
|
||||
newEnv['STDERR_PIPE_NAME'] = stdErrPipeName // tslint:disable-line
|
||||
newEnv['TSS_LOG'] = `-level verbose -file ${path.join(os.tmpdir(), 'coc-nvim-tsc.log')}` // tslint:disable-line
|
||||
|
||||
newEnv['NODE_PATH'] = path.join(modulePath, '..', '..', '..')
|
||||
// Ensure we always have a PATH set
|
||||
newEnv['PATH'] = newEnv['PATH'] || process.env.PATH // tslint:disable-line
|
||||
return newEnv
|
||||
|
@ -75,88 +67,14 @@ export function fork(
|
|||
args: string[],
|
||||
options: IForkOptions,
|
||||
logger: Logger,
|
||||
callback: (error: any, cp: cp.ChildProcess | null) => void
|
||||
): void {
|
||||
let callbackCalled = false
|
||||
const resolve = (result: cp.ChildProcess) => {
|
||||
if (callbackCalled) {
|
||||
return
|
||||
}
|
||||
callbackCalled = true
|
||||
callback(null, result)
|
||||
}
|
||||
const reject = (err: any) => {
|
||||
if (callbackCalled) {
|
||||
return
|
||||
}
|
||||
callbackCalled = true
|
||||
callback(err, null)
|
||||
}
|
||||
|
||||
// Generate three unique pipe names
|
||||
const stdInPipeName = generatePipeName()
|
||||
const stdOutPipeName = generatePipeName()
|
||||
const stdErrPipeName = generatePipeName()
|
||||
|
||||
const newEnv = generatePatchedEnv(
|
||||
process.env,
|
||||
stdInPipeName,
|
||||
stdOutPipeName,
|
||||
stdErrPipeName
|
||||
)
|
||||
newEnv['NODE_PATH'] = path.join(modulePath, '..', '..', '..') // tslint:disable-line
|
||||
|
||||
let childProcess: cp.ChildProcess
|
||||
// Begin listening to stderr pipe
|
||||
let stdErrServer = net.createServer(stdErrStream => {
|
||||
// From now on the childProcess.stderr is available for reading
|
||||
childProcess.stderr = stdErrStream
|
||||
})
|
||||
stdErrServer.listen(stdErrPipeName)
|
||||
|
||||
// Begin listening to stdout pipe
|
||||
let stdOutServer = net.createServer(stdOutStream => {
|
||||
// The child process will write exactly one chunk with content `ready` when it has installed a listener to the stdin pipe
|
||||
|
||||
stdOutStream.once('data', (_chunk: Buffer) => {
|
||||
// The child process is sending me the `ready` chunk, time to connect to the stdin pipe
|
||||
childProcess.stdin = net.connect(stdInPipeName) as any
|
||||
|
||||
// From now on the childProcess.stdout is available for reading
|
||||
childProcess.stdout = stdOutStream
|
||||
|
||||
resolve(childProcess)
|
||||
})
|
||||
})
|
||||
stdOutServer.listen(stdOutPipeName)
|
||||
|
||||
let serverClosed = false
|
||||
const closeServer = () => {
|
||||
if (serverClosed) {
|
||||
return
|
||||
}
|
||||
serverClosed = true
|
||||
stdOutServer.close()
|
||||
stdErrServer.close()
|
||||
}
|
||||
|
||||
): cp.ChildProcess {
|
||||
// Create the process
|
||||
logger.info('Forking TSServer', `PATH: ${newEnv['PATH']} `)
|
||||
|
||||
const bootstrapperPath = path.resolve(__dirname, '../bin/tsserverForkStart')
|
||||
childProcess = cp.fork(bootstrapperPath, [modulePath].concat(args), {
|
||||
logger.info('Forking TSServer', `PATH: ${modulePath} `)
|
||||
let childProcess = cp.fork(modulePath, args, {
|
||||
silent: true,
|
||||
env: newEnv,
|
||||
cwd: undefined,
|
||||
env: generatePatchedEnv(process.env, modulePath),
|
||||
execArgv: options.execArgv
|
||||
})
|
||||
|
||||
childProcess.once('error', (err: Error) => {
|
||||
closeServer()
|
||||
reject(err)
|
||||
})
|
||||
|
||||
childProcess.once('exit', (err: Error) => {
|
||||
closeServer()
|
||||
reject(err)
|
||||
})
|
||||
return childProcess
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Helpers for converting FROM LanguageServer types language-server ts types
|
||||
*/
|
||||
import * as language from 'vscode-languageserver-protocol'
|
||||
import { TextDocumentEdit } from 'vscode-languageserver-protocol'
|
||||
import Proto from '../protocol'
|
||||
import * as PConst from '../protocol.const'
|
||||
import { ITypeScriptServiceClient } from '../typescriptService'
|
||||
|
@ -98,14 +99,20 @@ export namespace WorkspaceEdit {
|
|||
client: ITypeScriptServiceClient,
|
||||
edits: Iterable<Proto.FileCodeEdits>
|
||||
): language.WorkspaceEdit {
|
||||
let changes = {}
|
||||
let documentChanges: TextDocumentEdit[] = []
|
||||
for (const edit of edits) {
|
||||
let uri = client.toResource(edit.fileName)
|
||||
changes[uri] = edit.textChanges.map(change => {
|
||||
return TextEdit.fromCodeEdit(change)
|
||||
documentChanges.push({
|
||||
textDocument: {
|
||||
uri,
|
||||
version: null
|
||||
},
|
||||
edits: edit.textChanges.map(change => {
|
||||
return TextEdit.fromCodeEdit(change)
|
||||
})
|
||||
})
|
||||
}
|
||||
return { changes }
|
||||
return { documentChanges }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { StatusBarItem, window } from 'coc.nvim'
|
||||
import { StatusBarItem, workspace, window } from 'coc.nvim'
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
|
@ -110,10 +110,19 @@ export class AtaProgressReporter {
|
|||
}
|
||||
}
|
||||
|
||||
private onTypesInstallerInitializationFailed() { // tslint:disable-line
|
||||
private async onTypesInstallerInitializationFailed() { // tslint:disable-line
|
||||
this.statusItem.hide()
|
||||
if (!this._invalid) {
|
||||
window.showMessage('Could not install typings files for JavaScript language features. Please ensure that NPM is installed', 'error')
|
||||
const config = workspace.getConfiguration('typescript')
|
||||
if (config.get<boolean>('check.npmIsInstalled', true)) {
|
||||
const dontShowAgain = "Don't Show Again"
|
||||
const selected = await window.showWarningMessage(
|
||||
"Could not install typings files for JavaScript language features. Please ensure that NPM is installed or configure 'typescript.npm' in your user settings. visit https://go.microsoft.com/fwlink/?linkid=847635 to learn more.",
|
||||
dontShowAgain)
|
||||
if (selected === dontShowAgain) {
|
||||
config.update('check.npmIsInstalled', false, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
this._invalid = true
|
||||
}
|
||||
|
|
|
@ -106,6 +106,15 @@ export class TypeScriptVersionProvider {
|
|||
return undefined
|
||||
}
|
||||
|
||||
public getVersionFromTscPath(tscPath: string): TypeScriptVersion | undefined {
|
||||
if (!tscPath || !fs.existsSync(tscPath)) return undefined
|
||||
let libFolder = path.resolve(tscPath, '../../lib')
|
||||
if (fs.existsSync(libFolder)) {
|
||||
let version = new TypeScriptVersion(libFolder)
|
||||
if (version.isValid) return version
|
||||
}
|
||||
}
|
||||
|
||||
public getLocalVersion(): TypeScriptVersion | undefined {
|
||||
let folders = workspace.workspaceFolders.map(f => Uri.parse(f.uri).fsPath)
|
||||
for (let p of folders) {
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { disposeAll } from 'coc.nvim'
|
||||
import stream from 'stream'
|
||||
import { Disposable, Emitter } from 'vscode-languageserver-protocol'
|
||||
|
||||
const DefaultSize = 8192
|
||||
const ContentLength = 'Content-Length: '
|
||||
|
@ -99,18 +101,30 @@ export interface ICallback<T> {
|
|||
(data: T): void // tslint:disable-line
|
||||
}
|
||||
|
||||
export class Reader<T> {
|
||||
export class Reader<T> implements Disposable {
|
||||
private readonly buffer: ProtocolBuffer = new ProtocolBuffer()
|
||||
private nextMessageLength = -1
|
||||
private disposables: Disposable[] = []
|
||||
|
||||
public constructor(
|
||||
private readonly readable: stream.Readable,
|
||||
private readonly callback: ICallback<T>,
|
||||
private readonly onError: (error: any) => void
|
||||
) {
|
||||
this.readable.on('data', (data: Buffer) => {
|
||||
private readonly _onError = new Emitter<Error>()
|
||||
public readonly onError = this._onError.event
|
||||
|
||||
private readonly _onData = new Emitter<T>()
|
||||
public readonly onData = this._onData.event
|
||||
|
||||
public constructor(readable: stream.Readable) {
|
||||
const onData = (data: Buffer) => {
|
||||
this.onLengthData(data)
|
||||
}
|
||||
readable.on('data', onData)
|
||||
|
||||
this.disposables.push({
|
||||
dispose: () => {
|
||||
readable.off('data', onData)
|
||||
}
|
||||
})
|
||||
this.disposables.push(this._onError)
|
||||
this.disposables.push(this._onData)
|
||||
}
|
||||
|
||||
private onLengthData(data: Buffer): void {
|
||||
|
@ -129,10 +143,14 @@ export class Reader<T> {
|
|||
}
|
||||
this.nextMessageLength = -1
|
||||
const json = JSON.parse(msg)
|
||||
this.callback(json)
|
||||
this._onData.fire(json)
|
||||
}
|
||||
} catch (e) {
|
||||
this.onError(e)
|
||||
this._onError.fire(e)
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
disposeAll(this.disposables)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"allowUnreachableCode": true,
|
||||
"allowUnusedLabels": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"noImplicitAny": false,
|
||||
"noImplicitReturns": false,
|
||||
"noUnusedLocals": false,
|
||||
|
|
163
yarn.lock
163
yarn.lock
|
@ -2,35 +2,153 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/node@^10.12.0":
|
||||
version "10.17.44"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.44.tgz#3945e6b702cb6403f22b779c8ea9e5c3f44ead40"
|
||||
integrity sha512-vHPAyBX1ffLcy4fQHmDyIUMUb42gHZjPHU66nhvbMzAWJqHnySGZ6STwN3rwrnSd1FHB0DI/RWgGELgKSYRDmw==
|
||||
"@types/node@^12.12.12":
|
||||
version "12.20.41"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.41.tgz#81d7734c5257da9f04354bd9084a6ebbdd5198a5"
|
||||
integrity sha512-f6xOqucbDirG7LOzedpvzjP3UTmHttRou3Mosx3vL9wr9AIQGhcPgVnqa8ihpZYnxyM1rxeNCvTyukPKZtq10Q==
|
||||
|
||||
coc.nvim@^0.0.81-next.6:
|
||||
version "0.0.81-next.6"
|
||||
resolved "https://registry.yarnpkg.com/coc.nvim/-/coc.nvim-0.0.81-next.6.tgz#c3ee7079a66702ebb3b06d4c2bf333d9306ec561"
|
||||
integrity sha512-VT+DhygyTIzu9IRrwCUljMzfNfh8TeXqqrvFsBE0E8cUwERgCAIvRbBMEDfqaaI+XFgyuwNRwbX5kEvfjG/u3g==
|
||||
coc.nvim@^0.0.81-next.25:
|
||||
version "0.0.81-next.25"
|
||||
resolved "https://registry.yarnpkg.com/coc.nvim/-/coc.nvim-0.0.81-next.25.tgz#8f84b7c71b742e111d330fb553b0df604d4929ec"
|
||||
integrity sha512-c0OOZQSjgKLGNhIpKzlxkPiPmMCmYHSVcCDNA26BqFX8X0iWt3xXqwbxKiE54zfIsz0wFqL59iBVGUSBaqHGpA==
|
||||
|
||||
esbuild@^0.8.29:
|
||||
version "0.8.29"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.8.29.tgz#cc20fb752e0905a3546d68ae1be58f9b97044c39"
|
||||
integrity sha512-UDsEoeXuctVgG2hEts1Hwq2jYDGqV7nksEHEZaiCy2v+lXF5ButX4ErPAJAFi5ZNKKW+6Pom93pArV7hki6HnQ==
|
||||
esbuild-android-arm64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.11.tgz#b8b34e35a5b43880664ac7a3fbc70243d7ed894f"
|
||||
integrity sha512-6iHjgvMnC/SzDH8TefL+/3lgCjYWwAd1LixYfmz/TBPbDQlxcuSkX0yiQgcJB9k+ibZ54yjVXziIwGdlc+6WNw==
|
||||
|
||||
esbuild-darwin-64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.11.tgz#ba805de98c0412e50fcd0636451797da157b0625"
|
||||
integrity sha512-olq84ikh6TiBcrs3FnM4eR5VPPlcJcdW8BnUz/lNoEWYifYQ+Po5DuYV1oz1CTFMw4k6bQIZl8T3yxL+ZT2uvQ==
|
||||
|
||||
esbuild-darwin-arm64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.11.tgz#4d3573e448af76ce33e16231f3d9f878542d6fe8"
|
||||
integrity sha512-Jj0ieWLREPBYr/TZJrb2GFH8PVzDqiQWavo1pOFFShrcmHWDBDrlDxPzEZ67NF/Un3t6sNNmeI1TUS/fe1xARg==
|
||||
|
||||
esbuild-freebsd-64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.11.tgz#9294e6ab359ec93590ab097b0f2017de7c78ab4d"
|
||||
integrity sha512-C5sT3/XIztxxz/zwDjPRHyzj/NJFOnakAanXuyfLDwhwupKPd76/PPHHyJx6Po6NI6PomgVp/zi6GRB8PfrOTA==
|
||||
|
||||
esbuild-freebsd-arm64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.11.tgz#ae3e0b09173350b66cf8321583c9a1c1fcb8bb55"
|
||||
integrity sha512-y3Llu4wbs0bk4cwjsdAtVOesXb6JkdfZDLKMt+v1U3tOEPBdSu6w8796VTksJgPfqvpX22JmPLClls0h5p+L9w==
|
||||
|
||||
esbuild-linux-32@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.11.tgz#ddadbc7038aa5a6b1675bb1503cf79a0cbf1229a"
|
||||
integrity sha512-Cg3nVsxArjyLke9EuwictFF3Sva+UlDTwHIuIyx8qpxRYAOUTmxr2LzYrhHyTcGOleLGXUXYsnUVwKqnKAgkcg==
|
||||
|
||||
esbuild-linux-64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.11.tgz#d698e3ce3a231ddfeec6b5df8c546ae8883fcd88"
|
||||
integrity sha512-oeR6dIrrojr8DKVrxtH3xl4eencmjsgI6kPkDCRIIFwv4p+K7ySviM85K66BN01oLjzthpUMvBVfWSJkBLeRbg==
|
||||
|
||||
esbuild-linux-arm64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.11.tgz#85faea9fa99ad355b5e3b283197a4dfd0a110fe7"
|
||||
integrity sha512-+e6ZCgTFQYZlmg2OqLkg1jHLYtkNDksxWDBWNtI4XG4WxuOCUErLqfEt9qWjvzK3XBcCzHImrajkUjO+rRkbMg==
|
||||
|
||||
esbuild-linux-arm@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.11.tgz#74cbcf0b8a22c8401bcbcd6ebd4cbf2baca8b7b4"
|
||||
integrity sha512-vcwskfD9g0tojux/ZaTJptJQU3a7YgTYsptK1y6LQ/rJmw7U5QJvboNawqM98Ca3ToYEucfCRGbl66OTNtp6KQ==
|
||||
|
||||
esbuild-linux-mips64le@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.11.tgz#490429211a3233f5cbbd8575b7758b897e42979a"
|
||||
integrity sha512-Rrs99L+p54vepmXIb87xTG6ukrQv+CzrM8eoeR+r/OFL2Rg8RlyEtCeshXJ2+Q66MXZOgPJaokXJZb9snq28bw==
|
||||
|
||||
esbuild-linux-ppc64le@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.11.tgz#fc79d60710213b5b98345f5b138d48245616827a"
|
||||
integrity sha512-JyzziGAI0D30Vyzt0HDihp4s1IUtJ3ssV2zx9O/c+U/dhUHVP2TmlYjzCfCr2Q6mwXTeloDcLS4qkyvJtYptdQ==
|
||||
|
||||
esbuild-linux-s390x@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.11.tgz#ca4b93556bbba6cc95b0644f2ee93c982165ba07"
|
||||
integrity sha512-DoThrkzunZ1nfRGoDN6REwmo8ZZWHd2ztniPVIR5RMw/Il9wiWEYBahb8jnMzQaSOxBsGp0PbyJeVLTUatnlcw==
|
||||
|
||||
esbuild-netbsd-64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.11.tgz#edb340bc6653c88804cac2253e21b74258fce165"
|
||||
integrity sha512-12luoRQz+6eihKYh1zjrw0CBa2aw3twIiHV/FAfjh2NEBDgJQOY4WCEUEN+Rgon7xmLh4XUxCQjnwrvf8zhACw==
|
||||
|
||||
esbuild-openbsd-64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.11.tgz#caeff5f946f79a60ce7bcf88871ca4c71d3476e8"
|
||||
integrity sha512-l18TZDjmvwW6cDeR4fmizNoxndyDHamGOOAenwI4SOJbzlJmwfr0jUgjbaXCUuYVOA964siw+Ix+A+bhALWg8Q==
|
||||
|
||||
esbuild-sunos-64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.11.tgz#90ce7e1749c2958a53509b4bae7b8f7d98f276d6"
|
||||
integrity sha512-bmYzDtwASBB8c+0/HVOAiE9diR7+8zLm/i3kEojUH2z0aIs6x/S4KiTuT5/0VKJ4zk69kXel1cNWlHBMkmavQg==
|
||||
|
||||
esbuild-windows-32@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.11.tgz#d067f4ce15b29efba6336e6a23597120fafe49ec"
|
||||
integrity sha512-J1Ys5hMid8QgdY00OBvIolXgCQn1ARhYtxPnG6ESWNTty3ashtc4+As5nTrsErnv8ZGUcWZe4WzTP/DmEVX1UQ==
|
||||
|
||||
esbuild-windows-64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.11.tgz#13e86dd37a6cd61a5276fa2d271342d0f74da864"
|
||||
integrity sha512-h9FmMskMuGeN/9G9+LlHPAoiQk9jlKDUn9yA0MpiGzwLa82E7r1b1u+h2a+InprbSnSLxDq/7p5YGtYVO85Mlg==
|
||||
|
||||
esbuild-windows-arm64@0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.11.tgz#e8edfdf1d712085e6dc3fba18a0c225aaae32b75"
|
||||
integrity sha512-dZp7Krv13KpwKklt9/1vBFBMqxEQIO6ri7Azf8C+ob4zOegpJmha2XY9VVWP/OyQ0OWk6cEeIzMJwInRZrzBUQ==
|
||||
|
||||
esbuild@^0.14.11:
|
||||
version "0.14.11"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.11.tgz#ac4acb78907874832afb704c3afe58ad37715c27"
|
||||
integrity sha512-xZvPtVj6yecnDeFb3KjjCM6i7B5TCAQZT77kkW/CpXTMnd6VLnRPKrUB1XHI1pSq6a4Zcy3BGueQ8VljqjDGCg==
|
||||
optionalDependencies:
|
||||
esbuild-android-arm64 "0.14.11"
|
||||
esbuild-darwin-64 "0.14.11"
|
||||
esbuild-darwin-arm64 "0.14.11"
|
||||
esbuild-freebsd-64 "0.14.11"
|
||||
esbuild-freebsd-arm64 "0.14.11"
|
||||
esbuild-linux-32 "0.14.11"
|
||||
esbuild-linux-64 "0.14.11"
|
||||
esbuild-linux-arm "0.14.11"
|
||||
esbuild-linux-arm64 "0.14.11"
|
||||
esbuild-linux-mips64le "0.14.11"
|
||||
esbuild-linux-ppc64le "0.14.11"
|
||||
esbuild-linux-s390x "0.14.11"
|
||||
esbuild-netbsd-64 "0.14.11"
|
||||
esbuild-openbsd-64 "0.14.11"
|
||||
esbuild-sunos-64 "0.14.11"
|
||||
esbuild-windows-32 "0.14.11"
|
||||
esbuild-windows-64 "0.14.11"
|
||||
esbuild-windows-arm64 "0.14.11"
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
|
||||
|
||||
semver@^7.3.2:
|
||||
version "7.3.2"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
|
||||
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
|
||||
lru-cache@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
|
||||
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
typescript@^4.3.5:
|
||||
version "4.3.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4"
|
||||
integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==
|
||||
semver@^7.3.5:
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
typescript@^4.7.2:
|
||||
version "4.7.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.2.tgz#1f9aa2ceb9af87cca227813b4310fff0b51593c4"
|
||||
integrity sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==
|
||||
|
||||
vscode-jsonrpc@6.0.0:
|
||||
version "6.0.0"
|
||||
|
@ -56,3 +174,8 @@ which@^2.0.2:
|
|||
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
|
|
Loading…
Reference in a new issue