diff --git a/Readme.md b/Readme.md index 7e41cc0..40ca472 100644 --- a/Readme.md +++ b/Readme.md @@ -149,6 +149,11 @@ for guide of coc.nvim's configuration. default: `true` - `typescript.suggest.completeFunctionCalls`:Enable snippet for method suggestion, default: `true` +- `typescript.suggest.includeCompletionsForImportStatements`: Enable/disable + auto-import-style completions on partially-typed import statements. Requires using + 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.format.enabled`:Enable/disable format of typescript files. - `typescript.format.insertSpaceAfterCommaDelimiter` default: `true` - `typescript.format.insertSpaceAfterConstructor` default: `false` @@ -197,6 +202,9 @@ for guide of coc.nvim's configuration. default: `true` - `javascript.suggest.completeFunctionCalls`:Enable snippet for method suggestion, default: `true` +- `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.format.insertSpaceAfterCommaDelimiter` default: `true` - `javascript.format.insertSpaceAfterConstructor` default: `false` - `javascript.format.insertSpaceAfterSemicolonInForStatements` default: `true` diff --git a/package.json b/package.json index 9a84a59..56dd345 100644 --- a/package.json +++ b/package.json @@ -326,6 +326,10 @@ "default": true, "description": "Enable/disable suggest paths in import statement and require calls" }, + "typescript.suggest.importStatements": { + "type": "boolean", + "default": true + }, "typescript.suggest.autoImports": { "type": "boolean", "default": true, @@ -336,6 +340,18 @@ "default": true, "description": "Enable snippet for method suggestion" }, + "typescript.suggest.includeCompletionsForImportStatements": { + "type": "boolean", + "default": true, + "description": "Enable/disable auto-import-style completions on partially-typed import statements. Requires using TypeScript 4.3+ in the workspace.", + "scope": "resource" + }, + "typescript.suggest.includeCompletionsWithSnippetText": { + "type": "boolean", + "default": true, + "description": "Enable/disable snippet completions from TS Server. Requires using TypeScript 4.3+ in the workspace.", + "scope": "resource" + }, "typescript.format.enabled": { "type": "boolean", "default": true, @@ -522,6 +538,12 @@ "default": true, "description": "Enable snippet for method suggestion" }, + "javascript.suggest.includeCompletionsForImportStatements": { + "type": "boolean", + "default": true, + "description": "Enable/disable auto-import-style completions on partially-typed import statements. Requires using TypeScript 4.3+ in the workspace.", + "scope": "resource" + }, "javascript.format.enabled": { "type": "boolean", "default": true, @@ -630,12 +652,12 @@ "devDependencies": { "@types/node": "^10.12.0", "coc.nvim": "^0.0.80", + "esbuild": "^0.8.29", "semver": "^7.3.2", "vscode-languageserver-protocol": "^3.15.3", - "esbuild": "^0.8.29", "which": "^2.0.2" }, "dependencies": { - "typescript": "^4.1.3" + "typescript": "^4.3.2" } } diff --git a/src/server/features/completionItemProvider.ts b/src/server/features/completionItemProvider.ts index 3245a77..ef914c7 100644 --- a/src/server/features/completionItemProvider.ts +++ b/src/server/features/completionItemProvider.ts @@ -49,7 +49,7 @@ class ApplyCompletionCodeActionCommand implements CommandItem { export default class TypeScriptCompletionItemProvider implements CompletionItemProvider { - public static readonly triggerCharacters = ['.', '"', '\'', '`', '/', '@', '<', '#'] + public static readonly triggerCharacters = ['.', '"', '\'', '`', '/', '@', '<', '#', ' '] private completeOption: SuggestOptions constructor( @@ -148,7 +148,7 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP dotAccessorContext = { range, text } } } - isIncomplete = (response as any).metadata && (response as any).metadata.isIncomplete + isIncomplete = !!response.body.isIncomplete || (response as any).metadata && (response as any).metadata.isIncomplete entries = response.body.entries } catch (e) { if (e.message == 'No content available.') { @@ -194,6 +194,8 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP case '#': // Workaround for https://github.com/microsoft/TypeScript/issues/36367 return this.client.apiVersion.lt(API.v381) ? undefined : '#' + case ' ': + return this.client.apiVersion.gte(API.v430) ? ' ' : undefined case '.': case '"': @@ -338,6 +340,13 @@ export default class TypeScriptCompletionItemProvider implements CompletionItemP } } + if (triggerCharacter === ' ') { + if (!this.completeOption.importStatementSuggestions || !this.client.apiVersion.lt(API.v430)) { + return false + } + return pre === 'import '; + } + return true } diff --git a/src/server/features/fileConfigurationManager.ts b/src/server/features/fileConfigurationManager.ts index 5ec9c72..f44464a 100644 --- a/src/server/features/fileConfigurationManager.ts +++ b/src/server/features/fileConfigurationManager.ts @@ -37,6 +37,9 @@ export interface SuggestOptions { readonly completeFunctionCalls: boolean readonly autoImports: boolean readonly includeAutomaticOptionalChainCompletions: boolean + readonly importStatementSuggestions: boolean + readonly includeCompletionsForImportStatements: boolean + readonly includeCompletionsWithSnippetText: boolean } export default class FileConfigurationManager { @@ -156,6 +159,9 @@ export default class FileConfigurationManager { paths: config.get<boolean>('paths', true), completeFunctionCalls: config.get<boolean>('completeFunctionCalls', true), autoImports: config.get<boolean>('autoImports', true), + importStatementSuggestions: config.get<boolean>('importStatements', true), + includeCompletionsForImportStatements: config.get<boolean>('includeCompletionsForImportStatements', true), + includeCompletionsWithSnippetText: config.get<boolean>('includeCompletionsWithSnippetText', true), includeAutomaticOptionalChainCompletions: config.get<boolean>('includeAutomaticOptionalChainCompletions', true) } } @@ -173,6 +179,8 @@ export default class FileConfigurationManager { 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, } return preferences } @@ -190,7 +198,7 @@ export default class FileConfigurationManager { type ModuleImportType = 'relative' | 'non-relative' | 'auto' -function getImportModuleSpecifier(config): ModuleImportType { +function getImportModuleSpecifier(config: WorkspaceConfiguration): ModuleImportType { let val = config.get('importModuleSpecifier') switch (val) { case 'relative': diff --git a/src/server/utils/api.ts b/src/server/utils/api.ts index c3bb9ba..6f6008a 100644 --- a/src/server/utils/api.ts +++ b/src/server/utils/api.ts @@ -39,7 +39,9 @@ export default class API { public static readonly v381 = API.fromSimpleString('3.8.1') public static readonly v390 = API.fromSimpleString('3.9.0') public static readonly v400 = API.fromSimpleString('4.0.0') - public static readonly v401 = API.fromSimpleString('4.0.1'); + 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 fromVersionString(versionString: string): API { let version = semver.valid(versionString) diff --git a/src/server/utils/completionItem.ts b/src/server/utils/completionItem.ts index f12c142..3100663 100644 --- a/src/server/utils/completionItem.ts +++ b/src/server/utils/completionItem.ts @@ -37,7 +37,7 @@ export function convertCompletionEntry( if (tsEntry.isRecommended) { preselect = true } - if (tsEntry.source) { + if (tsEntry.source && tsEntry.hasAction) { // De-prioritze auto-imports https://github.com/Microsoft/vscode/issues/40311 sortText = '\uffff' + sortText } else { @@ -53,13 +53,18 @@ export function convertCompletionEntry( let insertText = tsEntry.insertText let commitCharacters = getCommitCharacters(tsEntry, context) + if (tsEntry.isImportStatementCompletion) { + insertText = label + insertTextFormat = InsertTextFormat.Snippet + } + let textEdit: TextEdit | null = null if (tsEntry.replacementSpan) { let { start, end } = tsEntry.replacementSpan if (start.line == end.line) { textEdit = { range: Range.create(start.line - 1, start.offset - 1, end.line - 1, end.offset - 1), - newText: insertText || label + newText: tsEntry.insertText || label } } } diff --git a/yarn.lock b/yarn.lock index 75e347c..ed3d2de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,10 +27,10 @@ semver@^7.3.2: resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== -typescript@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" - integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== +typescript@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805" + integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw== vscode-jsonrpc@^5.0.1: version "5.0.1"