Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions Extension/src/LanguageServer/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ export interface Client {
getKnownCompilers(): Thenable<configs.KnownCompiler[] | undefined>;
takeOwnership(document: vscode.TextDocument): void;
sendDidOpen(document: vscode.TextDocument): Promise<void>;
requestSwitchHeaderSource(rootUri: vscode.Uri, fileName: string): Thenable<string>;
requestSwitchHeaderSource(rootUri: vscode.Uri, fileName: string, token: vscode.CancellationToken): Thenable<string>;
updateActiveDocumentTextOptions(): void;
didChangeActiveEditor(editor?: vscode.TextEditor, selection?: Range): Promise<void>;
restartIntelliSenseForFile(document: vscode.TextDocument): Promise<void>;
Expand Down Expand Up @@ -3019,12 +3019,23 @@ export class DefaultClient implements Client {
/**
* requests to the language server
*/
public async requestSwitchHeaderSource(rootUri: vscode.Uri, fileName: string): Promise<string> {
public async requestSwitchHeaderSource(rootUri: vscode.Uri, fileName: string, token: vscode.CancellationToken): Promise<string> {
const params: SwitchHeaderSourceParams = {
switchHeaderSourceFileName: fileName,
workspaceFolderUri: rootUri.toString()
};
return this.enqueue(async () => this.languageClient.sendRequest(SwitchHeaderSourceRequest, params));
return this.enqueue(async () => {
// Don't use withLspCancellationHandling() or withCancellation() here. If the switch target is already known,
// the caller should still be able to use it even if the progress notification was just cancelled.
try {
return await this.languageClient.sendRequest(SwitchHeaderSourceRequest, params, token);
} catch (e: any) {
if (e instanceof ResponseError && (e.code === RequestCancelled || e.code === ServerCancelled)) {
throw new vscode.CancellationError();
}
throw e;
}
});
}

public async requestCompiler(newCompilerPath?: string): Promise<configs.CompilerDefaults> {
Expand Down Expand Up @@ -4366,7 +4377,7 @@ class NullClient implements Client {
getKnownCompilers(): Thenable<configs.KnownCompiler[] | undefined> { return Promise.resolve([]); }
takeOwnership(document: vscode.TextDocument): void { }
sendDidOpen(document: vscode.TextDocument): Promise<void> { return Promise.resolve(); }
requestSwitchHeaderSource(rootUri: vscode.Uri, fileName: string): Thenable<string> { return Promise.resolve(""); }
requestSwitchHeaderSource(rootUri: vscode.Uri, fileName: string, token: vscode.CancellationToken): Thenable<string> { return Promise.resolve(""); }
updateActiveDocumentTextOptions(): void { }
didChangeActiveEditor(editor?: vscode.TextEditor): Promise<void> { return Promise.resolve(); }
restartIntelliSenseForFile(document: vscode.TextDocument): Promise<void> { return Promise.resolve(); }
Expand Down
71 changes: 59 additions & 12 deletions Extension/src/LanguageServer/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,19 +478,66 @@ async function onSwitchHeaderSource(): Promise<void> {
rootUri = vscode.Uri.file(path.dirname(fileName)); // When switching without a folder open.
}

let targetFileName: string = await clients.ActiveClient.requestSwitchHeaderSource(rootUri, fileName);
// If the targetFileName has a path that is a symlink target of a workspace folder,
// then replace the RootRealPath with the RootPath (the symlink path).
let targetFileNameReplaced: boolean = false;
clients.forEach(client => {
if (!targetFileNameReplaced && client.RootRealPath && client.RootPath !== client.RootRealPath
&& targetFileName.startsWith(client.RootRealPath)) {
targetFileName = client.RootPath + targetFileName.substring(client.RootRealPath.length);
targetFileNameReplaced = true;
const switchHeaderSource: (token: vscode.CancellationToken) => Promise<void> = async (token: vscode.CancellationToken) => {
try {
let targetFileName: string = await clients.ActiveClient.requestSwitchHeaderSource(rootUri, fileName, token);
if (!targetFileName) {
return;
}
// If the targetFileName has a path that is a symlink target of a workspace folder,
// then replace the RootRealPath with the RootPath (the symlink path).
let targetFileNameReplaced: boolean = false;
clients.forEach(client => {
if (!targetFileNameReplaced && client.RootRealPath && client.RootPath !== client.RootRealPath
&& targetFileName.startsWith(client.RootRealPath)) {
targetFileName = client.RootPath + targetFileName.substring(client.RootRealPath.length);
targetFileNameReplaced = true;
}
});
const document: vscode.TextDocument = await vscode.workspace.openTextDocument(targetFileName);
await vscode.window.showTextDocument(document).then(undefined, logAndReturn.undefined);
} catch (e) {
if (e instanceof vscode.CancellationError) {
return;
}
throw e;
}
});
const document: vscode.TextDocument = await vscode.workspace.openTextDocument(targetFileName);
void vscode.window.showTextDocument(document).then(undefined, logAndReturn.undefined);
};

const tokenSource: vscode.CancellationTokenSource = new vscode.CancellationTokenSource();
try {
const switchHeaderSourcePromise: Promise<void> = switchHeaderSource(tokenSource.token);
const showProgress: boolean = await new Promise<boolean>((resolve, reject) => {
const timer: NodeJS.Timeout = global.setTimeout(() => resolve(true), 2000);
void switchHeaderSourcePromise.then(() => {
clearTimeout(timer);
resolve(false);
}, (e) => {
clearTimeout(timer);
reject(e);
});
});

if (!showProgress) {
await switchHeaderSourcePromise;
return;
}

await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: localize('switch.header.source', 'Switching Header/Source...'),
cancellable: true
}, async (_progress, token) => {
const cancellationListener: vscode.Disposable = token.onCancellationRequested(() => tokenSource.cancel());
try {
await switchHeaderSourcePromise;
} finally {
cancellationListener.dispose();
}
});
} finally {
tokenSource.dispose();
}
}

/**
Expand Down
Loading