Change:
Follow up from I have a completion item provider for context keys. For the keybindings UI this isn't working yet and what's needed is the simple editor widget as the input when authoring when-clauses a similar completion item provider (using internal API) that uses the same data source ()
Started using (Code Editor) for when input and I am seeing following issues with the code editor widget is showing far away from the editor. <img width="858" alt="image" src="https://user-"listen on key and accept the when text. This is causing problem when I am accepting an option from suggest list using Enter. Is there a way to prevent this to happen? / Your expertise would be very helpful here. You can find changes here -
Pretty sure that you need to use the keybindings service instead, e.g don't listen to keydown/up event directly ops... that seems very wrong, both widgets are normal content/overlay widgets
Right. I am using keybindings to accept/reject when expression changes. And it fixed the second issue. Thanks. Issue with suggest widget is only pending.
Investigated the issue with overflow content widget misplacement and here is what I found: This seems to be a bug with editor overflowing content widget value set to . According to the docs, when position value is set to fixed then the position of the element will be relative to its containing block, which is In keybindings editor, the table widget (extending list widget) has the ancestor rows element with and css property set. Hence overflowing content widgets are drawn relative to the table rows element. This can be confirmed by disabling the on the table widget that does not set above css properties. This means, embedding a code editor widget inside any node that has these css properties set will break the position of the overflowing content widgets CC / for editor related. CC for table/list related. Can you please let me know what is the right way to proceed here. Does it makes sense to disable for keybindings table? Or this shall has to be fixed in editor?
It seems the trick is to use option in the code editor. But it seems to work only for content widgets but not for overlay widgets - like suggest element details. Using the same for overlay widgets fixes it.
For now disabled table transformations and created a separate PR to fix it in the editor -
Verify that while editing when column in keyboard shortcuts editor shows the list of context key suggestions.
I see this is implemented but it's also mostly broken because it doesn't work with prefixes

Discussion:
import { Delayer } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; import { isIOS, OS } from 'vs/base/common/platform'; <del> import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; </del> <ins> import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; </ins> import { ToggleActionViewItem } from 'vs/base/browser/ui/toggle/toggle'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';

import { CancellationToken } from 'vs/base/common/cancellation'; import { attachStylerCallback } from 'vs/platform/theme/common/styler'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; <del> import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; </del> import { Emitter, Event } from 'vs/base/common/event'; import { MenuRegistry, MenuId, isIMenuItem } from 'vs/platform/actions/common/actions'; import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';

