diff --git a/Readme.md b/Readme.md index 8abf432..9892aee 100644 --- a/Readme.md +++ b/Readme.md @@ -103,6 +103,7 @@ Checkout [using the configuration file](https://github.com/neoclide/coc.nvim/wik - `tsserver.trace.server`:Trace level of tsserver, default: `"off"` - `tsserver.pluginRoot`:Folder 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. - `tsserver.reportStyleChecksAsWarnings` default: `true` - `tsserver.implicitProjectConfig.checkJs`:Enable checkJs for implicit project, default: `false` - `tsserver.implicitProjectConfig.experimentalDecorators`:Enable experimentalDecorators for implicit project, default: `false` diff --git a/package.json b/package.json index 0e77999..7a007e9 100644 --- a/package.json +++ b/package.json @@ -139,6 +139,47 @@ "default": 0, "description": "Set the maximum amount of memory to allocate to the TypeScript server process" }, + "tsserver.watchOptions": { + "type": "object", + "description": "Configure which watching strategies should be used to keep track of files and directories. Requires using TypeScript 3.8+ in the workspace.", + "properties": { + "watchFile": { + "type": "string", + "description": "Strategy for how individual files are watched.", + "enum": [ + "fixedPollingInterval", + "priorityPollingInterval", + "dynamicPriorityPolling", + "useFsEvents", + "useFsEventsOnParentDirectory" + ], + "default": "useFsEvents" + }, + "watchDirectory": { + "type": "string", + "description": "Strategy for how entire directory trees are watched under systems that lack recursive file-watching functionality.", + "enum": [ + "fixedPollingInterval", + "dynamicPriorityPolling", + "useFsEvents" + ], + "default": "useFsEvents" + }, + "fallbackPolling": { + "type": "string", + "description": "When using file system events, this option specifies the polling strategy that gets used when the system runs out of native file watchers and/or doesn’t support native file watchers.", + "enum": [ + "fixedPollingInterval", + "priorityPollingInterval", + "dynamicPriorityPolling" + ] + }, + "synchronousWatchDirectory": { + "type": "boolean", + "description": "Disable deferred watching on directories. Deferred watching is useful when lots of file changes might occur at once (e.g. a change in node_modules from running npm install), but you might want to disable it with this flag for some less-common setups." + } + } + }, "tsserver.tsdk": { "type": "string", "default": "", diff --git a/src/server/features/bufferSyncSupport.ts b/src/server/features/bufferSyncSupport.ts index 7f766b6..2f622bd 100644 --- a/src/server/features/bufferSyncSupport.ts +++ b/src/server/features/bufferSyncSupport.ts @@ -120,6 +120,11 @@ class BufferSynchronizer { f(this._pending) } } + + public reset(): void { + this._pending = {} + this._pendingFiles.clear() + } } export default class BufferSyncSupport { @@ -179,7 +184,7 @@ export default class BufferSyncSupport { disposeAll(this.disposables) } - private onDidOpenTextDocument(document: TextDocument): void { + public onDidOpenTextDocument(document: TextDocument): void { if (!this.modeIds.has(document.languageId)) return let { uri } = document let filepath = this.client.toPath(uri) @@ -339,6 +344,15 @@ export default class BufferSyncSupport { } return this._validateTypeScript } + + public reinitialize(): void { + this.pendingDiagnostics.clear() + this.pendingGetErr?.cancel() + this.synchronizer.reset() + for (let doc of workspace.documents) { + this.onDidOpenTextDocument(doc.textDocument) + } + } } class GetErrRequest { diff --git a/src/server/features/completionItemProvider.ts b/src/server/features/completionItemProvider.ts index 3ba3a56..3bf49c1 100644 --- a/src/server/features/completionItemProvider.ts +++ b/src/server/features/completionItemProvider.ts @@ -51,7 +51,7 @@ class ApplyCompletionCodeActionCommand implements CommandItem { export default class TypeScriptCompletionItemProvider implements CompletionItemProvider { - public static readonly triggerCharacters = ['.', '"', '\'', '/', '@'] + public static readonly triggerCharacters = ['.', '"', '\'', '`', '/', '@', '<', '#'] private completeOption: SuggestOptions constructor( @@ -185,14 +185,23 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP } private getTsTriggerCharacter(context: CompletionContext): Proto.CompletionsTriggerCharacter | undefined { - // Workaround for https://github.com/Microsoft/TypeScript/issues/27321 - if (context.triggerCharacter === '@' - && this.client.apiVersion.gte(API.v310) && this.client.apiVersion.lt(API.v320) - ) { - return undefined - } + // return context.triggerCharacter as Proto.CompletionsTriggerCharacter + switch (context.triggerCharacter) { + case '@': // Workaround for https://github.com/Microsoft/TypeScript/issues/27321 + return this.client.apiVersion.gte(API.v310) && this.client.apiVersion.lt(API.v320) ? undefined : '@' - return context.triggerCharacter as Proto.CompletionsTriggerCharacter + case '#': // Workaround for https://github.com/microsoft/TypeScript/issues/36367 + return this.client.apiVersion.lt(API.v381) ? undefined : '#' + + case '.': + case '"': + case '\'': + case '`': + case '/': + case '<': + return context.triggerCharacter + } + return undefined } /** diff --git a/src/server/features/fileConfigurationManager.ts b/src/server/features/fileConfigurationManager.ts index f09d123..673138a 100644 --- a/src/server/features/fileConfigurationManager.ts +++ b/src/server/features/fileConfigurationManager.ts @@ -59,15 +59,14 @@ export default class FileConfigurationManager { this.cachedMap.set(document.uri, currentOptions) const args: Proto.ConfigureRequestArguments = { file, - hostInfo: `nvim-coc ${workspace.version}`, ...currentOptions } await this.client.execute('configure', args, CancellationToken.None) } public async ensureConfigurationForDocument(document: TextDocument): Promise { - let opts = await workspace.getFormatOptions(document.uri) if (!this.client.bufferSyncSupport.has(document.uri)) return + let opts = await workspace.getFormatOptions(document.uri) return this.ensureConfigurationOptions(document, opts.insertSpaces, opts.tabSize) } diff --git a/src/server/index.ts b/src/server/index.ts index a4c2910..c903df3 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -68,8 +68,6 @@ export default class TsserverService implements IServiceProvider { private async ensureConfiguration(): Promise { if (!this.clientHost) return let document = await workspace.document - await wait(100) - let uri = Uri.parse(document.uri) let language = this.clientHost.findLanguage(uri) if (!language) return diff --git a/src/server/typescriptServiceClient.ts b/src/server/typescriptServiceClient.ts index 772893f..d3b86ae 100644 --- a/src/server/typescriptServiceClient.ts +++ b/src/server/typescriptServiceClient.ts @@ -16,7 +16,6 @@ import API from './utils/api' import { TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration' import Logger from './utils/logger' import { fork, getTempFile, getTempDirectory, IForkOptions, makeRandomHexString } from './utils/process' -import { languageIds } from './utils/languageModeIds' import Tracer from './utils/tracer' import { inferredProjectConfig } from './utils/tsconfig' import { TypeScriptVersion, TypeScriptVersionProvider } from './utils/versionProvider' @@ -385,18 +384,27 @@ export default class TypeScriptServiceClient implements ITypeScriptServiceClient } private serviceStarted(resendModels: boolean): void { - let document = workspace.getDocument(workspace.bufnr) - if (document && languageIds.indexOf(document.filetype) !== -1) { - this.fileConfigurationManager.ensureConfigurationForDocument(document.textDocument) // tslint:disable-line - } else { - const configureOptions: Proto.ConfigureRequestArguments = { - hostInfo: 'nvim-coc' - } - this.execute('configure', configureOptions, CancellationToken.None) // tslint:disable-line + const watchOptions = this.apiVersion.gte(API.v380) + ? this.configuration.watchOptions + : undefined + const configureOptions: Proto.ConfigureRequestArguments = { + hostInfo: 'coc-nvim', + preferences: { + providePrefixAndSuffixTextForRename: true, + allowRenameOfImportPath: true, + }, + watchOptions } + this.executeWithoutWaitingForResponse('configure', configureOptions) // tslint:disable-line this.setCompilerOptionsForInferredProjects(this._configuration) if (resendModels) { this._onResendModelsRequested.fire(void 0) + this.diagnosticsManager.reInitialize() + this.bufferSyncSupport.reinitialize() + } + // Reconfigure any plugins + for (const [config, pluginName] of this.pluginManager.configurations()) { + this.configurePlugin(config, pluginName) } } diff --git a/src/server/utils/configuration.ts b/src/server/utils/configuration.ts index 1c187db..b9ef8a5 100644 --- a/src/server/utils/configuration.ts +++ b/src/server/utils/configuration.ts @@ -64,6 +64,11 @@ export class TypeScriptServiceConfiguration { return TsServerLogLevel.fromString(this._configuration.get('log', null)) } + // public readonly watchOptions: protocol.WatchOptions | undefined; + public get watchOptions(): protocol.WatchOptions | undefined { + return this._configuration.get('watchOptions') + } + public get typingsCacheLocation(): string { return this._configuration.get('typingsCacheLocation', '') }