Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added option to enable proposed features #602

Merged
merged 3 commits into from
Jun 7, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@ Please use a dedicated extension like [blamer-vs](https://marketplace.visualstud

## Experimental

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

Example:
```json
```js
// FROM
{
"extensionAllowedProposedApi": [
Expand All @@ -91,6 +91,7 @@ Here is a table of settings with their default values. To change any of these, a
|Config|Description|Default|
|-|-|-|
|`svn.enabled`|Whether svn is enabled|`true`|
|`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`|
|`svn.autorefresh`|Whether auto refreshing is enabled|`true`|
|`svn.decorations.enabled`|Controls if SVN contributes colors and badges to the explorer and the open (VSCode \>= 1.18 with proposed-api)|`true`|
|`svn.path`|Path to the svn executable|`null`|
Expand Down Expand Up @@ -126,3 +127,5 @@ Here is a table of settings with their default values. To change any of these, a
|`svn.remoteChanges.checkFrequency`|Set the interval in seconds to check changed files on remote repository and show in statusbar. 0 to disable|`300`|
|`svn.sourceControl.hideUnversioned`|Hide unversioned files in Source Control UI|`false`|
|`svn.refresh.remoteChanges`|Refresh remote changes on refresh command|`false`|
|`svn.sourceControl.changesLeftClick`|Set left click functionality on changes resource state|`"open diff"`|
|`svn.gravatars.enabled`|Use garavatar icons in log viewers|`true`|
16 changes: 15 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,20 @@
"description": "Whether svn is enabled",
"default": true
},
"svn.enableProposedApi": {
"type": [
"string",
"null"
],
"enum": [
null,
"product",
"argument",
"none"
],
"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",
"default": null
},
"svn.autorefresh": {
"type": "boolean",
"description": "Whether auto refreshing is enabled",
Expand Down Expand Up @@ -1152,4 +1166,4 @@
}
}
}
}
}
3 changes: 3 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ItemLogProvider } from "./historyView/itemLogProvider";
import { RepoLogProvider } from "./historyView/repoLogProvider";
import * as messages from "./messages";
import { Model } from "./model";
import { checkProposedApi } from "./proposed";
import { Svn } from "./svn";
import { SvnContentProvider } from "./svnContentProvider";
import { SvnFinder } from "./svnFinder";
Expand Down Expand Up @@ -79,6 +80,8 @@ async function init(
toDisposable(() => svn.onOutput.removeListener("log", onOutput))
);
disposables.push(toDisposable(messages.dispose));

checkProposedApi();
}