import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { isString } from 'vs/base/common/types'; <ins> import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; </ins> const $ = DOM.$;

} } <del> interface IWhenColumnTemplateData { readonly element: HTMLElement; readonly whenContainer: HTMLElement; readonly whenLabel: HighlightedLabel; readonly whenInput: InputBox; readonly renderDisposables: DisposableStore; readonly onDidAccept: Event<void>; readonly onDidReject: Event<void>; readonly disposables: DisposableStore; } </del> <ins> class WhenInputWidget extends Disposable { </ins> <del> class WhenColumnRenderer implements ITableRenderer<IKeybindingItemEntry, IWhenColumnTemplateData> { </del> <ins> private readonly input: InputBox; readonly el: HTMLElement; </ins> <del> static readonly TEMPLATE_ID = 'when'; </del> <ins> private readonly _onDidAccept = this._register(new Emitter<string>()); readonly onDidAccept = this._onDidAccept.event; </ins> <del> readonly templateId: string = WhenColumnRenderer.TEMPLATE_ID; private whenFocusContextKey: IContextKey<boolean>; </del> <ins> private readonly _onDidReject = this._register(new Emitter<void>()); readonly onDidReject = this._onDidReject.event; </ins> constructor( <del> private readonly keybindingsEditor: KeybindingsEditor, @IContextViewService private readonly contextViewService: IContextViewService, </del> @IContextKeyService contextKeyService: IContextKeyService, <ins> @IContextViewService contextViewService: IContextViewService, </ins> ) { <del> this.whenFocusContextKey = CONTEXT_WHEN_FOCUS.bindTo(contextKeyService); } renderTemplate(container: HTMLElement): IWhenColumnTemplateData { const element = DOM.append(container, $('.when')); </del> <ins> super(); </ins> <del> const whenContainer = DOM.append(element, $('div.when-label')); const whenLabel = new HighlightedLabel(whenContainer); const whenInput = new InputBox(element, this.contextViewService, { </del> <ins> this.input = new InputBox(this.el = DOM.$('.when-input'), contextViewService, { </ins> validationOptions: { validation: (value) => { try {

inputBoxStyles: defaultInputBoxStyles }); <del> const disposables = new DisposableStore(); const _onDidAccept: Emitter<void> = disposables.add(new Emitter<void>()); const onDidAccept: Event<void> = _onDidAccept.event; const _onDidReject: Emitter<void> = disposables.add(new Emitter<void>()); const onDidReject: Event<void> = _onDidReject.event; const hideInputBox = () => { element.classList.remove('input-mode'); container.style.paddingLeft = '10px'; }; disposables.add(DOM.addStandardDisposableListener(whenInput.inputElement, DOM.EventType.KEY_DOWN, e => { </del> <ins> this._register(DOM.addStandardDisposableListener(this.input.inputElement, DOM.EventType.KEY_DOWN, e => { </ins> let handled = false; if (e.equals(KeyCode.Enter)) { <del> hideInputBox(); _onDidAccept.fire(); </del> <ins> this._onDidAccept.fire(this.input.value); </ins> handled = true; } else if (e.equals(KeyCode.Escape)) { <del> hideInputBox(); _onDidReject.fire(); </del> <ins> this._onDidReject.fire(); </ins> handled = true; } if (handled) {

e.stopPropagation(); } })); <del> disposables.add((DOM.addDisposableListener(whenInput.inputElement, DOM.EventType.FOCUS, () => { this.whenFocusContextKey.set(true); }))); disposables.add((DOM.addDisposableListener(whenInput.inputElement, DOM.EventType.BLUR, () => { this.whenFocusContextKey.set(false); hideInputBox(); _onDidReject.fire(); </del> <ins> const whenFocusContextKey = CONTEXT_WHEN_FOCUS.bindTo(contextKeyService); this._register((DOM.addDisposableListener(this.input.inputElement, DOM.EventType.FOCUS, () => whenFocusContextKey.set(true)))); this._register((DOM.addDisposableListener(this.input.inputElement, DOM.EventType.BLUR, () => { whenFocusContextKey.set(false); this._onDidReject.fire(); </ins> }))); // stop double click action on the input #148493 <del> disposables.add((DOM.addDisposableListener(whenInput.inputElement, DOM.EventType.DBLCLICK, e => DOM.EventHelper.stop(e)))); </del> <ins> this._register((DOM.addDisposableListener(this.input.inputElement, DOM.EventType.DBLCLICK, e => DOM.EventHelper.stop(e)))); } </ins> <del> const renderDisposables = disposables.add(new DisposableStore()); </del> <ins> layout(dimension: DOM.Dimension): void { this.input.element.style.height = `${dimension.height}px`; } show(value: string): void { DOM.show(this.el); this.input.value = value; this.input.focus(); this.input.select(); } hide(): void { DOM.hide(this.el); } } interface IWhenColumnTemplateData { readonly element: HTMLElement; readonly whenLabelContainer: HTMLElement; readonly whenInputContainer: HTMLElement; readonly whenLabel: HighlightedLabel; readonly disposables: DisposableStore; } class WhenColumnRenderer implements ITableRenderer<IKeybindingItemEntry, IWhenColumnTemplateData> { static readonly TEMPLATE_ID = 'when'; readonly templateId: string = WhenColumnRenderer.TEMPLATE_ID; private readonly whenInputWidget: WhenInputWidget; constructor( private readonly keybindingsEditor: KeybindingsEditor, @IInstantiationService instantiationService: IInstantiationService, ) { this.whenInputWidget = instantiationService.createInstance(WhenInputWidget); } renderTemplate(container: HTMLElement): IWhenColumnTemplateData { const element = DOM.append(container, $('.when')); const whenLabelContainer = DOM.append(element, $('div.when-label')); const whenLabel = new HighlightedLabel(whenLabelContainer); const whenInputContainer = DOM.append(element, $('div.when-input-container')); </ins> return { element, <del> whenContainer, </del> <ins> whenLabelContainer, </ins> whenLabel, <del> whenInput, onDidAccept, onDidReject, renderDisposables, disposables, </del> <ins> whenInputContainer, disposables: new DisposableStore(), </ins> }; } renderElement(keybindingItemEntry: IKeybindingItemEntry, index: number, templateData: IWhenColumnTemplateData, height: number | undefined): void { <del> templateData.renderDisposables.clear(); templateData.renderDisposables.add(this.keybindingsEditor.onDefineWhenExpression(e => { </del> <ins> templateData.disposables.clear(); const whenInputDisposables = templateData.disposables.add(new DisposableStore()); templateData.disposables.add(this.keybindingsEditor.onDefineWhenExpression(e => { </ins> if (keybindingItemEntry === e) { templateData.element.classList.add('input-mode'); <del> templateData.whenInput.focus(); templateData.whenInput.select(); </del> <ins> DOM.append(templateData.whenInputContainer, this.whenInputWidget.el); this.whenInputWidget.show(keybindingItemEntry.keybindingItem.when || ''); this.whenInputWidget.layout(new DOM.Dimension(templateData.element.parentElement!.clientWidth, 24)); const hideInputWidget = () => { whenInputDisposables.clear(); templateData.element.classList.remove('input-mode'); templateData.element.parentElement!.style.paddingLeft = '10px'; DOM.clearNode(templateData.whenInputContainer); this.whenInputWidget.hide(); }; whenInputDisposables.add(this.whenInputWidget.onDidAccept(value => { hideInputWidget(); this.keybindingsEditor.updateKeybinding(keybindingItemEntry, keybindingItemEntry.keybindingItem.keybinding ? keybindingItemEntry.keybindingItem.keybinding.getUserSettingsLabel() || '' : '', value); this.keybindingsEditor.selectKeybinding(keybindingItemEntry); })); whenInputDisposables.add(this.whenInputWidget.onDidReject(value => { hideInputWidget(); this.keybindingsEditor.selectKeybinding(keybindingItemEntry); })); </ins> templateData.element.parentElement!.style.paddingLeft = '0px'; } })); <del> templateData.whenInput.value = keybindingItemEntry.keybindingItem.when || ''; templateData.whenContainer.classList.toggle('code', !!keybindingItemEntry.keybindingItem.when); templateData.whenContainer.classList.toggle('empty', !keybindingItemEntry.keybindingItem.when); </del> <ins> templateData.whenLabelContainer.classList.toggle('code', !!keybindingItemEntry.keybindingItem.when); templateData.whenLabelContainer.classList.toggle('empty', !keybindingItemEntry.keybindingItem.when); </ins> if (keybindingItemEntry.keybindingItem.when) { templateData.whenLabel.set(keybindingItemEntry.keybindingItem.when, keybindingItemEntry.whenMatches);

templateData.element.title = ''; } <del> templateData.renderDisposables.add(templateData.onDidAccept(() => { this.keybindingsEditor.updateKeybinding(keybindingItemEntry, keybindingItemEntry.keybindingItem.keybinding ? keybindingItemEntry.keybindingItem.keybinding.getUserSettingsLabel() || '' : '', templateData.whenInput.value); this.keybindingsEditor.selectKeybinding(keybindingItemEntry); })); templateData.renderDisposables.add(templateData.onDidReject(() => { templateData.whenInput.value = keybindingItemEntry.keybindingItem.when || ''; this.keybindingsEditor.selectKeybinding(keybindingItemEntry); })); </del> } disposeTemplate(templateData: IWhenColumnTemplateData): void { templateData.disposables.dispose(); <del> templateData.renderDisposables.dispose(); </del> } }

padding-left: 4px; } <del> .keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when:not(.input-mode) .monaco-inputbox, </del> .keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when.input-mode .when-label { display: none; } <del> .keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when .monaco-inputbox { line-height: normal; } .keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when .monaco-inputbox input { </del> <ins> .keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when .suggest-input-container { </ins> padding-left: 10px; } <del> .monaco-workbench.mac .keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when .monaco-inputbox, .monaco-workbench.mac .keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .when .monaco-inputbox { height: 24px; } </del> /** Source column styling **/ .keybindings-editor > .keybindings-body > .keybindings-table-container .monaco-table-tr .monaco-table-td .source a { color: var(--vscode-textLink-foreground);