Skip to content

Commit 02c983b

Browse files
edgardmessiasJohnstonCode
authored andcommitted
feat: Added support to revert from explorer (close #606) (#608)
1 parent 3b7e74b commit 02c983b

8 files changed

+154
-51
lines changed

package.json

+18
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,15 @@
304304
"dark": "icons/dark/clean.svg"
305305
}
306306
},
307+
{
308+
"command": "svn.revertExplorer",
309+
"title": "Revert with SVN",
310+
"category": "SVN",
311+
"icon": {
312+
"light": "icons/light/clean.svg",
313+
"dark": "icons/dark/clean.svg"
314+
}
315+
},
307316
{
308317
"command": "svn.revertAll",
309318
"title": "Revert All Changes",
@@ -483,6 +492,10 @@
483492
"command": "svn.revert",
484493
"when": "config.svn.enabled && svnOpenRepositoryCount != 0"
485494
},
495+
{
496+
"command": "svn.revertExplorer",
497+
"when": "false"
498+
},
486499
{
487500
"command": "svn.update",
488501
"when": "config.svn.enabled && svnOpenRepositoryCount != 0"
@@ -902,6 +915,11 @@
902915
"command": "svn.changelist",
903916
"group": "9_svn",
904917
"when": "config.svn.enabled && svnOpenRepositoryCount != 0"
918+
},
919+
{
920+
"command": "svn.revertExplorer",
921+
"group": "7_modification",
922+
"when": "config.svn.enabled && svnOpenRepositoryCount != 0"
905923
}
906924
]
907925
},

src/commands.ts

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { Resolved } from "./commands/resolved";
3737
import { Revert } from "./commands/revert";
3838
import { RevertAll } from "./commands/revertAll";
3939
import { RevertChange } from "./commands/revertChange";
40+
import { RevertExplorer } from "./commands/revertExplorer";
4041
import { RevertSelectedRanges } from "./commands/revertSelectedRanges";
4142
import { SwitchBranch } from "./commands/switchBranch";
4243
import { Update } from "./commands/update";
@@ -86,4 +87,5 @@ export function registerCommands(model: Model, disposables: Disposable[]) {
8687
disposables.push(new OpenHeadFile());
8788
disposables.push(new RevertAll());
8889
disposables.push(new PickCommitMessage());
90+
disposables.push(new RevertExplorer());
8991
}

src/commands/revert.ts

+6-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { SourceControlResourceState, window } from "vscode";
2-
import { SvnDepth } from "../common/types";
2+
import { checkAndPromptDepth, confirmRevert } from "../input/revert";
33
import { Command } from "./command";
44

