diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 2d3b2a2a0ce6c..90cd1063ef5ff 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1268,10 +1268,7 @@ namespace ts { }); } - export function assign, T2, T3>(t: T1, arg1: T2, arg2: T3): T1 & T2 & T3; - export function assign, T2>(t: T1, arg1: T2): T1 & T2; - export function assign>(t: T1, ...args: any[]): any; - export function assign>(t: T1, ...args: any[]) { + export function assign(t: T, ...args: T[]) { for (const arg of args) { for (const p in arg) { if (hasProperty(arg, p)) { diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 8170c663b1f9d..840c5e37ce877 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -4131,7 +4131,7 @@ namespace ts.projectSystem { checkErrorMessage(session, "semanticDiag", { file: file1.path, diagnostics: [] }); }); - it("info diagnostics", () => { + it("suggestion diagnostics", () => { const file: FileOrFolder = { path: "/a.js", content: 'require("b")', @@ -4184,6 +4184,57 @@ namespace ts.projectSystem { session.clearMessages(); }); + it("disable suggestion diagnostics", () => { + const file: FileOrFolder = { + path: "/a.js", + content: 'require("b")', + }; + + const host = createServerHost([file]); + const session = createSession(host, { canUseEvents: true }); + const service = session.getProjectService(); + + session.executeCommandSeq({ + command: server.CommandNames.Open, + arguments: { file: file.path, fileContent: file.content }, + }); + + session.executeCommandSeq({ + command: server.CommandNames.Configure, + arguments: { + preferences: { disableSuggestions: true } + }, + }); + + checkNumberOfProjects(service, { inferredProjects: 1 }); + session.clearMessages(); + const expectedSequenceId = session.getNextSeq(); + host.checkTimeoutQueueLengthAndRun(2); + + checkProjectUpdatedInBackgroundEvent(session, [file.path]); + session.clearMessages(); + + session.executeCommandSeq({ + command: server.CommandNames.Geterr, + arguments: { + delay: 0, + files: [file.path], + } + }); + + host.checkTimeoutQueueLengthAndRun(1); + + checkErrorMessage(session, "syntaxDiag", { file: file.path, diagnostics: [] }, /*isMostRecent*/ true); + session.clearMessages(); + + host.runQueuedImmediateCallbacks(1); + + checkErrorMessage(session, "semanticDiag", { file: file.path, diagnostics: [] }); + // No suggestion event, we're done. + checkCompleteEvent(session, 2, expectedSequenceId); + session.clearMessages(); + }); + it("suppressed diagnostic events", () => { const file: FileOrFolder = { path: "/a.ts", diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index af4d34b8bb235..987621a2865b3 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1842,11 +1842,11 @@ namespace ts.server { this.logger.info(`Host information ${args.hostInfo}`); } if (args.formatOptions) { - mergeMapLikes(this.hostConfiguration.formatCodeOptions, convertFormatOptions(args.formatOptions)); + this.hostConfiguration.formatCodeOptions = { ...this.hostConfiguration.formatCodeOptions, ...convertFormatOptions(args.formatOptions) }; this.logger.info("Format host information updated"); } if (args.preferences) { - mergeMapLikes(this.hostConfiguration.preferences, args.preferences); + this.hostConfiguration.preferences = { ...this.hostConfiguration.preferences, ...args.preferences }; } if (args.extraFileExtensions) { this.hostConfiguration.extraFileExtensions = args.extraFileExtensions; diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 74b6865a3c315..3be352adfee73 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -2638,6 +2638,7 @@ namespace ts.server.protocol { } export interface UserPreferences { + readonly disableSuggestions?: boolean; readonly quotePreference?: "double" | "single"; /** * If enabled, TypeScript will search through all external modules' exports and add them to the completions list. diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 843122e44c01f..11c721344f6e8 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -397,15 +397,18 @@ namespace ts.server { if (formatSettings) { if (!this.formatSettings) { this.formatSettings = getDefaultFormatCodeSettings(this.host); + assign(this.formatSettings, formatSettings); + } + else { + this.formatSettings = { ...this.formatSettings, ...formatSettings }; } - mergeMapLikes(this.formatSettings, formatSettings); } if (preferences) { if (!this.preferences) { - this.preferences = clone(defaultPreferences); + this.preferences = defaultPreferences; } - mergeMapLikes(this.preferences, preferences); + this.preferences = { ...this.preferences, ...preferences }; } } diff --git a/src/server/session.ts b/src/server/session.ts index 3979687d63172..37cd92faa2032 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -527,12 +527,20 @@ namespace ts.server { return; } - next.immediate(() => { - this.suggestionCheck(fileName, project); + const goNext = () => { if (checkList.length > index) { next.delay(followMs, checkOne); } - }); + }; + if (this.getPreferences(fileName).disableSuggestions) { + goNext(); + } + else { + next.immediate(() => { + this.suggestionCheck(fileName, project); + goNext(); + }); + } }); }; diff --git a/src/server/utilities.ts b/src/server/utilities.ts index e2329b868e33f..3a0b1935ede1e 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -83,14 +83,6 @@ namespace ts.server { }; } - export function mergeMapLikes(target: T, source: Partial): void { - for (const key in source) { - if (hasProperty(source, key)) { - target[key] = source[key]; - } - } - } - export type NormalizedPath = string & { __normalizedPathTag: any }; export function toNormalizedPath(fileName: string): NormalizedPath { diff --git a/src/services/types.ts b/src/services/types.ts index 0c3e6a9031455..c5b58bab04d0a 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -228,6 +228,7 @@ namespace ts { } export interface UserPreferences { + readonly disableSuggestions?: boolean; readonly quotePreference?: "double" | "single"; readonly includeCompletionsForModuleExports?: boolean; readonly includeCompletionsWithInsertText?: boolean; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index f602e872c14fd..1b7200d63ebc4 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -4116,6 +4116,7 @@ declare namespace ts { installPackage?(options: InstallPackageOptions): Promise; } interface UserPreferences { + readonly disableSuggestions?: boolean; readonly quotePreference?: "double" | "single"; readonly includeCompletionsForModuleExports?: boolean; readonly includeCompletionsWithInsertText?: boolean; @@ -5041,7 +5042,6 @@ declare namespace ts.server { function ThrowProjectDoesNotContainDocument(fileName: string, project: Project): never; } function getDefaultFormatCodeSettings(host: ServerHost): FormatCodeSettings; - function mergeMapLikes(target: T, source: Partial): void; type NormalizedPath = string & { __normalizedPathTag: any; }; @@ -7156,6 +7156,7 @@ declare namespace ts.server.protocol { insertSpaceBeforeTypeAnnotation?: boolean; } interface UserPreferences { + readonly disableSuggestions?: boolean; readonly quotePreference?: "double" | "single"; /** * If enabled, TypeScript will search through all external modules' exports and add them to the completions list. diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 94fd684daee27..d8cb5bd206345 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -4369,6 +4369,7 @@ declare namespace ts { installPackage?(options: InstallPackageOptions): Promise; } interface UserPreferences { + readonly disableSuggestions?: boolean; readonly quotePreference?: "double" | "single"; readonly includeCompletionsForModuleExports?: boolean; readonly includeCompletionsWithInsertText?: boolean;