From ca1deee166d0ff7a1209df1e69d8a12752218c39 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 21 Feb 2017 11:55:21 +0100 Subject: [PATCH] git: give up on using the editor fixes #20983 --- extensions/git/package.json | 8 - extensions/git/src/scmProvider.ts | 4 + product.json | 7 +- src/vs/vscode.proposed.d.ts | 1 + src/vs/workbench/api/node/extHost.protocol.ts | 2 + src/vs/workbench/api/node/extHostSCM.ts | 11 ++ src/vs/workbench/api/node/mainThreadSCM.ts | 14 +- src/vs/workbench/parts/git/browser/gitScm.ts | 4 + .../scm/electron-browser/media/scmViewlet.css | 29 ++-- .../parts/scm/electron-browser/scmEditor.ts | 145 ------------------ .../parts/scm/electron-browser/scmViewlet.ts | 37 +++-- src/vs/workbench/services/scm/common/scm.ts | 9 +- .../services/scm/common/scmService.ts | 42 ++--- 13 files changed, 112 insertions(+), 201 deletions(-) delete mode 100644 src/vs/workbench/parts/scm/electron-browser/scmEditor.ts diff --git a/extensions/git/package.json b/extensions/git/package.json index bd11f740c88..76055d4d169 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -212,14 +212,6 @@ "category": "Git" } ], - "keybindings": [ - { - "command": "git.commitWithInput", - "key": "ctrl+enter", - "mac": "cmd+enter", - "when": "inSCMInput" - } - ], "menus": { "commandPalette": [ { diff --git a/extensions/git/src/scmProvider.ts b/extensions/git/src/scmProvider.ts index 71dda0dec4c..7c064993ef4 100644 --- a/extensions/git/src/scmProvider.ts +++ b/extensions/git/src/scmProvider.ts @@ -49,6 +49,10 @@ export class GitSCMProvider implements SCMProvider { return this.commandCenter.open(resource); } + acceptChanges(): ProviderResult { + return this.commandCenter.commitWithInput(); + } + drag(resource: Resource, resourceGroup: ResourceGroup): void { console.log('drag', resource, resourceGroup); } diff --git a/product.json b/product.json index 49f852e2928..348457da81a 100644 --- a/product.json +++ b/product.json @@ -14,5 +14,10 @@ "win32ShellNameShort": "C&ode - OSS", "darwinBundleIdentifier": "com.visualstudio.code.oss", "reportIssueUrl": "https://github.com/Microsoft/vscode/issues/new", - "urlProtocol": "code-oss" + "urlProtocol": "code-oss", + "extensionsGallery": { + "serviceUrl": "https://marketplace.visualstudio.com/_apis/public/gallery", + "cacheUrl": "https://vscode.blob.core.windows.net/gallery/index", + "itemUrl": "https://marketplace.visualstudio.com/items" + } } \ No newline at end of file diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 660e6de1dfa..0ed123b7208 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -139,6 +139,7 @@ declare module 'vscode' { getOriginalResource?(uri: Uri, token: CancellationToken): ProviderResult; open?(resource: SCMResource, token: CancellationToken): ProviderResult; drag?(resource: SCMResource, resourceGroup: SCMResourceGroup, token: CancellationToken): ProviderResult; + acceptChanges?(token: CancellationToken): ProviderResult; } export interface SCMInputBox { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 1a0c54b595a..6387a7351b0 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -245,6 +245,7 @@ export abstract class MainProcessExtensionServiceShape { export interface SCMProviderFeatures { label: string; supportsOpen: boolean; + supportsAcceptChanges: boolean; supportsDrag: boolean; supportsOriginalResource: boolean; } @@ -394,6 +395,7 @@ export abstract class ExtHostTerminalServiceShape { export abstract class ExtHostSCMShape { $open(id: string, resourceGroupId: string, uri: string): TPromise { throw ni(); } + $acceptChanges(id: string): TPromise { throw ni(); } $drag(id: string, fromResourceGroupId: string, fromUri: string, toResourceGroupId: string): TPromise { throw ni(); } $getOriginalResource(id: string, uri: URI): TPromise { throw ni(); } $onInputBoxValueChange(value: string): TPromise { throw ni(); } diff --git a/src/vs/workbench/api/node/extHostSCM.ts b/src/vs/workbench/api/node/extHostSCM.ts index 978ca281f8e..e74f42aad19 100644 --- a/src/vs/workbench/api/node/extHostSCM.ts +++ b/src/vs/workbench/api/node/extHostSCM.ts @@ -152,6 +152,7 @@ export class ExtHostSCM { this._proxy.$register(providerId, { label: provider.label, supportsOpen: !!provider.open, + supportsAcceptChanges: !!provider.acceptChanges, supportsDrag: !!provider.drag, supportsOriginalResource: !!provider.getOriginalResource }); @@ -217,6 +218,16 @@ export class ExtHostSCM { return asWinJsPromise(token => provider.open(resource, token)); } + $acceptChanges(providerId: string): TPromise { + const provider = this._providers[providerId]; + + if (!provider) { + return TPromise.as(null); + } + + return asWinJsPromise(token => provider.acceptChanges(token)); + } + $drag(providerId: string, fromResourceGroupId: string, fromUri: string, toResourceGroupId: string): TPromise { const provider = this._providers[providerId]; diff --git a/src/vs/workbench/api/node/mainThreadSCM.ts b/src/vs/workbench/api/node/mainThreadSCM.ts index 5726da0a8e1..873d5bf4180 100644 --- a/src/vs/workbench/api/node/mainThreadSCM.ts +++ b/src/vs/workbench/api/node/mainThreadSCM.ts @@ -52,6 +52,14 @@ class MainThreadSCMProvider implements ISCMProvider { return this.proxy.$open(this.id, resource.resourceGroupId, resource.uri.toString()); } + acceptChanges(): TPromise { + if (!this.features.supportsAcceptChanges) { + return TPromise.as(null); + } + + return this.proxy.$acceptChanges(this.id); + } + drag(from: ISCMResource, to: ISCMResourceGroup): TPromise { if (!this.features.supportsDrag) { return TPromise.as(null); @@ -125,8 +133,8 @@ export class MainThreadSCM extends MainThreadSCMShape { super(); this.proxy = threadService.get(ExtHostContext.ExtHostSCM); - this.inputBoxListener = this.scmService.inputBoxModel.onDidChangeContent(e => { - this.proxy.$onInputBoxValueChange(this.scmService.inputBoxModel.getValue()); + this.inputBoxListener = this.scmService.input.onDidChange(value => { + this.proxy.$onInputBoxValueChange(value); }); } @@ -156,7 +164,7 @@ export class MainThreadSCM extends MainThreadSCMShape { } $setInputBoxValue(value: string): void { - this.scmService.inputBoxModel.setValue(value); + this.scmService.input.value = value; } dispose(): void { diff --git a/src/vs/workbench/parts/git/browser/gitScm.ts b/src/vs/workbench/parts/git/browser/gitScm.ts index 95cee05ea81..c88455979c7 100644 --- a/src/vs/workbench/parts/git/browser/gitScm.ts +++ b/src/vs/workbench/parts/git/browser/gitScm.ts @@ -48,6 +48,10 @@ export class GitSCMProvider implements IWorkbenchContribution, ISCMProvider, ITe return TPromise.wrapError('not implemented'); } + acceptChanges(): TPromise { + return TPromise.wrapError('not implemented'); + } + drag(from: ISCMResource, to: ISCMResourceGroup): TPromise { return TPromise.wrapError('not implemented'); } diff --git a/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css b/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css index 84ea63f415e..38482f3723e 100644 --- a/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css +++ b/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css @@ -9,10 +9,6 @@ background-position: center; } -.scm-viewlet > .scm-editor { - padding: 5px 9px 5px 16px; -} - .scm-viewlet .monaco-list-row { padding: 0 12px 0 20px; line-height: 22px; @@ -76,18 +72,27 @@ display: none; } -.monaco-shell.vs .scm-viewlet > .scm-editor > .monaco-editor.focused { - outline: 1px solid rgba(0, 122, 204, 0.4); +.scm-viewlet > .scm-editor { + padding: 5px 9px 5px 16px; } -.monaco-shell.vs-dark .scm-viewlet > .scm-editor > .monaco-editor.focused { - outline: 1px solid rgba(14, 99, 156, 0.6); +.scm-viewlet > .scm-editor { + box-sizing: border-box; + padding: 5px 9px 5px 16px; } -.monaco-shell.hc-black .scm-viewlet > .scm-editor > .monaco-editor { - outline: 1px solid #6fc3df; +.scm-viewlet > .scm-editor > .monaco-inputbox { + width: 100%; } -.monaco-shell.hc-black .scm-viewlet > .scm-editor > .monaco-editor.focused { - outline: 2px solid #f38518; +.scm-viewlet > .scm-editor > .monaco-inputbox > .wrapper > .mirror { + max-height: 134px; } + +.scm-viewlet > .scm-editor > .monaco-inputbox > .wrapper > textarea.input { + min-height: 26px; +} + +.scm-viewlet > .scm-editor.scroll > .monaco-inputbox > .wrapper > textarea.input { + overflow-y: scroll; +} \ No newline at end of file diff --git a/src/vs/workbench/parts/scm/electron-browser/scmEditor.ts b/src/vs/workbench/parts/scm/electron-browser/scmEditor.ts deleted file mode 100644 index 64449ee704c..00000000000 --- a/src/vs/workbench/parts/scm/electron-browser/scmEditor.ts +++ /dev/null @@ -1,145 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { IEditorOptions, IDimension } from 'vs/editor/common/editorCommon'; -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 { IModelService } from 'vs/editor/common/services/modelService'; -import { IThemeService } from 'vs/workbench/services/themes/common/themeService'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { ISCMService } from 'vs/workbench/services/scm/common/scm'; - -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 - ]; - } - - protected _getActions(): EditorAction[] { - return CommonEditorRegistry.getEditorActions(); - } -} - -export const InSCMInputContextKey = new RawContextKey('inSCMInput', false); - -export class SCMEditor { - - private static VerticalPadding = 4; - - private editor: SCMCodeEditorWidget; - private disposables: IDisposable[] = []; - - private get editorOptions(): IEditorOptions { - return { - wrappingColumn: 0, - overviewRulerLanes: 0, - glyphMargin: false, - lineNumbers: 'off', - folding: false, - selectOnLineNumbers: false, - selectionHighlight: false, - scrollbar: { - horizontal: 'hidden' - }, - lineDecorationsWidth: 3, - 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, - @IModeService private modeService: IModeService, - @IModelService private modelService: IModelService, - @IContextKeyService private contextKeyService: IContextKeyService, - @ISCMService private scmService: ISCMService - ) { - 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); - - const model = this.scmService.inputBoxModel; - this.editor.setModel(model); - - this.editor.changeViewZones(accessor => { - accessor.addZone({ - afterLineNumber: 0, - heightInPx: SCMEditor.VerticalPadding, - domNode: document.createElement('div') - }); - }); - } - - private get lineHeight(): number { - return this.editor.getConfiguration().lineHeight; - } - - // TODO@joao TODO@alex isn't there a better way to get the number of lines? - private get lineCount(): number { - const model = this.scmService.inputBoxModel; - const modelLength = model.getValueLength(); - const lastPosition = model.getPositionAt(modelLength); - const lastLineTop = this.editor.getTopForPosition(lastPosition.lineNumber, lastPosition.column); - const viewHeight = lastLineTop + this.lineHeight; - - return viewHeight / this.lineHeight; - } - - get viewHeight(): number { - return Math.min(this.lineCount, 8) * this.lineHeight + (SCMEditor.VerticalPadding); - } - - layout(dimension: IDimension): void { - this.editor.layout(dimension); - } - - focus(): void { - this.editor.focus(); - } - - dispose(): void { - this.disposables = dispose(this.disposables); - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index a05f153f3a1..0530f397b4f 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -8,10 +8,13 @@ import 'vs/css!./media/scmViewlet'; import { TPromise } from 'vs/base/common/winjs.base'; import { chain } from 'vs/base/common/event'; +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'; import { append, $, toggleClass } from 'vs/base/browser/dom'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { IDelegate, IRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list'; @@ -31,7 +34,7 @@ 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 { SCMEditor } from './scmEditor'; +import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import { IModelService } from 'vs/editor/common/services/modelService'; function isSCMResource(element: ISCMResourceGroup | ISCMResource): element is ISCMResource { @@ -153,7 +156,8 @@ class Delegate implements IDelegate { export class SCMViewlet extends Viewlet { private cachedDimension: Dimension; - private editor: SCMEditor; + private inputBoxContainer: HTMLElement; + private inputBox: InputBox; private listContainer: HTMLElement; private list: List; private menus: SCMMenus; @@ -199,12 +203,20 @@ export class SCMViewlet extends Viewlet { parent.addClass('scm-viewlet'); const root = parent.getHTMLElement(); - const editorContainer = append(root, $('.scm-editor')); + this.inputBoxContainer = append(root, $('.scm-editor')); - this.editor = this.instantiationService.createInstance(SCMEditor, editorContainer); - this.disposables.push(this.editor); + this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, { flexibleHeight: true }); + this.disposables.push(this.inputBox); - this.disposables.push(this.scmService.inputBoxModel.onDidChangeContent(() => this.layout())); + this.inputBox.value = this.scmService.input.value; + this.inputBox.onDidChange(value => this.scmService.input.value = value, null, this.disposables); + this.scmService.input.onDidChange(value => this.inputBox.value = value, null, this.disposables); + this.disposables.push(this.scmService.input.onDidChange(() => this.layout())); + + 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.acceptChanges, this, this.disposables); this.listContainer = append(root, $('.scm-status.show-file-icons')); const delegate = new Delegate(); @@ -257,13 +269,14 @@ export class SCMViewlet extends Viewlet { } this.cachedDimension = dimension; + this.inputBox.layout(); - const editorHeight = this.editor.viewHeight; - this.editor.layout({ width: dimension.width - 25, height: editorHeight }); - + const editorHeight = this.inputBox.height; const listHeight = dimension.height - (editorHeight + 12 /* margin */); this.listContainer.style.height = `${listHeight}px`; this.list.layout(listHeight); + + toggleClass(this.inputBoxContainer, 'scroll', editorHeight >= 134); } getOptimalWidth(): number { @@ -272,13 +285,17 @@ export class SCMViewlet extends Viewlet { focus(): void { super.focus(); - this.editor.focus(); + this.inputBox.focus(); } private open(e: ISCMResource): void { this.scmService.activeProvider.open(e); } + private acceptChanges(): void { + this.scmService.activeProvider.acceptChanges(); + } + getActions(): IAction[] { return this.menus.getTitleActions(); } diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index 42f1bc2272f..2d433fdf8f6 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -10,7 +10,6 @@ import URI from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { IModel } from 'vs/editor/common/editorCommon'; export interface IBaselineResourceProvider { getBaselineResource(resource: URI): TPromise; @@ -45,17 +44,23 @@ export interface ISCMProvider extends IDisposable { readonly state?: string; open(uri: ISCMResource): TPromise; + acceptChanges(): TPromise; drag(from: ISCMResource, to: ISCMResourceGroup): TPromise; getOriginalResource(uri: URI): TPromise; } +export interface ISCMInput { + value: string; + readonly onDidChange: Event; +} + export interface ISCMService { readonly _serviceBrand: any; readonly onDidChangeProvider: Event; readonly providers: ISCMProvider[]; + readonly input: ISCMInput; activeProvider: ISCMProvider | undefined; - readonly inputBoxModel: IModel; registerSCMProvider(provider: ISCMProvider): IDisposable; } \ No newline at end of file diff --git a/src/vs/workbench/services/scm/common/scmService.ts b/src/vs/workbench/services/scm/common/scmService.ts index 204b5dcb95d..5eb30f7f59d 100644 --- a/src/vs/workbench/services/scm/common/scmService.ts +++ b/src/vs/workbench/services/scm/common/scmService.ts @@ -7,14 +7,26 @@ import { IDisposable, toDisposable, empty as EmptyDisposable } from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; +import { memoize } from 'vs/base/common/decorators'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IModel } from 'vs/editor/common/editorCommon'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { RawText } from 'vs/editor/common/model/textModel'; -import { Model } from 'vs/editor/common/model/model'; -import { PLAINTEXT_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/modesRegistry'; -import { ISCMService, ISCMProvider } from './scm'; +import { ISCMService, ISCMProvider, ISCMInput } from './scm'; + +class SCMInput implements ISCMInput { + + private _value = ''; + + get value(): string { + return this._value; + } + + set value(value: string) { + this._value = value; + this._onDidChange.fire(value); + } + + private _onDidChange = new Emitter(); + get onDidChange(): Event { return this._onDidChange.event; } +} export class SCMService implements ISCMService { @@ -55,24 +67,14 @@ export class SCMService implements ISCMService { private _onDidChangeProvider = new Emitter(); get onDidChangeProvider(): Event { return this._onDidChangeProvider.event; } - private _inputBoxModel: IModel; - get inputBoxModel(): IModel { return this._inputBoxModel; } + @memoize + get input(): ISCMInput { return new SCMInput(); } constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @IModeService modeService: IModeService, - @IModelService modelService: IModelService + @IContextKeyService contextKeyService: IContextKeyService ) { this.activeProviderContextKey = contextKeyService.createKey('scmProvider', void 0); this.activeProviderStateContextKey = contextKeyService.createKey('scmProviderState', void 0); - - const options = modelService.getCreationOptions('git-commit'); - const rawText = RawText.fromString('', options); - - this._inputBoxModel = new Model(rawText, PLAINTEXT_LANGUAGE_IDENTIFIER); - - modeService.getOrCreateMode('git-commit') - .done(mode => this._inputBoxModel.setMode(mode.getLanguageIdentifier())); } registerSCMProvider(provider: ISCMProvider): IDisposable {