Skip to content

Commit 3eedbb5

Browse files
edgardmessiasJohnstonCode
authored andcommitted
feat: Added option to enable proposed features (#602)
1 parent f16c9f4 commit 3eedbb5

8 files changed

+173
-12
lines changed

README.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,14 @@ Please use a dedicated extension like [blamer-vs](https://marketplace.visualstud
6363

6464
## Experimental
6565

66-
### * SVN Status in File Explorer (See #34)
66+
### * SVN Status in File Explorer (See [#34](https://github.com/JohnstonCode/svn-scm/issues/34))
6767
How to enable:
6868
* Open the file: `<vscode path>\resources\app\product.json`
6969
* Find `extensionAllowedProposedApi`
7070
* Append `"johnstoncode.svn-scm"` in the array
7171

7272
Example:
73-
```json
73+
```js
7474
// FROM
7575
{
7676
"extensionAllowedProposedApi": [
@@ -91,6 +91,7 @@ Here is a table of settings with their default values. To change any of these, a
9191
|Config|Description|Default|
9292
|-|-|-|
9393
|`svn.enabled`|Whether svn is enabled|`true`|
94+
|`svn.enableProposedApi`|Allow usage of proposed APIs of VSCode. set 'product' to auto-edit product.json, set 'argument' to allow with start argument, set 'none' to not prompt|`null`|
9495
|`svn.autorefresh`|Whether auto refreshing is enabled|`true`|
9596
|`svn.decorations.enabled`|Controls if SVN contributes colors and badges to the explorer and the open (VSCode \>= 1.18 with proposed-api)|`true`|
9697
|`svn.path`|Path to the svn executable|`null`|
@@ -126,3 +127,5 @@ Here is a table of settings with their default values. To change any of these, a
126127
|`svn.remoteChanges.checkFrequency`|Set the interval in seconds to check changed files on remote repository and show in statusbar. 0 to disable|`300`|
127128
|`svn.sourceControl.hideUnversioned`|Hide unversioned files in Source Control UI|`false`|
128129
|`svn.refresh.remoteChanges`|Refresh remote changes on refresh command|`false`|
130+
|`svn.sourceControl.changesLeftClick`|Set left click functionality on changes resource state|`"open diff"`|
131+
|`svn.gravatars.enabled`|Use garavatar icons in log viewers|`true`|

package.json

+15-1
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,20 @@
913913
"description": "Whether svn is enabled",
914914
"default": true
915915
},
916+
"svn.enableProposedApi": {
917+
"type": [
918+
"string",
919+
"null"
920+
],
921+
"enum": [
922+
null,
923+
"product",
924+
"argument",
925+
"none"
926+
],
927+
"description": "Allow usage of proposed APIs of VSCode. set 'product' to auto-edit product.json, set 'argument' to allow with start argument, set 'none' to not prompt",
928+
"default": null
929+
},
916930
"svn.autorefresh": {
917931
"type": "boolean",
918932
"description": "Whether auto refreshing is enabled",
@@ -1152,4 +1166,4 @@
11521166
}
11531167
}
11541168
}
1155-
}
1169+
}

src/extension.ts

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { ItemLogProvider } from "./historyView/itemLogProvider";
1717
import { RepoLogProvider } from "./historyView/repoLogProvider";
1818
import * as messages from "./messages";
1919
import { Model } from "./model";
20+
import { checkProposedApi } from "./proposed";
2021
import { Svn } from "./svn";
2122
import { SvnContentProvider } from "./svnContentProvider";
2223
import { SvnFinder } from "./svnFinder";
@@ -79,6 +80,8 @@ async function init(
7980
toDisposable(() => svn.onOutput.removeListener("log", onOutput))
8081
);
8182
disposables.push(toDisposable(messages.dispose));
83+
84+
checkProposedApi();
8285
}
8386

