Skip to content

Commit 572f21a

Browse files
authored
Merge pull request #1482 from Microsoft/inactive-region-highlight
Inactive region highlight
2 parents 510094a + 0eae7fd commit 572f21a

File tree

4 files changed

+82
-4
lines changed

4 files changed

+82
-4
lines changed

Extension/.vscode/launch.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
1111
"stopOnEntry": false,
1212
"sourceMaps": true,
13-
"outDir": "${workspaceRoot}/out/src",
13+
"outFiles": ["${workspaceRoot}/out/src"],
1414
"preLaunchTask": "npm"
1515
},
1616
{
@@ -21,7 +21,7 @@
2121
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
2222
"stopOnEntry": false,
2323
"sourceMaps": true,
24-
"outDir": "${workspaceRoot}/out/test",
24+
"outFiles": ["${workspaceRoot}/out/test"],
2525
"preLaunchTask": "npm"
2626
},
2727
{

Extension/bin/msvc.64.darwin.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
"defaults": [
33
"--clang",
44
"--pack_alignment",
5-
"8",
6-
"--framework_include_directory=/System/Library/Frameworks"
5+
"8"
76
],
87
"defaults_op" : "merge"
98
}

Extension/src/LanguageServer/client.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ interface OutputNotificationBody {
6969
output: string;
7070
}
7171

72+
interface InactiveRegionParams {
73+
uri: string;
74+
ranges: vscode.Range[];
75+
}
76+
77+
interface DecorationRangesPair {
78+
decoration: vscode.TextEditorDecorationType;
79+
ranges: vscode.Range[];
80+
}
81+
7282
// Requests
7383
const NavigationListRequest: RequestType<TextDocumentIdentifier, string, void, void> = new RequestType<TextDocumentIdentifier, string, void, void>('cpptools/requestNavigationList');
7484
const GoToDeclarationRequest: RequestType<void, void, void, void> = new RequestType<void, void, void, void>('cpptools/goToDeclaration');
@@ -97,6 +107,7 @@ const ReportTagParseStatusNotification: NotificationType<ReportStatusNotificatio
97107
const ReportStatusNotification: NotificationType<ReportStatusNotificationBody, void> = new NotificationType<ReportStatusNotificationBody, void>('cpptools/reportStatus');
98108
const DebugProtocolNotification: NotificationType<OutputNotificationBody, void> = new NotificationType<OutputNotificationBody, void>('cpptools/debugProtocol');
99109
const DebugLogNotification: NotificationType<OutputNotificationBody, void> = new NotificationType<OutputNotificationBody, void>('cpptools/debugLog');
110+
const InactiveRegionNotification: NotificationType<InactiveRegionParams, void> = new NotificationType<InactiveRegionParams, void>('cpptools/inactiveRegions');
100111

