Skip to content
Draft
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
9 changes: 9 additions & 0 deletions Extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3989,6 +3989,11 @@
"title": "%c_cpp.command.switchHeaderSource.title%",
"category": "C/C++"
},
{
"command": "C_Cpp.SelectTranslationUnit",
"title": "%c_cpp.command.selectTranslationUnit.title%",
"category": "C/C++"
},
{
"command": "C_Cpp.EnableErrorSquiggles",
"title": "%c_cpp.command.enableErrorSquiggles.title%",
Expand Down Expand Up @@ -6536,6 +6541,10 @@
"command": "C_Cpp.SwitchHeaderSource",
"when": "editorLangId =~ /^(c|(cuda-)?cpp)$/ && !(config.C_Cpp.intelliSenseEngine =~ /^[dD]isabled$/)"
},
{
"command": "C_Cpp.SelectTranslationUnit",
"when": "editorLangId =~ /^(c|(cuda-)?cpp)$/ && config.C_Cpp.intelliSenseEngine =~ /^[dD]efault$/"
},
{
"command": "C_Cpp.EnableErrorSquiggles",
"when": "config.C_Cpp.intelliSenseEngine =~ /^[dD]efault$/"
Expand Down
1 change: 1 addition & 0 deletions Extension/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"c_cpp.command.installCompiler.title": "Install a C++ Compiler",
"c_cpp.command.rescanCompilers.title": "Rescan for Compilers",
"c_cpp.command.switchHeaderSource.title": "Switch Header/Source",
"c_cpp.command.selectTranslationUnit.title": "Select a Translation Unit...",
"c_cpp.command.enableErrorSquiggles.title": "Enable Error Squiggles",
"c_cpp.command.disableErrorSquiggles.title": "Disable Error Squiggles",
"c_cpp.command.toggleDimInactiveRegions.title": "Toggle Inactive Region Colorization",
Expand Down
32 changes: 32 additions & 0 deletions Extension/src/LanguageServer/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,16 @@ interface SwitchHeaderSourceParams extends WorkspaceFolderParams {
switchHeaderSourceFileName: string;
}

interface GetTranslationUnitSourceCandidatesResult {
candidates: string[];
currentTranslationUnit: string;
}

interface SelectTranslationUnitParams {
uri: string;
translationUnit: string;
}

interface FileChangedParams extends WorkspaceFolderParams {
uri: string;
}
Expand Down Expand Up @@ -625,6 +635,7 @@ const PreInitializationRequest: RequestType<void, string, void> = new RequestTyp
const InitializationRequest: RequestType<CppInitializationParams, CppInitializationResult, void> = new RequestType<CppInitializationParams, CppInitializationResult, void>('cpptools/initialize');
const QueryCompilerDefaultsRequest: RequestType<QueryDefaultCompilerParams, configs.CompilerDefaults, void> = new RequestType<QueryDefaultCompilerParams, configs.CompilerDefaults, void>('cpptools/queryCompilerDefaults');
const SwitchHeaderSourceRequest: RequestType<SwitchHeaderSourceParams, string, void> = new RequestType<SwitchHeaderSourceParams, string, void>('cpptools/didSwitchHeaderSource');
const GetTranslationUnitSourceCandidatesRequest: RequestType<TextDocumentIdentifier, GetTranslationUnitSourceCandidatesResult, void> = new RequestType<TextDocumentIdentifier, GetTranslationUnitSourceCandidatesResult, void>('cpptools/getTranslationUnitSourceCandidates');
const GetDiagnosticsRequest: RequestType<void, GetDiagnosticsResult, void> = new RequestType<void, GetDiagnosticsResult, void>('cpptools/getDiagnostics');
export const GetDocumentSymbolRequest: RequestType<GetDocumentSymbolRequestParams, GetDocumentSymbolResult, void> = new RequestType<GetDocumentSymbolRequestParams, GetDocumentSymbolResult, void>('cpptools/getDocumentSymbols');
export const GetSymbolInfoRequest: RequestType<WorkspaceSymbolParams, LocalizeSymbolInformation[], void> = new RequestType<WorkspaceSymbolParams, LocalizeSymbolInformation[], void>('cpptools/getWorkspaceSymbols');
Expand Down Expand Up @@ -653,6 +664,7 @@ const PauseParsingNotification: NotificationType<void> = new NotificationType<vo
const ResumeParsingNotification: NotificationType<void> = new NotificationType<void>('cpptools/resumeParsing');
const DidChangeActiveEditorNotification: NotificationType<DidChangeActiveEditorParams> = new NotificationType<DidChangeActiveEditorParams>('cpptools/didChangeActiveEditor');
const RestartIntelliSenseForFileNotification: NotificationType<TextDocumentIdentifier> = new NotificationType<TextDocumentIdentifier>('cpptools/restartIntelliSenseForFile');
const SelectTranslationUnitNotification: NotificationType<SelectTranslationUnitParams> = new NotificationType<SelectTranslationUnitParams>('cpptools/selectTranslationUnit');
const DidChangeTextEditorSelectionNotification: NotificationType<Range> = new NotificationType<Range>('cpptools/didChangeTextEditorSelection');
const ChangeCompileCommandsNotification: NotificationType<FileChangedParams> = new NotificationType<FileChangedParams>('cpptools/didChangeCompileCommands');
const ChangeSelectedSettingNotification: NotificationType<FolderSelectedSettingParams> = new NotificationType<FolderSelectedSettingParams>('cpptools/didChangeSelectedSetting');
Expand Down Expand Up @@ -832,6 +844,8 @@ export interface Client {
takeOwnership(document: vscode.TextDocument): void;
sendDidOpen(document: vscode.TextDocument): Promise<void>;
requestSwitchHeaderSource(rootUri: vscode.Uri, fileName: string, token: vscode.CancellationToken): Thenable<string>;
getTranslationUnitSourceCandidates(uri: vscode.Uri): Promise<GetTranslationUnitSourceCandidatesResult>;
selectTranslationUnit(uri: vscode.Uri, translationUnit: string): Promise<void>;
updateActiveDocumentTextOptions(): void;
didChangeActiveEditor(editor?: vscode.TextEditor, selection?: Range): Promise<void>;
restartIntelliSenseForFile(document: vscode.TextDocument): Promise<void>;
Expand Down Expand Up @@ -3164,6 +3178,20 @@ export class DefaultClient implements Client {
});
}

