- code documentation, clean-up

- sourceControlPane argument in the command handlers
- command to open fiddle in the browser
This commit is contained in:
Jan Dolejsi
2019-05-17 00:52:52 +02:00
parent 4143736821
commit 80f5553e69
5 changed files with 110 additions and 68 deletions

View File

@ -56,13 +56,19 @@ The three commands (command, roll-back and refresh) in the title of the source c
"command": "extension.source-control.refresh",
"group": "navigation",
"when": "scmProvider == jsfiddle"
},
{
"command": "extension.source-control.browse",
"when": "scmProvider == jsfiddle"
}
]
}
},
```
It is also worth noting that the sample extension needs to overcome reloading that VS Code triggers when a new workspace folder is added. This is done by writing a memo into the `context.globalState` and reading it upon the next extension activation.
Note that the `extension.source-control.browse` command is intentionally missing the `"group": "navigation"` placement specification, which makes it show up under the [dot dot dot] button.
It is also worth noting that the sample extension needs to overcome reloading that VS Code triggers when a new workspace folder is added. This could be done either by writing a memo into the `context.globalState`, or a configuration file into the workspace folder and reading it upon the next extension activation. The selected solution is to use `.jsfiddle` configuration file as described below.
## Status bar controls
@ -126,7 +132,7 @@ This extension implements the _cloning_ using the `extension.source-control.open
This sample extension stores the source control configuration in the `.jsfiddle` JSON file in the workspace folder root.
Upon extension activation such file is discovered in the workspace folder and source control initialized.
This is done by storing the `.jsfiddle` configuration file into the `WorkspaceFolder` just inserting the workspace folder via the `vscode.workspace.updateWorkspaceFolders(...)` call, which seems to make the extension re-activate. Upon the re-activation, the `initializeFromConfigurationFile()` function scans all `WorkspaceFolder`s for the `.jsfiddle` configuration files and re-creates the `SourceControl` instances.
## Multiple workspace folder support

View File

@ -52,6 +52,10 @@
"light": "resources/icons/light/refresh.svg",
"dark": "resources/icons/dark/refresh.svg"
}
},
{
"command": "extension.source-control.browse",
"title": "Open current Fiddle in the default browser"
}
],
"menus": {
@ -70,6 +74,10 @@
"command": "extension.source-control.refresh",
"group": "navigation",
"when": "scmProvider == jsfiddle"
},
{
"command": "extension.source-control.browse",
"when": "scmProvider == jsfiddle"
}
]
}

View File

