Skip to content

Commit d464dba

Browse files
authored
Merge pull request #374 from edgardmessias/delete_unversioned
feat: Added context menu to delete unversioned files (Close #364)
2 parents 2139b9c + c85a345 commit d464dba

File tree

3 files changed

+82
-9
lines changed

3 files changed

+82
-9
lines changed

package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,11 @@
278278
"command": "svn.treeview.pullIncomingChange",
279279
"title": "Pull selected changes",
280280
"category": "SVN"
281+
},
282+
{
283+
"command": "svn.deleteUnversioned",
284+
"title": "Delete selected files",
285+
"category": "SVN"
281286
}
282287
],
283288
"menus": {
@@ -381,6 +386,10 @@
381386
{
382387
"command": "svn.renameExplorer",
383388
"when": "false"
389+
},
390+
{
391+
"command": "svn.deleteUnversioned",
392+
"when": "false"
384393
}
385394
],
386395
"view/title": [
@@ -538,6 +547,11 @@
538547
"when": "config.svn.enabled && scmProvider == svn && scmResourceGroup != unversioned && scmResourceGroup != external && scmResourceGroup != conflicts && scmResourceGroup != remotechanged",
539548
"group": "2_modification"
540549
},
550+
{
551+
"command": "svn.deleteUnversioned",
552+
"when": "config.svn.enabled && scmProvider == svn && scmResourceGroup == unversioned",
553+
"group": "2_modification"
554+
},
541555
{
542556
"command": "svn.addToIgnoreSCM",
543557
"when": "config.svn.enabled && scmProvider == svn && scmResourceGroup == unversioned",

src/commands.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { Svn, svnErrorCodes } from "./svn";
4343
import IncomingChangeNode from "./treeView/nodes/incomingChangeNode";
4444
import { fromSvnUri, toSvnUri } from "./uri";
4545
import {
46+
deleteDirectory,
4647
fixPathSeparator,
4748
hasSupportToRegisterDiffCommand,
4849
IDisposable
@@ -1511,6 +1512,44 @@ export class SvnCommands implements IDisposable {
15111512
}
15121513
}
15131514

1515+
@command("svn.deleteUnversioned")
1516+
public async deleteUnversioned(
1517+
...resourceStates: SourceControlResourceState[]
1518+
): Promise<void> {
1519+
const selection = this.getResourceStates(resourceStates);
1520+
1521+
if (selection.length === 0) {
1522+
return;
1523+
}
1524+
1525+
const uris = selection.map(resource => resource.resourceUri);
1526+
1527+
const answer = await window.showWarningMessage(
1528+
"Would you like delete the files?.",
1529+
{ modal: true },
1530+
"Yes",
1531+
"No"
1532+
);
1533+
1534+
if (answer === "Yes") {
1535+
for (const uri of uris) {
1536+
const fsPath = uri.fsPath;
1537+
1538+
if (!fs.existsSync(fsPath)) {
1539+
continue;
1540+
}
1541+
1542+
const stat = fs.lstatSync(fsPath);
1543+
1544+
if (stat.isDirectory()) {
1545+
deleteDirectory(fsPath);
1546+
} else {
1547+
fs.unlinkSync(fsPath);
1548+
}
1549+
}
1550+
}
1551+
}
1552+
15141553
private getSCMResource(uri?: Uri): Resource | undefined {
15151554
uri = uri
15161555
? uri

src/util.ts

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { sep } from "path";
1+
import * as fs from "fs";
2+
import * as path from "path";
23
import { commands, Event, window } from "vscode";
34
import { Operation } from "./common/types";
45

@@ -68,10 +69,10 @@ export function eventToPromise<T>(event: Event<T>): Promise<T> {
6869
return new Promise<T>(c => onceEvent(event)(c));
6970
}
7071

71-
const regexNormalizePath = new RegExp(sep === "/" ? "\\\\" : "/", "g");
72+
const regexNormalizePath = new RegExp(path.sep === "/" ? "\\\\" : "/", "g");
7273
const regexNormalizeWindows = new RegExp("^\\\\(\\w:)", "g");
7374
export function fixPathSeparator(file: string) {
74-
file = file.replace(regexNormalizePath, sep);
75+
file = file.replace(regexNormalizePath, path.sep);
7576
file = file.replace(regexNormalizeWindows, "$1"); // "\t:\test" => "t:\test"
7677
return file;
7778
}
@@ -80,19 +81,19 @@ export function normalizePath(file: string) {
8081
file = fixPathSeparator(file);
8182

8283
// IF Windows
83-
if (sep === "\\") {
84+
if (path.sep === "\\") {
8485
file = file.toLowerCase();
8586
}
8687

8788
return file;
8889
}
8990

9091
export function isDescendant(parent: string, descendant: string): boolean {
91-
parent = parent.replace(/[\\\/]/g, sep);
92-
descendant = descendant.replace(/[\\\/]/g, sep);
92+
parent = parent.replace(/[\\\/]/g, path.sep);
93+
descendant = descendant.replace(/[\\\/]/g, path.sep);
9394

9495
// IF Windows
95-
if (sep === "\\") {
96+
if (path.sep === "\\") {
9697
parent = parent.replace(/^\\/, "").toLowerCase();
9798
descendant = descendant.replace(/^\\/, "").toLowerCase();
9899
}
@@ -101,8 +102,8 @@ export function isDescendant(parent: string, descendant: string): boolean {
101102
return true;
102103
}
103104

104-
if (parent.charAt(parent.length - 1) !== sep) {
105-
parent += sep;
105+
if (parent.charAt(parent.length - 1) !== path.sep) {
106+
parent += path.sep;
106107
}
107108

108109
return descendant.startsWith(parent);
@@ -161,3 +162,22 @@ export function isReadOnly(operation: Operation): boolean {
161162
return false;
162163
}
163164
}
165+
166+
/**
167+
* Remove directory recursively
168+
* @param {string} dirPath
169+
* @see https://stackoverflow.com/a/42505874/3027390
170+
*/
171+
export function deleteDirectory(dirPath: string) {
172+
if (fs.existsSync(dirPath) && fs.lstatSync(dirPath).isDirectory()) {
173+
fs.readdirSync(dirPath).forEach((entry: string) => {
174+
const entryPath = path.join(dirPath, entry);
175+
if (fs.lstatSync(entryPath).isDirectory()) {
176+
deleteDirectory(entryPath);
177+
} else {
178+
fs.unlinkSync(entryPath);
179+
}
180+
});
181+
fs.rmdirSync(dirPath);
182+
}
183+
}

0 commit comments

Comments
 (0)