mirror of
https://github.com/microsoft/vscode-extension-samples.git
synced 2026-04-27 16:55:44 +08:00
@ -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
|
||||
|
||||
|
||||
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -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; }
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
Reference in New Issue
Block a user