8487
async function _activate(context: ExtensionContext, disposables: Disposable[]) {

src/fs/access.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { access as fsAccess } from "original-fs";
2+
3+
export function access(
4+
path: string,
5+
mode: number | undefined
6+
): Promise<boolean> {
7+
return new Promise((resolve, _reject) => {
8+
fsAccess(path, mode, err => (err ? resolve(false) : resolve(true)));
9+
});
10+
}

src/fs/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export { access } from "./access";
12
export { exists } from "./exists";
23
export { lstat } from "./lstat";
34
export { mkdir } from "./mkdir";

src/helpers/configuration.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import {
44
ConfigurationChangeEvent,
5+
ConfigurationTarget,
56
Event,
67
EventEmitter,
78
workspace,
@@ -37,8 +38,12 @@ class Configuration {
3738
return this.configuration.get<T>(section, defaultValue!);
3839
}
3940

40-
public update(section: string, value: any): Thenable<void> {
41-
return this.configuration.update(section, value);
41+
public update(
42+
section: string,
43+
value: any,
44+
configurationTarget?: ConfigurationTarget | boolean
45+
): Thenable<void> {
46+
return this.configuration.update(section, value, configurationTarget);
4247
}
4348

4449
public inspect(section: string) {

src/model.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ export class Model implements IDisposable {
8787
})() as unknown) as Model;
8888
}
8989

90+
public openRepositoriesSorted(): IOpenRepository[] {
91+
// Sort by path length (First external and ignored over root)
92+
return this.openRepositories.sort(
93+
(a, b) => b.repository.workspaceRoot.length - a.repository.workspaceRoot.length
94+
);
95+
}
96+
9097
private onDidChangeConfiguration(): void {
9198
const enabled = configuration.get<boolean>("enabled") === true;
9299

@@ -332,7 +339,7 @@ export class Model implements IDisposable {
332339
}
333340

334341
if (hint instanceof Uri) {
335-
return this.openRepositories.find(liveRepository => {
342+
return this.openRepositoriesSorted().find(liveRepository => {
336343
if (
337344
!isDescendant(liveRepository.repository.workspaceRoot, hint.fsPath)
338345
) {
@@ -379,12 +386,7 @@ export class Model implements IDisposable {
379386

380387
public async getRepositoryFromUri(uri: Uri): Promise<Repository | null> {
381388

382-
// Sort by path length (First external and ignored over root)
383-
const open = this.openRepositories.sort(
384-
(a, b) => b.repository.workspaceRoot.length - a.repository.workspaceRoot.length
385-
);
386-
387-
for (const liveRepository of open) {
389+
for (const liveRepository of this.openRepositoriesSorted()) {
388390
const repository = liveRepository.repository;
389391

390392
// Ignore path is not child (fix for multiple externals)

src/proposed.ts

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import * as fs from "original-fs";
2+
import { ConfigurationTarget, env, window } from "vscode";
3+
import { access, exists, writeFile } from "./fs";
4+
import { configuration } from "./helpers/configuration";
5+
import { hasSupportToDecorationProvider } from "./util";
6+
7+
enum ProposedType {
8+
PRODUCT = "product",
9+
ARGUMENT = "argument",
10+
NONE = "none",
11+
}
12+
13+
export async function checkProposedApi() {
14+
15+
if (hasSupportToDecorationProvider()) {
16+
return;
17+
}
18+
19+
let status: ProposedType | null | undefined = null;
20+
status = configuration.get<ProposedType | null>("enableProposedApi", null);
21+
22+
if (!status) {
23+
status = await promptProposedApi();
24+
}
25+
26+
try {
27+
setProposedApi(status);
28+
} catch (error) {
29+
console.error(error);
30+
await window.showErrorMessage("Failed to configure proposed features for SVN");
31+
}
32+
}
33+
34+
async function promptProposedApi() {
35+
const product = "Yes, edit product.json";
36+
const argument = "Yes, with start argument";
37+
const none = "No";
38+
const choice = await window.showWarningMessage(
39+
`Would you like to enable proposed features for SVN?
40+
More info [here](https://github.com/JohnstonCode/svn-scm#experimental)`,
41+
product,
42+
argument,
43+
none
44+
);
45+
46+
switch (choice) {
47+
case product:
48+
return ProposedType.PRODUCT;
49+
case argument:
50+
return ProposedType.ARGUMENT;
51+
case none:
52+
return ProposedType.NONE;
53+
}
54+
55+
return undefined;
56+
}
57+
58+
export async function setProposedApi(status?: ProposedType) {
59+
switch (status) {
60+
case ProposedType.PRODUCT:
61+
enableProposedProduct();
62+
break;
63+
case ProposedType.ARGUMENT:
64+
enableProposedArgument();
65+
break;
66+
case ProposedType.NONE:
67+
break;
68+
}
69+
70+
if (status) {
71+
configuration.update("enableProposedApi", status, ConfigurationTarget.Global);
72+
}
73+
}
74+
75+
async function enableProposedProduct() {
76+
const productPath = env.appRoot + "/product.json";
77+
78+
if (!await exists(productPath)) {
79+
window.showErrorMessage(`Can't find the "product.json" of VSCode.`);
80+
return;
81+
}
82+
if (!await access(productPath, fs.constants.W_OK)) {
83+
window.showErrorMessage(`The "product.json" of VSCode is not writable.
84+
Please, append "johnstoncode.svn-scm" on "extensionAllowedProposedApi" array`);
85+
return;
86+
}
87+
88+
const productJson = require(productPath) as {
89+
extensionAllowedProposedApi: string[],
90+
[key: string]: any;
91+
};
92+
93+
productJson.extensionAllowedProposedApi = productJson.extensionAllowedProposedApi || [];
94+
95+
if (productJson.extensionAllowedProposedApi.includes("johnstoncode.svn-scm")) {
96+
return;
97+
}
98+
productJson.extensionAllowedProposedApi.push("johnstoncode.svn-scm");
99+
100+
await writeFile(productPath, JSON.stringify(productJson, null, 2));
101+
102+
const message = "SVN proposed features enabled, please restart VSCode";
103+
104+
window.showInformationMessage(message);
105+
}
106+
107+
async function enableProposedArgument() {
108+
const packagePath = __dirname + "/../package.json";
109+
110+
const packageJson = require(packagePath);
111+
112+
if (!packageJson || packageJson.enableProposedApi !== false) {
113+
return;
114+
}
115+
116+
packageJson.enableProposedApi = true;
117+
await writeFile(packagePath, JSON.stringify(packageJson, null, 2));
118+
119+
const message = `SVN proposed features enabled,
120+
please close the VSCode and run with: --enable-proposed-api johnstoncode.svn-scm`;
121+
122+
window.showInformationMessage(message);
123+
}

0 commit comments

Comments
 (0)