async function _activate(context: ExtensionContext, disposables: Disposable[]) {
Expand Down
10 changes: 10 additions & 0 deletions src/fs/access.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { access as fsAccess } from "original-fs";

export function access(
path: string,
mode: number | undefined
): Promise<boolean> {
return new Promise((resolve, _reject) => {
fsAccess(path, mode, err => (err ? resolve(false) : resolve(true)));
});
}
1 change: 1 addition & 0 deletions src/fs/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { access } from "./access";
export { exists } from "./exists";
export { lstat } from "./lstat";
export { mkdir } from "./mkdir";
Expand Down
9 changes: 7 additions & 2 deletions src/helpers/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import {
ConfigurationChangeEvent,
ConfigurationTarget,
Event,
EventEmitter,
workspace,
Expand Down Expand Up @@ -37,8 +38,12 @@ class Configuration {
return this.configuration.get<T>(section, defaultValue!);
}

public update(section: string, value: any): Thenable<void> {
return this.configuration.update(section, value);
public update(
section: string,
value: any,
configurationTarget?: ConfigurationTarget | boolean
): Thenable<void> {
return this.configuration.update(section, value, configurationTarget);
}

public inspect(section: string) {
Expand Down
16 changes: 9 additions & 7 deletions src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ export class Model implements IDisposable {
})() as unknown) as Model;
}

public openRepositoriesSorted(): IOpenRepository[] {
// Sort by path length (First external and ignored over root)
return this.openRepositories.sort(
(a, b) => b.repository.workspaceRoot.length - a.repository.workspaceRoot.length
);
}

private onDidChangeConfiguration(): void {
const enabled = configuration.get<boolean>("enabled") === true;

Expand Down Expand Up @@ -332,7 +339,7 @@ export class Model implements IDisposable {
}

if (hint instanceof Uri) {
return this.openRepositories.find(liveRepository => {
return this.openRepositoriesSorted().find(liveRepository => {
if (
!isDescendant(liveRepository.repository.workspaceRoot, hint.fsPath)
) {
Expand Down Expand Up @@ -379,12 +386,7 @@ export class Model implements IDisposable {

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

// Sort by path length (First external and ignored over root)
const open = this.openRepositories.sort(
(a, b) => b.repository.workspaceRoot.length - a.repository.workspaceRoot.length
);

for (const liveRepository of open) {
for (const liveRepository of this.openRepositoriesSorted()) {
const repository = liveRepository.repository;

// Ignore path is not child (fix for multiple externals)
Expand Down
123 changes: 123 additions & 0 deletions src/proposed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import * as fs from "original-fs";
import { ConfigurationTarget, env, window } from "vscode";
import { access, exists, writeFile } from "./fs";
import { configuration } from "./helpers/configuration";
import { hasSupportToDecorationProvider } from "./util";

enum ProposedType {
PRODUCT = "product",
ARGUMENT = "argument",
NONE = "none",
}

export async function checkProposedApi() {

if (hasSupportToDecorationProvider()) {
return;
}

let status: ProposedType | null | undefined = null;
status = configuration.get<ProposedType | null>("enableProposedApi", null);

if (!status) {
status = await promptProposedApi();
}

try {
setProposedApi(status);
} catch (error) {
console.error(error);
await window.showErrorMessage("Failed to configure proposed features for SVN");
}
}

async function promptProposedApi() {
const product = "Yes, edit product.json";
const argument = "Yes, with start argument";
const none = "No";
const choice = await window.showWarningMessage(
`Do you like to enable proposed features for SVN?
More info [here](https://github.com/JohnstonCode/svn-scm#experimental)`,
product,
argument,
none
);

switch (choice) {
case product:
return ProposedType.PRODUCT;
case argument:
return ProposedType.ARGUMENT;
case none:
return ProposedType.NONE;
}

return undefined;
}

export async function setProposedApi(status?: ProposedType) {
switch (status) {
case ProposedType.PRODUCT:
enableProposedProduct();
break;
case ProposedType.ARGUMENT:
enableProposedArgument();
break;
case ProposedType.NONE:
break;
}

if (status) {
configuration.update("enableProposedApi", status, ConfigurationTarget.Global);
}
}

async function enableProposedProduct() {
const productPath = env.appRoot + "/product.json";

if (!await exists(productPath)) {
window.showErrorMessage(`Can't find the "product.json" of VSCode.`);
return;
}
if (!await access(productPath, fs.constants.W_OK)) {
window.showErrorMessage(`The "product.json" of VSCode is not writable.
Please, append "johnstoncode.svn-scm" on "extensionAllowedProposedApi" array`);
return;
}

const productJson = require(productPath) as {
extensionAllowedProposedApi: string[],
[key: string]: any;
};

productJson.extensionAllowedProposedApi = productJson.extensionAllowedProposedApi || [];

if (productJson.extensionAllowedProposedApi.includes("johnstoncode.svn-scm")) {
return;
}
productJson.extensionAllowedProposedApi.push("johnstoncode.svn-scm");

await writeFile(productPath, JSON.stringify(productJson, null, 2));

const message = "SVN proposed features enabled, please, close the VSCode and open again";

window.showInformationMessage(message);
}

async function enableProposedArgument() {
const packagePath = __dirname + "/../package.json";

const packageJson = require(packagePath);

if (!packageJson || packageJson.enableProposedApi !== false) {
return;
}

packageJson.enableProposedApi = true;
await writeFile(packagePath, JSON.stringify(packageJson, null, 2));

const message = `SVN proposed features enabled, please,
close the VSCode and run with: --enable-proposed-api johnstoncode.svn-scm`;

window.showInformationMessage(message);
}