mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-13 01:58:01 +01:00
Merge branch 'scm-commit-box'
This commit is contained in:
@@ -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')
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
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() === scmInputUri.toString();
|
||||
}
|
||||
|
||||
interface Diagnostic {
|
||||
range: Range;
|
||||
message: string;
|
||||
}
|
||||
|
||||
// TODO@Joao: hover dissapears if editor is scrolled
|
||||
export class CommitController implements HoverProvider {
|
||||
|
||||
private visibleTextEditorsDisposable: Disposable;
|
||||
private editor: TextEditor;
|
||||
private diagnostics: Diagnostic[] = [];
|
||||
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);
|
||||
|
||||
this.decorationType = window.createTextEditorDecorationType({
|
||||
isWholeLine: true,
|
||||
color: 'rgb(228, 157, 43)',
|
||||
dark: {
|
||||
color: 'rgb(220, 211, 71)'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onVisibleTextEditors(editors: TextEditor[]): void {
|
||||
const [editor] = editors.filter(e => isSCMInput(e.document.uri));
|
||||
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.visibleTextEditorsDisposable.dispose();
|
||||
this.editor = editor;
|
||||
|
||||
const onDidChange = filterEvent(workspace.onDidChangeTextDocument, e => e.document && isSCMInput(e.document.uri));
|
||||
onDidChange(this.onSCMInputChange, this, this.disposables);
|
||||
|
||||
languages.registerHoverProvider({ scheme: 'scm' }, this);
|
||||
}
|
||||
|
||||
private onSCMInputChange(e: TextDocumentChangeEvent): void {
|
||||
this.diagnostics = [];
|
||||
|
||||
const range = e.document.lineAt(0).range;
|
||||
const length = range.end.character - range.start.character;
|
||||
|
||||
if (length > 80) {
|
||||
const message = localize('too long', "You should keep the first line under 50 characters.\n\nYou can use more lines for extra information.");
|
||||
this.diagnostics.push({ range, message });
|
||||
}
|
||||
|
||||
this.editor.setDecorations(this.decorationType, this.diagnostics.map(d => d.range));
|
||||
}
|
||||
|
||||
provideHover(document: TextDocument, position: Position): Hover | undefined {
|
||||
const [decoration] = this.diagnostics.filter(d => d.range.contains(position));
|
||||
|
||||
if (!decoration) {
|
||||
return;
|
||||
}
|
||||
|
||||
return new Hover(decoration.message, decoration.range);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables.forEach(d => d.dispose());
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import { filterEvent, anyEvent } from './util';
|
||||
import { GitContentProvider } from './contentProvider';
|
||||
import { AutoFetcher } from './autofetch';
|
||||
import { MergeDecorator } from './merge';
|
||||
import { CommitController } from './commit';
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
const localize = nls.config()();
|
||||
@@ -41,7 +42,8 @@ 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);
|
||||
@@ -50,6 +52,7 @@ async function init(disposables: Disposable[]): Promise<void> {
|
||||
const mergeDecorator = new MergeDecorator(model);
|
||||
|
||||
disposables.push(
|
||||
commitHandler,
|
||||
commandCenter,
|
||||
provider,
|
||||
contentProvider,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import EditorContextKeys = editorCommon.EditorContextKeys;
|
||||
|
||||
@editorContribution
|
||||
class ModesHoverController implements editorCommon.IEditorContribution {
|
||||
export class ModesHoverController implements editorCommon.IEditorContribution {
|
||||
|
||||
private static ID = 'editor.contrib.hover';
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ import 'vs/workbench/parts/search/browser/search.contribution';
|
||||
import 'vs/workbench/parts/search/browser/searchViewlet'; // can be packaged separately
|
||||
import 'vs/workbench/parts/search/browser/openAnythingHandler'; // can be packaged separately
|
||||
|
||||
import 'vs/workbench/parts/scm/browser/scm.contribution';
|
||||
import 'vs/workbench/parts/scm/browser/scmViewlet'; // can be packaged separately
|
||||
import 'vs/workbench/parts/scm/electron-browser/scm.contribution';
|
||||
import 'vs/workbench/parts/scm/electron-browser/scmViewlet'; // can be packaged separately
|
||||
|
||||
import 'vs/workbench/parts/git/electron-browser/git.contribution';
|
||||
import 'vs/workbench/parts/git/browser/gitQuickOpen';
|
||||
|
||||
|
Before Width: | Height: | Size: 194 B After Width: | Height: | Size: 194 B |
|
Before Width: | Height: | Size: 220 B After Width: | Height: | Size: 220 B |
|
Before Width: | Height: | Size: 871 B After Width: | Height: | Size: 871 B |
+1
-9
@@ -9,18 +9,10 @@
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.scm-viewlet > .scm-commit-box {
|
||||
.scm-viewlet > .scm-editor {
|
||||
padding: 5px 9px 5px 16px;
|
||||
}
|
||||
|
||||
.scm-viewlet > .scm-commit-box > .monaco-inputbox > .wrapper > .mirror {
|
||||
max-height: 134px;
|
||||
}
|
||||
|
||||
.scm-viewlet > .scm-commit-box.scroll > .monaco-inputbox > .wrapper > textarea.input {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.scm-viewlet .monaco-list-row {
|
||||
padding: 0 12px 0 20px;
|
||||
line-height: 22px;
|
||||
+2
-2
@@ -21,7 +21,7 @@ import { ISCMService } from 'vs/workbench/services/scm/common/scm';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { StatusUpdater } from './scmActivity';
|
||||
import SCMPreview, { DisableSCMPreviewAction, EnableSCMPreviewAction } from 'vs/workbench/parts/scm/browser/scmPreview';
|
||||
import SCMPreview, { DisableSCMPreviewAction, EnableSCMPreviewAction } from '../browser/scmPreview';
|
||||
|
||||
class OpenSCMViewletAction extends ToggleViewletAction {
|
||||
|
||||
@@ -64,7 +64,7 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
|
||||
|
||||
if (SCMPreview.enabled) {
|
||||
const viewletDescriptor = new ViewletDescriptor(
|
||||
'vs/workbench/parts/scm/browser/scmViewlet',
|
||||
'vs/workbench/parts/scm/electron-browser/scmViewlet',
|
||||
'SCMViewlet',
|
||||
VIEWLET_ID,
|
||||
localize('scm', "SCM"),
|
||||
@@ -0,0 +1,168 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'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, 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';
|
||||
import { SelectionClipboard } from 'vs/editor/contrib/selectionClipboard/electron-browser/selectionClipboard';
|
||||
import { ContextMenuController } from 'vs/editor/contrib/contextmenu/browser/contextmenu';
|
||||
import { SuggestController } from 'vs/editor/contrib/suggest/browser/suggestController';
|
||||
import { SnippetController } from 'vs/editor/contrib/snippet/common/snippetController';
|
||||
import { TabCompletionController } from 'vs/editor/contrib/suggest/browser/tabCompletion';
|
||||
import { ModesHoverController } from 'vs/editor/contrib/hover/browser/hover';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
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 {
|
||||
|
||||
constructor(
|
||||
domElement: HTMLElement,
|
||||
options: IEditorOptions,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
super(domElement, options, instantiationService, codeEditorService, commandService, contextKeyService);
|
||||
}
|
||||
|
||||
protected _getContributions(): IEditorContributionCtor[] {
|
||||
return [
|
||||
MenuPreventer,
|
||||
SelectionClipboard,
|
||||
ContextMenuController,
|
||||
SuggestController,
|
||||
SnippetController,
|
||||
TabCompletionController,
|
||||
ModesHoverController
|
||||
];
|
||||
}
|
||||
|
||||
protected _getActions(): EditorAction[] {
|
||||
return CommonEditorRegistry.getEditorActions();
|
||||
}
|
||||
}
|
||||
|
||||
export const InSCMInputContextKey = new RawContextKey<boolean>('inSCMInput', false);
|
||||
|
||||
export class SCMEditor implements ITextModelContentProvider {
|
||||
|
||||
private editor: SCMCodeEditorWidget;
|
||||
private model: IModel;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
@memoize
|
||||
get onDidChangeContent(): Event<void> {
|
||||
let listener: IDisposable;
|
||||
const emitter = new Emitter<void>({
|
||||
onFirstListenerAdd: () => listener = this.model.onDidChangeContent(() => emitter.fire()),
|
||||
onLastListenerRemove: () => dispose(listener)
|
||||
});
|
||||
|
||||
return emitter.event;
|
||||
}
|
||||
|
||||
private get editorOptions(): IEditorOptions {
|
||||
return {
|
||||
wrappingColumn: 0,
|
||||
overviewRulerLanes: 0,
|
||||
glyphMargin: false,
|
||||
lineNumbers: 'off',
|
||||
folding: false,
|
||||
selectOnLineNumbers: false,
|
||||
selectionHighlight: false,
|
||||
scrollbar: {
|
||||
horizontal: 'hidden'
|
||||
},
|
||||
lineDecorationsWidth: 0,
|
||||
scrollBeyondLastLine: false,
|
||||
theme: this.themeService.getColorTheme().id,
|
||||
renderLineHighlight: 'none',
|
||||
fixedOverflowWidgets: true,
|
||||
acceptSuggestionOnEnter: false,
|
||||
wordWrap: true
|
||||
};
|
||||
}
|
||||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
@IThemeService private themeService: IThemeService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IModelService private modelService: IModelService,
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@ITextModelResolverService private textModelResolverService: ITextModelResolverService
|
||||
) {
|
||||
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 {
|
||||
return this.editor.getConfiguration().lineHeight;
|
||||
}
|
||||
|
||||
// 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);
|
||||
const viewHeight = lastLineTop + this.lineHeight;
|
||||
|
||||
return viewHeight / this.lineHeight;
|
||||
}
|
||||
|
||||
layout(dimension: IDimension): void {
|
||||
this.editor.layout(dimension);
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
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);
|
||||
}
|
||||
}
|
||||
+27
-91
@@ -6,12 +6,8 @@
|
||||
'use strict';
|
||||
|
||||
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';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IDisposable, dispose, empty as EmptyDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Builder, Dimension } from 'vs/base/browser/builder';
|
||||
import { Viewlet } from 'vs/workbench/browser/viewlet';
|
||||
@@ -27,17 +23,16 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IMessageService, Severity } from 'vs/platform/message/common/message';
|
||||
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { IMessageService } from 'vs/platform/message/common/message';
|
||||
import { IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { Action, IAction, IActionItem } from 'vs/base/common/actions';
|
||||
import { IAction, IActionItem } from 'vs/base/common/actions';
|
||||
import { createActionItem } from 'vs/platform/actions/browser/menuItemActionItem';
|
||||
import { SCMMenus } from './scmMenus';
|
||||
import { ActionBar, IActionItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IThemeService } from 'vs/workbench/services/themes/common/themeService';
|
||||
import { isDarkTheme } from 'vs/platform/theme/common/themes';
|
||||
import { SCMEditor } from './scmEditor';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
|
||||
interface SearchInputEvent extends Event {
|
||||
target: HTMLInputElement;
|
||||
@@ -145,59 +140,10 @@ class Delegate implements IDelegate<ISCMResourceGroup | ISCMResource> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HACK
|
||||
*/
|
||||
class CommitAction extends Action {
|
||||
|
||||
private activeProvider: ISCMProvider;
|
||||
private isRunning = false;
|
||||
private throttler = new Throttler();
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
private inputBox: InputBox,
|
||||
@ISCMService scmService: ISCMService,
|
||||
@IMessageService private messageService: IMessageService
|
||||
) {
|
||||
super('scm.commit', localize('commit', "Commit"), 'scm-commit');
|
||||
|
||||
this.setActiveProvider(scmService.activeProvider);
|
||||
scmService.onDidChangeProvider(this.setActiveProvider, this, this.disposables);
|
||||
inputBox.onDidChange(this.updateEnablement, this, this.disposables);
|
||||
}
|
||||
|
||||
private setActiveProvider(activeProvider: ISCMProvider | undefined): void {
|
||||
this.activeProvider = activeProvider;
|
||||
this.updateEnablement();
|
||||
}
|
||||
|
||||
private updateEnablement(): void {
|
||||
this.enabled = !!this.activeProvider && !this.isRunning && !!this.inputBox.value;
|
||||
}
|
||||
|
||||
run(): TPromise<any> {
|
||||
return this.throttler
|
||||
.queue(() => {
|
||||
this.isRunning = true;
|
||||
return this.activeProvider.commit(this.inputBox.value);
|
||||
})
|
||||
.then(() => this.inputBox.value = '', err => this.messageService.show(Severity.Error, err))
|
||||
.then(() => this.isRunning = false);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
}
|
||||
|
||||
export class SCMViewlet extends Viewlet {
|
||||
|
||||
private static ACCEPT_KEYBINDING = platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter';
|
||||
|
||||
private cachedDimension: Dimension;
|
||||
private inputBoxContainer: HTMLElement;
|
||||
private inputBox: InputBox;
|
||||
private editor: SCMEditor;
|
||||
private listContainer: HTMLElement;
|
||||
private list: List<ISCMResourceGroup | ISCMResource>;
|
||||
private menus: SCMMenus;
|
||||
@@ -214,7 +160,8 @@ export class SCMViewlet extends Viewlet {
|
||||
@IMessageService private messageService: IMessageService,
|
||||
@IContextMenuService private contextMenuService: IContextMenuService,
|
||||
@IThemeService private themeService: IThemeService,
|
||||
@IMenuService private menuService: IMenuService
|
||||
@IMenuService private menuService: IMenuService,
|
||||
@IModelService private modelService: IModelService
|
||||
) {
|
||||
super(VIEWLET_ID, telemetryService);
|
||||
|
||||
@@ -240,22 +187,22 @@ export class SCMViewlet extends Viewlet {
|
||||
parent.addClass('scm-viewlet');
|
||||
|
||||
const root = parent.getHTMLElement();
|
||||
this.inputBoxContainer = append(root, $('.scm-commit-box'));
|
||||
const editorContainer = append(root, $('.scm-editor'));
|
||||
|
||||
this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, {
|
||||
placeholder: localize('accept', "Message (press {0} to submit)", SCMViewlet.ACCEPT_KEYBINDING),
|
||||
ariaLabel: localize('acceptAria', "Changes: Type message and press {0} to accept the changes", SCMViewlet.ACCEPT_KEYBINDING),
|
||||
flexibleHeight: true
|
||||
});
|
||||
this.editor = this.instantiationService.createInstance(SCMEditor, editorContainer);
|
||||
this.editor.onDidChangeContent(() => this.layout(), null, this.disposables);
|
||||
this.disposables.push(this.editor);
|
||||
|
||||
chain(domEvent(this.inputBox.inputElement, 'keydown'))
|
||||
.map(e => new StandardKeyboardEvent(e))
|
||||
.filter(e => e.equals(KeyMod.CtrlCmd | KeyCode.Enter) || e.equals(KeyMod.CtrlCmd | KeyCode.KEY_S))
|
||||
.on(this.accept, this, this.disposables);
|
||||
// this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, {
|
||||
// placeholder: localize('accept', "Message (press {0} to submit)", SCMViewlet.ACCEPT_KEYBINDING),
|
||||
// ariaLabel: localize('acceptAria', "Changes: Type message and press {0} to accept the changes", SCMViewlet.ACCEPT_KEYBINDING),
|
||||
// flexibleHeight: true
|
||||
// });
|
||||
|
||||
chain(this.inputBox.onDidHeightChange)
|
||||
.map(() => this.cachedDimension)
|
||||
.on(this.layout, this, this.disposables);
|
||||
// chain(domEvent(this.inputBox.inputElement, 'keydown'))
|
||||
// .map(e => new StandardKeyboardEvent(e))
|
||||
// .filter(e => e.equals(KeyMod.CtrlCmd | KeyCode.Enter) || e.equals(KeyMod.CtrlCmd | KeyCode.KEY_S))
|
||||
// .on(this.accept, this, this.disposables);
|
||||
|
||||
this.listContainer = append(root, $('.scm-status.show-file-icons'));
|
||||
const delegate = new Delegate();
|
||||
@@ -273,7 +220,7 @@ export class SCMViewlet extends Viewlet {
|
||||
.on(this.open, this, this.disposables);
|
||||
|
||||
this.list.onContextMenu(this.onListContextMenu, this, this.disposables);
|
||||
this.disposables.push(this.inputBox, this.list);
|
||||
this.disposables.push(this.list);
|
||||
|
||||
this.setActiveProvider(this.scmService.activeProvider);
|
||||
this.scmService.onDidChangeProvider(this.setActiveProvider, this, this.disposables);
|
||||
@@ -290,7 +237,6 @@ export class SCMViewlet extends Viewlet {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const elements = provider.resources
|
||||
.reduce<(ISCMResourceGroup | ISCMResource)[]>((r, g) => [...r, g, ...g.resources], []);
|
||||
|
||||
@@ -303,13 +249,13 @@ export class SCMViewlet extends Viewlet {
|
||||
}
|
||||
|
||||
this.cachedDimension = dimension;
|
||||
this.inputBox.layout();
|
||||
|
||||
const listHeight = dimension.height - (this.inputBox.height + 12 /* margin */);
|
||||
const editorHeight = Math.min(this.editor.lineCount, 8) * this.editor.lineHeight;
|
||||
this.editor.layout({ width: dimension.width - 25, height: editorHeight });
|
||||
|
||||
const listHeight = dimension.height - (editorHeight + 12 /* margin */);
|
||||
this.listContainer.style.height = `${listHeight}px`;
|
||||
this.list.layout(listHeight);
|
||||
|
||||
toggleClass(this.inputBoxContainer, 'scroll', this.inputBox.height >= 134);
|
||||
}
|
||||
|
||||
getOptimalWidth(): number {
|
||||
@@ -318,14 +264,7 @@ export class SCMViewlet extends Viewlet {
|
||||
|
||||
focus(): void {
|
||||
super.focus();
|
||||
this.inputBox.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));
|
||||
this.editor.focus();
|
||||
}
|
||||
|
||||
private open(e: ISCMResource): void {
|
||||
@@ -333,10 +272,7 @@ export class SCMViewlet extends Viewlet {
|
||||
}
|
||||
|
||||
getActions(): IAction[] {
|
||||
return [
|
||||
this.instantiationService.createInstance(CommitAction, this.inputBox),
|
||||
...this.menus.getTitleActions()
|
||||
];
|
||||
return this.menus.getTitleActions();
|
||||
}
|
||||
|
||||
getSecondaryActions(): IAction[] {
|
||||
Reference in New Issue
Block a user