@ -30,26 +30,38 @@ export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider(JSFIDDLE_SCHEME, jsFiddleDocumentContentProvider));
context.subscriptions.push(vscode.commands.registerCommand("extension.source-control.refresh", async () => {
let sourceControl = await pickSourceControl();
if (sourceControl) { sourceControl.refresh(); }
}));
context.subscriptions.push(vscode.commands.registerCommand("extension.source-control.discard", async () => {
let sourceControl = await pickSourceControl();
if (sourceControl) { sourceControl.resetFilesToCheckedOutVersion(); }
}));
context.subscriptions.push(vscode.commands.registerCommand("extension.source-control.commit", async () => {
let sourceControl = await pickSourceControl();
if (sourceControl) { sourceControl.commitAll(); }
}));
context.subscriptions.push(vscode.commands.registerCommand("extension.source-control.refresh",
async (sourceControlPane: vscode.SourceControl) => {
let sourceControl = await pickSourceControl(sourceControlPane);
if (sourceControl) { sourceControl.refresh(); }
}));
context.subscriptions.push(vscode.commands.registerCommand("extension.source-control.discard",
async (sourceControlPane: vscode.SourceControl) => {
let sourceControl = await pickSourceControl(sourceControlPane);
if (sourceControl) { sourceControl.resetFilesToCheckedOutVersion(); }
}));
context.subscriptions.push(vscode.commands.registerCommand("extension.source-control.commit",
async (sourceControlPane: vscode.SourceControl) => {
let sourceControl = await pickSourceControl(sourceControlPane);
if (sourceControl) { sourceControl.commitAll(); }
}));
context.subscriptions.push(vscode.commands.registerCommand("extension.source-control.checkout",
async (sourceControl: FiddleSourceControl, newVersion?: number) => {
sourceControl = sourceControl || await pickSourceControl();
sourceControl = sourceControl || await pickSourceControl(null);
if (sourceControl) { sourceControl.tryCheckout(newVersion); }
}));
context.subscriptions.push(vscode.commands.registerCommand("extension.source-control.browse",
async (sourceControlPane: vscode.SourceControl) => {
let sourceControl = await pickSourceControl(sourceControlPane);
if (sourceControl) { sourceControl.openInBrowser(); }
}));
}
async function pickSourceControl(): Promise<FiddleSourceControl | undefined> {
async function pickSourceControl(sourceControlPane: vscode.SourceControl): Promise<FiddleSourceControl | undefined> {
if (sourceControlPane) {
return fiddleSourceControlRegister.get(sourceControlPane.rootUri);
}
// todo: when/if the SourceControl exposes a 'selected' property, use that instead
if (fiddleSourceControlRegister.size === 0) { return undefined; }
@ -131,6 +143,10 @@ function registerFiddleSourceControl(fiddleSourceControl: FiddleSourceControl, c
context.subscriptions.push(fiddleSourceControl);
}
/**
* When the extension starts up, it must visit all workspace folders to see if any of them are fiddles.
* @param context extension context
*/
function initializeFromConfigurationFile(context: vscode.ExtensionContext): void {
if (!vscode.workspace.workspaceFolders) { return; }

View File

@ -147,7 +147,7 @@ export async function uploadFiddle(slug: string, version: number, html: string,
}
}
function toFiddleId(slug: string, version: number | undefined): string {
export function toFiddleId(slug: string, version: number | undefined): string {
if (version === undefined) {
return slug;
}

View File

@ -1,5 +1,5 @@
import * as vscode from 'vscode';
import { FiddleRepository, toExtension, downloadFiddle, areIdentical, uploadFiddle, Fiddle } from './fiddleRepository';
import { FiddleRepository, toExtension, downloadFiddle, areIdentical, uploadFiddle, Fiddle, toFiddleId } from './fiddleRepository';
import * as path from 'path';
import { writeFileSync, existsSync, writeFile } from 'fs';
import { FiddleConfiguration, parseFiddleId } from './fiddleConfiguration';
@ -185,56 +185,6 @@ export class FiddleSourceControl implements vscode.Disposable {
});
}
/**
* Refresh is used when the information on the server may have changed.
* For example another user updates the Fiddle online.
*/
async refresh(): Promise<void> {
let latestVersion = this.fiddle.version || 0;
while (true) {
try {
let latestFiddle = await downloadFiddle(this.fiddle.slug, latestVersion);
this.latestFiddleVersion = latestVersion;
latestVersion++;
} catch (ex) {
// typically the ex.statusCode == 404, when there is no further version
break;
}
}
this.refreshStatusBar();
}
/**
* Determines which version was checked out and finds the index of the latest version.
*/
async establishVersion(): Promise<void> {
let version = 0;
let latestVersion = Number.NaN;
let currentFiddle: Fiddle | undefined = undefined;
while (true) {
try {
let latestFiddle = await downloadFiddle(this.fiddle.slug, version);
latestVersion = version;
version++;
if (areIdentical(this.fiddle.data, latestFiddle.data)) {
currentFiddle = latestFiddle;
}
} catch (ex) {
// typically the ex.statusCode == 404, when there is no further version
break;
}
}
this.latestFiddleVersion = latestVersion;
// now we know the version of the current fiddle, let's set it
if (currentFiddle) {
this.setFiddle(currentFiddle, false);
}
}
get onRepositoryChange(): vscode.Event<Fiddle> {
return this._onRepositoryChange.event;
}
@ -253,6 +203,7 @@ export class FiddleSourceControl implements vscode.Disposable {
}
}
/** This is where the source control determines, which documents were updated, removed, and theoretically added. */
async updateChangedGroup(): Promise<void> {
// for simplicity we ignore which document was changed in this event and scan all of them
let changedResources: vscode.SourceControlResourceState[] = [];
@ -280,6 +231,9 @@ export class FiddleSourceControl implements vscode.Disposable {
}
this.changedResources.resourceStates = changedResources;
// the number of modified resources needs to be assigned to the SourceControl.count filed to let VS Code show the number.
this.jsFiddleScm.count = this.changedResources.resourceStates.length;
}
/** Determines whether the resource is different, regardless of line endings. */
@ -315,6 +269,64 @@ export class FiddleSourceControl implements vscode.Disposable {
return resourceState;
}
/**
* Refresh is used when the information on the server may have changed.
* For example another user updates the Fiddle online.
*/
async refresh(): Promise<void> {
let latestVersion = this.fiddle.version || 0;
while (true) {
try {
let latestFiddle = await downloadFiddle(this.fiddle.slug, latestVersion);
this.latestFiddleVersion = latestVersion;
latestVersion++;
} catch (ex) {
// typically the ex.statusCode == 404, when there is no further version
break;
}
}
this.refreshStatusBar();
}
/**
* Determines which version was checked out and finds the index of the latest version.
*
* When a fiddle is open by the hash code, the latest version is downloaded,
* but extension does not know what version it is.
*/
async establishVersion(): Promise<void> {
let version = 0;
let latestVersion = Number.NaN;
let currentFiddle: Fiddle | undefined = undefined;
while (true) {
try {
let latestFiddle = await downloadFiddle(this.fiddle.slug, version);
latestVersion = version;
version++;
if (areIdentical(this.fiddle.data, latestFiddle.data)) {
currentFiddle = latestFiddle;
}
} catch (ex) {
// typically the ex.statusCode == 404, when there is no further version
break;
}
}
this.latestFiddleVersion = latestVersion;
// now we know the version of the current fiddle, let's set it
if (currentFiddle) {
this.setFiddle(currentFiddle, false);
}
}
/** Opens the fiddle in the default browser. */
openInBrowser() {
let url = "https://jsfiddle.net/" + toFiddleId(this.fiddle.slug, this.fiddle.version);
vscode.env.openExternal(vscode.Uri.parse(url));
}
dispose() {
this._onRepositoryChange.dispose();
this.jsFiddleScm.dispose();