diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 9de657dcd87da8d758de994d22b77641c1940618..93c7b9bcef4efd176deba3f8ad25a6fe5b7ce073 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -2668,6 +2668,10 @@ export interface ISuggestOptions { * Show snippet-suggestions. */ showSnippets?: boolean; + /** + * Controls the visibility of the status bar at the bottom of the suggest widget. + */ + hideStatusBar?: boolean; } export type InternalSuggestOptions = Readonly>; @@ -2709,6 +2713,7 @@ class EditorSuggest extends BaseEditorOption .tree { + margin-bottom: 18px; +} +.monaco-editor .suggest-widget > .suggest-status-bar { + visibility: hidden; + + position: absolute; + left: 0; + + box-sizing: border-box; + + display: flex; + flex-flow: row nowrap; + justify-content: space-between; + + width: 100%; + + font-size: 80%; + + border-left-width: 1px; + border-left-style: solid; + border-right-width: 1px; + border-right-style: solid; + border-bottom-width: 1px; + border-bottom-style: solid; + + padding: 1px 8px 1px 4px; + + box-shadow: 0 -.5px 3px #ddd; +} +.monaco-editor .suggest-widget > .suggest-status-bar span { + opacity: 0.7; +} +.monaco-editor .suggest-widget.list-right.docs-side > .suggest-status-bar { + left: auto; + right: 0; +} +.monaco-editor .suggest-widget.docs-side > .suggest-status-bar { + width: 50%; +} + /** ReadMore Icon styles **/ .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close, diff --git a/src/vs/editor/contrib/suggest/media/suggestStatusBar.css b/src/vs/editor/contrib/suggest/media/suggestStatusBar.css new file mode 100644 index 0000000000000000000000000000000000000000..cf7b3924f581eb9de1b443f8997af694dad5aa48 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/suggestStatusBar.css @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar { + visibility: visible; +} + +.monaco-editor .suggest-widget.with-status-bar .suggest-status-bar span { + min-height: 18px; +} + +.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row > .contents > .main > .right > .readMore, +.monaco-editor .suggest-widget.with-status-bar .monaco-list .monaco-list-row.focused > .contents > .main > .right:not(.always-show-details) > .readMore { + display: none; +} + +.monaco-editor .suggest-widget.with-status-bar:not(.docs-side) .monaco-list .monaco-list-row:hover > .contents > .main > .right.can-expand-details > .details-label { + width: 100%; +} diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index 719c5446138fd7a55b7099f2ff765766899d1a5d..f54f304688cfc9ba4688cde2df03f6f85741c3df 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 { @@ -528,11 +528,8 @@ const SuggestCommand = EditorCommand.bindToContribution(Sugge registerEditorCommand(new SuggestCommand({ id: 'acceptSelectedSuggestion', precondition: SuggestContext.Visible, - handler(x, args) { - const alternative: boolean = typeof args === 'object' && typeof args.alternative === 'boolean' - ? args.alternative - : false; - x.acceptSelectedSuggestion(true, alternative); + handler(x) { + x.acceptSelectedSuggestion(true, false); } })); @@ -552,16 +549,23 @@ KeybindingsRegistry.registerKeybindingRule({ weight }); +// todo@joh control enablement via context key // shift+enter and shift+tab use the alternative-flag so that the suggest controller // is doing the opposite of the editor.suggest.overwriteOnAccept-configuration -KeybindingsRegistry.registerKeybindingRule({ - id: 'acceptSelectedSuggestion', - when: ContextKeyExpr.and(SuggestContext.Visible, EditorContextKeys.textInputFocus), - primary: KeyMod.Shift | KeyCode.Tab, - secondary: [KeyMod.Shift | KeyCode.Enter], - args: { alternative: true }, - weight -}); +registerEditorCommand(new SuggestCommand({ + id: 'acceptAlternativeSelectedSuggestion', + precondition: ContextKeyExpr.and(SuggestContext.Visible, EditorContextKeys.textInputFocus), + kbOpts: { + weight: weight, + kbExpr: EditorContextKeys.textInputFocus, + primary: KeyMod.Shift | KeyCode.Enter, + secondary: [KeyMod.Shift | KeyCode.Tab], + }, + handler(x) { + x.acceptSelectedSuggestion(false, true); + }, +})); + // continue to support the old command CommandsRegistry.registerCommandAlias('acceptSelectedSuggestionOnEnter', 'acceptSelectedSuggestion'); diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 3f6f7a3b4f11e283dd05a3772291c2bde52ae9db..95c1a8c24f9360f84d857068c874b234da022b26 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/suggest'; +import 'vs/css!./media/suggestStatusBar'; import 'vs/base/browser/ui/codiconLabel/codiconLabel'; // The codicon symbol styles are defined here and must be loaded import 'vs/editor/contrib/documentSymbols/outlineTree'; // The codicon symbol colors are defined here and must be loaded import * as nls from 'vs/nls'; @@ -41,6 +42,7 @@ import { FileKind } from 'vs/platform/files/common/files'; import { MarkdownString } from 'vs/base/common/htmlContent'; import { flatten } from 'vs/base/common/arrays'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { Position } from 'vs/editor/common/core/position'; const expandSuggestionDocsByDefault = false; @@ -301,7 +303,7 @@ class SuggestionDetails { private readonly widget: SuggestWidget, private readonly editor: ICodeEditor, private readonly markdownRenderer: MarkdownRenderer, - private readonly triggerKeybindingLabel: string, + private readonly kbToggleDetails: string, ) { this.disposables = new DisposableStore(); @@ -316,7 +318,7 @@ class SuggestionDetails { this.header = append(this.body, $('.header')); this.close = append(this.header, $('span.codicon.codicon-close')); - this.close.title = nls.localize('readLess', "Read less...{0}", this.triggerKeybindingLabel); + this.close.title = nls.localize('readLess', "Read less...{0}", this.kbToggleDetails); this.type = append(this.header, $('p.type')); this.docs = append(this.body, $('p.docs')); @@ -468,6 +470,9 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate; private listHeight?: number; @@ -517,18 +525,20 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate toggleClass(this.element, 'with-status-bar', !this.editor.getOption(EditorOption.suggest).hideStatusBar); + applyStatusBarStyle(); + + this.statusBarElement = append(this.element, $('.suggest-status-bar')); + this.statusBarLeftSpan = append(this.statusBarElement, $('span')); + this.statusBarRightSpan = append(this.statusBarElement, $('span')); + + this.setStatusBarLeftText(''); + this.setStatusBarRightText(''); + + this.details = instantiationService.createInstance(SuggestionDetails, this.element, this, this.editor, markdownRenderer, kbToggleDetails); const applyIconStyle = () => toggleClass(this.element, 'no-icons', !this.editor.getOption(EditorOption.suggest).showIcons); applyIconStyle(); - let renderer = instantiationService.createInstance(ItemRenderer, this, this.editor, triggerKeybindingLabel); + let renderer = instantiationService.createInstance(ItemRenderer, this, this.editor, kbToggleDetails); this.list = new List('SuggestWidget', this.listElement, this, [renderer], { useShadows: false, @@ -582,7 +603,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 => { if (e.hasChanged(EditorOption.suggest)) { applyIconStyle(); } })); + this.toDispose.add(this.editor.onDidChangeConfiguration(e => { + if (e.hasChanged(EditorOption.suggest)) { + applyStatusBarStyle(); + applyIconStyle(); + } + })); this.suggestWidgetVisible = SuggestContext.Visible.bindTo(contextKeyService); this.suggestWidgetMultipleSuggestions = SuggestContext.MultipleSuggestions.bindTo(contextKeyService); @@ -661,12 +687,14 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate this should a toolbar with actions so that these things become + // mouse clickable and fit for accessibility... + const wantsInsert = this.editor.getOption(EditorOption.suggest).insertMode === 'insert'; + const kbAccept = this.keybindingService.lookupKeybinding('acceptSelectedSuggestion')?.getLabel(); + const kbAcceptAlt = this.keybindingService.lookupKeybinding('acceptAlternativeSelectedSuggestion')?.getLabel(); + if (!Position.equals(item.editInsertEnd, item.editReplaceEnd)) { + // insert AND replace + if (wantsInsert) { + this.setStatusBarLeftText(nls.localize('insert', "{0} to insert, {1} to replace", kbAccept, kbAcceptAlt)); + } else { + this.setStatusBarLeftText(nls.localize('replace', "{0} to replace, {1} to insert", kbAccept, kbAcceptAlt)); + } + } else { + this.setStatusBarLeftText(nls.localize('accept', "{0} to accept", kbAccept)); + } if (this.currentSuggestionDetails) { this.currentSuggestionDetails.cancel(); @@ -739,6 +783,16 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate>;