提交 a8b29458 编写于 作者: J Joao Moreno

🐛 remove the notion of active scm provider

introduces more changes to the SCM api

fixes #23623
fixes #23676
上级 ce46000f
...@@ -5,17 +5,16 @@ ...@@ -5,17 +5,16 @@
'use strict'; 'use strict';
import { ExtensionContext, workspace, window, Disposable, commands, Uri, scm } from 'vscode'; import { ExtensionContext, workspace, window, Disposable, commands, Uri } from 'vscode';
import { findGit, Git } from './git'; import { findGit, Git } from './git';
import { Model } from './model'; import { Model } from './model';
import { GitSCMProvider } from './scmProvider'; import { GitSCMProvider } from './scmProvider';
import { CommandCenter } from './commands'; import { CommandCenter } from './commands';
import { CheckoutStatusBar, SyncStatusBar } from './statusbar'; import { StatusBarCommands } from './statusbar';
import { GitContentProvider } from './contentProvider'; import { GitContentProvider } from './contentProvider';
import { AutoFetcher } from './autofetch'; import { AutoFetcher } from './autofetch';
import { MergeDecorator } from './merge'; import { MergeDecorator } from './merge';
import { Askpass } from './askpass'; import { Askpass } from './askpass';
import { filterEvent } from './util';
import TelemetryReporter from 'vscode-extension-telemetry'; import TelemetryReporter from 'vscode-extension-telemetry';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
...@@ -46,15 +45,15 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi ...@@ -46,15 +45,15 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi
} }
const model = new Model(git, workspaceRootPath); const model = new Model(git, workspaceRootPath);
const commitTemplate = await model.getCommitTemplate();
outputChannel.appendLine(localize('using git', "Using git {0} from {1}", info.version, info.path)); outputChannel.appendLine(localize('using git', "Using git {0} from {1}", info.version, info.path));
git.onOutput(str => outputChannel.append(str), null, disposables); git.onOutput(str => outputChannel.append(str), null, disposables);
const commandCenter = new CommandCenter(git, model, outputChannel, telemetryReporter); const commandCenter = new CommandCenter(git, model, outputChannel, telemetryReporter);
const provider = new GitSCMProvider(model, commandCenter); const statusBarCommands = new StatusBarCommands(model);
const provider = new GitSCMProvider(model, commandCenter, statusBarCommands, commitTemplate);
const contentProvider = new GitContentProvider(model); const contentProvider = new GitContentProvider(model);
const checkoutStatusBar = new CheckoutStatusBar(model);
const syncStatusBar = new SyncStatusBar(model);
const autoFetcher = new AutoFetcher(model); const autoFetcher = new AutoFetcher(model);
const mergeDecorator = new MergeDecorator(model); const mergeDecorator = new MergeDecorator(model);
...@@ -62,8 +61,6 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi ...@@ -62,8 +61,6 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi
commandCenter, commandCenter,
provider, provider,
contentProvider, contentProvider,
checkoutStatusBar,
syncStatusBar,
autoFetcher, autoFetcher,
mergeDecorator, mergeDecorator,
model model
...@@ -77,13 +74,6 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi ...@@ -77,13 +74,6 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi
commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/')); commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/'));
} }
} }
filterEvent(scm.onDidAcceptInputValue, () => scm.activeSourceControl === provider.sourceControl)
(commandCenter.commitWithInput, commandCenter, disposables);
if (scm.activeSourceControl === provider.sourceControl) {
scm.inputBox.value = await model.getCommitTemplate();
}
} }
export function activate(context: ExtensionContext): any { export function activate(context: ExtensionContext): any {
......
...@@ -7,8 +7,12 @@ ...@@ -7,8 +7,12 @@
import { scm, Uri, Disposable, SourceControl, SourceControlResourceGroup, Event, workspace, commands } from 'vscode'; import { scm, Uri, Disposable, SourceControl, SourceControlResourceGroup, Event, workspace, commands } from 'vscode';
import { Model, State } from './model'; import { Model, State } from './model';
import { StatusBarCommands } from './statusBar';
import { CommandCenter } from './commands'; import { CommandCenter } from './commands';
import { mapEvent } from './util'; import { mapEvent } from './util';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export class GitSCMProvider { export class GitSCMProvider {
...@@ -53,11 +57,22 @@ export class GitSCMProvider { ...@@ -53,11 +57,22 @@ export class GitSCMProvider {
private indexGroup: SourceControlResourceGroup; private indexGroup: SourceControlResourceGroup;
private workingTreeGroup: SourceControlResourceGroup; private workingTreeGroup: SourceControlResourceGroup;
constructor(private model: Model, private commandCenter: CommandCenter) { constructor(
private model: Model,
private commandCenter: CommandCenter,
private statusBarCommands: StatusBarCommands,
private commitTemplate: string
) {
this._sourceControl = scm.createSourceControl('git', 'Git'); this._sourceControl = scm.createSourceControl('git', 'Git');
this._sourceControl.quickDiffProvider = this;
this.disposables.push(this._sourceControl); this.disposables.push(this._sourceControl);
this._sourceControl.commitTemplate = commitTemplate;
this._sourceControl.acceptInputCommand = { command: 'git.commitWithInput', title: localize('commit', "Commit") };
this._sourceControl.quickDiffProvider = this;
this.statusBarCommands.onDidChange(this.onDidStatusBarCommandsChange, this, this.disposables);
this.onDidStatusBarCommandsChange();
this.mergeGroup = this._sourceControl.createResourceGroup(model.mergeGroup.id, model.mergeGroup.label); this.mergeGroup = this._sourceControl.createResourceGroup(model.mergeGroup.id, model.mergeGroup.label);
this.indexGroup = this._sourceControl.createResourceGroup(model.indexGroup.id, model.indexGroup.label); this.indexGroup = this._sourceControl.createResourceGroup(model.indexGroup.id, model.indexGroup.label);
this.workingTreeGroup = this._sourceControl.createResourceGroup(model.workingTreeGroup.id, model.workingTreeGroup.label); this.workingTreeGroup = this._sourceControl.createResourceGroup(model.workingTreeGroup.id, model.workingTreeGroup.label);
...@@ -90,6 +105,10 @@ export class GitSCMProvider { ...@@ -90,6 +105,10 @@ export class GitSCMProvider {
commands.executeCommand('setContext', 'gitState', this.stateContextKey); commands.executeCommand('setContext', 'gitState', this.stateContextKey);
} }
private onDidStatusBarCommandsChange(): void {
this._sourceControl.statusBarCommands = this.statusBarCommands.commands;
}
dispose(): void { dispose(): void {
this.disposables.forEach(d => d.dispose()); this.disposables.forEach(d => d.dispose());
this.disposables = []; this.disposables = [];
......
...@@ -5,48 +5,45 @@ ...@@ -5,48 +5,45 @@
'use strict'; 'use strict';
import { window, Disposable, StatusBarItem, StatusBarAlignment } from 'vscode'; import { Disposable, Command, EventEmitter, Event } from 'vscode';
import { RefType, Branch } from './git'; import { RefType, Branch } from './git';
import { Model, Operation } from './model'; import { Model, Operation } from './model';
import { anyEvent, dispose } from './util';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
export class CheckoutStatusBar { class CheckoutStatusBar {
private raw: StatusBarItem; private _onDidChange = new EventEmitter<void>();
get onDidChange(): Event<void> { return this._onDidChange.event; }
private disposables: Disposable[] = []; private disposables: Disposable[] = [];
constructor(private model: Model) { constructor(private model: Model) {
this.raw = window.createStatusBarItem(StatusBarAlignment.Left, Number.MAX_VALUE - 1); model.onDidChange(this._onDidChange.fire, this._onDidChange, this.disposables);
this.raw.show();
this.disposables.push(this.raw);
model.onDidChange(this.update, this, this.disposables);
this.update();
} }
private update(): void { get command(): Command | undefined {
const HEAD = this.model.HEAD; const HEAD = this.model.HEAD;
if (!HEAD) { if (!HEAD) {
this.raw.hide(); return undefined;
return;
} }
const tag = this.model.refs.filter(iref => iref.type === RefType.Tag && iref.commit === HEAD.commit)[0]; const tag = this.model.refs.filter(iref => iref.type === RefType.Tag && iref.commit === HEAD.commit)[0];
const tagName = tag && tag.name; const tagName = tag && tag.name;
const head = HEAD.name || tagName || (HEAD.commit || '').substr(0, 8); const head = HEAD.name || tagName || (HEAD.commit || '').substr(0, 8);
const title = '$(git-branch) '
this.raw.command = 'git.checkout'; + head
this.raw.color = 'rgb(255, 255, 255)'; + (this.model.workingTreeGroup.resources.length > 0 ? '*' : '')
this.raw.tooltip = localize('checkout', 'Checkout...'); + (this.model.indexGroup.resources.length > 0 ? '+' : '')
this.raw.text = '$(git-branch) ' + + (this.model.mergeGroup.resources.length > 0 ? '!' : '');
head +
(this.model.workingTreeGroup.resources.length > 0 ? '*' : '') + return {
(this.model.indexGroup.resources.length > 0 ? '+' : '') + command: 'git.checkout',
(this.model.mergeGroup.resources.length > 0 ? '!' : ''); tooltip: localize('checkout', 'Checkout...'),
this.raw.show(); title
};
} }
dispose(): void { dispose(): void {
...@@ -60,7 +57,7 @@ interface SyncStatusBarState { ...@@ -60,7 +57,7 @@ interface SyncStatusBarState {
HEAD: Branch | undefined; HEAD: Branch | undefined;
} }
export class SyncStatusBar { class SyncStatusBar {
private static StartState: SyncStatusBarState = { private static StartState: SyncStatusBarState = {
isSyncRunning: false, isSyncRunning: false,
...@@ -68,22 +65,21 @@ export class SyncStatusBar { ...@@ -68,22 +65,21 @@ export class SyncStatusBar {
HEAD: undefined HEAD: undefined
}; };
private raw: StatusBarItem; private _onDidChange = new EventEmitter<void>();
get onDidChange(): Event<void> { return this._onDidChange.event; }
private disposables: Disposable[] = []; private disposables: Disposable[] = [];
private _state: SyncStatusBarState = SyncStatusBar.StartState; private _state: SyncStatusBarState = SyncStatusBar.StartState;
private get state() { return this._state; } private get state() { return this._state; }
private set state(state: SyncStatusBarState) { private set state(state: SyncStatusBarState) {
this._state = state; this._state = state;
this.render(); this._onDidChange.fire();
} }
constructor(private model: Model) { constructor(private model: Model) {
this.raw = window.createStatusBarItem(StatusBarAlignment.Left, Number.MAX_VALUE);
this.disposables.push(this.raw);
model.onDidChange(this.onModelChange, this, this.disposables); model.onDidChange(this.onModelChange, this, this.disposables);
model.onDidChangeOperations(this.onOperationsChange, this, this.disposables); model.onDidChangeOperations(this.onOperationsChange, this, this.disposables);
this.render(); this._onDidChange.fire();
} }
private onOperationsChange(): void { private onOperationsChange(): void {
...@@ -101,10 +97,9 @@ export class SyncStatusBar { ...@@ -101,10 +97,9 @@ export class SyncStatusBar {
}; };
} }
private render(): void { get command(): Command | undefined {
if (!this.state.hasRemotes) { if (!this.state.hasRemotes) {
this.raw.hide(); return undefined;
return;
} }
const HEAD = this.state.HEAD; const HEAD = this.state.HEAD;
...@@ -136,20 +131,57 @@ export class SyncStatusBar { ...@@ -136,20 +131,57 @@ export class SyncStatusBar {
tooltip = localize('syncing changes', "Synchronizing changes..."); tooltip = localize('syncing changes', "Synchronizing changes...");
} }
this.raw.text = [icon, text].join(' ').trim(); return {
this.raw.command = command; command,
this.raw.tooltip = tooltip; title: [icon, text].join(' ').trim(),
tooltip
};
}
if (command) { dispose(): void {
this.raw.color = ''; this.disposables.forEach(d => d.dispose());
} else { }
this.raw.color = 'rgba(255,255,255,0.7)'; }
export class StatusBarCommands {
private syncStatusBar: SyncStatusBar;
private checkoutStatusBar: CheckoutStatusBar;
private disposables: Disposable[] = [];
constructor(model: Model) {
this.syncStatusBar = new SyncStatusBar(model);
this.checkoutStatusBar = new CheckoutStatusBar(model);
}
get onDidChange(): Event<void> {
return anyEvent(
this.syncStatusBar.onDidChange,
this.checkoutStatusBar.onDidChange
);
}
get commands(): Command[] {
const result: Command[] = [];
const checkout = this.checkoutStatusBar.command;
if (checkout) {
result.push(checkout);
}
const sync = this.syncStatusBar.command;
if (sync) {
result.push(sync);
} }
this.raw.show(); return result;
} }
dispose(): void { dispose(): void {
this.disposables.forEach(d => d.dispose()); this.syncStatusBar.dispose();
this.checkoutStatusBar.dispose();
this.disposables = dispose(this.disposables);
} }
} }
\ No newline at end of file
...@@ -654,6 +654,7 @@ export interface RenameProvider { ...@@ -654,6 +654,7 @@ export interface RenameProvider {
export interface Command { export interface Command {
id: string; id: string;
title: string; title: string;
tooltip?: string;
arguments?: any[]; arguments?: any[];
} }
export interface ICodeLensSymbol { export interface ICodeLensSymbol {
......
...@@ -4866,6 +4866,7 @@ declare module monaco.languages { ...@@ -4866,6 +4866,7 @@ declare module monaco.languages {
export interface Command { export interface Command {
id: string; id: string;
title: string; title: string;
tooltip?: string;
arguments?: any[]; arguments?: any[];
} }
......
...@@ -28,6 +28,11 @@ declare module 'vscode' { ...@@ -28,6 +28,11 @@ declare module 'vscode' {
*/ */
command: string; command: string;
/**
* A tooltip for for command, when represented in the UI.
*/
tooltip?: string;
/** /**
* Arguments that the command handler should be * Arguments that the command handler should be
* invoked with. * invoked with.
...@@ -4681,38 +4686,45 @@ declare module 'vscode' { ...@@ -4681,38 +4686,45 @@ declare module 'vscode' {
quickDiffProvider?: QuickDiffProvider; quickDiffProvider?: QuickDiffProvider;
/** /**
* Create a new [resource group](#SourceControlResourceGroup). * Optional commit template string.
*
* The Source Control viewlet will populate the Source Control
* input with this value when appropriate.
*/ */
createResourceGroup(id: string, label: string): SourceControlResourceGroup; commitTemplate?: string;
/** /**
* Dispose this source control. * Optional accept input command.
*
* This command will be invoked when the user accepts the value
* in the Source Control input.
*/ */
dispose(): void; acceptInputCommand?: Command;
}
export namespace scm {
/** /**
* The currently active [source control](#SourceControl). * Optional status bar commands.
*
* These commands will be displayed in the editor's status bar.
*/ */
export let activeSourceControl: SourceControl | undefined; statusBarCommands?: Command[];
/** /**
* An [event](#Event) which fires when the active [source control](#SourceControl) * Create a new [resource group](#SourceControlResourceGroup).
* has changed.
*/ */
export const onDidChangeActiveSourceControl: Event<SourceControl>; createResourceGroup(id: string, label: string): SourceControlResourceGroup;
/** /**
* The [input box](#SourceControlInputBox) in the Source Control viewlet. * Dispose this source control.
*/ */
export const inputBox: SourceControlInputBox; dispose(): void;
}
export namespace scm {
/** /**
* An [event](#Event) which fires when the user has accepted the changes. * The [input box](#SourceControlInputBox) in the Source Control viewlet.
*/ */
export const onDidAcceptInputValue: Event<SourceControlInputBox>; export const inputBox: SourceControlInputBox;
/** /**
* Creates a new [source control](#SourceControl) instance. * Creates a new [source control](#SourceControl) instance.
......
...@@ -253,6 +253,9 @@ export abstract class MainProcessExtensionServiceShape { ...@@ -253,6 +253,9 @@ export abstract class MainProcessExtensionServiceShape {
export interface SCMProviderFeatures { export interface SCMProviderFeatures {
hasQuickDiffProvider?: boolean; hasQuickDiffProvider?: boolean;
count?: number; count?: number;
commitTemplate?: string;
acceptInputCommand?: modes.Command;
statusBarCommands?: modes.Command[];
} }
export interface SCMGroupFeatures { export interface SCMGroupFeatures {
......
...@@ -192,6 +192,10 @@ export class CommandsConverter { ...@@ -192,6 +192,10 @@ export class CommandsConverter {
result.arguments = [id]; result.arguments = [id];
} }
if (command.tooltip) {
result.tooltip = command.tooltip;
}
return result; return result;
} }
......
...@@ -181,6 +181,43 @@ class ExtHostSourceControl implements vscode.SourceControl { ...@@ -181,6 +181,43 @@ class ExtHostSourceControl implements vscode.SourceControl {
this._proxy.$updateSourceControl(this._handle, { hasQuickDiffProvider: !!quickDiffProvider }); this._proxy.$updateSourceControl(this._handle, { hasQuickDiffProvider: !!quickDiffProvider });
} }
private _commitTemplate: string | undefined = undefined;
get commitTemplate(): string | undefined {
return this._commitTemplate;
}
set commitTemplate(commitTemplate: string | undefined) {
this._commitTemplate = commitTemplate;
this._proxy.$updateSourceControl(this._handle, { commitTemplate });
}
private _acceptInputCommand: vscode.Command | undefined = undefined;
get acceptInputCommand(): vscode.Command | undefined {
return this._acceptInputCommand;
}
set acceptInputCommand(acceptInputCommand: vscode.Command | undefined) {
this._acceptInputCommand = acceptInputCommand;
const internal = this._commands.toInternal(acceptInputCommand);
this._proxy.$updateSourceControl(this._handle, { acceptInputCommand: internal });
}
private _statusBarCommands: vscode.Command[] | undefined = undefined;
get statusBarCommands(): vscode.Command[] | undefined {
return this._statusBarCommands;
}
set statusBarCommands(statusBarCommands: vscode.Command[] | undefined) {
this._statusBarCommands = statusBarCommands;
const internal = (statusBarCommands || []).map(c => this._commands.toInternal(c));
this._proxy.$updateSourceControl(this._handle, { statusBarCommands: internal });
}
private _handle: number = ExtHostSourceControl._handlePool++; private _handle: number = ExtHostSourceControl._handlePool++;
constructor( constructor(
......
...@@ -78,6 +78,13 @@ class MainThreadSCMProvider implements ISCMProvider { ...@@ -78,6 +78,13 @@ class MainThreadSCMProvider implements ISCMProvider {
get label(): string { return this._label; } get label(): string { return this._label; }
get contextKey(): string { return this._id; } get contextKey(): string { return this._id; }
get commitTemplate(): string | undefined { return this.features.commitTemplate; }
get acceptInputCommand(): Command | undefined { return this.features.acceptInputCommand; }
get statusBarCommands(): Command[] | undefined { return this.features.statusBarCommands; }
private _onDidChangeCommitTemplate = new Emitter<string>();
get onDidChangeCommitTemplate(): Event<string> { return this._onDidChangeCommitTemplate.event; }
private _count: number | undefined = undefined; private _count: number | undefined = undefined;
get count(): number | undefined { return this._count; } get count(): number | undefined { return this._count; }
...@@ -93,6 +100,10 @@ class MainThreadSCMProvider implements ISCMProvider { ...@@ -93,6 +100,10 @@ class MainThreadSCMProvider implements ISCMProvider {
$updateSourceControl(features: SCMProviderFeatures): void { $updateSourceControl(features: SCMProviderFeatures): void {
this.features = assign(this.features, features); this.features = assign(this.features, features);
this._onDidChange.fire(); this._onDidChange.fire();
if (typeof features.commitTemplate !== 'undefined') {
this._onDidChangeCommitTemplate.fire(this.commitTemplate);
}
} }
$registerGroup(handle: number, id: string, label: string): void { $registerGroup(handle: number, id: string, label: string): void {
...@@ -194,7 +205,6 @@ export class MainThreadSCM extends MainThreadSCMShape { ...@@ -194,7 +205,6 @@ export class MainThreadSCM extends MainThreadSCMShape {
this.scmService.onDidChangeProvider(this.onDidChangeProvider, this, this._disposables); this.scmService.onDidChangeProvider(this.onDidChangeProvider, this, this._disposables);
this.scmService.input.onDidChange(this._proxy.$onInputBoxValueChange, this._proxy, this._disposables); this.scmService.input.onDidChange(this._proxy.$onInputBoxValueChange, this._proxy, this._disposables);
this.scmService.input.onDidAccept(this._proxy.$onInputBoxAcceptChanges, this._proxy, this._disposables);
} }
$registerSourceControl(handle: number, id: string, label: string): void { $registerSourceControl(handle: number, id: string, label: string): void {
......
...@@ -12,7 +12,7 @@ import { chain } from 'vs/base/common/event'; ...@@ -12,7 +12,7 @@ import { chain } from 'vs/base/common/event';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import * as platform from 'vs/base/common/platform'; import * as platform from 'vs/base/common/platform';
import { domEvent } from 'vs/base/browser/event'; import { domEvent } from 'vs/base/browser/event';
import { IDisposable, dispose, empty as EmptyDisposable } from 'vs/base/common/lifecycle'; import { IDisposable, dispose, empty as EmptyDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { Builder, Dimension } from 'vs/base/browser/builder'; import { Builder, Dimension } from 'vs/base/browser/builder';
import { Viewlet } from 'vs/workbench/browser/viewlet'; import { Viewlet } from 'vs/workbench/browser/viewlet';
import { append, $, toggleClass } from 'vs/base/browser/dom'; import { append, $, toggleClass } from 'vs/base/browser/dom';
...@@ -212,6 +212,7 @@ function resourceSorter(a: ISCMResource, b: ISCMResource): number { ...@@ -212,6 +212,7 @@ function resourceSorter(a: ISCMResource, b: ISCMResource): number {
export class SCMViewlet extends Viewlet { export class SCMViewlet extends Viewlet {
private activeProvider: ISCMProvider | undefined;
private cachedDimension: Dimension; private cachedDimension: Dimension;
private inputBoxContainer: HTMLElement; private inputBoxContainer: HTMLElement;
private inputBox: InputBox; private inputBox: InputBox;
...@@ -245,13 +246,21 @@ export class SCMViewlet extends Viewlet { ...@@ -245,13 +246,21 @@ export class SCMViewlet extends Viewlet {
private setActiveProvider(activeProvider: ISCMProvider | undefined): void { private setActiveProvider(activeProvider: ISCMProvider | undefined): void {
this.providerChangeDisposable.dispose(); this.providerChangeDisposable.dispose();
this.activeProvider = activeProvider;
if (activeProvider) { if (activeProvider) {
this.providerChangeDisposable = activeProvider.onDidChange(this.update, this); const disposables = [activeProvider.onDidChange(this.update, this)];
if (activeProvider.onDidChangeCommitTemplate) {
disposables.push(activeProvider.onDidChangeCommitTemplate(this.updateInputBox, this));
}
this.providerChangeDisposable = combinedDisposable(disposables);
} else { } else {
this.providerChangeDisposable = EmptyDisposable; this.providerChangeDisposable = EmptyDisposable;
} }
this.updateInputBox();
this.updateTitleArea(); this.updateTitleArea();
this.update(); this.update();
} }
...@@ -278,7 +287,7 @@ export class SCMViewlet extends Viewlet { ...@@ -278,7 +287,7 @@ export class SCMViewlet extends Viewlet {
chain(domEvent(this.inputBox.inputElement, 'keydown')) chain(domEvent(this.inputBox.inputElement, 'keydown'))
.map(e => new StandardKeyboardEvent(e)) .map(e => new StandardKeyboardEvent(e))
.filter(e => e.equals(KeyMod.CtrlCmd | KeyCode.Enter) || e.equals(KeyMod.CtrlCmd | KeyCode.KEY_S)) .filter(e => e.equals(KeyMod.CtrlCmd | KeyCode.Enter) || e.equals(KeyMod.CtrlCmd | KeyCode.KEY_S))
.on(this.scmService.input.acceptChanges, this.scmService.input, this.disposables); .on(this.onDidAcceptInput, this, this.disposables);
this.listContainer = append(root, $('.scm-status.show-file-icons')); this.listContainer = append(root, $('.scm-status.show-file-icons'));
const delegate = new Delegate(); const delegate = new Delegate();
...@@ -312,6 +321,22 @@ export class SCMViewlet extends Viewlet { ...@@ -312,6 +321,22 @@ export class SCMViewlet extends Viewlet {
return TPromise.as(null); return TPromise.as(null);
} }
private onDidAcceptInput(): void {
if (!this.activeProvider) {
return;
}
if (!this.activeProvider.acceptInputCommand) {
return;
}
const id = this.activeProvider.acceptInputCommand.id;
const args = this.activeProvider.acceptInputCommand.arguments;
this.commandService.executeCommand(id, ...args)
.done(undefined, onUnexpectedError);
}
private update(): void { private update(): void {
const provider = this.scmService.activeProvider; const provider = this.scmService.activeProvider;
...@@ -326,6 +351,18 @@ export class SCMViewlet extends Viewlet { ...@@ -326,6 +351,18 @@ export class SCMViewlet extends Viewlet {
this.list.splice(0, this.list.length, elements); this.list.splice(0, this.list.length, elements);
} }
private updateInputBox(): void {
if (!this.activeProvider) {
return;
}
if (typeof this.activeProvider.commitTemplate === 'undefined') {
return;
}
this.inputBox.value = this.activeProvider.commitTemplate;
}
layout(dimension: Dimension = this.cachedDimension): void { layout(dimension: Dimension = this.cachedDimension): void {
if (!dimension) { if (!dimension) {
return; return;
......
...@@ -25,7 +25,6 @@ export interface ISCMResourceDecorations { ...@@ -25,7 +25,6 @@ export interface ISCMResourceDecorations {
} }
export interface ISCMResource { export interface ISCMResource {
// readonly uri: URI;
readonly resourceGroup: ISCMResourceGroup; readonly resourceGroup: ISCMResourceGroup;
readonly sourceUri: URI; readonly sourceUri: URI;
readonly command?: Command; readonly command?: Command;
...@@ -33,7 +32,6 @@ export interface ISCMResource { ...@@ -33,7 +32,6 @@ export interface ISCMResource {
} }
export interface ISCMResourceGroup { export interface ISCMResourceGroup {
// readonly uri: URI;
readonly provider: ISCMProvider; readonly provider: ISCMProvider;
readonly label: string; readonly label: string;
readonly contextKey?: string; readonly contextKey?: string;
...@@ -44,9 +42,12 @@ export interface ISCMProvider extends IDisposable { ...@@ -44,9 +42,12 @@ export interface ISCMProvider extends IDisposable {
readonly label: string; readonly label: string;
readonly contextKey?: string; readonly contextKey?: string;
readonly resources: ISCMResourceGroup[]; readonly resources: ISCMResourceGroup[];
// TODO: Event<void>
readonly onDidChange: Event<void>; readonly onDidChange: Event<void>;
readonly count?: number; readonly count?: number;
readonly commitTemplate?: string;
readonly onDidChangeCommitTemplate?: Event<string>;
readonly acceptInputCommand?: Command;
readonly statusBarCommands?: Command[];
getOriginalResource(uri: URI): TPromise<URI>; getOriginalResource(uri: URI): TPromise<URI>;
} }
...@@ -54,8 +55,6 @@ export interface ISCMProvider extends IDisposable { ...@@ -54,8 +55,6 @@ export interface ISCMProvider extends IDisposable {
export interface ISCMInput { export interface ISCMInput {
value: string; value: string;
readonly onDidChange: Event<string>; readonly onDidChange: Event<string>;
readonly onDidAccept: Event<string>;
acceptChanges(): void;
} }
export interface ISCMService { export interface ISCMService {
......
...@@ -5,10 +5,11 @@ ...@@ -5,10 +5,11 @@
'use strict'; 'use strict';
import { IDisposable, toDisposable, empty as EmptyDisposable } from 'vs/base/common/lifecycle'; import { IDisposable, toDisposable, empty as EmptyDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import Event, { Emitter } from 'vs/base/common/event'; import Event, { Emitter } from 'vs/base/common/event';
import { memoize } from 'vs/base/common/decorators'; import { memoize } from 'vs/base/common/decorators';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { ISCMService, ISCMProvider, ISCMInput } from './scm'; import { ISCMService, ISCMProvider, ISCMInput } from './scm';
class SCMInput implements ISCMInput { class SCMInput implements ISCMInput {
...@@ -26,20 +27,14 @@ class SCMInput implements ISCMInput { ...@@ -26,20 +27,14 @@ class SCMInput implements ISCMInput {
private _onDidChange = new Emitter<string>(); private _onDidChange = new Emitter<string>();
get onDidChange(): Event<string> { return this._onDidChange.event; } get onDidChange(): Event<string> { return this._onDidChange.event; }
private _onDidAccept = new Emitter<string>();
get onDidAccept(): Event<string> { return this._onDidAccept.event; }
acceptChanges(): void {
this._onDidAccept.fire(this._value);
}
} }
export class SCMService implements ISCMService { export class SCMService implements ISCMService {
_serviceBrand; _serviceBrand;
private providerChangeDisposable: IDisposable = EmptyDisposable; private activeProviderDisposable: IDisposable = EmptyDisposable;
private statusBarDisposable: IDisposable = EmptyDisposable;
private activeProviderContextKey: IContextKey<string | undefined>; private activeProviderContextKey: IContextKey<string | undefined>;
private _activeProvider: ISCMProvider | undefined; private _activeProvider: ISCMProvider | undefined;
...@@ -49,6 +44,8 @@ export class SCMService implements ISCMService { ...@@ -49,6 +44,8 @@ export class SCMService implements ISCMService {
} }
set activeProvider(provider: ISCMProvider | undefined) { set activeProvider(provider: ISCMProvider | undefined) {
this.activeProviderDisposable.dispose();
if (!provider) { if (!provider) {
throw new Error('invalid provider'); throw new Error('invalid provider');
} }
...@@ -58,10 +55,11 @@ export class SCMService implements ISCMService { ...@@ -58,10 +55,11 @@ export class SCMService implements ISCMService {
} }
this._activeProvider = provider; this._activeProvider = provider;
this.activeProviderContextKey.set(provider ? provider.contextKey : void 0);
this.providerChangeDisposable.dispose(); this.activeProviderDisposable = provider.onDidChange(() => this.onDidProviderChange(provider));
this.onDidProviderChange(provider);
this.activeProviderContextKey.set(provider ? provider.contextKey : void 0);
this._onDidChangeProvider.fire(provider); this._onDidChangeProvider.fire(provider);
} }
...@@ -75,7 +73,8 @@ export class SCMService implements ISCMService { ...@@ -75,7 +73,8 @@ export class SCMService implements ISCMService {
get input(): ISCMInput { return new SCMInput(); } get input(): ISCMInput { return new SCMInput(); }
constructor( constructor(
@IContextKeyService contextKeyService: IContextKeyService @IContextKeyService contextKeyService: IContextKeyService,
@IStatusbarService private statusbarService: IStatusbarService
) { ) {
this.activeProviderContextKey = contextKeyService.createKey<string | undefined>('scmProvider', void 0); this.activeProviderContextKey = contextKeyService.createKey<string | undefined>('scmProvider', void 0);
} }
...@@ -101,4 +100,17 @@ export class SCMService implements ISCMService { ...@@ -101,4 +100,17 @@ export class SCMService implements ISCMService {
} }
}); });
} }
private onDidProviderChange(provider: ISCMProvider): void {
this.statusBarDisposable.dispose();
const commands = provider.statusBarCommands || [];
const disposables = commands.map(c => this.statusbarService.addEntry({
text: c.title,
tooltip: c.tooltip,
command: c.id
}, MainThreadStatusBarAlignment.LEFT, 10000));
this.statusBarDisposable = combinedDisposable(disposables);
}
} }
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册