mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-30 08:40:29 -04:00
Initial VS Code 1.19 source merge (#571)
* Initial 1.19 xcopy * Fix yarn build * Fix numerous build breaks * Next batch of build break fixes * More build break fixes * Runtime breaks * Additional post merge fixes * Fix windows setup file * Fix test failures. * Update license header blocks to refer to source eula
This commit is contained in:
@@ -82,11 +82,6 @@ class KeybindingInputWidget extends Widget {
|
||||
this._chordPart = null;
|
||||
}
|
||||
|
||||
public setAcceptChords(acceptChords: boolean) {
|
||||
this._acceptChords = acceptChords;
|
||||
this._chordPart = null;
|
||||
}
|
||||
|
||||
private _onKeyDown(keyboardEvent: IKeyboardEvent): void {
|
||||
keyboardEvent.preventDefault();
|
||||
keyboardEvent.stopPropagation();
|
||||
@@ -137,8 +132,8 @@ class KeybindingInputWidget extends Widget {
|
||||
|
||||
export class DefineKeybindingWidget extends Widget {
|
||||
|
||||
private static WIDTH = 400;
|
||||
private static HEIGHT = 90;
|
||||
private static readonly WIDTH = 400;
|
||||
private static readonly HEIGHT = 90;
|
||||
|
||||
private _domNode: FastDomNode<HTMLElement>;
|
||||
private _keybindingInputWidget: KeybindingInputWidget;
|
||||
@@ -152,7 +147,6 @@ export class DefineKeybindingWidget extends Widget {
|
||||
|
||||
constructor(
|
||||
parent: HTMLElement,
|
||||
@IKeybindingService private keybindingService: IKeybindingService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IThemeService private themeService: IThemeService
|
||||
) {
|
||||
@@ -209,7 +203,7 @@ export class DefineKeybindingWidget extends Widget {
|
||||
this._domNode.setClassName('defineKeybindingWidget');
|
||||
this._domNode.setWidth(DefineKeybindingWidget.WIDTH);
|
||||
this._domNode.setHeight(DefineKeybindingWidget.HEIGHT);
|
||||
dom.append(this._domNode.domNode, dom.$('.message', null, nls.localize('defineKeybinding.initial', "Press desired key combination and ENTER. ESCAPE to cancel.")));
|
||||
dom.append(this._domNode.domNode, dom.$('.message', null, nls.localize('defineKeybinding.initial', "Press desired key combination and then press ENTER.")));
|
||||
|
||||
this._register(attachStylerCallback(this.themeService, { editorWidgetBackground, widgetShadow }, colors => {
|
||||
this._domNode.domNode.style.backgroundColor = colors.editorWidgetBackground;
|
||||
@@ -257,7 +251,7 @@ export class DefineKeybindingWidget extends Widget {
|
||||
|
||||
export class DefineKeybindingOverlayWidget extends Disposable implements IOverlayWidget {
|
||||
|
||||
private static ID = 'editor.contrib.defineKeybindingWidget';
|
||||
private static readonly ID = 'editor.contrib.defineKeybindingWidget';
|
||||
|
||||
private readonly _widget: DefineKeybindingWidget;
|
||||
|
||||
@@ -295,4 +289,4 @@ export class DefineKeybindingOverlayWidget extends Disposable implements IOverla
|
||||
this._widget.layout(new Dimension(layoutInfo.width, layoutInfo.height));
|
||||
return this._widget.define();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLa
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorInput } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { KeybindingsEditorModel, IKeybindingItemEntry, IListEntry, KEYBINDING_ENTRY_TEMPLATE_ID, KEYBINDING_HEADER_TEMPLATE_ID } from 'vs/workbench/parts/preferences/common/keybindingsEditorModel';
|
||||
@@ -30,17 +30,17 @@ import {
|
||||
} from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IKeybindingEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
|
||||
import { IListService } from 'vs/platform/list/browser/listService';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IDelegate, IRenderer, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IChoiceService, IMessageService, Severity } from 'vs/platform/message/common/message';
|
||||
import { IMessageService, Severity } from 'vs/platform/message/common/message';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode, ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
import { listHighlightForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions';
|
||||
import { WorkbenchList, IListService } from 'vs/platform/list/browser/listService';
|
||||
|
||||
let $ = DOM.$;
|
||||
|
||||
@@ -49,7 +49,7 @@ export class KeybindingsEditorInput extends EditorInput {
|
||||
public static ID: string = 'workbench.input.keybindings';
|
||||
public readonly keybindingsModel: KeybindingsEditorModel;
|
||||
|
||||
constructor( @IInstantiationService private instantiationService: IInstantiationService) {
|
||||
constructor( @IInstantiationService instantiationService: IInstantiationService) {
|
||||
super();
|
||||
this.keybindingsModel = instantiationService.createInstance(KeybindingsEditorModel, OS);
|
||||
}
|
||||
@@ -106,7 +106,6 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
|
||||
@IKeybindingEditingService private keybindingEditingService: IKeybindingEditingService,
|
||||
@IListService private listService: IListService,
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@IChoiceService private choiceService: IChoiceService,
|
||||
@IMessageService private messageService: IMessageService,
|
||||
@IClipboardService private clipboardService: IClipboardService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@@ -132,23 +131,22 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
|
||||
this.createBody(keybindingsEditorElement);
|
||||
|
||||
const focusTracker = this._register(DOM.trackFocus(parentElement));
|
||||
this._register(focusTracker.addFocusListener(() => this.keybindingsEditorContextKey.set(true)));
|
||||
this._register(focusTracker.addBlurListener(() => this.keybindingsEditorContextKey.reset()));
|
||||
this._register(focusTracker.onDidFocus(() => this.keybindingsEditorContextKey.set(true)));
|
||||
this._register(focusTracker.onDidBlur(() => this.keybindingsEditorContextKey.reset()));
|
||||
}
|
||||
|
||||
setInput(input: KeybindingsEditorInput): TPromise<void> {
|
||||
setInput(input: KeybindingsEditorInput, options: EditorOptions): TPromise<void> {
|
||||
const oldInput = this.input;
|
||||
return super.setInput(input)
|
||||
.then(() => {
|
||||
if (!input.matches(oldInput)) {
|
||||
this.render();
|
||||
this.render(options && options.preserveFocus);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
clearInput(): void {
|
||||
super.clearInput();
|
||||
this.searchWidget.clear();
|
||||
this.keybindingsEditorContextKey.reset();
|
||||
this.keybindingFocusContextKey.reset();
|
||||
}
|
||||
@@ -237,8 +235,8 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
|
||||
this.selectEntry(keybinding);
|
||||
this.reportKeybindingAction(KEYBINDINGS_EDITOR_COMMAND_COPY, keybinding.keybindingItem.command, keybinding.keybindingItem.keybinding);
|
||||
const userFriendlyKeybinding: IUserFriendlyKeybinding = {
|
||||
command: keybinding.keybindingItem.command,
|
||||
key: keybinding.keybindingItem.keybinding ? keybinding.keybindingItem.keybinding.getUserSettingsLabel() : ''
|
||||
key: keybinding.keybindingItem.keybinding ? keybinding.keybindingItem.keybinding.getUserSettingsLabel() : '',
|
||||
command: keybinding.keybindingItem.command
|
||||
};
|
||||
if (keybinding.keybindingItem.when) {
|
||||
userFriendlyKeybinding.when = keybinding.keybindingItem.when;
|
||||
@@ -328,28 +326,41 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
|
||||
private createList(parent: HTMLElement): void {
|
||||
this.keybindingsListContainer = DOM.append(parent, $('.keybindings-list-container'));
|
||||
|
||||
this.keybindingsList = this._register(new List<IListEntry>(this.keybindingsListContainer, new Delegate(), [new KeybindingHeaderRenderer(), new KeybindingItemRenderer(this, this.keybindingsService)],
|
||||
{ identityProvider: e => e.id, keyboardSupport: false, mouseSupport: true, ariaLabel: localize('keybindingsLabel', "Keybindings") }));
|
||||
this.keybindingsList = this._register(new WorkbenchList<IListEntry>(this.keybindingsListContainer, new Delegate(), [new KeybindingHeaderRenderer(), new KeybindingItemRenderer(this, this.keybindingsService)],
|
||||
{ identityProvider: e => e.id, keyboardSupport: false, mouseSupport: true, ariaLabel: localize('keybindingsLabel', "Keybindings") }, this.contextKeyService, this.listService, this.themeService));
|
||||
this._register(this.keybindingsList.onContextMenu(e => this.onContextMenu(e)));
|
||||
this._register(this.keybindingsList.onFocusChange(e => this.onFocusChange(e)));
|
||||
this._register(this.keybindingsList.onDOMFocus(() => {
|
||||
this._register(this.keybindingsList.onDidFocus(() => {
|
||||
DOM.addClass(this.keybindingsList.getHTMLElement(), 'focused');
|
||||
}));
|
||||
this._register(this.keybindingsList.onDOMBlur(() => {
|
||||
this._register(this.keybindingsList.onDidBlur(() => {
|
||||
DOM.removeClass(this.keybindingsList.getHTMLElement(), 'focused');
|
||||
this.keybindingFocusContextKey.reset();
|
||||
}));
|
||||
|
||||
this._register(attachListStyler(this.keybindingsList, this.themeService));
|
||||
this._register(this.listService.register(this.keybindingsList));
|
||||
this._register(this.keybindingsList.onKeyUp(e => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
if (event.keyCode === KeyCode.Enter) {
|
||||
const keybindingEntry = this.activeKeybindingEntry;
|
||||
if (keybindingEntry) {
|
||||
this.defineKeybinding(this.activeKeybindingEntry);
|
||||
}
|
||||
e.stopPropagation();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private render(): TPromise<any> {
|
||||
private render(preserveFocus?: boolean): TPromise<any> {
|
||||
if (this.input) {
|
||||
return this.input.resolve()
|
||||
.then((keybindingsModel: KeybindingsEditorModel) => this.keybindingsEditorModel = keybindingsModel)
|
||||
.then(() => this.keybindingsEditorModel.resolve())
|
||||
.then(() => this.renderKeybindingsEntries(false));
|
||||
.then(() => {
|
||||
const editorActionsLabels: { [id: string]: string; } = EditorExtensionsRegistry.getEditorActions().reduce((editorActions, editorAction) => {
|
||||
editorActions[editorAction.id] = editorAction.label;
|
||||
return editorActions;
|
||||
}, {});
|
||||
return this.keybindingsEditorModel.resolve(editorActionsLabels);
|
||||
})
|
||||
.then(() => this.renderKeybindingsEntries(false, preserveFocus));
|
||||
}
|
||||
return TPromise.as(null);
|
||||
}
|
||||
@@ -359,7 +370,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
|
||||
this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(this.searchWidget.getValue()));
|
||||
}
|
||||
|
||||
private renderKeybindingsEntries(reset: boolean): void {
|
||||
private renderKeybindingsEntries(reset: boolean, preserveFocus?: boolean): void {
|
||||
if (this.keybindingsEditorModel) {
|
||||
const filter = this.searchWidget.getValue();
|
||||
const keybindingsEntries: IKeybindingItemEntry[] = this.keybindingsEditorModel.fetch(filter, this.sortByPrecedence.checked);
|
||||
@@ -384,7 +395,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
|
||||
this.unAssignedKeybindingItemToRevealAndFocus = null;
|
||||
} else if (currentSelectedIndex !== -1 && currentSelectedIndex < this.listEntries.length) {
|
||||
this.selectEntry(currentSelectedIndex);
|
||||
} else if (this.editorService.getActiveEditor() === this) {
|
||||
} else if (this.editorService.getActiveEditor() === this && !preserveFocus) {
|
||||
this.focus();
|
||||
}
|
||||
}
|
||||
@@ -737,7 +748,7 @@ class CommandColumn extends Column {
|
||||
commandLabel.set(keybindingItem.command, keybindingItemEntry.commandIdMatches);
|
||||
}
|
||||
if (commandLabel) {
|
||||
commandLabel.element.title = keybindingItem.command;
|
||||
commandLabel.element.title = keybindingItem.commandLabel ? localize('title', "{0} ({1})", keybindingItem.commandLabel, keybindingItem.command) : keybindingItem.command;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,4 +832,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
||||
if (listHighlightForegroundColor) {
|
||||
collector.addRule(`.keybindings-editor > .keybindings-body > .keybindings-list-container .monaco-list-row > .column .highlight { color: ${listHighlightForegroundColor}; }`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,10 +15,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { ServicesAccessor, registerEditorCommand, EditorCommand } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { registerEditorContribution, ServicesAccessor, registerEditorCommand, EditorCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2';
|
||||
import { SmartSnippetInserter } from 'vs/workbench/parts/preferences/common/smartSnippetInserter';
|
||||
import { DefineKeybindingOverlayWidget } from 'vs/workbench/parts/preferences/browser/keybindingWidgets';
|
||||
import { FloatingClickWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
|
||||
@@ -35,12 +34,11 @@ const NLS_KB_LAYOUT_ERROR_MESSAGE = nls.localize('defineKeybinding.kbLayoutError
|
||||
|
||||
const INTERESTING_FILE = /keybindings\.json$/;
|
||||
|
||||
@editorContribution
|
||||
export class DefineKeybindingController extends Disposable implements editorCommon.IEditorContribution {
|
||||
|
||||
private static ID = 'editor.contrib.defineKeybinding';
|
||||
private static readonly ID = 'editor.contrib.defineKeybinding';
|
||||
|
||||
public static get(editor: editorCommon.ICommonCodeEditor): DefineKeybindingController {
|
||||
public static get(editor: ICodeEditor): DefineKeybindingController {
|
||||
return editor.getContribution<DefineKeybindingController>(DefineKeybindingController.ID);
|
||||
}
|
||||
|
||||
@@ -371,7 +369,7 @@ class DefineKeybindingCommand extends EditorCommand {
|
||||
});
|
||||
}
|
||||
|
||||
public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void {
|
||||
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
if (!isInterestingEditorModel(editor) || editor.getConfiguration().readOnly) {
|
||||
return;
|
||||
}
|
||||
@@ -382,7 +380,7 @@ class DefineKeybindingCommand extends EditorCommand {
|
||||
}
|
||||
}
|
||||
|
||||
function isInterestingEditorModel(editor: editorCommon.ICommonCodeEditor): boolean {
|
||||
function isInterestingEditorModel(editor: ICodeEditor): boolean {
|
||||
let model = editor.getModel();
|
||||
if (!model) {
|
||||
return false;
|
||||
@@ -391,4 +389,5 @@ function isInterestingEditorModel(editor: editorCommon.ICommonCodeEditor): boole
|
||||
return INTERESTING_FILE.test(url);
|
||||
}
|
||||
|
||||
registerEditorContribution(DefineKeybindingController);
|
||||
registerEditorCommand(new DefineKeybindingCommand());
|
||||
|
||||
@@ -22,42 +22,79 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.settings-targets-widget {
|
||||
flex-wrap: wrap;
|
||||
margin: 4px 0 4px 18px;
|
||||
display: flex;
|
||||
border-radius: 4px;
|
||||
padding: 0 8px;
|
||||
cursor: pointer;
|
||||
.preferences-editor > .preferences-editors-container.side-by-side-preferences-editor .preferences-header-container {
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.settings-targets-widget > .settings-target {
|
||||
font-size: 11px;
|
||||
padding: 2px 4px 0 0;
|
||||
white-space: nowrap;
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item.disabled {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item {
|
||||
max-width: 300px;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.settings-targets-widget > .settings-target > .settings-target-label {
|
||||
.default-preferences-editor-container > .preferences-header-container > .default-preferences-header,
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label {
|
||||
text-transform: uppercase;
|
||||
font-size: 11px;
|
||||
margin-left: 33px;
|
||||
margin-right: 5px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.settings-targets-widget > .settings-target > .settings-target-details {
|
||||
.settings-tabs-widget > .monaco-action-bar .actions-container {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item {
|
||||
padding: 3px 0px;
|
||||
}
|
||||
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-title {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-details {
|
||||
text-transform: none;
|
||||
margin-left: 0.5em;
|
||||
font-size: 10px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.settings-targets-widget > .settings-target > .settings-target-details.empty {
|
||||
margin-left: 0;
|
||||
.settings-tabs-widget .monaco-action-bar .action-item .dropdown-icon {
|
||||
padding-left: 0.3em;
|
||||
padding-top: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.settings-targets-widget > .settings-target-dropdown-icon {
|
||||
padding-left: 0.5em;
|
||||
padding-top: 4px;
|
||||
font-size: 12px;
|
||||
.settings-tabs-widget .monaco-action-bar .action-item .dropdown-icon.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vs .settings-tabs-widget > .monaco-action-bar .action-item .action-label {
|
||||
color: #424242;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.vs-dark .settings-tabs-widget > .monaco-action-bar .action-item .action-label {
|
||||
color: #e7e7e7;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.hc-black .settings-tabs-widget > .monaco-action-bar .action-item .action-label {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item:hover .action-label,
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label.checked {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.preferences-header > .settings-header-widget {
|
||||
@@ -89,20 +126,19 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle {
|
||||
.settings-header-widget > .settings-search-controls > .prefs-natural-language-search-toggle {
|
||||
margin: 5px 3px 5px 0px;
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle.hidden {
|
||||
.settings-header-widget > .settings-search-controls > .prefs-natural-language-search-toggle.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vs .settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle {
|
||||
background: url('regex.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .settings-header-widget > .settings-search-controls > .prefs-fuzzy-search-toggle {
|
||||
background: url('regex-dark.svg') center center no-repeat;
|
||||
.settings-header-widget > .settings-search-controls > .prefs-natural-language-search-toggle > .octicon {
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.settings-header-widget > .settings-search-container {
|
||||
@@ -155,13 +191,13 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.monaco-editor .settings-header-widget .title-container .settings-header-fuzzy-link {
|
||||
.monaco-editor .settings-header-widget .title-container .settings-header-natural-language-link {
|
||||
margin-left: 4px;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.monaco-editor .settings-header-widget .title-container .settings-header-fuzzy-link.hidden {
|
||||
.monaco-editor .settings-header-widget .title-container .settings-header-natural-language-link.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
||||
import { EditorInput, IEditorInputFactory, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { DefaultPreferencesEditorInput, PreferencesEditor, PreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor';
|
||||
import { KeybindingsEditor, KeybindingsEditorInput } from 'vs/workbench/parts/preferences/browser/keybindingsEditor';
|
||||
import { OpenGlobalSettingsAction, OpenGlobalKeybindingsAction, OpenGlobalKeybindingsFileAction, OpenWorkspaceSettingsAction, OpenFolderSettingsAction, ConfigureLanguageBasedSettingsAction, OPEN_FOLDER_SETTINGS_COMMAND } from 'vs/workbench/parts/preferences/browser/preferencesActions';
|
||||
import {
|
||||
IPreferencesService, IKeybindingsEditor, CONTEXT_KEYBINDING_FOCUS, CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_SEARCH,
|
||||
KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SHOW_CONFLICTS, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS
|
||||
} from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { PreferencesService } from 'vs/workbench/parts/preferences/browser/preferencesService';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { PreferencesContribution } from 'vs/workbench/parts/preferences/common/preferencesContribution';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
|
||||
registerSingleton(IPreferencesService, PreferencesService);
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
new EditorDescriptor(
|
||||
PreferencesEditor,
|
||||
PreferencesEditor.ID,
|
||||
nls.localize('defaultPreferencesEditor', "Default Preferences Editor")
|
||||
),
|
||||
[
|
||||
new SyncDescriptor(PreferencesEditorInput)
|
||||
]
|
||||
);
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
new EditorDescriptor(
|
||||
KeybindingsEditor,
|
||||
KeybindingsEditor.ID,
|
||||
nls.localize('keybindingsEditor', "Keybindings Editor")
|
||||
),
|
||||
[
|
||||
new SyncDescriptor(KeybindingsEditorInput)
|
||||
]
|
||||
);
|
||||
|
||||
interface ISerializedPreferencesEditorInput {
|
||||
name: string;
|
||||
description: string;
|
||||
|
||||
detailsSerialized: string;
|
||||
masterSerialized: string;
|
||||
|
||||
detailsTypeId: string;
|
||||
masterTypeId: string;
|
||||
}
|
||||
|
||||
// Register Preferences Editor Input Factory
|
||||
class PreferencesEditorInputFactory implements IEditorInputFactory {
|
||||
|
||||
public serialize(editorInput: EditorInput): string {
|
||||
const input = <PreferencesEditorInput>editorInput;
|
||||
|
||||
if (input.details && input.master) {
|
||||
const registry = Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories);
|
||||
const detailsInputFactory = registry.getEditorInputFactory(input.details.getTypeId());
|
||||
const masterInputFactory = registry.getEditorInputFactory(input.master.getTypeId());
|
||||
|
||||
if (detailsInputFactory && masterInputFactory) {
|
||||
const detailsSerialized = detailsInputFactory.serialize(input.details);
|
||||
const masterSerialized = masterInputFactory.serialize(input.master);
|
||||
|
||||
if (detailsSerialized && masterSerialized) {
|
||||
return JSON.stringify(<ISerializedPreferencesEditorInput>{
|
||||
name: input.getName(),
|
||||
description: input.getDescription(),
|
||||
detailsSerialized,
|
||||
masterSerialized,
|
||||
detailsTypeId: input.details.getTypeId(),
|
||||
masterTypeId: input.master.getTypeId()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput {
|
||||
const deserialized: ISerializedPreferencesEditorInput = JSON.parse(serializedEditorInput);
|
||||
|
||||
const registry = Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories);
|
||||
const detailsInputFactory = registry.getEditorInputFactory(deserialized.detailsTypeId);
|
||||
const masterInputFactory = registry.getEditorInputFactory(deserialized.masterTypeId);
|
||||
|
||||
if (detailsInputFactory && masterInputFactory) {
|
||||
const detailsInput = detailsInputFactory.deserialize(instantiationService, deserialized.detailsSerialized);
|
||||
const masterInput = masterInputFactory.deserialize(instantiationService, deserialized.masterSerialized);
|
||||
|
||||
if (detailsInput && masterInput) {
|
||||
return new PreferencesEditorInput(deserialized.name, deserialized.description, detailsInput, masterInput);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class KeybindingsEditorInputFactory implements IEditorInputFactory {
|
||||
|
||||
public serialize(editorInput: EditorInput): string {
|
||||
const input = <KeybindingsEditorInput>editorInput;
|
||||
return JSON.stringify({
|
||||
name: input.getName(),
|
||||
typeId: input.getTypeId()
|
||||
});
|
||||
}
|
||||
|
||||
public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput {
|
||||
return instantiationService.createInstance(KeybindingsEditorInput);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface ISerializedDefaultPreferencesEditorInput {
|
||||
resource: string;
|
||||
}
|
||||
|
||||
// Register Default Preferences Editor Input Factory
|
||||
class DefaultPreferencesEditorInputFactory implements IEditorInputFactory {
|
||||
|
||||
public serialize(editorInput: EditorInput): string {
|
||||
const input = <DefaultPreferencesEditorInput>editorInput;
|
||||
|
||||
const serialized: ISerializedDefaultPreferencesEditorInput = { resource: input.getResource().toString() };
|
||||
|
||||
return JSON.stringify(serialized);
|
||||
}
|
||||
|
||||
public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput {
|
||||
const deserialized: ISerializedDefaultPreferencesEditorInput = JSON.parse(serializedEditorInput);
|
||||
|
||||
return instantiationService.createInstance(DefaultPreferencesEditorInput, URI.parse(deserialized.resource));
|
||||
}
|
||||
}
|
||||
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(PreferencesEditorInput.ID, PreferencesEditorInputFactory);
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(DefaultPreferencesEditorInput.ID, DefaultPreferencesEditorInputFactory);
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(KeybindingsEditorInput.ID, KeybindingsEditorInputFactory);
|
||||
|
||||
// Contribute Global Actions
|
||||
const category = nls.localize('preferences', "Preferences");
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenGlobalSettingsAction, OpenGlobalSettingsAction.ID, OpenGlobalSettingsAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_COMMA }), 'Preferences: Open User Settings', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceSettingsAction, OpenWorkspaceSettingsAction.ID, OpenWorkspaceSettingsAction.LABEL), 'Preferences: Open Workspace Settings', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderSettingsAction, OpenFolderSettingsAction.ID, OpenFolderSettingsAction.LABEL), 'Preferences: Open Folder Settings', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenGlobalKeybindingsAction, OpenGlobalKeybindingsAction.ID, OpenGlobalKeybindingsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_S) }), 'Preferences: Open Keyboard Shortcuts', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenGlobalKeybindingsFileAction, OpenGlobalKeybindingsFileAction.ID, OpenGlobalKeybindingsFileAction.LABEL, { primary: null }), 'Preferences: Open Keyboard Shortcuts File', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureLanguageBasedSettingsAction, ConfigureLanguageBasedSettingsAction.ID, ConfigureLanguageBasedSettingsAction.LABEL), 'Preferences: Configure Language Specific Settings...', category);
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: KEYBINDINGS_EDITOR_COMMAND_DEFINE,
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDING_FOCUS),
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_K),
|
||||
handler: (accessor, args: any) => {
|
||||
const editor = accessor.get(IWorkbenchEditorService).getActiveEditor() as IKeybindingsEditor;
|
||||
editor.defineKeybinding(editor.activeKeybindingEntry);
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: KEYBINDINGS_EDITOR_COMMAND_REMOVE,
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDING_FOCUS),
|
||||
primary: KeyCode.Delete,
|
||||
mac: {
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.Backspace)
|
||||
},
|
||||
handler: (accessor, args: any) => {
|
||||
const editor = accessor.get(IWorkbenchEditorService).getActiveEditor() as IKeybindingsEditor;
|
||||
editor.removeKeybinding(editor.activeKeybindingEntry);
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: KEYBINDINGS_EDITOR_COMMAND_RESET,
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDING_FOCUS),
|
||||
primary: null,
|
||||
handler: (accessor, args: any) => {
|
||||
const editor = accessor.get(IWorkbenchEditorService).getActiveEditor() as IKeybindingsEditor;
|
||||
editor.resetKeybinding(editor.activeKeybindingEntry);
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: KEYBINDINGS_EDITOR_COMMAND_SEARCH,
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDING_FOCUS),
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_F,
|
||||
handler: (accessor, args: any) => (accessor.get(IWorkbenchEditorService).getActiveEditor() as IKeybindingsEditor).search('')
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: KEYBINDINGS_EDITOR_COMMAND_SHOW_CONFLICTS,
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDING_FOCUS),
|
||||
primary: null,
|
||||
handler: (accessor, args: any) => {
|
||||
const editor = accessor.get(IWorkbenchEditorService).getActiveEditor() as IKeybindingsEditor;
|
||||
editor.showConflicts(editor.activeKeybindingEntry);
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: KEYBINDINGS_EDITOR_COMMAND_COPY,
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDING_FOCUS),
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
|
||||
handler: (accessor, args: any) => {
|
||||
const editor = accessor.get(IWorkbenchEditorService).getActiveEditor() as IKeybindingsEditor;
|
||||
editor.copyKeybinding(editor.activeKeybindingEntry);
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS,
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS),
|
||||
primary: KeyCode.DownArrow,
|
||||
handler: (accessor, args: any) => {
|
||||
const editor = accessor.get(IWorkbenchEditorService).getActiveEditor() as IKeybindingsEditor;
|
||||
editor.focusKeybindings();
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS,
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS),
|
||||
primary: KeyCode.Escape,
|
||||
handler: (accessor, args: any) => {
|
||||
const editor = accessor.get(IWorkbenchEditorService).getActiveEditor() as IKeybindingsEditor;
|
||||
editor.clearSearchResults();
|
||||
}
|
||||
});
|
||||
|
||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(PreferencesContribution);
|
||||
|
||||
CommandsRegistry.registerCommand(OPEN_FOLDER_SETTINGS_COMMAND, function (accessor: ServicesAccessor, args?: IWorkspaceFolder) {
|
||||
const preferencesService = accessor.get(IPreferencesService);
|
||||
return preferencesService.openFolderSettings(args.uri);
|
||||
});
|
||||
@@ -16,10 +16,28 @@ import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/p
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { PICK_WORKSPACE_FOLDER_COMMAND } from 'vs/workbench/browser/actions/workspaceActions';
|
||||
|
||||
export class OpenRawDefaultSettingsAction extends Action {
|
||||
|
||||
public static readonly ID = 'workbench.action.openRawDefaultSettings';
|
||||
public static readonly LABEL = nls.localize('openRawDefaultSettings', "Open Raw Default Settings");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IPreferencesService private preferencesService: IPreferencesService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(event?: any): TPromise<any> {
|
||||
return this.preferencesService.openRawDefaultSettings();
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenGlobalSettingsAction extends Action {
|
||||
|
||||
public static ID = 'workbench.action.openGlobalSettings';
|
||||
public static LABEL = nls.localize('openGlobalSettings', "Open User Settings");
|
||||
public static readonly ID = 'workbench.action.openGlobalSettings';
|
||||
public static readonly LABEL = nls.localize('openGlobalSettings', "Open User Settings");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
@@ -36,8 +54,8 @@ export class OpenGlobalSettingsAction extends Action {
|
||||
|
||||
export class OpenGlobalKeybindingsAction extends Action {
|
||||
|
||||
public static ID = 'workbench.action.openGlobalKeybindings';
|
||||
public static LABEL = nls.localize('openGlobalKeybindings', "Open Keyboard Shortcuts");
|
||||
public static readonly ID = 'workbench.action.openGlobalKeybindings';
|
||||
public static readonly LABEL = nls.localize('openGlobalKeybindings', "Open Keyboard Shortcuts");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
@@ -54,8 +72,8 @@ export class OpenGlobalKeybindingsAction extends Action {
|
||||
|
||||
export class OpenGlobalKeybindingsFileAction extends Action {
|
||||
|
||||
public static ID = 'workbench.action.openGlobalKeybindingsFile';
|
||||
public static LABEL = nls.localize('openGlobalKeybindingsFile', "Open Keyboard Shortcuts File");
|
||||
public static readonly ID = 'workbench.action.openGlobalKeybindingsFile';
|
||||
public static readonly LABEL = nls.localize('openGlobalKeybindingsFile', "Open Keyboard Shortcuts File");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
@@ -72,8 +90,8 @@ export class OpenGlobalKeybindingsFileAction extends Action {
|
||||
|
||||
export class OpenWorkspaceSettingsAction extends Action {
|
||||
|
||||
public static ID = 'workbench.action.openWorkspaceSettings';
|
||||
public static LABEL = nls.localize('openWorkspaceSettings', "Open Workspace Settings");
|
||||
public static readonly ID = 'workbench.action.openWorkspaceSettings';
|
||||
public static readonly LABEL = nls.localize('openWorkspaceSettings', "Open Workspace Settings");
|
||||
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
@@ -105,8 +123,8 @@ export class OpenWorkspaceSettingsAction extends Action {
|
||||
export const OPEN_FOLDER_SETTINGS_COMMAND = '_workbench.action.openFolderSettings';
|
||||
export class OpenFolderSettingsAction extends Action {
|
||||
|
||||
public static ID = 'workbench.action.openFolderSettings';
|
||||
public static LABEL = nls.localize('openFolderSettings', "Open Folder Settings");
|
||||
public static readonly ID = 'workbench.action.openFolderSettings';
|
||||
public static readonly LABEL = nls.localize('openFolderSettings', "Open Folder Settings");
|
||||
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
@@ -114,7 +132,6 @@ export class OpenFolderSettingsAction extends Action {
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService,
|
||||
@ICommandService private commandService: ICommandService
|
||||
) {
|
||||
@@ -146,8 +163,8 @@ export class OpenFolderSettingsAction extends Action {
|
||||
|
||||
export class ConfigureLanguageBasedSettingsAction extends Action {
|
||||
|
||||
public static ID = 'workbench.action.configureLanguageBasedSettings';
|
||||
public static LABEL = nls.localize('configureLanguageBasedSettings', "Configure Language Specific Settings...");
|
||||
public static readonly ID = 'workbench.action.configureLanguageBasedSettings';
|
||||
public static readonly LABEL = nls.localize('configureLanguageBasedSettings', "Configure Language Specific Settings...");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
|
||||
@@ -14,6 +14,7 @@ import { ArrayNavigator, INavigator } from 'vs/base/common/iterator';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { SideBySideEditorInput, EditorOptions, EditorInput } from 'vs/workbench/common/editor';
|
||||
import { Scope } from 'vs/workbench/common/memento';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel';
|
||||
import { IEditorControl, Position, Verbosity } from 'vs/platform/editor/common/editor';
|
||||
@@ -23,35 +24,29 @@ import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
import { CodeEditor } from 'vs/editor/browser/codeEditor';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import {
|
||||
IPreferencesService, ISettingsGroup, ISetting, IFilterResult,
|
||||
CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING
|
||||
IPreferencesService, ISettingsGroup, ISetting, IFilterResult, IPreferencesSearchService,
|
||||
CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, IFilterMetadata, IPreferencesSearchModel
|
||||
} from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { SettingsEditorModel, DefaultSettingsEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels';
|
||||
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
|
||||
import { ICodeEditor, IEditorContributionCtor } from 'vs/editor/browser/editorBrowser';
|
||||
import { SearchWidget, SettingsTargetsWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
|
||||
import { PreferencesSearchProvider, PreferencesSearchModel } from 'vs/workbench/parts/preferences/browser/preferencesSearch';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { SearchWidget, SettingsTargetsWidget, SettingsTarget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
|
||||
import { ContextKeyExpr, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Command } from 'vs/editor/common/editorCommonExtensions';
|
||||
import { registerEditorContribution, Command, IEditorContributionCtor } from 'vs/editor/browser/editorExtensions';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { VSash } from 'vs/base/browser/ui/sash/sash';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { IPreferencesRenderer, DefaultSettingsRenderer, UserSettingsRenderer, WorkspaceSettingsRenderer, FolderSettingsRenderer } from 'vs/workbench/parts/preferences/browser/preferencesRenderers';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { getCodeEditor } from 'vs/editor/common/services/codeEditorService';
|
||||
import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
import { FoldingController } from 'vs/editor/contrib/folding/browser/folding';
|
||||
import { FindController } from 'vs/editor/contrib/find/browser/find';
|
||||
import { SelectionHighlighter } from 'vs/editor/contrib/multicursor/common/multicursor';
|
||||
import { FoldingController } from 'vs/editor/contrib/folding/folding';
|
||||
import { FindController } from 'vs/editor/contrib/find/findController';
|
||||
import { SelectionHighlighter } from 'vs/editor/contrib/multicursor/multicursor';
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { attachStylerCallback } from 'vs/platform/theme/common/styler';
|
||||
@@ -62,6 +57,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { MessageController } from 'vs/editor/contrib/message/messageController';
|
||||
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { IHashService } from 'vs/workbench/services/hash/common/hashService';
|
||||
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
|
||||
export class PreferencesEditorInput extends SideBySideEditorInput {
|
||||
public static ID: string = 'workbench.editorinputs.preferencesEditorInput';
|
||||
@@ -70,13 +66,17 @@ export class PreferencesEditorInput extends SideBySideEditorInput {
|
||||
return PreferencesEditorInput.ID;
|
||||
}
|
||||
|
||||
public supportsSplitEditor(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public getTitle(verbosity: Verbosity): string {
|
||||
return this.master.getTitle(verbosity);
|
||||
}
|
||||
}
|
||||
|
||||
export class DefaultPreferencesEditorInput extends ResourceEditorInput {
|
||||
public static ID = 'workbench.editorinputs.defaultpreferences';
|
||||
public static readonly ID = 'workbench.editorinputs.defaultpreferences';
|
||||
constructor(defaultSettingsResource: URI,
|
||||
@ITextModelService textModelResolverService: ITextModelService,
|
||||
@IHashService hashService: IHashService
|
||||
@@ -107,33 +107,32 @@ export class PreferencesEditor extends BaseEditor {
|
||||
private focusSettingsContextKey: IContextKey<boolean>;
|
||||
private headerContainer: HTMLElement;
|
||||
private searchWidget: SearchWidget;
|
||||
private settingsTargetsWidget: SettingsTargetsWidget;
|
||||
private sideBySidePreferencesWidget: SideBySidePreferencesWidget;
|
||||
private preferencesRenderers: PreferencesRenderers;
|
||||
private searchProvider: PreferencesSearchProvider;
|
||||
|
||||
private delayedFilterLogging: Delayer<void>;
|
||||
private filterThrottle: ThrottledDelayer<void>;
|
||||
|
||||
private latestEmptyFilters: string[] = [];
|
||||
private lastFocusedWidget: SearchWidget | SideBySidePreferencesWidget = null;
|
||||
private memento: any;
|
||||
|
||||
constructor(
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@IPreferencesSearchService private preferencesSearchService: IPreferencesSearchService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
) {
|
||||
super(PreferencesEditor.ID, telemetryService, themeService);
|
||||
this.defaultSettingsEditorContextKey = CONTEXT_SETTINGS_EDITOR.bindTo(this.contextKeyService);
|
||||
this.focusSettingsContextKey = CONTEXT_SETTINGS_SEARCH_FOCUS.bindTo(this.contextKeyService);
|
||||
this.delayedFilterLogging = new Delayer<void>(1000);
|
||||
this.searchProvider = this.instantiationService.createInstance(PreferencesSearchProvider);
|
||||
this.filterThrottle = new ThrottledDelayer(200);
|
||||
this.memento = this.getMemento(storageService, Scope.WORKSPACE);
|
||||
}
|
||||
|
||||
public createEditor(parent: Builder): void {
|
||||
@@ -145,29 +144,30 @@ export class PreferencesEditor extends BaseEditor {
|
||||
this.searchWidget = this._register(this.instantiationService.createInstance(SearchWidget, this.headerContainer, {
|
||||
ariaLabel: nls.localize('SearchSettingsWidget.AriaLabel', "Search settings"),
|
||||
placeholder: nls.localize('SearchSettingsWidget.Placeholder', "Search Settings"),
|
||||
focusKey: this.focusSettingsContextKey
|
||||
focusKey: this.focusSettingsContextKey,
|
||||
showFuzzyToggle: true,
|
||||
showResultCount: true
|
||||
}));
|
||||
this.searchWidget.setFuzzyToggleVisible(this.searchProvider.remoteSearchEnabled);
|
||||
this._register(this.searchProvider.onRemoteSearchEnablementChanged(enabled => this.searchWidget.setFuzzyToggleVisible(enabled)));
|
||||
this.searchWidget.setFuzzyToggleVisible(this.preferencesSearchService.remoteSearchAllowed);
|
||||
this.searchWidget.fuzzyEnabled = this.memento['fuzzyEnabled'];
|
||||
this._register(this.preferencesSearchService.onRemoteSearchEnablementChanged(enabled => this.searchWidget.setFuzzyToggleVisible(enabled)));
|
||||
this._register(this.searchWidget.onDidChange(value => this.onInputChanged()));
|
||||
this._register(this.searchWidget.onFocus(() => this.lastFocusedWidget = this.searchWidget));
|
||||
this.lastFocusedWidget = this.searchWidget;
|
||||
|
||||
this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, this.headerContainer, this.preferencesService.userSettingsResource, ConfigurationTarget.USER));
|
||||
this._register(this.settingsTargetsWidget.onDidTargetChange(target => this.switchSettings(target)));
|
||||
|
||||
const editorsContainer = DOM.append(parentElement, DOM.$('.preferences-editors-container'));
|
||||
this.sideBySidePreferencesWidget = this._register(this.instantiationService.createInstance(SideBySidePreferencesWidget, editorsContainer));
|
||||
this._register(this.sideBySidePreferencesWidget.onFocus(() => this.lastFocusedWidget = this.sideBySidePreferencesWidget));
|
||||
this._register(this.sideBySidePreferencesWidget.onDidSettingsTargetChange(target => this.switchSettings(target)));
|
||||
|
||||
this.preferencesRenderers = this._register(new PreferencesRenderers());
|
||||
this._register(this.workspaceContextService.onDidChangeWorkspaceFolders(() => this.onWorkspaceFoldersChanged()));
|
||||
this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this.onWorkbenchStateChanged()));
|
||||
this.preferencesRenderers = this._register(new PreferencesRenderers(this.preferencesSearchService));
|
||||
|
||||
this._register(this.preferencesRenderers.onTriggeredFuzzy(() => {
|
||||
this.searchWidget.fuzzyEnabled = true;
|
||||
this.filterPreferences();
|
||||
}));
|
||||
|
||||
this._register(this.preferencesRenderers.onDidFilterResultsCountChange(count => this.showSearchResultsMessage(count)));
|
||||
}
|
||||
|
||||
public clearSearchResults(): void {
|
||||
@@ -242,9 +242,6 @@ export class PreferencesEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
private updateInput(oldInput: PreferencesEditorInput, newInput: PreferencesEditorInput, options?: EditorOptions): TPromise<void> {
|
||||
const resource = newInput.master.getResource();
|
||||
this.settingsTargetsWidget.updateTargets(this.getSettingsConfigurationTargetUri(resource), this.getSettingsConfigurationTarget(resource));
|
||||
|
||||
return this.sideBySidePreferencesWidget.setInput(<DefaultPreferencesEditorInput>newInput.details, <EditorInput>newInput.master, options).then(({ defaultPreferencesRenderer, editablePreferencesRenderer }) => {
|
||||
this.preferencesRenderers.defaultPreferencesRenderer = defaultPreferencesRenderer;
|
||||
this.preferencesRenderers.editablePreferencesRenderer = editablePreferencesRenderer;
|
||||
@@ -264,98 +261,68 @@ export class PreferencesEditor extends BaseEditor {
|
||||
this.filterThrottle.trigger(() => this.filterPreferences());
|
||||
}
|
||||
|
||||
private getSettingsConfigurationTarget(resource: URI): ConfigurationTarget {
|
||||
if (this.preferencesService.userSettingsResource.toString() === resource.toString()) {
|
||||
return ConfigurationTarget.USER;
|
||||
}
|
||||
|
||||
const workspaceSettingsResource = this.preferencesService.workspaceSettingsResource;
|
||||
if (workspaceSettingsResource && workspaceSettingsResource.toString() === resource.toString()) {
|
||||
return ConfigurationTarget.WORKSPACE;
|
||||
}
|
||||
|
||||
if (this.workspaceContextService.getWorkspaceFolder(resource)) {
|
||||
return ConfigurationTarget.WORKSPACE_FOLDER;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private getSettingsConfigurationTargetUri(resource: URI): URI {
|
||||
if (this.preferencesService.userSettingsResource.toString() === resource.toString()) {
|
||||
return resource;
|
||||
}
|
||||
if (this.preferencesService.workspaceSettingsResource.toString() === resource.toString()) {
|
||||
return resource;
|
||||
}
|
||||
|
||||
const workspaceFolder = this.workspaceContextService.getWorkspaceFolder(resource);
|
||||
return workspaceFolder ? workspaceFolder.uri : null;
|
||||
}
|
||||
|
||||
private onWorkspaceFoldersChanged(): void {
|
||||
if (this.input) {
|
||||
const settingsResource = (<PreferencesEditorInput>this.input).master.getResource();
|
||||
const targetResource = this.getSettingsConfigurationTargetUri(settingsResource);
|
||||
if (!targetResource) {
|
||||
this.switchSettings(this.preferencesService.userSettingsResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onWorkbenchStateChanged(): void {
|
||||
if (this.input) {
|
||||
const editableSettingsResource = (<PreferencesEditorInput>this.input).master.getResource();
|
||||
const newConfigurationTarget = this.getSettingsConfigurationTarget(editableSettingsResource);
|
||||
if (newConfigurationTarget) {
|
||||
if (newConfigurationTarget !== this.settingsTargetsWidget.configurationTarget) {
|
||||
// Update the editor if the configuration target of the settings resource changed
|
||||
this.switchSettings(editableSettingsResource);
|
||||
}
|
||||
} else {
|
||||
this.switchSettings(this.preferencesService.userSettingsResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private switchSettings(resource: URI): void {
|
||||
private switchSettings(target: SettingsTarget): void {
|
||||
// Focus the editor if this editor is not active editor
|
||||
if (this.editorService.getActiveEditor() !== this) {
|
||||
this.focus();
|
||||
}
|
||||
const promise = this.input.isDirty() ? this.input.save() : TPromise.as(true);
|
||||
promise.done(value => this.preferencesService.switchSettings(this.getSettingsConfigurationTarget(resource), resource));
|
||||
promise.done(value => {
|
||||
if (target === ConfigurationTarget.USER) {
|
||||
this.preferencesService.switchSettings(ConfigurationTarget.USER, this.preferencesService.userSettingsResource);
|
||||
} else if (target === ConfigurationTarget.WORKSPACE) {
|
||||
this.preferencesService.switchSettings(ConfigurationTarget.WORKSPACE, this.preferencesService.workspaceSettingsResource);
|
||||
} else if (target instanceof URI) {
|
||||
this.preferencesService.switchSettings(ConfigurationTarget.WORKSPACE_FOLDER, target);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private filterPreferences(): TPromise<void> {
|
||||
this.memento['fuzzyEnabled'] = this.searchWidget.fuzzyEnabled;
|
||||
const filter = this.searchWidget.getValue().trim();
|
||||
return this.preferencesRenderers.filterPreferences(filter, this.searchProvider, this.searchWidget.fuzzyEnabled).then(count => {
|
||||
const message = filter ? this.showSearchResultsMessage(count) : nls.localize('totalSettingsMessage', "Total {0} Settings", count);
|
||||
this.searchWidget.showMessage(message, count);
|
||||
if (count === 0) {
|
||||
return this.preferencesRenderers.filterPreferences({ filter, fuzzy: this.searchWidget.fuzzyEnabled }).then(result => {
|
||||
this.showSearchResultsMessage(result.count);
|
||||
if (result.count === 0) {
|
||||
this.latestEmptyFilters.push(filter);
|
||||
}
|
||||
this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(filter));
|
||||
this.preferencesRenderers.focusFirst();
|
||||
this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(filter, result.metadata));
|
||||
}, onUnexpectedError);
|
||||
}
|
||||
|
||||
private showSearchResultsMessage(count: number): string {
|
||||
return count === 0 ? nls.localize('noSettingsFound', "No Results") :
|
||||
count === 1 ? nls.localize('oneSettingFound', "1 Setting matched") :
|
||||
nls.localize('settingsFound', "{0} Settings matched", count);
|
||||
private showSearchResultsMessage(count: number): void {
|
||||
if (this.searchWidget.getValue()) {
|
||||
if (count === 0) {
|
||||
this.searchWidget.showMessage(nls.localize('noSettingsFound', "No Results"), count);
|
||||
} else if (count === 1) {
|
||||
this.searchWidget.showMessage(nls.localize('oneSettingFound', "1 Setting matched"), count);
|
||||
} else {
|
||||
this.searchWidget.showMessage(nls.localize('settingsFound', "{0} Settings matched", count), count);
|
||||
}
|
||||
} else {
|
||||
this.searchWidget.showMessage(nls.localize('totalSettingsMessage', "Total {0} Settings", count), count);
|
||||
}
|
||||
}
|
||||
|
||||
private reportFilteringUsed(filter: string): void {
|
||||
private reportFilteringUsed(filter: string, metadata?: IFilterMetadata): void {
|
||||
if (filter) {
|
||||
let data = {
|
||||
filter,
|
||||
emptyFilters: this.getLatestEmptyFiltersForTelemetry()
|
||||
emptyFilters: this.getLatestEmptyFiltersForTelemetry(),
|
||||
fuzzy: !!metadata,
|
||||
duration: metadata ? metadata.duration : undefined,
|
||||
context: metadata ? metadata.context : undefined
|
||||
};
|
||||
|
||||
this.latestEmptyFilters = [];
|
||||
/* __GDPR__
|
||||
"defaultSettings.filter" : {
|
||||
"filter": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"emptyFilters" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
"emptyFilters" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"fuzzy" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"context" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('defaultSettings.filter', data);
|
||||
@@ -405,32 +372,57 @@ class SettingsNavigator implements INavigator<ISetting> {
|
||||
}
|
||||
}
|
||||
|
||||
interface ISearchCriteria {
|
||||
filter: string;
|
||||
fuzzy: boolean;
|
||||
}
|
||||
|
||||
class PreferencesRenderers extends Disposable {
|
||||
|
||||
private _defaultPreferencesRenderer: IPreferencesRenderer<ISetting>;
|
||||
private _defaultPreferencesRendererDisposables: IDisposable[] = [];
|
||||
|
||||
private _defaultPreferencesFilterResult: IFilterResult;
|
||||
private _editablePreferencesFilterResult: IFilterResult;
|
||||
|
||||
private _editablePreferencesRenderer: IPreferencesRenderer<ISetting>;
|
||||
private _editablePreferencesRendererDisposables: IDisposable[] = [];
|
||||
|
||||
private _settingsNavigator: SettingsNavigator;
|
||||
private _filtersInProgress: TPromise<any>[];
|
||||
private _searchCriteria: ISearchCriteria;
|
||||
private _currentSearchModel: IPreferencesSearchModel;
|
||||
|
||||
private _disposables: IDisposable[] = [];
|
||||
|
||||
private _onTriggeredFuzzy: Emitter<void> = new Emitter<void>();
|
||||
private _onTriggeredFuzzy: Emitter<void> = this._register(new Emitter<void>());
|
||||
public onTriggeredFuzzy: Event<void> = this._onTriggeredFuzzy.event;
|
||||
|
||||
public get defaultPreferencesRenderer(): IPreferencesRenderer<ISetting> {
|
||||
private _onDidFilterResultsCountChange: Emitter<number> = this._register(new Emitter<number>());
|
||||
public onDidFilterResultsCountChange: Event<number> = this._onDidFilterResultsCountChange.event;
|
||||
|
||||
constructor(
|
||||
private preferencesSearchService: IPreferencesSearchService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
get defaultPreferencesRenderer(): IPreferencesRenderer<ISetting> {
|
||||
return this._defaultPreferencesRenderer;
|
||||
}
|
||||
|
||||
public set defaultPreferencesRenderer(defaultPreferencesRenderer: IPreferencesRenderer<ISetting>) {
|
||||
get editablePreferencesRenderer(): IPreferencesRenderer<ISetting> {
|
||||
return this._editablePreferencesRenderer;
|
||||
}
|
||||
|
||||
set defaultPreferencesRenderer(defaultPreferencesRenderer: IPreferencesRenderer<ISetting>) {
|
||||
if (this._defaultPreferencesRenderer !== defaultPreferencesRenderer) {
|
||||
this._defaultPreferencesRenderer = defaultPreferencesRenderer;
|
||||
|
||||
this._disposables = dispose(this._disposables);
|
||||
this._defaultPreferencesRendererDisposables = dispose(this._defaultPreferencesRendererDisposables);
|
||||
|
||||
if (this._defaultPreferencesRenderer) {
|
||||
this._defaultPreferencesRenderer.onUpdatePreference(({ key, value, source }) => this._updatePreference(key, value, source, this._editablePreferencesRenderer), this, this._disposables);
|
||||
this._defaultPreferencesRenderer.onFocusPreference(preference => this._focusPreference(preference, this._editablePreferencesRenderer), this, this._disposables);
|
||||
this._defaultPreferencesRenderer.onClearFocusPreference(preference => this._clearFocus(preference, this._editablePreferencesRenderer), this, this._disposables);
|
||||
this._defaultPreferencesRenderer.onUpdatePreference(({ key, value, source, index }) => this._updatePreference(key, value, source, index, this._editablePreferencesRenderer), this, this._defaultPreferencesRendererDisposables);
|
||||
this._defaultPreferencesRenderer.onFocusPreference(preference => this._focusPreference(preference, this._editablePreferencesRenderer), this, this._defaultPreferencesRendererDisposables);
|
||||
this._defaultPreferencesRenderer.onClearFocusPreference(preference => this._clearFocus(preference, this._editablePreferencesRenderer), this, this._defaultPreferencesRendererDisposables);
|
||||
if (this._defaultPreferencesRenderer.onTriggeredFuzzy) {
|
||||
this._register(this._defaultPreferencesRenderer.onTriggeredFuzzy(() => this._onTriggeredFuzzy.fire()));
|
||||
}
|
||||
@@ -438,37 +430,50 @@ class PreferencesRenderers extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
public set editablePreferencesRenderer(editableSettingsRenderer: IPreferencesRenderer<ISetting>) {
|
||||
this._editablePreferencesRenderer = editableSettingsRenderer;
|
||||
set editablePreferencesRenderer(editableSettingsRenderer: IPreferencesRenderer<ISetting>) {
|
||||
if (this._editablePreferencesRenderer !== editableSettingsRenderer) {
|
||||
this._editablePreferencesRenderer = editableSettingsRenderer;
|
||||
this._editablePreferencesRendererDisposables = dispose(this._editablePreferencesRendererDisposables);
|
||||
if (this._editablePreferencesRenderer) {
|
||||
(<ISettingsEditorModel>this._editablePreferencesRenderer.preferencesModel).onDidChangeGroups(() => {
|
||||
if (this._currentSearchModel) {
|
||||
this._filterEditablePreferences()
|
||||
.then(() => {
|
||||
const count = this.consolidateAndUpdate();
|
||||
this._onDidFilterResultsCountChange.fire(count);
|
||||
});
|
||||
}
|
||||
}, this, this._editablePreferencesRendererDisposables);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public filterPreferences(filter: string, searchProvider: PreferencesSearchProvider, fuzzy: boolean): TPromise<number> {
|
||||
filterPreferences(criteria: ISearchCriteria): TPromise<{ count: number, metadata: IFilterMetadata }> {
|
||||
this._searchCriteria = criteria;
|
||||
|
||||
if (this._filtersInProgress) {
|
||||
// Resolved/rejected promises have no .cancel()
|
||||
this._filtersInProgress.forEach(p => p.cancel && p.cancel());
|
||||
}
|
||||
|
||||
const searchModel = searchProvider.startSearch(filter, fuzzy);
|
||||
this._filtersInProgress = [
|
||||
this._filterPreferences(searchModel, searchProvider, this._defaultPreferencesRenderer),
|
||||
this._filterPreferences(searchModel, searchProvider, this._editablePreferencesRenderer)];
|
||||
this._currentSearchModel = this.preferencesSearchService.startSearch(this._searchCriteria.filter, criteria.fuzzy);
|
||||
this._filtersInProgress = [this._filterDefaultPreferences(), this._filterEditablePreferences()];
|
||||
|
||||
return TPromise.join<IFilterResult>(this._filtersInProgress).then(filterResults => {
|
||||
this._filtersInProgress = null;
|
||||
const defaultPreferencesFilterResult = filterResults[0];
|
||||
const editablePreferencesFilterResult = filterResults[1];
|
||||
|
||||
const defaultPreferencesFilteredGroups = defaultPreferencesFilterResult ? defaultPreferencesFilterResult.filteredGroups : this._getAllPreferences(this._defaultPreferencesRenderer);
|
||||
const editablePreferencesFilteredGroups = editablePreferencesFilterResult ? editablePreferencesFilterResult.filteredGroups : this._getAllPreferences(this._editablePreferencesRenderer);
|
||||
const consolidatedSettings = this._consolidateSettings(editablePreferencesFilteredGroups, defaultPreferencesFilteredGroups);
|
||||
|
||||
this._settingsNavigator = new SettingsNavigator(filter ? consolidatedSettings : []);
|
||||
|
||||
return consolidatedSettings.length;
|
||||
return TPromise.join<IFilterResult>(this._filtersInProgress).then(() => {
|
||||
const count = this.consolidateAndUpdate();
|
||||
return { count, metadata: this._defaultPreferencesFilterResult && this._defaultPreferencesFilterResult.metadata };
|
||||
});
|
||||
}
|
||||
|
||||
public focusNextPreference(forward: boolean = true) {
|
||||
focusFirst(): void {
|
||||
// Focus first match in both renderers
|
||||
this._focusPreference(this._getFirstSettingFromTheGroups(this._defaultPreferencesFilterResult ? this._defaultPreferencesFilterResult.filteredGroups : []), this._defaultPreferencesRenderer);
|
||||
this._focusPreference(this._getFirstSettingFromTheGroups(this._editablePreferencesFilterResult ? this._editablePreferencesFilterResult.filteredGroups : []), this._editablePreferencesRenderer);
|
||||
|
||||
this._settingsNavigator.first(); // Move to first
|
||||
}
|
||||
|
||||
focusNextPreference(forward: boolean = true) {
|
||||
if (!this._settingsNavigator) {
|
||||
return;
|
||||
}
|
||||
@@ -478,21 +483,54 @@ class PreferencesRenderers extends Disposable {
|
||||
this._focusPreference(setting, this._editablePreferencesRenderer);
|
||||
}
|
||||
|
||||
private _filterDefaultPreferences(): TPromise<void> {
|
||||
if (this._searchCriteria && this._defaultPreferencesRenderer) {
|
||||
return this._filterPreferences(this._searchCriteria, this._defaultPreferencesRenderer, this._currentSearchModel)
|
||||
.then(filterResult => { this._defaultPreferencesFilterResult = filterResult; });
|
||||
}
|
||||
return TPromise.wrap(null);
|
||||
}
|
||||
|
||||
private _filterEditablePreferences(): TPromise<void> {
|
||||
if (this._searchCriteria && this._editablePreferencesRenderer) {
|
||||
return this._filterPreferences(this._searchCriteria, this._editablePreferencesRenderer, this._currentSearchModel)
|
||||
.then(filterResult => { this._editablePreferencesFilterResult = filterResult; });
|
||||
}
|
||||
return TPromise.wrap(null);
|
||||
}
|
||||
|
||||
private _getFirstSettingFromTheGroups(allGroups: ISettingsGroup[]): ISetting {
|
||||
if (allGroups.length) {
|
||||
if (allGroups[0].sections.length) {
|
||||
return allGroups[0].sections[0].settings[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private _getAllPreferences(preferencesRenderer: IPreferencesRenderer<ISetting>): ISettingsGroup[] {
|
||||
return preferencesRenderer ? (<ISettingsEditorModel>preferencesRenderer.preferencesModel).settingsGroups : [];
|
||||
}
|
||||
|
||||
private _filterPreferences(searchModel: PreferencesSearchModel, searchProvider: PreferencesSearchProvider, preferencesRenderer: IPreferencesRenderer<ISetting>): TPromise<IFilterResult> {
|
||||
if (preferencesRenderer) {
|
||||
private _filterPreferences(searchCriteria: ISearchCriteria, preferencesRenderer: IPreferencesRenderer<ISetting>, searchModel: IPreferencesSearchModel): TPromise<IFilterResult> {
|
||||
if (preferencesRenderer && searchCriteria) {
|
||||
const prefSearchP = searchModel.filterPreferences(<ISettingsEditorModel>preferencesRenderer.preferencesModel);
|
||||
|
||||
return prefSearchP.then(filterResult => {
|
||||
preferencesRenderer.filterPreferences(filterResult, searchProvider.remoteSearchEnabled);
|
||||
preferencesRenderer.filterPreferences(filterResult, this.preferencesSearchService.remoteSearchAllowed);
|
||||
return filterResult;
|
||||
});
|
||||
}
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
return TPromise.wrap(null);
|
||||
private consolidateAndUpdate(): number {
|
||||
const defaultPreferencesFilteredGroups = this._defaultPreferencesFilterResult ? this._defaultPreferencesFilterResult.filteredGroups : this._getAllPreferences(this._defaultPreferencesRenderer);
|
||||
const editablePreferencesFilteredGroups = this._editablePreferencesFilterResult ? this._editablePreferencesFilterResult.filteredGroups : this._getAllPreferences(this._editablePreferencesRenderer);
|
||||
const consolidatedSettings = this._consolidateSettings(editablePreferencesFilteredGroups, defaultPreferencesFilteredGroups);
|
||||
|
||||
this._settingsNavigator = new SettingsNavigator(this._searchCriteria.filter ? consolidatedSettings : []);
|
||||
return consolidatedSettings.length;
|
||||
}
|
||||
|
||||
private _focusPreference(preference: ISetting, preferencesRenderer: IPreferencesRenderer<ISetting>): void {
|
||||
@@ -507,16 +545,16 @@ class PreferencesRenderers extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private _updatePreference(key: string, value: any, source: ISetting, preferencesRenderer: IPreferencesRenderer<ISetting>): void {
|
||||
private _updatePreference(key: string, value: any, source: ISetting, index: number, preferencesRenderer: IPreferencesRenderer<ISetting>): void {
|
||||
if (preferencesRenderer) {
|
||||
preferencesRenderer.updatePreference(key, value, source);
|
||||
preferencesRenderer.updatePreference(key, value, source, index);
|
||||
}
|
||||
}
|
||||
|
||||
private _consolidateSettings(editableSettingsGroups: ISettingsGroup[], defaultSettingsGroups: ISettingsGroup[]): ISetting[] {
|
||||
const editableSettings = this._flatten(editableSettingsGroups);
|
||||
const defaultSettings = this._flatten(defaultSettingsGroups).filter(secondarySetting => !editableSettings.some(primarySetting => primarySetting.key === secondarySetting.key));
|
||||
return [...editableSettings, ...defaultSettings];
|
||||
return [...defaultSettings, ...editableSettings];
|
||||
}
|
||||
|
||||
private _flatten(settingsGroups: ISettingsGroup[]): ISetting[] {
|
||||
@@ -530,7 +568,8 @@ class PreferencesRenderers extends Disposable {
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
dispose(this._disposables);
|
||||
dispose(this._defaultPreferencesRendererDisposables);
|
||||
dispose(this._editablePreferencesRendererDisposables);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -539,19 +578,31 @@ class SideBySidePreferencesWidget extends Widget {
|
||||
|
||||
private dimension: Dimension;
|
||||
|
||||
private defaultPreferencesHeader: HTMLElement;
|
||||
private defaultPreferencesEditor: DefaultPreferencesEditor;
|
||||
private editablePreferencesEditor: BaseEditor;
|
||||
private defaultPreferencesEditorContainer: HTMLElement;
|
||||
private editablePreferencesEditorContainer: HTMLElement;
|
||||
|
||||
private settingsTargetsWidget: SettingsTargetsWidget;
|
||||
|
||||
private _onFocus: Emitter<void> = new Emitter<void>();
|
||||
readonly onFocus: Event<void> = this._onFocus.event;
|
||||
|
||||
private _onDidSettingsTargetChange: Emitter<SettingsTarget> = new Emitter<SettingsTarget>();
|
||||
readonly onDidSettingsTargetChange: Event<SettingsTarget> = this._onDidSettingsTargetChange.event;
|
||||
|
||||
private lastFocusedEditor: BaseEditor;
|
||||
|
||||
private sash: VSash;
|
||||
|
||||
constructor(parent: HTMLElement, @IInstantiationService private instantiationService: IInstantiationService, @IThemeService private themeService: IThemeService) {
|
||||
constructor(
|
||||
parent: HTMLElement,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IThemeService private themeService: IThemeService,
|
||||
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService,
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
) {
|
||||
super();
|
||||
this.create(parent);
|
||||
}
|
||||
@@ -562,6 +613,13 @@ class SideBySidePreferencesWidget extends Widget {
|
||||
|
||||
this.defaultPreferencesEditorContainer = DOM.append(parentElement, DOM.$('.default-preferences-editor-container'));
|
||||
this.defaultPreferencesEditorContainer.style.position = 'absolute';
|
||||
|
||||
const defaultPreferencesHeaderContainer = DOM.append(this.defaultPreferencesEditorContainer, DOM.$('.preferences-header-container'));
|
||||
defaultPreferencesHeaderContainer.style.height = '30px';
|
||||
defaultPreferencesHeaderContainer.style.marginBottom = '4px';
|
||||
this.defaultPreferencesHeader = DOM.append(defaultPreferencesHeaderContainer, DOM.$('div.default-preferences-header'));
|
||||
this.defaultPreferencesHeader.textContent = nls.localize('defaultSettings', "Default Settings");
|
||||
|
||||
this.defaultPreferencesEditor = this._register(this.instantiationService.createInstance(DefaultPreferencesEditor));
|
||||
this.defaultPreferencesEditor.create(new Builder(this.defaultPreferencesEditorContainer));
|
||||
this.defaultPreferencesEditor.setVisible(true);
|
||||
@@ -569,6 +627,11 @@ class SideBySidePreferencesWidget extends Widget {
|
||||
|
||||
this.editablePreferencesEditorContainer = DOM.append(parentElement, DOM.$('.editable-preferences-editor-container'));
|
||||
this.editablePreferencesEditorContainer.style.position = 'absolute';
|
||||
const editablePreferencesHeaderContainer = DOM.append(this.editablePreferencesEditorContainer, DOM.$('.preferences-header-container'));
|
||||
editablePreferencesHeaderContainer.style.height = '30px';
|
||||
editablePreferencesHeaderContainer.style.marginBottom = '4px';
|
||||
this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, editablePreferencesHeaderContainer));
|
||||
this._register(this.settingsTargetsWidget.onDidTargetChange(target => this._onDidSettingsTargetChange.fire(target)));
|
||||
|
||||
this._register(attachStylerCallback(this.themeService, { scrollbarShadow }, colors => {
|
||||
const shadow = colors.scrollbarShadow ? colors.scrollbarShadow.toString() : null;
|
||||
@@ -581,15 +644,19 @@ class SideBySidePreferencesWidget extends Widget {
|
||||
}));
|
||||
|
||||
const focusTracker = this._register(DOM.trackFocus(parentElement));
|
||||
this._register(focusTracker.addFocusListener(() => this._onFocus.fire()));
|
||||
this._register(focusTracker.onDidFocus(() => this._onFocus.fire()));
|
||||
}
|
||||
|
||||
public setInput(defaultPreferencesEditorInput: DefaultPreferencesEditorInput, editablePreferencesEditorInput: EditorInput, options?: EditorOptions): TPromise<{ defaultPreferencesRenderer: IPreferencesRenderer<ISetting>, editablePreferencesRenderer: IPreferencesRenderer<ISetting> }> {
|
||||
this.getOrCreateEditablePreferencesEditor(editablePreferencesEditorInput);
|
||||
this.settingsTargetsWidget.settingsTarget = this.getSettingsTarget(editablePreferencesEditorInput.getResource());
|
||||
this.dolayout(this.sash.getVerticalSashLeft());
|
||||
return TPromise.join([this.updateInput(this.defaultPreferencesEditor, defaultPreferencesEditorInput, DefaultSettingsEditorContribution.ID, editablePreferencesEditorInput.getResource(), options),
|
||||
this.updateInput(this.editablePreferencesEditor, editablePreferencesEditorInput, SettingsEditorContribution.ID, defaultPreferencesEditorInput.getResource(), options)])
|
||||
.then(([defaultPreferencesRenderer, editablePreferencesRenderer]) => ({ defaultPreferencesRenderer, editablePreferencesRenderer }));
|
||||
.then(([defaultPreferencesRenderer, editablePreferencesRenderer]) => {
|
||||
this.defaultPreferencesHeader.textContent = defaultPreferencesRenderer && (<DefaultSettingsEditorModel>defaultPreferencesRenderer.preferencesModel).configurationScope === ConfigurationScope.RESOURCE ? nls.localize('defaultFolderSettings', "Default Folder Settings") : nls.localize('defaultSettings', "Default Settings");
|
||||
return { defaultPreferencesRenderer, editablePreferencesRenderer };
|
||||
});
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): void {
|
||||
@@ -668,8 +735,26 @@ class SideBySidePreferencesWidget extends Widget {
|
||||
this.editablePreferencesEditorContainer.style.height = `${this.dimension.height}px`;
|
||||
this.editablePreferencesEditorContainer.style.left = `${splitPoint}px`;
|
||||
|
||||
this.defaultPreferencesEditor.layout(new Dimension(detailsEditorWidth, this.dimension.height));
|
||||
this.editablePreferencesEditor.layout(new Dimension(masterEditorWidth, this.dimension.height));
|
||||
this.defaultPreferencesEditor.layout(new Dimension(detailsEditorWidth, this.dimension.height - 34 /* height of header container */));
|
||||
this.editablePreferencesEditor.layout(new Dimension(masterEditorWidth, this.dimension.height - 34 /* height of header container */));
|
||||
}
|
||||
|
||||
private getSettingsTarget(resource: URI): SettingsTarget {
|
||||
if (this.preferencesService.userSettingsResource.toString() === resource.toString()) {
|
||||
return ConfigurationTarget.USER;
|
||||
}
|
||||
|
||||
const workspaceSettingsResource = this.preferencesService.workspaceSettingsResource;
|
||||
if (workspaceSettingsResource && workspaceSettingsResource.toString() === resource.toString()) {
|
||||
return ConfigurationTarget.WORKSPACE;
|
||||
}
|
||||
|
||||
const folder = this.workspaceContextService.getWorkspaceFolder(resource);
|
||||
if (folder) {
|
||||
return folder.uri;
|
||||
}
|
||||
|
||||
return ConfigurationTarget.USER;
|
||||
}
|
||||
|
||||
private disposeEditors(): void {
|
||||
@@ -689,98 +774,20 @@ class SideBySidePreferencesWidget extends Widget {
|
||||
}
|
||||
}
|
||||
|
||||
export class EditableSettingsEditor extends BaseTextEditor {
|
||||
|
||||
public static ID: string = 'workbench.editor.settingsEditor';
|
||||
|
||||
private modelDisposables: IDisposable[] = [];
|
||||
private saveDelayer: Delayer<void>;
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@ITextResourceConfigurationService configurationService: ITextResourceConfigurationService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
@IModelService private modelService: IModelService,
|
||||
@IModeService modeService: IModeService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IEditorGroupService editorGroupService: IEditorGroupService
|
||||
) {
|
||||
super(EditableSettingsEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, modeService, textFileService, editorGroupService);
|
||||
this._register({ dispose: () => dispose(this.modelDisposables) });
|
||||
this.saveDelayer = new Delayer<void>(1000);
|
||||
}
|
||||
|
||||
protected createEditor(parent: Builder): void {
|
||||
super.createEditor(parent);
|
||||
|
||||
const codeEditor = getCodeEditor(this);
|
||||
if (codeEditor) {
|
||||
this._register(codeEditor.onDidChangeModel(() => this.onDidModelChange()));
|
||||
}
|
||||
}
|
||||
|
||||
protected getAriaLabel(): string {
|
||||
const input = this.input;
|
||||
const inputName = input && input.getName();
|
||||
|
||||
let ariaLabel: string;
|
||||
if (inputName) {
|
||||
ariaLabel = nls.localize('fileEditorWithInputAriaLabel', "{0}. Text file editor.", inputName);
|
||||
} else {
|
||||
ariaLabel = nls.localize('fileEditorAriaLabel', "Text file editor.");
|
||||
}
|
||||
|
||||
return ariaLabel;
|
||||
}
|
||||
|
||||
setInput(input: EditorInput, options: EditorOptions): TPromise<void> {
|
||||
return super.setInput(input, options)
|
||||
.then(() => this.input.resolve()
|
||||
.then(editorModel => editorModel.load())
|
||||
.then(editorModel => this.getControl().setModel((<ResourceEditorModel>editorModel).textEditorModel)));
|
||||
}
|
||||
|
||||
clearInput(): void {
|
||||
this.modelDisposables = dispose(this.modelDisposables);
|
||||
super.clearInput();
|
||||
}
|
||||
|
||||
private onDidModelChange(): void {
|
||||
this.modelDisposables = dispose(this.modelDisposables);
|
||||
const model = getCodeEditor(this).getModel();
|
||||
if (model) {
|
||||
this.preferencesService.createPreferencesEditorModel(model.uri)
|
||||
.then(preferencesEditorModel => {
|
||||
const settingsEditorModel = <SettingsEditorModel>preferencesEditorModel;
|
||||
this.modelDisposables.push(settingsEditorModel);
|
||||
this.modelDisposables.push(model.onDidChangeContent(() => this.saveDelayer.trigger(() => settingsEditorModel.save())));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class DefaultPreferencesEditor extends BaseTextEditor {
|
||||
|
||||
public static ID: string = 'workbench.editor.defaultPreferences';
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@ITextResourceConfigurationService configurationService: ITextResourceConfigurationService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
@IModelService private modelService: IModelService,
|
||||
@IModeService modeService: IModeService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IEditorGroupService editorGroupService: IEditorGroupService
|
||||
) {
|
||||
super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, modeService, textFileService, editorGroupService);
|
||||
super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorGroupService);
|
||||
}
|
||||
|
||||
public createEditorControl(parent: Builder, configuration: IEditorOptions): editorCommon.IEditor {
|
||||
@@ -793,7 +800,7 @@ export class DefaultPreferencesEditor extends BaseTextEditor {
|
||||
return editor;
|
||||
}
|
||||
|
||||
private showReadonlyHint(editor: editorCommon.ICommonCodeEditor): void {
|
||||
private showReadonlyHint(editor: ICodeEditor): void {
|
||||
const messageController = MessageController.get(editor);
|
||||
if (!messageController.isVisible()) {
|
||||
messageController.showMessage(nls.localize('defaultEditorReadonly', "Edit in the right hand side editor to override defaults."), editor.getSelection().getPosition());
|
||||
@@ -862,7 +869,7 @@ interface ISettingsEditorContribution extends editorCommon.IEditorContribution {
|
||||
|
||||
}
|
||||
|
||||
abstract class AbstractSettingsEditorContribution extends Disposable {
|
||||
abstract class AbstractSettingsEditorContribution extends Disposable implements ISettingsEditorContribution {
|
||||
|
||||
private preferencesRendererCreationPromise: TPromise<IPreferencesRenderer<ISetting>>;
|
||||
|
||||
@@ -938,6 +945,7 @@ abstract class AbstractSettingsEditorContribution extends Disposable {
|
||||
}
|
||||
|
||||
protected abstract _createPreferencesRenderer(): TPromise<IPreferencesRenderer<ISetting>>;
|
||||
abstract getId(): string;
|
||||
}
|
||||
|
||||
class DefaultSettingsEditorContribution extends AbstractSettingsEditorContribution implements ISettingsEditorContribution {
|
||||
@@ -961,7 +969,6 @@ class DefaultSettingsEditorContribution extends AbstractSettingsEditorContributi
|
||||
}
|
||||
}
|
||||
|
||||
@editorContribution
|
||||
class SettingsEditorContribution extends AbstractSettingsEditorContribution implements ISettingsEditorContribution {
|
||||
|
||||
static ID: string = 'editor.contrib.settings';
|
||||
@@ -1031,6 +1038,8 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl
|
||||
|
||||
}
|
||||
|
||||
registerEditorContribution(SettingsEditorContribution);
|
||||
|
||||
abstract class SettingsCommand extends Command {
|
||||
|
||||
protected getPreferencesEditor(accessor: ServicesAccessor): PreferencesEditor {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { tail } from 'vs/base/common/arrays';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
@@ -16,16 +17,14 @@ import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { Range, IRange } from 'vs/editor/common/core/range';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IPreferencesService, ISettingsGroup, ISetting, IPreferencesEditorModel, IFilterResult, ISettingsEditorModel, IScoredResults } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { IPreferencesService, ISettingsGroup, ISetting, IPreferencesEditorModel, IFilterResult, ISettingsEditorModel, IScoredResults, IWorkbenchSettingsConfiguration } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { SettingsEditorModel, DefaultSettingsEditorModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels';
|
||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { IContextMenuService, ContextSubMenu } from 'vs/platform/contextview/browser/contextView';
|
||||
import { SettingsGroupTitleWidget, EditPreferenceWidget, SettingsHeaderWidget, DefaultSettingsHeaderWidget, FloatingClickWidget } from 'vs/workbench/parts/preferences/browser/preferencesWidgets';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { RangeHighlightDecorations } from 'vs/workbench/common/editor/rangeDecorations';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { RangeHighlightDecorations } from 'vs/workbench/browser/parts/editor/rangeDecorations';
|
||||
import { IMarkerService, IMarkerData } from 'vs/platform/markers/common/markers';
|
||||
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { IMessageService, Severity } from 'vs/platform/message/common/message';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
@@ -41,11 +40,11 @@ export interface IPreferencesRenderer<T> extends IDisposable {
|
||||
|
||||
onFocusPreference: Event<T>;
|
||||
onClearFocusPreference: Event<T>;
|
||||
onUpdatePreference: Event<{ key: string, value: any, source: T }>;
|
||||
onUpdatePreference?: Event<{ key: string, value: any, source: T, index: number }>;
|
||||
onTriggeredFuzzy?: Event<void>;
|
||||
|
||||
render(): void;
|
||||
updatePreference(key: string, value: any, source: T): void;
|
||||
updatePreference(key: string, value: any, source: T, index: number): void;
|
||||
filterPreferences(filterResult: IFilterResult, fuzzySearchAvailable: boolean): void;
|
||||
focusPreference(setting: T): void;
|
||||
clearFocus(setting: T): void;
|
||||
@@ -62,9 +61,6 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
|
||||
private _onFocusPreference: Emitter<ISetting> = new Emitter<ISetting>();
|
||||
public readonly onFocusPreference: Event<ISetting> = this._onFocusPreference.event;
|
||||
|
||||
private _onUpdatePreference: Emitter<{ key: string, value: any, source: ISetting }> = new Emitter<{ key: string, value: any, source: ISetting }>();
|
||||
public readonly onUpdatePreference: Event<{ key: string, value: any, source: ISetting }> = this._onUpdatePreference.event;
|
||||
|
||||
private _onClearFocusPreference: Emitter<ISetting> = new Emitter<ISetting>();
|
||||
public readonly onClearFocusPreference: Event<ISetting> = this._onClearFocusPreference.event;
|
||||
|
||||
@@ -73,7 +69,6 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
|
||||
constructor(protected editor: ICodeEditor, public readonly preferencesModel: SettingsEditorModel,
|
||||
@IPreferencesService protected preferencesService: IPreferencesService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@ITextFileService private textFileService: ITextFileService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IInstantiationService protected instantiationService: IInstantiationService
|
||||
) {
|
||||
@@ -81,7 +76,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
|
||||
this.settingHighlighter = this._register(instantiationService.createInstance(SettingHighlighter, editor, this._onFocusPreference, this._onClearFocusPreference));
|
||||
this.highlightMatchesRenderer = this._register(instantiationService.createInstance(HighlightMatchesRenderer, editor));
|
||||
this.editSettingActionRenderer = this._register(this.instantiationService.createInstance(EditSettingRenderer, this.editor, this.preferencesModel, this.settingHighlighter));
|
||||
this._register(this.editSettingActionRenderer.onUpdateSetting(({ key, value, source }) => this.updatePreference(key, value, source)));
|
||||
this._register(this.editSettingActionRenderer.onUpdateSetting(({ key, value, source, index }) => this.updatePreference(key, value, source, index, true)));
|
||||
this._register(this.editor.getModel().onDidChangeContent(() => this.modelChangeDelayer.trigger(() => this.onModelChanged())));
|
||||
|
||||
this.createHeader();
|
||||
@@ -107,13 +102,30 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
|
||||
}
|
||||
}
|
||||
|
||||
public updatePreference(key: string, value: any, source: ISetting): void {
|
||||
public updatePreference(key: string, value: any, source: ISetting, index: number, fromEditableSettings?: boolean): void {
|
||||
const data = {
|
||||
userConfigurationKeys: [key]
|
||||
};
|
||||
|
||||
if (this.filterResult) {
|
||||
data['query'] = this.filterResult.query;
|
||||
data['fuzzy'] = !!this.filterResult.metadata;
|
||||
data['duration'] = this.filterResult.metadata && this.filterResult.metadata.duration;
|
||||
data['index'] = index;
|
||||
data['editableSide'] = !!fromEditableSettings;
|
||||
}
|
||||
|
||||
/* __GDPR__
|
||||
"defaultSettingsActions.copySetting" : {
|
||||
"userConfigurationKeys" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
"userConfigurationKeys" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"query" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"fuzzy" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"index" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"editableSide" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('defaultSettingsActions.copySetting', { userConfigurationKeys: [key] });
|
||||
this.telemetryService.publicLog('defaultSettingsActions.copySetting', data);
|
||||
const overrideIdentifier = source.overrideOf ? overrideIdentifierFromKey(source.overrideOf.key) : null;
|
||||
const resource = this.preferencesModel.uri;
|
||||
this.configurationService.updateValue(key, value, { overrideIdentifier, resource }, this.preferencesModel.configurationTarget)
|
||||
@@ -162,6 +174,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
|
||||
const s = this.getSetting(setting);
|
||||
if (s) {
|
||||
this.settingHighlighter.highlight(s, true);
|
||||
this.editor.setPosition({ lineNumber: s.keyRange.startLineNumber, column: s.keyRange.startColumn });
|
||||
} else {
|
||||
this.settingHighlighter.clear(true);
|
||||
}
|
||||
@@ -180,11 +193,10 @@ export class WorkspaceSettingsRenderer extends UserSettingsRenderer implements I
|
||||
constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel,
|
||||
@IPreferencesService preferencesService: IPreferencesService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super(editor, preferencesModel, preferencesService, telemetryService, textFileService, configurationService, instantiationService);
|
||||
super(editor, preferencesModel, preferencesService, telemetryService, configurationService, instantiationService);
|
||||
this.unsupportedSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedSettingsRenderer, editor, preferencesModel));
|
||||
this.workspaceConfigurationRenderer = this._register(instantiationService.createInstance(WorkspaceConfigurationRenderer, editor, preferencesModel));
|
||||
}
|
||||
@@ -207,11 +219,10 @@ export class FolderSettingsRenderer extends UserSettingsRenderer implements IPre
|
||||
constructor(editor: ICodeEditor, preferencesModel: SettingsEditorModel,
|
||||
@IPreferencesService preferencesService: IPreferencesService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@ITextFileService textFileService: ITextFileService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super(editor, preferencesModel, preferencesService, telemetryService, textFileService, configurationService, instantiationService);
|
||||
super(editor, preferencesModel, preferencesService, telemetryService, configurationService, instantiationService);
|
||||
this.unsupportedSettingsRenderer = this._register(instantiationService.createInstance(UnsupportedSettingsRenderer, editor, preferencesModel));
|
||||
}
|
||||
|
||||
@@ -236,8 +247,8 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
|
||||
private editSettingActionRenderer: EditSettingRenderer;
|
||||
private feedbackWidgetRenderer: FeedbackWidgetRenderer;
|
||||
|
||||
private _onUpdatePreference: Emitter<{ key: string, value: any, source: ISetting }> = new Emitter<{ key: string, value: any, source: ISetting }>();
|
||||
public readonly onUpdatePreference: Event<{ key: string, value: any, source: ISetting }> = this._onUpdatePreference.event;
|
||||
private _onUpdatePreference: Emitter<{ key: string, value: any, source: ISetting, index: number }> = new Emitter<{ key: string, value: any, source: ISetting, index: number }>();
|
||||
public readonly onUpdatePreference: Event<{ key: string, value: any, source: ISetting, index: number }> = this._onUpdatePreference.event;
|
||||
|
||||
private _onFocusPreference: Emitter<ISetting> = new Emitter<ISetting>();
|
||||
public readonly onFocusPreference: Event<ISetting> = this._onFocusPreference.event;
|
||||
@@ -251,7 +262,6 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
|
||||
|
||||
constructor(protected editor: ICodeEditor, public readonly preferencesModel: DefaultSettingsEditorModel,
|
||||
@IPreferencesService protected preferencesService: IPreferencesService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IInstantiationService protected instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
@@ -261,14 +271,12 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
|
||||
this.filteredMatchesRenderer = this._register(instantiationService.createInstance(FilteredMatchesRenderer, editor));
|
||||
this.editSettingActionRenderer = this._register(instantiationService.createInstance(EditSettingRenderer, editor, preferencesModel, this.settingHighlighter));
|
||||
this.feedbackWidgetRenderer = this._register(instantiationService.createInstance(FeedbackWidgetRenderer, editor));
|
||||
const parenthesisHidingRenderer = this._register(instantiationService.createInstance(StaticContentHidingRenderer, editor, preferencesModel));
|
||||
this.hiddenAreasRenderer = this._register(instantiationService.createInstance(HiddenAreasRenderer, editor, [this.settingsGroupTitleRenderer, this.filteredMatchesRenderer, parenthesisHidingRenderer]));
|
||||
|
||||
this._register(this.editSettingActionRenderer.onUpdateSetting(e => this._onUpdatePreference.fire(e)));
|
||||
const parenthesisHidingRenderer = this._register(instantiationService.createInstance(StaticContentHidingRenderer, editor, preferencesModel.settingsGroups));
|
||||
|
||||
const hiddenAreasProviders = [this.settingsGroupTitleRenderer, this.filteredMatchesRenderer, parenthesisHidingRenderer];
|
||||
this.hiddenAreasRenderer = this._register(instantiationService.createInstance(HiddenAreasRenderer, editor, hiddenAreasProviders));
|
||||
|
||||
this._register(this.settingsGroupTitleRenderer.onHiddenAreasChanged(() => this.hiddenAreasRenderer.render()));
|
||||
this._register(preferencesModel.onDidChangeGroups(() => this.render()));
|
||||
|
||||
this.onTriggeredFuzzy = this.settingsHeaderRenderer.onClick;
|
||||
}
|
||||
@@ -286,7 +294,6 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
|
||||
this.settingsGroupTitleRenderer.render(this.preferencesModel.settingsGroups);
|
||||
this.editSettingActionRenderer.render(this.preferencesModel.settingsGroups, this._associatedPreferencesModel);
|
||||
this.feedbackWidgetRenderer.render(null);
|
||||
this.hiddenAreasRenderer.render();
|
||||
this.settingHighlighter.clear(true);
|
||||
this.settingsGroupTitleRenderer.showGroup(0);
|
||||
this.hiddenAreasRenderer.render();
|
||||
@@ -356,10 +363,6 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
|
||||
this.settingHighlighter.clear(true);
|
||||
}
|
||||
|
||||
public collapseAll() {
|
||||
this.settingsGroupTitleRenderer.collapseAll();
|
||||
}
|
||||
|
||||
public updatePreference(key: string, value: any, source: ISetting): void {
|
||||
}
|
||||
}
|
||||
@@ -370,7 +373,7 @@ export interface HiddenAreasProvider {
|
||||
|
||||
export class StaticContentHidingRenderer extends Disposable implements HiddenAreasProvider {
|
||||
|
||||
constructor(private editor: ICodeEditor, private settingsGroups: ISettingsGroup[]
|
||||
constructor(private editor: ICodeEditor, private settingsEditorModel: ISettingsEditorModel
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -379,7 +382,8 @@ export class StaticContentHidingRenderer extends Disposable implements HiddenAre
|
||||
const model = this.editor.getModel();
|
||||
|
||||
// Hide extra chars for "search results" and "commonly used" groups
|
||||
const lastGroup = tail(this.settingsGroups);
|
||||
const settingsGroups = this.settingsEditorModel.settingsGroups;
|
||||
const lastGroup = tail(settingsGroups);
|
||||
return [
|
||||
{
|
||||
startLineNumber: 1,
|
||||
@@ -388,10 +392,10 @@ export class StaticContentHidingRenderer extends Disposable implements HiddenAre
|
||||
endColumn: model.getLineMaxColumn(2)
|
||||
},
|
||||
{
|
||||
startLineNumber: this.settingsGroups[0].range.endLineNumber + 1,
|
||||
startColumn: model.getLineMinColumn(this.settingsGroups[0].range.endLineNumber + 1),
|
||||
endLineNumber: this.settingsGroups[0].range.endLineNumber + 4,
|
||||
endColumn: model.getLineMaxColumn(this.settingsGroups[0].range.endLineNumber + 4)
|
||||
startLineNumber: settingsGroups[0].range.endLineNumber + 1,
|
||||
startColumn: model.getLineMinColumn(settingsGroups[0].range.endLineNumber + 1),
|
||||
endLineNumber: settingsGroups[0].range.endLineNumber + 4,
|
||||
endColumn: model.getLineMaxColumn(settingsGroups[0].range.endLineNumber + 4)
|
||||
},
|
||||
{
|
||||
startLineNumber: lastGroup.range.endLineNumber + 1,
|
||||
@@ -415,10 +419,9 @@ class DefaultSettingsHeaderRenderer extends Disposable {
|
||||
private settingsHeaderWidget: DefaultSettingsHeaderWidget;
|
||||
public onClick: Event<void>;
|
||||
|
||||
constructor(private editor: ICodeEditor, scope: ConfigurationScope) {
|
||||
constructor(editor: ICodeEditor, scope: ConfigurationScope) {
|
||||
super();
|
||||
const title = scope === ConfigurationScope.RESOURCE ? nls.localize('defaultFolderSettingsTitle', "Default Folder Settings") : nls.localize('defaultSettingsTitle', "Default Settings");
|
||||
this.settingsHeaderWidget = this._register(new DefaultSettingsHeaderWidget(editor, title));
|
||||
this.settingsHeaderWidget = this._register(new DefaultSettingsHeaderWidget(editor, ''));
|
||||
this.onClick = this.settingsHeaderWidget.onClick;
|
||||
}
|
||||
|
||||
@@ -432,7 +435,7 @@ class DefaultSettingsHeaderRenderer extends Disposable {
|
||||
export class SettingsGroupTitleRenderer extends Disposable implements HiddenAreasProvider {
|
||||
|
||||
private _onHiddenAreasChanged: Emitter<void> = new Emitter<void>();
|
||||
get onHiddenAreasChanged(): Event<void> { return this._onHiddenAreasChanged.event; };
|
||||
get onHiddenAreasChanged(): Event<void> { return this._onHiddenAreasChanged.event; }
|
||||
|
||||
private settingsGroups: ISettingsGroup[];
|
||||
private hiddenGroups: ISettingsGroup[] = [];
|
||||
@@ -494,15 +497,6 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea
|
||||
}
|
||||
}
|
||||
|
||||
public collapseAll() {
|
||||
this.editor.setPosition({ lineNumber: 1, column: 1 });
|
||||
this.hiddenGroups = this.settingsGroups.slice();
|
||||
for (const groupTitleWidget of this.settingsGroupTitleWidgets) {
|
||||
groupTitleWidget.toggleCollapse(true);
|
||||
}
|
||||
this._onHiddenAreasChanged.fire();
|
||||
}
|
||||
|
||||
private onToggled(collapsed: boolean, group: ISettingsGroup) {
|
||||
const index = this.hiddenGroups.indexOf(group);
|
||||
if (collapsed) {
|
||||
@@ -530,8 +524,7 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea
|
||||
|
||||
export class HiddenAreasRenderer extends Disposable {
|
||||
|
||||
constructor(private editor: ICodeEditor, private hiddenAreasProviders: HiddenAreasProvider[],
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
constructor(private editor: ICodeEditor, private hiddenAreasProviders: HiddenAreasProvider[]
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -551,7 +544,12 @@ export class HiddenAreasRenderer extends Disposable {
|
||||
}
|
||||
|
||||
export class FeedbackWidgetRenderer extends Disposable {
|
||||
private static COMMENT_TEXT = 'Modify the below results to match your expectations. Assign scores to indicate their relevance. Replace this comment with any text feedback.';
|
||||
private static readonly DEFAULT_COMMENT_TEXT = 'Replace this comment with any text feedback.';
|
||||
private static readonly INSTRUCTION_TEXT = [
|
||||
'// Modify the "resultScores" section to contain only your expected results. Assign scores to indicate their relevance.',
|
||||
'// Results present in "resultScores" will be automatically "boosted" for this query, if they are not already at the top of the result set.',
|
||||
'// Add phrase pairs to the "alts" section to have them considered to be synonyms in queries.'
|
||||
].join('\n');
|
||||
|
||||
private _feedbackWidget: FloatingClickWidget;
|
||||
private _currentResult: IFilterResult;
|
||||
@@ -560,14 +558,17 @@ export class FeedbackWidgetRenderer extends Disposable {
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@IMessageService private messageService: IMessageService
|
||||
@IMessageService private messageService: IMessageService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@IConfigurationService private configurationService: IConfigurationService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public render(result: IFilterResult): void {
|
||||
const workbenchSettings = this.configurationService.getValue<IWorkbenchSettingsConfiguration>().workbench.settings;
|
||||
this._currentResult = result;
|
||||
if (result && result.metadata) {
|
||||
if (result && result.metadata && workbenchSettings.enableNaturalLanguageSearchFeedback) {
|
||||
this.showWidget();
|
||||
} else if (this._feedbackWidget) {
|
||||
this.disposeWidget();
|
||||
@@ -583,24 +584,29 @@ export class FeedbackWidgetRenderer extends Disposable {
|
||||
}
|
||||
|
||||
private getFeedback(): void {
|
||||
if (!this.telemetryService.isOptedIn) {
|
||||
if (!this.telemetryService.isOptedIn && this.environmentService.appQuality) {
|
||||
this.messageService.show(Severity.Error, 'Can\'t send feedback, user is opted out of telemetry');
|
||||
return;
|
||||
}
|
||||
|
||||
const result = this._currentResult;
|
||||
const actualResultNames = Object.keys(result.metadata.scoredResults);
|
||||
const actualResults = result.metadata.scoredResults;
|
||||
const actualResultNames = Object.keys(actualResults);
|
||||
|
||||
const feedbackQuery = {};
|
||||
feedbackQuery['comment'] = FeedbackWidgetRenderer.COMMENT_TEXT;
|
||||
const feedbackQuery: any = {};
|
||||
feedbackQuery['comment'] = FeedbackWidgetRenderer.DEFAULT_COMMENT_TEXT;
|
||||
feedbackQuery['queryString'] = result.query;
|
||||
feedbackQuery['resultScores'] = {};
|
||||
actualResultNames.forEach(settingKey => {
|
||||
feedbackQuery['resultScores'][settingKey] = 10;
|
||||
});
|
||||
feedbackQuery['alts'] = [];
|
||||
|
||||
const contents = JSON.stringify(feedbackQuery, undefined, ' ');
|
||||
this.editorService.openEditor({ contents, language: 'json' }, /*sideBySide=*/true).then(feedbackEditor => {
|
||||
const contents = FeedbackWidgetRenderer.INSTRUCTION_TEXT + '\n' +
|
||||
JSON.stringify(feedbackQuery, undefined, ' ') + '\n\n' +
|
||||
actualResultNames.map(name => `// ${name}: ${result.metadata.scoredResults[name]}`).join('\n');
|
||||
|
||||
this.editorService.openEditor({ contents, language: 'jsonc' }, /*sideBySide=*/true).then(feedbackEditor => {
|
||||
const sendFeedbackWidget = this._register(this.instantiationService.createInstance(FloatingClickWidget, feedbackEditor.getControl(), 'Send feedback', null));
|
||||
sendFeedbackWidget.render();
|
||||
|
||||
@@ -617,7 +623,9 @@ export class FeedbackWidgetRenderer extends Disposable {
|
||||
|
||||
private sendFeedback(feedbackEditor: ICodeEditor, result: IFilterResult, actualResults: IScoredResults): TPromise<void> {
|
||||
const model = feedbackEditor.getModel();
|
||||
const expectedQueryLines = model.getLinesContent();
|
||||
const expectedQueryLines = model.getLinesContent()
|
||||
.filter(line => !strings.startsWith(line, '//'));
|
||||
|
||||
let expectedQuery: any;
|
||||
try {
|
||||
expectedQuery = JSON.parse(expectedQueryLines.join('\n'));
|
||||
@@ -626,7 +634,17 @@ export class FeedbackWidgetRenderer extends Disposable {
|
||||
return TPromise.wrapError(new Error('Invalid JSON: ' + e.message));
|
||||
}
|
||||
|
||||
const userComment = expectedQuery.comment === FeedbackWidgetRenderer.COMMENT_TEXT ? undefined : expectedQuery.comment;
|
||||
const userComment = expectedQuery.comment === FeedbackWidgetRenderer.DEFAULT_COMMENT_TEXT ? undefined : expectedQuery.comment;
|
||||
|
||||
// validate alts
|
||||
if (!this.validateAlts(expectedQuery.alts)) {
|
||||
return TPromise.wrapError(new Error('alts must be an array of 2-element string arrays'));
|
||||
}
|
||||
|
||||
const altsAdded = expectedQuery.alts && expectedQuery.alts.length;
|
||||
const alts = altsAdded ? expectedQuery.alts : undefined;
|
||||
const workbenchSettings = this.configurationService.getValue<IWorkbenchSettingsConfiguration>().workbench.settings;
|
||||
const autoIngest = workbenchSettings.naturalLanguageSearchAutoIngestFeedback;
|
||||
|
||||
/* __GDPR__
|
||||
"settingsSearchResultFeedback" : {
|
||||
@@ -646,10 +664,33 @@ export class FeedbackWidgetRenderer extends Disposable {
|
||||
expectedResults: expectedQuery.resultScores,
|
||||
url: result.metadata.remoteUrl,
|
||||
duration: result.metadata.duration,
|
||||
timestamp: result.metadata.timestamp
|
||||
timestamp: result.metadata.timestamp,
|
||||
buildNumber: this.environmentService.settingsSearchBuildId,
|
||||
alts,
|
||||
autoIngest
|
||||
});
|
||||
}
|
||||
|
||||
private validateAlts(alts?: string[][]): boolean {
|
||||
if (!alts) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Array.isArray(alts)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!alts.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!alts.every(altPair => Array.isArray(altPair) && altPair.length === 2 && typeof altPair[0] === 'string' && typeof altPair[1] === 'string')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private disposeWidget(): void {
|
||||
if (this._feedbackWidget) {
|
||||
this._feedbackWidget.dispose();
|
||||
@@ -669,8 +710,7 @@ export class FilteredMatchesRenderer extends Disposable implements HiddenAreasPr
|
||||
private decorationIds: string[] = [];
|
||||
public hiddenAreas: IRange[] = [];
|
||||
|
||||
constructor(private editor: ICodeEditor,
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
constructor(private editor: ICodeEditor
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -773,8 +813,7 @@ export class HighlightMatchesRenderer extends Disposable {
|
||||
|
||||
private decorationIds: string[] = [];
|
||||
|
||||
constructor(private editor: ICodeEditor,
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
constructor(private editor: ICodeEditor
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -791,7 +830,7 @@ export class HighlightMatchesRenderer extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private static _FIND_MATCH = ModelDecorationOptions.register({
|
||||
private static readonly _FIND_MATCH = ModelDecorationOptions.register({
|
||||
stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
className: 'findMatch'
|
||||
});
|
||||
@@ -813,21 +852,24 @@ export class HighlightMatchesRenderer extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
interface IIndexedSetting extends ISetting {
|
||||
index: number;
|
||||
}
|
||||
|
||||
class EditSettingRenderer extends Disposable {
|
||||
|
||||
private editPreferenceWidgetForCusorPosition: EditPreferenceWidget<ISetting>;
|
||||
private editPreferenceWidgetForMouseMove: EditPreferenceWidget<ISetting>;
|
||||
private editPreferenceWidgetForCusorPosition: EditPreferenceWidget<IIndexedSetting>;
|
||||
private editPreferenceWidgetForMouseMove: EditPreferenceWidget<IIndexedSetting>;
|
||||
|
||||
private settingsGroups: ISettingsGroup[];
|
||||
public associatedPreferencesModel: IPreferencesEditorModel<ISetting>;
|
||||
private toggleEditPreferencesForMouseMoveDelayer: Delayer<void>;
|
||||
|
||||
private _onUpdateSetting: Emitter<{ key: string, value: any, source: ISetting }> = new Emitter<{ key: string, value: any, source: ISetting }>();
|
||||
public readonly onUpdateSetting: Event<{ key: string, value: any, source: ISetting }> = this._onUpdateSetting.event;
|
||||
private _onUpdateSetting: Emitter<{ key: string, value: any, source: ISetting, index: number }> = new Emitter<{ key: string, value: any, source: ISetting, index: number }>();
|
||||
public readonly onUpdateSetting: Event<{ key: string, value: any, source: ISetting, index: number }> = this._onUpdateSetting.event;
|
||||
|
||||
constructor(private editor: ICodeEditor, private masterSettingsModel: ISettingsEditorModel,
|
||||
private settingHighlighter: SettingHighlighter,
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IContextMenuService private contextMenuService: IContextMenuService
|
||||
) {
|
||||
@@ -885,7 +927,7 @@ class EditSettingRenderer extends Disposable {
|
||||
return;
|
||||
}
|
||||
this.settingHighlighter.clear();
|
||||
this.toggleEditPreferencesForMouseMoveDelayer.trigger(() => this.toggleEidtPreferenceWidgetForMouseMove(mouseMoveEvent));
|
||||
this.toggleEditPreferencesForMouseMoveDelayer.trigger(() => this.toggleEditPreferenceWidgetForMouseMove(mouseMoveEvent));
|
||||
}
|
||||
|
||||
private getEditPreferenceWidgetUnderMouse(mouseMoveEvent: IEditorMouseEvent): EditPreferenceWidget<ISetting> {
|
||||
@@ -901,7 +943,7 @@ class EditSettingRenderer extends Disposable {
|
||||
return null;
|
||||
}
|
||||
|
||||
private toggleEidtPreferenceWidgetForMouseMove(mouseMoveEvent: IEditorMouseEvent): void {
|
||||
private toggleEditPreferenceWidgetForMouseMove(mouseMoveEvent: IEditorMouseEvent): void {
|
||||
const settings = mouseMoveEvent.target.position ? this.getSettings(mouseMoveEvent.target.position.lineNumber) : null;
|
||||
if (settings && settings.length) {
|
||||
this.showEditPreferencesWidget(this.editPreferenceWidgetForMouseMove, settings);
|
||||
@@ -910,7 +952,7 @@ class EditSettingRenderer extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private showEditPreferencesWidget(editPreferencesWidget: EditPreferenceWidget<ISetting>, settings: ISetting[]) {
|
||||
private showEditPreferencesWidget(editPreferencesWidget: EditPreferenceWidget<ISetting>, settings: IIndexedSetting[]) {
|
||||
const line = settings[0].valueRange.startLineNumber;
|
||||
if (this.editor.getConfiguration().viewInfo.glyphMargin && this.marginFreeFromOtherDecorations(line)) {
|
||||
editPreferencesWidget.show(line, nls.localize('editTtile', "Edit"), settings);
|
||||
@@ -931,7 +973,7 @@ class EditSettingRenderer extends Disposable {
|
||||
return true;
|
||||
}
|
||||
|
||||
private getSettings(lineNumber: number): ISetting[] {
|
||||
private getSettings(lineNumber: number): IIndexedSetting[] {
|
||||
const configurationMap = this.getConfigurationsMap();
|
||||
return this.getSettingsAtLineNumber(lineNumber).filter(setting => {
|
||||
let configurationNode = configurationMap[setting.key];
|
||||
@@ -956,7 +998,10 @@ class EditSettingRenderer extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private getSettingsAtLineNumber(lineNumber: number): ISetting[] {
|
||||
private getSettingsAtLineNumber(lineNumber: number): IIndexedSetting[] {
|
||||
// index of setting, across all groups/sections
|
||||
let index = 0;
|
||||
|
||||
const settings = [];
|
||||
for (const group of this.settingsGroups) {
|
||||
if (group.range.startLineNumber > lineNumber) {
|
||||
@@ -973,13 +1018,15 @@ class EditSettingRenderer extends Disposable {
|
||||
// Only one level because override settings cannot have override settings
|
||||
for (const overrideSetting of setting.overrides) {
|
||||
if (lineNumber >= overrideSetting.range.startLineNumber && lineNumber <= overrideSetting.range.endLineNumber) {
|
||||
settings.push(overrideSetting);
|
||||
settings.push({ ...overrideSetting, index });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
settings.push(setting);
|
||||
settings.push({ ...setting, index });
|
||||
}
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -991,7 +1038,7 @@ class EditSettingRenderer extends Disposable {
|
||||
this.settingHighlighter.highlight(editPreferenceWidget.preferences[0]);
|
||||
}
|
||||
|
||||
private onEditSettingClicked(editPreferenceWidget: EditPreferenceWidget<ISetting>, e: IEditorMouseEvent): void {
|
||||
private onEditSettingClicked(editPreferenceWidget: EditPreferenceWidget<IIndexedSetting>, e: IEditorMouseEvent): void {
|
||||
const anchor = { x: e.event.posx, y: e.event.posy + 10 };
|
||||
const actions = this.getSettings(editPreferenceWidget.getLine()).length === 1 ? this.getActions(editPreferenceWidget.preferences[0], this.getConfigurationsMap()[editPreferenceWidget.preferences[0].key])
|
||||
: editPreferenceWidget.preferences.map(setting => new ContextSubMenu(setting.key, this.getActions(setting, this.getConfigurationsMap()[setting.key])));
|
||||
@@ -1005,7 +1052,7 @@ class EditSettingRenderer extends Disposable {
|
||||
return Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
|
||||
}
|
||||
|
||||
private getActions(setting: ISetting, jsonSchema: IJSONSchema): IAction[] {
|
||||
private getActions(setting: IIndexedSetting, jsonSchema: IJSONSchema): IAction[] {
|
||||
if (jsonSchema.type === 'boolean') {
|
||||
return [<IAction>{
|
||||
id: 'truthyValue',
|
||||
@@ -1032,7 +1079,7 @@ class EditSettingRenderer extends Disposable {
|
||||
return this.getDefaultActions(setting);
|
||||
}
|
||||
|
||||
private getDefaultActions(setting: ISetting): IAction[] {
|
||||
private getDefaultActions(setting: IIndexedSetting): IAction[] {
|
||||
if (this.isDefaultSettings()) {
|
||||
const settingInOtherModel = this.associatedPreferencesModel.getPreference(setting.key);
|
||||
return [<IAction>{
|
||||
@@ -1045,8 +1092,8 @@ class EditSettingRenderer extends Disposable {
|
||||
return [];
|
||||
}
|
||||
|
||||
private updateSetting(key: string, value: any, source: ISetting): void {
|
||||
this._onUpdateSetting.fire({ key, value, source });
|
||||
private updateSetting(key: string, value: any, source: IIndexedSetting): void {
|
||||
this._onUpdateSetting.fire({ key, value, source, index: source.index });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1056,7 +1103,7 @@ class SettingHighlighter extends Disposable {
|
||||
private volatileHighlighter: RangeHighlightDecorations;
|
||||
private highlightedSetting: ISetting;
|
||||
|
||||
constructor(private editor: editorCommon.ICommonCodeEditor, private focusEventEmitter: Emitter<ISetting>, private clearFocusEventEmitter: Emitter<ISetting>,
|
||||
constructor(private editor: ICodeEditor, private focusEventEmitter: Emitter<ISetting>, private clearFocusEventEmitter: Emitter<ISetting>,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
@@ -1096,9 +1143,8 @@ class UnsupportedSettingsRenderer extends Disposable {
|
||||
private renderingDelayer: Delayer<void> = new Delayer<void>(200);
|
||||
|
||||
constructor(
|
||||
private editor: editorCommon.ICommonCodeEditor,
|
||||
private editor: ICodeEditor,
|
||||
private settingsEditorModel: SettingsEditorModel,
|
||||
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
|
||||
@IMarkerService private markerService: IMarkerService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService
|
||||
) {
|
||||
@@ -1174,14 +1220,14 @@ class UnsupportedSettingsRenderer extends Disposable {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private static _DIM_CONFIGUARATION_ = ModelDecorationOptions.register({
|
||||
private static readonly _DIM_CONFIGUARATION_ = ModelDecorationOptions.register({
|
||||
stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
inlineClassName: 'dim-configuration',
|
||||
beforeContentClassName: 'unsupportedWorkbenhSettingInfo',
|
||||
hoverMessage: new MarkdownString().appendText(nls.localize('unsupportedWorkbenchSetting', "This setting cannot be applied now. It will be applied when you open this folder directly."))
|
||||
});
|
||||
|
||||
private static _DIM_CONFIGUARATION_DEV_MODE = ModelDecorationOptions.register({
|
||||
private static readonly _DIM_CONFIGUARATION_DEV_MODE = ModelDecorationOptions.register({
|
||||
stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
inlineClassName: 'dim-configuration',
|
||||
beforeContentClassName: 'unsupportedWorkbenhSettingInfo',
|
||||
@@ -1194,7 +1240,7 @@ class WorkspaceConfigurationRenderer extends Disposable {
|
||||
private decorationIds: string[] = [];
|
||||
private renderingDelayer: Delayer<void> = new Delayer<void>(200);
|
||||
|
||||
constructor(private editor: editorCommon.ICommonCodeEditor, private workspaceSettingsEditorModel: SettingsEditorModel,
|
||||
constructor(private editor: ICodeEditor, private workspaceSettingsEditorModel: SettingsEditorModel,
|
||||
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService
|
||||
) {
|
||||
super();
|
||||
@@ -1224,7 +1270,7 @@ class WorkspaceConfigurationRenderer extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private static _DIM_CONFIGURATION_ = ModelDecorationOptions.register({
|
||||
private static readonly _DIM_CONFIGURATION_ = ModelDecorationOptions.register({
|
||||
stickiness: editorCommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
|
||||
inlineClassName: 'dim-configuration'
|
||||
});
|
||||
|
||||
@@ -1,326 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { ISettingsEditorModel, IFilterResult, ISetting, ISettingsGroup, IWorkbenchSettingsConfiguration, IFilterMetadata } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { distinct } from 'vs/base/common/arrays';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters';
|
||||
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
export interface IEndpointDetails {
|
||||
urlBase: string;
|
||||
key: string;
|
||||
boost: number;
|
||||
}
|
||||
|
||||
export class PreferencesSearchProvider {
|
||||
private _onRemoteSearchEnablementChanged = new Emitter<boolean>();
|
||||
public onRemoteSearchEnablementChanged: Event<boolean> = this._onRemoteSearchEnablementChanged.event;
|
||||
|
||||
constructor(
|
||||
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService
|
||||
) {
|
||||
configurationService.onDidChangeConfiguration(() => this._onRemoteSearchEnablementChanged.fire(this.remoteSearchEnabled));
|
||||
}
|
||||
|
||||
get remoteSearchEnabled(): boolean {
|
||||
if (this.environmentService.appQuality === 'stable') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const endpoint = this.endpoint;
|
||||
return !!endpoint.urlBase && !!endpoint.key;
|
||||
}
|
||||
|
||||
get endpoint(): IEndpointDetails {
|
||||
const workbenchSettings = this.configurationService.getConfiguration<IWorkbenchSettingsConfiguration>().workbench.settings;
|
||||
return {
|
||||
urlBase: workbenchSettings.experimentalFuzzySearchEndpoint,
|
||||
key: workbenchSettings.experimentalFuzzySearchKey,
|
||||
boost: workbenchSettings.experimentalFuzzySearchBoost
|
||||
};
|
||||
}
|
||||
|
||||
startSearch(filter: string, remote: boolean): PreferencesSearchModel {
|
||||
return new PreferencesSearchModel(this, filter, remote);
|
||||
}
|
||||
}
|
||||
|
||||
export class PreferencesSearchModel {
|
||||
private _localProvider: LocalSearchProvider;
|
||||
private _remoteProvider: RemoteSearchProvider;
|
||||
|
||||
constructor(private provider: PreferencesSearchProvider, private filter: string, remote: boolean) {
|
||||
this._localProvider = new LocalSearchProvider(filter);
|
||||
|
||||
if (remote && filter) {
|
||||
this._remoteProvider = new RemoteSearchProvider(filter, this.provider.endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
filterPreferences(preferencesModel: ISettingsEditorModel): TPromise<IFilterResult> {
|
||||
if (!this.filter) {
|
||||
return TPromise.wrap(null);
|
||||
}
|
||||
|
||||
if (this._remoteProvider) {
|
||||
return this._remoteProvider.filterPreferences(preferencesModel).then(null, err => {
|
||||
return this._localProvider.filterPreferences(preferencesModel);
|
||||
});
|
||||
} else {
|
||||
return this._localProvider.filterPreferences(preferencesModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LocalSearchProvider {
|
||||
private _filter: string;
|
||||
|
||||
constructor(filter: string) {
|
||||
this._filter = filter;
|
||||
}
|
||||
|
||||
filterPreferences(preferencesModel: ISettingsEditorModel): TPromise<IFilterResult> {
|
||||
const regex = strings.createRegExp(this._filter, false, { global: true });
|
||||
|
||||
const groupFilter = (group: ISettingsGroup) => {
|
||||
return regex.test(group.title);
|
||||
};
|
||||
|
||||
const settingFilter = (setting: ISetting) => {
|
||||
return new SettingMatches(this._filter, setting, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches;
|
||||
};
|
||||
|
||||
return TPromise.wrap(preferencesModel.filterSettings(this._filter, groupFilter, settingFilter));
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteSearchProvider {
|
||||
private _filter: string;
|
||||
private _remoteSearchP: TPromise<IFilterMetadata>;
|
||||
|
||||
constructor(filter: string, endpoint: IEndpointDetails) {
|
||||
this._filter = filter;
|
||||
this._remoteSearchP = filter ? getSettingsFromBing(filter, endpoint) : TPromise.wrap(null);
|
||||
}
|
||||
|
||||
filterPreferences(preferencesModel: ISettingsEditorModel): TPromise<IFilterResult> {
|
||||
return this._remoteSearchP.then(remoteResult => {
|
||||
const settingFilter = (setting: ISetting) => {
|
||||
if (!!remoteResult.scoredResults[setting.key]) {
|
||||
const settingMatches = new SettingMatches(this._filter, setting, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches;
|
||||
if (settingMatches.length) {
|
||||
return settingMatches;
|
||||
} else {
|
||||
return [new Range(setting.keyRange.startLineNumber, setting.keyRange.startColumn, setting.keyRange.endLineNumber, setting.keyRange.startColumn)];
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
if (remoteResult) {
|
||||
const sortedNames = Object.keys(remoteResult.scoredResults).sort((a, b) => remoteResult.scoredResults[b] - remoteResult.scoredResults[a]);
|
||||
const result = preferencesModel.filterSettings(this._filter, group => null, settingFilter, sortedNames);
|
||||
result.metadata = remoteResult;
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getSettingsFromBing(filter: string, endpoint: IEndpointDetails): TPromise<IFilterMetadata> {
|
||||
const url = prepareUrl(filter, endpoint);
|
||||
console.log('fetching: ' + url);
|
||||
const start = Date.now();
|
||||
const p = fetch(url, {
|
||||
headers: new Headers({
|
||||
'User-Agent': 'request',
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'api-key': endpoint.key
|
||||
})
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(result => {
|
||||
const timestamp = Date.now();
|
||||
const duration = timestamp - start;
|
||||
console.log('time: ' + duration / 1000);
|
||||
const suggestions = (result.value || [])
|
||||
.map(r => ({
|
||||
name: r.setting || r.Setting,
|
||||
score: r['@search.score']
|
||||
}));
|
||||
|
||||
const scoredResults = Object.create(null);
|
||||
suggestions.forEach(s => {
|
||||
const name = s.name
|
||||
.replace(/^"/, '')
|
||||
.replace(/"$/, '');
|
||||
scoredResults[name] = s.score;
|
||||
});
|
||||
|
||||
return <IFilterMetadata>{
|
||||
remoteUrl: url,
|
||||
duration,
|
||||
timestamp,
|
||||
scoredResults
|
||||
};
|
||||
});
|
||||
|
||||
return TPromise.as(p as any);
|
||||
}
|
||||
|
||||
const API_VERSION = 'api-version=2016-09-01-Preview';
|
||||
const QUERY_TYPE = 'querytype=full';
|
||||
const SCORING_PROFILE = 'scoringProfile=ranking';
|
||||
|
||||
function escapeSpecialChars(query: string): string {
|
||||
return query.replace(/\./g, ' ')
|
||||
.replace(/[\\/+\-&|!"~*?:(){}\[\]\^]/g, '\\$&')
|
||||
.replace(/ /g, ' ') // collapse spaces
|
||||
.trim();
|
||||
}
|
||||
|
||||
function prepareUrl(query: string, endpoint: IEndpointDetails): string {
|
||||
query = escapeSpecialChars(query);
|
||||
const boost = endpoint.boost || 1;
|
||||
const userQuery = `(${query})^${boost}`;
|
||||
|
||||
// Appending Fuzzy after each word.
|
||||
query = query.replace(/\ +/g, '~ ') + '~';
|
||||
|
||||
return `${endpoint.urlBase}?${API_VERSION}&search=${encodeURIComponent(userQuery + ' || ' + query)}&${QUERY_TYPE}&${SCORING_PROFILE}`;
|
||||
}
|
||||
|
||||
class SettingMatches {
|
||||
|
||||
private readonly descriptionMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
|
||||
private readonly keyMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
|
||||
private readonly valueMatchingWords: Map<string, IRange[]> = new Map<string, IRange[]>();
|
||||
|
||||
public readonly matches: IRange[];
|
||||
|
||||
constructor(searchString: string, setting: ISetting, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) {
|
||||
this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`);
|
||||
}
|
||||
|
||||
private _findMatchesInSetting(searchString: string, setting: ISetting): IRange[] {
|
||||
const result = this._doFindMatchesInSetting(searchString, setting);
|
||||
if (setting.overrides && setting.overrides.length) {
|
||||
for (const subSetting of setting.overrides) {
|
||||
const subSettingMatches = new SettingMatches(searchString, subSetting, this.valuesMatcher);
|
||||
let words = searchString.split(' ');
|
||||
const descriptionRanges: IRange[] = this.getRangesForWords(words, this.descriptionMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]);
|
||||
const keyRanges: IRange[] = this.getRangesForWords(words, this.keyMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]);
|
||||
const subSettingKeyRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.keyMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.valueMatchingWords]);
|
||||
const subSettinValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]);
|
||||
result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettinValueRanges);
|
||||
result.push(...subSettingMatches.matches);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private _doFindMatchesInSetting(searchString: string, setting: ISetting): IRange[] {
|
||||
const registry: { [qualifiedKey: string]: IJSONSchema } = Registry.as<IConfigurationRegistry>(Extensions.Configuration).getConfigurationProperties();
|
||||
const schema: IJSONSchema = registry[setting.key];
|
||||
|
||||
let words = searchString.split(' ');
|
||||
const settingKeyAsWords: string = setting.key.split('.').join(' ');
|
||||
|
||||
for (const word of words) {
|
||||
for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) {
|
||||
const descriptionMatches = matchesWords(word, setting.description[lineIndex], true);
|
||||
if (descriptionMatches) {
|
||||
this.descriptionMatchingWords.set(word, descriptionMatches.map(match => this.toDescriptionRange(setting, match, lineIndex)));
|
||||
}
|
||||
}
|
||||
|
||||
const keyMatches = or(matchesWords, matchesCamelCase)(word, settingKeyAsWords);
|
||||
if (keyMatches) {
|
||||
this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match)));
|
||||
}
|
||||
|
||||
const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null;
|
||||
if (valueMatches) {
|
||||
this.valueMatchingWords.set(word, valueMatches.map(match => this.toValueRange(setting, match)));
|
||||
} else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) {
|
||||
this.valueMatchingWords.set(word, []);
|
||||
}
|
||||
}
|
||||
|
||||
const descriptionRanges: IRange[] = [];
|
||||
for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) {
|
||||
const matches = or(matchesContiguousSubString)(searchString, setting.description[lineIndex] || '') || [];
|
||||
descriptionRanges.push(...matches.map(match => this.toDescriptionRange(setting, match, lineIndex)));
|
||||
}
|
||||
if (descriptionRanges.length === 0) {
|
||||
descriptionRanges.push(...this.getRangesForWords(words, this.descriptionMatchingWords, [this.keyMatchingWords, this.valueMatchingWords]));
|
||||
}
|
||||
|
||||
const keyMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.key);
|
||||
const keyRanges: IRange[] = keyMatches ? keyMatches.map(match => this.toKeyRange(setting, match)) : this.getRangesForWords(words, this.keyMatchingWords, [this.descriptionMatchingWords, this.valueMatchingWords]);
|
||||
|
||||
let valueRanges: IRange[] = [];
|
||||
if (setting.value && typeof setting.value === 'string') {
|
||||
const valueMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.value);
|
||||
valueRanges = valueMatches ? valueMatches.map(match => this.toValueRange(setting, match)) : this.getRangesForWords(words, this.valueMatchingWords, [this.keyMatchingWords, this.descriptionMatchingWords]);
|
||||
} else {
|
||||
valueRanges = this.valuesMatcher(searchString, setting);
|
||||
}
|
||||
|
||||
return [...descriptionRanges, ...keyRanges, ...valueRanges];
|
||||
}
|
||||
|
||||
private getRangesForWords(words: string[], from: Map<string, IRange[]>, others: Map<string, IRange[]>[]): IRange[] {
|
||||
const result: IRange[] = [];
|
||||
for (const word of words) {
|
||||
const ranges = from.get(word);
|
||||
if (ranges) {
|
||||
result.push(...ranges);
|
||||
} else if (others.every(o => !o.has(word))) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private toKeyRange(setting: ISetting, match: IMatch): IRange {
|
||||
return {
|
||||
startLineNumber: setting.keyRange.startLineNumber,
|
||||
startColumn: setting.keyRange.startColumn + match.start,
|
||||
endLineNumber: setting.keyRange.startLineNumber,
|
||||
endColumn: setting.keyRange.startColumn + match.end
|
||||
};
|
||||
}
|
||||
|
||||
private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange {
|
||||
return {
|
||||
startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber,
|
||||
startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start,
|
||||
endLineNumber: setting.descriptionRanges[lineIndex].endLineNumber,
|
||||
endColumn: setting.descriptionRanges[lineIndex].startColumn + match.end
|
||||
};
|
||||
}
|
||||
|
||||
private toValueRange(setting: ISetting, match: IMatch): IRange {
|
||||
return {
|
||||
startLineNumber: setting.valueRange.startLineNumber,
|
||||
startColumn: setting.valueRange.startColumn + match.start + 1,
|
||||
endLineNumber: setting.valueRange.startLineNumber,
|
||||
endColumn: setting.valueRange.startColumn + match.end + 1
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -17,21 +17,19 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { Position as EditorPosition, IEditor, IEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { ICommonCodeEditor, IModel } from 'vs/editor/common/editorCommon';
|
||||
import { IModel } from 'vs/editor/common/editorCommon';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IFileService, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||
import { IMessageService, Severity, IChoiceService } from 'vs/platform/message/common/message';
|
||||
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
|
||||
import { IMessageService, Severity } from 'vs/platform/message/common/message';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IPreferencesService, IPreferencesEditorModel, ISetting, getSettingsTargetName, FOLDER_SETTINGS_PATH, DEFAULT_SETTINGS_EDITOR_SETTING } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, DefaultSettingsModel, WorkspaceConfigurationEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels';
|
||||
import { SettingsEditorModel, DefaultSettingsEditorModel, DefaultKeybindingsEditorModel, defaultKeybindingsContents, DefaultSettings, WorkspaceConfigurationEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { DefaultPreferencesEditorInput, PreferencesEditorInput } from 'vs/workbench/parts/preferences/browser/preferencesEditor';
|
||||
import { KeybindingsEditorInput } from 'vs/workbench/parts/preferences/browser/keybindingsEditor';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { getCodeEditor } from 'vs/editor/common/services/codeEditorService';
|
||||
import { getCodeEditor } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position, IPosition } from 'vs/editor/common/core/position';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
@@ -41,6 +39,7 @@ import { ConfigurationScope } from 'vs/platform/configuration/common/configurati
|
||||
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { parse } from 'vs/base/common/json';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
|
||||
const emptyEditableSettingsContent = '{\n}';
|
||||
|
||||
@@ -53,9 +52,9 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
private _onDispose: Emitter<void> = new Emitter<void>();
|
||||
|
||||
private _defaultSettingsUriCounter = 0;
|
||||
private _defaultSettingsContentModel: DefaultSettingsModel;
|
||||
private _defaultSettingsContentModel: DefaultSettings;
|
||||
private _defaultResourceSettingsUriCounter = 0;
|
||||
private _defaultResourceSettingsContentModel: DefaultSettingsModel;
|
||||
private _defaultResourceSettingsContentModel: DefaultSettings;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@@ -63,14 +62,11 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
@IFileService private fileService: IFileService,
|
||||
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
|
||||
@IMessageService private messageService: IMessageService,
|
||||
@IChoiceService private choiceService: IChoiceService,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IStorageService private storageService: IStorageService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@ITextModelService private textModelResolverService: ITextModelService,
|
||||
@IExtensionService private extensionService: IExtensionService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IModelService private modelService: IModelService,
|
||||
@IJSONEditingService private jsonEditingService: IJSONEditingService,
|
||||
@@ -97,6 +93,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
}
|
||||
|
||||
readonly defaultKeybindingsResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/keybindings.json' });
|
||||
private readonly defaultSettingsRawResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/defaultSettings.json' });
|
||||
|
||||
get userSettingsResource(): URI {
|
||||
return this.getEditableSettingsURI(ConfigurationTarget.USER);
|
||||
@@ -112,19 +109,44 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
|
||||
resolveModel(uri: URI): TPromise<IModel> {
|
||||
if (this.isDefaultSettingsResource(uri) || this.isDefaultResourceSettingsResource(uri)) {
|
||||
return this.extensionService.onReady()
|
||||
.then(() => {
|
||||
const scope = this.isDefaultSettingsResource(uri) ? ConfigurationScope.WINDOW : ConfigurationScope.RESOURCE;
|
||||
const settingsModel = this.getDefaultSettingsModel(scope);
|
||||
const mode = this.modeService.getOrCreateMode('json');
|
||||
const model = this._register(this.modelService.createModel(settingsModel.content, mode, uri));
|
||||
return model;
|
||||
});
|
||||
|
||||
const scope = this.isDefaultSettingsResource(uri) ? ConfigurationScope.WINDOW : ConfigurationScope.RESOURCE;
|
||||
const mode = this.modeService.getOrCreateMode('jsonc');
|
||||
const model = this._register(this.modelService.createModel('', mode, uri));
|
||||
|
||||
let defaultSettings: DefaultSettings;
|
||||
this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.source === ConfigurationTarget.DEFAULT) {
|
||||
const model = this.modelService.getModel(uri);
|
||||
if (!model) {
|
||||
// model has not been given out => nothing to do
|
||||
return;
|
||||
}
|
||||
defaultSettings = this.getDefaultSettings(scope);
|
||||
this.modelService.updateModel(model, defaultSettings.parse());
|
||||
defaultSettings._onDidChange.fire();
|
||||
}
|
||||
});
|
||||
|
||||
// Check if Default settings is already created and updated in above promise
|
||||
if (!defaultSettings) {
|
||||
defaultSettings = this.getDefaultSettings(scope);
|
||||
this.modelService.updateModel(model, defaultSettings.parse());
|
||||
}
|
||||
|
||||
return TPromise.as(model);
|
||||
}
|
||||
|
||||
if (this.defaultSettingsRawResource.toString() === uri.toString()) {
|
||||
let defaultSettings: DefaultSettings = this.getDefaultSettings(ConfigurationScope.WINDOW);
|
||||
const mode = this.modeService.getOrCreateMode('jsonc');
|
||||
const model = this._register(this.modelService.createModel(defaultSettings.raw, mode, uri));
|
||||
return TPromise.as(model);
|
||||
}
|
||||
|
||||
if (this.defaultKeybindingsResource.toString() === uri.toString()) {
|
||||
const defaultKeybindingsEditorModel = this.instantiationService.createInstance(DefaultKeybindingsEditorModel, uri);
|
||||
const mode = this.modeService.getOrCreateMode('json');
|
||||
const mode = this.modeService.getOrCreateMode('jsonc');
|
||||
const model = this._register(this.modelService.createModel(defaultKeybindingsEditorModel.content, mode, uri));
|
||||
return TPromise.as(model);
|
||||
}
|
||||
@@ -153,6 +175,10 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
return TPromise.wrap<IPreferencesEditorModel<any>>(null);
|
||||
}
|
||||
|
||||
openRawDefaultSettings(): TPromise<void> {
|
||||
return this.editorService.openEditor({ resource: this.defaultSettingsRawResource }, EditorPosition.ONE) as TPromise<any>;
|
||||
}
|
||||
|
||||
openGlobalSettings(options?: IEditorOptions, position?: EditorPosition): TPromise<IEditor> {
|
||||
return this.doOpenSettings(ConfigurationTarget.USER, this.userSettingsResource, options, position);
|
||||
}
|
||||
@@ -290,20 +316,20 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
return this.textModelResolverService.createModelReference(defaultSettingsUri)
|
||||
.then(reference => {
|
||||
const scope = this.isDefaultSettingsResource(defaultSettingsUri) ? ConfigurationScope.WINDOW : ConfigurationScope.RESOURCE;
|
||||
return this.instantiationService.createInstance(DefaultSettingsEditorModel, defaultSettingsUri, reference, scope, this.getDefaultSettingsModel(scope).settingsGroups);
|
||||
return this.instantiationService.createInstance(DefaultSettingsEditorModel, defaultSettingsUri, reference, scope, this.getDefaultSettings(scope));
|
||||
});
|
||||
}
|
||||
|
||||
private getDefaultSettingsModel(scope: ConfigurationScope): DefaultSettingsModel {
|
||||
private getDefaultSettings(scope: ConfigurationScope): DefaultSettings {
|
||||
switch (scope) {
|
||||
case ConfigurationScope.WINDOW:
|
||||
if (!this._defaultSettingsContentModel) {
|
||||
this._defaultSettingsContentModel = new DefaultSettingsModel(this.getMostCommonlyUsedSettings(), scope);
|
||||
this._defaultSettingsContentModel = new DefaultSettings(this.getMostCommonlyUsedSettings(), scope);
|
||||
}
|
||||
return this._defaultSettingsContentModel;
|
||||
case ConfigurationScope.RESOURCE:
|
||||
if (!this._defaultResourceSettingsContentModel) {
|
||||
this._defaultResourceSettingsContentModel = new DefaultSettingsModel(this.getMostCommonlyUsedSettings(), scope);
|
||||
this._defaultResourceSettingsContentModel = new DefaultSettings(this.getMostCommonlyUsedSettings(), scope);
|
||||
}
|
||||
return this._defaultResourceSettingsContentModel;
|
||||
}
|
||||
@@ -367,22 +393,22 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
];
|
||||
}
|
||||
|
||||
private getPosition(language: string, codeEditor: ICommonCodeEditor): TPromise<IPosition> {
|
||||
private getPosition(language: string, codeEditor: ICodeEditor): TPromise<IPosition> {
|
||||
return this.createPreferencesEditorModel(this.userSettingsResource)
|
||||
.then((settingsModel: IPreferencesEditorModel<ISetting>) => {
|
||||
const languageKey = `[${language}]`;
|
||||
let setting = settingsModel.getPreference(languageKey);
|
||||
const model = codeEditor.getModel();
|
||||
const configuration = this.configurationService.getConfiguration<{ tabSize: number; insertSpaces: boolean }>('editor');
|
||||
const { eol } = this.configurationService.getConfiguration<{ eol: string }>('files');
|
||||
const configuration = this.configurationService.getValue<{ editor: { tabSize: number; insertSpaces: boolean }, files: { eol: string } }>();
|
||||
const eol = configuration.files && configuration.files.eol;
|
||||
if (setting) {
|
||||
if (setting.overrides.length) {
|
||||
const lastSetting = setting.overrides[setting.overrides.length - 1];
|
||||
let content;
|
||||
if (lastSetting.valueRange.endLineNumber === setting.range.endLineNumber) {
|
||||
content = ',' + eol + this.spaces(2, configuration) + eol + this.spaces(1, configuration);
|
||||
content = ',' + eol + this.spaces(2, configuration.editor) + eol + this.spaces(1, configuration.editor);
|
||||
} else {
|
||||
content = ',' + eol + this.spaces(2, configuration);
|
||||
content = ',' + eol + this.spaces(2, configuration.editor);
|
||||
}
|
||||
const editOperation = EditOperation.insert(new Position(lastSetting.valueRange.endLineNumber, lastSetting.valueRange.endColumn), content);
|
||||
model.pushEditOperations([], [editOperation], () => []);
|
||||
@@ -393,7 +419,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic
|
||||
return this.configurationService.updateValue(languageKey, {}, ConfigurationTarget.USER)
|
||||
.then(() => {
|
||||
setting = settingsModel.getPreference(languageKey);
|
||||
let content = eol + this.spaces(2, configuration) + eol + this.spaces(1, configuration);
|
||||
let content = eol + this.spaces(2, configuration.editor) + eol + this.spaces(1, configuration.editor);
|
||||
let editOperation = EditOperation.insert(new Position(setting.valueRange.endLineNumber, setting.valueRange.endColumn - 1), content);
|
||||
model.pushEditOperations([], [editOperation], () => []);
|
||||
let lineNumber = setting.valueRange.endLineNumber + 1;
|
||||
|
||||
@@ -5,38 +5,36 @@
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { Dimension } from 'vs/base/browser/builder';
|
||||
import { Dimension, $ } from 'vs/base/browser/builder';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference, IViewZone, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { InputBox, IInputOptions } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ISettingsGroup, IPreferencesService, getSettingsTargetName } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { ISettingsGroup } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IAction, IActionRunner } from 'vs/base/common/actions';
|
||||
import { attachInputBoxStyler, attachStylerCallback, attachSelectBoxStyler, attachCheckboxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IAction, Action } from 'vs/base/common/actions';
|
||||
import { attachInputBoxStyler, attachStylerCallback, attachCheckboxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { buttonBackground, buttonForeground, badgeForeground, badgeBackground, contrastBorder, errorForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { buttonBackground, buttonForeground, badgeForeground, badgeBackground, contrastBorder, errorForeground, focusBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ISelectBoxStyles, defaultStyles } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { Separator, ActionBar, ActionsOrientation, BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
|
||||
import { render as renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
|
||||
import { PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_INACTIVE_TITLE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
|
||||
export class SettingsHeaderWidget extends Widget implements IViewZone {
|
||||
|
||||
@@ -91,7 +89,7 @@ export class SettingsHeaderWidget extends Widget implements IViewZone {
|
||||
const configuration = this.editor.getConfiguration();
|
||||
this.titleContainer.style.fontSize = configuration.fontInfo.fontSize + 'px';
|
||||
if (!configuration.contribInfo.folding) {
|
||||
this.titleContainer.style.paddingLeft = '12px';
|
||||
this.titleContainer.style.paddingLeft = '6px';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,8 +110,8 @@ export class DefaultSettingsHeaderWidget extends SettingsHeaderWidget {
|
||||
protected create() {
|
||||
super.create();
|
||||
|
||||
this.linkElement = DOM.append(this.titleContainer, DOM.$('a.settings-header-fuzzy-link'));
|
||||
this.linkElement.textContent = localize('defaultSettingsFuzzyPrompt', "Try fuzzy search!");
|
||||
this.linkElement = DOM.append(this.titleContainer, DOM.$('a.settings-header-natural-language-link'));
|
||||
this.linkElement.textContent = localize('defaultSettingsFuzzyPrompt', "Try natural language search!");
|
||||
|
||||
this.onclick(this.linkElement, e => this._onClick.fire());
|
||||
this.toggleMessage(true);
|
||||
@@ -178,8 +176,9 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone {
|
||||
this.onclick(this.titleContainer, () => this.toggle());
|
||||
this.onkeydown(this.titleContainer, (e) => this.onKeyDown(e));
|
||||
const focusTracker = this._register(DOM.trackFocus(this.titleContainer));
|
||||
focusTracker.addFocusListener(() => this.toggleFocus(true));
|
||||
focusTracker.addBlurListener(() => this.toggleFocus(false));
|
||||
|
||||
this._register(focusTracker.onDidFocus(() => this.toggleFocus(true)));
|
||||
this._register(focusTracker.onDidBlur(() => this.toggleFocus(false)));
|
||||
|
||||
this.icon = DOM.append(this.titleContainer, DOM.$('.expand-collapse-icon'));
|
||||
this.title = DOM.append(this.titleContainer, DOM.$('.title'));
|
||||
@@ -293,137 +292,249 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone {
|
||||
}
|
||||
}
|
||||
|
||||
export class SettingsTargetsWidget extends Widget {
|
||||
export class FolderSettingsActionItem extends BaseActionItem {
|
||||
|
||||
public actionRunner: IActionRunner;
|
||||
private settingsTargetsContainer: HTMLSelectElement;
|
||||
private targetLabel: HTMLSelectElement;
|
||||
private targetDetails: HTMLSelectElement;
|
||||
private _folder: IWorkspaceFolder;
|
||||
|
||||
private _onDidTargetChange: Emitter<URI> = new Emitter<URI>();
|
||||
public readonly onDidTargetChange: Event<URI> = this._onDidTargetChange.event;
|
||||
private container: HTMLElement;
|
||||
private anchorElement: HTMLElement;
|
||||
private labelElement: HTMLElement;
|
||||
private detailsElement: HTMLElement;
|
||||
private dropDownElement: HTMLElement;
|
||||
|
||||
private borderColor: Color;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(parent: HTMLElement, private _uri: URI, private _configuartionTarget: ConfigurationTarget,
|
||||
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService,
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
@IContextMenuService private contextMenuService: IContextMenuService,
|
||||
@IThemeService themeService: IThemeService) {
|
||||
super();
|
||||
|
||||
this.borderColor = defaultStyles.selectBorder;
|
||||
this.create(parent);
|
||||
this._register(attachSelectBoxStyler(this, themeService, {
|
||||
selectBackground: SIDE_BAR_BACKGROUND
|
||||
}));
|
||||
constructor(
|
||||
action: IAction,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService,
|
||||
@IContextMenuService private contextMenuService: IContextMenuService
|
||||
) {
|
||||
super(null, action);
|
||||
const workspace = this.contextService.getWorkspace();
|
||||
this._folder = workspace.folders.length === 1 ? workspace.folders[0] : null;
|
||||
this.disposables.push(this.contextService.onDidChangeWorkspaceFolders(() => this.onWorkspaceFoldersChanged()));
|
||||
}
|
||||
|
||||
get configurationTarget(): ConfigurationTarget {
|
||||
return this._configuartionTarget;
|
||||
get folder(): IWorkspaceFolder {
|
||||
return this._folder;
|
||||
}
|
||||
|
||||
public updateTargets(uri: URI, configuartionTarget: ConfigurationTarget): void {
|
||||
this._uri = uri;
|
||||
this._configuartionTarget = configuartionTarget;
|
||||
this.updateLabel();
|
||||
set folder(folder: IWorkspaceFolder) {
|
||||
this._folder = folder;
|
||||
this.update();
|
||||
}
|
||||
|
||||
private create(parent: HTMLElement): void {
|
||||
this.settingsTargetsContainer = DOM.append(parent, DOM.$('.settings-targets-widget'));
|
||||
this.settingsTargetsContainer.style.width = this.workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? '200px' : '150px';
|
||||
public render(container: HTMLElement): void {
|
||||
this.builder = $(container);
|
||||
|
||||
const targetElement = DOM.append(this.settingsTargetsContainer, DOM.$('.settings-target'));
|
||||
this.targetLabel = DOM.append(targetElement, DOM.$('.settings-target-label'));
|
||||
this.targetDetails = DOM.append(targetElement, DOM.$('.settings-target-details'));
|
||||
this.updateLabel();
|
||||
this.container = container;
|
||||
this.labelElement = DOM.$('.action-title');
|
||||
this.detailsElement = DOM.$('.action-details');
|
||||
this.dropDownElement = DOM.$('.dropdown-icon.octicon.octicon-triangle-down.hide');
|
||||
this.anchorElement = DOM.$('a.action-label', {
|
||||
role: 'button',
|
||||
'aria-haspopup': 'true',
|
||||
'tabindex': '0'
|
||||
}, this.labelElement, this.detailsElement, this.dropDownElement);
|
||||
this.disposables.push(DOM.addDisposableListener(this.anchorElement, DOM.EventType.CLICK, e => this.onClick(e)));
|
||||
this.disposables.push(DOM.addDisposableListener(this.anchorElement, DOM.EventType.KEY_UP, e => this.onKeyUp(e)));
|
||||
|
||||
this.onclick(this.settingsTargetsContainer, e => this.showContextMenu(e));
|
||||
DOM.append(this.container, this.anchorElement);
|
||||
|
||||
DOM.append(this.settingsTargetsContainer, DOM.$('.settings-target-dropdown-icon.octicon.octicon-triangle-down'));
|
||||
|
||||
this.applyStyles();
|
||||
this.update();
|
||||
}
|
||||
|
||||
private updateLabel(): void {
|
||||
this.targetLabel.textContent = getSettingsTargetName(this._configuartionTarget, this._uri, this.workspaceContextService);
|
||||
const details = ConfigurationTarget.WORKSPACE_FOLDER === this._configuartionTarget ? localize('folderSettingsDetails', "Folder Settings") : '';
|
||||
this.targetDetails.textContent = details;
|
||||
DOM.toggleClass(this.targetDetails, 'empty', !details);
|
||||
}
|
||||
|
||||
private showContextMenu(event: IMouseEvent): void {
|
||||
const actions = this.getSettingsTargetsActions();
|
||||
let elementPosition = DOM.getDomNodePagePosition(this.settingsTargetsContainer);
|
||||
const anchor = { x: elementPosition.left, y: elementPosition.top + elementPosition.height + 5 };
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => TPromise.wrap(actions)
|
||||
});
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
private getSettingsTargetsActions(): IAction[] {
|
||||
const actions: IAction[] = [];
|
||||
const userSettingsResource = this.preferencesService.userSettingsResource;
|
||||
actions.push(<IAction>{
|
||||
id: 'userSettingsTarget',
|
||||
label: getSettingsTargetName(ConfigurationTarget.USER, userSettingsResource, this.workspaceContextService),
|
||||
checked: this._uri.toString() === userSettingsResource.toString(),
|
||||
enabled: true,
|
||||
run: () => this.onTargetClicked(userSettingsResource)
|
||||
});
|
||||
|
||||
if (this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY) {
|
||||
const workspaceSettingsResource = this.preferencesService.workspaceSettingsResource;
|
||||
actions.push(<IAction>{
|
||||
id: 'workspaceSettingsTarget',
|
||||
label: getSettingsTargetName(ConfigurationTarget.WORKSPACE, workspaceSettingsResource, this.workspaceContextService),
|
||||
checked: this._uri.toString() === workspaceSettingsResource.toString(),
|
||||
enabled: true,
|
||||
run: () => this.onTargetClicked(workspaceSettingsResource)
|
||||
});
|
||||
private onKeyUp(event: any): void {
|
||||
const keyboardEvent = new StandardKeyboardEvent(event);
|
||||
switch (keyboardEvent.keyCode) {
|
||||
case KeyCode.Enter:
|
||||
case KeyCode.Space:
|
||||
this.onClick(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const workspaceFolders = this.workspaceContextService.getWorkspace().folders;
|
||||
if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.WORKSPACE && workspaceFolders.length > 0) {
|
||||
public onClick(event: DOM.EventLike): void {
|
||||
DOM.EventHelper.stop(event, true);
|
||||
if (!this.folder || this._action.checked) {
|
||||
this.showMenu();
|
||||
} else {
|
||||
this._action.run(this._folder);
|
||||
}
|
||||
}
|
||||
|
||||
protected _updateEnabled(): void {
|
||||
this.update();
|
||||
}
|
||||
|
||||
protected _updateChecked(): void {
|
||||
this.update();
|
||||
}
|
||||
|
||||
private onWorkspaceFoldersChanged(): void {
|
||||
const oldFolder = this._folder;
|
||||
const workspace = this.contextService.getWorkspace();
|
||||
if (this._folder) {
|
||||
this._folder = workspace.folders.filter(folder => folder.uri.toString() === this._folder.uri.toString())[0] || workspace.folders[0];
|
||||
}
|
||||
this._folder = this._folder ? this._folder : workspace.folders.length === 1 ? workspace.folders[0] : null;
|
||||
|
||||
this.update();
|
||||
|
||||
if (this._action.checked) {
|
||||
if ((oldFolder || !this._folder)
|
||||
|| (!oldFolder || this._folder)
|
||||
|| (oldFolder && this._folder && oldFolder.uri.toString() === this._folder.uri.toString())) {
|
||||
this._action.run(this._folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private update(): void {
|
||||
const workspace = this.contextService.getWorkspace();
|
||||
if (this._folder) {
|
||||
this.labelElement.textContent = this._folder.name;
|
||||
this.anchorElement.title = this._folder.name;
|
||||
this.detailsElement.textContent = this._action.label;
|
||||
DOM.toggleClass(this.dropDownElement, 'hide', workspace.folders.length === 1 || !this._action.checked);
|
||||
} else {
|
||||
this.labelElement.textContent = this._action.label;
|
||||
this.detailsElement.textContent = '';
|
||||
this.anchorElement.title = this._action.label;
|
||||
DOM.removeClass(this.dropDownElement, 'hide');
|
||||
}
|
||||
DOM.toggleClass(this.anchorElement, 'checked', this._action.checked);
|
||||
DOM.toggleClass(this.container, 'disabled', !this._action.enabled);
|
||||
}
|
||||
|
||||
private showMenu(): void {
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => this.container,
|
||||
getActions: () => TPromise.as(this.getDropdownMenuActions()),
|
||||
getActionItem: (action) => null,
|
||||
onHide: () => {
|
||||
this.anchorElement.blur();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getDropdownMenuActions(): IAction[] {
|
||||
const actions: IAction[] = [];
|
||||
const workspaceFolders = this.contextService.getWorkspace().folders;
|
||||
if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && workspaceFolders.length > 0) {
|
||||
actions.push(new Separator());
|
||||
actions.push(...workspaceFolders.map((folder, index) => {
|
||||
return <IAction>{
|
||||
id: 'folderSettingsTarget' + index,
|
||||
label: getSettingsTargetName(ConfigurationTarget.WORKSPACE_FOLDER, folder.uri, this.workspaceContextService),
|
||||
checked: this._uri.toString() === folder.uri.toString(),
|
||||
label: folder.name,
|
||||
checked: this.folder && this.folder.uri.toString() === folder.uri.toString(),
|
||||
enabled: true,
|
||||
run: () => this.onTargetClicked(folder.uri)
|
||||
run: () => this._action.run(folder)
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
private onTargetClicked(target: URI): void {
|
||||
if (this._uri.toString() === target.toString()) {
|
||||
return;
|
||||
}
|
||||
this._onDidTargetChange.fire(target);
|
||||
public dispose(): void {
|
||||
dispose(this.disposables);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export type SettingsTarget = ConfigurationTarget.USER | ConfigurationTarget.WORKSPACE | URI;
|
||||
|
||||
export class SettingsTargetsWidget extends Widget {
|
||||
|
||||
private settingsSwitcherBar: ActionBar;
|
||||
private userSettings: Action;
|
||||
private workspaceSettings: Action;
|
||||
private folderSettings: FolderSettingsActionItem;
|
||||
|
||||
private _settingsTarget: SettingsTarget;
|
||||
|
||||
private _onDidTargetChange: Emitter<SettingsTarget> = new Emitter<SettingsTarget>();
|
||||
public readonly onDidTargetChange: Event<SettingsTarget> = this._onDidTargetChange.event;
|
||||
|
||||
constructor(
|
||||
parent: HTMLElement,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
this.create(parent);
|
||||
this._register(this.contextService.onDidChangeWorkbenchState(() => this.onWorkbenchStateChanged()));
|
||||
this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.update()));
|
||||
}
|
||||
|
||||
style(styles: ISelectBoxStyles): void {
|
||||
this.borderColor = styles.selectBorder;
|
||||
this.applyStyles();
|
||||
private create(parent: HTMLElement): void {
|
||||
const settingsTabsWidget = DOM.append(parent, DOM.$('.settings-tabs-widget'));
|
||||
this.settingsSwitcherBar = this._register(new ActionBar(settingsTabsWidget, {
|
||||
orientation: ActionsOrientation.HORIZONTAL,
|
||||
ariaLabel: localize('settingsSwitcherBarAriaLabel', "Settings Switcher"),
|
||||
animated: false,
|
||||
actionItemProvider: (action: Action) => action.id === 'folderSettings' ? this.folderSettings : null
|
||||
}));
|
||||
|
||||
this.userSettings = new Action('userSettings', localize('userSettings', "User Settings"), '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER));
|
||||
this.userSettings.tooltip = this.userSettings.label;
|
||||
|
||||
this.workspaceSettings = new Action('workspaceSettings', localize('workspaceSettings', "Workspace Settings"), '.settings-tab', false, () => this.updateTarget(ConfigurationTarget.WORKSPACE));
|
||||
this.workspaceSettings.tooltip = this.workspaceSettings.label;
|
||||
|
||||
const folderSettingsAction = new Action('folderSettings', localize('folderSettings', "Folder Settings"), '.settings-tab', false, (folder: IWorkspaceFolder) => this.updateTarget(folder ? folder.uri : ConfigurationTarget.USER));
|
||||
this.folderSettings = this.instantiationService.createInstance(FolderSettingsActionItem, folderSettingsAction);
|
||||
|
||||
this.update();
|
||||
|
||||
this.settingsSwitcherBar.push([this.userSettings, this.workspaceSettings, folderSettingsAction]);
|
||||
}
|
||||
|
||||
private applyStyles(): void {
|
||||
if (this.settingsTargetsContainer) {
|
||||
this.settingsTargetsContainer.style.border = this.borderColor ? `1px solid ${this.borderColor}` : null;
|
||||
public get settingsTarget(): SettingsTarget {
|
||||
return this._settingsTarget;
|
||||
}
|
||||
|
||||
public set settingsTarget(settingsTarget: SettingsTarget) {
|
||||
this._settingsTarget = settingsTarget;
|
||||
this.userSettings.checked = ConfigurationTarget.USER === this.settingsTarget;
|
||||
this.workspaceSettings.checked = ConfigurationTarget.WORKSPACE === this.settingsTarget;
|
||||
if (this.settingsTarget instanceof URI) {
|
||||
this.folderSettings.getAction().checked = true;
|
||||
this.folderSettings.folder = this.contextService.getWorkspaceFolder(this.settingsTarget as URI);
|
||||
} else {
|
||||
this.folderSettings.getAction().checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
private onWorkbenchStateChanged(): void {
|
||||
this.folderSettings.folder = null;
|
||||
this.update();
|
||||
if (this.settingsTarget === ConfigurationTarget.WORKSPACE && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
|
||||
this.updateTarget(ConfigurationTarget.USER);
|
||||
}
|
||||
}
|
||||
|
||||
private updateTarget(settingsTarget: SettingsTarget): TPromise<void> {
|
||||
const isSameTarget = this.settingsTarget === settingsTarget || settingsTarget instanceof URI && this.settingsTarget instanceof URI && this.settingsTarget.toString() === settingsTarget.toString();
|
||||
if (!isSameTarget) {
|
||||
this.settingsTarget = settingsTarget;
|
||||
this._onDidTargetChange.fire(this.settingsTarget);
|
||||
}
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
private update(): void {
|
||||
DOM.toggleClass(this.settingsSwitcherBar.domNode, 'empty-workbench', this.contextService.getWorkbenchState() === WorkbenchState.EMPTY);
|
||||
this.workspaceSettings.enabled = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY;
|
||||
this.folderSettings.getAction().enabled = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && this.contextService.getWorkspace().folders.length > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface SearchOptions extends IInputOptions {
|
||||
focusKey?: IContextKey<boolean>;
|
||||
showFuzzyToggle?: boolean;
|
||||
showResultCount?: boolean;
|
||||
}
|
||||
|
||||
export class SearchWidget extends Widget {
|
||||
@@ -444,7 +555,6 @@ export class SearchWidget extends Widget {
|
||||
|
||||
constructor(parent: HTMLElement, protected options: SearchOptions,
|
||||
@IContextViewService private contextViewService: IContextViewService,
|
||||
@IContextMenuService private contextMenuService: IContextMenuService,
|
||||
@IInstantiationService protected instantiationService: IInstantiationService,
|
||||
@IThemeService private themeService: IThemeService
|
||||
) {
|
||||
@@ -464,39 +574,44 @@ export class SearchWidget extends Widget {
|
||||
this.domNode = DOM.append(parent, DOM.$('div.settings-header-widget'));
|
||||
this.createSearchContainer(DOM.append(this.domNode, DOM.$('div.settings-search-container')));
|
||||
this.controlsDiv = DOM.append(this.domNode, DOM.$('div.settings-search-controls'));
|
||||
this.fuzzyToggle = this._register(new Checkbox({
|
||||
actionClassName: 'prefs-fuzzy-search-toggle',
|
||||
isChecked: false,
|
||||
onChange: () => {
|
||||
this.inputBox.focus();
|
||||
this._onDidChange.fire();
|
||||
},
|
||||
title: localize('enableFuzzySearch', 'Enable experimental fuzzy search')
|
||||
}));
|
||||
DOM.append(this.controlsDiv, this.fuzzyToggle.domNode);
|
||||
this._register(attachCheckboxStyler(this.fuzzyToggle, this.themeService));
|
||||
if (this.options.showFuzzyToggle) {
|
||||
this.fuzzyToggle = this._register(new Checkbox({
|
||||
actionClassName: 'prefs-natural-language-search-toggle',
|
||||
isChecked: false,
|
||||
onChange: () => {
|
||||
this.inputBox.focus();
|
||||
this._onDidChange.fire();
|
||||
},
|
||||
title: localize('enableFuzzySearch', 'Enable natural language search')
|
||||
}));
|
||||
this.fuzzyToggle.domNode.innerHTML = renderOcticons('$(light-bulb)');
|
||||
DOM.append(this.controlsDiv, this.fuzzyToggle.domNode);
|
||||
this._register(attachCheckboxStyler(this.fuzzyToggle, this.themeService));
|
||||
}
|
||||
|
||||
this.countElement = DOM.append(this.controlsDiv, DOM.$('.settings-count-widget'));
|
||||
this._register(attachStylerCallback(this.themeService, { badgeBackground, contrastBorder }, colors => {
|
||||
const background = colors.badgeBackground ? colors.badgeBackground.toString() : null;
|
||||
const border = colors.contrastBorder ? colors.contrastBorder.toString() : null;
|
||||
if (this.options.showResultCount) {
|
||||
this.countElement = DOM.append(this.controlsDiv, DOM.$('.settings-count-widget'));
|
||||
this._register(attachStylerCallback(this.themeService, { badgeBackground, contrastBorder }, colors => {
|
||||
const background = colors.badgeBackground ? colors.badgeBackground.toString() : null;
|
||||
const border = colors.contrastBorder ? colors.contrastBorder.toString() : null;
|
||||
|
||||
this.countElement.style.backgroundColor = background;
|
||||
this.countElement.style.backgroundColor = background;
|
||||
|
||||
this.countElement.style.borderWidth = border ? '1px' : null;
|
||||
this.countElement.style.borderStyle = border ? 'solid' : null;
|
||||
this.countElement.style.borderColor = border;
|
||||
this.countElement.style.borderWidth = border ? '1px' : null;
|
||||
this.countElement.style.borderStyle = border ? 'solid' : null;
|
||||
this.countElement.style.borderColor = border;
|
||||
|
||||
this.styleCountElementForeground();
|
||||
}));
|
||||
}
|
||||
|
||||
this.styleCountElementForeground();
|
||||
}));
|
||||
this.inputBox.inputElement.setAttribute('aria-live', 'assertive');
|
||||
|
||||
const focusTracker = this._register(DOM.trackFocus(this.inputBox.inputElement));
|
||||
this._register(focusTracker.addFocusListener(() => this._onFocus.fire()));
|
||||
this._register(focusTracker.onDidFocus(() => this._onFocus.fire()));
|
||||
|
||||
if (this.options.focusKey) {
|
||||
this._register(focusTracker.addFocusListener(() => this.options.focusKey.set(true)));
|
||||
this._register(focusTracker.addBlurListener(() => this.options.focusKey.set(false)));
|
||||
this._register(focusTracker.onDidFocus(() => this.options.focusKey.set(true)));
|
||||
this._register(focusTracker.onDidBlur(() => this.options.focusKey.set(false)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,11 +630,13 @@ export class SearchWidget extends Widget {
|
||||
}
|
||||
|
||||
public showMessage(message: string, count: number): void {
|
||||
this.countElement.textContent = message;
|
||||
this.inputBox.inputElement.setAttribute('aria-label', message);
|
||||
DOM.toggleClass(this.countElement, 'no-results', count === 0);
|
||||
this.inputBox.inputElement.style.paddingRight = this.getControlsWidth() + 'px';
|
||||
this.styleCountElementForeground();
|
||||
if (this.countElement) {
|
||||
this.countElement.textContent = message;
|
||||
this.inputBox.inputElement.setAttribute('aria-label', message);
|
||||
DOM.toggleClass(this.countElement, 'no-results', count === 0);
|
||||
this.inputBox.inputElement.style.paddingRight = this.getControlsWidth() + 'px';
|
||||
this.styleCountElementForeground();
|
||||
}
|
||||
}
|
||||
|
||||
public setFuzzyToggleVisible(visible: boolean): void {
|
||||
@@ -540,16 +657,24 @@ export class SearchWidget extends Widget {
|
||||
|
||||
public layout(dimension: Dimension) {
|
||||
if (dimension.width < 400) {
|
||||
DOM.addClass(this.countElement, 'hide');
|
||||
if (this.countElement) {
|
||||
DOM.addClass(this.countElement, 'hide');
|
||||
}
|
||||
|
||||
this.inputBox.inputElement.style.paddingRight = '0px';
|
||||
} else {
|
||||
DOM.removeClass(this.countElement, 'hide');
|
||||
if (this.countElement) {
|
||||
DOM.removeClass(this.countElement, 'hide');
|
||||
}
|
||||
|
||||
this.inputBox.inputElement.style.paddingRight = this.getControlsWidth() + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
private getControlsWidth(): number {
|
||||
return DOM.getTotalWidth(this.countElement) + DOM.getTotalWidth(this.fuzzyToggle.domNode) + 20;
|
||||
const countWidth = this.countElement ? DOM.getTotalWidth(this.countElement) : 0;
|
||||
const fuzzyToggleWidth = this.fuzzyToggle ? DOM.getTotalWidth(this.fuzzyToggle.domNode) : 0;
|
||||
return countWidth + fuzzyToggleWidth + 20;
|
||||
}
|
||||
|
||||
public focus() {
|
||||
@@ -593,7 +718,7 @@ export class FloatingClickWidget extends Widget implements IOverlayWidget {
|
||||
constructor(
|
||||
private editor: ICodeEditor,
|
||||
private label: string,
|
||||
private keyBindingAction: string,
|
||||
keyBindingAction: string,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IThemeService private themeService: IThemeService
|
||||
) {
|
||||
@@ -641,7 +766,7 @@ export class FloatingClickWidget extends Widget implements IOverlayWidget {
|
||||
|
||||
export class EditPreferenceWidget<T> extends Disposable {
|
||||
|
||||
public static GLYPH_MARGIN_CLASS_NAME = 'edit-preferences-widget';
|
||||
public static readonly GLYPH_MARGIN_CLASS_NAME = 'edit-preferences-widget';
|
||||
|
||||
private _line: number;
|
||||
private _preferences: T[];
|
||||
@@ -705,3 +830,72 @@ export class EditPreferenceWidget<T> extends Disposable {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
||||
|
||||
collector.addRule(`
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label:focus,
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label.checked {
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
`);
|
||||
// Title Active
|
||||
const titleActive = theme.getColor(PANEL_ACTIVE_TITLE_FOREGROUND);
|
||||
const titleActiveBorder = theme.getColor(PANEL_ACTIVE_TITLE_BORDER);
|
||||
if (titleActive || titleActiveBorder) {
|
||||
collector.addRule(`
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label:hover,
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label.checked {
|
||||
color: ${titleActive};
|
||||
border-bottom-color: ${titleActiveBorder};
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
// Title Inactive
|
||||
const titleInactive = theme.getColor(PANEL_INACTIVE_TITLE_FOREGROUND);
|
||||
if (titleInactive) {
|
||||
collector.addRule(`
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label {
|
||||
color: ${titleInactive};
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
// Title focus
|
||||
const focusBorderColor = theme.getColor(focusBorder);
|
||||
if (focusBorderColor) {
|
||||
collector.addRule(`
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label:focus {
|
||||
border-bottom-color: ${focusBorderColor} !important;
|
||||
}
|
||||
`);
|
||||
collector.addRule(`
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label:focus {
|
||||
outline: none;
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
// Styling with Outline color (e.g. high contrast theme)
|
||||
const outline = theme.getColor(activeContrastBorder);
|
||||
if (outline) {
|
||||
const outline = theme.getColor(activeContrastBorder);
|
||||
|
||||
collector.addRule(`
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label.checked,
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label:hover {
|
||||
outline-color: ${outline};
|
||||
outline-width: 1px;
|
||||
outline-style: solid;
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
.settings-tabs-widget > .monaco-action-bar .action-item .action-label:not(.checked):hover {
|
||||
outline-style: dashed;
|
||||
}
|
||||
`);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user