From a563b5e5e5d5fd0265d376cda71f9f3ab075ac81 Mon Sep 17 00:00:00 2001 From: Ilya Murav'jov Date: Wed, 17 Jan 2018 15:05:41 +0300 Subject: [PATCH 001/177] editor.insertSpaceAfterComment setting --- src/vs/editor/common/config/commonEditorConfig.ts | 5 +++++ src/vs/editor/contrib/comment/comment.ts | 3 ++- .../editor/contrib/comment/lineCommentCommand.ts | 14 +++++++++----- .../comment/test/lineCommentCommand.test.ts | 13 ++++++++----- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index 73339f9d245..4149e2093dc 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -643,6 +643,11 @@ const editorConfiguration: IConfigurationNode = { 'description': nls.localize('selectionClipboard', "Controls if the Linux primary clipboard should be supported."), 'included': platform.isLinux }, + 'editor.insertSpaceAfterComment': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('insertSpaceAfterComment', "Whether to insert space after comment character.") + }, 'diffEditor.renderSideBySide': { 'type': 'boolean', 'default': true, diff --git a/src/vs/editor/contrib/comment/comment.ts b/src/vs/editor/contrib/comment/comment.ts index a72eae7bc90..4f79eb765ba 100644 --- a/src/vs/editor/contrib/comment/comment.ts +++ b/src/vs/editor/contrib/comment/comment.ts @@ -12,6 +12,7 @@ import { registerEditorAction, IActionOptions, EditorAction, ServicesAccessor } import { BlockCommentCommand } from './blockCommentCommand'; import { LineCommentCommand, Type } from './lineCommentCommand'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; abstract class CommentLineAction extends EditorAction { @@ -33,7 +34,7 @@ abstract class CommentLineAction extends EditorAction { var opts = model.getOptions(); for (var i = 0; i < selections.length; i++) { - commands.push(new LineCommentCommand(selections[i], opts.tabSize, this._type)); + commands.push(new LineCommentCommand(selections[i], opts.tabSize, this._type, accessor.get(IConfigurationService))); } editor.pushUndoStop(); diff --git a/src/vs/editor/contrib/comment/lineCommentCommand.ts b/src/vs/editor/contrib/comment/lineCommentCommand.ts index 4a31a0424b7..f57f0f8fb6e 100644 --- a/src/vs/editor/contrib/comment/lineCommentCommand.ts +++ b/src/vs/editor/contrib/comment/lineCommentCommand.ts @@ -14,6 +14,7 @@ import { BlockCommentCommand } from './blockCommentCommand'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { CharCode } from 'vs/base/common/charCode'; import { ITextModel, IIdentifiedSingleEditOperation } from 'vs/editor/common/model'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export interface IInsertionPoint { ignore: boolean; @@ -52,7 +53,9 @@ export class LineCommentCommand implements editorCommon.ICommand { private _tabSize: number; private _type: Type; - constructor(selection: Selection, tabSize: number, type: Type) { + constructor(selection: Selection, tabSize: number, type: Type, + @IConfigurationService private _configurationService: IConfigurationService, + ) { this._selection = selection; this._tabSize = tabSize; this._type = type; @@ -198,7 +201,7 @@ export class LineCommentCommand implements editorCommon.ICommand { ops = LineCommentCommand._createRemoveLineCommentsOperations(data.lines, s.startLineNumber); } else { LineCommentCommand._normalizeInsertionPoint(model, data.lines, s.startLineNumber, this._tabSize); - ops = LineCommentCommand._createAddLineCommentsOperations(data.lines, s.startLineNumber); + ops = this._createAddLineCommentsOperations(data.lines, s.startLineNumber); } const cursorPosition = new Position(s.positionLineNumber, s.positionColumn); @@ -371,11 +374,12 @@ export class LineCommentCommand implements editorCommon.ICommand { /** * Generate edit operations in the add line comment case */ - public static _createAddLineCommentsOperations(lines: ILinePreflightData[], startLineNumber: number): IIdentifiedSingleEditOperation[] { + public _createAddLineCommentsOperations(lines: ILinePreflightData[], startLineNumber: number): IIdentifiedSingleEditOperation[] { var i: number, len: number, lineData: ILinePreflightData, - res: IIdentifiedSingleEditOperation[] = []; + res: IIdentifiedSingleEditOperation[] = [], + afterCommentStr = this._configurationService.getValue('editor.insertSpaceAfterComment') ? ' ' : ''; for (i = 0, len = lines.length; i < len; i++) { lineData = lines[i]; @@ -384,7 +388,7 @@ export class LineCommentCommand implements editorCommon.ICommand { continue; } - res.push(EditOperation.insert(new Position(startLineNumber + i, lineData.commentStrOffset + 1), lineData.commentStr + ' ')); + res.push(EditOperation.insert(new Position(startLineNumber + i, lineData.commentStrOffset + 1), lineData.commentStr + afterCommentStr)); } return res; diff --git a/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts index e1e61fa2262..dbfaed3786c 100644 --- a/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts @@ -15,18 +15,21 @@ import { TokenizationResult2 } from 'vs/editor/common/core/token'; import { MockMode } from 'vs/editor/test/common/mocks/mockMode'; import { CommentRule } from 'vs/editor/common/modes/languageConfiguration'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; + +var mockConfigService = new TestConfigurationService(); suite('Editor Contrib - Line Comment Command', () => { function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void { let mode = new CommentMode({ lineComment: '!@#', blockComment: [''] }); - testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection); + testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, mockConfigService), expectedLines, expectedSelection); mode.dispose(); } function testAddLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void { let mode = new CommentMode({ lineComment: '!@#', blockComment: [''] }); - testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.ForceAdd), expectedLines, expectedSelection); + testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.ForceAdd, mockConfigService), expectedLines, expectedSelection); mode.dispose(); } @@ -594,7 +597,7 @@ suite('Editor Contrib - Line Comment As Block Comment', () => { function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void { let mode = new CommentMode({ lineComment: '', blockComment: ['(', ')'] }); - testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection); + testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, mockConfigService), expectedLines, expectedSelection); mode.dispose(); } @@ -705,7 +708,7 @@ suite('Editor Contrib - Line Comment As Block Comment', () => { suite('Editor Contrib - Line Comment As Block Comment 2', () => { function testLineCommentCommand(lines: string[], selection: Selection, expectedLines: string[], expectedSelection: Selection): void { let mode = new CommentMode({ lineComment: null, blockComment: [''] }); - testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, expectedSelection); + testCommand(lines, mode.getLanguageIdentifier(), selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle, mockConfigService), expectedLines, expectedSelection); mode.dispose(); } @@ -944,7 +947,7 @@ suite('Editor Contrib - Line Comment in mixed modes', () => { lines, outerMode.getLanguageIdentifier(), selection, - (sel) => new LineCommentCommand(sel, 4, Type.Toggle), + (sel) => new LineCommentCommand(sel, 4, Type.Toggle, mockConfigService), expectedLines, expectedSelection ); From 94f10a489f4006d2d534a75ee761b88082511752 Mon Sep 17 00:00:00 2001 From: Ilya Murav'jov Date: Tue, 30 Jan 2018 03:52:50 +0300 Subject: [PATCH 002/177] fix tests --- src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts index dbfaed3786c..7e6df5d47d1 100644 --- a/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts @@ -18,6 +18,7 @@ import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageCo import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; var mockConfigService = new TestConfigurationService(); +mockConfigService.setUserConfiguration('editor', { 'insertSpaceAfterComment': true }); suite('Editor Contrib - Line Comment Command', () => { From 60c653ea6c7a5b940beab6c9498e000ebd838253 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 21 Nov 2019 18:42:47 +0100 Subject: [PATCH 003/177] wip: scm input editor --- .../contrib/scm/browser/media/scmViewlet.css | 12 +- .../contrib/scm/browser/repositoryPane.ts | 154 +++++++++++------- 2 files changed, 94 insertions(+), 72 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css b/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css index 1a56521f66e..f4dda15248f 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css +++ b/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css @@ -171,16 +171,8 @@ display: none; } -.scm-viewlet .scm-editor > .monaco-inputbox { - width: 100%; -} - -.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-container { + padding: 3px 4px; } .scm-viewlet .scm-editor.scroll > .monaco-inputbox > .wrapper > textarea.input { diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts index e4fa1369aed..ecc1d3b558b 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts @@ -5,13 +5,12 @@ import 'vs/css!./media/scmViewlet'; import { Event, Emitter } from 'vs/base/common/event'; -import { domEvent } from 'vs/base/browser/event'; import { basename, isEqual } from 'vs/base/common/resources'; import { IDisposable, Disposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle'; import { ViewletPane, IViewletPaneOptions } from 'vs/workbench/browser/parts/views/paneViewlet'; import { append, $, addClass, toggleClass, trackFocus, removeClass } from 'vs/base/browser/dom'; import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list'; -import { ISCMRepository, ISCMResourceGroup, ISCMResource, InputValidationType } from 'vs/workbench/contrib/scm/common/scm'; +import { ISCMRepository, ISCMResourceGroup, ISCMResource } from 'vs/workbench/contrib/scm/common/scm'; import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -27,14 +26,11 @@ import { SCMMenus } from './menus'; import { ActionBar, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; import { IThemeService, LIGHT } from 'vs/platform/theme/common/themeService'; import { isSCMResource, isSCMResourceGroup, connectPrimaryMenuToInlineActionBar } from './util'; -import { attachBadgeStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler'; -import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; -import { format } from 'vs/base/common/strings'; +import { attachBadgeStyler } from 'vs/platform/theme/common/styler'; import { WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ThrottledDelayer, disposableTimeout } from 'vs/base/common/async'; +import { disposableTimeout } from 'vs/base/common/async'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import * as platform from 'vs/base/common/platform'; import { ITreeNode, ITreeFilter, ITreeSorter, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; import { ResourceTree, IResourceNode } from 'vs/base/common/resourceTree'; import { ISequence, ISplice } from 'vs/base/common/sequence'; @@ -54,6 +50,11 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; import { Hasher } from 'vs/base/common/hash'; +import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget'; +import { ITextModel } from 'vs/editor/common/model'; +import { IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions'; +import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; +import { IModelService } from 'vs/editor/common/services/modelService'; type TreeElement = ISCMResourceGroup | IResourceNode | ISCMResource; @@ -578,20 +579,21 @@ export class ToggleViewModeAction extends Action { } } -function convertValidationType(type: InputValidationType): MessageType { - switch (type) { - case InputValidationType.Information: return MessageType.INFO; - case InputValidationType.Warning: return MessageType.WARNING; - case InputValidationType.Error: return MessageType.ERROR; - } -} +// function convertValidationType(type: InputValidationType): MessageType { +// switch (type) { +// case InputValidationType.Information: return MessageType.INFO; +// case InputValidationType.Warning: return MessageType.WARNING; +// case InputValidationType.Error: return MessageType.ERROR; +// } +// } export class RepositoryPane extends ViewletPane { private cachedHeight: number | undefined = undefined; private cachedWidth: number | undefined = undefined; - private inputBoxContainer!: HTMLElement; - private inputBox!: InputBox; + private inputContainer!: HTMLElement; + private inputEditor!: CodeEditorWidget; + private inputModel!: ITextModel; private listContainer!: HTMLElement; private tree!: WorkbenchCompressibleObjectTree; private viewModel!: ViewModel; @@ -599,7 +601,7 @@ export class RepositoryPane extends ViewletPane { private menus: SCMMenus; private toggleViewModelModeAction: ToggleViewModeAction | undefined; protected contextKeyService: IContextKeyService; - private commitTemplate = ''; + // private commitTemplate = ''; constructor( readonly repository: ISCMRepository, @@ -615,7 +617,8 @@ export class RepositoryPane extends ViewletPane { @IConfigurationService protected configurationService: IConfigurationService, @IContextKeyService contextKeyService: IContextKeyService, @IMenuService protected menuService: IMenuService, - @IStorageService private storageService: IStorageService + @IStorageService private storageService: IStorageService, + @IModelService private modelService: IModelService ) { super(options, keybindingService, contextMenuService, configurationService, contextKeyService); @@ -655,51 +658,76 @@ export class RepositoryPane extends ViewletPane { this._register(focusTracker); // Input - this.inputBoxContainer = append(container, $('.scm-editor')); + this.inputContainer = append(container, $('.scm-editor')); + const editorContainer = append(this.inputContainer, $('.scm-editor-container')); + // TODO@joao const updatePlaceholder = () => { - const binding = this.keybindingService.lookupKeybinding('scm.acceptInput'); - const label = binding ? binding.getLabel() : (platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter'); - const placeholder = format(this.repository.input.placeholder, label); + // const binding = this.keybindingService.lookupKeybinding('scm.acceptInput'); + // const label = binding ? binding.getLabel() : (platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter'); + // const placeholder = format(this.repository.input.placeholder, label); - this.inputBox.setPlaceHolder(placeholder); + // this.inputBox.setPlaceHolder(placeholder); }; - const validationDelayer = new ThrottledDelayer(200); - const validate = () => { - return this.repository.input.validateInput(this.inputBox.value, this.inputBox.inputElement.selectionStart || 0).then(result => { - if (!result) { - this.inputBox.inputElement.removeAttribute('aria-invalid'); - this.inputBox.hideMessage(); - } else { - this.inputBox.inputElement.setAttribute('aria-invalid', 'true'); - this.inputBox.showMessage({ content: result.message, type: convertValidationType(result.type) }); - } - }); + // const validationDelayer = new ThrottledDelayer(200); + // const validate = () => { + + // const position = this.inputEditor.getSelection()?.getStartPosition(); + // const offset = position && this.inputModel.getOffsetAt(position); + // const value = this.inputModel.getValue(); + + // return this.repository.input.validateInput(value, offset || 0).then(result => { + + // // TODO@joao + // if (!result) { + // // this.inputBox.inputElement.removeAttribute('aria-invalid'); + // // this.inputBox.hideMessage(); + // } else { + // // this.inputBox.inputElement.setAttribute('aria-invalid', 'true'); + // // this.inputBox.showMessage({ content: result.message, type: convertValidationType(result.type) }); + // } + // }); + // }; + + // const triggerValidation = () => validationDelayer.trigger(validate); + + const editorOptions: IEditorConstructionOptions = { + ...getSimpleEditorOptions() + }; + const codeEditorWidgetOptions: ICodeEditorWidgetOptions = { + isSimpleWidget: true }; - const triggerValidation = () => validationDelayer.trigger(validate); + this.inputEditor = this.instantiationService.createInstance(CodeEditorWidget, editorContainer, editorOptions, codeEditorWidgetOptions); - this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, { flexibleHeight: true, flexibleMaxHeight: 134 }); - this.inputBox.setEnabled(this.isBodyVisible()); - this._register(attachInputBoxStyler(this.inputBox, this.themeService)); - this._register(this.inputBox); + // this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, { flexibleHeight: true, flexibleMaxHeight: 134 }); + // this.inputBox.setEnabled(this.isBodyVisible()); + // this._register(attachInputBoxStyler(this.inputBox, this.themeService)); + this._register(this.inputEditor); - this._register(this.inputBox.onDidChange(triggerValidation, null)); + this._register(this.inputEditor.onDidFocusEditorText(() => addClass(editorContainer, 'synthetic-focus'))); + this._register(this.inputEditor.onDidBlurEditorText(() => removeClass(editorContainer, 'synthetic-focus'))); - const onKeyUp = domEvent(this.inputBox.inputElement, 'keyup'); - const onMouseUp = domEvent(this.inputBox.inputElement, 'mouseup'); - this._register(Event.any(onKeyUp, onMouseUp)(triggerValidation, null)); + let resource = URI.parse('scm://input'); + this.inputModel = this.modelService.createModel('', null, resource, true); + this.inputEditor.setModel(this.inputModel); - this.inputBox.value = this.repository.input.value; - this._register(this.inputBox.onDidChange(value => this.repository.input.value = value, null)); - this._register(this.repository.input.onDidChange(value => this.inputBox.value = value, null)); + // this._register(this.inputBox.onDidChange(triggerValidation, null)); + + // const onKeyUp = domEvent(this.inputBox.inputElement, 'keyup'); + // const onMouseUp = domEvent(this.inputBox.inputElement, 'mouseup'); + // this._register(Event.any(onKeyUp, onMouseUp)(triggerValidation, null)); + + // this.inputBox.value = this.repository.input.value; + // this._register(this.inputBox.onDidChange(value => this.repository.input.value = value, null)); + // this._register(this.repository.input.onDidChange(value => this.inputBox.value = value, null)); updatePlaceholder(); this._register(this.repository.input.onDidChangePlaceholder(updatePlaceholder, null)); this._register(this.keybindingService.onDidUpdateKeybindings(updatePlaceholder, null)); - this._register(this.inputBox.onDidHeightChange(() => this.layoutBody())); + // this._register(this.inputBox.onDidHeightChange(() => this.layoutBody())); if (this.repository.provider.onDidChangeCommitTemplate) { this._register(this.repository.provider.onDidChangeCommitTemplate(this.onDidChangeCommitTemplate, this)); @@ -822,15 +850,16 @@ export class RepositoryPane extends ViewletPane { this.cachedHeight = height; if (this.repository.input.visible) { - removeClass(this.inputBoxContainer, 'hidden'); - this.inputBox.layout(); + removeClass(this.inputContainer, 'hidden'); + this.inputEditor.layout({ height: 38, width: width! - 12 - 16 - 2 }); // TODO@joao - const editorHeight = this.inputBox.height; + const editorHeight = 40; // TODO@joao const listHeight = height - (editorHeight + 12 /* margin */); this.listContainer.style.height = `${listHeight}px`; this.tree.layout(listHeight, width); } else { - addClass(this.inputBoxContainer, 'hidden'); + addClass(this.inputContainer, 'hidden'); + // TODO@joao: disable editor this.listContainer.style.height = `${height}px`; this.tree.layout(height, width); @@ -842,7 +871,7 @@ export class RepositoryPane extends ViewletPane { if (this.isExpanded()) { if (this.repository.input.visible) { - this.inputBox.focus(); + this.inputEditor.focus(); } else { this.tree.domFocus(); } @@ -852,7 +881,7 @@ export class RepositoryPane extends ViewletPane { } private _onDidChangeVisibility(visible: boolean): void { - this.inputBox.setEnabled(visible); + // this.inputEditor.setEnabled(visible); this.viewModel.setVisible(visible); } @@ -929,19 +958,20 @@ export class RepositoryPane extends ViewletPane { .filter(r => !!r && !isSCMResourceGroup(r))! as any; } + // TODO@joao private onDidChangeCommitTemplate(): void { - if (typeof this.repository.provider.commitTemplate === 'undefined' || !this.repository.input.visible) { - return; - } + // if (typeof this.repository.provider.commitTemplate === 'undefined' || !this.repository.input.visible) { + // return; + // } - const oldCommitTemplate = this.commitTemplate; - this.commitTemplate = this.repository.provider.commitTemplate; + // const oldCommitTemplate = this.commitTemplate; + // this.commitTemplate = this.repository.provider.commitTemplate; - if (this.inputBox.value && this.inputBox.value !== oldCommitTemplate) { - return; - } + // if (this.inputBox.value && this.inputBox.value !== oldCommitTemplate) { + // return; + // } - this.inputBox.value = this.commitTemplate; + // this.inputBox.value = this.commitTemplate; } private updateInputBoxVisibility(): void { From f9a16cbf777f653a1fb0622b0a5d477055efc205 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 25 Nov 2019 12:26:01 +0100 Subject: [PATCH 004/177] editor: fix word wrap settings in simple editor --- src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index 29f6839f84b..a6b6117b2aa 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -211,6 +211,10 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution // in the settings editor... return; } + if (this.editor.isSimpleWidget) { + // in a simple widget... + return; + } // Ensure correct word wrap settings const newModel = this.editor.getModel(); if (!newModel) { From 8300c92f0e77293301fd4ac68bcb17b033f98ec5 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 25 Nov 2019 15:42:29 +0100 Subject: [PATCH 005/177] improve editor padding --- .../contrib/scm/browser/media/scmViewlet.css | 2 +- .../contrib/scm/browser/repositoryPane.ts | 27 +++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css b/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css index f4dda15248f..48e93bc55af 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css +++ b/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css @@ -172,7 +172,7 @@ } .scm-viewlet .scm-editor-container { - padding: 3px 4px; + padding: 1px; } .scm-viewlet .scm-editor.scroll > .monaco-inputbox > .wrapper > textarea.input { diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts index ecc1d3b558b..e0c4894d807 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts @@ -55,6 +55,10 @@ import { ITextModel } from 'vs/editor/common/model'; import { IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions'; import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; import { IModelService } from 'vs/editor/common/services/modelService'; +import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; +import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; +import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; +import { ContextMenuController } from 'vs/editor/contrib/contextmenu/contextmenu'; type TreeElement = ISCMResourceGroup | IResourceNode | ISCMResource; @@ -693,10 +697,18 @@ export class RepositoryPane extends ViewletPane { // const triggerValidation = () => validationDelayer.trigger(validate); const editorOptions: IEditorConstructionOptions = { - ...getSimpleEditorOptions() + ...getSimpleEditorOptions(), + lineDecorationsWidth: 4, + dragAndDrop: false, + // fontFamily: 'Arial' }; const codeEditorWidgetOptions: ICodeEditorWidgetOptions = { - isSimpleWidget: true + isSimpleWidget: true, + contributions: EditorExtensionsRegistry.getSomeEditorContributions([ + MenuPreventer.ID, + SelectionClipboardContributionID, + ContextMenuController.ID + ]) }; this.inputEditor = this.instantiationService.createInstance(CodeEditorWidget, editorContainer, editorOptions, codeEditorWidgetOptions); @@ -713,6 +725,10 @@ export class RepositoryPane extends ViewletPane { this.inputModel = this.modelService.createModel('', null, resource, true); this.inputEditor.setModel(this.inputModel); + this.inputEditor.changeViewZones(accessor => { + accessor.addZone({ afterLineNumber: 0, domNode: $('div'), heightInPx: 3 }); + }); + // this._register(this.inputBox.onDidChange(triggerValidation, null)); // const onKeyUp = domEvent(this.inputBox.inputElement, 'keyup'); @@ -851,10 +867,11 @@ export class RepositoryPane extends ViewletPane { if (this.repository.input.visible) { removeClass(this.inputContainer, 'hidden'); - this.inputEditor.layout({ height: 38, width: width! - 12 - 16 - 2 }); // TODO@joao + // const editorHeight = 25; // TODO@joao + const editorHeight = 250; // TODO@joao + this.inputEditor.layout({ height: editorHeight, width: width! - 12 - 16 - 2 /* - 8 */ }); // TODO@joao - const editorHeight = 40; // TODO@joao - const listHeight = height - (editorHeight + 12 /* margin */); + const listHeight = height - (editorHeight + 5 + 2 /* + 3 + 3 */ + 5); this.listContainer.style.height = `${listHeight}px`; this.tree.layout(listHeight, width); } else { From 4f07d93cf7569f2e2c2801635ac53cf5673105c0 Mon Sep 17 00:00:00 2001 From: jeanp413 Date: Sat, 28 Dec 2019 16:52:15 -0500 Subject: [PATCH 006/177] Fixes #79857 --- src/vs/base/browser/dom.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index b7a55a4ca64..40c7153ced7 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -287,7 +287,7 @@ export function addDisposableGenericMouseUpListner(node: EventTarget, handler: ( export function addDisposableNonBubblingMouseOutListener(node: Element, handler: (event: MouseEvent) => void): IDisposable { return addDisposableListener(node, 'mouseout', (e: MouseEvent) => { // Mouse out bubbles, so this is an attempt to ignore faux mouse outs coming from children elements - let toElement: Node | null = (e.relatedTarget || e.target); + let toElement: Node | null = (e.relatedTarget); while (toElement && toElement !== node) { toElement = toElement.parentNode; } @@ -302,7 +302,7 @@ export function addDisposableNonBubblingMouseOutListener(node: Element, handler: export function addDisposableNonBubblingPointerOutListener(node: Element, handler: (event: MouseEvent) => void): IDisposable { return addDisposableListener(node, 'pointerout', (e: MouseEvent) => { // Mouse out bubbles, so this is an attempt to ignore faux mouse outs coming from children elements - let toElement: Node | null = (e.relatedTarget || e.target); + let toElement: Node | null = (e.relatedTarget); while (toElement && toElement !== node) { toElement = toElement.parentNode; } From 5ed421a823d77f3c600db9d7d22fe65f38b4121e Mon Sep 17 00:00:00 2001 From: Brett Cannon <54418+brettcannon@users.noreply.github.com> Date: Tue, 31 Dec 2019 14:40:40 -0800 Subject: [PATCH 007/177] Fix a grammatical mistake in a docstring --- src/vs/vscode.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 1e9ffcc6d9c..a8131f133d9 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -9998,7 +9998,7 @@ declare module 'vscode' { export function getExtension(extensionId: string): Extension | undefined; /** - * Get an extension its full identifier in the form of: `publisher.name`. + * Get an extension by its full identifier in the form of: `publisher.name`. * * @param extensionId An extension identifier. * @return An extension or `undefined`. From 5a23709e39ab584755c648fa049f5a94e6ee5fb9 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 10 Jan 2020 15:34:17 +0100 Subject: [PATCH 008/177] WIP for #39441 --- .../client/src/cssMain.ts | 15 ++++++++- src/vs/editor/common/config/editorOptions.ts | 13 +++++++- .../editor/contrib/suggest/media/suggest.css | 31 ++++++++++++++++--- src/vs/editor/contrib/suggest/suggest.ts | 2 +- .../contrib/suggest/suggestController.ts | 2 +- .../editor/contrib/suggest/suggestWidget.ts | 9 +++++- .../suggest/test/completionModel.test.ts | 1 + src/vs/monaco.d.ts | 4 +++ 8 files changed, 68 insertions(+), 9 deletions(-) diff --git a/extensions/css-language-features/client/src/cssMain.ts b/extensions/css-language-features/client/src/cssMain.ts index 936176e9103..bc8bbdc9ff7 100644 --- a/extensions/css-language-features/client/src/cssMain.ts +++ b/extensions/css-language-features/client/src/cssMain.ts @@ -45,8 +45,8 @@ export function activate(context: ExtensionContext) { dataPaths }, middleware: { - // testing the replace / insert mode provideCompletionItem(document: TextDocument, position: Position, context: CompletionContext, token: CancellationToken, next: ProvideCompletionItemsSignature): ProviderResult { + // testing the replace / insert mode function updateRanges(item: CompletionItem) { const range = item.range; if (range && range.end.isAfter(position) && range.start.isBeforeOrEqual(position)) { @@ -54,10 +54,23 @@ export function activate(context: ExtensionContext) { item.range = undefined; } } + function updateProposals(r: CompletionItem[] | CompletionList | null | undefined): CompletionItem[] | CompletionList | null | undefined { if (r) { (Array.isArray(r) ? r : r.items).forEach(updateRanges); + + if (!Array.isArray(r)) { + r.isDetailsResolved = true; + r.items.forEach(i => { + if (i.kind === CompletionItemKind.Color) { + i.detail = i.documentation?.toString(); + } else { + i.detail = i.label; + } + }); + } } + return r; } const isThenable = (obj: ProviderResult): obj is Thenable => obj && (obj)['then']; diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 94af6b10d1b..feb53271431 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -2495,6 +2495,10 @@ export interface ISuggestOptions { * Max suggestions to show in suggestions. Defaults to 12. */ maxVisibleSuggestions?: number; + /** + * Always show inline details + */ + alwaysRevealInlineDetails?: boolean; /** * Show method-suggestions. */ @@ -2614,6 +2618,7 @@ class EditorSuggest extends BaseEditorOption .contents > .main > .readMore, +/** Inline type Label (details) **/ + .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .type-label, +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .type-label { + display: none; +} + +.monaco-editor .suggest-widget.always-reveal-inline-details .monaco-list .monaco-list-row > .contents > .main > .type-label, +.monaco-editor .suggest-widget.always-reveal-inline-details.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .type-label { + display: inline; +} + +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .type-label { + display: inline; +} + +/** readMore icon **/ + +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore, .monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .readMore, -.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .type-label, .monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { display: none; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .readMore, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .type-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { + display: inline; +} +.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.focused) > .contents > .main > .readMore { + display: inline; + visibility: hidden; +} + +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { display: inline; } diff --git a/src/vs/editor/contrib/suggest/suggest.ts b/src/vs/editor/contrib/suggest/suggest.ts index c2d3185ce7d..f408f88ec12 100644 --- a/src/vs/editor/contrib/suggest/suggest.ts +++ b/src/vs/editor/contrib/suggest/suggest.ts @@ -47,7 +47,7 @@ export class CompletionItem { idx?: number; word?: string; - // + // all details resolved, we can show them all readonly isDetailsResolved: boolean; constructor( diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index cdf2e4f41ef..a4330d1d438 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -43,7 +43,7 @@ import { SuggestRangeHighlighter } from 'vs/editor/contrib/suggest/suggestRangeH * Stop suggest widget from disappearing when clicking into other areas * For development purpose only */ -const _sticky = false; +const _sticky = true; class LineSuffix { diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 85358ea708f..24bb13a3043 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -517,7 +517,9 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate toggleClass(this.element, 'no-icons', !this.editor.getOption(EditorOption.suggest).showIcons); + const applyAlwaysRevealInlineDetailsStyle = () => toggleClass(this.element, 'always-reveal-inline-details', this.editor.getOption(EditorOption.suggest).alwaysRevealInlineDetails); applyIconStyle(); + applyAlwaysRevealInlineDetailsStyle(); let renderer = instantiationService.createInstance(Renderer, this, this.editor, triggerKeybindingLabel); @@ -538,7 +540,12 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate this.onListSelection(e))); this.toDispose.add(this.list.onFocusChange(e => this.onListFocus(e))); this.toDispose.add(this.editor.onDidChangeCursorSelection(() => this.onCursorSelectionChanged())); - this.toDispose.add(this.editor.onDidChangeConfiguration(e => e.hasChanged(EditorOption.suggest) && applyIconStyle())); + this.toDispose.add(this.editor.onDidChangeConfiguration(e => { + if (e.hasChanged(EditorOption.suggest)) { + applyIconStyle(); + applyAlwaysRevealInlineDetailsStyle(); + } + })); this.suggestWidgetVisible = SuggestContext.Visible.bindTo(contextKeyService); this.suggestWidgetMultipleSuggestions = SuggestContext.MultipleSuggestions.bindTo(contextKeyService); diff --git a/src/vs/editor/contrib/suggest/test/completionModel.test.ts b/src/vs/editor/contrib/suggest/test/completionModel.test.ts index 6a26c5fd584..c3bd3d76100 100644 --- a/src/vs/editor/contrib/suggest/test/completionModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/completionModel.test.ts @@ -41,6 +41,7 @@ suite('CompletionModel', function () { shareSuggestSelections: false, showIcons: true, maxVisibleSuggestions: 12, + alwaysRevealInlineDetails: false, showMethods: true, showFunctions: true, showConstructors: true, diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index ace85852ace..ba478dbc33a 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3381,6 +3381,10 @@ declare namespace monaco.editor { * Max suggestions to show in suggestions. Defaults to 12. */ maxVisibleSuggestions?: number; + /** + * Always show inline details + */ + alwaysRevealInlineDetails?: boolean; /** * Show method-suggestions. */ From 438c35c042b9d114244c7014528a4217c1bea78c Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Fri, 10 Jan 2020 17:59:06 +0000 Subject: [PATCH 009/177] Applying changes for shadow DOM --- src/vs/base/browser/dom.ts | 19 +++-- src/vs/base/browser/keyboardEvent.ts | 2 +- src/vs/base/browser/mouseEvent.ts | 2 +- .../editor/browser/controller/mouseTarget.ts | 5 +- src/vs/editor/browser/editorDom.ts | 84 +++++++++++++++++++ 5 files changed, 104 insertions(+), 8 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index b7a55a4ca64..5b48ad6478d 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -810,7 +810,7 @@ export function findParentWithClass(node: HTMLElement, clazz: string, stopAtClaz } } - node = node.parentNode; + node = node.parentNode || (node as any).host; } return null; @@ -820,7 +820,16 @@ export function hasParentWithClass(node: HTMLElement, clazz: string, stopAtClazz return !!findParentWithClass(node, clazz, stopAtClazzOrNode); } -export function createStyleSheet(container: HTMLElement = document.getElementsByTagName('head')[0]): HTMLStyleElement { +export function createStyleSheet(container: HTMLElement): HTMLStyleElement { + if (!container) { + if ((window as any).monacoShadowRoot) { + container = (window as any).monacoShadowRoot.querySelector('head'); + } + else { + container = document.getElementsByTagName('head')[0] + } + } + let style = document.createElement('style'); style.type = 'text/css'; style.media = 'screen'; @@ -979,7 +988,7 @@ export function saveParentsScrollTop(node: Element): number[] { let r: number[] = []; for (let i = 0; node && node.nodeType === node.ELEMENT_NODE; i++) { r[i] = node.scrollTop; - node = node.parentNode; + node = node.parentNode || (node as any).host; } return r; } @@ -989,7 +998,7 @@ export function restoreParentsScrollTop(node: Element, state: number[]): void { if (node.scrollTop !== state[i]) { node.scrollTop = state[i]; } - node = node.parentNode; + node = node.parentNode || (node as any).host; } } @@ -1172,7 +1181,7 @@ function findParentWithAttribute(node: Node | null, attribute: string): HTMLElem return node; } - node = node.parentNode; + node = node.parentNode || (node as any).host; } return null; diff --git a/src/vs/base/browser/keyboardEvent.ts b/src/vs/base/browser/keyboardEvent.ts index 03bdffc95ed..1f312c6fae1 100644 --- a/src/vs/base/browser/keyboardEvent.ts +++ b/src/vs/base/browser/keyboardEvent.ts @@ -228,7 +228,7 @@ export class StandardKeyboardEvent implements IKeyboardEvent { let e = source; this.browserEvent = e; - this.target = e.target; + this.target = (e as any).path ? (e as any).path[0] : e.target; this.ctrlKey = e.ctrlKey; this.shiftKey = e.shiftKey; diff --git a/src/vs/base/browser/mouseEvent.ts b/src/vs/base/browser/mouseEvent.ts index f3f2089100b..082a458f2f2 100644 --- a/src/vs/base/browser/mouseEvent.ts +++ b/src/vs/base/browser/mouseEvent.ts @@ -50,7 +50,7 @@ export class StandardMouseEvent implements IMouseEvent { this.middleButton = e.button === 1; this.rightButton = e.button === 2; - this.target = e.target; + this.target = (e as any).path ? (e as any).path[0] : e.target; this.detail = e.detail || 1; if (e.type === 'dblclick') { diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index c38191a19c6..3e75b7fa835 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -836,7 +836,10 @@ export class MouseTargetFactory { private static _actualDoHitTestWithCaretRangeFromPoint(ctx: HitTestContext, coords: ClientCoordinates): IHitTestResult { - const range: Range = document.caretRangeFromPoint(coords.clientX, coords.clientY); + const docOrRoot = (window as any).monacoShadowRoot || document; + const range: Range = docOrRoot.caretRangeFromPoint(coords.clientX, coords.clientY); + + //const range: Range = document.caretRangeFromPoint(coords.clientX, coords.clientY); if (!range || !range.startContainer) { return { diff --git a/src/vs/editor/browser/editorDom.ts b/src/vs/editor/browser/editorDom.ts index 9401fdd259e..1fd10f1932d 100644 --- a/src/vs/editor/browser/editorDom.ts +++ b/src/vs/editor/browser/editorDom.ts @@ -205,3 +205,87 @@ export class GlobalEditorMouseMoveMonitor extends Disposable { }); } } + + +// Dynamically polyfill the `caretRangeFromPoint` method +if (typeof ShadowRoot.prototype.caretRangeFromPoint === 'undefined') { + /** + * The `best I can do` polyfill for this method + */ + ShadowRoot.prototype.caretRangeFromPoint = function (x, y) { + + let range = document.createRange(); + + // Get the element under the point + let el:Element | null = this.elementFromPoint(x, y); + + if (el !== null) { + // Get the last child of the element until its firstChild is a text node + // This assumes that the pointer is on the right of the line, out of the tokens + // and that we want to get the offset of the last token of the line + while ((el as any).firstChild.nodeType !== (el as any).firstChild.TEXT_NODE) { + el = (el as any).lastChild; + } + + // Grab its rect + let rect = (el as any).getBoundingClientRect(); + + // And its font + let font = window.getComputedStyle(el as any, null).getPropertyValue('font'); + + // And also its txt content + let text = (el as any).innerText; + + // Position the pixel cursor at the left of the element + let pixelCursor = rect.left; + let offset = 0; + let step; + + // If the point is on the right of the box put the cursor after the last character + if (x > rect.left + rect.width) { + offset = text.length; + } else { + // Goes through all the characters of the innerText, and checks if the x of the point + // belongs to the character. + for (let i = 0; i < text.length + 1; i++) { + // The step is half the width of the character + step = (window as any)._getCharWidth(text.charAt(i), font) / 2; + // Move to the center of the character + pixelCursor += step; + // If the x of the point is smaller that the position of the cursor, the point is over that character + if (x < pixelCursor) { + offset = i; + break; + } + // Move between the current character and the next + pixelCursor += step; + } + } + + // Creates a range with the text node of the element and set the offset found + range.setStart((el as any).firstChild, offset); + range.setEnd((el as any).firstChild, offset); + } + + return range; + }; +} + +(function (window) { + (window as any)._getCharWidth = (char:any, font:any) => { + let cacheKey = char + font; + if ((window as any)._getCharWidth._cache[cacheKey]) { + return (window as any)._getCharWidth._cache[cacheKey]; + } + + let context = (window as any)._getCharWidth._canvas.getContext("2d"); + context.font = font; + let metrics = context.measureText(char); + let width = metrics.width; + (window as any)._getCharWidth._cache[cacheKey] = width; + return width; + } + + (window as any)._getCharWidth._cache = {}; + (window as any)._getCharWidth._canvas = document.createElement('canvas'); +})(window); From c5771a3cb61fa62ac79bc92418adacd67c78c4aa Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Mon, 13 Jan 2020 09:36:48 +0000 Subject: [PATCH 010/177] Small changes to ShadowDOM --- src/vs/base/browser/dom.ts | 2 +- src/vs/editor/browser/editorDom.ts | 130 +++++++++++++++++------------ 2 files changed, 78 insertions(+), 54 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 5b48ad6478d..5bf15cdfa1b 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -826,7 +826,7 @@ export function createStyleSheet(container: HTMLElement): HTMLStyleElement { container = (window as any).monacoShadowRoot.querySelector('head'); } else { - container = document.getElementsByTagName('head')[0] + container = document.getElementsByTagName('head')[0]; } } diff --git a/src/vs/editor/browser/editorDom.ts b/src/vs/editor/browser/editorDom.ts index 1fd10f1932d..aeb5c00029c 100644 --- a/src/vs/editor/browser/editorDom.ts +++ b/src/vs/editor/browser/editorDom.ts @@ -14,10 +14,7 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; export class PageCoordinates { _pageCoordinatesBrand: void; - constructor( - public readonly x: number, - public readonly y: number - ) { } + constructor(public readonly x: number, public readonly y: number) { } public toClientCoordinates(): ClientCoordinates { return new ClientCoordinates(this.x - dom.StandardWindow.scrollX, this.y - dom.StandardWindow.scrollY); @@ -34,10 +31,7 @@ export class PageCoordinates { export class ClientCoordinates { _clientCoordinatesBrand: void; - constructor( - public readonly clientX: number, - public readonly clientY: number - ) { } + constructor(public readonly clientX: number, public readonly clientY: number) { } public toPageCoordinates(): PageCoordinates { return new PageCoordinates(this.clientX + dom.StandardWindow.scrollX, this.clientY + dom.StandardWindow.scrollY); @@ -88,7 +82,6 @@ export interface EditorMouseEventMerger { } export class EditorMouseEventFactory { - private readonly _editorViewDomNode: HTMLElement; constructor(editorViewDomNode: HTMLElement) { @@ -123,16 +116,29 @@ export class EditorMouseEventFactory { }); } - public onMouseMoveThrottled(target: HTMLElement, callback: (e: EditorMouseEvent) => void, merger: EditorMouseEventMerger, minimumTimeMs: number): IDisposable { - const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => { + public onMouseMoveThrottled( + target: HTMLElement, + callback: (e: EditorMouseEvent) => void, + merger: EditorMouseEventMerger, + minimumTimeMs: number + ): IDisposable { + const myMerger: dom.IEventMerger = ( + lastEvent: EditorMouseEvent | null, + currentEvent: MouseEvent + ): EditorMouseEvent => { return merger(lastEvent, this._create(currentEvent)); }; - return dom.addDisposableThrottledListener(target, 'mousemove', callback, myMerger, minimumTimeMs); + return dom.addDisposableThrottledListener( + target, + 'mousemove', + callback, + myMerger, + minimumTimeMs + ); } } export class EditorPointerEventFactory { - private readonly _editorViewDomNode: HTMLElement; constructor(editorViewDomNode: HTMLElement) { @@ -161,16 +167,29 @@ export class EditorPointerEventFactory { }); } - public onPointerMoveThrottled(target: HTMLElement, callback: (e: EditorMouseEvent) => void, merger: EditorMouseEventMerger, minimumTimeMs: number): IDisposable { - const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => { + public onPointerMoveThrottled( + target: HTMLElement, + callback: (e: EditorMouseEvent) => void, + merger: EditorMouseEventMerger, + minimumTimeMs: number + ): IDisposable { + const myMerger: dom.IEventMerger = ( + lastEvent: EditorMouseEvent | null, + currentEvent: MouseEvent + ): EditorMouseEvent => { return merger(lastEvent, this._create(currentEvent)); }; - return dom.addDisposableThrottledListener(target, 'pointermove', callback, myMerger, minimumTimeMs); + return dom.addDisposableThrottledListener( + target, + 'pointermove', + callback, + myMerger, + minimumTimeMs + ); } } export class GlobalEditorMouseMoveMonitor extends Disposable { - private readonly _editorViewDomNode: HTMLElement; protected readonly _globalMouseMoveMonitor: GlobalMouseMoveMonitor; private _keydownListener: IDisposable | null; @@ -182,20 +201,31 @@ export class GlobalEditorMouseMoveMonitor extends Disposable { this._keydownListener = null; } - public startMonitoring(merger: EditorMouseEventMerger, mouseMoveCallback: (e: EditorMouseEvent) => void, onStopCallback: () => void): void { - + public startMonitoring( + merger: EditorMouseEventMerger, + mouseMoveCallback: (e: EditorMouseEvent) => void, + onStopCallback: () => void + ): void { // Add a <> keydown event listener that will cancel the monitoring // if something other than a modifier key is pressed - this._keydownListener = dom.addStandardDisposableListener(document, 'keydown', (e) => { - const kb = e.toKeybinding(); - if (kb.isModifierKey()) { - // Allow modifier keys - return; - } - this._globalMouseMoveMonitor.stopMonitoring(true); - }, true); + this._keydownListener = dom.addStandardDisposableListener( + document, + 'keydown', + e => { + const kb = e.toKeybinding(); + if (kb.isModifierKey()) { + // Allow modifier keys + return; + } + this._globalMouseMoveMonitor.stopMonitoring(true); + }, + true + ); - const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => { + const myMerger: dom.IEventMerger = ( + lastEvent: EditorMouseEvent | null, + currentEvent: MouseEvent + ): EditorMouseEvent => { return merger(lastEvent, new EditorMouseEvent(currentEvent, this._editorViewDomNode)); }; @@ -206,18 +236,12 @@ export class GlobalEditorMouseMoveMonitor extends Disposable { } } - -// Dynamically polyfill the `caretRangeFromPoint` method if (typeof ShadowRoot.prototype.caretRangeFromPoint === 'undefined') { - /** - * The `best I can do` polyfill for this method - */ - ShadowRoot.prototype.caretRangeFromPoint = function (x, y) { - + ShadowRoot.prototype.caretRangeFromPoint = function (x, y) { let range = document.createRange(); - // Get the element under the point - let el:Element | null = this.elementFromPoint(x, y); + // Get the element under the point + let el: Element | null = this.elementFromPoint(x, y); if (el !== null) { // Get the last child of the element until its firstChild is a text node @@ -267,25 +291,25 @@ if (typeof ShadowRoot.prototype.caretRangeFromPoint === 'undefined') { range.setEnd((el as any).firstChild, offset); } - return range; - }; + return range; + }; } (function (window) { - (window as any)._getCharWidth = (char:any, font:any) => { - let cacheKey = char + font; - if ((window as any)._getCharWidth._cache[cacheKey]) { - return (window as any)._getCharWidth._cache[cacheKey]; - } + (window as any)._getCharWidth = (char: any, font: any) => { + let cacheKey = char + font; + if ((window as any)._getCharWidth._cache[cacheKey]) { + return (window as any)._getCharWidth._cache[cacheKey]; + } - let context = (window as any)._getCharWidth._canvas.getContext("2d"); - context.font = font; - let metrics = context.measureText(char); - let width = metrics.width; - (window as any)._getCharWidth._cache[cacheKey] = width; - return width; - } + let context = (window as any)._getCharWidth._canvas.getContext('2d'); + context.font = font; + let metrics = context.measureText(char); + let width = metrics.width; + (window as any)._getCharWidth._cache[cacheKey] = width; + return width; + }; - (window as any)._getCharWidth._cache = {}; - (window as any)._getCharWidth._canvas = document.createElement('canvas'); + (window as any)._getCharWidth._cache = {}; + (window as any)._getCharWidth._canvas = document.createElement('canvas'); })(window); From a6990443cb1f1813948bba71f4f4aeb0a63df6a0 Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Mon, 13 Jan 2020 10:04:11 +0000 Subject: [PATCH 011/177] Fix formatting --- src/vs/editor/browser/editorDom.ts | 89 +++++++++++------------------- 1 file changed, 31 insertions(+), 58 deletions(-) diff --git a/src/vs/editor/browser/editorDom.ts b/src/vs/editor/browser/editorDom.ts index aeb5c00029c..91a89670f08 100644 --- a/src/vs/editor/browser/editorDom.ts +++ b/src/vs/editor/browser/editorDom.ts @@ -14,7 +14,10 @@ import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; export class PageCoordinates { _pageCoordinatesBrand: void; - constructor(public readonly x: number, public readonly y: number) { } + constructor( + public readonly x: number, + public readonly y: number + ) { } public toClientCoordinates(): ClientCoordinates { return new ClientCoordinates(this.x - dom.StandardWindow.scrollX, this.y - dom.StandardWindow.scrollY); @@ -31,7 +34,10 @@ export class PageCoordinates { export class ClientCoordinates { _clientCoordinatesBrand: void; - constructor(public readonly clientX: number, public readonly clientY: number) { } + constructor( + public readonly clientX: number, + public readonly clientY: number + ) { } public toPageCoordinates(): PageCoordinates { return new PageCoordinates(this.clientX + dom.StandardWindow.scrollX, this.clientY + dom.StandardWindow.scrollY); @@ -82,6 +88,7 @@ export interface EditorMouseEventMerger { } export class EditorMouseEventFactory { + private readonly _editorViewDomNode: HTMLElement; constructor(editorViewDomNode: HTMLElement) { @@ -116,29 +123,16 @@ export class EditorMouseEventFactory { }); } - public onMouseMoveThrottled( - target: HTMLElement, - callback: (e: EditorMouseEvent) => void, - merger: EditorMouseEventMerger, - minimumTimeMs: number - ): IDisposable { - const myMerger: dom.IEventMerger = ( - lastEvent: EditorMouseEvent | null, - currentEvent: MouseEvent - ): EditorMouseEvent => { + public onMouseMoveThrottled(target: HTMLElement, callback: (e: EditorMouseEvent) => void, merger: EditorMouseEventMerger, minimumTimeMs: number): IDisposable { + const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => { return merger(lastEvent, this._create(currentEvent)); }; - return dom.addDisposableThrottledListener( - target, - 'mousemove', - callback, - myMerger, - minimumTimeMs - ); + return dom.addDisposableThrottledListener(target, 'mousemove', callback, myMerger, minimumTimeMs); } } export class EditorPointerEventFactory { + private readonly _editorViewDomNode: HTMLElement; constructor(editorViewDomNode: HTMLElement) { @@ -167,29 +161,16 @@ export class EditorPointerEventFactory { }); } - public onPointerMoveThrottled( - target: HTMLElement, - callback: (e: EditorMouseEvent) => void, - merger: EditorMouseEventMerger, - minimumTimeMs: number - ): IDisposable { - const myMerger: dom.IEventMerger = ( - lastEvent: EditorMouseEvent | null, - currentEvent: MouseEvent - ): EditorMouseEvent => { + public onPointerMoveThrottled(target: HTMLElement, callback: (e: EditorMouseEvent) => void, merger: EditorMouseEventMerger, minimumTimeMs: number): IDisposable { + const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => { return merger(lastEvent, this._create(currentEvent)); }; - return dom.addDisposableThrottledListener( - target, - 'pointermove', - callback, - myMerger, - minimumTimeMs - ); + return dom.addDisposableThrottledListener(target, 'pointermove', callback, myMerger, minimumTimeMs); } } export class GlobalEditorMouseMoveMonitor extends Disposable { + private readonly _editorViewDomNode: HTMLElement; protected readonly _globalMouseMoveMonitor: GlobalMouseMoveMonitor; private _keydownListener: IDisposable | null; @@ -201,31 +182,20 @@ export class GlobalEditorMouseMoveMonitor extends Disposable { this._keydownListener = null; } - public startMonitoring( - merger: EditorMouseEventMerger, - mouseMoveCallback: (e: EditorMouseEvent) => void, - onStopCallback: () => void - ): void { + public startMonitoring(merger: EditorMouseEventMerger, mouseMoveCallback: (e: EditorMouseEvent) => void, onStopCallback: () => void): void { + // Add a <> keydown event listener that will cancel the monitoring // if something other than a modifier key is pressed - this._keydownListener = dom.addStandardDisposableListener( - document, - 'keydown', - e => { - const kb = e.toKeybinding(); - if (kb.isModifierKey()) { - // Allow modifier keys - return; - } - this._globalMouseMoveMonitor.stopMonitoring(true); - }, - true - ); + this._keydownListener = dom.addStandardDisposableListener(document, 'keydown', (e) => { + const kb = e.toKeybinding(); + if (kb.isModifierKey()) { + // Allow modifier keys + return; + } + this._globalMouseMoveMonitor.stopMonitoring(true); + }, true); - const myMerger: dom.IEventMerger = ( - lastEvent: EditorMouseEvent | null, - currentEvent: MouseEvent - ): EditorMouseEvent => { + const myMerger: dom.IEventMerger = (lastEvent: EditorMouseEvent | null, currentEvent: MouseEvent): EditorMouseEvent => { return merger(lastEvent, new EditorMouseEvent(currentEvent, this._editorViewDomNode)); }; @@ -236,8 +206,11 @@ export class GlobalEditorMouseMoveMonitor extends Disposable { } } + if (typeof ShadowRoot.prototype.caretRangeFromPoint === 'undefined') { + ShadowRoot.prototype.caretRangeFromPoint = function (x, y) { + let range = document.createRange(); // Get the element under the point From b4bed747eb17efe1954dee0e3e1ee449ff15b78d Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Mon, 13 Jan 2020 12:24:27 +0000 Subject: [PATCH 012/177] Formatting changes --- src/vs/base/browser/keyboardEvent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/browser/keyboardEvent.ts b/src/vs/base/browser/keyboardEvent.ts index 1f312c6fae1..9303029b89c 100644 --- a/src/vs/base/browser/keyboardEvent.ts +++ b/src/vs/base/browser/keyboardEvent.ts @@ -228,7 +228,7 @@ export class StandardKeyboardEvent implements IKeyboardEvent { let e = source; this.browserEvent = e; - this.target = (e as any).path ? (e as any).path[0] : e.target; + this.target = (e as any).path ? (e as any).path[0] : e.target; this.ctrlKey = e.ctrlKey; this.shiftKey = e.shiftKey; From 4766c9d226da8828b2661089f2908c73ff63c953 Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Mon, 13 Jan 2020 12:51:40 +0000 Subject: [PATCH 013/177] Fixing small issue in dom.ts --- src/vs/base/browser/dom.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 5bf15cdfa1b..f45c1697c78 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -820,7 +820,7 @@ export function hasParentWithClass(node: HTMLElement, clazz: string, stopAtClazz return !!findParentWithClass(node, clazz, stopAtClazzOrNode); } -export function createStyleSheet(container: HTMLElement): HTMLStyleElement { +export function createStyleSheet(container: HTMLElement | null): HTMLStyleElement { if (!container) { if ((window as any).monacoShadowRoot) { container = (window as any).monacoShadowRoot.querySelector('head'); @@ -833,7 +833,7 @@ export function createStyleSheet(container: HTMLElement): HTMLStyleElement { let style = document.createElement('style'); style.type = 'text/css'; style.media = 'screen'; - container.appendChild(style); + (container as HTMLElement).appendChild(style); return style; } @@ -846,7 +846,7 @@ export function createMetaElement(container: HTMLElement = document.getElementsB let _sharedStyleSheet: HTMLStyleElement | null = null; function getSharedStyleSheet(): HTMLStyleElement { if (!_sharedStyleSheet) { - _sharedStyleSheet = createStyleSheet(); + _sharedStyleSheet = createStyleSheet(null); } return _sharedStyleSheet; } From 9d2b165a056dd101e1d7abd5d9f3ee773c0991eb Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Mon, 13 Jan 2020 14:30:10 +0000 Subject: [PATCH 014/177] Fixing build isssues --- src/vs/base/browser/dom.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index f45c1697c78..2e738925710 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -820,7 +820,7 @@ export function hasParentWithClass(node: HTMLElement, clazz: string, stopAtClazz return !!findParentWithClass(node, clazz, stopAtClazzOrNode); } -export function createStyleSheet(container: HTMLElement | null): HTMLStyleElement { +export function createStyleSheet(container: HTMLElement | null = null): HTMLStyleElement { if (!container) { if ((window as any).monacoShadowRoot) { container = (window as any).monacoShadowRoot.querySelector('head'); @@ -846,7 +846,7 @@ export function createMetaElement(container: HTMLElement = document.getElementsB let _sharedStyleSheet: HTMLStyleElement | null = null; function getSharedStyleSheet(): HTMLStyleElement { if (!_sharedStyleSheet) { - _sharedStyleSheet = createStyleSheet(null); + _sharedStyleSheet = createStyleSheet(); } return _sharedStyleSheet; } From fecfa6ecdb5a91e57e3c48f75f2211fb8f8e583b Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 14 Jan 2020 10:06:18 +0100 Subject: [PATCH 015/177] Fix css --- src/vs/editor/contrib/suggest/media/suggest.css | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index e001eb32bff..5efde04b9ae 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -167,11 +167,16 @@ display: none; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { +.monaco-editor .suggest-widget.always-reveal-inline-details .monaco-list .monaco-list-row > .contents > .main > .readMore, +.monaco-editor .suggest-widget.always-reveal-inline-details.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .readMore, +.monaco-editor .suggest-widget.always-reveal-inline-details.docs-below .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { display: inline; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row:not(.focused) > .contents > .main > .readMore { - display: inline; + +.monaco-editor .suggest-widget.always-reveal-inline-details .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { + visibility: visible; +} +.monaco-editor .suggest-widget.always-reveal-inline-details .monaco-list .monaco-list-row:not(.focused) > .contents > .main > .readMore { visibility: hidden; } From 79a01a0f27bd9f21bee8e278b56bf51bbc9dd962 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Tue, 14 Jan 2020 17:20:41 +0100 Subject: [PATCH 016/177] Revert isDetailsResolved and implement CompletionItemLabel --- .../client/src/cssMain.ts | 11 +++++--- src/vs/editor/common/modes.ts | 25 ++++++++++++++++-- .../editor/contrib/suggest/completionModel.ts | 7 ++--- src/vs/editor/contrib/suggest/suggest.ts | 17 +++++++----- .../contrib/suggest/suggestController.ts | 3 ++- .../editor/contrib/suggest/suggestWidget.ts | 26 +++++++++++++------ src/vs/editor/contrib/suggest/wordDistance.ts | 5 +++- src/vs/monaco.d.ts | 21 +++++++++++++-- src/vs/vscode.d.ts | 2 +- src/vs/vscode.proposed.d.ts | 22 ++++++++++++++-- .../api/browser/mainThreadLanguageFeatures.ts | 7 +++-- .../workbench/api/common/extHost.protocol.ts | 3 +-- .../api/common/extHostLanguageFeatures.ts | 9 ++++--- src/vs/workbench/api/common/extHostTypes.ts | 12 ++++++--- .../browser/snippetCompletionProvider.ts | 2 +- 15 files changed, 131 insertions(+), 41 deletions(-) diff --git a/extensions/css-language-features/client/src/cssMain.ts b/extensions/css-language-features/client/src/cssMain.ts index bc8bbdc9ff7..8822571d076 100644 --- a/extensions/css-language-features/client/src/cssMain.ts +++ b/extensions/css-language-features/client/src/cssMain.ts @@ -60,12 +60,17 @@ export function activate(context: ExtensionContext) { (Array.isArray(r) ? r : r.items).forEach(updateRanges); if (!Array.isArray(r)) { - r.isDetailsResolved = true; r.items.forEach(i => { if (i.kind === CompletionItemKind.Color) { - i.detail = i.documentation?.toString(); + i.label = { + label: i.label as string, + details: i.documentation?.toString() + }; } else { - i.detail = i.label; + i.label = { + label: i.label as string, + details: i.label as string + }; } }); } diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 78495217dc3..f22125a6acb 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -369,6 +369,28 @@ export let completionKindFromString: { }; })(); +export interface CompletionItemLabel { + + /** + * The label of this completion item. By default + * this is also the text that is inserted when selecting + * this completion. + */ + label: string; + + /** + * A description of the completion item which is rendered + * less prominent. + */ + // description?: string; + + /** + * Details of the completion item that is rendered less + * prominent to the right. + */ + details?: string; +} + export const enum CompletionItemTag { Deprecated = 1 } @@ -396,7 +418,7 @@ export interface CompletionItem { * this is also the text that is inserted when selecting * this completion. */ - label: string; + label: string | CompletionItemLabel; /** * The kind of this completion item. Based on the kind * an icon is chosen by the editor. @@ -481,7 +503,6 @@ export interface CompletionItem { export interface CompletionList { suggestions: CompletionItem[]; incomplete?: boolean; - isDetailsResolved?: boolean; dispose?(): void; } diff --git a/src/vs/editor/contrib/suggest/completionModel.ts b/src/vs/editor/contrib/suggest/completionModel.ts index c1349fa7935..5382be986e9 100644 --- a/src/vs/editor/contrib/suggest/completionModel.ts +++ b/src/vs/editor/contrib/suggest/completionModel.ts @@ -192,6 +192,7 @@ export class CompletionModel { } } + const label = typeof item.completion.label === 'string' ? item.completion.label : item.completion.label.label; if (wordPos >= wordLen) { // the wordPos at which scoring starts is the whole word // and therefore the same rules as not having a word apply @@ -206,19 +207,19 @@ export class CompletionModel { if (!match) { continue; // NO match } - if (compareIgnoreCase(item.completion.filterText, item.completion.label) === 0) { + if (compareIgnoreCase(item.completion.filterText, label) === 0) { // filterText and label are actually the same -> use good highlights item.score = match; } else { // re-run the scorer on the label in the hope of a result BUT use the rank // of the filterText-match - item.score = anyScore(word, wordLow, wordPos, item.completion.label, item.labelLow, 0); + item.score = anyScore(word, wordLow, wordPos, label, item.labelLow, 0); item.score[0] = match[0]; // use score from filterText } } else { // by default match `word` against the `label` - let match = scoreFn(word, wordLow, wordPos, item.completion.label, item.labelLow, 0, false); + let match = scoreFn(word, wordLow, wordPos, label, item.labelLow, 0, false); if (!match) { continue; // NO match } diff --git a/src/vs/editor/contrib/suggest/suggest.ts b/src/vs/editor/contrib/suggest/suggest.ts index f408f88ec12..61813788b10 100644 --- a/src/vs/editor/contrib/suggest/suggest.ts +++ b/src/vs/editor/contrib/suggest/suggest.ts @@ -36,6 +36,9 @@ export class CompletionItem { readonly editInsertEnd: IPosition; readonly editReplaceEnd: IPosition; + // + readonly textLabel: string; + // perf readonly labelLow: string; readonly sortTextLow?: string; @@ -47,9 +50,6 @@ export class CompletionItem { idx?: number; word?: string; - // all details resolved, we can show them all - readonly isDetailsResolved: boolean; - constructor( readonly position: IPosition, readonly completion: modes.CompletionItem, @@ -57,8 +57,13 @@ export class CompletionItem { readonly provider: modes.CompletionItemProvider, model: ITextModel ) { + this.textLabel = typeof completion.label === 'string' + ? completion.label + : completion.label.label; + // ensure lower-variants (perf) - this.labelLow = completion.label.toLowerCase(); + this.labelLow = this.textLabel.toLowerCase(); + this.sortTextLow = completion.sortText && completion.sortText.toLowerCase(); this.filterTextLow = completion.filterText && completion.filterText.toLowerCase(); @@ -73,8 +78,6 @@ export class CompletionItem { this.editReplaceEnd = new Position(completion.range.replace.endLineNumber, completion.range.replace.endColumn); } - this.isDetailsResolved = container.isDetailsResolved || typeof provider.resolveCompletionItem === 'undefined'; - // create the suggestion resolver const { resolveCompletionItem } = provider; if (typeof resolveCompletionItem !== 'function') { @@ -188,7 +191,7 @@ export function provideSuggestionItems( } // fill in default sortText when missing if (!suggestion.sortText) { - suggestion.sortText = suggestion.label; + suggestion.sortText = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.label; } allSuggestions.push(new CompletionItem(position, suggestion, container, provider, model)); diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index a4330d1d438..b0fa140844a 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -343,8 +343,9 @@ export class SuggestController implements IEditorContribution { } private _alertCompletionItem({ completion: suggestion }: CompletionItem): void { + const textLabel = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.label; if (isNonEmptyArray(suggestion.additionalTextEdits)) { - let msg = nls.localize('arai.alert.snippet', "Accepting '{0}' made {1} additional edits", suggestion.label, suggestion.additionalTextEdits.length); + let msg = nls.localize('arai.alert.snippet', "Accepting '{0}' made {1} additional edits", textLabel, suggestion.additionalTextEdits.length); alert(msg); } } diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 24bb13a3043..90f1a7ba65d 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -67,8 +67,12 @@ export const editorSuggestWidgetHighlightForeground = registerColor('editorSugge const colorRegExp = /^(#([\da-f]{3}){1,2}|(rgb|hsl)a\(\s*(\d{1,3}%?\s*,\s*){3}(1|0?\.\d+)\)|(rgb|hsl)\(\s*\d{1,3}%?(\s*,\s*\d{1,3}%?){2}\s*\))$/i; function extractColor(item: CompletionItem, out: string[]): boolean { - if (item.completion.label.match(colorRegExp)) { - out[0] = item.completion.label; + const label = typeof item.completion.label === 'string' + ? item.completion.label + : item.completion.label.label; + + if (label.match(colorRegExp)) { + out[0] = label; return true; } if (typeof item.completion.documentation === 'string' && item.completion.documentation.match(colorRegExp)) { @@ -163,6 +167,7 @@ class Renderer implements IListRenderer renderElement(element: CompletionItem, _index: number, templateData: ISuggestionTemplateData): void { const data = templateData; const suggestion = (element).completion; + const textLabel = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.label; data.icon.className = 'icon ' + completionKindToCssClass(suggestion.kind); data.colorspan.style.backgroundColor = ''; @@ -183,7 +188,7 @@ class Renderer implements IListRenderer // special logic for 'file' completion items data.icon.className = 'icon hide'; data.iconContainer.className = 'icon hide'; - const labelClasses = getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FILE); + const labelClasses = getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: textLabel }), FileKind.FILE); const detailClasses = getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FILE); labelOptions.extraClasses = labelClasses.length > detailClasses.length ? labelClasses : detailClasses; @@ -192,7 +197,7 @@ class Renderer implements IListRenderer data.icon.className = 'icon hide'; data.iconContainer.className = 'icon hide'; labelOptions.extraClasses = flatten([ - getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FOLDER), + getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: textLabel }), FileKind.FOLDER), getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FOLDER) ]); } else { @@ -207,8 +212,12 @@ class Renderer implements IListRenderer labelOptions.matches = []; } - data.iconLabel.setLabel(suggestion.label, undefined, labelOptions); - data.typeLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, ''); + data.iconLabel.setLabel(textLabel, undefined, labelOptions); + if (typeof suggestion.label === 'string') { + data.typeLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, ''); + } else { + data.typeLabel.textContent = (suggestion.label.details || '').replace(/\n.*$/m, ''); + } if (canExpandCompletionItem(element)) { show(data.readMore); @@ -621,10 +630,11 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate MainThreadLanguageFeatures._inflateSuggestDto(result.a, d)), incomplete: result.c, - isDetailsResolved: result.d, dispose: () => typeof result.x === 'number' && this._proxy.$releaseCompletionItems(handle, result.x) }; }); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 227a885f876..5b65014b083 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -989,7 +989,7 @@ export const enum ISuggestDataDtoField { } export interface ISuggestDataDto { - [ISuggestDataDtoField.label]: string; + [ISuggestDataDtoField.label]: string | modes.CompletionItemLabel; [ISuggestDataDtoField.kind]: modes.CompletionItemKind; [ISuggestDataDtoField.detail]?: string; [ISuggestDataDtoField.documentation]?: string | IMarkdownString; @@ -1012,7 +1012,6 @@ export interface ISuggestResultDto { a: { insert: IRange, replace: IRange; }; b: ISuggestDataDto[]; c?: boolean; - d?: boolean; } export interface ISignatureHelpDto { diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 737ed4be714..19fa91f1de3 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -787,8 +787,7 @@ class SuggestAdapter { x: pid, b: [], a: { replace: typeConvert.Range.from(replaceRange), insert: typeConvert.Range.from(insertRange) }, - c: list.isIncomplete || undefined, - d: list.isDetailsResolved || undefined + c: list.isIncomplete || undefined }; for (let i = 0; i < list.items.length; i++) { @@ -858,7 +857,11 @@ class SuggestAdapter { } private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: extHostProtocol.ChainedCacheId): extHostProtocol.ISuggestDataDto | undefined { - if (typeof item.label !== 'string' || item.label.length === 0) { + const label = typeof item.label === 'string' + ? item.label + : item.label.label; + + if (typeof label !== 'string' || label.length === 0) { this._logService.warn('INVALID text edit -> must have at least a label'); return undefined; } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 5239da9499b..19863726fac 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1351,10 +1351,17 @@ export enum CompletionItemTag { Deprecated = 1, } +export interface CompletionItemLabel { + label: string; + // description?: string; + details?: string; +} + + @es5ClassCompat export class CompletionItem implements vscode.CompletionItem { - label: string; + label: string | CompletionItemLabel; kind?: CompletionItemKind; tags?: CompletionItemTag[]; detail?: string; @@ -1371,7 +1378,7 @@ export class CompletionItem implements vscode.CompletionItem { additionalTextEdits?: TextEdit[]; command?: vscode.Command; - constructor(label: string, kind?: CompletionItemKind) { + constructor(label: string | CompletionItemLabel, kind?: CompletionItemKind) { this.label = label; this.kind = kind; } @@ -1395,7 +1402,6 @@ export class CompletionItem implements vscode.CompletionItem { export class CompletionList { isIncomplete?: boolean; - isDetailsResolved?: boolean; items: vscode.CompletionItem[]; constructor(items: vscode.CompletionItem[] = [], isIncomplete: boolean = false) { diff --git a/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts b/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts index e30853b4c2c..96d9f026104 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetCompletionProvider.ts @@ -146,7 +146,7 @@ export class SnippetCompletionProvider implements CompletionItemProvider { i = to; } } - return { suggestions, isDetailsResolved: true }; + return { suggestions }; }); } From 31ec4fe4346dddf99f53f3aecfd529081febdbae Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 15 Jan 2020 10:37:33 +0100 Subject: [PATCH 017/177] CompletionItemLabel#label -> name --- src/vs/editor/common/modes.ts | 6 ++---- src/vs/editor/contrib/suggest/completionModel.ts | 2 +- src/vs/editor/contrib/suggest/suggest.ts | 4 ++-- src/vs/editor/contrib/suggest/suggestController.ts | 2 +- src/vs/editor/contrib/suggest/suggestWidget.ts | 6 +++--- src/vs/editor/contrib/suggest/wordDistance.ts | 2 +- src/vs/monaco.d.ts | 6 ++---- src/vs/vscode.proposed.d.ts | 6 ++---- src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts | 2 +- src/vs/workbench/api/common/extHostLanguageFeatures.ts | 2 +- src/vs/workbench/api/common/extHostTypes.ts | 2 +- 11 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index f22125a6acb..3722d37916a 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -372,11 +372,9 @@ export let completionKindFromString: { export interface CompletionItemLabel { /** - * The label of this completion item. By default - * this is also the text that is inserted when selecting - * this completion. + * The name of this completion item's label. */ - label: string; + name: string; /** * A description of the completion item which is rendered diff --git a/src/vs/editor/contrib/suggest/completionModel.ts b/src/vs/editor/contrib/suggest/completionModel.ts index 5382be986e9..5013d8c1734 100644 --- a/src/vs/editor/contrib/suggest/completionModel.ts +++ b/src/vs/editor/contrib/suggest/completionModel.ts @@ -192,7 +192,7 @@ export class CompletionModel { } } - const label = typeof item.completion.label === 'string' ? item.completion.label : item.completion.label.label; + const label = typeof item.completion.label === 'string' ? item.completion.label : item.completion.label.name; if (wordPos >= wordLen) { // the wordPos at which scoring starts is the whole word // and therefore the same rules as not having a word apply diff --git a/src/vs/editor/contrib/suggest/suggest.ts b/src/vs/editor/contrib/suggest/suggest.ts index 61813788b10..c1f13090b28 100644 --- a/src/vs/editor/contrib/suggest/suggest.ts +++ b/src/vs/editor/contrib/suggest/suggest.ts @@ -59,7 +59,7 @@ export class CompletionItem { ) { this.textLabel = typeof completion.label === 'string' ? completion.label - : completion.label.label; + : completion.label.name; // ensure lower-variants (perf) this.labelLow = this.textLabel.toLowerCase(); @@ -191,7 +191,7 @@ export function provideSuggestionItems( } // fill in default sortText when missing if (!suggestion.sortText) { - suggestion.sortText = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.label; + suggestion.sortText = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name; } allSuggestions.push(new CompletionItem(position, suggestion, container, provider, model)); diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index b0fa140844a..8964cf24ecb 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -343,7 +343,7 @@ export class SuggestController implements IEditorContribution { } private _alertCompletionItem({ completion: suggestion }: CompletionItem): void { - const textLabel = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.label; + const textLabel = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name; if (isNonEmptyArray(suggestion.additionalTextEdits)) { let msg = nls.localize('arai.alert.snippet', "Accepting '{0}' made {1} additional edits", textLabel, suggestion.additionalTextEdits.length); alert(msg); diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 90f1a7ba65d..aca32568984 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -69,7 +69,7 @@ const colorRegExp = /^(#([\da-f]{3}){1,2}|(rgb|hsl)a\(\s*(\d{1,3}%?\s*,\s*){3}(1 function extractColor(item: CompletionItem, out: string[]): boolean { const label = typeof item.completion.label === 'string' ? item.completion.label - : item.completion.label.label; + : item.completion.label.name; if (label.match(colorRegExp)) { out[0] = label; @@ -167,7 +167,7 @@ class Renderer implements IListRenderer renderElement(element: CompletionItem, _index: number, templateData: ISuggestionTemplateData): void { const data = templateData; const suggestion = (element).completion; - const textLabel = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.label; + const textLabel = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.name; data.icon.className = 'icon ' + completionKindToCssClass(suggestion.kind); data.colorspan.style.backgroundColor = ''; @@ -630,7 +630,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate must have at least a label'); diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 19863726fac..97d0d97feb2 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1352,7 +1352,7 @@ export enum CompletionItemTag { } export interface CompletionItemLabel { - label: string; + name: string; // description?: string; details?: string; } From b2950b03a8ea046553dd3e85071acddc24da3a8b Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 15 Jan 2020 10:48:51 +0100 Subject: [PATCH 018/177] Adopt css --- extensions/css-language-features/client/src/cssMain.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/css-language-features/client/src/cssMain.ts b/extensions/css-language-features/client/src/cssMain.ts index 8822571d076..81a5f7df086 100644 --- a/extensions/css-language-features/client/src/cssMain.ts +++ b/extensions/css-language-features/client/src/cssMain.ts @@ -63,12 +63,12 @@ export function activate(context: ExtensionContext) { r.items.forEach(i => { if (i.kind === CompletionItemKind.Color) { i.label = { - label: i.label as string, + name: i.label as string, details: i.documentation?.toString() }; } else { i.label = { - label: i.label as string, + name: i.label as string, details: i.label as string }; } From 7f8018fbf217914a6776af60e025eb22db1072e6 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 15 Jan 2020 11:05:59 +0100 Subject: [PATCH 019/177] Try adoptions --- .../css-language-features/server/src/pathCompletion.ts | 6 ++++++ extensions/html-language-features/client/src/htmlMain.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/extensions/css-language-features/server/src/pathCompletion.ts b/extensions/css-language-features/server/src/pathCompletion.ts index 6862f28e034..d480da4f350 100644 --- a/extensions/css-language-features/server/src/pathCompletion.ts +++ b/extensions/css-language-features/server/src/pathCompletion.ts @@ -54,6 +54,12 @@ export function getPathCompletionParticipant( }); } + if (suggestions[0]) { + suggestions[0].documentation = 'test: ' + suggestions[0].label; + } + if (suggestions[2]) { + suggestions[2].documentation = 'test: ' + suggestions[2].label; + } result.items = [...suggestions, ...result.items]; } }; diff --git a/extensions/html-language-features/client/src/htmlMain.ts b/extensions/html-language-features/client/src/htmlMain.ts index 2df5e7f5c13..923477f51be 100644 --- a/extensions/html-language-features/client/src/htmlMain.ts +++ b/extensions/html-language-features/client/src/htmlMain.ts @@ -104,6 +104,12 @@ export function activate(context: ExtensionContext) { function updateProposals(r: CompletionItem[] | CompletionList | null | undefined): CompletionItem[] | CompletionList | null | undefined { if (r) { (Array.isArray(r) ? r : r.items).forEach(updateRanges); + + if (!Array.isArray(r)) { + r.items.forEach(i => { + i.detail = typeof i.label === 'string' ? i.label : i.label.name; + }); + } } return r; } From ad7fd5c516837f66577b426c2c97127921f41f3d Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 15 Jan 2020 11:08:48 +0100 Subject: [PATCH 020/177] Drop alwaysRevealInlineDetails --- src/vs/editor/common/config/editorOptions.ts | 11 ----------- src/vs/editor/contrib/suggest/suggestWidget.ts | 3 --- .../contrib/suggest/test/completionModel.test.ts | 1 - src/vs/monaco.d.ts | 4 ---- 4 files changed, 19 deletions(-) diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index feb53271431..104c3a91d58 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -2495,10 +2495,6 @@ export interface ISuggestOptions { * Max suggestions to show in suggestions. Defaults to 12. */ maxVisibleSuggestions?: number; - /** - * Always show inline details - */ - alwaysRevealInlineDetails?: boolean; /** * Show method-suggestions. */ @@ -2618,7 +2614,6 @@ class EditorSuggest extends BaseEditorOption toggleClass(this.element, 'no-icons', !this.editor.getOption(EditorOption.suggest).showIcons); - const applyAlwaysRevealInlineDetailsStyle = () => toggleClass(this.element, 'always-reveal-inline-details', this.editor.getOption(EditorOption.suggest).alwaysRevealInlineDetails); applyIconStyle(); - applyAlwaysRevealInlineDetailsStyle(); let renderer = instantiationService.createInstance(Renderer, this, this.editor, triggerKeybindingLabel); @@ -552,7 +550,6 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { if (e.hasChanged(EditorOption.suggest)) { applyIconStyle(); - applyAlwaysRevealInlineDetailsStyle(); } })); diff --git a/src/vs/editor/contrib/suggest/test/completionModel.test.ts b/src/vs/editor/contrib/suggest/test/completionModel.test.ts index c3bd3d76100..6a26c5fd584 100644 --- a/src/vs/editor/contrib/suggest/test/completionModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/completionModel.test.ts @@ -41,7 +41,6 @@ suite('CompletionModel', function () { shareSuggestSelections: false, showIcons: true, maxVisibleSuggestions: 12, - alwaysRevealInlineDetails: false, showMethods: true, showFunctions: true, showConstructors: true, diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index c463fa8414e..226176b9410 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3381,10 +3381,6 @@ declare namespace monaco.editor { * Max suggestions to show in suggestions. Defaults to 12. */ maxVisibleSuggestions?: number; - /** - * Always show inline details - */ - alwaysRevealInlineDetails?: boolean; /** * Show method-suggestions. */ From e6233feb84b184dbc05dad0fbc6dc97f2ac37d87 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 15 Jan 2020 11:17:09 +0100 Subject: [PATCH 021/177] typeLabel -> detailsLabel, restore old visibility model --- .../editor/contrib/suggest/media/suggest.css | 40 +++---------------- .../editor/contrib/suggest/suggestWidget.ts | 11 +++-- 2 files changed, 13 insertions(+), 38 deletions(-) diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 5efde04b9ae..5e7b46ffba1 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -129,7 +129,7 @@ /** Type Info and icon next to the label in the focused completion item **/ -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .type-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .details-label { margin-left: 0.8em; flex: 1; text-align: right; @@ -139,48 +139,20 @@ white-space: nowrap; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .type-label > .monaco-tokenized-source { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .details-label > .monaco-tokenized-source { display: inline; } -/** Inline type Label (details) **/ - -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .type-label, -.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .type-label { - display: none; -} - -.monaco-editor .suggest-widget.always-reveal-inline-details .monaco-list .monaco-list-row > .contents > .main > .type-label, -.monaco-editor .suggest-widget.always-reveal-inline-details.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .type-label { - display: inline; -} - -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .type-label { - display: inline; -} - -/** readMore icon **/ - .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore, +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .details-label, .monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .readMore, +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .details-label, .monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { display: none; } -.monaco-editor .suggest-widget.always-reveal-inline-details .monaco-list .monaco-list-row > .contents > .main > .readMore, -.monaco-editor .suggest-widget.always-reveal-inline-details.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .readMore, -.monaco-editor .suggest-widget.always-reveal-inline-details.docs-below .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { - display: inline; -} - -.monaco-editor .suggest-widget.always-reveal-inline-details .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { - visibility: visible; -} -.monaco-editor .suggest-widget.always-reveal-inline-details .monaco-list .monaco-list-row:not(.focused) > .contents > .main > .readMore { - visibility: hidden; -} - -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .readMore, +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .details-label { display: inline; } diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 3ef5f9af35d..b0b1b7ee20b 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -51,7 +51,10 @@ interface ISuggestionTemplateData { colorspan: HTMLElement; iconLabel: IconLabel; iconContainer: HTMLElement; - typeLabel: HTMLElement; + /** + * Showing either `CompletionItem#details` or `CompletionItemLabel#name` + */ + detailsLabel: HTMLElement; readMore: HTMLElement; disposables: DisposableStore; } @@ -128,7 +131,7 @@ class Renderer implements IListRenderer data.iconLabel = new IconLabel(main, { supportHighlights: true, supportCodicons: true }); data.disposables.add(data.iconLabel); - data.typeLabel = append(main, $('span.type-label')); + data.detailsLabel = append(main, $('span.details-label')); data.readMore = append(main, $('span.readMore.codicon.codicon-info')); data.readMore.title = nls.localize('readMore', "Read More...{0}", this.triggerKeybindingLabel); @@ -214,9 +217,9 @@ class Renderer implements IListRenderer data.iconLabel.setLabel(textLabel, undefined, labelOptions); if (typeof suggestion.label === 'string') { - data.typeLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, ''); + data.detailsLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, ''); } else { - data.typeLabel.textContent = (suggestion.label.details || '').replace(/\n.*$/m, ''); + data.detailsLabel.textContent = (suggestion.label.details || '').replace(/\n.*$/m, ''); } if (canExpandCompletionItem(element)) { From e193cb5bfe0123787ab8399e31a05d1903d14865 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Wed, 15 Jan 2020 11:34:56 +0100 Subject: [PATCH 022/177] Implement visibility change --- .../editor/contrib/suggest/media/suggest.css | 26 +++++++++++++++---- .../editor/contrib/suggest/suggestWidget.ts | 2 ++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 5e7b46ffba1..63d54498c2b 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -143,19 +143,35 @@ display: inline; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore, +/** Details: if using CompletionItem#details, show on focus **/ + .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .details-label, -.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .readMore, -.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .details-label, -.monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .details-label { display: none; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .readMore, .monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .details-label { display: inline; } +/** Details: if using CompletionItemLabel#details, always show **/ + +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .details-label.always-show, +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .details-label.always-show { + display: inline; +} + +/** ReadMore: always layout, only shown on focus **/ + +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore { + display: inline; + visibility: hidden; +} + +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { + visibility: visible; +} + /** Styles for each row in the list **/ .monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.deprecated { diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index b0b1b7ee20b..2dfa7201a3e 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -218,8 +218,10 @@ class Renderer implements IListRenderer data.iconLabel.setLabel(textLabel, undefined, labelOptions); if (typeof suggestion.label === 'string') { data.detailsLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, ''); + removeClass(data.detailsLabel, 'always-show'); } else { data.detailsLabel.textContent = (suggestion.label.details || '').replace(/\n.*$/m, ''); + addClass(data.detailsLabel, 'always-show'); } if (canExpandCompletionItem(element)) { From 2872a0022dc5ec933045f2d32807fa071532aea6 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Thu, 16 Jan 2020 12:23:07 +0100 Subject: [PATCH 023/177] Hover to show readMore --- .../editor/contrib/suggest/media/suggest.css | 28 ++++++++++++++++--- .../editor/contrib/suggest/suggestWidget.ts | 4 +++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 63d54498c2b..79c19965dc1 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -110,9 +110,10 @@ .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close, .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore::before { color: inherit; - opacity: 0.6; + opacity: 1; font-size: 14px; - margin-left: 4px; + margin-left: 2px; + margin-right: 2px; cursor: pointer; } @@ -161,14 +162,33 @@ display: inline; } -/** ReadMore: always layout, only shown on focus **/ +.monaco-editor .suggest-widget .monaco-list .monaco-list-row:hover > .contents > .main > .details-label { + opacity: 0.3; +} +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row:hover > .contents > .main > .details-label, +.monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row:hover > .contents > .main > .details-label, +.monaco-editor .suggest-widget .monaco-list .monaco-list-row:hover > .contents > .main > .details-label:not(.can-expand) { + opacity: 0.7; +} + +/** ReadMore: always layout, only shown on hover **/ +/** But if docs is side or bottom, hide still **/ .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore { display: inline; visibility: hidden; + position: absolute; + top: 0px; + right: 0px; + padding-right: 10px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .readMore { +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row > .contents > .main > .readMore, +.monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row > .contents > .main > .readMore { + display: none; +} + +.monaco-editor .suggest-widget .monaco-list .monaco-list-row:hover > .contents > .main > .readMore { visibility: visible; } diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 2dfa7201a3e..67197ed73c2 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -136,6 +136,8 @@ class Renderer implements IListRenderer data.readMore = append(main, $('span.readMore.codicon.codicon-info')); data.readMore.title = nls.localize('readMore', "Read More...{0}", this.triggerKeybindingLabel); + data.readMore.style.backgroundColor = this._themeService.getTheme().getColor('list.hoverBackground', true)!.toString(); + const configureFont = () => { const options = this.editor.getOptions(); const fontInfo = options.get(EditorOption.fontInfo); @@ -225,6 +227,7 @@ class Renderer implements IListRenderer } if (canExpandCompletionItem(element)) { + addClass(data.detailsLabel, 'can-expand'); show(data.readMore); data.readMore.onmousedown = e => { e.stopPropagation(); @@ -236,6 +239,7 @@ class Renderer implements IListRenderer this.widget.toggleDetails(); }; } else { + removeClass(data.detailsLabel, 'can-expand'); hide(data.readMore); data.readMore.onmousedown = null; data.readMore.onclick = null; From 51c0c5d155e62e7d5922b3d560059ec650a9f664 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 16 Jan 2020 16:35:58 +0100 Subject: [PATCH 024/177] use new editor wrapping --- .../contrib/scm/browser/repositoryPane.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts index 8dbac82847f..7e67f14a9c2 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts @@ -701,8 +701,14 @@ export class RepositoryPane extends ViewPane { ...getSimpleEditorOptions(), lineDecorationsWidth: 4, dragAndDrop: false, - // fontFamily: 'Arial' + cursorWidth: 1, + fontSize: 13, + lineHeight: 20, + fontFamily: ' -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif', + wrappingAlgorithm: 'dom', + wrappingIndent: 'none' }; + const codeEditorWidgetOptions: ICodeEditorWidgetOptions = { isSimpleWidget: true, contributions: EditorExtensionsRegistry.getSomeEditorContributions([ @@ -744,7 +750,8 @@ export class RepositoryPane extends ViewPane { this._register(this.repository.input.onDidChangePlaceholder(updatePlaceholder, null)); this._register(this.keybindingService.onDidUpdateKeybindings(updatePlaceholder, null)); - // this._register(this.inputBox.onDidHeightChange(() => this.layoutBody())); + const onDidChangeContentHeight = Event.filter(this.inputEditor.onDidScrollChange, e => e.scrollHeightChanged); + this._register(onDidChangeContentHeight(() => this.layoutBody())); if (this.repository.provider.onDidChangeCommitTemplate) { this._register(this.repository.provider.onDidChangeCommitTemplate(this.onDidChangeCommitTemplate, this)); @@ -865,11 +872,12 @@ export class RepositoryPane extends ViewPane { } this.cachedHeight = height; + this.cachedWidth = width; if (this.repository.input.visible) { removeClass(this.inputContainer, 'hidden'); - // const editorHeight = 25; // TODO@joao - const editorHeight = 250; // TODO@joao + const editorHeight = this.inputEditor.getScrollHeight(); + this.inputEditor.layout({ height: editorHeight, width: width! - 12 - 16 - 2 /* - 8 */ }); // TODO@joao const listHeight = height - (editorHeight + 5 + 2 /* + 3 + 3 */ + 5); From 20ccfb070c899b0f49b616e4cf6899d98e1b7574 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 16 Jan 2020 16:41:03 +0100 Subject: [PATCH 025/177] scm: make commit template work again --- .../contrib/scm/browser/repositoryPane.ts | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts index 7e67f14a9c2..eafe52641af 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts @@ -606,7 +606,7 @@ export class RepositoryPane extends ViewPane { private menus: SCMMenus; private toggleViewModelModeAction: ToggleViewModeAction | undefined; protected contextKeyService: IContextKeyService; - // private commitTemplate = ''; + private commitTemplate = ''; constructor( readonly repository: ISCMRepository, @@ -984,20 +984,21 @@ export class RepositoryPane extends ViewPane { .filter(r => !!r && !isSCMResourceGroup(r))! as any; } - // TODO@joao private onDidChangeCommitTemplate(): void { - // if (typeof this.repository.provider.commitTemplate === 'undefined' || !this.repository.input.visible) { - // return; - // } + if (typeof this.repository.provider.commitTemplate === 'undefined' || !this.repository.input.visible) { + return; + } - // const oldCommitTemplate = this.commitTemplate; - // this.commitTemplate = this.repository.provider.commitTemplate; + const oldCommitTemplate = this.commitTemplate; + this.commitTemplate = this.repository.provider.commitTemplate; - // if (this.inputBox.value && this.inputBox.value !== oldCommitTemplate) { - // return; - // } + const value = this.inputModel.getValue(); - // this.inputBox.value = this.commitTemplate; + if (value && value !== oldCommitTemplate) { + return; + } + + this.inputModel.setValue(this.commitTemplate); } private updateInputBoxVisibility(): void { From 140c711603eda74a4af92b0939e331ed94fb2051 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jan 2020 10:06:14 +0100 Subject: [PATCH 026/177] repo pane: input placeholder --- .../contrib/scm/browser/media/scmViewlet.css | 12 +++++++++ .../contrib/scm/browser/repositoryPane.ts | 26 ++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css b/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css index a2aba241e63..aebd84f7452 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css +++ b/src/vs/workbench/contrib/scm/browser/media/scmViewlet.css @@ -177,6 +177,18 @@ padding: 1px; } +.scm-viewlet .scm-editor-placeholder { + position: absolute; + pointer-events: none; + z-index: 1; + margin: 1px; + padding: 3px 4px; +} + +.scm-viewlet .scm-editor-placeholder.hidden { + display: none; +} + .scm-viewlet .scm-editor.scroll > .monaco-inputbox > .wrapper > textarea.input { overflow-y: scroll; } diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts index eafe52641af..ba965cf6250 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts @@ -24,7 +24,7 @@ import { IAction, IActionViewItem, ActionRunner, Action } from 'vs/base/common/a import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { SCMMenus } from './menus'; import { ActionBar, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IThemeService, LIGHT } from 'vs/platform/theme/common/themeService'; +import { IThemeService, LIGHT, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { isSCMResource, isSCMResourceGroup, connectPrimaryMenuToInlineActionBar } from './util'; import { attachBadgeStyler } from 'vs/platform/theme/common/styler'; import { WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listService'; @@ -60,6 +60,9 @@ import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreve import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; import { ContextMenuController } from 'vs/editor/contrib/contextmenu/contextmenu'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import * as platform from 'vs/base/common/platform'; +import { format } from 'vs/base/common/strings'; +import { inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; type TreeElement = ISCMResourceGroup | IResourceNode | ISCMResource; @@ -666,13 +669,13 @@ export class RepositoryPane extends ViewPane { this.inputContainer = append(container, $('.scm-editor')); const editorContainer = append(this.inputContainer, $('.scm-editor-container')); - // TODO@joao + const placeholderTextContainer = append(editorContainer, $('.scm-editor-placeholder')); const updatePlaceholder = () => { - // const binding = this.keybindingService.lookupKeybinding('scm.acceptInput'); - // const label = binding ? binding.getLabel() : (platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter'); - // const placeholder = format(this.repository.input.placeholder, label); + const binding = this.keybindingService.lookupKeybinding('scm.acceptInput'); + const label = binding ? binding.getLabel() : (platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter'); + const placeholderText = format(this.repository.input.placeholder, label); - // this.inputBox.setPlaceHolder(placeholder); + placeholderTextContainer.textContent = placeholderText; }; // const validationDelayer = new ThrottledDelayer(200); @@ -746,6 +749,10 @@ export class RepositoryPane extends ViewPane { // this._register(this.inputBox.onDidChange(value => this.repository.input.value = value, null)); // this._register(this.repository.input.onDidChange(value => this.inputBox.value = value, null)); + this.inputModel.onDidChangeContent(() => { + toggleClass(placeholderTextContainer, 'hidden', this.inputModel.getValueLength() > 0); + }); + updatePlaceholder(); this._register(this.repository.input.onDidChangePlaceholder(updatePlaceholder, null)); this._register(this.keybindingService.onDidUpdateKeybindings(updatePlaceholder, null)); @@ -1030,3 +1037,10 @@ export class RepositoryViewDescriptor implements IViewDescriptor { this.ctorDescriptor = new SyncDescriptor(RepositoryPane, [repository]); } } + +registerThemingParticipant((theme, collector) => { + let inputPlaceholderForegroundColor = theme.getColor(inputPlaceholderForeground); + if (inputPlaceholderForegroundColor) { + collector.addRule(`.scm-viewlet .scm-editor-placeholder { color: ${inputPlaceholderForegroundColor}; }`); + } +}); From 48ebd1cff3904825952354b96df245ef48197d6d Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jan 2020 10:26:30 +0100 Subject: [PATCH 027/177] repo pane: enable suggest --- src/vs/workbench/contrib/scm/browser/repositoryPane.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts index ba965cf6250..3b21c5e447a 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts @@ -63,6 +63,8 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import * as platform from 'vs/base/common/platform'; import { format } from 'vs/base/common/strings'; import { inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; +import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; +import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; type TreeElement = ISCMResourceGroup | IResourceNode | ISCMResource; @@ -715,6 +717,8 @@ export class RepositoryPane extends ViewPane { const codeEditorWidgetOptions: ICodeEditorWidgetOptions = { isSimpleWidget: true, contributions: EditorExtensionsRegistry.getSomeEditorContributions([ + SuggestController.ID, + SnippetController2.ID, MenuPreventer.ID, SelectionClipboardContributionID, ContextMenuController.ID @@ -731,8 +735,7 @@ export class RepositoryPane extends ViewPane { this._register(this.inputEditor.onDidFocusEditorText(() => addClass(editorContainer, 'synthetic-focus'))); this._register(this.inputEditor.onDidBlurEditorText(() => removeClass(editorContainer, 'synthetic-focus'))); - let resource = URI.parse('scm://input'); - this.inputModel = this.modelService.createModel('', null, resource, true); + this.inputModel = this.modelService.createModel('', null, URI.parse('scm:///input')); this.inputEditor.setModel(this.inputModel); this.inputEditor.changeViewZones(accessor => { From a15b64050acf85ab7e02883577c0e8d59388fe48 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jan 2020 11:55:45 +0100 Subject: [PATCH 028/177] repo pane: use proper uri for input model --- .../contrib/scm/browser/repositoryPane.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts index 3b21c5e447a..5de50a95422 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts @@ -65,6 +65,7 @@ import { format } from 'vs/base/common/strings'; import { inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; +import { Schemas } from 'vs/base/common/network'; type TreeElement = ISCMResourceGroup | IResourceNode | ISCMResource; @@ -735,7 +736,19 @@ export class RepositoryPane extends ViewPane { this._register(this.inputEditor.onDidFocusEditorText(() => addClass(editorContainer, 'synthetic-focus'))); this._register(this.inputEditor.onDidBlurEditorText(() => removeClass(editorContainer, 'synthetic-focus'))); - this.inputModel = this.modelService.createModel('', null, URI.parse('scm:///input')); + let query: string | undefined; + + if (this.repository.provider.rootUri) { + query = `rootUri=${encodeURIComponent(this.repository.provider.rootUri.toString())}`; + } + + const uri = URI.from({ + scheme: Schemas.vscode, + path: `scm/${this.repository.provider.contextValue}/${this.repository.provider.id}/input`, + query + }); + + this.inputModel = this.modelService.createModel('', null, uri); this.inputEditor.setModel(this.inputModel); this.inputEditor.changeViewZones(accessor => { From f5496b0d8fb8a4b722e748b6a9d97a7932488028 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jan 2020 12:06:31 +0100 Subject: [PATCH 029/177] repo pane: adopt getContentHeight() --- src/vs/workbench/contrib/scm/browser/repositoryPane.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts index 5de50a95422..2d02b3f6249 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts @@ -773,7 +773,7 @@ export class RepositoryPane extends ViewPane { this._register(this.repository.input.onDidChangePlaceholder(updatePlaceholder, null)); this._register(this.keybindingService.onDidUpdateKeybindings(updatePlaceholder, null)); - const onDidChangeContentHeight = Event.filter(this.inputEditor.onDidScrollChange, e => e.scrollHeightChanged); + const onDidChangeContentHeight = Event.filter(this.inputEditor.onDidContentSizeChange, e => e.contentHeightChanged); this._register(onDidChangeContentHeight(() => this.layoutBody())); if (this.repository.provider.onDidChangeCommitTemplate) { @@ -899,7 +899,8 @@ export class RepositoryPane extends ViewPane { if (this.repository.input.visible) { removeClass(this.inputContainer, 'hidden'); - const editorHeight = this.inputEditor.getScrollHeight(); + const editorContentHeight = this.inputEditor.getContentHeight(); + const editorHeight = Math.min(editorContentHeight + 3, 134); this.inputEditor.layout({ height: editorHeight, width: width! - 12 - 16 - 2 /* - 8 */ }); // TODO@joao From be9c3b8ece1c12c2cfcb90df920360686691a28c Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jan 2020 12:30:16 +0100 Subject: [PATCH 030/177] repo pane: validation --- .../contrib/scm/browser/repositoryPane.ts | 71 +++++++++++-------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts index 2d02b3f6249..c8390041438 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPane.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPane.ts @@ -10,7 +10,7 @@ import { IDisposable, Disposable, DisposableStore, combinedDisposable } from 'vs import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer'; import { append, $, addClass, toggleClass, trackFocus, removeClass } from 'vs/base/browser/dom'; import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list'; -import { ISCMRepository, ISCMResourceGroup, ISCMResource } from 'vs/workbench/contrib/scm/common/scm'; +import { ISCMRepository, ISCMResourceGroup, ISCMResource, InputValidationType } from 'vs/workbench/contrib/scm/common/scm'; import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -29,7 +29,7 @@ import { isSCMResource, isSCMResourceGroup, connectPrimaryMenuToInlineActionBar import { attachBadgeStyler } from 'vs/platform/theme/common/styler'; import { WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { disposableTimeout } from 'vs/base/common/async'; +import { disposableTimeout, ThrottledDelayer } from 'vs/base/common/async'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ITreeNode, ITreeFilter, ITreeSorter, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; import { ResourceTree, IResourceNode } from 'vs/base/common/resourceTree'; @@ -66,6 +66,9 @@ import { inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegist import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; import { Schemas } from 'vs/base/common/network'; +import { IMarkerService, MarkerSeverity } from 'vs/platform/markers/common/markers'; +import { ModesHoverController } from 'vs/editor/contrib/hover/hover'; +import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector'; type TreeElement = ISCMResourceGroup | IResourceNode | ISCMResource; @@ -590,13 +593,13 @@ export class ToggleViewModeAction extends Action { } } -// function convertValidationType(type: InputValidationType): MessageType { -// switch (type) { -// case InputValidationType.Information: return MessageType.INFO; -// case InputValidationType.Warning: return MessageType.WARNING; -// case InputValidationType.Error: return MessageType.ERROR; -// } -// } +function convertValidationType(type: InputValidationType): MarkerSeverity { + switch (type) { + case InputValidationType.Information: return MarkerSeverity.Info; + case InputValidationType.Warning: return MarkerSeverity.Warning; + case InputValidationType.Error: return MarkerSeverity.Error; + } +} export class RepositoryPane extends ViewPane { @@ -629,7 +632,8 @@ export class RepositoryPane extends ViewPane { @IContextKeyService contextKeyService: IContextKeyService, @IMenuService protected menuService: IMenuService, @IStorageService private storageService: IStorageService, - @IModelService private modelService: IModelService + @IModelService private modelService: IModelService, + @IMarkerService private markerService: IMarkerService ) { super(options, keybindingService, contextMenuService, configurationService, contextKeyService, instantiationService); @@ -681,27 +685,31 @@ export class RepositoryPane extends ViewPane { placeholderTextContainer.textContent = placeholderText; }; - // const validationDelayer = new ThrottledDelayer(200); - // const validate = () => { + const validationDelayer = new ThrottledDelayer(200); + const validate = () => { + const position = this.inputEditor.getSelection()?.getStartPosition(); + const offset = position && this.inputModel.getOffsetAt(position); + const value = this.inputModel.getValue(); - // const position = this.inputEditor.getSelection()?.getStartPosition(); - // const offset = position && this.inputModel.getOffsetAt(position); - // const value = this.inputModel.getValue(); + return this.repository.input.validateInput(value, offset || 0).then(result => { + if (!result) { + this.markerService.changeOne('scm', uri, []); + } else { + const range = this.inputModel.getFullModelRange(); - // return this.repository.input.validateInput(value, offset || 0).then(result => { + this.markerService.changeOne('scm', uri, [{ + message: result.message, + severity: convertValidationType(result.type), + startLineNumber: range.startLineNumber, + startColumn: range.startColumn, + endLineNumber: range.endLineNumber, + endColumn: range.endColumn + }]); + } + }); + }; - // // TODO@joao - // if (!result) { - // // this.inputBox.inputElement.removeAttribute('aria-invalid'); - // // this.inputBox.hideMessage(); - // } else { - // // this.inputBox.inputElement.setAttribute('aria-invalid', 'true'); - // // this.inputBox.showMessage({ content: result.message, type: convertValidationType(result.type) }); - // } - // }); - // }; - - // const triggerValidation = () => validationDelayer.trigger(validate); + const triggerValidation = () => validationDelayer.trigger(validate); const editorOptions: IEditorConstructionOptions = { ...getSimpleEditorOptions(), @@ -722,7 +730,9 @@ export class RepositoryPane extends ViewPane { SnippetController2.ID, MenuPreventer.ID, SelectionClipboardContributionID, - ContextMenuController.ID + ContextMenuController.ID, + ColorDetector.ID, + ModesHoverController.ID ]) }; @@ -755,7 +765,8 @@ export class RepositoryPane extends ViewPane { accessor.addZone({ afterLineNumber: 0, domNode: $('div'), heightInPx: 3 }); }); - // this._register(this.inputBox.onDidChange(triggerValidation, null)); + this._register(this.inputModel.onDidChangeContent(triggerValidation)); + this._register(this.inputEditor.onDidChangeCursorPosition(triggerValidation)); // const onKeyUp = domEvent(this.inputBox.inputElement, 'keyup'); // const onMouseUp = domEvent(this.inputBox.inputElement, 'mouseup'); From 93dbc5b1a8fdec7579719744bff23abe1189c090 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 17 Jan 2020 12:30:39 +0100 Subject: [PATCH 031/177] wip: git suggestions --- extensions/git/src/main.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts index 80435de391a..d9e1c959c69 100644 --- a/extensions/git/src/main.ts +++ b/extensions/git/src/main.ts @@ -6,7 +6,7 @@ import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { ExtensionContext, workspace, window, Disposable, commands, Uri, OutputChannel, WorkspaceFolder } from 'vscode'; +import { ExtensionContext, workspace, window, Disposable, commands, Uri, OutputChannel, WorkspaceFolder, languages, CompletionItemProvider, CompletionItem, TextDocument } from 'vscode'; import { findGit, Git, IGit } from './git'; import { Model } from './model'; import { CommandCenter } from './commands'; @@ -21,6 +21,7 @@ import { GitProtocolHandler } from './protocolHandler'; import { GitExtensionImpl } from './api/extension'; import * as path from 'path'; import * as fs from 'fs'; +import * as qs from 'querystring'; import { createIPCServer, IIPCServer } from './ipc/ipcServer'; const deactivateTasks: { (): Promise; }[] = []; @@ -164,6 +165,20 @@ export async function activate(context: ExtensionContext): Promise try { const model = await createModel(context, outputChannel, telemetryReporter, disposables); + + languages.registerCompletionItemProvider({ scheme: 'vscode', pattern: 'scm/git/**/input' }, new class implements CompletionItemProvider { + provideCompletionItems(document: TextDocument): CompletionItem[] { + const uri = document.uri; + const query = qs.parse(uri.query); + const rootUri = Uri.parse(query.rootUri as string); + const repository = model.getRepository(rootUri); + + console.log(rootUri, repository); + + return [{ label: 'hello' }]; + } + }); + return new GitExtensionImpl(model); } catch (err) { if (!/Git installation not found/.test(err.message || '')) { From 3b26aec31d90b1476cf444f1970db4d2896ea976 Mon Sep 17 00:00:00 2001 From: Pine Wu Date: Fri, 17 Jan 2020 15:29:20 +0100 Subject: [PATCH 032/177] Ellipsis behavior for details --- .../editor/contrib/suggest/media/suggest.css | 79 +++++++++++-------- .../editor/contrib/suggest/suggestWidget.ts | 39 ++++++--- 2 files changed, 74 insertions(+), 44 deletions(-) diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 79c19965dc1..82b36f56856 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -99,21 +99,25 @@ overflow: hidden; text-overflow: ellipsis; white-space: pre; + justify-content: space-between; +} + +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left, +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right { + display: flex; } .monaco-editor .suggest-widget:not(.frozen) .monaco-highlighted-label .highlight { font-weight: bold; } -/** Icon styles **/ +/** ReadMore Icon styles **/ .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore::before { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .readMore::before { color: inherit; opacity: 1; font-size: 14px; - margin-left: 2px; - margin-right: 2px; cursor: pointer; } @@ -124,71 +128,82 @@ } .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close:hover, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore:hover { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .readMore:hover { opacity: 1; } /** Type Info and icon next to the label in the focused completion item **/ -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .details-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label { margin-left: 0.8em; - flex: 1; - text-align: right; overflow: hidden; text-overflow: ellipsis; opacity: 0.7; white-space: nowrap; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .details-label > .monaco-tokenized-source { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label > .monaco-tokenized-source { display: inline; } /** Details: if using CompletionItem#details, show on focus **/ -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .details-label, -.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .details-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .details-label, +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .right > .details-label { display: none; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .details-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .right > .details-label { display: inline; } /** Details: if using CompletionItemLabel#details, always show **/ -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .details-label.always-show, -.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .details-label.always-show { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right.always-show-details > .details-label, +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row.focused > .contents > .main > .right.always-show-details > .details-label { display: inline; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row:hover > .contents > .main > .details-label { - opacity: 0.3; -} -.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row:hover > .contents > .main > .details-label, -.monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row:hover > .contents > .main > .details-label, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row:hover > .contents > .main > .details-label:not(.can-expand) { - opacity: 0.7; +/** Ellipsis on hover **/ +.monaco-editor .suggest-widget:not(.docs-side) .monaco-list .monaco-list-row:hover > .contents > .main > .right.can-expand-details > .details-label { + width: calc(100% - 26px); } -/** ReadMore: always layout, only shown on hover **/ -/** But if docs is side or bottom, hide still **/ +/** ReadMore: show on hover **/ +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right { + overflow: hidden; +} -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore { - display: inline; - visibility: hidden; +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > .readMore { + display: inline-block; position: absolute; - top: 0px; - right: 0px; - padding-right: 10px; + right: 10px; + width: 18px; + height: 18px; + visibility: hidden; } -.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row > .contents > .main > .readMore, -.monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row > .contents > .main > .readMore { +/** Do NOT display ReadMore when docs is side/below **/ +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row > .contents > .main > .right > .readMore, +.monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row > .contents > .main > .right > .readMore { + display: none !important; +} + +/** Do NOT display ReadMore when using plain CompletionItemLabel (details/documentation might not be resolved) **/ +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right:not(.always-show-details) > .readMore { + display: none; +} +/** Focused item can show ReadMore, but can't when docs is side/below **/ +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .right:not(.always-show-details) > .readMore { + display: inline-block; +} + +.monaco-editor .suggest-widget.docs-side .monaco-list .monaco-list-row > .contents > .main > .right > .readMore, +.monaco-editor .suggest-widget.docs-below .monaco-list .monaco-list-row > .contents > .main > .right > .readMore { display: none; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row:hover > .contents > .main > .readMore { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row:hover > .contents > .main > .right > .readMore { visibility: visible; } diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 67197ed73c2..fabe0d8c571 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -47,6 +47,15 @@ const expandSuggestionDocsByDefault = false; interface ISuggestionTemplateData { root: HTMLElement; + + /** + * Flexbox + * < -- left --> <--- right ---> + *