Skip to content

Commit 779f2ce

Browse files
ColengmsColen Garoutte-Carson
authored andcommitted
Fix issue with didClose received after didOpen (#3844)
1 parent 0c4c83e commit 779f2ce

File tree

3 files changed

+96
-77
lines changed

3 files changed

+96
-77
lines changed

Extension/src/LanguageServer/client.ts

Lines changed: 91 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -786,94 +786,92 @@ class DefaultClient implements Client {
786786
}
787787

788788
public async provideCustomConfiguration(document: vscode.TextDocument): Promise<void> {
789-
let tokenSource: CancellationTokenSource = new CancellationTokenSource();
790-
let providers: CustomConfigurationProviderCollection = getCustomConfigProviders();
791-
if (providers.size === 0) {
792-
return Promise.resolve();
793-
}
794-
console.log("provideCustomConfiguration");
795-
let providerId: string|undefined = await this.getCustomConfigurationProviderId();
796-
if (!providerId) {
797-
return Promise.resolve();
798-
}
789+
return this.queueBlockingTask(async () => {
790+
let tokenSource: CancellationTokenSource = new CancellationTokenSource();
791+
let providers: CustomConfigurationProviderCollection = getCustomConfigProviders();
792+
if (providers.size === 0) {
793+
return Promise.resolve();
794+
}
795+
console.log("provideCustomConfiguration");
796+
let providerId: string|undefined = this.configuration.CurrentConfigurationProvider;
797+
if (!providerId) {
798+
return Promise.resolve();
799+
}
799800

800-
let providerName: string = providerId;
801-
let params: QueryTranslationUnitSourceParams = {
802-
uri: document.uri.toString()
803-
};
804-
let response: QueryTranslationUnitSourceResult = await this.requestWhenReady(() => this.languageClient.sendRequest(QueryTranslationUnitSourceRequest, params));
805-
if (response.configDisposition === QueryTranslationUnitSourceConfigDisposition.ConfigNotNeeded) {
806-
return Promise.resolve();
807-
}
801+
let providerName: string = providerId;
802+
let params: QueryTranslationUnitSourceParams = {
803+
uri: document.uri.toString()
804+
};
805+
let response: QueryTranslationUnitSourceResult = await this.languageClient.sendRequest(QueryTranslationUnitSourceRequest, params);
806+
if (response.configDisposition === QueryTranslationUnitSourceConfigDisposition.ConfigNotNeeded) {
807+
return Promise.resolve();
808+
}
808809

809-
let tuUri: vscode.Uri = vscode.Uri.parse(response.uri);
810-
let configName: string = await this.getCurrentConfigName();
811-
const notReadyMessage: string = `${providerName} is not ready`;
812-
let provideConfigurationAsync: () => Thenable<SourceFileConfigurationItem[]> = async () => {
813-
// The config requests that we use a provider, try to get IntelliSense configuration info from that provider.
814-
try {
815-
let provider: CustomConfigurationProvider1|null = providers.get(providerId);
816-
if (provider) {
817-
if (!provider.isReady) {
818-
return Promise.reject(notReadyMessage);
819-
}
810+
let tuUri: vscode.Uri = vscode.Uri.parse(response.uri);
811+
let configName: string = this.configuration.CurrentConfiguration.name;
812+
const notReadyMessage: string = `${providerName} is not ready`;
813+
let provideConfigurationAsync: () => Thenable<SourceFileConfigurationItem[]> = async () => {
814+
// The config requests that we use a provider, try to get IntelliSense configuration info from that provider.
815+
try {
816+
let provider: CustomConfigurationProvider1|null = providers.get(providerId);
817+
if (provider) {
818+
if (!provider.isReady) {
819+
return Promise.reject(notReadyMessage);
820+
}
820821

821-
providerName = provider.name;
822-
if (await provider.canProvideConfiguration(tuUri, tokenSource.token)) {
823-
return provider.provideConfigurations([tuUri], tokenSource.token);
822+
providerName = provider.name;
823+
if (await provider.canProvideConfiguration(tuUri, tokenSource.token)) {
824+
return provider.provideConfigurations([tuUri], tokenSource.token);
825+
}
824826
}
827+
} catch (err) {
825828
}
826-
} catch (err) {
827-
}
828-
console.warn("failed to provide configuration");
829-
return Promise.reject("");
830-
};
829+
console.warn("failed to provide configuration");
830+
return Promise.reject("");
831+
};
831832

832-
return this.queueTaskWithTimeout(provideConfigurationAsync, configProviderTimeout, tokenSource).then(
833-
(configs: SourceFileConfigurationItem[]) => {
834-
if (configs && configs.length > 0) {
835-
this.sendCustomConfigurations(configs, true);
836-
if (response.configDisposition === QueryTranslationUnitSourceConfigDisposition.AncestorConfigNeeded) {
837-
// replacing uri with original uri
838-
let newConfig: SourceFileConfigurationItem = { uri: document.uri, configuration: configs[0].configuration };
839-
this.sendCustomConfigurations([newConfig], true);
833+
return this.callTaskWithTimeout(provideConfigurationAsync, configProviderTimeout, tokenSource).then(
834+
(configs: SourceFileConfigurationItem[]) => {
835+
if (configs && configs.length > 0) {
836+
this.sendCustomConfigurations(configs, false);
837+
if (response.configDisposition === QueryTranslationUnitSourceConfigDisposition.AncestorConfigNeeded) {
838+
// replacing uri with original uri
839+
let newConfig: SourceFileConfigurationItem = { uri: document.uri, configuration: configs[0].configuration };
840+
this.sendCustomConfigurations([newConfig], false);
841+
}
840842
}
841-
}
842-
},
843-
(err) => {
844-
if (err === notReadyMessage) {
845-
return;
846-
}
847-
let settings: CppSettings = new CppSettings(this.RootUri);
848-
if (settings.configurationWarnings === "Enabled" && !this.isExternalHeader(document.uri) && !vscode.debug.activeDebugSession) {
849-
const dismiss: string = "Dismiss";
850-
const disable: string = "Disable Warnings";
851-
let message: string = `'${providerName}' is unable to provide IntelliSense configuration information for '${document.uri.fsPath}'. ` +
852-
`Settings from the '${configName}' configuration will be used instead.`;
853-
if (err) {
854-
message += ` (${err})`;
843+
},
844+
(err) => {
845+
if (err === notReadyMessage) {
846+
return;
855847
}
848+
let settings: CppSettings = new CppSettings(this.RootUri);
849+
if (settings.configurationWarnings === "Enabled" && !this.isExternalHeader(document.uri) && !vscode.debug.activeDebugSession) {
850+
const dismiss: string = "Dismiss";
851+
const disable: string = "Disable Warnings";
852+
let message: string = `'${providerName}' is unable to provide IntelliSense configuration information for '${document.uri.fsPath}'. ` +
853+
`Settings from the '${configName}' configuration will be used instead.`;
854+
if (err) {
855+
message += ` (${err})`;
856+
}
856857

857-
vscode.window.showInformationMessage(message, dismiss, disable).then(response => {
858+
vscode.window.showInformationMessage(message, dismiss, disable).then(response => {
858859
switch (response) {
859860
case disable: {
860861
settings.toggleSetting("configurationWarnings", "Enabled", "Disabled");
861862
break;
862863
}
863864
}
864865
});
865-
}
866-
});
866+
}
867+
});
868+
});
867869
}
868870

869871
private isExternalHeader(uri: vscode.Uri): boolean {
870872
return util.isHeader(uri) && !uri.toString().startsWith(this.RootUri.toString());
871873
}
872874

873-
private getCustomConfigurationProviderId(): Thenable<string|undefined> {
874-
return this.queueTask(() => Promise.resolve(this.configuration.CurrentConfigurationProvider));
875-
}
876-
877875
public getCurrentConfigName(): Thenable<string> {
878876
return this.queueTask(() => Promise.resolve(this.configuration.CurrentConfiguration.name));
879877
}
@@ -923,7 +921,7 @@ class DefaultClient implements Client {
923921

924922
if (this.pendingTask && !this.pendingTask.Done) {
925923
// We don't want the queue to stall because of a rejected promise.
926-
return this.pendingTask.then(nextTask, nextTask);
924+
return this.pendingTask.getPromise().then(nextTask, nextTask);
927925
} else {
928926
this.pendingTask = undefined;
929927
return nextTask();
@@ -941,6 +939,7 @@ class DefaultClient implements Client {
941939
private queueBlockingTask(task: () => Thenable<void>): Thenable<void> {
942940
if (this.isSupported) {
943941
this.pendingTask = new util.BlockingTask<void>(task, this.pendingTask);
942+
return this.pendingTask.getPromise();
944943
} else {
945944
return Promise.reject("Unsupported client");
946945
}
@@ -973,6 +972,31 @@ class DefaultClient implements Client {
973972
});
974973
}
975974

975+
private callTaskWithTimeout(task: () => Thenable<any>, ms: number, cancelToken?: CancellationTokenSource): Thenable<any> {
976+
let timer: NodeJS.Timer;
977+
// Create a promise that rejects in <ms> milliseconds
978+
let timeout: () => Promise<any> = () => new Promise((resolve, reject) => {
979+
timer = setTimeout(() => {
980+
clearTimeout(timer);
981+
if (cancelToken) {
982+
cancelToken.cancel();
983+
}
984+
reject("Timed out in " + ms + "ms.");
985+
}, ms);
986+
});
987+
988+
// Returns a race between our timeout and the passed in promise
989+
return Promise.race([task(), timeout()]).then(
990+
(result: any) => {
991+
clearTimeout(timer);
992+
return result;
993+
},
994+
(error: any) => {
995+
clearTimeout(timer);
996+
throw error;
997+
});
998+
}
999+
9761000
public requestWhenReady(request: () => Thenable<any>): Thenable<any> {
9771001
return this.queueTask(request);
9781002
}

Extension/src/LanguageServer/protocolFilter.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,8 @@ export function createProtocolFilter(me: Client, clients: ClientCollection): Mid
3333
}
3434

3535
me.onDidOpenTextDocument(document);
36-
me.provideCustomConfiguration(document).then(() => {
37-
sendMessage(document);
38-
}, () => {
39-
sendMessage(document);
40-
});
36+
me.provideCustomConfiguration(document);
37+
me.notifyWhenReady(() => sendMessage(document));
4138
}
4239
},
4340
didChange: (textDocumentChangeEvent, sendMessage) => {

Extension/src/common.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -890,16 +890,14 @@ export class BlockingTask<T> {
890890
this.dependency.promise.then(f1, f2);
891891
});
892892
}
893+
this.promise.then(() => this.done = true, () => this.done = true);
893894
}
894895

895896
public get Done(): boolean {
896897
return this.done;
897898
}
898899

899-
public then<T2>(onSucceeded: (value: T) => T2, onRejected?: (err) => any): Thenable<T2> {
900-
if (onRejected) {
901-
return this.promise.then(onSucceeded, onRejected);
902-
}
903-
return this.promise.then(onSucceeded);
900+
public getPromise(): Thenable<T> {
901+
return this.promise;
904902
}
905903
}

0 commit comments

Comments
 (0)