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
24 changes: 24 additions & 0 deletions Extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,12 @@
"description": "%c_cpp.configuration.dimInactiveRegions.description%",
"scope": "resource"
},
"C_Cpp.autoFoldInactiveRegions": {
"type": "boolean",
"default": false,
"description": "%c_cpp.configuration.autoFoldInactiveRegions.description%",
"scope": "resource"
},
"C_Cpp.inactiveRegionOpacity": {
"type": "number",
"default": 0.55,
Expand Down Expand Up @@ -3999,6 +4005,16 @@
"title": "%c_cpp.command.toggleDimInactiveRegions.title%",
"category": "C/C++"
},
{
"command": "C_Cpp.FoldAllInactiveRegions",
"title": "%c_cpp.command.foldAllInactiveRegions.title%",
"category": "C/C++"
},
{
"command": "C_Cpp.UnfoldAllInactiveRegions",
"title": "%c_cpp.command.unfoldAllInactiveRegions.title%",
"category": "C/C++"
},
{
"command": "C_Cpp.ResetDatabase",
"title": "%c_cpp.command.resetDatabase.title%",
Expand Down Expand Up @@ -6552,6 +6568,14 @@
"command": "C_Cpp.ToggleDimInactiveRegions",
"when": "config.C_Cpp.intelliSenseEngine =~ /^[dD]efault$/"
},
{
"command": "C_Cpp.FoldAllInactiveRegions",
"when": "editorLangId =~ /^(c|(cuda-)?cpp)$/ && config.C_Cpp.intelliSenseEngine =~ /^[dD]efault$/ && config.C_Cpp.codeFolding =~ /^[eE]nabled$/"
},
{
"command": "C_Cpp.UnfoldAllInactiveRegions",
"when": "editorLangId =~ /^(c|(cuda-)?cpp)$/ && config.C_Cpp.intelliSenseEngine =~ /^[dD]efault$/ && config.C_Cpp.codeFolding =~ /^[eE]nabled$/"
},
{
"command": "C_Cpp.ResetDatabase",
"when": "!(config.C_Cpp.intelliSenseEngine =~ /^[dD]isabled$/)"
Expand Down
3 changes: 3 additions & 0 deletions Extension/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"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",
"c_cpp.command.foldAllInactiveRegions.title": "Fold All Inactive Regions",
"c_cpp.command.unfoldAllInactiveRegions.title": "Unfold All Inactive Regions",
"c_cpp.command.resetDatabase.title": "Reset IntelliSense Database",
"c_cpp.command.takeSurvey.title": "Take Survey",
"c_cpp.command.restartIntelliSenseForFile.title": "Restart IntelliSense for Active File",
Expand Down Expand Up @@ -486,6 +488,7 @@
"c_cpp.configuration.autocomplete.disabled.description": "Uses the word-based completion provided by Visual Studio Code.",
"c_cpp.configuration.errorSquiggles.description": "Controls whether suspected compile errors detected by the IntelliSense engine will be reported back to the editor. It also controls whether code analysis warnings are reported if includes can't be found. This setting is ignored by the Tag Parser engine.",
"c_cpp.configuration.dimInactiveRegions.description": "Controls whether inactive preprocessor blocks are colored differently than active code. This setting has no effect if IntelliSense is disabled or if using the Default High Contrast theme.",
"c_cpp.configuration.autoFoldInactiveRegions.description": "Controls whether inactive preprocessor blocks are automatically folded when a file is opened. This setting requires IntelliSense and code folding to be enabled.",
"c_cpp.configuration.inactiveRegionOpacity.markdownDescription": {
"message": "Controls the opacity of inactive preprocessor blocks. Scales between `0.1` and `1.0`. This setting only applies when inactive region dimming is enabled.",
"comment": [
Expand Down
155 changes: 121 additions & 34 deletions Extension/src/LanguageServer/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import { CustomConfigurationProvider1, getCustomConfigProviders, isSameProviderE
import { DataBinding } from './dataBinding';
import { cachedEditorConfigSettings, getEditorConfigSettings } from './editorConfig';
import { CppSourceStr, clients, configPrefix, initializeIntervalTimer, isWritingCrashCallStack, updateLanguageConfigurations, usesCrashHandler, watchForCrashes } from './extension';
import { InactiveRegion, InactiveRegionStore, getInactiveRegionStartLines } from './inactiveRegions';
import { LanguageClient } from './languageClient';
import { LocalizeStringParams, getLocaleId, getLocalizedString } from './localization';
import { PersistentFolderState, PersistentState, PersistentWorkspaceState } from './persistentState';
Expand Down Expand Up @@ -227,18 +228,13 @@ interface FileChangedParams extends WorkspaceFolderParams {
uri: string;
}

interface InputRegion {
startLine: number;
startColumn: number;
endLine: number;
endColumn: number;
}

interface DecorationRangesPair {
decoration: vscode.TextEditorDecorationType;
ranges: vscode.Range[];
}

type InactiveRegionFoldingOperation = 'fold' | 'unfold';

interface InternalSourceFileConfiguration extends SourceFileConfiguration {
compilerArgsLegacy?: string[];
}
Expand Down Expand Up @@ -362,7 +358,7 @@ export interface IntelliSenseResult {
uri: string;
fileVersion: number;
diagnostics: IntelliSenseDiagnostic[];
inactiveRegions: InputRegion[];
inactiveRegions: InactiveRegion[];
semanticTokens: SemanticToken[];
inlayHints: CppInlayHint[];
clearExistingDiagnostics: boolean;
Expand Down Expand Up @@ -806,6 +802,8 @@ export interface Client {
selectTranslationUnit(uri: vscode.Uri, translationUnit: string): Promise<void>;
updateActiveDocumentTextOptions(): void;
didChangeActiveEditor(editor?: vscode.TextEditor, selection?: Range): Promise<void>;
foldAllInactiveRegions(): Promise<void>;
unfoldAllInactiveRegions(): Promise<void>;
restartIntelliSenseForFile(document: vscode.TextDocument): Promise<void>;
activate(): void;
selectionChanged(selection: Range): Promise<void>;
Expand Down Expand Up @@ -886,6 +884,9 @@ export class DefaultClient implements Client {
private workspaceStoragePath: string;
private trackedDocuments = new Map<string, vscode.TextDocument>();
private inactiveRegionsDecorations = new Map<string, DecorationRangesPair>();
private inactiveRegions = new InactiveRegionStore();
private pendingInactiveRegionFoldingOperations = new Map<string, InactiveRegionFoldingOperation>();
private autoFoldedEditors = new WeakSet<vscode.TextEditor>();
private settingsTracker: SettingsTracker;
private loggingLevel: number = 1;
private configurationProvider?: string;
Expand Down Expand Up @@ -1476,7 +1477,8 @@ export class DefaultClient implements Client {
intelliSenseCachePath: util.resolveCachePath(settings.intelliSenseCachePath, this.AdditionalEnvironment),
intelliSenseCacheSize: settings.intelliSenseCacheSize,
intelliSenseMemoryLimit: settings.intelliSenseMemoryLimit,
dimInactiveRegions: settings.dimInactiveRegions,
// Native uses this flag to decide whether to report inactive ranges.
dimInactiveRegions: settings.dimInactiveRegions || settings.autoFoldInactiveRegions || settings.codeFolding,
suggestSnippets: settings.suggestSnippets,
legacyCompilerArgsBehavior: settings.legacyCompilerArgsBehavior,
defaultSystemIncludePath: settings.defaultSystemIncludePath,
Expand Down Expand Up @@ -1903,6 +1905,10 @@ export class DefaultClient implements Client {
void ui.ShowConfigureIntelliSenseButton(false, this, ConfigurationType.CompilerPath, showButtonSender);
}
}
if (changedSettings.autoFoldInactiveRegions !== undefined && vscode.window.activeTextEditor
&& clients.getClientFor(vscode.window.activeTextEditor.document.uri) === this) {
void this.tryApplyInactiveRegionFolding(vscode.window.activeTextEditor).catch(logAndReturn.undefined);
}
if (changedSettings.legacyCompilerArgsBehavior !== undefined) {
this.configuration.handleConfigurationChange();
}
Expand Down Expand Up @@ -1997,7 +2003,9 @@ export class DefaultClient implements Client {
const oldVersion: number | undefined = openFileVersions.get(textDocumentChangeEvent.document.uri.toString());
const newVersion: number = textDocumentChangeEvent.document.version;
if (oldVersion === undefined || newVersion > oldVersion) {
openFileVersions.set(textDocumentChangeEvent.document.uri.toString(), newVersion);
const uri: string = textDocumentChangeEvent.document.uri.toString();
openFileVersions.set(uri, newVersion);
this.inactiveRegions.delete(uri);
}
}
}
Expand All @@ -2006,6 +2014,8 @@ export class DefaultClient implements Client {
if (document.uri.scheme === "file") {
const uri: string = document.uri.toString();
openFileVersions.set(uri, document.version);
this.inactiveRegions.delete(uri);
this.pendingInactiveRegionFoldingOperations.delete(uri);
}
}

Expand All @@ -2017,6 +2027,8 @@ export class DefaultClient implements Client {
if (this.inlayHintsProvider) {
this.inlayHintsProvider.removeFile(uri);
}
this.inactiveRegions.delete(uri);
this.pendingInactiveRegionFoldingOperations.delete(uri);
this.inactiveRegionsDecorations.delete(uri);
if (diagnosticsCollectionIntelliSense) {
diagnosticsCollectionIntelliSense.delete(document.uri);
Expand Down Expand Up @@ -2615,7 +2627,8 @@ export class DefaultClient implements Client {
this.inlayHintsProvider.deliverInlayHints(intelliSenseResult.uri, intelliSenseResult.inlayHints, intelliSenseResult.clearExistingInlayHint);
}

this.updateInactiveRegions(intelliSenseResult.uri, intelliSenseResult.inactiveRegions, intelliSenseResult.clearExistingInactiveRegions);
this.updateInactiveRegions(intelliSenseResult.uri, intelliSenseResult.inactiveRegions,
intelliSenseResult.clearExistingInactiveRegions, intelliSenseResult.isCompletePass);
if (intelliSenseResult.clearExistingDiagnostics || intelliSenseResult.diagnostics.length > 0) {
this.updateSquiggles(intelliSenseResult.uri, intelliSenseResult.diagnostics, intelliSenseResult.clearExistingDiagnostics);
}
Expand Down Expand Up @@ -2927,11 +2940,13 @@ export class DefaultClient implements Client {
this.model.isParsingWorkspacePaused.Value = tagParseStatus.isPaused;
}

private updateInactiveRegions(uriString: string, inactiveRegions: InputRegion[], startNewSet: boolean): void {
private updateInactiveRegions(uriString: string, inactiveRegions: InactiveRegion[], startNewSet: boolean, isCompletePass: boolean): void {
const client: Client = clients.getClientFor(vscode.Uri.parse(uriString));
if (!(client instanceof DefaultClient) || (!startNewSet && inactiveRegions.length === 0)) {
if (!(client instanceof DefaultClient) || (!startNewSet && inactiveRegions.length === 0 && !isCompletePass)) {
return;
}
client.inactiveRegions.update(uriString, inactiveRegions, startNewSet, isCompletePass);

const settings: CppSettings = new CppSettings(client.RootUri);
const dimInactiveRegions: boolean = settings.dimInactiveRegions;
let currentSet: DecorationRangesPair | undefined = this.inactiveRegionsDecorations.get(uriString);
Expand All @@ -2940,32 +2955,101 @@ export class DefaultClient implements Client {
currentSet.decoration.dispose();
this.inactiveRegionsDecorations.delete(uriString);
}
if (!dimInactiveRegions) {
return;
}
currentSet = undefined;
}
if (currentSet === undefined) {
const opacity: number | undefined = settings.inactiveRegionOpacity;
currentSet = {
decoration: vscode.window.createTextEditorDecorationType({
opacity: (opacity === undefined) ? "0.55" : opacity.toString(),
backgroundColor: settings.inactiveRegionBackgroundColor,
color: settings.inactiveRegionForegroundColor,
rangeBehavior: vscode.DecorationRangeBehavior.OpenOpen
}),
ranges: []
};
this.inactiveRegionsDecorations.set(uriString, currentSet);
if (dimInactiveRegions) {
if (currentSet === undefined) {
const opacity: number | undefined = settings.inactiveRegionOpacity;
currentSet = {
decoration: vscode.window.createTextEditorDecorationType({
opacity: (opacity === undefined) ? "0.55" : opacity.toString(),
backgroundColor: settings.inactiveRegionBackgroundColor,
color: settings.inactiveRegionForegroundColor,
rangeBehavior: vscode.DecorationRangeBehavior.OpenOpen
}),
ranges: []
};
this.inactiveRegionsDecorations.set(uriString, currentSet);
}

Array.prototype.push.apply(currentSet.ranges, inactiveRegions.map(element =>
new vscode.Range(element.startLine, element.startColumn, element.endLine, element.endColumn)));

// Apply the decorations to all *visible* text editors
const editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === uriString);
for (const e of editors) {
e.setDecorations(currentSet.decoration, currentSet.ranges);
}
}

const activeEditor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
if (isCompletePass && activeEditor?.document.uri.toString() === uriString) {
void client.tryApplyInactiveRegionFolding(activeEditor).catch(logAndReturn.undefined);
}
}

public foldAllInactiveRegions(): Promise<void> {
return this.applyInactiveRegionFolding('fold');
}

public unfoldAllInactiveRegions(): Promise<void> {
return this.applyInactiveRegionFolding('unfold');
}

private async applyInactiveRegionFolding(operation: InactiveRegionFoldingOperation): Promise<void> {
const editor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
if (!editor || !util.isCpp(editor.document)) {
return;
}

this.pendingInactiveRegionFoldingOperations.set(editor.document.uri.toString(), operation);
await this.tryApplyInactiveRegionFolding(editor);
}

private async tryApplyInactiveRegionFolding(editor: vscode.TextEditor): Promise<void> {
if (vscode.window.activeTextEditor !== editor || !util.isCpp(editor.document)) {
return;
}

const uri: string = editor.document.uri.toString();
const inactiveRegions: readonly InactiveRegion[] | undefined = this.inactiveRegions.getComplete(uri);
if (inactiveRegions === undefined) {
return;
}

Array.prototype.push.apply(currentSet.ranges, inactiveRegions.map(element =>
new vscode.Range(element.startLine, element.startColumn, element.endLine, element.endColumn)));
const settings: CppSettings = new CppSettings(editor.document.uri);
const autoFold: boolean = settings.autoFoldInactiveRegions && settings.codeFolding
&& !this.autoFoldedEditors.has(editor);
const pendingOperation: InactiveRegionFoldingOperation | undefined =
this.pendingInactiveRegionFoldingOperations.get(uri);
const operation: InactiveRegionFoldingOperation | undefined = pendingOperation ?? (autoFold ? 'fold' : undefined);
if (operation === undefined) {
return;
}

this.pendingInactiveRegionFoldingOperations.delete(uri);

const selectionLines: number[] = getInactiveRegionStartLines(inactiveRegions);
if (selectionLines.length === 0) {
return;
}

// Apply the decorations to all *visible* text editors
const editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === uriString);
for (const e of editors) {
e.setDecorations(currentSet.decoration, currentSet.ranges);
if (autoFold) {
this.autoFoldedEditors.add(editor);
}
try {
await vscode.commands.executeCommand(`editor.${operation}`, {
selectionLines,
direction: 'down'
});
} catch (error) {
if (autoFold) {
this.autoFoldedEditors.delete(editor);
}
if (pendingOperation) {
this.pendingInactiveRegionFoldingOperations.set(uri, pendingOperation);
}
throw error;
}
}

Expand Down Expand Up @@ -3136,6 +3220,7 @@ export class DefaultClient implements Client {
return;
}

void this.tryApplyInactiveRegionFolding(editor).catch(logAndReturn.undefined);
this.updateActiveDocumentTextOptions();

const params: DidChangeActiveEditorParams = {
Expand Down Expand Up @@ -4447,6 +4532,8 @@ class NullClient implements Client {
selectTranslationUnit(uri: vscode.Uri, translationUnit: string): Promise<void> { return Promise.resolve(); }
updateActiveDocumentTextOptions(): void { }
didChangeActiveEditor(editor?: vscode.TextEditor): Promise<void> { return Promise.resolve(); }
foldAllInactiveRegions(): Promise<void> { return Promise.resolve(); }
unfoldAllInactiveRegions(): Promise<void> { return Promise.resolve(); }
restartIntelliSenseForFile(document: vscode.TextDocument): Promise<void> { return Promise.resolve(); }
activate(): void { }
selectionChanged(selection: Range): Promise<void> { return Promise.resolve(); }
Expand Down
Loading
Loading