public async getTranslationUnitSourceCandidates(uri: vscode.Uri): Promise<GetTranslationUnitSourceCandidatesResult> {
const params: TextDocumentIdentifier = { uri: uri.toString() };
await this.ready;
return this.languageClient.sendRequest(
GetTranslationUnitSourceCandidatesRequest,
params);
}

public async selectTranslationUnit(uri: vscode.Uri, translationUnit: string): Promise<void> {
const params: SelectTranslationUnitParams = { uri: uri.toString(), translationUnit };
await this.ready;
return this.languageClient.sendNotification(SelectTranslationUnitNotification, params).catch(logAndReturn.undefined);
}

public async requestCompiler(newCompilerPath?: string): Promise<configs.CompilerDefaults> {
const params: QueryDefaultCompilerParams = {
newTrustedCompilerPath: newCompilerPath ?? ""
Expand Down Expand Up @@ -4560,6 +4588,10 @@ class NullClient implements Client {
takeOwnership(document: vscode.TextDocument): void { }
sendDidOpen(document: vscode.TextDocument): Promise<void> { return Promise.resolve(); }
requestSwitchHeaderSource(rootUri: vscode.Uri, fileName: string, token: vscode.CancellationToken): Thenable<string> { return Promise.resolve(""); }
getTranslationUnitSourceCandidates(uri: vscode.Uri): Promise<GetTranslationUnitSourceCandidatesResult> {
return Promise.resolve({ candidates: [], currentTranslationUnit: "" });
}
selectTranslationUnit(uri: vscode.Uri, translationUnit: string): Promise<void> { 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
67 changes: 57 additions & 10 deletions Extension/src/LanguageServer/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ export async function registerCommands(enabled: boolean): Promise<void> {
commandDisposables.forEach(d => d.dispose());
commandDisposables.length = 0;
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.SwitchHeaderSource', enabled ? onSwitchHeaderSource : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.SelectTranslationUnit', enabled ? onSelectTranslationUnit : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ResetDatabase', enabled ? onResetDatabase : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.SelectIntelliSenseConfiguration', enabled ? selectIntelliSenseConfiguration : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.InstallCompiler', enabled ? installCompiler : onDisabledCommand));
Expand Down Expand Up @@ -468,6 +469,61 @@ async function onRestartIntelliSenseForFile() {
return clients.ActiveClient.restartIntelliSenseForFile(activeEditor.document);
}

function getEditorPath(fileName: string): string {
let bestRealRoot: string | undefined;
let bestRootPath: string | undefined;
clients.forEach(client => {
if (!client.RootRealPath) {
return;
}
const relativePath: string = path.relative(client.RootRealPath, fileName);
const isUnderRoot: boolean = relativePath === "" ||
(relativePath !== ".." && !relativePath.startsWith(`..${path.sep}`) && !path.isAbsolute(relativePath));
if (isUnderRoot && (!bestRealRoot || client.RootRealPath.length > bestRealRoot.length)) {
bestRealRoot = client.RootRealPath;
bestRootPath = client.RootPath;
}
});
return bestRealRoot && bestRootPath ? path.join(bestRootPath, path.relative(bestRealRoot, fileName)) : fileName;
}

interface TranslationUnitQuickPickItem extends vscode.QuickPickItem {
translationUnit: string;
}

async function onSelectTranslationUnit(): Promise<void> {
const activeEditor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
if (!activeEditor || !util.isCpp(activeEditor.document)) {
return;
}

const client: Client = clients.ActiveClient;
const result = await client.getTranslationUnitSourceCandidates(activeEditor.document.uri);
const currentTranslationUnit: string = getEditorPath(result.currentTranslationUnit);
const items: TranslationUnitQuickPickItem[] = result.candidates.map(candidate => {
const editorPath: string = getEditorPath(candidate);
const relativePath: string = vscode.workspace.asRelativePath(vscode.Uri.file(editorPath));
const directory: string = path.dirname(relativePath);
const isCurrent: boolean = editorPath === currentTranslationUnit;
return {
label: `${isCurrent ? "$(check) " : ""}${path.basename(relativePath)}`,
description: isCurrent ? localize('current.translation.unit', 'Current translation unit') :
directory === "." ? undefined : directory,
detail: editorPath,
translationUnit: editorPath
};
});
const selection: TranslationUnitQuickPickItem | undefined = await vscode.window.showQuickPick(items, {
title: localize('select.translation.unit', 'Select a Translation Unit'),
placeHolder: localize('select.translation.unit.placeholder', 'Select a source file to use as the translation unit'),
matchOnDescription: true,
matchOnDetail: true
});
if (selection !== undefined) {
await client.selectTranslationUnit(activeEditor.document.uri, selection.translationUnit);
}
}

async function onSwitchHeaderSource(): Promise<void> {
const activeEditor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
if (!activeEditor || !util.isCpp(activeEditor.document)) {
Expand All @@ -487,16 +543,7 @@ async function onSwitchHeaderSource(): Promise<void> {
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;
}
});
targetFileName = getEditorPath(targetFileName);
const document: vscode.TextDocument = await vscode.workspace.openTextDocument(targetFileName);
await vscode.window.showTextDocument(document).then(undefined, logAndReturn.undefined);
} catch (e) {
Expand Down
Loading