Extract autosuggest editor to own class; bring into settings (#55924)
* Extract autosuggest editor to own class; bring into settings * Remove unused css. Fix clipping issue. * Autosuggest -> suggest * Remove rounded selections from suggest inputs
This commit is contained in:
parent
753c832fdd
commit
5e37f92880
16 changed files with 376 additions and 225 deletions
|
@ -0,0 +1,27 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.suggest-input-container {
|
||||
padding: 3px 4px 5px;
|
||||
}
|
||||
|
||||
.suggest-input-container .monaco-editor-background,
|
||||
.suggest-input-container .monaco-editor,
|
||||
.suggest-input-container .mtk1 {
|
||||
/* allow the embedded monaco to be styled from the outer context */
|
||||
background-color: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.suggest-input-container .suggest-input-placeholder {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
pointer-events: none;
|
||||
margin-top: 2px;
|
||||
margin-left: 1px;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
export function getSimpleEditorOptions(): IEditorOptions {
|
||||
return {
|
||||
wordWrap: 'on',
|
||||
overviewRulerLanes: 0,
|
||||
glyphMargin: false,
|
||||
lineNumbers: 'off',
|
||||
folding: false,
|
||||
selectOnLineNumbers: false,
|
||||
hideCursorInOverviewRuler: true,
|
||||
selectionHighlight: false,
|
||||
scrollbar: {
|
||||
horizontal: 'hidden'
|
||||
},
|
||||
lineDecorationsWidth: 0,
|
||||
overviewRulerBorder: false,
|
||||
scrollBeyondLastLine: false,
|
||||
renderLineHighlight: 'none',
|
||||
fixedOverflowWidgets: true,
|
||||
acceptSuggestionOnEnter: 'smart',
|
||||
minimap: {
|
||||
enabled: false
|
||||
}
|
||||
};
|
||||
}
|
232
src/vs/workbench/parts/codeEditor/browser/suggestEnabledInput.ts
Normal file
232
src/vs/workbench/parts/codeEditor/browser/suggestEnabledInput.ts
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./media/suggestEnabledInput';
|
||||
import { $, addClass, append, removeClass, Dimension } from 'vs/base/browser/dom';
|
||||
import { chain, Emitter, Event } from 'vs/base/common/event';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import uri from 'vs/base/common/uri';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ContextMenuController } from 'vs/editor/contrib/contextmenu/contextmenu';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
|
||||
import { SuggestController } from 'vs/editor/contrib/suggest/suggestController';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { inputBackground, inputBorder, inputForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { Component } from 'vs/workbench/common/component';
|
||||
import { MenuPreventer } from 'vs/workbench/parts/codeEditor/browser/menuPreventer';
|
||||
import { getSimpleEditorOptions } from 'vs/workbench/parts/codeEditor/browser/simpleEditorOptions';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
interface SuggestResultsProvider {
|
||||
/**
|
||||
* Provider function for suggestion results.
|
||||
*
|
||||
* @param query the full text of the input.
|
||||
*/
|
||||
provideResults: (query: string) => string[];
|
||||
|
||||
/**
|
||||
* Trigger characters for this input. Suggestions will appear when one of these is typed,
|
||||
* or upon `ctrl+space` triggering at a word boundary.
|
||||
*
|
||||
* Defaults to the empty array.
|
||||
*/
|
||||
triggerCharacters?: string[];
|
||||
|
||||
/**
|
||||
* Defines the sorting function used when showing results.
|
||||
*
|
||||
* Defaults to the identity function.
|
||||
*/
|
||||
sortKey?: (result: string) => string;
|
||||
}
|
||||
|
||||
interface SuggestEnabledInputOptions {
|
||||
/**
|
||||
* The text to show when no input is present.
|
||||
*
|
||||
* Defaults to the empty string.
|
||||
*/
|
||||
placeholderText?: string;
|
||||
|
||||
/**
|
||||
* Context key tracking the focus state of this element
|
||||
*/
|
||||
focusContextKey?: IContextKey<boolean>;
|
||||
}
|
||||
|
||||
export class SuggestEnabledInput extends Component {
|
||||
|
||||
private _onShouldFocusResults = new Emitter<void>();
|
||||
readonly onShouldFocusResults: Event<void> = this._onShouldFocusResults.event;
|
||||
|
||||
private _onEnter = new Emitter<void>();
|
||||
readonly onEnter: Event<void> = this._onEnter.event;
|
||||
|
||||
private _onInputDidChange = new Emitter<string>();
|
||||
readonly onInputDidChange: Event<string> = this._onInputDidChange.event;
|
||||
|
||||
private disposables: IDisposable[] = [];
|
||||
private inputWidget: CodeEditorWidget;
|
||||
private stylingContainer: HTMLDivElement;
|
||||
private placeholderText: HTMLDivElement;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
parent: HTMLElement,
|
||||
suggestionProvider: SuggestResultsProvider,
|
||||
ariaLabel: string,
|
||||
resourceHandle: string,
|
||||
options: SuggestEnabledInputOptions,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IModelService modelService: IModelService,
|
||||
) {
|
||||
super(id, themeService);
|
||||
|
||||
this.stylingContainer = append(parent, $('.suggest-input-container'));
|
||||
this.placeholderText = append(this.stylingContainer, $('.suggest-input-placeholder', null, options.placeholderText || ''));
|
||||
|
||||
this.inputWidget = instantiationService.createInstance(CodeEditorWidget, this.stylingContainer,
|
||||
mixinHTMLInputStyleOptions(getSimpleEditorOptions(), ariaLabel),
|
||||
{
|
||||
contributions: [SuggestController, SnippetController2, ContextMenuController, MenuPreventer],
|
||||
isSimpleWidget: true,
|
||||
});
|
||||
|
||||
let scopeHandle = uri.parse(resourceHandle);
|
||||
this.inputWidget.setModel(modelService.createModel('', null, scopeHandle, true));
|
||||
|
||||
this.disposables.push(this.inputWidget.onDidPaste(() => this.setValue(this.getValue()))); // setter cleanses
|
||||
|
||||
this.disposables.push((this.inputWidget.onDidFocusEditorText(() => {
|
||||
if (options.focusContextKey) { options.focusContextKey.set(true); }
|
||||
addClass(this.stylingContainer, 'synthetic-focus');
|
||||
})));
|
||||
this.disposables.push((this.inputWidget.onDidBlurEditorText(() => {
|
||||
if (options.focusContextKey) { options.focusContextKey.set(false); }
|
||||
removeClass(this.stylingContainer, 'synthetic-focus');
|
||||
})));
|
||||
|
||||
const onKeyDownMonaco = chain(this.inputWidget.onKeyDown);
|
||||
onKeyDownMonaco.filter(e => e.keyCode === KeyCode.Enter).on(e => { e.preventDefault(); this._onEnter.fire(); }, this, this.disposables);
|
||||
onKeyDownMonaco.filter(e => e.keyCode === KeyCode.DownArrow && (isMacintosh ? e.metaKey : e.ctrlKey)).on(() => this._onShouldFocusResults.fire(), this, this.disposables);
|
||||
|
||||
let preexistingContent = this.getValue();
|
||||
this.disposables.push(this.inputWidget.getModel().onDidChangeContent(() => {
|
||||
let content = this.getValue();
|
||||
this.placeholderText.style.visibility = content ? 'hidden' : 'visible';
|
||||
if (preexistingContent.trim() === content.trim()) { return; }
|
||||
this._onInputDidChange.fire();
|
||||
preexistingContent = content;
|
||||
}));
|
||||
|
||||
let validatedSuggestProvider = {
|
||||
provideResults: suggestionProvider.provideResults,
|
||||
sortKey: suggestionProvider.sortKey || (a => a),
|
||||
triggerCharacters: suggestionProvider.triggerCharacters || []
|
||||
};
|
||||
|
||||
this.disposables.push(modes.SuggestRegistry.register({ scheme: scopeHandle.scheme, pattern: '**/' + scopeHandle.path, hasAccessToAllModels: true }, {
|
||||
triggerCharacters: validatedSuggestProvider.triggerCharacters,
|
||||
provideCompletionItems: (model: ITextModel, position: Position, _context: modes.SuggestContext) => {
|
||||
let query = model.getValue();
|
||||
|
||||
let wordStart = query.lastIndexOf(' ', position.column - 1) + 1;
|
||||
let alreadyTypedCount = position.column - wordStart - 1;
|
||||
|
||||
// dont show suggestions if the user has typed something, but hasn't used the trigger character
|
||||
if (alreadyTypedCount > 0 && (validatedSuggestProvider.triggerCharacters).indexOf(query[wordStart]) === -1) { return { suggestions: [] }; }
|
||||
|
||||
return {
|
||||
suggestions: suggestionProvider.provideResults(query).map(result => {
|
||||
return {
|
||||
label: result,
|
||||
insertText: result,
|
||||
overwriteBefore: alreadyTypedCount,
|
||||
sortText: validatedSuggestProvider.sortKey(result),
|
||||
type: <modes.SuggestionType>'keyword'
|
||||
};
|
||||
})
|
||||
};
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public setValue(val: string) {
|
||||
val = val.replace(/\s/g, ' ');
|
||||
this.inputWidget.setValue(val);
|
||||
this.inputWidget.setScrollTop(0);
|
||||
this.inputWidget.setPosition(new Position(1, val.length + 1));
|
||||
}
|
||||
|
||||
public getValue(): string {
|
||||
return this.inputWidget.getValue();
|
||||
}
|
||||
|
||||
|
||||
public updateStyles(): void {
|
||||
super.updateStyles();
|
||||
|
||||
this.stylingContainer.style.backgroundColor = this.getColor(inputBackground);
|
||||
this.stylingContainer.style.color = this.getColor(inputForeground);
|
||||
this.placeholderText.style.color = this.getColor(inputPlaceholderForeground);
|
||||
|
||||
const inputBorderColor = this.getColor(inputBorder);
|
||||
this.stylingContainer.style.borderWidth = inputBorderColor ? '1px' : null;
|
||||
this.stylingContainer.style.borderStyle = inputBorderColor ? 'solid' : null;
|
||||
this.stylingContainer.style.borderColor = inputBorderColor;
|
||||
|
||||
let cursor = this.stylingContainer.getElementsByClassName('cursor')[0] as HTMLDivElement;
|
||||
if (cursor) {
|
||||
cursor.style.backgroundColor = this.getColor(inputForeground);
|
||||
}
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
this.inputWidget.focus();
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): void {
|
||||
this.inputWidget.layout(dimension);
|
||||
this.placeholderText.style.width = `${dimension.width}px`;
|
||||
}
|
||||
|
||||
public selectAll(): void {
|
||||
this.inputWidget.setSelection(new Range(1, 1, 1, this.getValue().length + 1));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function mixinHTMLInputStyleOptions(config: IEditorOptions, ariaLabel?: string): IEditorOptions {
|
||||
config.fontSize = 13;
|
||||
config.lineHeight = 22;
|
||||
config.wordWrap = 'off';
|
||||
config.scrollbar.vertical = 'hidden';
|
||||
config.roundedSelection = false;
|
||||
config.ariaLabel = ariaLabel || '';
|
||||
config.renderIndentGuides = false;
|
||||
config.cursorWidth = 1;
|
||||
config.snippetSuggestions = 'none';
|
||||
config.suggest = { filterGraceful: false };
|
||||
config.fontFamily = ' -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Ubuntu", "Droid Sans", sans-serif';
|
||||
return config;
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
import './electron-browser/accessibility';
|
||||
import './electron-browser/inspectKeybindings';
|
||||
import './electron-browser/largeFileOptimizations';
|
||||
import './electron-browser/menuPreventer';
|
||||
import './browser/menuPreventer';
|
||||
import './electron-browser/selectionClipboard';
|
||||
import './electron-browser/textMate/inspectTMScopes';
|
||||
import './electron-browser/toggleMinimap';
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { MenuPreventer } from 'vs/workbench/parts/codeEditor/electron-browser/menuPreventer';
|
||||
import { MenuPreventer } from 'vs/workbench/parts/codeEditor/browser/menuPreventer';
|
||||
import { SelectionClipboard } from 'vs/workbench/parts/codeEditor/electron-browser/selectionClipboard';
|
||||
import { ContextMenuController } from 'vs/editor/contrib/contextmenu/contextmenu';
|
||||
import { SuggestController } from 'vs/editor/contrib/suggest/suggestController';
|
||||
|
@ -24,29 +23,4 @@ export function getSimpleCodeEditorWidgetOptions(): ICodeEditorWidgetOptions {
|
|||
TabCompletionController,
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
export function getSimpleEditorOptions(): IEditorOptions {
|
||||
return {
|
||||
wordWrap: 'on',
|
||||
overviewRulerLanes: 0,
|
||||
glyphMargin: false,
|
||||
lineNumbers: 'off',
|
||||
folding: false,
|
||||
selectOnLineNumbers: false,
|
||||
hideCursorInOverviewRuler: true,
|
||||
selectionHighlight: false,
|
||||
scrollbar: {
|
||||
horizontal: 'hidden'
|
||||
},
|
||||
lineDecorationsWidth: 0,
|
||||
overviewRulerBorder: false,
|
||||
scrollBeyondLastLine: false,
|
||||
renderLineHighlight: 'none',
|
||||
fixedOverflowWidgets: true,
|
||||
acceptSuggestionOnEnter: 'smart',
|
||||
minimap: {
|
||||
enabled: false
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
|||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
|
||||
// Allowed Editor Contributions:
|
||||
import { MenuPreventer } from 'vs/workbench/parts/codeEditor/electron-browser/menuPreventer';
|
||||
import { MenuPreventer } from 'vs/workbench/parts/codeEditor/browser/menuPreventer';
|
||||
import { SelectionClipboard } from 'vs/workbench/parts/codeEditor/electron-browser/selectionClipboard';
|
||||
import { ContextMenuController } from 'vs/editor/contrib/contextmenu/contextmenu';
|
||||
import { SuggestController } from 'vs/editor/contrib/suggest/suggestController';
|
||||
|
|
|
@ -33,7 +33,8 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
|||
import { IDecorationOptions } from 'vs/editor/common/editorCommon';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { getSimpleEditorOptions, getSimpleCodeEditorWidgetOptions } from 'vs/workbench/parts/codeEditor/electron-browser/simpleEditorOptions';
|
||||
import { getSimpleCodeEditorWidgetOptions } from 'vs/workbench/parts/codeEditor/electron-browser/simpleEditorOptions';
|
||||
import { getSimpleEditorOptions } from 'vs/workbench/parts/codeEditor/browser/simpleEditorOptions';
|
||||
|
||||
const $ = dom.$;
|
||||
const IPrivateBreakpointWidgetService = createDecorator<IPrivateBreakpointWidgetService>('privateBreakopintWidgetService');
|
||||
|
|
|
@ -47,7 +47,8 @@ import { HistoryNavigator } from 'vs/base/common/history';
|
|||
import { IHistoryNavigationWidget } from 'vs/base/browser/history';
|
||||
import { createAndBindHistoryNavigationWidgetScopedContextKeyService } from 'vs/platform/widget/browser/contextScopedHistoryWidget';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { getSimpleEditorOptions, getSimpleCodeEditorWidgetOptions } from 'vs/workbench/parts/codeEditor/electron-browser/simpleEditorOptions';
|
||||
import { getSimpleCodeEditorWidgetOptions } from 'vs/workbench/parts/codeEditor/electron-browser/simpleEditorOptions';
|
||||
import { getSimpleEditorOptions } from 'vs/workbench/parts/codeEditor/browser/simpleEditorOptions';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ export class Query {
|
|||
this.value = value.trim();
|
||||
}
|
||||
|
||||
static autocompletions(query: string): string[] {
|
||||
static suggestions(query: string): string[] {
|
||||
const commands = ['installed', 'outdated', 'enabled', 'disabled', 'builtin', 'recommended', 'sort', 'category', 'tag', 'ext'];
|
||||
const subcommands = {
|
||||
'sort': ['installs', 'rating', 'name'],
|
||||
|
|
|
@ -6,21 +6,18 @@
|
|||
'use strict';
|
||||
|
||||
import 'vs/css!./media/extensionsViewlet';
|
||||
import uri from 'vs/base/common/uri';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ThrottledDelayer, always } from 'vs/base/common/async';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { isPromiseCanceledError, onUnexpectedError, create as createError } from 'vs/base/common/errors';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Event as EventOf, Emitter, chain } from 'vs/base/common/event';
|
||||
import { Event as EventOf, Emitter } from 'vs/base/common/event';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IViewlet } from 'vs/workbench/common/viewlet';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { append, $, addClass, removeClass, toggleClass, Dimension } from 'vs/base/browser/dom';
|
||||
import { append, $, addClass, toggleClass, Dimension } from 'vs/base/browser/dom';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
@ -39,7 +36,6 @@ import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorG
|
|||
import Severity from 'vs/base/common/severity';
|
||||
import { IActivityService, ProgressBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { inputForeground, inputBackground, inputBorder, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ViewsRegistry, IViewDescriptor } from 'vs/workbench/common/views';
|
||||
import { ViewContainerViewlet, IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
|
@ -59,18 +55,7 @@ import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/e
|
|||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { SingleServerExtensionManagementServerService } from 'vs/workbench/services/extensions/node/extensionManagementServerService';
|
||||
import { Query } from 'vs/workbench/parts/extensions/common/extensionQuery';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { getSimpleEditorOptions } from 'vs/workbench/parts/codeEditor/electron-browser/simpleEditorOptions';
|
||||
import { SuggestController } from 'vs/editor/contrib/suggest/suggestController';
|
||||
import { ContextMenuController } from 'vs/editor/contrib/contextmenu/contextmenu';
|
||||
import { MenuPreventer } from 'vs/workbench/parts/codeEditor/electron-browser/menuPreventer';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { SuggestEnabledInput } from 'vs/workbench/parts/codeEditor/browser/suggestEnabledInput';
|
||||
|
||||
interface SearchInputEvent extends Event {
|
||||
target: HTMLInputElement;
|
||||
|
@ -265,14 +250,12 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
private searchDelayer: ThrottledDelayer<any>;
|
||||
private root: HTMLElement;
|
||||
|
||||
private searchBox: CodeEditorWidget;
|
||||
private searchBox: SuggestEnabledInput;
|
||||
private extensionsBox: HTMLElement;
|
||||
private primaryActions: IAction[];
|
||||
private secondaryActions: IAction[];
|
||||
private groupByServerAction: IAction;
|
||||
private disposables: IDisposable[] = [];
|
||||
private monacoStyleContainer: HTMLDivElement;
|
||||
private placeholderText: HTMLDivElement;
|
||||
|
||||
constructor(
|
||||
@IPartService partService: IPartService,
|
||||
|
@ -290,8 +273,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IExtensionManagementServerService private extensionManagementServerService: IExtensionManagementServerService,
|
||||
@IModelService private modelService: IModelService,
|
||||
@IExtensionManagementServerService private extensionManagementServerService: IExtensionManagementServerService
|
||||
) {
|
||||
super(VIEWLET_ID, `${VIEWLET_ID}.state`, true, partService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
|
||||
|
||||
|
@ -315,28 +297,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey));
|
||||
}
|
||||
}, this, this.disposables);
|
||||
|
||||
modes.SuggestRegistry.register({ scheme: 'extensions', pattern: '**/searchinput', hasAccessToAllModels: true }, {
|
||||
triggerCharacters: ['@'],
|
||||
provideCompletionItems: (model: ITextModel, position: Position, _context: modes.SuggestContext) => {
|
||||
const sortKey = (item: string) => {
|
||||
if (item.indexOf(':') === -1) { return 'a'; }
|
||||
else if (/ext:/.test(item) || /tag:/.test(item)) { return 'b'; }
|
||||
else if (/sort:/.test(item)) { return 'c'; }
|
||||
else { return 'd'; }
|
||||
};
|
||||
return {
|
||||
suggestions: this.autoComplete(model.getValue(), position.column).map(item => (
|
||||
{
|
||||
label: item.fullText,
|
||||
insertText: item.fullText,
|
||||
overwriteBefore: item.overwrite,
|
||||
sortText: sortKey(item.fullText),
|
||||
type: <modes.SuggestionType>'keyword'
|
||||
}))
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
create(parent: HTMLElement): TPromise<void> {
|
||||
|
@ -344,51 +304,32 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
this.root = parent;
|
||||
|
||||
const header = append(this.root, $('.header'));
|
||||
this.monacoStyleContainer = append(header, $('.monaco-container'));
|
||||
this.searchBox = this.instantiationService.createInstance(CodeEditorWidget, this.monacoStyleContainer,
|
||||
mixinHTMLInputStyleOptions(getSimpleEditorOptions(), localize('searchExtensions', "Search Extensions in Marketplace")),
|
||||
{
|
||||
isSimpleWidget: true, contributions: [
|
||||
SuggestController,
|
||||
SnippetController2,
|
||||
ContextMenuController,
|
||||
MenuPreventer
|
||||
]
|
||||
});
|
||||
|
||||
this.placeholderText = append(this.monacoStyleContainer, $('.search-placeholder', null, localize('searchExtensions', "Search Extensions in Marketplace")));
|
||||
const placeholder = localize('searchExtensions', "Search Extensions in Marketplace");
|
||||
|
||||
this.searchBox = this.instantiationService.createInstance(SuggestEnabledInput, `${VIEWLET_ID}.searchbox`, header, {
|
||||
triggerCharacters: ['@'],
|
||||
sortKey: item => {
|
||||
if (item.indexOf(':') === -1) { return 'a'; }
|
||||
else if (/ext:/.test(item) || /tag:/.test(item)) { return 'b'; }
|
||||
else if (/sort:/.test(item)) { return 'c'; }
|
||||
else { return 'd'; }
|
||||
},
|
||||
provideResults: (query) => Query.suggestions(query)
|
||||
}, placeholder, 'extensions:searchinput', { placeholderText: placeholder });
|
||||
|
||||
this.disposables.push(this.searchBox);
|
||||
|
||||
const _searchChange = new Emitter<string>();
|
||||
this.onSearchChange = _searchChange.event;
|
||||
this.searchBox.onInputDidChange(() => {
|
||||
this.triggerSearch();
|
||||
_searchChange.fire(this.searchBox.getValue());
|
||||
}, this, this.disposables);
|
||||
|
||||
this.searchBox.onShouldFocusResults(() => this.focusListView(), this, this.disposables);
|
||||
|
||||
this.extensionsBox = append(this.root, $('.extensions'));
|
||||
|
||||
this.searchBox.setModel(this.modelService.createModel('', null, uri.parse('extensions:searchinput'), true));
|
||||
|
||||
this.disposables.push(this.searchBox.onDidPaste(() => {
|
||||
let trimmed = this.searchBox.getValue().replace(/\s+/g, ' ');
|
||||
this.searchBox.setValue(trimmed);
|
||||
this.searchBox.setScrollTop(0);
|
||||
this.searchBox.setPosition(new Position(1, trimmed.length + 1));
|
||||
}));
|
||||
|
||||
this.disposables.push(this.searchBox.onDidFocusEditorText(() => addClass(this.monacoStyleContainer, 'synthetic-focus')));
|
||||
this.disposables.push(this.searchBox.onDidBlurEditorText(() => removeClass(this.monacoStyleContainer, 'synthetic-focus')));
|
||||
|
||||
const onKeyDownMonaco = chain(this.searchBox.onKeyDown);
|
||||
onKeyDownMonaco.filter(e => e.keyCode === KeyCode.Enter).on(e => e.preventDefault(), this, this.disposables);
|
||||
onKeyDownMonaco.filter(e => e.keyCode === KeyCode.DownArrow && (isMacintosh ? e.metaKey : e.ctrlKey)).on(() => this.focusListView(), this, this.disposables);
|
||||
|
||||
const searchChangeEvent = new Emitter<string>();
|
||||
this.onSearchChange = searchChangeEvent.event;
|
||||
|
||||
let existingContent = this.searchBox.getValue().trim();
|
||||
this.disposables.push(this.searchBox.getModel().onDidChangeContent(() => {
|
||||
this.placeholderText.style.visibility = this.searchBox.getValue() ? 'hidden' : 'visible';
|
||||
let content = this.searchBox.getValue().trim();
|
||||
if (existingContent === content) { return; }
|
||||
this.triggerSearch();
|
||||
searchChangeEvent.fire(content);
|
||||
existingContent = content;
|
||||
}));
|
||||
|
||||
return super.create(this.extensionsBox)
|
||||
.then(() => this.extensionManagementService.getInstalled(LocalExtensionType.User))
|
||||
.then(installed => {
|
||||
|
@ -401,20 +342,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
|
||||
public updateStyles(): void {
|
||||
super.updateStyles();
|
||||
|
||||
this.monacoStyleContainer.style.backgroundColor = this.getColor(inputBackground);
|
||||
this.monacoStyleContainer.style.color = this.getColor(inputForeground);
|
||||
this.placeholderText.style.color = this.getColor(inputPlaceholderForeground);
|
||||
|
||||
const inputBorderColor = this.getColor(inputBorder);
|
||||
this.monacoStyleContainer.style.borderWidth = inputBorderColor ? '1px' : null;
|
||||
this.monacoStyleContainer.style.borderStyle = inputBorderColor ? 'solid' : null;
|
||||
this.monacoStyleContainer.style.borderColor = inputBorderColor;
|
||||
|
||||
let cursor = this.monacoStyleContainer.getElementsByClassName('cursor')[0] as HTMLDivElement;
|
||||
if (cursor) {
|
||||
cursor.style.backgroundColor = this.getColor(inputForeground);
|
||||
}
|
||||
this.searchBox.updateStyles();
|
||||
}
|
||||
|
||||
setVisible(visible: boolean): TPromise<void> {
|
||||
|
@ -423,7 +351,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
if (isVisibilityChanged) {
|
||||
if (visible) {
|
||||
this.searchBox.focus();
|
||||
this.searchBox.setSelection(new Range(1, 1, 1, this.searchBox.getValue().length + 1));
|
||||
this.searchBox.selectAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -436,8 +364,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
layout(dimension: Dimension): void {
|
||||
toggleClass(this.root, 'narrow', dimension.width <= 300);
|
||||
this.searchBox.layout({ height: 20, width: dimension.width - 34 });
|
||||
this.placeholderText.style.width = '' + (dimension.width - 30) + 'px';
|
||||
|
||||
super.layout(new Dimension(dimension.width, dimension.height - 38));
|
||||
}
|
||||
|
||||
|
@ -493,7 +419,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
event.immediate = true;
|
||||
|
||||
this.searchBox.setValue(value);
|
||||
this.searchBox.setPosition(new Position(1, value.length + 1));
|
||||
}
|
||||
|
||||
private triggerSearch(immediate = false): void {
|
||||
|
@ -501,7 +426,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
}
|
||||
|
||||
private normalizedQuery(): string {
|
||||
return (this.searchBox.getValue() || '').replace(/@category/g, 'category').replace(/@tag:/g, 'tag:').replace(/@ext:/g, 'ext:');
|
||||
return this.searchBox.getValue().replace(/@category/g, 'category').replace(/@tag:/g, 'tag:').replace(/@ext:/g, 'ext:');
|
||||
}
|
||||
|
||||
private doSearch(): TPromise<any> {
|
||||
|
@ -539,16 +464,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
return this.instantiationService.createInstance(viewDescriptor.ctor, options) as ViewletPanel;
|
||||
}
|
||||
|
||||
private autoComplete(query: string, position: number): { fullText: string, overwrite: number }[] {
|
||||
let wordStart = query.lastIndexOf(' ', position - 1) + 1;
|
||||
let alreadyTypedCount = position - wordStart - 1;
|
||||
|
||||
// dont show autosuggestions if the user has typed something, but hasn't used the trigger character
|
||||
if (alreadyTypedCount > 0 && query[wordStart] !== '@') { return []; }
|
||||
|
||||
return Query.autocompletions(query).map(replacement => ({ fullText: replacement, overwrite: alreadyTypedCount }));
|
||||
}
|
||||
|
||||
private count(): number {
|
||||
return this.panels.reduce((count, view) => (<ExtensionsListView>view).count() + count, 0);
|
||||
}
|
||||
|
@ -690,18 +605,4 @@ export class MaliciousExtensionChecker implements IWorkbenchContribution {
|
|||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
}
|
||||
|
||||
function mixinHTMLInputStyleOptions(config: IEditorOptions, ariaLabel?: string): IEditorOptions {
|
||||
config.fontSize = 13;
|
||||
config.lineHeight = 22;
|
||||
config.wordWrap = 'off';
|
||||
config.scrollbar.vertical = 'hidden';
|
||||
config.ariaLabel = ariaLabel || '';
|
||||
config.renderIndentGuides = false;
|
||||
config.cursorWidth = 1;
|
||||
config.snippetSuggestions = 'none';
|
||||
config.suggest = { filterGraceful: false };
|
||||
config.fontFamily = ' -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Ubuntu", "Droid Sans", sans-serif';
|
||||
return config;
|
||||
}
|
||||
}
|
|
@ -202,32 +202,6 @@
|
|||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.extensions-viewlet .header .monaco-container {
|
||||
padding: 3px 4px 5px;
|
||||
}
|
||||
|
||||
.extensions-viewlet .header .monaco-container .suggest-widget {
|
||||
width: 275px;
|
||||
}
|
||||
|
||||
.extensions-viewlet .header .monaco-container .monaco-editor-background,
|
||||
.extensions-viewlet .header .monaco-container .monaco-editor,
|
||||
.extensions-viewlet .header .monaco-container .mtk1 {
|
||||
/* allow the embedded monaco to be styled from the outer context */
|
||||
background-color: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.extensions-viewlet .header .search-placeholder {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
pointer-events: none;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .bookmark,
|
||||
.vs-dark .extensions-viewlet > .extensions .monaco-list-row.disabled > .bookmark,
|
||||
.vs .extensions-viewlet > .extensions .monaco-list-row.disabled > .extension > .icon,
|
||||
|
|
|
@ -142,10 +142,10 @@ suite('Extension query', () => {
|
|||
});
|
||||
|
||||
test('autocomplete', () => {
|
||||
Query.autocompletions('@sort:in').some(x => x === '@sort:installs ');
|
||||
Query.autocompletions('@sort:installs').every(x => x !== '@sort:rating ');
|
||||
Query.suggestions('@sort:in').some(x => x === '@sort:installs ');
|
||||
Query.suggestions('@sort:installs').every(x => x !== '@sort:rating ');
|
||||
|
||||
Query.autocompletions('@category:blah').some(x => x === '@category:"extension packs" ');
|
||||
Query.autocompletions('@category:"extension packs"').every(x => x !== '@category:formatters ');
|
||||
Query.suggestions('@category:blah').some(x => x === '@category:"extension packs" ');
|
||||
Query.suggestions('@category:"extension packs"').every(x => x !== '@category:formatters ');
|
||||
});
|
||||
});
|
|
@ -39,24 +39,6 @@
|
|||
margin-right: 7px;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-header > .search-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-header .search-container > .settings-search-input {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-header .search-container > .settings-search-input > .monaco-inputbox {
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-header .search-container .settings-search-input > .monaco-inputbox .input {
|
||||
font-size: 14px;
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-header > .settings-header-controls {
|
||||
height: 32px;
|
||||
display: flex;
|
||||
|
|
|
@ -32,7 +32,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
|
|||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorOptions, IEditor } from 'vs/workbench/common/editor';
|
||||
import { PreferencesEditor } from 'vs/workbench/parts/preferences/browser/preferencesEditor';
|
||||
import { SearchWidget, SettingsTarget, SettingsTargetsWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
|
||||
import { SettingsTarget, SettingsTargetsWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
|
||||
import { commonlyUsedData, tocData } from 'vs/workbench/parts/preferences/browser/settingsLayout';
|
||||
import { ISettingsEditorViewState, MODIFIED_SETTING_TAG, ONLINE_SERVICES_SETTING_TAG, resolveExtensionsSettings, resolveSettingsTree, SearchResultIdx, SearchResultModel, SettingsRenderer, SettingsTree, SettingsTreeElement, SettingsTreeGroupElement, SettingsTreeModel, SettingsTreeSettingElement } from 'vs/workbench/parts/preferences/browser/settingsTree';
|
||||
import { TOCRenderer, TOCTree, TOCTreeModel } from 'vs/workbench/parts/preferences/browser/tocTree';
|
||||
|
@ -40,6 +40,8 @@ import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW
|
|||
import { IPreferencesService, ISearchResult, ISettingsEditorModel } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput';
|
||||
import { DefaultSettingsEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels';
|
||||
import { SuggestEnabledInput } from 'vs/workbench/parts/codeEditor/browser/suggestEnabledInput';
|
||||
import { IEditorGroup } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
|
||||
const $ = DOM.$;
|
||||
|
||||
|
@ -51,7 +53,7 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
|
||||
private rootElement: HTMLElement;
|
||||
private headerContainer: HTMLElement;
|
||||
private searchWidget: SearchWidget;
|
||||
private searchWidget: SuggestEnabledInput;
|
||||
private settingsTargetsWidget: SettingsTargetsWidget;
|
||||
private toolbar: ToolBar;
|
||||
|
||||
|
@ -121,6 +123,7 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
|
||||
this.createHeader(this.rootElement);
|
||||
this.createBody(this.rootElement);
|
||||
this.updateStyles();
|
||||
}
|
||||
|
||||
setInput(input: SettingsEditor2Input, options: EditorOptions, token: CancellationToken): Thenable<void> {
|
||||
|
@ -138,9 +141,12 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
}
|
||||
|
||||
layout(dimension: DOM.Dimension): void {
|
||||
this.searchWidget.layout(dimension);
|
||||
this.layoutTrees(dimension);
|
||||
|
||||
let innerWidth = dimension.width - 24 * 2; // 24px padding on left and right
|
||||
let monacoWidth = (innerWidth > 1000 ? 1000 : innerWidth - 10);
|
||||
this.searchWidget.layout({ height: 20, width: monacoWidth });
|
||||
|
||||
DOM.toggleClass(this.rootElement, 'narrow', dimension.width < 600);
|
||||
|
||||
this.delayRefreshOnLayout.trigger(() => this.refreshTreeAndMaintainFocus());
|
||||
|
@ -162,7 +168,7 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
}
|
||||
|
||||
clearSearchResults(): void {
|
||||
this.searchWidget.clear();
|
||||
this.searchWidget.setValue('');
|
||||
}
|
||||
|
||||
search(text: string): void {
|
||||
|
@ -184,13 +190,20 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
previewTextLabel.textContent = localize('previewLabel', "This is a preview of our new settings editor");
|
||||
|
||||
const searchContainer = DOM.append(this.headerContainer, $('.search-container'));
|
||||
this.searchWidget = this._register(this.instantiationService.createInstance(SearchWidget, searchContainer, {
|
||||
ariaLabel: localize('SearchSettings.AriaLabel', "Search settings"),
|
||||
placeholder: localize('SearchSettings.Placeholder', "Search settings"),
|
||||
focusKey: this.searchFocusContextKey,
|
||||
ariaLive: 'assertive'
|
||||
}));
|
||||
this._register(this.searchWidget.onDidChange(() => this.onSearchInputChanged()));
|
||||
|
||||
let searchBoxLabel = localize('SearchSettings.AriaLabel', "Search settings");
|
||||
this.searchWidget = this._register(this.instantiationService.createInstance(SuggestEnabledInput, `${SettingsEditor2.ID}.searchbox`, searchContainer, {
|
||||
triggerCharacters: ['@'],
|
||||
provideResults: (query: string) => {
|
||||
return ['@modified', '@tag:usesOnlineServices'].filter(tag => query.indexOf(tag) === -1).map(tag => tag + ' ');
|
||||
}
|
||||
}, searchBoxLabel, 'settingseditor:searchinput', {
|
||||
placeholderText: searchBoxLabel,
|
||||
focusContextKey: this.searchFocusContextKey,
|
||||
// TODO: Aria-live
|
||||
}));
|
||||
|
||||
this._register(this.searchWidget.onInputDidChange(() => this.onSearchInputChanged()));
|
||||
|
||||
const headerControlsContainer = DOM.append(this.headerContainer, $('.settings-header-controls'));
|
||||
const targetWidgetContainer = DOM.append(headerControlsContainer, $('.settings-target-container'));
|
||||
|
@ -818,6 +831,20 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
|
||||
this.settingsTreeRenderer.updateWidth(dimension.width);
|
||||
}
|
||||
|
||||
public updateStyles(): void {
|
||||
super.updateStyles();
|
||||
this.searchWidget.updateStyles();
|
||||
}
|
||||
|
||||
setVisible(visible: boolean, group?: IEditorGroup): TPromise<void> {
|
||||
if (visible) {
|
||||
this.searchWidget.focus();
|
||||
this.searchWidget.selectAll();
|
||||
}
|
||||
|
||||
return TPromise.as(super.setVisible(visible, group));
|
||||
}
|
||||
}
|
||||
|
||||
interface ISettingsToolbarContext {
|
||||
|
|
|
@ -35,6 +35,7 @@ import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
|||
import { PreferencesSearchService } from 'vs/workbench/parts/preferences/electron-browser/preferencesSearch';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { Command } from 'vs/editor/browser/editorExtensions';
|
||||
import { Context as SuggestContext } from 'vs/editor/contrib/suggest/suggest';
|
||||
|
||||
registerSingleton(IPreferencesSearchService, PreferencesSearchService);
|
||||
|
||||
|
@ -384,14 +385,14 @@ class FocusSettingsFileEditorCommand extends SettingsCommand {
|
|||
}
|
||||
const focusSettingsFileEditorCommand = new FocusSettingsFileEditorCommand({
|
||||
id: SETTINGS_EDITOR_COMMAND_FOCUS_FILE,
|
||||
precondition: CONTEXT_SETTINGS_SEARCH_FOCUS,
|
||||
precondition: ContextKeyExpr.and(CONTEXT_SETTINGS_SEARCH_FOCUS, SuggestContext.Visible.toNegated()),
|
||||
kbOpts: { primary: KeyCode.DownArrow, weight: KeybindingWeight.EditorContrib }
|
||||
});
|
||||
focusSettingsFileEditorCommand.register();
|
||||
|
||||
const focusSettingsFromSearchCommand = new FocusSettingsFileEditorCommand({
|
||||
id: SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH,
|
||||
precondition: CONTEXT_SETTINGS_SEARCH_FOCUS,
|
||||
precondition: ContextKeyExpr.and(CONTEXT_SETTINGS_SEARCH_FOCUS, SuggestContext.Visible.toNegated()),
|
||||
kbOpts: { primary: KeyCode.DownArrow, weight: KeybindingWeight.WorkbenchContrib }
|
||||
});
|
||||
focusSettingsFromSearchCommand.register();
|
||||
|
|
Loading…
Reference in a new issue