mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 04:49:35 +00:00
git: commit
This commit is contained in:
parent
b276b5e04b
commit
cb36e6c217
|
@ -94,6 +94,11 @@
|
|||
"dark": "resources/icons/dark/clean.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "git.commit",
|
||||
"title": "%command.commit%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.commitStaged",
|
||||
"title": "%command.commitStaged%",
|
||||
|
@ -165,6 +170,14 @@
|
|||
"category": "Git"
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"command": "git.commitWithInput",
|
||||
"key": "ctrl+enter",
|
||||
"mac": "cmd+enter",
|
||||
"when": "inSCMInput"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"scm/title": [
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"command.unstageAll": "Unstage All",
|
||||
"command.clean": "Clean",
|
||||
"command.cleanAll": "Clean All",
|
||||
"command.commit": "Commit",
|
||||
"command.commitStaged": "Commit Staged",
|
||||
"command.commitStagedSigned": "Commit Staged (Signed Off)",
|
||||
"command.commitAll": "Commit All",
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import { Uri, commands, scm, Disposable, SCMResourceGroup, SCMResource, window, workspace, QuickPickItem, OutputChannel } from 'vscode';
|
||||
import { IRef, RefType } from './git';
|
||||
import { Model, Resource, Status } from './model';
|
||||
import { CommitController } from './commit';
|
||||
import * as path from 'path';
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
|
@ -125,7 +126,11 @@ export class CommandCenter {
|
|||
|
||||
private disposables: Disposable[];
|
||||
|
||||
constructor(private model: Model, private outputChannel: OutputChannel) {
|
||||
constructor(
|
||||
private model: Model,
|
||||
private commitController: CommitController,
|
||||
private outputChannel: OutputChannel
|
||||
) {
|
||||
this.disposables = CommandCenter.Commands
|
||||
.map(({ commandId, method }) => commands.registerCommand(commandId, method, this));
|
||||
}
|
||||
|
@ -286,7 +291,7 @@ export class CommandCenter {
|
|||
return;
|
||||
}
|
||||
|
||||
return await this.model.clean(resource);
|
||||
await this.model.clean(resource);
|
||||
}
|
||||
|
||||
@CommandCenter.Command('git.cleanAll')
|
||||
|
@ -301,13 +306,45 @@ export class CommandCenter {
|
|||
return;
|
||||
}
|
||||
|
||||
return await this.model.clean(...this.model.workingTreeGroup.resources);
|
||||
await this.model.clean(...this.model.workingTreeGroup.resources);
|
||||
}
|
||||
|
||||
@CommandCenter.CatchErrors
|
||||
async commit(message: string): Promise<void> {
|
||||
private async _commit(fn: () => Promise<string>): Promise<boolean> {
|
||||
if (this.model.indexGroup.resources.length === 0 && this.model.workingTreeGroup.resources.length === 0) {
|
||||
window.showInformationMessage(localize('no changes', "There are no changes to commit."));
|
||||
return false;
|
||||
}
|
||||
|
||||
const message = await fn();
|
||||
|
||||
if (!message) {
|
||||
// TODO@joao: show modal dialog to confirm empty message commit
|
||||
return false;
|
||||
}
|
||||
|
||||
const all = this.model.indexGroup.resources.length === 0;
|
||||
return this.model.commit(message, { all });
|
||||
await this.model.commit(message, { all });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@CommandCenter.Command('git.commit')
|
||||
@CommandCenter.CatchErrors
|
||||
async commit(): Promise<void> {
|
||||
await this._commit(async () => await window.showInputBox({
|
||||
placeHolder: localize('commit message', "Commit message"),
|
||||
prompt: localize('provide commit message', "Please provide a commit message")
|
||||
}));
|
||||
}
|
||||
|
||||
@CommandCenter.Command('git.commitWithInput')
|
||||
@CommandCenter.CatchErrors
|
||||
async commitWithInput(): Promise<void> {
|
||||
const didCommit = await this._commit(async () => this.commitController.message);
|
||||
|
||||
if (didCommit) {
|
||||
this.commitController.message = '';
|
||||
}
|
||||
}
|
||||
|
||||
@CommandCenter.Command('git.commitStaged')
|
||||
|
|
|
@ -5,15 +5,16 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { workspace, window, languages, Disposable, Uri, TextDocumentChangeEvent, HoverProvider, Hover, TextEditor, Position, TextDocument, Range, TextEditorDecorationType } from 'vscode';
|
||||
import { workspace, window, languages, Disposable, Uri, TextDocumentChangeEvent, HoverProvider, Hover, TextEditor, Position, TextDocument, Range, TextEditorDecorationType, WorkspaceEdit } from 'vscode';
|
||||
import { Model } from './model';
|
||||
import { filterEvent } from './util';
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
const scmInputUri = Uri.parse('scm:input');
|
||||
|
||||
function isSCMInput(uri: Uri) {
|
||||
return uri.toString() === 'scm:input';
|
||||
return uri.toString() === scmInputUri.toString();
|
||||
}
|
||||
|
||||
interface Diagnostic {
|
||||
|
@ -22,7 +23,7 @@ interface Diagnostic {
|
|||
}
|
||||
|
||||
// TODO@Joao: hover dissapears if editor is scrolled
|
||||
export class CommitHandler implements HoverProvider {
|
||||
export class CommitController implements HoverProvider {
|
||||
|
||||
private visibleTextEditorsDisposable: Disposable;
|
||||
private editor: TextEditor;
|
||||
|
@ -30,6 +31,28 @@ export class CommitHandler implements HoverProvider {
|
|||
private decorationType: TextEditorDecorationType;
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
get message(): string | undefined {
|
||||
if (!this.editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.editor.document.getText();
|
||||
}
|
||||
|
||||
set message(message: string | undefined) {
|
||||
if (!this.editor || message === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const document = this.editor.document;
|
||||
const start = document.lineAt(0).range.start;
|
||||
const end = document.lineAt(document.lineCount - 1).range.end;
|
||||
const range = new Range(start, end);
|
||||
const edit = new WorkspaceEdit();
|
||||
edit.replace(scmInputUri, range, message);
|
||||
workspace.applyEdit(edit);
|
||||
}
|
||||
|
||||
constructor(private model: Model) {
|
||||
this.visibleTextEditorsDisposable = window.onDidChangeVisibleTextEditors(this.onVisibleTextEditors, this);
|
||||
this.onVisibleTextEditors(window.visibleTextEditors);
|
||||
|
|
|
@ -15,7 +15,7 @@ import { filterEvent, anyEvent } from './util';
|
|||
import { GitContentProvider } from './contentProvider';
|
||||
import { AutoFetcher } from './autofetch';
|
||||
import { MergeDecorator } from './merge';
|
||||
import { CommitHandler } from './commit';
|
||||
import { CommitController } from './commit';
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
const localize = nls.config()();
|
||||
|
@ -42,16 +42,17 @@ async function init(disposables: Disposable[]): Promise<void> {
|
|||
outputChannel.appendLine(localize('using git', "Using git {0} from {1}", info.version, info.path));
|
||||
git.onOutput(str => outputChannel.append(str), null, disposables);
|
||||
|
||||
const commandCenter = new CommandCenter(model, outputChannel);
|
||||
const commitHandler = new CommitController(model);
|
||||
const commandCenter = new CommandCenter(model, commitHandler, outputChannel);
|
||||
const provider = new GitSCMProvider(model, commandCenter);
|
||||
const contentProvider = new GitContentProvider(git, rootPath, onGitChange);
|
||||
const checkoutStatusBar = new CheckoutStatusBar(model);
|
||||
const syncStatusBar = new SyncStatusBar(model);
|
||||
const autoFetcher = new AutoFetcher(model);
|
||||
const mergeDecorator = new MergeDecorator(model);
|
||||
const commitHandler = new CommitHandler(model);
|
||||
|
||||
disposables.push(
|
||||
commitHandler,
|
||||
commandCenter,
|
||||
provider,
|
||||
contentProvider,
|
||||
|
@ -60,8 +61,7 @@ async function init(disposables: Disposable[]): Promise<void> {
|
|||
checkoutStatusBar,
|
||||
syncStatusBar,
|
||||
autoFetcher,
|
||||
mergeDecorator,
|
||||
commitHandler
|
||||
mergeDecorator
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,6 @@ export class GitSCMProvider implements SCMProvider {
|
|||
scm.registerSCMProvider('git', this);
|
||||
}
|
||||
|
||||
commit(message: string): Thenable<void> {
|
||||
return this.commandCenter.commit(message);
|
||||
}
|
||||
|
||||
open(resource: Resource): ProviderResult<void> {
|
||||
return this.commandCenter.open(resource);
|
||||
}
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IModel, IEditorOptions, IDimension } from 'vs/editor/common/editorCommon';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { EditorAction, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
|
||||
import { IEditorContributionCtor } from 'vs/editor/browser/editorBrowser';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { MenuPreventer } from 'vs/editor/contrib/multicursor/browser/menuPreventer';
|
||||
|
@ -26,6 +27,8 @@ import { IThemeService } from 'vs/workbench/services/themes/common/themeService'
|
|||
import URI from 'vs/base/common/uri';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { ITextModelResolverService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService';
|
||||
|
||||
class SCMCodeEditorWidget extends CodeEditorWidget {
|
||||
|
||||
|
@ -57,7 +60,9 @@ class SCMCodeEditorWidget extends CodeEditorWidget {
|
|||
}
|
||||
}
|
||||
|
||||
export class SCMEditor {
|
||||
export const InSCMInputContextKey = new RawContextKey<boolean>('inSCMInput', false);
|
||||
|
||||
export class SCMEditor implements ITextModelContentProvider {
|
||||
|
||||
private editor: SCMCodeEditorWidget;
|
||||
private model: IModel;
|
||||
|
@ -99,14 +104,28 @@ export class SCMEditor {
|
|||
constructor(
|
||||
container: HTMLElement,
|
||||
@IThemeService private themeService: IThemeService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IModelService private modelService: IModelService
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IModelService private modelService: IModelService,
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@ITextModelResolverService private textModelResolverService: ITextModelResolverService
|
||||
) {
|
||||
this.editor = this.instantiationService.createInstance(SCMCodeEditorWidget, container, this.editorOptions);
|
||||
this.model = this.modelService.createModel('', null, URI.parse(`scm:input`));
|
||||
this.editor.setModel(this.model);
|
||||
textModelResolverService.registerTextModelContentProvider('scm', this);
|
||||
|
||||
const scopedContextKeyService = this.contextKeyService.createScoped(container);
|
||||
InSCMInputContextKey.bindTo(scopedContextKeyService).set(true);
|
||||
this.disposables.push(scopedContextKeyService);
|
||||
|
||||
const services = new ServiceCollection();
|
||||
services.set(IContextKeyService, scopedContextKeyService);
|
||||
const scopedInstantiationService = instantiationService.createChild(services);
|
||||
|
||||
this.editor = scopedInstantiationService.createInstance(SCMCodeEditorWidget, container, this.editorOptions);
|
||||
this.themeService.onDidColorThemeChange(e => this.editor.updateOptions(this.editorOptions), null, this.disposables);
|
||||
|
||||
textModelResolverService.createModelReference(URI.parse('scm:input')).done(ref => {
|
||||
this.model = ref.object.textEditorModel;
|
||||
this.editor.setModel(this.model);
|
||||
});
|
||||
}
|
||||
|
||||
get lineHeight(): number {
|
||||
|
@ -115,6 +134,10 @@ export class SCMEditor {
|
|||
|
||||
// TODO@joao TODO@alex isn't there a better way to get the number of lines?
|
||||
get lineCount(): number {
|
||||
if (!this.model) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const modelLength = this.model.getValueLength();
|
||||
const lastPosition = this.model.getPositionAt(modelLength);
|
||||
const lastLineTop = this.editor.getTopForPosition(lastPosition.lineNumber, lastPosition.column);
|
||||
|
@ -131,6 +154,14 @@ export class SCMEditor {
|
|||
this.editor.focus();
|
||||
}
|
||||
|
||||
provideTextContent(resource: URI): TPromise<IModel> {
|
||||
if (resource.toString() !== 'scm:input') {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
return TPromise.as(this.modelService.createModel('', null, resource));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
import 'vs/css!./media/scmViewlet';
|
||||
import { localize } from 'vs/nls';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { chain } from 'vs/base/common/event';
|
||||
import { Throttler } from 'vs/base/common/async';
|
||||
|
@ -192,8 +191,6 @@ class CommitAction extends Action {
|
|||
|
||||
export class SCMViewlet extends Viewlet {
|
||||
|
||||
private static readonly ACCEPT_KEYBINDING = platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter';
|
||||
|
||||
private cachedDimension: Dimension;
|
||||
private editor: SCMEditor;
|
||||
private listContainer: HTMLElement;
|
||||
|
@ -319,13 +316,6 @@ export class SCMViewlet extends Viewlet {
|
|||
this.editor.focus();
|
||||
}
|
||||
|
||||
private acceptThrottler = new Throttler();
|
||||
private accept(): void {
|
||||
// this.acceptThrottler
|
||||
// .queue(() => this.scmService.activeProvider.commit(this.inputBox.value))
|
||||
// .done(() => this.inputBox.value = '', err => this.messageService.show(Severity.Error, err));
|
||||
}
|
||||
|
||||
private open(e: ISCMResource): void {
|
||||
this.scmService.activeProvider.open(e);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue