Skip to content

Commit f80f755

Browse files
Decorate all active edit ranges
If a user selects multiple chunks of code with cmd-I, only the most recent chunk of code is decorated as a selection. This commit addresses that problem by changing setDecorations to addDecorations, and carefully tracking which ranges are currently active in the EditDecorationManager.
1 parent 11fa260 commit f80f755

File tree

2 files changed

+43
-5
lines changed

2 files changed

+43
-5
lines changed

extensions/vscode/src/commands.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ const getCommandsMap: (
569569
const range =
570570
args?.range ?? new vscode.Range(startFromCharZero, endAtCharLast);
571571

572-
editDecorationManager.setDecoration(editor, range);
572+
editDecorationManager.addDecorations(editor, [range]);
573573

574574
const rangeInFileWithContents = getRangeInFileWithContents(true, range);
575575

extensions/vscode/src/quickEdit/EditDecorationManager.ts

+42-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import vscode from "vscode";
22
class EditDecorationManager {
33
private _lastEditor: vscode.TextEditor | undefined;
44
private decorationType: vscode.TextEditorDecorationType;
5+
private activeRangesMap: Map<string, vscode.Range> = new Map(); // Store unique active ranges
56

67
constructor(context: vscode.ExtensionContext) {
78
this.decorationType = vscode.window.createTextEditorDecorationType({
@@ -23,18 +24,55 @@ class EditDecorationManager {
2324
);
2425
}
2526

26-
setDecoration(editor: vscode.TextEditor, range: vscode.Range) {
27-
if (this._lastEditor) {
28-
this._lastEditor.setDecorations(this.decorationType, []);
27+
// Converts each range to a unique string for storing in the map
28+
private rangeToString(range: vscode.Range): string {
29+
return `(${range.start.line},${range.start.character})-(${range.end.line},${range.end.character})`;
30+
}
31+
32+
// Checks if two ranges are adjacent or overlapping
33+
private rangesCoincide(range1: vscode.Range, range2: vscode.Range): boolean {
34+
return range1.start.isEqual(range2.start)
35+
|| range1.end.isEqual(range2.start)
36+
|| range2.end.isEqual(range1.start)
37+
|| !!range1.intersection(range2);
38+
}
39+
40+
// Merges new range with existing ranges in the map
41+
private mergeNewRange(newRange: vscode.Range): void {
42+
let mergedRange = newRange;
43+
const rangesToPrune: string[] = [];
44+
45+
for (const [key, existingRange] of this.activeRangesMap.entries()) {
46+
if (!this.rangesCoincide(mergedRange, existingRange)) continue;
47+
mergedRange = mergedRange.union(existingRange);
48+
rangesToPrune.push(key);
49+
}
50+
51+
for (const key of rangesToPrune) this.activeRangesMap.delete(key);
52+
this.activeRangesMap.set(this.rangeToString(mergedRange), mergedRange);
53+
}
54+
55+
// Adds a new decoration to the editor and merges it with existing ranges
56+
addDecorations(editor: vscode.TextEditor, ranges: vscode.Range[]): void {
57+
if (this._lastEditor?.document !== editor.document) {
58+
this.clear(); // Clear previous decorations if editor has changed
2959
}
30-
editor.setDecorations(this.decorationType, [range]);
3160
this._lastEditor = editor;
61+
62+
for (const range of ranges) this.mergeNewRange(range);
63+
64+
const activeRanges = Array.from(this.activeRangesMap.values());
65+
if (activeRanges.length === 0) return; // No ranges to highlight
66+
67+
// Update active ranges and apply decorations
68+
editor.setDecorations(this.decorationType, activeRanges);
3269
this.updateInEditMode(true);
3370
}
3471

3572
clear() {
3673
if (this._lastEditor) {
3774
this._lastEditor.setDecorations(this.decorationType, []);
75+
this.activeRangesMap.clear();
3876
this._lastEditor = undefined;
3977
this.updateInEditMode(false);
4078
}

0 commit comments

Comments
 (0)