Skip to content

Commit 177bb0b

Browse files
YanpasJohnstonCode
authored andcommitted
feat: Add remove unversioned command (#769)
1 parent aba73cb commit 177bb0b

18 files changed

+129
-35
lines changed

package.json

+14-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"lint:fix": "npm run lint -- --fix",
4141
"lint": "eslint \"src/**/*.ts\"",
4242
"semantic-release": "semantic-release",
43-
"style-check": "npx prettylint src/**/*.ts",
43+
"style-check": "npx prettylint 'src/**/*.ts'",
4444
"test": "node ./out/test/runTest.js",
4545
"tools:genReadme": "node ./out/tools/generateConfigSectionForReadme.js",
4646
"vscode:prepublish": "npm run lint && npm run build",
@@ -401,6 +401,11 @@
401401
"title": "Clean up working copy",
402402
"category": "SVN"
403403
},
404+
{
405+
"command": "svn.removeUnversioned",
406+
"title": "Remove unversioned files",
407+
"category": "SVN"
408+
},
404409
{
405410
"command": "svn.patchChangeList",
406411
"title": "Show patch from changelist",
@@ -552,6 +557,10 @@
552557
"command": "svn.cleanup",
553558
"when": "config.svn.enabled && svnOpenRepositoryCount != 0"
554559
},
560+
{
561+
"command": "svn.removeUnversioned",
562+
"when": "config.svn.enabled && svnOpenRepositoryCount != 0 && isSvn19orGreater"
563+
},
555564
{
556565
"command": "svn.addToIgnoreExplorer",
557566
"when": "false"
@@ -752,6 +761,10 @@
752761
"command": "svn.cleanup",
753762
"when": "config.svn.enabled && scmProvider == svn"
754763
},
764+
{
765+
"command": "svn.removeUnversioned",
766+
"when": "config.svn.enabled && scmProvider == svn && isSvn19orGreater"
767+
},
755768
{
756769
"command": "svn.patchChangeList",
757770
"when": "config.svn.enabled && scmProvider == svn"

src/commands.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { PullIncommingChange } from "./commands/pullIncomingChange";
3030
import { Refresh } from "./commands/refresh";
3131
import { RefreshRemoteChanges } from "./commands/refreshRemoteChanges";
3232
import { Remove } from "./commands/remove";
33+
import { RemoveUnversioned } from "./commands/removeUnversioned";
3334
import { RenameExplorer } from "./commands/renameExplorer";
3435
import { Resolve } from "./commands/resolve";
3536
import { ResolveAll } from "./commands/resolveAll";
@@ -43,7 +44,10 @@ import { Update } from "./commands/update";
4344
import { Upgrade } from "./commands/upgrade";
4445
import { SourceControlManager } from "./source_control_manager";
4546

46-
export function registerCommands(sourceControlManager: SourceControlManager, disposables: Disposable[]) {
47+
export function registerCommands(
48+
sourceControlManager: SourceControlManager,
49+
disposables: Disposable[]
50+
) {
4751
disposables.push(new GetSourceControlManager(sourceControlManager));
4852
disposables.push(new FileOpen());
4953
disposables.push(new OpenFile());
@@ -71,6 +75,7 @@ export function registerCommands(sourceControlManager: SourceControlManager, dis
7175
disposables.push(new RevertChange());
7276
disposables.push(new Close());
7377
disposables.push(new Cleanup());
78+
disposables.push(new RemoveUnversioned());
7479
disposables.push(new FinishCheckout());
7580
disposables.push(new AddToIgnoreSCM());
7681
disposables.push(new AddToIgnoreExplorer());

src/commands/removeUnversioned.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Repository } from "../repository";
2+
import { Command } from "./command";
3+
import { window } from "vscode";
4+
5+
export class RemoveUnversioned extends Command {
6+
constructor() {
7+
super("svn.removeUnversioned", { repository: true });
8+
}
9+
10+
public async execute(repository: Repository) {
11+
const answer = await window.showWarningMessage(
12+
"Are you sure? This will remove all unversioned files except for ignored.",
13+
{ modal: true },
14+
"Yes",
15+
"No"
16+
);
17+
if (answer !== "Yes") {
18+
return;
19+
}
20+
await repository.removeUnversioned();
21+
}
22+
}

src/contexts/checkActiveEditor.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { commands, Disposable, window } from "vscode";
1+
import { Disposable, window } from "vscode";
22
import { Status } from "../common/types";
33
import { debounce } from "../decorators";
44
import { SourceControlManager } from "../source_control_manager";
5-
import { IDisposable } from "../util";
5+
import { IDisposable, setVscodeContext } from "../util";
66

77
export class CheckActiveEditor implements IDisposable {
88
private disposables: Disposable[] = [];
@@ -24,8 +24,7 @@ export class CheckActiveEditor implements IDisposable {
2424

2525
@debounce(100)
2626
private checkHasChangesOnActiveEditor() {
27-
commands.executeCommand(
28-
"setContext",
27+
setVscodeContext(
2928
"svnActiveEditorHasChanges",
3029
this.hasChangesOnActiveEditor()
3130
);

src/contexts/isSvn19orGreater.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Disposable } from "vscode";
2+
import * as semver from "semver";
3+
import { setVscodeContext } from "../util";
4+
5+
export class IsSvn19orGreater implements Disposable {
6+
constructor(svnVersion: string) {
7+
const is19orGreater = semver.satisfies(svnVersion, ">= 1.9");
8+
9+
setVscodeContext("isSvn19orGreater", is19orGreater);
10+
}
11+
12+
// eslint-disable-next-line @typescript-eslint/no-empty-function
13+
dispose() {}
14+
}

src/contexts/openRepositoryCount.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { commands, Disposable } from "vscode";
1+
import { Disposable } from "vscode";
22
import { debounce } from "../decorators";
33
import { SourceControlManager } from "../source_control_manager";
4-
import { IDisposable } from "../util";
4+
import { IDisposable, setVscodeContext } from "../util";
55

66
export class OpenRepositoryCount implements IDisposable {
77
private disposables: Disposable[] = [];
@@ -24,10 +24,9 @@ export class OpenRepositoryCount implements IDisposable {
2424

2525
@debounce(100)
2626
private checkOpened() {
27-
commands.executeCommand(
28-
"setContext",
27+
setVscodeContext(
2928
"svnOpenRepositoryCount",
30-
`${this.sourceControlManager.repositories.length}`
29+
this.sourceControlManager.repositories.length
3130
);
3231
}
3332

src/diffParser.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@ export async function parseDiffXml(content: string): Promise<ISvnPath[]> {
1414
tagNameProcessors: [camelcase]
1515
},
1616
(err, result) => {
17-
if (
18-
err ||
19-
!result.paths ||
20-
!result.paths.path
21-
) {
17+
if (err || !result.paths || !result.paths.path) {
2218
reject();
2319
}
2420

src/extension.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { SvnFinder } from "./svnFinder";
2222
import SvnProvider from "./treeView/dataProviders/svnProvider";
2323
import { toDisposable } from "./util";
2424
import { BranchChangesProvider } from "./historyView/branchChangesProvider";
25+
import { IsSvn19orGreater } from "./contexts/isSvn19orGreater";
2526

2627
async function init(
2728
_context: ExtensionContext,
@@ -33,7 +34,10 @@ async function init(
3334

3435
const info = await svnFinder.findSvn(pathHint);
3536
const svn = new Svn({ svnPath: info.path, version: info.version });
36-
const sourceControlManager = await new SourceControlManager(svn, ConstructorPolicy.Async);
37+
const sourceControlManager = await new SourceControlManager(
38+
svn,
39+
ConstructorPolicy.Async
40+
);
3741
const contentProvider = new SvnContentProvider(sourceControlManager);
3842

3943
registerCommands(sourceControlManager, disposables);
@@ -58,6 +62,7 @@ async function init(
5862

5963
disposables.push(new CheckActiveEditor(sourceControlManager));
6064
disposables.push(new OpenRepositoryCount(sourceControlManager));
65+
disposables.push(new IsSvn19orGreater(info.version));
6166

6267
outputChannel.appendLine(`Using svn "${info.version}" from "${info.path}"`);
6368

src/messages.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,11 @@ async function showCommitInput(message?: string, filePaths?: string[]) {
7878
Use a content security policy to only allow loading images from https or from our extension directory,
7979
and only allow scripts that have a specific nonce.
8080
-->
81-
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${panel.webview.cspSource} https:; script-src ${panel.webview.cspSource} 'unsafe-inline'; style-src ${panel.webview.cspSource};">
81+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${
82+
panel.webview.cspSource
83+
} https:; script-src ${panel.webview.cspSource} 'unsafe-inline'; style-src ${
84+
panel.webview.cspSource
85+
};">
8286
8387
<title>Commit Message</title>
8488
<link rel="stylesheet" href="${styleUri}">
@@ -178,7 +182,9 @@ async function showCommitInput(message?: string, filePaths?: string[]) {
178182
"svn.getSourceControlManager",
179183
""
180184
)) as SourceControlManager;
181-
repository = await sourceControlManager.getRepositoryFromUri(Uri.file(filePaths[0]));
185+
repository = await sourceControlManager.getRepositoryFromUri(
186+
Uri.file(filePaths[0])
187+
);
182188
}
183189

184190
const message = await commands.executeCommand(

src/repository.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,10 @@ export class Repository implements IRemoteRepository {
359359
}
360360

361361
if (actionForDeletedFiles === "remove") {
362-
return this.removeFiles(uris.map(uri => uri.fsPath), false);
362+
return this.removeFiles(
363+
uris.map(uri => uri.fsPath),
364+
false
365+
);
363366
} else if (actionForDeletedFiles === "prompt") {
364367
return commands.executeCommand("svn.promptRemove", ...uris);
365368
}
@@ -862,6 +865,12 @@ export class Repository implements IRemoteRepository {
862865
return this.run(Operation.CleanUp, () => this.repository.cleanup());
863866
}
864867

868+
public async removeUnversioned() {
869+
return this.run(Operation.CleanUp, () =>
870+
this.repository.removeUnversioned()
871+
);
872+
}
873+
865874
public async getInfo(path: string, revision?: string): Promise<ISvnInfo> {
866875
return this.run(Operation.Info, () =>
867876
this.repository.getInfo(path, revision, true)

src/resource.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export class Resource implements SourceControlResourceState {
8383
faded,
8484
tooltip,
8585
light,
86-
dark,
86+
dark
8787
};
8888
}
8989

src/statusParser.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ function processEntry(
1818
}
1919

2020
const wcStatus: IWcStatus = {
21-
locked: !!entry.wcStatus.wcLocked && entry.wcStatus.wcLocked === "true" || !!(entry.reposStatus && entry.reposStatus.lock),
21+
locked:
22+
(!!entry.wcStatus.wcLocked && entry.wcStatus.wcLocked === "true") ||
23+
!!(entry.reposStatus && entry.reposStatus.lock),
2224
switched: !!entry.wcStatus.switched && entry.wcStatus.switched === "true"
2325
};
2426

src/svn.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class Svn {
7171
this.svnPath = options.svnPath;
7272
}
7373

74-
private logOutput(output: string): void {
74+
public logOutput(output: string): void {
7575
this._onOutput.emit("log", output);
7676
}
7777

src/svnContentProvider.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ export class SvnContentProvider
4040

4141
constructor(private sourceControlManager: SourceControlManager) {
4242
this.disposables.push(
43-
sourceControlManager.onDidChangeRepository(this.onDidChangeRepository, this),
43+
sourceControlManager.onDidChangeRepository(
44+
this.onDidChangeRepository,
45+
this
46+
),
4447
workspace.registerTextDocumentContentProvider("svn", this)
4548
);
4649

@@ -79,8 +82,7 @@ export class SvnContentProvider
7982

8083
const keys = Object.keys(this.cache);
8184

82-
cacheLoop:
83-
for (const key of keys) {
85+
cacheLoop: for (const key of keys) {
8486
const uri = this.cache[key].uri;
8587
const fsPath = uri.fsPath;
8688

@@ -91,7 +93,6 @@ export class SvnContentProvider
9193
}
9294
}
9395
}
94-
9596
}
9697

9798
public async provideTextDocumentContent(uri: Uri): Promise<string> {

src/svnRepository.ts

+8
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,14 @@ export class Repository {
700700
return result.stdout;
701701
}
702702

703+
public async removeUnversioned() {
704+
const result = await this.exec(["cleanup", "--remove-unversioned"]);
705+
706+
this.svn.logOutput(result.stdout);
707+
708+
return result.stdout;
709+
}
710+
703711
public async finishCheckout() {
704712
const info = await this.getInfo();
705713

src/treeView/dataProviders/svnProvider.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,22 @@ export default class SvnProvider implements TreeDataProvider<BaseNode> {
3131
}
3232

3333
public async getChildren(element?: BaseNode): Promise<BaseNode[]> {
34-
if (!this.sourceControlManager || this.sourceControlManager.openRepositories.length === 0) {
34+
if (
35+
!this.sourceControlManager ||
36+
this.sourceControlManager.openRepositories.length === 0
37+
) {
3538
return Promise.resolve([]);
3639
}
3740

3841
if (element) {
3942
return element.getChildren();
4043
}
4144

42-
const repositories = this.sourceControlManager.openRepositories.map(repository => {
43-
return new RepositoryNode(repository.repository, this);
44-
});
45+
const repositories = this.sourceControlManager.openRepositories.map(
46+
repository => {
47+
return new RepositoryNode(repository.repository, this);
48+
}
49+
);
4550

4651
return repositories;
4752
}

src/util.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as path from "path";
2-
import { Event } from "vscode";
2+
import { Event, commands } from "vscode";
33
import { Operation } from "./common/types";
44
import { exists, lstat, readdir, rmdir, unlink } from "./fs";
55

@@ -196,3 +196,7 @@ export async function isSvnFolder(
196196

197197
return isSvnFolder(parent, true);
198198
}
199+
200+
export function setVscodeContext(key: string, value: any) {
201+
commands.executeCommand("setContext", key, value);
202+
}

src/vscodeModules.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,15 @@ function loadVSCodeModule(id: string) {
1818
module.paths.unshift(`${baseDir}/node_modules`);
1919
return require(id);
2020
} catch (eb) {
21-
vscode.window.showErrorMessage(`Missing dependency, go to "${baseDir}" and run: npm install ${id}`);
21+
vscode.window.showErrorMessage(
22+
`Missing dependency, go to "${baseDir}" and run: npm install ${id}`
23+
);
2224
}
2325
}
2426

25-
export const iconv = loadVSCodeModule("iconv-lite") as typeof import("iconv-lite");
26-
export const jschardet = loadVSCodeModule("jschardet") as typeof import("jschardet");
27+
export const iconv = loadVSCodeModule(
28+
"iconv-lite"
29+
) as typeof import("iconv-lite");
30+
export const jschardet = loadVSCodeModule(
31+
"jschardet"
32+
) as typeof import("jschardet");

0 commit comments

Comments
 (0)