Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved text selection by allowing multiple edit ranges to be highlighted #4725

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

GauravVBhambhani
Copy link

@GauravVBhambhani GauravVBhambhani commented Mar 19, 2025

Description

Text Selection: 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.

Additionally, overlapping or adjacent ranges are now merged seamlessly to prevent redundant highlights.

Screenshots

Screenshot 2025-03-19 at 12 44 14 PM

Granite.Code Issue #49
@halfline

@GauravVBhambhani GauravVBhambhani requested a review from a team as a code owner March 19, 2025 16:51
@GauravVBhambhani GauravVBhambhani requested review from tomasz-stefaniak and removed request for a team March 19, 2025 16:51
Copy link

netlify bot commented Mar 19, 2025

Deploy Preview for continuedev canceled.

Name Link
🔨 Latest commit 8699786
🔍 Latest deploy log https://app.netlify.com/sites/continuedev/deploys/67dc77958025ac00081f09a9

Copy link
Contributor

@halfline halfline left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey thanks for working on this. I love that you're just going through our todo list and clearing it out ! :-) You're very quick.

I haven't tried this yet, but I made a few suggestions. As always Nate and Dallin get final call, but here are my thoughts just doing a quick read through.

The commit message also needs work. The top line of a git commit message is supposed to be a summary line that doesn't get much longer than 50 characters.

I'd suggest something like:

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.

Comment on lines 5 to 6
private activeRanges: vscode.Range[] = []; // Store active ranges to be highlighted
private activeRangeSet: Set<string> = new Set(); // Store active ranges as strings to avoid duplicates
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be a little cleaner to combine these into a single map instead

    private activeRangesMap: Map<string, vscode.Range> = new Map();

setDecoration(editor: vscode.TextEditor, range: vscode.Range) {
if (this._lastEditor) {
this._lastEditor.setDecorations(this.decorationType, []);
// converting each range to a unique string for storing in set
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Converts each range to a unique string for storing in the map

this._lastEditor.setDecorations(this.decorationType, []);
// converting each range to a unique string for storing in set
private rangeToString(range: vscode.Range): string {
return `${range.start.line}:${range.start.character}-${range.end.line}:${range.end.character}`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like some slightly different punctuation could make this clearer in console.log output or whatever...e.g, you have

1:1-4:80

but

(1,1)-(4,80)

would look a little clearer. doesn't really matter, but just food for though for later debugging sanity :-)

return `${range.start.line}:${range.start.character}-${range.end.line}:${range.end.character}`;
}

setDecoration(editor: vscode.TextEditor, ranges: vscode.Range[]): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"set" usually means "replace" but this function augments not replaces now.should probably be renamed addDecorations

Comment on lines 39 to 53
// Filter out already highlighted ranges
const newRanges = ranges.filter(range => {
const rangeKey = this.rangeToString(range);
if (this.activeRangeSet.has(rangeKey)) {
return false; // already highlighted
}
this.activeRangeSet.add(rangeKey);
return true;
});

if (newRanges.length === 0) return; // No new ranges to highlight

// Update active ranges and apply decorations
this.activeRanges.push(...newRanges);
editor.setDecorations(this.decorationType, this.activeRanges);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't really handle overlapping ranges right I think.

I think you need some code like this (assuming we switch to the map as suggested above):

  private rangesCoincide(a: vscode.Range, b: vscode.Range): boolean {
    if (a.end.isEqual(b.start)) return true;
    if (b.end.isEqual(a.start)) return true;
    if (a.intersection(b)) return true;
    return false;
  }

  private mergeNewRange(newRange: vscode.Range): void {
    let mergedRange = newRange;
    const rangesToPrune: string[] = [];

    for (const [key, existingRange] of this.activeRangesMap.entries()) {
      if (!this.rangesCoincide(merged, existingRange)) continue;
      mergedRange = mergedRange.union(existingRange);
      rangesToPrune.push(key);
    }

    for (const key of rangesToPrune) this.activeRangesMap.delete(key);

    this.activeRangesMap.set(this.rangeToString(mergedRange), mergedRange);
  }

and then here like

    for (const range of ranges) this.mergeNewRange(range);

    const activeRanges = Array.from(this.activeRangesMap.values());
    if (activeRanges.length === 0) return; // No new ranges to highlight
    editor.setDecorations(this.decorationType, activeRanges);

or something like that.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You pretty much fixed the whole thing😂, but thank you! Got to learn a few things. Appreciate it! 😊

@GauravVBhambhani GauravVBhambhani force-pushed the multiple-range-highlighting branch from 5a91e51 to fb03412 Compare March 20, 2025 18:33
this._lastEditor.setDecorations(this.decorationType, []);
// Converts each range to a unique string for storing in the map
private rangeToString(range: vscode.Range): string {
return `(${range.start.line},${range.start.character}-${range.end.line},${range.end.character})`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would still bracket it differently... like:

 return `(${range.start.line},${range.start.character})-(${range.end.line},${range.end.character})`;

so dev reading logs knows immediately it's (a,b)-(c,d), not (a, b-c, d)

}

// Adds a new decoration to the editor and merges it with existing ranges
addDecoration(editor: vscode.TextEditor, ranges: vscode.Range[]): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would make this plural since it's takes an array of ranges and could end up with more than one

@GauravVBhambhani GauravVBhambhani force-pushed the multiple-range-highlighting branch from 744df41 to f80f755 Compare March 20, 2025 19:20
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.

Additionally, overlapping or adjacent ranges are now merged seamlessly to prevent redundant highlights.
@GauravVBhambhani GauravVBhambhani force-pushed the multiple-range-highlighting branch from 0cb7648 to 8699786 Compare March 20, 2025 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants