Skip to content

Commit d95aea2

Browse files
committed
feat: add support for multiline selections in new findings and partially reviewed regions
1 parent 0f0d8d9 commit d95aea2

File tree

1 file changed

+92
-75
lines changed

1 file changed

+92
-75
lines changed

src/codeMarker.ts

Lines changed: 92 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -721,93 +721,97 @@ class WARoot {
721721
addPartiallyAudited(relativePath: string): void {
722722
// check if file is already in list
723723
const index = this.auditedFiles.findIndex((file) => file.path === relativePath);
724-
725724
// if file is already audited ignore
726725
if (index > -1) {
727726
return;
728727
}
729728

730-
const location = this.getActiveSelectionLocation();
731-
const alreadyMarked = this.partiallyAuditedFiles.findIndex(
732-
(file) => file.path === relativePath && file.startLine <= location.startLine && file.endLine >= location.endLine,
733-
);
729+
const locations = this.getActiveSelectionLocation();
734730

735-
// this section is already marked. Remove it then
736-
if (alreadyMarked > -1) {
737-
// Splits the existing entry into 2 and remove the location marked by the user
738-
const previousMarkedEntry = this.partiallyAuditedFiles[alreadyMarked];
731+
// Process each selection/location separately
732+
for (const location of locations) {
733+
const alreadyMarked = this.partiallyAuditedFiles.findIndex(
734+
(file) => file.path === relativePath && file.startLine <= location.startLine && file.endLine >= location.endLine,
735+
);
739736

740-
// same area has been selected so lets delete it
741-
if (previousMarkedEntry.startLine === location.startLine && previousMarkedEntry.endLine === location.endLine) {
742-
this.partiallyAuditedFiles.splice(alreadyMarked, 1);
743-
} else {
744-
// not the same area so we need to split the entry or change it
737+
// this section is already marked. Remove it then
738+
if (alreadyMarked > -1) {
739+
// Splits the existing entry into 2 and remove the location marked by the user
740+
const previousMarkedEntry = this.partiallyAuditedFiles[alreadyMarked];
745741

746-
const locationClone = { ...previousMarkedEntry };
742+
// same area has been selected so lets delete it
743+
if (previousMarkedEntry.startLine === location.startLine && previousMarkedEntry.endLine === location.endLine) {
744+
this.partiallyAuditedFiles.splice(alreadyMarked, 1);
745+
} else {
746+
// not the same area so we need to split the entry or change it
747747

748-
// if either the end line or the start line is the same we don't need
749-
// to split the entry but can just adjust the current one
750-
let splitNeeded = true;
751-
if (previousMarkedEntry.endLine === location.endLine) {
752-
previousMarkedEntry.endLine = location.startLine - 1;
753-
splitNeeded = false;
754-
}
748+
const locationClone = { ...previousMarkedEntry };
755749

756-
if (previousMarkedEntry.startLine === location.startLine) {
757-
previousMarkedEntry.startLine = location.endLine + 1;
758-
splitNeeded = false;
759-
}
750+
// if either the end line or the start line is the same we don't need
751+
// to split the entry but can just adjust the current one
752+
let splitNeeded = true;
753+
if (previousMarkedEntry.endLine === location.endLine) {
754+
previousMarkedEntry.endLine = location.startLine - 1;
755+
splitNeeded = false;
756+
}
760757

761-
if (splitNeeded) {
762-
previousMarkedEntry.endLine = location.startLine - 1;
763-
locationClone.startLine = location.endLine + 1;
758+
if (previousMarkedEntry.startLine === location.startLine) {
759+
previousMarkedEntry.startLine = location.endLine + 1;
760+
splitNeeded = false;
761+
}
764762

765-
this.partiallyAuditedFiles.push(locationClone);
766-
}
763+
if (splitNeeded) {
764+
previousMarkedEntry.endLine = location.startLine - 1;
765+
locationClone.startLine = location.endLine + 1;
766+
767+
this.partiallyAuditedFiles.push(locationClone);
768+
}
767769

768-
this.partiallyAuditedFiles[alreadyMarked] = previousMarkedEntry;
770+
this.partiallyAuditedFiles[alreadyMarked] = previousMarkedEntry;
771+
}
772+
} else {
773+
this.partiallyAuditedFiles.push({
774+
path: relativePath,
775+
author: this.username,
776+
startLine: location.startLine,
777+
endLine: location.endLine,
778+
});
769779
}
770-
} else {
771-
this.partiallyAuditedFiles.push({
772-
path: relativePath,
773-
author: this.username,
774-
startLine: location.startLine,
775-
endLine: location.endLine,
776-
});
777780
}
778781

779782
this.mergePartialAudits();
780783
}
781784

782785
/**
783-
* Gets the active selection location.
784-
* @returns A Location corresponding to the active selection location.
786+
* Gets the active selection locations, supporting multiple selections.
787+
* @returns An array of FullLocations corresponding to all active selections.
785788
*/
786-
getActiveSelectionLocation(): FullLocation {
789+
getActiveSelectionLocation(): FullLocation[] {
787790
// the null assertion is never undefined because we check if the editor is undefined
788791
const editor = vscode.window.activeTextEditor!;
789792
const uri = editor.document.uri;
793+
const relativePath = path.relative(this.rootPath, uri.fsPath);
790794

791-
const selectedCode = editor.selection;
792-
const startLine = selectedCode.start.line;
795+
return editor.selections.map((selection) => {
796+
const startLine = selection.start.line;
797+
let endLine = selection.end.line;
793798

794-
let endLine = selectedCode.end.line;
795-
// vscode sets the end of a fully selected line as the first character of the next line
796-
// so we decrement the end line if the end character is 0 and the end line is not the same as the start line
797-
if (endLine > selectedCode.start.line && selectedCode.end.character === 0) {
798-
endLine--;
799-
}
799+
// vscode sets the end of a fully selected line as the first character of the next line
800+
// so we decrement the end line if the end character is 0 and the end line is not the same as the start line
801+
if (endLine > selection.start.line && selection.end.character === 0) {
802+
endLine--;
803+
}
800804

801-
// github preview does not show the preview if the last document line is empty
802-
// so we decrement it by one
803-
if (endLine === editor.document.lineCount - 1 && editor.document.lineAt(endLine).text === "") {
804-
// ensure that we don't go before the start line
805-
endLine = Math.max(endLine - 1, startLine);
806-
}
805+
// github preview does not show the preview if the last document line is empty
806+
// so we decrement it by one
807+
if (endLine === editor.document.lineCount - 1 && editor.document.lineAt(endLine).text === "") {
808+
// ensure that we don't go before the start line
809+
endLine = Math.max(endLine - 1, startLine);
810+
}
807811

808-
const relativePath = path.relative(this.rootPath, uri.fsPath);
809-
// TODO: error if not in this workspace root?
810-
return { path: relativePath, startLine, endLine, label: "", description: "", rootPath: this.rootPath };
812+
// TODO: error if not in this workspace root?
813+
return { path: relativePath, startLine, endLine, label: "", description: "", rootPath: this.rootPath };
814+
});
811815
}
812816

813817
/**
@@ -1466,7 +1470,7 @@ class MultiRootManager {
14661470
* @param uri The uri of the current file.
14671471
* @returns A FullLocation corresponding to the selection or undefined if the current file is not in any workspace root.
14681472
*/
1469-
getActiveSelectionLocation(uri: vscode.Uri): FullLocation | undefined {
1473+
getActiveSelectionLocation(uri: vscode.Uri): FullLocation[] | undefined {
14701474
const [wsRoot, _relativePath] = this.getCorrespondingRootAndPath(uri.fsPath);
14711475
const result = wsRoot?.getActiveSelectionLocation();
14721476
if (result === undefined) {
@@ -2086,10 +2090,13 @@ export class CodeMarker implements vscode.TreeDataProvider<TreeEntry> {
20862090
}
20872091

20882092
async getSelectedClientCodeAndPermalink(): Promise<FromLocationResponse | void> {
2089-
const location = this.getActiveSelectionLocation();
2090-
if (location === undefined) {
2093+
const locations = this.getActiveSelectionLocation();
2094+
if (locations === undefined || locations.length === 0) {
20912095
return;
20922096
}
2097+
2098+
// Use the first (primary) selection if more than one is present
2099+
const location = locations[0];
20932100
const editor = vscode.window.activeTextEditor!;
20942101

20952102
const remoteAndPermalink = await this.getRemoteAndPermalink(Repository.Client, location);
@@ -2592,10 +2599,12 @@ export class CodeMarker implements vscode.TreeDataProvider<TreeEntry> {
25922599
* @param repository If the repository is the Audit repository or the Client repository
25932600
*/
25942601
async copySelectedCodePermalink(repository: Repository): Promise<void> {
2595-
const location = this.getActiveSelectionLocation();
2596-
if (location === undefined) {
2602+
const locations = this.getActiveSelectionLocation();
2603+
if (locations === undefined || locations.length === 0) {
25972604
return;
25982605
}
2606+
// Use the first selection
2607+
const location = locations[0];
25992608

26002609
const remoteAndPermalink = await this.getRemoteAndPermalink(repository, location);
26012610
if (remoteAndPermalink === undefined) {
@@ -2999,12 +3008,17 @@ export class CodeMarker implements vscode.TreeDataProvider<TreeEntry> {
29993008
return;
30003009
}
30013010
const uri = editor.document.uri;
3002-
const location = this.workspaces.getActiveSelectionLocation(uri);
3011+
const locations = this.workspaces.getActiveSelectionLocation(uri);
30033012

3004-
if (location === undefined) {
3013+
if (locations === undefined) {
30053014
vscode.window.showErrorMessage("Trying to add entries to a file outside this workspace: " + uri.fsPath);
30063015
return;
30073016
}
3017+
if (locations.length === 0) {
3018+
return;
3019+
}
3020+
3021+
const location = locations[0];
30083022

30093023
const intersectedIdx = this.getIntersectingTreeEntryIndex(location, entryType);
30103024

@@ -3026,7 +3040,7 @@ export class CodeMarker implements vscode.TreeDataProvider<TreeEntry> {
30263040
label: title,
30273041
entryType: entryType,
30283042
author: this.username,
3029-
locations: [location],
3043+
locations: locations,
30303044
details: createDefaultEntryDetails(),
30313045
};
30323046
this.treeEntries.push(entry);
@@ -3053,18 +3067,18 @@ export class CodeMarker implements vscode.TreeDataProvider<TreeEntry> {
30533067
this.refresh(uri);
30543068
}
30553069

3056-
getActiveSelectionLocation(): FullLocation | undefined {
3070+
getActiveSelectionLocation(): FullLocation[] | undefined {
30573071
// the null assertion is never undefined because we check if the editor is undefined
30583072
const editor = vscode.window.activeTextEditor!;
30593073
const uri = editor.document.uri;
3060-
const location = this.workspaces.getActiveSelectionLocation(uri);
3074+
const locations = this.workspaces.getActiveSelectionLocation(uri);
30613075

3062-
if (location === undefined) {
3076+
if (locations === undefined) {
30633077
vscode.window.showErrorMessage(`weAudit: Error determining location of selected code. Filepath: ${uri.fsPath} is not in any workspace root.`);
30643078
return;
30653079
}
30663080

3067-
return location;
3081+
return locations;
30683082
}
30693083

30703084
/**
@@ -3150,15 +3164,15 @@ export class CodeMarker implements vscode.TreeDataProvider<TreeEntry> {
31503164
if (editor === undefined) {
31513165
return;
31523166
}
3153-
const location = this.getActiveSelectionLocation();
3154-
if (location === undefined) {
3167+
const locations = this.getActiveSelectionLocation();
3168+
if (locations === undefined || locations.length === 0) {
31553169
return;
31563170
}
31573171

31583172
// create a quick pick to select the entry to add the region to
31593173
const items = this.treeEntries
31603174
.filter((entry) => {
3161-
if (entry.locations.length === 0 || entry.locations[0].rootPath !== location.rootPath) {
3175+
if (entry.locations.length === 0 || entry.locations[0].rootPath !== locations[0].rootPath) {
31623176
return false;
31633177
}
31643178
return true;
@@ -3186,7 +3200,10 @@ export class CodeMarker implements vscode.TreeDataProvider<TreeEntry> {
31863200
return;
31873201
}
31883202
const entry = pickItem.entry;
3189-
entry.locations.push(location);
3203+
// Add each selection as a separate region
3204+
for (const location of locations) {
3205+
entry.locations.push(location);
3206+
}
31903207
this.updateSavedData(entry.author);
31913208
this.decorateWithUri(editor.document.uri);
31923209
this.refresh(editor.document.uri);

0 commit comments

Comments
 (0)