55
export class Revert extends Command {
@@ -10,33 +10,17 @@ export class Revert extends Command {
1010
public async execute(...resourceStates: SourceControlResourceState[]) {
1111
const selection = await this.getResourceStates(resourceStates);
1212

13-
if (selection.length === 0) {
13+
if (selection.length === 0 || !(await confirmRevert())) {
1414
return;
1515
}
1616

17-
const yes = "Yes I'm sure";
18-
const answer = await window.showWarningMessage(
19-
"Are you sure? This will wipe all local changes.",
20-
{ modal: true },
21-
yes
22-
);
17+
const uris = selection.map(resource => resource.resourceUri);
18+
const depth = await checkAndPromptDepth(uris);
2319

24-
if (answer !== yes) {
20+
if (!depth) {
2521
return;
2622
}
2723

28-
const picks: any[] = [];
29-
30-
for (const depth in SvnDepth) {
31-
if (SvnDepth.hasOwnProperty(depth)) {
32-
picks.push({ label: depth, description: SvnDepth[depth] });
33-
}
34-
}
35-
36-
const placeHolder = "Select revert depth";
37-
const pick = await window.showQuickPick(picks, { placeHolder });
38-
const uris = selection.map(resource => resource.resourceUri);
39-
4024
await this.runByRepository(uris, async (repository, resources) => {
4125
if (!repository) {
4226
return;
@@ -45,7 +29,7 @@ export class Revert extends Command {
4529
const paths = resources.map(resource => resource.fsPath);
4630

4731
try {
48-
await repository.revert(paths, pick.label);
32+
await repository.revert(paths, depth);
4933
} catch (error) {
5034
console.log(error);
5135
window.showErrorMessage("Unable to revert");

src/commands/revertAll.ts

+6-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { SourceControlResourceGroup, window } from "vscode";
2-
import { SvnDepth } from "../common/types";
2+
import { checkAndPromptDepth, confirmRevert } from "../input/revert";
33
import { Command } from "./command";
44

55
export class RevertAll extends Command {
@@ -10,33 +10,17 @@ export class RevertAll extends Command {
1010
public async execute(resourceGroup: SourceControlResourceGroup) {
1111
const resourceStates = resourceGroup.resourceStates;
1212

13-
if (resourceStates.length === 0) {
13+
if (resourceStates.length === 0 || !(await confirmRevert())) {
1414
return;
1515
}
1616

17-
const yes = "Yes I'm sure";
18-
const answer = await window.showWarningMessage(
19-
"Are you sure? This will wipe all local changes.",
20-
{ modal: true },
21-
yes
22-
);
17+
const uris = resourceStates.map(resource => resource.resourceUri);
18+
const depth = await checkAndPromptDepth(uris);
2319

24-
if (answer !== yes) {
20+
if (!depth) {
2521
return;
2622
}
2723

28-
const picks: any[] = [];
29-
30-
for (const depth in SvnDepth) {
31-
if (SvnDepth.hasOwnProperty(depth)) {
32-
picks.push({ label: depth, description: SvnDepth[depth] });
33-
}
34-
}
35-
36-
const placeHolder = "Select revert depth";
37-
const pick = await window.showQuickPick(picks, { placeHolder });
38-
const uris = resourceStates.map(resource => resource.resourceUri);
39-
4024
await this.runByRepository(uris, async (repository, resources) => {
4125
if (!repository) {
4226
return;
@@ -45,7 +29,7 @@ export class RevertAll extends Command {
4529
const paths = resources.map(resource => resource.fsPath);
4630

4731
try {
48-
await repository.revert(paths, pick.label);
32+
await repository.revert(paths, depth);
4933
} catch (error) {
5034
console.log(error);
5135
window.showErrorMessage("Unable to revert");

src/commands/revertExplorer.ts

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Uri, window } from "vscode";
2+
import { checkAndPromptDepth, confirmRevert } from "../input/revert";
3+
import { Command } from "./command";
4+
5+
export class RevertExplorer extends Command {
6+
constructor() {
7+
super("svn.revertExplorer");
8+
}
9+
10+
public async execute(_mainUri?: Uri, allUris?: Uri[]) {
11+
if (!allUris) {
12+
return;
13+
}
14+
15+
const uris = allUris;
16+
if (uris.length === 0 || !(await confirmRevert())) {
17+
return;
18+
}
19+
20+
const depth = await checkAndPromptDepth(uris);
21+
22+
if (!depth) {
23+
return;
24+
}
25+
26+
await this.runByRepository(uris, async (repository, resources) => {
27+
if (!repository) {
28+
return;
29+
}
30+
31+
const paths = resources.map(resource => resource.fsPath);
32+
33+
try {
34+
await repository.revert(paths, depth);
35+
} catch (error) {
36+
console.log(error);
37+
window.showErrorMessage("Unable to revert");
38+
}
39+
});
40+
}
41+
}

src/input/revert.ts

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { Uri, window } from "vscode";
2+
import { SvnDepth } from "../common/types";
3+
import { lstat } from "../fs";
4+
5+
export async function confirmRevert() {
6+
const yes = "Yes I'm sure";
7+
const answer = await window.showWarningMessage(
8+
"Are you sure? This will wipe all local changes.",
9+
{ modal: true },
10+
yes
11+
);
12+
13+
if (answer !== yes) {
14+
return false;
15+
}
16+
17+
return true;
18+
}
19+
20+
export async function promptDepth() {
21+
const picks: any[] = [];
22+
23+
for (const depth in SvnDepth) {
24+
if (SvnDepth.hasOwnProperty(depth)) {
25+
picks.push({ label: depth, description: SvnDepth[depth] });
26+
}
27+
}
28+
29+
const placeHolder = "Select revert depth";
30+
const pick = await window.showQuickPick(picks, { placeHolder });
31+
if (!pick) {
32+
return undefined;
33+
}
34+
return pick.label;
35+
}
36+
37+
export async function checkAndPromptDepth(
38+
uris: Uri[],
39+
defaultDepth: keyof typeof SvnDepth = "empty"
40+
) {
41+
// Without uris, force prompt
42+
let hasDirectory = uris.length === 0;
43+
44+
for (const uri of uris) {
45+
if (uri.scheme !== "file") {
46+
continue;
47+
}
48+
try {
49+
const stat = await lstat(uri.fsPath);
50+
if (stat.isDirectory()) {
51+
hasDirectory = true;
52+
break;
53+
}
54+
} catch (error) {
55+
// ignore
56+
}
57+
}
58+
59+
if (hasDirectory) {
60+
return await promptDepth();
61+
}
62+
63+
return defaultDepth;
64+
}

src/repository.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -816,8 +816,10 @@ export class Repository implements IRemoteRepository {
816816
);
817817
}
818818

819-
public async revert(files: string[], depth: SvnDepth) {
820-
return this.run(Operation.Revert, () => this.repository.revert(files, depth));
819+
public async revert(files: string[], depth: keyof typeof SvnDepth) {
820+
return this.run(Operation.Revert, () =>
821+
this.repository.revert(files, depth)
822+
);
821823
}
822824

823825
public async info(path: string) {

src/svnRepository.ts

+13-5
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,8 @@ export class Repository {
184184
filePath = file;
185185
}
186186

187-
const isChild = uri.scheme === "file" && isDescendant(this.workspaceRoot, uri.fsPath);
187+
const isChild =
188+
uri.scheme === "file" && isDescendant(this.workspaceRoot, uri.fsPath);
188189

189190
let target: string = filePath;
190191

@@ -194,7 +195,10 @@ export class Repository {
194195

195196
if (revision) {
196197
args.push("-r", revision);
197-
if (isChild && !["BASE", "COMMITTED", "PREV"].includes(revision.toUpperCase())) {
198+
if (
199+
isChild &&
200+
!["BASE", "COMMITTED", "PREV"].includes(revision.toUpperCase())
201+
) {
198202
const info = await this.getInfo();
199203
target = info.url + "/" + target.replace(/\\/g, "/");
200204
// TODO move to SvnRI
@@ -292,9 +296,13 @@ export class Repository {
292296

293297
const matches = result.stdout.match(/Committed revision (.*)\./i);
294298
if (matches && matches[0]) {
295-
const sendedFiles = (result.stdout.match(/(Sending|Adding|Deleting)\s+/g) || []).length;
299+
const sendedFiles = (
300+
result.stdout.match(/(Sending|Adding|Deleting)\s+/g) || []
301+
).length;
296302

297-
const filesMessage = `${sendedFiles} ${sendedFiles === 1 ? "file" : "files"} commited`;
303+
const filesMessage = `${sendedFiles} ${
304+
sendedFiles === 1 ? "file" : "files"
305+
} commited`;
298306

299307
return `${filesMessage}: revision ${matches[1]}.`;
300308
}
@@ -453,7 +461,7 @@ export class Repository {
453461
return true;
454462
}
455463

456-
public async revert(files: string[], depth: SvnDepth) {
464+
public async revert(files: string[], depth: keyof typeof SvnDepth) {
457465
files = files.map(file => this.removeAbsolutePath(file));
458466
const result = await this.exec(["revert", "--depth", depth, ...files]);
459467
return result.stdout;

0 commit comments

Comments
 (0)