101112
const maxSettingLengthForTelemetry: number = 50;
102113
let previousCppSettings: { [key: string]: any } = {};
@@ -159,6 +170,7 @@ export interface Client {
159170
Name: string;
160171
TrackedDocuments: Set<vscode.TextDocument>;
161172
onDidChangeSettings(): void;
173+
onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void;
162174
takeOwnership(document: vscode.TextDocument): void;
163175
requestGoToDeclaration(): Thenable<void>;
164176
requestSwitchHeaderSource(rootPath: string, fileName: string): Thenable<string>;
@@ -198,6 +210,7 @@ class DefaultClient implements Client {
198210
private crashTimes: number[] = [];
199211
private failureMessageShown = new PersistentState<boolean>("DefaultClient.failureMessageShown", false);
200212
private isSupported: boolean = true;
213+
private inactiveRegionsDecorations = new Map<string, DecorationRangesPair>();
201214

202215
// The "model" that is displayed via the UI (status bar).
203216
private model: ClientModel = {
@@ -382,6 +395,16 @@ class DefaultClient implements Client {
382395
}
383396
}
384397

398+
public onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void {
399+
//Apply text decorations to inactive regions
400+
for (let e of editors) {
401+
let valuePair: DecorationRangesPair = this.inactiveRegionsDecorations.get(e.document.uri.toString());
402+
if (valuePair) {
403+
e.setDecorations(valuePair.decoration, valuePair.ranges); // VSCode clears the decorations when the text editor becomes invisible
404+
}
405+
}
406+
}
407+
385408
/**
386409
* Take ownership of a document that was previously serviced by another client.
387410
* This process involves sending a textDocument/didOpen message to the server so
@@ -434,6 +457,7 @@ class DefaultClient implements Client {
434457
this.languageClient.onNotification(ReportNavigationNotification, (e) => this.navigate(e));
435458
this.languageClient.onNotification(ReportStatusNotification, (e) => this.updateStatus(e));
436459
this.languageClient.onNotification(ReportTagParseStatusNotification, (e) => this.updateTagParseStatus(e));
460+
this.languageClient.onNotification(InactiveRegionNotification, (e) => this.updateInactiveRegions(e));
437461
this.setupOutputHandlers();
438462
}
439463

@@ -620,6 +644,55 @@ class DefaultClient implements Client {
620644
this.model.tagParserStatus.Value = notificationBody.status;
621645
}
622646

647+
private updateInactiveRegions(params: InactiveRegionParams): void {
648+
let renderOptions: vscode.DecorationRenderOptions = {
649+
light: { color: "rgba(175,175,175,1.0)" },
650+
dark: { color: "rgba(155,155,155,1.0)" }
651+
};
652+
let decoration: vscode.TextEditorDecorationType = vscode.window.createTextEditorDecorationType(renderOptions);
653+
654+
// Recycle the active text decorations when we receive a new set of inactive regions
655+
let valuePair: DecorationRangesPair = this.inactiveRegionsDecorations.get(params.uri);
656+
if (valuePair) {
657+
// The language server will send notifications regardless of whether the ranges have changed
658+
if (!this.areRangesEqual(valuePair.ranges, params.ranges)) {
659+
// Disposing of and resetting the decoration will undo previously applied text decorations
660+
valuePair.decoration.dispose();
661+
valuePair.decoration = decoration;
662+
663+
// As vscode.TextEditor.setDecorations only applies to visible editors, we must cache the range for when another editor becomes visible
664+
valuePair.ranges = params.ranges;
665+
}
666+
} else { // The entry does not exist. Make a new one
667+
let toInsert: DecorationRangesPair = {
668+
decoration: decoration,
669+
ranges: params.ranges
670+
};
671+
this.inactiveRegionsDecorations.set(params.uri, toInsert);
672+
}
673+
674+
// Apply the decorations to all *visible* text editors
675+
let editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === params.uri);
676+
for (let e of editors) {
677+
e.setDecorations(decoration, params.ranges);
678+
}
679+
}
680+
681+
// Helper method to compare two ranges arrays for equality
682+
private areRangesEqual(r1: vscode.Range[], r2: vscode.Range[]): boolean {
683+
if (r1.length !== r2.length) {
684+
return false;
685+
}
686+
687+
for (let i: number = 0; i < r1.length; ++i) {
688+
if (!r1[i].isEqual(r2[i])) {
689+
return false;
690+
}
691+
}
692+
693+
return true;
694+
}
695+
623696
/*********************************************
624697
* requests to the language server
625698
*********************************************/
@@ -809,6 +882,7 @@ class NullClient implements Client {
809882
Name: string = "(empty)";
810883
TrackedDocuments = new Set<vscode.TextDocument>();
811884
onDidChangeSettings(): void {}
885+
onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void {}
812886
takeOwnership(document: vscode.TextDocument): void {}
813887
requestGoToDeclaration(): Thenable<void> { return Promise.resolve(); }
814888
requestSwitchHeaderSource(rootPath: string, fileName: string): Thenable<string> { return Promise.resolve(""); }

Extension/src/LanguageServer/extension.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ function realActivation(): void {
126126
disposables.push(vscode.workspace.onDidSaveTextDocument(onDidSaveTextDocument));
127127
disposables.push(vscode.window.onDidChangeActiveTextEditor(onDidChangeActiveTextEditor));
128128
disposables.push(vscode.window.onDidChangeTextEditorSelection(onDidChangeTextEditorSelection));
129+
disposables.push(vscode.window.onDidChangeVisibleTextEditors(onDidChangeVisibleTextEditors));
129130

130131
disposables.push(vscode.languages.setLanguageConfiguration('c', multilineCommentRules));
131132
disposables.push(vscode.languages.setLanguageConfiguration('cpp', multilineCommentRules));
@@ -189,6 +190,10 @@ function onDidChangeTextEditorSelection(event: vscode.TextEditorSelectionChangeE
189190
clients.ActiveClient.selectionChanged(event.selections[0].start);
190191
}
191192

193+
function onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void {
194+
clients.forEach(client => client.onDidChangeVisibleTextEditors(editors));
195+
}
196+
192197
function onInterval(): void {
193198
// TODO: do we need to pump messages to all clients? depends on what we do with the icons, I suppose.
194199
clients.ActiveClient.onInterval();

0 commit comments

Comments
 (0)