Merge from vscode 1ec43773e37997841c5af42b33ddb180e9735bf2

This commit is contained in:
ADS Merger
2020-03-29 01:29:32 +00:00
parent 586ec50916
commit a64304602e
316 changed files with 6524 additions and 11687 deletions

View File

@@ -1,196 +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 { Registry } from 'vs/platform/registry/common/platform';
import { IAction } from 'vs/base/common/actions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree';
import { IInstantiationService, IConstructorSignature0, ServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
/**
* The action bar contributor allows to add actions to an actionbar in a given context.
*/
export class ActionBarContributor {
/**
* Returns true if this contributor has actions for the given context.
*/
hasActions(context: unknown): boolean {
return false;
}
/**
* Returns an array of primary actions in the given context.
*/
getActions(context: unknown): ReadonlyArray<IAction> {
return [];
}
}
/**
* Some predefined scopes to contribute actions to
*/
export const Scope = {
/**
* Actions inside tree widgets.
*/
VIEWER: 'viewer'
};
/**
* The ContributableActionProvider leverages the actionbar contribution model to find actions.
*/
export class ContributableActionProvider implements IActionProvider {
private readonly registry: IActionBarRegistry = Registry.as<IActionBarRegistry>(Extensions.Actionbar);
private toContext(tree: ITree, element: unknown): unknown {
return {
viewer: tree,
element: element
};
}
hasActions(tree: ITree, element: unknown): boolean {
const context = this.toContext(tree, element);
const contributors = this.registry.getActionBarContributors(Scope.VIEWER);
return contributors.some(contributor => contributor.hasActions(context));
}
getActions(tree: ITree, element: unknown): ReadonlyArray<IAction> {
const actions: IAction[] = [];
const context = this.toContext(tree, element);
// Collect Actions
const contributors = this.registry.getActionBarContributors(Scope.VIEWER);
for (const contributor of contributors) {
if (contributor.hasActions(context)) {
actions.push(...contributor.getActions(context));
}
}
return prepareActions(actions);
}
}
// Helper function used in parts to massage actions before showing in action areas
export function prepareActions(actions: IAction[]): IAction[] {
if (!actions.length) {
return actions;
}
// Clean up leading separators
let firstIndexOfAction = -1;
for (let i = 0; i < actions.length; i++) {
if (actions[i].id === Separator.ID) {
continue;
}
firstIndexOfAction = i;
break;
}
if (firstIndexOfAction === -1) {
return [];
}
actions = actions.slice(firstIndexOfAction);
// Clean up trailing separators
for (let h = actions.length - 1; h >= 0; h--) {
const isSeparator = actions[h].id === Separator.ID;
if (isSeparator) {
actions.splice(h, 1);
} else {
break;
}
}
// Clean up separator duplicates
let foundAction = false;
for (let k = actions.length - 1; k >= 0; k--) {
const isSeparator = actions[k].id === Separator.ID;
if (isSeparator && !foundAction) {
actions.splice(k, 1);
} else if (!isSeparator) {
foundAction = true;
} else if (isSeparator) {
foundAction = false;
}
}
return actions;
}
export const Extensions = {
Actionbar: 'workbench.contributions.actionbar'
};
export interface IActionBarRegistry {
/**
* Registers an Actionbar contributor. It will be called to contribute actions to all the action bars
* that are used in the Workbench in the given scope.
*/
registerActionBarContributor<Services extends BrandedService[]>(scope: string, ctor: { new(...services: Services): ActionBarContributor }): void;
/**
* Returns an array of registered action bar contributors known to the workbench for the given scope.
*/
getActionBarContributors(scope: string): ActionBarContributor[];
/**
* Starts the registry by providing the required services.
*/
start(accessor: ServicesAccessor): void;
}
class ActionBarRegistry implements IActionBarRegistry {
private readonly actionBarContributorConstructors: { scope: string; ctor: IConstructorSignature0<ActionBarContributor>; }[] = [];
private readonly actionBarContributorInstances: Map<string, ActionBarContributor[]> = new Map();
private instantiationService: IInstantiationService | undefined;
start(accessor: ServicesAccessor): void {
this.instantiationService = accessor.get(IInstantiationService);
while (this.actionBarContributorConstructors.length > 0) {
const entry = this.actionBarContributorConstructors.shift()!;
this.createActionBarContributor(entry.scope, entry.ctor);
}
}
private createActionBarContributor(scope: string, ctor: IConstructorSignature0<ActionBarContributor>): void {
if (this.instantiationService) {
const instance = this.instantiationService.createInstance(ctor);
let target = this.actionBarContributorInstances.get(scope);
if (!target) {
target = [];
this.actionBarContributorInstances.set(scope, target);
}
target.push(instance);
}
}
private getContributors(scope: string): ActionBarContributor[] {
return this.actionBarContributorInstances.get(scope) || [];
}
registerActionBarContributor(scope: string, ctor: IConstructorSignature0<ActionBarContributor>): void {
if (!this.instantiationService) {
this.actionBarContributorConstructors.push({
scope: scope,
ctor: ctor
});
} else {
this.createActionBarContributor(scope, ctor);
}
}
getActionBarContributors(scope: string): ActionBarContributor[] {
return this.getContributors(scope).slice(0);
}
}
Registry.add(Extensions.Actionbar, new ActionBarRegistry());

View File

@@ -0,0 +1,251 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IQuickInputService, ItemActivation } from 'vs/platform/quickinput/common/quickInput';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { Action } from 'vs/base/common/actions';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { inQuickPickContext, defaultQuickAccessContext, getQuickNavigateHandler } from 'vs/workbench/browser/quickaccess';
//#region Quick access management commands and keys
const globalQuickAccessKeybinding = {
primary: KeyMod.CtrlCmd | KeyCode.KEY_P,
secondary: [KeyMod.CtrlCmd | KeyCode.KEY_E],
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_P, secondary: undefined }
};
const QUICKACCESS_ACTION_ID = 'workbench.action.quickOpen';
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: { id: QUICKACCESS_ACTION_ID, title: { value: localize('quickOpen', "Go to File..."), original: 'Go to File...' } }
});
KeybindingsRegistry.registerKeybindingRule({
id: QUICKACCESS_ACTION_ID,
weight: KeybindingWeight.WorkbenchContrib,
when: undefined,
primary: globalQuickAccessKeybinding.primary,
secondary: globalQuickAccessKeybinding.secondary,
mac: globalQuickAccessKeybinding.mac
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.closeQuickOpen',
weight: KeybindingWeight.WorkbenchContrib,
when: inQuickPickContext,
primary: KeyCode.Escape, secondary: [KeyMod.Shift | KeyCode.Escape],
handler: accessor => {
const quickInputService = accessor.get(IQuickInputService);
return quickInputService.cancel();
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.acceptSelectedQuickOpenItem',
weight: KeybindingWeight.WorkbenchContrib,
when: inQuickPickContext,
primary: 0,
handler: accessor => {
const quickInputService = accessor.get(IQuickInputService);
return quickInputService.accept();
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.alternativeAcceptSelectedQuickOpenItem',
weight: KeybindingWeight.WorkbenchContrib,
when: inQuickPickContext,
primary: 0,
handler: accessor => {
const quickInputService = accessor.get(IQuickInputService);
return quickInputService.accept({ ctrlCmd: true, alt: false });
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.focusQuickOpen',
weight: KeybindingWeight.WorkbenchContrib,
when: inQuickPickContext,
primary: 0,
handler: accessor => {
const quickInputService = accessor.get(IQuickInputService);
quickInputService.focus();
}
});
const quickAccessNavigateNextInFilePickerId = 'workbench.action.quickOpenNavigateNextInFilePicker';
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: quickAccessNavigateNextInFilePickerId,
weight: KeybindingWeight.WorkbenchContrib + 50,
handler: getQuickNavigateHandler(quickAccessNavigateNextInFilePickerId, true),
when: defaultQuickAccessContext,
primary: globalQuickAccessKeybinding.primary,
secondary: globalQuickAccessKeybinding.secondary,
mac: globalQuickAccessKeybinding.mac
});
const quickAccessNavigatePreviousInFilePickerId = 'workbench.action.quickOpenNavigatePreviousInFilePicker';
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: quickAccessNavigatePreviousInFilePickerId,
weight: KeybindingWeight.WorkbenchContrib + 50,
handler: getQuickNavigateHandler(quickAccessNavigatePreviousInFilePickerId, false),
when: defaultQuickAccessContext,
primary: globalQuickAccessKeybinding.primary | KeyMod.Shift,
secondary: [globalQuickAccessKeybinding.secondary[0] | KeyMod.Shift],
mac: {
primary: globalQuickAccessKeybinding.mac.primary | KeyMod.Shift,
secondary: undefined
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.quickPickManyToggle',
weight: KeybindingWeight.WorkbenchContrib,
when: inQuickPickContext,
primary: 0,
handler: accessor => {
const quickInputService = accessor.get(IQuickInputService);
quickInputService.toggle();
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.quickInputBack',
weight: KeybindingWeight.WorkbenchContrib + 50,
when: inQuickPickContext,
primary: 0,
win: { primary: KeyMod.Alt | KeyCode.LeftArrow },
mac: { primary: KeyMod.WinCtrl | KeyCode.US_MINUS },
linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.US_MINUS },
handler: accessor => {
const quickInputService = accessor.get(IQuickInputService);
quickInputService.back();
}
});
CommandsRegistry.registerCommand({
id: QUICKACCESS_ACTION_ID,
handler: async function (accessor: ServicesAccessor, prefix: unknown) {
const quickInputService = accessor.get(IQuickInputService);
quickInputService.quickAccess.show(typeof prefix === 'string' ? prefix : undefined);
},
description: {
description: `Quick access`,
args: [{
name: 'prefix',
schema: {
'type': 'string'
}
}]
}
});
CommandsRegistry.registerCommand('workbench.action.quickOpenPreviousEditor', async function (accessor: ServicesAccessor, prefix: string | null = null) {
const quickInputService = accessor.get(IQuickInputService);
quickInputService.quickAccess.show('', { itemActivation: ItemActivation.SECOND });
});
//#endregion
//#region Workbench actions
export class BaseQuickAccessNavigateAction extends Action {
constructor(
id: string,
label: string,
private next: boolean,
private quickNavigate: boolean,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IKeybindingService private readonly keybindingService: IKeybindingService
) {
super(id, label);
}
async run(): Promise<void> {
const keys = this.keybindingService.lookupKeybindings(this.id);
const quickNavigate = this.quickNavigate ? { keybindings: keys } : undefined;
this.quickInputService.navigate(this.next, quickNavigate);
}
}
export class QuickAccessNavigateNextAction extends BaseQuickAccessNavigateAction {
static readonly ID = 'workbench.action.quickOpenNavigateNext';
static readonly LABEL = localize('quickNavigateNext', "Navigate Next in Quick Open");
constructor(
id: string,
label: string,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, true, true, quickInputService, keybindingService);
}
}
class QuickAccessNavigatePreviousAction extends BaseQuickAccessNavigateAction {
static readonly ID = 'workbench.action.quickOpenNavigatePrevious';
static readonly LABEL = localize('quickNavigatePrevious', "Navigate Previous in Quick Open");
constructor(
id: string,
label: string,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, false, true, quickInputService, keybindingService);
}
}
class QuickAccessSelectNextAction extends BaseQuickAccessNavigateAction {
static readonly ID = 'workbench.action.quickOpenSelectNext';
static readonly LABEL = localize('quickSelectNext', "Select Next in Quick Open");
constructor(
id: string,
label: string,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, true, false, quickInputService, keybindingService);
}
}
class QuickAccessSelectPreviousAction extends BaseQuickAccessNavigateAction {
static readonly ID = 'workbench.action.quickOpenSelectPrevious';
static readonly LABEL = localize('quickSelectPrevious', "Select Previous in Quick Open");
constructor(
id: string,
label: string,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, false, false, quickInputService, keybindingService);
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickAccessSelectNextAction, QuickAccessSelectNextAction.ID, QuickAccessSelectNextAction.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_N } }, inQuickPickContext, KeybindingWeight.WorkbenchContrib + 50), 'Select Next in Quick Open');
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickAccessSelectPreviousAction, QuickAccessSelectPreviousAction.ID, QuickAccessSelectPreviousAction.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_P } }, inQuickPickContext, KeybindingWeight.WorkbenchContrib + 50), 'Select Previous in Quick Open');
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickAccessNavigateNextAction, QuickAccessNavigateNextAction.ID, QuickAccessNavigateNextAction.LABEL), 'Navigate Next in Quick Open');
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickAccessNavigatePreviousAction, QuickAccessNavigatePreviousAction.ID, QuickAccessNavigatePreviousAction.LABEL), 'Navigate Previous in Quick Open');
//#endregion

View File

@@ -29,7 +29,7 @@ import { FileKind } from 'vs/platform/files/common/files';
import { splitName } from 'vs/base/common/labels';
import { isMacintosh } from 'vs/base/common/platform';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { inQuickOpenContext, getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen';
import { inQuickPickContext, getQuickNavigateHandler } from 'vs/workbench/browser/quickaccess';
import { IHostService } from 'vs/workbench/services/host/browser/host';
export const inRecentFilesPickerContextKey = 'inRecentFilesPicker';
@@ -165,7 +165,7 @@ export class OpenRecentAction extends BaseOpenRecentAction {
}
}
class QuickOpenRecentAction extends BaseOpenRecentAction {
class QuickPickRecentAction extends BaseOpenRecentAction {
static readonly ID = 'workbench.action.quickOpenRecent';
static readonly LABEL = nls.localize('quickOpenRecent', "Quick Open Recent...");
@@ -270,7 +270,7 @@ const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActio
const fileCategory = nls.localize('file', "File");
registry.registerWorkbenchAction(SyncActionDescriptor.create(NewWindowAction, NewWindowAction.ID, NewWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_N }), 'New Window');
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickPickRecentAction, QuickPickRecentAction.ID, QuickPickRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.create(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', fileCategory);
const viewCategory = nls.localize('view', "View");
@@ -284,23 +284,23 @@ registry.registerWorkbenchAction(SyncActionDescriptor.create(ShowAboutDialogActi
// --- Commands/Keybindings Registration
const recentFilesPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(inRecentFilesPickerContextKey));
const recentFilesPickerContext = ContextKeyExpr.and(inQuickPickContext, ContextKeyExpr.has(inRecentFilesPickerContextKey));
const quickOpenNavigateNextInRecentFilesPickerId = 'workbench.action.quickOpenNavigateNextInRecentFilesPicker';
const quickPickNavigateNextInRecentFilesPickerId = 'workbench.action.quickOpenNavigateNextInRecentFilesPicker';
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: quickOpenNavigateNextInRecentFilesPickerId,
id: quickPickNavigateNextInRecentFilesPickerId,
weight: KeybindingWeight.WorkbenchContrib + 50,
handler: getQuickNavigateHandler(quickOpenNavigateNextInRecentFilesPickerId, true),
handler: getQuickNavigateHandler(quickPickNavigateNextInRecentFilesPickerId, true),
when: recentFilesPickerContext,
primary: KeyMod.CtrlCmd | KeyCode.KEY_R,
mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R }
});
const quickOpenNavigatePreviousInRecentFilesPicker = 'workbench.action.quickOpenNavigatePreviousInRecentFilesPicker';
const quickPickNavigatePreviousInRecentFilesPicker = 'workbench.action.quickOpenNavigatePreviousInRecentFilesPicker';
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: quickOpenNavigatePreviousInRecentFilesPicker,
id: quickPickNavigatePreviousInRecentFilesPicker,
weight: KeybindingWeight.WorkbenchContrib + 50,
handler: getQuickNavigateHandler(quickOpenNavigatePreviousInRecentFilesPicker, false),
handler: getQuickNavigateHandler(quickPickNavigatePreviousInRecentFilesPicker, false),
when: recentFilesPickerContext,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_R,
mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_R }

View File

@@ -206,7 +206,12 @@ export class WorkbenchContextKeysHandler extends Disposable {
if (activeEditorPane) {
this.activeEditorContext.set(activeEditorPane.getId());
this.activeEditorIsReadonly.set(activeEditorPane.input.isReadonly());
try {
this.activeEditorIsReadonly.set(activeEditorPane.input.isReadonly());
} catch (error) {
// TODO@ben for https://github.com/microsoft/vscode/issues/93224
throw new Error(`${error.message}: editor id ${activeEditorPane.getId()}`);
}
} else {
this.activeEditorContext.reset();
this.activeEditorIsReadonly.reset();

View File

@@ -223,9 +223,7 @@ body.web {
.monaco-workbench [tabindex="-1"]:active,
.monaco-workbench select:active,
.monaco-workbench input[type="button"]:active,
.monaco-workbench input[type="checkbox"]:active,
.monaco-workbench .monaco-tree .monaco-tree-row
.monaco-workbench .monaco-tree.focused.no-focused-item:active:before {
.monaco-workbench input[type="checkbox"]:active {
outline: 0 !important; /* fixes some flashing outlines from showing up when clicking */
}
@@ -233,12 +231,6 @@ body.web {
border-color: transparent; /* outline is a square, but border has a radius, so we avoid this glitch when focused (https://github.com/Microsoft/vscode/issues/26045) */
}
.monaco-workbench .monaco-tree.focused .monaco-tree-row.focused [tabindex="0"]:focus {
outline-width: 1px; /* higher contrast color for focusable elements in a row that shows focus feedback */
outline-style: solid;
}
.monaco-workbench .monaco-tree.focused.no-focused-item:focus:before,
.monaco-workbench .monaco-list:not(.element-focused):focus:before {
position: absolute;
top: 0;
@@ -267,7 +259,6 @@ body.web {
outline: 0 !important; /* outline is not going well with decoration */
}
.monaco-workbench .monaco-tree.focused:focus,
.monaco-workbench .monaco-list:focus {
outline: 0 !important; /* tree indicates focus not via outline but through the focused item */
}

View File

@@ -40,6 +40,8 @@ import { getMenuBarVisibility } from 'vs/platform/windows/common/windows';
import { isWeb } from 'vs/base/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { getUserDataSyncStore } from 'vs/platform/userDataSync/common/userDataSync';
import { IProductService } from 'vs/platform/product/common/productService';
interface IPlaceholderViewlet {
id: string;
@@ -109,7 +111,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
@IProductService private readonly productService: IProductService
) {
super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService);
this.migrateFromOldCachedViewletsValue();
@@ -395,13 +398,16 @@ export class ActivitybarPart extends Part implements IActivityBarService {
cssClass: 'codicon-settings-gear'
});
const profileAction = new ActivityAction({
id: 'workbench.actions.accounts',
name: nls.localize('accounts', "Accounts"),
cssClass: 'codicon-account'
});
if (getUserDataSyncStore(this.productService, this.configurationService)) {
const profileAction = new ActivityAction({
id: 'workbench.actions.accounts',
name: nls.localize('accounts', "Accounts"),
cssClass: 'codicon-account'
});
this.globalActivityActionBar.push(profileAction);
}
this.globalActivityActionBar.push(profileAction);
this.globalActivityActionBar.push(this.globalActivityAction);
}

View File

@@ -11,9 +11,8 @@ import * as strings from 'vs/base/common/strings';
import { Emitter } from 'vs/base/common/event';
import * as errors from 'vs/base/common/errors';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IActionViewItem, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { IActionViewItem, ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { prepareActions } from 'vs/workbench/browser/actions';
import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
import { Part, IPartOptions } from 'vs/workbench/browser/part';
import { Composite, CompositeRegistry } from 'vs/workbench/browser/composite';

View File

@@ -13,7 +13,7 @@ import { Extensions, IConfigurationRegistry, ConfigurationScope } from 'vs/platf
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Registry } from 'vs/platform/registry/common/platform';
import { GroupIdentifier } from 'vs/workbench/common/editor';
import { GroupIdentifier, IEditorPartOptions } from 'vs/workbench/common/editor';
export const IBreadcrumbsService = createDecorator<IBreadcrumbsService>('IEditorBreadcrumbsService');
@@ -72,6 +72,7 @@ export abstract class BreadcrumbsConfig<T> {
static readonly SymbolPath = BreadcrumbsConfig._stub<'on' | 'off' | 'last'>('breadcrumbs.symbolPath');
static readonly SymbolSortOrder = BreadcrumbsConfig._stub<'position' | 'name' | 'type'>('breadcrumbs.symbolSortOrder');
static readonly Icons = BreadcrumbsConfig._stub<boolean>('breadcrumbs.icons');
static readonly TitleScrollbarSizing = BreadcrumbsConfig._stub<IEditorPartOptions['titleScrollbarSizing']>('workbench.editor.titleScrollbarSizing');
static readonly FileExcludes = BreadcrumbsConfig._stub<glob.IExpression>('files.exclude');

View File

@@ -29,7 +29,7 @@ import { FileKind, IFileService, IFileStat } from 'vs/platform/files/common/file
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IListService, WorkbenchListFocusContextKey } from 'vs/platform/list/browser/listService';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { ColorIdentifier, ColorFunction } from 'vs/platform/theme/common/colorRegistry';
import { attachBreadcrumbsStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
@@ -38,7 +38,7 @@ import { ResourceLabel } from 'vs/workbench/browser/labels';
import { BreadcrumbsConfig, IBreadcrumbsService } from 'vs/workbench/browser/parts/editor/breadcrumbs';
import { BreadcrumbElement, EditorBreadcrumbsModel, FileElement } from 'vs/workbench/browser/parts/editor/breadcrumbsModel';
import { BreadcrumbsPicker, createBreadcrumbsPicker } from 'vs/workbench/browser/parts/editor/breadcrumbsPicker';
import { SideBySideEditorInput } from 'vs/workbench/common/editor';
import { SideBySideEditorInput, IEditorPartOptions } from 'vs/workbench/common/editor';
import { ACTIVE_GROUP, ACTIVE_GROUP_TYPE, IEditorService, SIDE_GROUP, SIDE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@@ -134,6 +134,11 @@ export class BreadcrumbsControl {
static readonly HEIGHT = 22;
private static readonly SCROLLBAR_SIZES = {
default: 3,
large: 8
};
static readonly Payload_Reveal = {};
static readonly Payload_RevealAside = {};
static readonly Payload_Pick = {};
@@ -148,6 +153,7 @@ export class BreadcrumbsControl {
private readonly _cfUseQuickPick: BreadcrumbsConfig<boolean>;
private readonly _cfShowIcons: BreadcrumbsConfig<boolean>;
private readonly _cfTitleScrollbarSizing: BreadcrumbsConfig<IEditorPartOptions['titleScrollbarSizing']>;
readonly domNode: HTMLDivElement;
private readonly _widget: BreadcrumbsWidget;
@@ -168,7 +174,7 @@ export class BreadcrumbsControl {
@IWorkspaceContextService private readonly _workspaceService: IWorkspaceContextService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IThemeService private readonly _themeService: IThemeService,
@IQuickOpenService private readonly _quickOpenService: IQuickOpenService,
@IQuickInputService private readonly _quickInputService: IQuickInputService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@ITextResourceConfigurationService private readonly _textResourceConfigurationService: ITextResourceConfigurationService,
@IFileService private readonly _fileService: IFileService,
@@ -180,7 +186,12 @@ export class BreadcrumbsControl {
dom.addClass(this.domNode, 'breadcrumbs-control');
dom.append(container, this.domNode);
this._widget = new BreadcrumbsWidget(this.domNode);
this._cfUseQuickPick = BreadcrumbsConfig.UseQuickPick.bindTo(_configurationService);
this._cfShowIcons = BreadcrumbsConfig.Icons.bindTo(_configurationService);
this._cfTitleScrollbarSizing = BreadcrumbsConfig.TitleScrollbarSizing.bindTo(_configurationService);
const sizing = this._cfTitleScrollbarSizing.getValue() ?? 'default';
this._widget = new BreadcrumbsWidget(this.domNode, BreadcrumbsControl.SCROLLBAR_SIZES[sizing]);
this._widget.onDidSelectItem(this._onSelectEvent, this, this._disposables);
this._widget.onDidFocusItem(this._onFocusEvent, this, this._disposables);
this._widget.onDidChangeFocus(this._updateCkBreadcrumbsActive, this, this._disposables);
@@ -190,9 +201,6 @@ export class BreadcrumbsControl {
this._ckBreadcrumbsVisible = BreadcrumbsControl.CK_BreadcrumbsVisible.bindTo(this._contextKeyService);
this._ckBreadcrumbsActive = BreadcrumbsControl.CK_BreadcrumbsActive.bindTo(this._contextKeyService);
this._cfUseQuickPick = BreadcrumbsConfig.UseQuickPick.bindTo(_configurationService);
this._cfShowIcons = BreadcrumbsConfig.Icons.bindTo(_configurationService);
this._disposables.add(breadcrumbsService.register(this._editorGroup.id, this._widget));
}
@@ -277,6 +285,14 @@ export class BreadcrumbsControl {
this._breadcrumbsDisposables.add(listener);
this._breadcrumbsDisposables.add(configListener);
const updateScrollbarSizing = () => {
const sizing = this._cfTitleScrollbarSizing.getValue() ?? 'default';
this._widget.setHorizontalScrollbarSize(BreadcrumbsControl.SCROLLBAR_SIZES[sizing]);
};
updateScrollbarSizing();
const updateScrollbarSizeListener = this._cfTitleScrollbarSizing.onDidChange(updateScrollbarSizing);
this._breadcrumbsDisposables.add(updateScrollbarSizeListener);
// close picker on hide/update
this._breadcrumbsDisposables.add({
dispose: () => {
@@ -343,7 +359,7 @@ export class BreadcrumbsControl {
// using quick pick
this._widget.setFocused(undefined);
this._widget.setSelection(undefined);
this._quickOpenService.show(element instanceof TreeElement ? '@' : '');
this._quickInputService.quickAccess.show(element instanceof TreeElement ? '@' : '');
return;
}

View File

@@ -6,8 +6,6 @@
import { Registry } from 'vs/platform/registry/common/platform';
import * as nls from 'vs/nls';
import { URI, UriComponents } from 'vs/base/common/uri';
import { Action, IAction } from 'vs/base/common/actions';
import { IEditorQuickOpenEntry, IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen';
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
import { EditorInput, IEditorInputFactory, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, TextCompareEditorActiveContext, EditorPinnedContext, EditorGroupEditorsCountContext } from 'vs/workbench/common/editor';
import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor';
@@ -21,15 +19,14 @@ import { SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textf
import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor';
import { ChangeEncodingAction, ChangeEOLAction, ChangeModeAction, EditorStatus } from 'vs/workbench/browser/parts/editor/editorStatus';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actions';
import { SyncActionDescriptor, MenuRegistry, MenuId, IMenuItem } from 'vs/platform/actions/common/actions';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import {
CloseEditorsInOtherGroupsAction, CloseAllEditorsAction, MoveGroupLeftAction, MoveGroupRightAction, SplitEditorAction, JoinTwoGroupsAction, OpenToSideFromQuickOpenAction, RevertAndCloseEditorAction,
CloseEditorsInOtherGroupsAction, CloseAllEditorsAction, MoveGroupLeftAction, MoveGroupRightAction, SplitEditorAction, JoinTwoGroupsAction, RevertAndCloseEditorAction,
NavigateBetweenGroupsAction, FocusActiveGroupAction, FocusFirstGroupAction, ResetGroupSizesAction, MaximizeGroupAction, MinimizeOtherGroupsAction, FocusPreviousGroup, FocusNextGroup,
toEditorQuickOpenEntry, CloseLeftEditorsInGroupAction, OpenNextEditor, OpenPreviousEditor, NavigateBackwardsAction, NavigateForwardAction, NavigateLastAction, ReopenClosedEditorAction,
QuickOpenPreviousRecentlyUsedEditorInGroupAction, QuickOpenPreviousEditorFromHistoryAction, ShowAllEditorsByAppearanceAction, ClearEditorHistoryAction, MoveEditorRightInGroupAction, OpenNextEditorInGroup,
CloseLeftEditorsInGroupAction, OpenNextEditor, OpenPreviousEditor, NavigateBackwardsAction, NavigateForwardAction, NavigateLastAction, ReopenClosedEditorAction,
QuickAccessPreviousRecentlyUsedEditorInGroupAction, QuickAccessPreviousEditorFromHistoryAction, ShowAllEditorsByAppearanceAction, ClearEditorHistoryAction, MoveEditorRightInGroupAction, OpenNextEditorInGroup,
OpenPreviousEditorInGroup, OpenNextRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorAction, MoveEditorToPreviousGroupAction,
MoveEditorToNextGroupAction, MoveEditorToFirstGroupAction, MoveEditorLeftInGroupAction, ClearRecentFilesAction, OpenLastEditorInGroup,
ShowEditorsInActiveGroupByMostRecentlyUsedAction, MoveEditorToLastGroupAction, OpenFirstEditorInGroup, MoveGroupUpAction, MoveGroupDownAction, FocusLastGroupAction, SplitEditorLeftAction, SplitEditorRightAction,
@@ -37,16 +34,14 @@ import {
JoinAllGroupsAction, FocusLeftGroup, FocusAboveGroup, FocusRightGroup, FocusBelowGroup, EditorLayoutSingleAction, EditorLayoutTwoColumnsAction, EditorLayoutThreeColumnsAction, EditorLayoutTwoByTwoGridAction,
EditorLayoutTwoRowsAction, EditorLayoutThreeRowsAction, EditorLayoutTwoColumnsBottomAction, EditorLayoutTwoRowsRightAction, NewEditorGroupLeftAction, NewEditorGroupRightAction,
NewEditorGroupAboveAction, NewEditorGroupBelowAction, SplitEditorOrthogonalAction, CloseEditorInAllGroupsAction, NavigateToLastEditLocationAction, ToggleGroupSizesAction, ShowAllEditorsByMostRecentlyUsedAction,
QuickOpenPreviousRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction, QuickOpenNextRecentlyUsedEditorAction as QuickOpenLeastRecentlyUsedEditorAction,
QuickOpenLeastRecentlyUsedEditorInGroupAction
QuickAccessPreviousRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction, QuickAccessLeastRecentlyUsedEditorAction, QuickAccessLeastRecentlyUsedEditorInGroupAction
} from 'vs/workbench/browser/parts/editor/editorActions';
import * as editorCommands from 'vs/workbench/browser/parts/editor/editorCommands';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { getQuickNavigateHandler, inQuickOpenContext } from 'vs/workbench/browser/parts/quickopen/quickopen';
import { inQuickPickContext, getQuickNavigateHandler } from 'vs/workbench/browser/quickaccess';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
import { isMacintosh } from 'vs/base/common/platform';
import { AllEditorsByAppearancePicker, ActiveGroupEditorsByMostRecentlyUsedPicker, AllEditorsByMostRecentlyUsedPicker } from 'vs/workbench/browser/parts/editor/editorPicker';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { OpenWorkspaceButtonContribution } from 'vs/workbench/browser/parts/editor/editorWidgets';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
@@ -270,101 +265,10 @@ if (Object.keys(SUPPORTED_ENCODINGS).length > 1) {
registry.registerWorkbenchAction(SyncActionDescriptor.create(ChangeEncodingAction, ChangeEncodingAction.ID, ChangeEncodingAction.LABEL), 'Change File Encoding');
}
export class QuickOpenActionContributor extends ActionBarContributor {
private openToSideActionInstance: OpenToSideFromQuickOpenAction | undefined;
constructor(@IInstantiationService private readonly instantiationService: IInstantiationService) {
super();
}
hasActions(context: unknown): boolean {
const entry = this.getEntry(context);
return !!entry;
}
getActions(context: unknown): ReadonlyArray<IAction> {
const actions: Action[] = [];
const entry = this.getEntry(context);
if (entry) {
if (!this.openToSideActionInstance) {
this.openToSideActionInstance = this.instantiationService.createInstance(OpenToSideFromQuickOpenAction);
} else {
this.openToSideActionInstance.updateClass();
}
actions.push(this.openToSideActionInstance);
}
return actions;
}
private getEntry(context: any): IEditorQuickOpenEntry | null {
if (!context || !context.element) {
return null;
}
return toEditorQuickOpenEntry(context.element);
}
}
const actionBarRegistry = Registry.as<IActionBarRegistry>(ActionBarExtensions.Actionbar);
actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionContributor);
const editorPickerContextKey = 'inEditorsPicker';
const editorPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(editorPickerContextKey));
Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpenHandler(
QuickOpenHandlerDescriptor.create(
ActiveGroupEditorsByMostRecentlyUsedPicker,
ActiveGroupEditorsByMostRecentlyUsedPicker.ID,
editorCommands.NAVIGATE_IN_ACTIVE_GROUP_BY_MOST_RECENTLY_USED_PREFIX,
editorPickerContextKey,
[
{
prefix: editorCommands.NAVIGATE_IN_ACTIVE_GROUP_BY_MOST_RECENTLY_USED_PREFIX,
needsEditor: false,
description: nls.localize('groupOnePicker', "Show Editors in Active Group By Most Recently Used")
}
]
)
);
Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpenHandler(
QuickOpenHandlerDescriptor.create(
AllEditorsByAppearancePicker,
AllEditorsByAppearancePicker.ID,
editorCommands.NAVIGATE_ALL_EDITORS_BY_APPEARANCE_PREFIX,
editorPickerContextKey,
[
{
prefix: editorCommands.NAVIGATE_ALL_EDITORS_BY_APPEARANCE_PREFIX,
needsEditor: false,
description: nls.localize('allEditorsPicker', "Show All Opened Editors By Appearance")
}
]
)
);
Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpenHandler(
QuickOpenHandlerDescriptor.create(
AllEditorsByMostRecentlyUsedPicker,
AllEditorsByMostRecentlyUsedPicker.ID,
editorCommands.NAVIGATE_ALL_EDITORS_BY_MOST_RECENTLY_USED_PREFIX,
editorPickerContextKey,
[
{
prefix: editorCommands.NAVIGATE_ALL_EDITORS_BY_MOST_RECENTLY_USED_PREFIX,
needsEditor: false,
description: nls.localize('allEditorsPickerByMostRecentlyUsed', "Show All Opened Editors By Most Recently Used")
}
]
)
);
// Register Editor Quick Access
const quickAccessRegistry = Registry.as<IQuickAccessRegistry>(QuickAccessExtensions.Quickaccess);
const editorPickerContextKey = 'inEditorsPicker';
const editorPickerContext = ContextKeyExpr.and(inQuickPickContext, ContextKeyExpr.has(editorPickerContextKey));
quickAccessRegistry.registerQuickAccessProvider({
ctor: ActiveGroupEditorsByMostRecentlyUsedQuickAccess,
@@ -469,29 +373,29 @@ registry.registerWorkbenchAction(SyncActionDescriptor.create(EditorLayoutTwoColu
// Register Quick Editor Actions including built in quick navigate support for some
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenPreviousRecentlyUsedEditorAction, QuickOpenPreviousRecentlyUsedEditorAction.ID, QuickOpenPreviousRecentlyUsedEditorAction.LABEL), 'View: Quick Open Previous Recently Used Editor', category);
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenLeastRecentlyUsedEditorAction, QuickOpenLeastRecentlyUsedEditorAction.ID, QuickOpenLeastRecentlyUsedEditorAction.LABEL), 'View: Quick Open Least Recently Used Editor', category);
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickAccessPreviousRecentlyUsedEditorAction, QuickAccessPreviousRecentlyUsedEditorAction.ID, QuickAccessPreviousRecentlyUsedEditorAction.LABEL), 'View: Quick Open Previous Recently Used Editor', category);
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickAccessLeastRecentlyUsedEditorAction, QuickAccessLeastRecentlyUsedEditorAction.ID, QuickAccessLeastRecentlyUsedEditorAction.LABEL), 'View: Quick Open Least Recently Used Editor', category);
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenPreviousRecentlyUsedEditorInGroupAction, QuickOpenPreviousRecentlyUsedEditorInGroupAction.ID, QuickOpenPreviousRecentlyUsedEditorInGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyCode.Tab } }), 'View: Quick Open Previous Recently Used Editor in Group', category);
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenLeastRecentlyUsedEditorInGroupAction, QuickOpenLeastRecentlyUsedEditorInGroupAction.ID, QuickOpenLeastRecentlyUsedEditorInGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } }), 'View: Quick Open Least Recently Used Editor in Group', category);
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickAccessPreviousRecentlyUsedEditorInGroupAction, QuickAccessPreviousRecentlyUsedEditorInGroupAction.ID, QuickAccessPreviousRecentlyUsedEditorInGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyCode.Tab } }), 'View: Quick Open Previous Recently Used Editor in Group', category);
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickAccessLeastRecentlyUsedEditorInGroupAction, QuickAccessLeastRecentlyUsedEditorInGroupAction.ID, QuickAccessLeastRecentlyUsedEditorInGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } }), 'View: Quick Open Least Recently Used Editor in Group', category);
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenPreviousEditorFromHistoryAction, QuickOpenPreviousEditorFromHistoryAction.ID, QuickOpenPreviousEditorFromHistoryAction.LABEL), 'Quick Open Previous Editor from History');
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickAccessPreviousEditorFromHistoryAction, QuickAccessPreviousEditorFromHistoryAction.ID, QuickAccessPreviousEditorFromHistoryAction.LABEL), 'Quick Open Previous Editor from History');
const quickOpenNavigateNextInEditorPickerId = 'workbench.action.quickOpenNavigateNextInEditorPicker';
const quickAccessNavigateNextInEditorPickerId = 'workbench.action.quickOpenNavigateNextInEditorPicker';
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: quickOpenNavigateNextInEditorPickerId,
id: quickAccessNavigateNextInEditorPickerId,
weight: KeybindingWeight.WorkbenchContrib + 50,
handler: getQuickNavigateHandler(quickOpenNavigateNextInEditorPickerId, true),
handler: getQuickNavigateHandler(quickAccessNavigateNextInEditorPickerId, true),
when: editorPickerContext,
primary: KeyMod.CtrlCmd | KeyCode.Tab,
mac: { primary: KeyMod.WinCtrl | KeyCode.Tab }
});
const quickOpenNavigatePreviousInEditorPickerId = 'workbench.action.quickOpenNavigatePreviousInEditorPicker';
const quickAccessNavigatePreviousInEditorPickerId = 'workbench.action.quickOpenNavigatePreviousInEditorPicker';
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: quickOpenNavigatePreviousInEditorPickerId,
id: quickAccessNavigatePreviousInEditorPickerId,
weight: KeybindingWeight.WorkbenchContrib + 50,
handler: getQuickNavigateHandler(quickOpenNavigatePreviousInEditorPickerId, false),
handler: getQuickNavigateHandler(quickAccessNavigatePreviousInEditorPickerId, false),
when: editorPickerContext,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab,
mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab }

View File

@@ -30,6 +30,7 @@ export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = {
highlightModifiedTabs: false,
tabCloseButton: 'right',
tabSizing: 'fit',
titleScrollbarSizing: 'default',
focusRecentEditorAfterClose: true,
showIcons: true,
enablePreview: true,

View File

@@ -5,26 +5,22 @@
import * as nls from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { mixin } from 'vs/base/common/objects';
import { IEditorInput, EditorInput, IEditorIdentifier, IEditorCommandsContext, CloseDirection, SaveReason, EditorsOrder, SideBySideEditorInput } from 'vs/workbench/common/editor';
import { QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { EditorQuickOpenEntry, EditorQuickOpenEntryGroup, IEditorQuickOpenEntry, QuickOpenAction } from 'vs/workbench/browser/quickopen';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { IEditorInput, IEditorIdentifier, IEditorCommandsContext, CloseDirection, SaveReason, EditorsOrder, SideBySideEditorInput } from 'vs/workbench/common/editor';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IResourceEditorInput } from 'vs/platform/editor/common/editor';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { CLOSE_EDITOR_COMMAND_ID, NAVIGATE_ALL_EDITORS_BY_APPEARANCE_PREFIX, MOVE_ACTIVE_EDITOR_COMMAND_ID, NAVIGATE_IN_ACTIVE_GROUP_BY_MOST_RECENTLY_USED_PREFIX, ActiveEditorMoveArguments, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, SPLIT_EDITOR_DOWN, splitEditor, LAYOUT_EDITOR_GROUPS_COMMAND_ID, mergeAllGroups, NAVIGATE_ALL_EDITORS_BY_MOST_RECENTLY_USED_PREFIX } from 'vs/workbench/browser/parts/editor/editorCommands';
import { CLOSE_EDITOR_COMMAND_ID, MOVE_ACTIVE_EDITOR_COMMAND_ID, ActiveEditorMoveArguments, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, SPLIT_EDITOR_DOWN, splitEditor, LAYOUT_EDITOR_GROUPS_COMMAND_ID, mergeAllGroups } from 'vs/workbench/browser/parts/editor/editorCommands';
import { IEditorGroupsService, IEditorGroup, GroupsArrangement, GroupLocation, GroupDirection, preferredSideBySideGroupDirection, IFindGroupScope, GroupOrientation, EditorGroupLayout, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { IFileDialogService, ConfirmResult } from 'vs/platform/dialogs/common/dialogs';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { values } from 'vs/base/common/map';
import { ItemActivation } from 'vs/platform/quickinput/common/quickInput';
import { ItemActivation, IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { AllEditorsByMostRecentlyUsedQuickAccess, ActiveGroupEditorsByMostRecentlyUsedQuickAccess, AllEditorsByAppearanceQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess';
export class ExecuteCommandAction extends Action {
@@ -390,63 +386,6 @@ export class FocusBelowGroup extends BaseFocusGroupAction {
}
}
export class OpenToSideFromQuickOpenAction extends Action {
static readonly OPEN_TO_SIDE_ID = 'workbench.action.openToSide';
static readonly OPEN_TO_SIDE_LABEL = nls.localize('openToSide', "Open to the Side");
constructor(
@IEditorService private readonly editorService: IEditorService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(OpenToSideFromQuickOpenAction.OPEN_TO_SIDE_ID, OpenToSideFromQuickOpenAction.OPEN_TO_SIDE_LABEL);
this.updateClass();
}
updateClass(): void {
const preferredDirection = preferredSideBySideGroupDirection(this.configurationService);
this.class = (preferredDirection === GroupDirection.RIGHT) ? 'codicon-split-horizontal' : 'codicon-split-vertical';
}
async run(context: unknown): Promise<void> {
const entry = toEditorQuickOpenEntry(context);
if (entry) {
const input = entry.getInput();
if (input) {
if (input instanceof EditorInput) {
await this.editorService.openEditor(input, entry.getOptions(), SIDE_GROUP);
return;
}
const resourceEditorInput = input as IResourceEditorInput;
resourceEditorInput.options = mixin(resourceEditorInput.options, entry.getOptions());
await this.editorService.openEditor(resourceEditorInput, SIDE_GROUP);
}
}
}
}
export function toEditorQuickOpenEntry(element: unknown): IEditorQuickOpenEntry | null {
// QuickOpenEntryGroup
if (element instanceof QuickOpenEntryGroup) {
const group = element;
if (group.getEntry()) {
element = group.getEntry();
}
}
// EditorQuickOpenEntry or EditorQuickOpenEntryGroup both implement IEditorQuickOpenEntry
if (element instanceof EditorQuickOpenEntry || element instanceof EditorQuickOpenEntryGroup) {
return element;
}
return null;
}
export class CloseEditorAction extends Action {
static readonly ID = 'workbench.action.closeActiveEditor';
@@ -1214,56 +1153,68 @@ export class ClearRecentFilesAction extends Action {
}
}
export class ShowEditorsInActiveGroupByMostRecentlyUsedAction extends QuickOpenAction {
export class ShowEditorsInActiveGroupByMostRecentlyUsedAction extends Action {
static readonly ID = 'workbench.action.showEditorsInActiveGroup';
static readonly LABEL = nls.localize('showEditorsInActiveGroup', "Show Editors in Active Group By Most Recently Used");
constructor(
actionId: string,
actionLabel: string,
@IQuickOpenService quickOpenService: IQuickOpenService
id: string,
label: string,
@IQuickInputService private readonly quickInputService: IQuickInputService
) {
super(actionId, actionLabel, NAVIGATE_IN_ACTIVE_GROUP_BY_MOST_RECENTLY_USED_PREFIX, quickOpenService);
super(id, label);
}
async run(): Promise<void> {
this.quickInputService.quickAccess.show(ActiveGroupEditorsByMostRecentlyUsedQuickAccess.PREFIX);
}
}
export class ShowAllEditorsByAppearanceAction extends QuickOpenAction {
export class ShowAllEditorsByAppearanceAction extends Action {
static readonly ID = 'workbench.action.showAllEditors';
static readonly LABEL = nls.localize('showAllEditors', "Show All Editors By Appearance");
constructor(
actionId: string,
actionLabel: string,
@IQuickOpenService quickOpenService: IQuickOpenService
id: string,
label: string,
@IQuickInputService private readonly quickInputService: IQuickInputService
) {
super(actionId, actionLabel, NAVIGATE_ALL_EDITORS_BY_APPEARANCE_PREFIX, quickOpenService);
super(id, label);
}
async run(): Promise<void> {
this.quickInputService.quickAccess.show(AllEditorsByAppearanceQuickAccess.PREFIX);
}
}
export class ShowAllEditorsByMostRecentlyUsedAction extends QuickOpenAction {
export class ShowAllEditorsByMostRecentlyUsedAction extends Action {
static readonly ID = 'workbench.action.showAllEditorsByMostRecentlyUsed';
static readonly LABEL = nls.localize('showAllEditorsByMostRecentlyUsed', "Show All Editors By Most Recently Used");
constructor(
actionId: string,
actionLabel: string,
@IQuickOpenService quickOpenService: IQuickOpenService
id: string,
label: string,
@IQuickInputService private readonly quickInputService: IQuickInputService
) {
super(actionId, actionLabel, NAVIGATE_ALL_EDITORS_BY_MOST_RECENTLY_USED_PREFIX, quickOpenService);
super(id, label);
}
async run(): Promise<void> {
this.quickInputService.quickAccess.show(AllEditorsByMostRecentlyUsedQuickAccess.PREFIX);
}
}
export class BaseQuickOpenEditorAction extends Action {
export class BaseQuickAccessEditorAction extends Action {
constructor(
id: string,
label: string,
private prefix: string,
private itemActivation: ItemActivation | undefined,
@IQuickOpenService private readonly quickOpenService: IQuickOpenService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IKeybindingService private readonly keybindingService: IKeybindingService
) {
super(id, label);
@@ -1272,14 +1223,14 @@ export class BaseQuickOpenEditorAction extends Action {
async run(): Promise<void> {
const keybindings = this.keybindingService.lookupKeybindings(this.id);
this.quickOpenService.show(this.prefix, {
this.quickInputService.quickAccess.show(this.prefix, {
quickNavigateConfiguration: { keybindings },
autoFocus: this.itemActivation === ItemActivation.LAST ? { autoFocusLastEntry: true } : undefined
itemActivation: this.itemActivation
});
}
}
export class QuickOpenPreviousRecentlyUsedEditorAction extends BaseQuickOpenEditorAction {
export class QuickAccessPreviousRecentlyUsedEditorAction extends BaseQuickAccessEditorAction {
static readonly ID = 'workbench.action.quickOpenPreviousRecentlyUsedEditor';
static readonly LABEL = nls.localize('quickOpenPreviousRecentlyUsedEditor', "Quick Open Previous Recently Used Editor");
@@ -1287,14 +1238,14 @@ export class QuickOpenPreviousRecentlyUsedEditorAction extends BaseQuickOpenEdit
constructor(
id: string,
label: string,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, NAVIGATE_ALL_EDITORS_BY_MOST_RECENTLY_USED_PREFIX, undefined, quickOpenService, keybindingService);
super(id, label, AllEditorsByMostRecentlyUsedQuickAccess.PREFIX, undefined, quickInputService, keybindingService);
}
}
export class QuickOpenNextRecentlyUsedEditorAction extends BaseQuickOpenEditorAction {
export class QuickAccessLeastRecentlyUsedEditorAction extends BaseQuickAccessEditorAction {
static readonly ID = 'workbench.action.quickOpenLeastRecentlyUsedEditor';
static readonly LABEL = nls.localize('quickOpenLeastRecentlyUsedEditor', "Quick Open Least Recently Used Editor");
@@ -1302,14 +1253,14 @@ export class QuickOpenNextRecentlyUsedEditorAction extends BaseQuickOpenEditorAc
constructor(
id: string,
label: string,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, NAVIGATE_ALL_EDITORS_BY_MOST_RECENTLY_USED_PREFIX, undefined, quickOpenService, keybindingService);
super(id, label, AllEditorsByMostRecentlyUsedQuickAccess.PREFIX, undefined, quickInputService, keybindingService);
}
}
export class QuickOpenPreviousRecentlyUsedEditorInGroupAction extends BaseQuickOpenEditorAction {
export class QuickAccessPreviousRecentlyUsedEditorInGroupAction extends BaseQuickAccessEditorAction {
static readonly ID = 'workbench.action.quickOpenPreviousRecentlyUsedEditorInGroup';
static readonly LABEL = nls.localize('quickOpenPreviousRecentlyUsedEditorInGroup', "Quick Open Previous Recently Used Editor in Group");
@@ -1317,14 +1268,14 @@ export class QuickOpenPreviousRecentlyUsedEditorInGroupAction extends BaseQuickO
constructor(
id: string,
label: string,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, NAVIGATE_IN_ACTIVE_GROUP_BY_MOST_RECENTLY_USED_PREFIX, undefined, quickOpenService, keybindingService);
super(id, label, ActiveGroupEditorsByMostRecentlyUsedQuickAccess.PREFIX, undefined, quickInputService, keybindingService);
}
}
export class QuickOpenLeastRecentlyUsedEditorInGroupAction extends BaseQuickOpenEditorAction {
export class QuickAccessLeastRecentlyUsedEditorInGroupAction extends BaseQuickAccessEditorAction {
static readonly ID = 'workbench.action.quickOpenLeastRecentlyUsedEditorInGroup';
static readonly LABEL = nls.localize('quickOpenLeastRecentlyUsedEditorInGroup', "Quick Open Least Recently Used Editor in Group");
@@ -1332,14 +1283,14 @@ export class QuickOpenLeastRecentlyUsedEditorInGroupAction extends BaseQuickOpen
constructor(
id: string,
label: string,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, NAVIGATE_IN_ACTIVE_GROUP_BY_MOST_RECENTLY_USED_PREFIX, ItemActivation.LAST, quickOpenService, keybindingService);
super(id, label, ActiveGroupEditorsByMostRecentlyUsedQuickAccess.PREFIX, ItemActivation.LAST, quickInputService, keybindingService);
}
}
export class QuickOpenPreviousEditorFromHistoryAction extends Action {
export class QuickAccessPreviousEditorFromHistoryAction extends Action {
static readonly ID = 'workbench.action.openPreviousEditorFromHistory';
static readonly LABEL = nls.localize('navigateEditorHistoryByInput', "Quick Open Previous Editor from History");
@@ -1347,7 +1298,7 @@ export class QuickOpenPreviousEditorFromHistoryAction extends Action {
constructor(
id: string,
label: string,
@IQuickOpenService private readonly quickOpenService: IQuickOpenService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IKeybindingService private readonly keybindingService: IKeybindingService
) {
super(id, label);
@@ -1356,7 +1307,7 @@ export class QuickOpenPreviousEditorFromHistoryAction extends Action {
async run(): Promise<void> {
const keybindings = this.keybindingService.lookupKeybindings(this.id);
this.quickOpenService.show(undefined, { quickNavigateConfiguration: { keybindings } });
this.quickInputService.quickAccess.show('', { quickNavigateConfiguration: { keybindings } });
}
}

View File

@@ -13,7 +13,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor';
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
import { URI } from 'vs/base/common/uri';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IListService } from 'vs/platform/list/browser/listService';
import { List } from 'vs/base/browser/ui/list/listWidget';
import { distinct, coalesce } from 'vs/base/common/arrays';
@@ -22,6 +22,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands';
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { ActiveGroupEditorsByMostRecentlyUsedQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess';
export const CLOSE_SAVED_EDITORS_COMMAND_ID = 'workbench.action.closeUnmodifiedEditors';
export const CLOSE_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeEditorsInGroup';
@@ -46,10 +47,6 @@ export const SPLIT_EDITOR_DOWN = 'workbench.action.splitEditorDown';
export const SPLIT_EDITOR_LEFT = 'workbench.action.splitEditorLeft';
export const SPLIT_EDITOR_RIGHT = 'workbench.action.splitEditorRight';
export const NAVIGATE_ALL_EDITORS_BY_APPEARANCE_PREFIX = 'edt ';
export const NAVIGATE_ALL_EDITORS_BY_MOST_RECENTLY_USED_PREFIX = 'edt mru ';
export const NAVIGATE_IN_ACTIVE_GROUP_BY_MOST_RECENTLY_USED_PREFIX = 'edt active ';
export const OPEN_EDITOR_AT_INDEX_COMMAND_ID = 'workbench.action.openEditorAtIndex';
export interface ActiveEditorMoveArguments {
@@ -652,7 +649,7 @@ function registerCloseEditorCommands() {
primary: undefined,
handler: (accessor, resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext) => {
const editorGroupService = accessor.get(IEditorGroupsService);
const quickOpenService = accessor.get(IQuickOpenService);
const quickInputService = accessor.get(IQuickInputService);
const commandsContext = getCommandsContext(resourceOrContext, context);
if (commandsContext && typeof commandsContext.groupId === 'number') {
@@ -662,7 +659,7 @@ function registerCloseEditorCommands() {
}
}
return quickOpenService.show(NAVIGATE_IN_ACTIVE_GROUP_BY_MOST_RECENTLY_USED_PREFIX);
return quickInputService.quickAccess.show(ActiveGroupEditorsByMostRecentlyUsedQuickAccess.PREFIX);
}
});

View File

@@ -23,10 +23,10 @@ export interface IOpenEditorResult {
export class EditorControl extends Disposable {
get minimumWidth() { return this._activeEditorPane ? this._activeEditorPane.minimumWidth : DEFAULT_EDITOR_MIN_DIMENSIONS.width; }
get minimumHeight() { return this._activeEditorPane ? this._activeEditorPane.minimumHeight : DEFAULT_EDITOR_MIN_DIMENSIONS.height; }
get maximumWidth() { return this._activeEditorPane ? this._activeEditorPane.maximumWidth : DEFAULT_EDITOR_MAX_DIMENSIONS.width; }
get maximumHeight() { return this._activeEditorPane ? this._activeEditorPane.maximumHeight : DEFAULT_EDITOR_MAX_DIMENSIONS.height; }
get minimumWidth() { return this._activeEditorPane?.minimumWidth ?? DEFAULT_EDITOR_MIN_DIMENSIONS.width; }
get minimumHeight() { return this._activeEditorPane?.minimumHeight ?? DEFAULT_EDITOR_MIN_DIMENSIONS.height; }
get maximumWidth() { return this._activeEditorPane?.maximumWidth ?? DEFAULT_EDITOR_MAX_DIMENSIONS.width; }
get maximumHeight() { return this._activeEditorPane?.maximumHeight ?? DEFAULT_EDITOR_MAX_DIMENSIONS.height; }
private readonly _onDidFocus = this._register(new Emitter<void>());
readonly onDidFocus = this._onDidFocus.event;

View File

@@ -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.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/editorpicker';
import * as nls from 'vs/nls';
import { IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { IAutoFocus, Mode, IEntryRunContext, IQuickNavigateConfiguration, IModel } from 'vs/base/parts/quickopen/common/quickOpen';
import { QuickOpenModel, QuickOpenEntry, QuickOpenEntryGroup, QuickOpenItemAccessor } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { IModeService } from 'vs/editor/common/services/modeService';
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { IModelService } from 'vs/editor/common/services/modelService';
import { QuickOpenHandler } from 'vs/workbench/browser/quickopen';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService, IEditorGroup, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { toResource, SideBySideEditor, IEditorInput, EditorsOrder } from 'vs/workbench/common/editor';
import { compareItemsByScore, scoreItem, ScorerCache, prepareQuery } from 'vs/base/common/fuzzyScorer';
import { CancellationToken } from 'vs/base/common/cancellation';
export class EditorPickerEntry extends QuickOpenEntryGroup {
constructor(
private editor: IEditorInput,
public readonly group: IEditorGroup,
@IModeService private readonly modeService: IModeService,
@IModelService private readonly modelService: IModelService
) {
super();
}
getLabelOptions(): IIconLabelValueOptions {
return {
extraClasses: getIconClasses(this.modelService, this.modeService, this.getResource()),
italic: !this.group.isPinned(this.editor)
};
}
getLabel(): string {
return this.editor.getName();
}
getIcon(): string {
return this.editor.isDirty() && !this.editor.isSaving() ? 'codicon codicon-circle-filled' : '';
}
getResource() {
return toResource(this.editor, { supportSideBySide: SideBySideEditor.MASTER });
}
getAriaLabel(): string {
return nls.localize('entryAriaLabel', "{0}, editor group picker", this.getLabel());
}
getDescription() {
return this.editor.getDescription();
}
run(mode: Mode, context: IEntryRunContext): boolean {
if (mode === Mode.OPEN) {
return this.runOpen(context);
}
return super.run(mode, context);
}
private runOpen(context: IEntryRunContext): boolean {
this.group.openEditor(this.editor);
return true;
}
}
export abstract class BaseEditorPicker extends QuickOpenHandler {
private scorerCache: ScorerCache;
constructor(
@IInstantiationService protected instantiationService: IInstantiationService,
@IEditorService protected editorService: IEditorService,
@IEditorGroupsService protected editorGroupService: IEditorGroupsService
) {
super();
this.scorerCache = Object.create(null);
}
getResults(searchValue: string, token: CancellationToken): Promise<QuickOpenModel | null> {
const editorEntries = this.getEditorEntries();
if (!editorEntries.length) {
return Promise.resolve(null);
}
// Prepare search for scoring
const query = prepareQuery(searchValue);
const entries = editorEntries.filter(e => {
if (!query.value) {
return true;
}
const itemScore = scoreItem(e, query, true, QuickOpenItemAccessor, this.scorerCache);
if (!itemScore.score) {
return false;
}
e.setHighlights(itemScore.labelMatch || [], itemScore.descriptionMatch);
return true;
});
// Sorting
if (query.value) {
const groups = this.editorGroupService.getGroups(GroupsOrder.GRID_APPEARANCE);
entries.sort((e1, e2) => {
if (e1.group !== e2.group) {
return groups.indexOf(e1.group) - groups.indexOf(e2.group); // older groups first
}
return compareItemsByScore(e1, e2, query, true, QuickOpenItemAccessor, this.scorerCache);
});
}
// Grouping (for more than one group)
if (this.editorGroupService.count > 1) {
let lastGroup: IEditorGroup;
entries.forEach(e => {
if (!lastGroup || lastGroup !== e.group) {
e.setGroupLabel(e.group.label);
e.setShowBorder(!!lastGroup);
lastGroup = e.group;
}
});
}
return Promise.resolve(new QuickOpenModel(entries));
}
onClose(canceled: boolean): void {
this.scorerCache = Object.create(null);
}
protected abstract count(): number;
protected abstract getEditorEntries(): EditorPickerEntry[];
getAutoFocus(searchValue: string, context: { model: IModel<QuickOpenEntry>, quickNavigateConfiguration?: IQuickNavigateConfiguration }): IAutoFocus {
if (searchValue || !context.quickNavigateConfiguration) {
return {
autoFocusFirstEntry: true
};
}
const isShiftNavigate = (context.quickNavigateConfiguration && context.quickNavigateConfiguration.keybindings.some(k => {
const [firstPart, chordPart] = k.getParts();
if (chordPart) {
return false;
}
return firstPart.shiftKey;
}));
if (isShiftNavigate) {
return {
autoFocusLastEntry: true
};
}
const editors = this.count();
return {
autoFocusFirstEntry: editors === 1,
autoFocusSecondEntry: editors > 1
};
}
}
export class ActiveGroupEditorsByMostRecentlyUsedPicker extends BaseEditorPicker {
static readonly ID = 'workbench.picker.activeGroupEditorsByMostRecentlyUsed';
protected count(): number {
return this.group.count;
}
protected getEditorEntries(): EditorPickerEntry[] {
return this.group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE).map(editor => this.instantiationService.createInstance(EditorPickerEntry, editor, this.group));
}
private get group(): IEditorGroup {
return this.editorGroupService.activeGroup;
}
getEmptyLabel(searchString: string): string {
if (searchString) {
return nls.localize('noResultsFoundInGroup', "No matching opened editor found in active editor group");
}
return nls.localize('noOpenedEditors', "List of opened editors is currently empty in active editor group");
}
}
export abstract class BaseAllEditorsPicker extends BaseEditorPicker {
constructor(
@IInstantiationService instantiationService: IInstantiationService,
@IEditorService editorService: IEditorService,
@IEditorGroupsService editorGroupService: IEditorGroupsService
) {
super(instantiationService, editorService, editorGroupService);
}
protected count(): number {
return this.editorService.count;
}
getEmptyLabel(searchString: string): string {
if (searchString) {
return nls.localize('noResultsFound', "No matching opened editor found");
}
return nls.localize('noOpenedEditorsAllGroups', "List of opened editors is currently empty");
}
getAutoFocus(searchValue: string, context: { model: IModel<QuickOpenEntry>, quickNavigateConfiguration?: IQuickNavigateConfiguration }): IAutoFocus {
if (searchValue) {
return {
autoFocusFirstEntry: true
};
}
return super.getAutoFocus(searchValue, context);
}
}
export class AllEditorsByAppearancePicker extends BaseAllEditorsPicker {
static readonly ID = 'workbench.picker.editorsByAppearance';
protected getEditorEntries(): EditorPickerEntry[] {
const entries: EditorPickerEntry[] = [];
for (const group of this.editorGroupService.getGroups(GroupsOrder.GRID_APPEARANCE)) {
for (const editor of group.getEditors(EditorsOrder.SEQUENTIAL)) {
entries.push(this.instantiationService.createInstance(EditorPickerEntry, editor, group));
}
}
return entries;
}
}
export class AllEditorsByMostRecentlyUsedPicker extends BaseAllEditorsPicker {
static readonly ID = 'workbench.picker.editorsByMostRecentlyUsed';
protected getEditorEntries(): EditorPickerEntry[] {
const entries: EditorPickerEntry[] = [];
for (const { editor, groupId } of this.editorService.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE)) {
entries.push(this.instantiationService.createInstance(EditorPickerEntry, editor, this.editorGroupService.getGroup(groupId)!));
}
return entries;
}
}

View File

@@ -127,10 +127,6 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
iconClasses: getIconClasses(this.modelService, this.modeService, resource),
italic: !this.editorGroupService.getGroup(groupId)?.isPinned(editor),
buttons: (() => {
if (this.pickState.isQuickNavigating) {
return undefined; // no actions when quick navigating
}
return [
{
iconClass: isDirty ? 'dirty-editor codicon-circle-filled' : 'codicon-close',

View File

@@ -1212,7 +1212,7 @@ export class ChangeModeAction extends Action {
this.configurationService.updateValue(FILES_ASSOCIATIONS_CONFIG, currentAssociations, target);
}
}, 50 /* quick open is sensitive to being opened so soon after another */);
}, 50 /* quick input is sensitive to being opened so soon after another */);
}
private getFakeResource(lang: string): URI | undefined {
@@ -1347,7 +1347,7 @@ export class ChangeEncodingAction extends Action {
return;
}
await timeout(50); // quick open is sensitive to being opened so soon after another
await timeout(50); // quick input is sensitive to being opened so soon after another
const resource = toResource(activeEditorPane.input, { supportSideBySide: SideBySideEditor.MASTER });
if (!resource || (!this.fileService.canHandleResource(resource) && resource.scheme !== Schemas.untitled)) {

View File

@@ -1,8 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench .monaco-quick-open-widget .quick-open-tree .quick-open-entry.editor-preview {
font-style: italic;
}

View File

@@ -88,8 +88,8 @@ export class NoTabsTitleControl extends TitleControl {
private onTitleLabelClick(e: MouseEvent): void {
EventHelper.stop(e, false);
// delayed to let the onTitleClick() come first which can cause a focus change which can close quick open
setTimeout(() => this.quickOpenService.show());
// delayed to let the onTitleClick() come first which can cause a focus change which can close quick access
setTimeout(() => this.quickInputService.quickAccess.show());
}
private onTitleDoubleClick(e: MouseEvent): void {
@@ -111,10 +111,10 @@ export class NoTabsTitleControl extends TitleControl {
}
} else {
// TODO@rebornix
// gesture tap should open the quick open
// gesture tap should open the quick access
// editorGroupView will focus on the editor again when there are mouse/pointer/touch down events
// we need to wait a bit as `GesureEvent.Tap` is generated from `touchstart` and then `touchend` evnets, which are not an atom event.
setTimeout(() => this.quickOpenService.show(), 50);
setTimeout(() => this.quickInputService.quickAccess.show(), 50);
}
}

View File

@@ -19,7 +19,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IMenuService } from 'vs/platform/actions/common/actions';
import { TitleControl } from 'vs/workbench/browser/parts/editor/titleControl';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IDisposable, dispose, DisposableStore, combinedDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
@@ -61,6 +61,11 @@ type AugmentedLabel = IEditorInputLabel & { editor: IEditorInput };
export class TabsTitleControl extends TitleControl {
private static readonly SCROLLBAR_SIZES = {
default: 3,
large: 10
};
private titleContainer: HTMLElement | undefined;
private tabsContainer: HTMLElement | undefined;
private editorToolbarContainer: HTMLElement | undefined;
@@ -89,7 +94,7 @@ export class TabsTitleControl extends TitleControl {
@ITelemetryService telemetryService: ITelemetryService,
@INotificationService notificationService: INotificationService,
@IMenuService menuService: IMenuService,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IQuickInputService quickInputService: IQuickInputService,
@IThemeService themeService: IThemeService,
@IExtensionService extensionService: IExtensionService,
@IConfigurationService configurationService: IConfigurationService,
@@ -97,7 +102,7 @@ export class TabsTitleControl extends TitleControl {
@IEditorService private readonly editorService: EditorServiceImpl,
@IRemotePathService private readonly remotePathService: IRemotePathService
) {
super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService, configurationService, fileService);
super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickInputService, themeService, extensionService, configurationService, fileService);
this.tabResourceLabels = this._register(this.instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER));
this.closeOneEditorAction = this._register(this.instantiationService.createInstance(CloseOneEditorAction, CloseOneEditorAction.ID, CloseOneEditorAction.LABEL));
@@ -108,6 +113,16 @@ export class TabsTitleControl extends TitleControl {
(async () => this.path = await this.remotePathService.path)();
}
protected registerListeners(): void {
super.registerListeners();
this._register(this.accessor.onDidEditorPartOptionsChange(e => {
if (e.oldPartOptions.titleScrollbarSizing !== e.newPartOptions.titleScrollbarSizing) {
this.updateTabsScrollbarSizing();
}
}));
}
protected create(parent: HTMLElement): void {
this.titleContainer = parent;
@@ -148,10 +163,10 @@ export class TabsTitleControl extends TitleControl {
private createTabsScrollbar(scrollable: HTMLElement): ScrollableElement {
const tabsScrollbar = new ScrollableElement(scrollable, {
horizontal: ScrollbarVisibility.Auto,
horizontalScrollbarSize: this.getTabsScrollbarSizing(),
vertical: ScrollbarVisibility.Hidden,
scrollYToX: true,
useShadows: false,
horizontalScrollbarSize: 3
useShadows: false
});
tabsScrollbar.onScroll(e => {
@@ -161,6 +176,20 @@ export class TabsTitleControl extends TitleControl {
return tabsScrollbar;
}
private updateTabsScrollbarSizing(): void {
this.tabsScrollbar?.updateOptions({
horizontalScrollbarSize: this.getTabsScrollbarSizing()
});
}
private getTabsScrollbarSizing(): number {
if (this.accessor.partOptions.titleScrollbarSizing !== 'large') {
return TabsTitleControl.SCROLLBAR_SIZES.default;
}
return TabsTitleControl.SCROLLBAR_SIZES.large;
}
private updateBreadcrumbsControl(): void {
if (this.breadcrumbsControl && this.breadcrumbsControl.update()) {
// relayout when we have a breadcrumbs and when update changed

View File

@@ -6,7 +6,7 @@
import { applyDragImage, DataTransfers } from 'vs/base/browser/dnd';
import { addDisposableListener, Dimension, EventType } from 'vs/base/browser/dom';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { ActionsOrientation, IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { ActionsOrientation, IActionViewItem, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IAction, IRunEvent, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
import * as arrays from 'vs/base/common/arrays';
@@ -23,11 +23,10 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { listActiveSelectionBackground, listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry';
import { ICssStyleCollector, IColorTheme, IThemeService, registerThemingParticipant, Themable } from 'vs/platform/theme/common/themeService';
import { prepareActions } from 'vs/workbench/browser/actions';
import { DraggedEditorGroupIdentifier, DraggedEditorIdentifier, fillResourceDataTransfers, LocalSelectionTransfer } from 'vs/workbench/browser/dnd';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { BreadcrumbsConfig } from 'vs/workbench/browser/parts/editor/breadcrumbs';
@@ -77,7 +76,7 @@ export abstract class TitleControl extends Themable {
// {{SQL CARBON EDIT}} -- need to make the notification service protected
@INotificationService protected readonly notificationService: INotificationService,
@IMenuService private readonly menuService: IMenuService,
@IQuickOpenService protected quickOpenService: IQuickOpenService,
@IQuickInputService protected quickInputService: IQuickInputService,
@IThemeService themeService: IThemeService,
@IExtensionService private readonly extensionService: IExtensionService,
@IConfigurationService protected configurationService: IConfigurationService,
@@ -94,7 +93,7 @@ export abstract class TitleControl extends Themable {
this.registerListeners();
}
private registerListeners(): void {
protected registerListeners(): void {
// Update actions toolbar when extension register that may contribute them
this._register(this.extensionService.onDidRegisterExtensions(() => this.updateEditorActionsToolbar()));

View File

@@ -1,15 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.vs .monaco-workbench .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.none,
.vs-dark .monaco-workbench .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.none {
width: 16px;
background: none;
}
.monaco-workbench .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.dirty {
width: 14px;
height: 18px;
}

View File

@@ -1,137 +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 { Registry } from 'vs/platform/registry/common/platform';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { RemoveFromEditorHistoryAction } from 'vs/workbench/browser/parts/quickopen/quickOpenController';
import { QuickOpenSelectNextAction, QuickOpenSelectPreviousAction, inQuickOpenContext, getQuickNavigateHandler, QuickOpenNavigateNextAction, QuickOpenNavigatePreviousAction, defaultQuickOpenContext, QUICKOPEN_ACTION_ID, QUICKOPEN_ACION_LABEL } from 'vs/workbench/browser/parts/quickopen/quickopen';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.closeQuickOpen',
weight: KeybindingWeight.WorkbenchContrib,
when: inQuickOpenContext,
primary: KeyCode.Escape, secondary: [KeyMod.Shift | KeyCode.Escape],
handler: accessor => {
const quickOpenService = accessor.get(IQuickOpenService);
quickOpenService.close();
const quickInputService = accessor.get(IQuickInputService);
return quickInputService.cancel();
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.acceptSelectedQuickOpenItem',
weight: KeybindingWeight.WorkbenchContrib,
when: inQuickOpenContext,
primary: 0,
handler: accessor => {
const quickOpenService = accessor.get(IQuickOpenService);
quickOpenService.accept();
const quickInputService = accessor.get(IQuickInputService);
return quickInputService.accept();
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.alternativeAcceptSelectedQuickOpenItem',
weight: KeybindingWeight.WorkbenchContrib,
when: inQuickOpenContext,
primary: 0,
handler: accessor => {
const quickInputService = accessor.get(IQuickInputService);
return quickInputService.accept({ ctrlCmd: true, alt: false });
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.focusQuickOpen',
weight: KeybindingWeight.WorkbenchContrib,
when: inQuickOpenContext,
primary: 0,
handler: accessor => {
const quickOpenService = accessor.get(IQuickOpenService);
quickOpenService.focus();
const quickInputService = accessor.get(IQuickInputService);
quickInputService.focus();
}
});
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
const globalQuickOpenKeybinding = { primary: KeyMod.CtrlCmd | KeyCode.KEY_P, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_E], mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_P, secondary: undefined } };
KeybindingsRegistry.registerKeybindingRule({
id: QUICKOPEN_ACTION_ID,
weight: KeybindingWeight.WorkbenchContrib,
when: undefined,
primary: globalQuickOpenKeybinding.primary,
secondary: globalQuickOpenKeybinding.secondary,
mac: globalQuickOpenKeybinding.mac
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: { id: QUICKOPEN_ACTION_ID, title: { value: QUICKOPEN_ACION_LABEL, original: 'Go to File...' } }
});
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenSelectNextAction, QuickOpenSelectNextAction.ID, QuickOpenSelectNextAction.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_N } }, inQuickOpenContext, KeybindingWeight.WorkbenchContrib + 50), 'Select Next in Quick Open');
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenSelectPreviousAction, QuickOpenSelectPreviousAction.ID, QuickOpenSelectPreviousAction.LABEL, { primary: 0, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_P } }, inQuickOpenContext, KeybindingWeight.WorkbenchContrib + 50), 'Select Previous in Quick Open');
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenNavigateNextAction, QuickOpenNavigateNextAction.ID, QuickOpenNavigateNextAction.LABEL), 'Navigate Next in Quick Open');
registry.registerWorkbenchAction(SyncActionDescriptor.create(QuickOpenNavigatePreviousAction, QuickOpenNavigatePreviousAction.ID, QuickOpenNavigatePreviousAction.LABEL), 'Navigate Previous in Quick Open');
registry.registerWorkbenchAction(SyncActionDescriptor.create(RemoveFromEditorHistoryAction, RemoveFromEditorHistoryAction.ID, RemoveFromEditorHistoryAction.LABEL), 'Remove From History');
const quickOpenNavigateNextInFilePickerId = 'workbench.action.quickOpenNavigateNextInFilePicker';
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: quickOpenNavigateNextInFilePickerId,
weight: KeybindingWeight.WorkbenchContrib + 50,
handler: getQuickNavigateHandler(quickOpenNavigateNextInFilePickerId, true),
when: defaultQuickOpenContext,
primary: globalQuickOpenKeybinding.primary,
secondary: globalQuickOpenKeybinding.secondary,
mac: globalQuickOpenKeybinding.mac
});
const quickOpenNavigatePreviousInFilePickerId = 'workbench.action.quickOpenNavigatePreviousInFilePicker';
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: quickOpenNavigatePreviousInFilePickerId,
weight: KeybindingWeight.WorkbenchContrib + 50,
handler: getQuickNavigateHandler(quickOpenNavigatePreviousInFilePickerId, false),
when: defaultQuickOpenContext,
primary: globalQuickOpenKeybinding.primary | KeyMod.Shift,
secondary: [globalQuickOpenKeybinding.secondary[0] | KeyMod.Shift],
mac: {
primary: globalQuickOpenKeybinding.mac.primary | KeyMod.Shift,
secondary: undefined
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.quickPickManyToggle',
weight: KeybindingWeight.WorkbenchContrib,
when: inQuickOpenContext,
primary: 0,
handler: accessor => {
const quickInputService = accessor.get(IQuickInputService);
quickInputService.toggle();
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.quickInputBack',
weight: KeybindingWeight.WorkbenchContrib + 50,
when: inQuickOpenContext,
primary: 0,
win: { primary: KeyMod.Alt | KeyCode.LeftArrow },
mac: { primary: KeyMod.WinCtrl | KeyCode.US_MINUS },
linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.US_MINUS },
handler: accessor => {
const quickInputService = accessor.get(IQuickInputService);
quickInputService.back();
}
});

View File

@@ -1,910 +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 'vs/css!./media/quickopen';
import * as nls from 'vs/nls';
import * as browser from 'vs/base/browser/browser';
import * as strings from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import * as resources from 'vs/base/common/resources';
import * as types from 'vs/base/common/types';
import { Action } from 'vs/base/common/actions';
import { IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { Mode, IEntryRunContext, IAutoFocus, IQuickNavigateConfiguration, IModel } from 'vs/base/parts/quickopen/common/quickOpen';
import { QuickOpenEntry, QuickOpenModel, QuickOpenEntryGroup, QuickOpenItemAccessorClass } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { QuickOpenWidget, HideReason } from 'vs/base/parts/quickopen/browser/quickOpenWidget';
import { ContributableActionProvider } from 'vs/workbench/browser/actions';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { Registry } from 'vs/platform/registry/common/platform';
import { IResourceEditorInput } from 'vs/platform/editor/common/editor';
import { IModeService } from 'vs/editor/common/services/modeService';
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { IModelService } from 'vs/editor/common/services/modelService';
import { EditorInput, IWorkbenchEditorConfiguration, IEditorInput } from 'vs/workbench/common/editor';
import { Component } from 'vs/workbench/common/component';
import { Event, Emitter } from 'vs/base/common/event';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { QuickOpenHandler, QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions, EditorQuickOpenEntry, CLOSE_ON_FOCUS_LOST_CONFIG, SEARCH_EDITOR_HISTORY, PRESERVE_INPUT_CONFIG, ENABLE_EXPERIMENTAL_VERSION_CONFIG } from 'vs/workbench/browser/quickopen';
import * as errors from 'vs/base/common/errors';
import { IQuickOpenService, IShowOptions } from 'vs/platform/quickOpen/common/quickOpen';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { quickInputBackground, quickInputForeground } from 'vs/platform/theme/common/colorRegistry';
import { attachQuickOpenStyler } from 'vs/platform/theme/common/styler';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IFileService } from 'vs/platform/files/common/files';
import { scoreItem, ScorerCache, compareItemsByScore, prepareQuery } from 'vs/base/common/fuzzyScorer';
import { WorkbenchTree } from 'vs/platform/list/browser/listService';
import { Schemas } from 'vs/base/common/network';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { Dimension, addClass } from 'vs/base/browser/dom';
import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ILabelService } from 'vs/platform/label/common/label';
import { timeout } from 'vs/base/common/async';
import { IQuickInputService, IQuickPickItem, ItemActivation } from 'vs/platform/quickinput/common/quickInput';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
const HELP_PREFIX = '?';
type ValueCallback<T = any> = (value: T | Promise<T>) => void;
export class QuickOpenController extends Component implements IQuickOpenService {
private static readonly MAX_SHORT_RESPONSE_TIME = 500;
private static readonly ID = 'workbench.component.quickopen';
_serviceBrand: undefined;
private readonly _onShow: Emitter<void> = this._register(new Emitter<void>());
readonly onShow: Event<void> = this._onShow.event;
private readonly _onHide: Emitter<void> = this._register(new Emitter<void>());
readonly onHide: Event<void> = this._onHide.event;
private preserveInput: boolean | undefined;
private isQuickOpen: boolean | undefined;
private lastInputValue: string | undefined;
private lastSubmittedInputValue: string | undefined;
private quickOpenWidget: QuickOpenWidget | undefined;
private mapResolvedHandlersToPrefix: Map<string, Promise<QuickOpenHandler>> = new Map();
private mapContextKeyToContext: Map<string, IContextKey<boolean>> = new Map();
private handlerOnOpenCalled: Set<string> = new Set();
private promisesToCompleteOnHide: ValueCallback[] = [];
private previousActiveHandlerDescriptor: QuickOpenHandlerDescriptor | null | undefined;
private actionProvider = new ContributableActionProvider();
private closeOnFocusLost: boolean | undefined;
private searchInEditorHistory: boolean | undefined;
private editorHistoryHandler: EditorHistoryHandler;
private pendingGetResultsInvocation: CancellationTokenSource | null = null;
private get useNewExperimentalVersion() {
return this.configurationService.getValue(ENABLE_EXPERIMENTAL_VERSION_CONFIG) === true;
}
constructor(
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@INotificationService private readonly notificationService: INotificationService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IThemeService themeService: IThemeService,
@IStorageService storageService: IStorageService,
@IQuickInputService private readonly quickInputService: IQuickInputService
) {
super(QuickOpenController.ID, themeService, storageService);
this.editorHistoryHandler = this.instantiationService.createInstance(EditorHistoryHandler);
this.updateConfiguration();
this.registerListeners();
}
private registerListeners(): void {
this._register(this.configurationService.onDidChangeConfiguration(() => this.updateConfiguration()));
this._register(this.layoutService.onPartVisibilityChange(() => this.positionQuickOpenWidget()));
this._register(browser.onDidChangeZoomLevel(() => this.positionQuickOpenWidget()));
this._register(this.layoutService.onLayout(dimension => this.layout(dimension)));
}
private updateConfiguration(): void {
if (this.environmentService.args['sticky-quickopen']) {
this.closeOnFocusLost = false;
} else {
this.closeOnFocusLost = this.configurationService.getValue(CLOSE_ON_FOCUS_LOST_CONFIG);
}
this.preserveInput = this.configurationService.getValue(PRESERVE_INPUT_CONFIG);
this.searchInEditorHistory = this.configurationService.getValue(SEARCH_EDITOR_HISTORY);
}
navigate(next: boolean, quickNavigate?: IQuickNavigateConfiguration): void {
if (this.useNewExperimentalVersion) {
// already handled
} else {
if (this.quickOpenWidget) {
this.quickOpenWidget.navigate(next, quickNavigate);
}
}
}
accept(): void {
if (this.useNewExperimentalVersion) {
// already handled
} else {
if (this.quickOpenWidget && this.quickOpenWidget.isVisible()) {
this.quickOpenWidget.accept();
}
}
}
focus(): void {
if (this.useNewExperimentalVersion) {
// already handled
} else {
if (this.quickOpenWidget && this.quickOpenWidget.isVisible()) {
this.quickOpenWidget.focus();
}
}
}
close(): void {
if (this.useNewExperimentalVersion) {
// already handled
} else {
if (this.quickOpenWidget && this.quickOpenWidget.isVisible()) {
this.quickOpenWidget.hide(HideReason.CANCELED);
}
}
}
private emitQuickOpenVisibilityChange(isVisible: boolean): void {
if (isVisible) {
this._onShow.fire();
} else {
this._onHide.fire();
}
}
show(prefix?: string, options?: IShowOptions): Promise<void> {
if (this.useNewExperimentalVersion) {
this.quickInputService.quickAccess.show(prefix, {
quickNavigateConfiguration: options?.quickNavigateConfiguration,
itemActivation: (() => {
if (options?.autoFocus?.autoFocusSecondEntry) {
return ItemActivation.SECOND;
}
if (options?.autoFocus?.autoFocusLastEntry) {
return ItemActivation.LAST;
}
return undefined;
})()
});
return Promise.resolve();
}
let quickNavigateConfiguration = options ? options.quickNavigateConfiguration : undefined;
let inputSelection = options ? options.inputSelection : undefined;
let autoFocus = options ? options.autoFocus : undefined;
const promiseCompletedOnHide = new Promise<void>(c => {
this.promisesToCompleteOnHide.push(c);
});
// Telemetry: log that quick open is shown and log the mode
const registry = Registry.as<IQuickOpenRegistry>(Extensions.Quickopen);
const handlerDescriptor = (prefix ? registry.getQuickOpenHandler(prefix) : undefined) || registry.getDefaultQuickOpenHandler();
// Trigger onOpen
this.resolveHandler(handlerDescriptor);
// Create upon first open
if (!this.quickOpenWidget) {
const quickOpenWidget: QuickOpenWidget = this.quickOpenWidget = this._register(new QuickOpenWidget(
this.layoutService.container,
{
onOk: () => this.onOk(),
onCancel: () => { /* ignore */ },
onType: (value: string) => this.onType(quickOpenWidget, value || ''),
onShow: () => this.handleOnShow(),
onHide: (reason) => this.handleOnHide(reason),
onFocusLost: () => !this.closeOnFocusLost
}, {
inputPlaceHolder: this.hasHandler(HELP_PREFIX) ? nls.localize('quickOpenInput', "Type '?' to get help on the actions you can take from here") : '',
keyboardSupport: false,
treeCreator: (container, config, opts) => this.instantiationService.createInstance(WorkbenchTree, container, config, opts)
}));
this._register(attachQuickOpenStyler(this.quickOpenWidget, this.themeService, { background: quickInputBackground, foreground: quickInputForeground }));
const quickOpenContainer = this.quickOpenWidget.create();
addClass(quickOpenContainer, 'show-file-icons');
this.positionQuickOpenWidget();
}
// Layout
this.quickOpenWidget.layout(this.layoutService.dimension);
// Show quick open with prefix or editor history
if (!this.quickOpenWidget.isVisible() || quickNavigateConfiguration) {
if (prefix) {
this.quickOpenWidget.show(prefix, { quickNavigateConfiguration, inputSelection, autoFocus });
} else {
const editorHistory = this.getEditorHistoryWithGroupLabel();
if (editorHistory.getEntries().length < 2) {
quickNavigateConfiguration = undefined; // If no entries can be shown, default to normal quick open mode
}
// Compute auto focus
if (!autoFocus) {
if (!quickNavigateConfiguration) {
autoFocus = { autoFocusFirstEntry: true };
} else {
const autoFocusFirstEntry = this.editorGroupService.activeGroup.count === 0;
autoFocus = { autoFocusFirstEntry, autoFocusSecondEntry: !autoFocusFirstEntry };
}
}
// Update context
const registry = Registry.as<IQuickOpenRegistry>(Extensions.Quickopen);
this.setQuickOpenContextKey(registry.getDefaultQuickOpenHandler().contextKey);
if (this.preserveInput) {
this.quickOpenWidget.show(editorHistory, { value: this.lastSubmittedInputValue, quickNavigateConfiguration, autoFocus, inputSelection });
} else {
this.quickOpenWidget.show(editorHistory, { quickNavigateConfiguration, autoFocus, inputSelection });
}
}
}
// Otherwise reset the widget to the prefix that is passed in
else {
this.quickOpenWidget.show(prefix || '', { inputSelection });
}
return promiseCompletedOnHide;
}
private positionQuickOpenWidget(): void {
if (this.quickOpenWidget) {
this.quickOpenWidget.getElement().style.top = `${this.layoutService.offset?.top ?? 0}px`;
}
}
private handleOnShow(): void {
this.emitQuickOpenVisibilityChange(true);
}
private handleOnHide(reason: HideReason): void {
// Clear state
this.previousActiveHandlerDescriptor = null;
// Cancel pending results calls
this.cancelPendingGetResultsInvocation();
// Pass to handlers
this.mapResolvedHandlersToPrefix.forEach((promise, prefix) => {
promise.then(handler => {
this.handlerOnOpenCalled.delete(prefix);
handler.onClose(reason === HideReason.CANCELED); // Don't check if onOpen was called to preserve old behaviour for now
});
});
// Complete promises that are waiting
while (this.promisesToCompleteOnHide.length) {
const callback = this.promisesToCompleteOnHide.pop();
if (callback) {
callback(true);
}
}
if (reason !== HideReason.FOCUS_LOST) {
this.editorGroupService.activeGroup.focus(); // focus back to editor group unless user clicked somewhere else
}
// Reset context keys
this.resetQuickOpenContextKeys();
// Events
this.emitQuickOpenVisibilityChange(false);
}
private cancelPendingGetResultsInvocation(): void {
if (this.pendingGetResultsInvocation) {
this.pendingGetResultsInvocation.cancel();
this.pendingGetResultsInvocation.dispose();
this.pendingGetResultsInvocation = null;
}
}
private resetQuickOpenContextKeys(): void {
this.mapContextKeyToContext.forEach(context => context.reset());
}
private setQuickOpenContextKey(id?: string): void {
let key: IContextKey<boolean> | undefined;
if (id) {
key = this.mapContextKeyToContext.get(id);
if (!key) {
key = new RawContextKey<boolean>(id, false).bindTo(this.contextKeyService);
this.mapContextKeyToContext.set(id, key);
}
}
if (key?.get()) {
return; // already active context
}
this.resetQuickOpenContextKeys();
if (key) {
key.set(true);
}
}
private hasHandler(prefix: string): boolean {
return !!Registry.as<IQuickOpenRegistry>(Extensions.Quickopen).getQuickOpenHandler(prefix);
}
private getEditorHistoryWithGroupLabel(): QuickOpenModel {
const entries: QuickOpenEntry[] = this.editorHistoryHandler.getResults();
// Apply label to first entry
if (entries.length > 0) {
entries[0] = new EditorHistoryEntryGroup(entries[0], nls.localize('historyMatches', "recently opened"), false);
}
return new QuickOpenModel(entries, this.actionProvider);
}
private onOk(): void {
if (this.isQuickOpen) {
this.lastSubmittedInputValue = this.lastInputValue;
}
}
private onType(quickOpenWidget: QuickOpenWidget, value: string): void {
// cancel any pending get results invocation and create new
this.cancelPendingGetResultsInvocation();
const pendingResultsInvocationTokenSource = new CancellationTokenSource();
const pendingResultsInvocationToken = pendingResultsInvocationTokenSource.token;
this.pendingGetResultsInvocation = pendingResultsInvocationTokenSource;
// look for a handler
const registry = Registry.as<IQuickOpenRegistry>(Extensions.Quickopen);
const handlerDescriptor = registry.getQuickOpenHandler(value);
const defaultHandlerDescriptor = registry.getDefaultQuickOpenHandler();
const instantProgress = handlerDescriptor?.instantProgress;
const contextKey = handlerDescriptor ? handlerDescriptor.contextKey : defaultHandlerDescriptor.contextKey;
// Reset Progress
if (!instantProgress) {
quickOpenWidget.getProgressBar().stop().hide();
}
// Reset Extra Class
quickOpenWidget.setExtraClass(null);
// Update context
this.setQuickOpenContextKey(contextKey);
// Remove leading and trailing whitespace
const trimmedValue = strings.trim(value);
// If no value provided, default to editor history
if (!trimmedValue) {
// Trigger onOpen
this.resolveHandler(handlerDescriptor || defaultHandlerDescriptor);
quickOpenWidget.setInput(this.getEditorHistoryWithGroupLabel(), { autoFocusFirstEntry: true });
// If quickOpen entered empty we have to clear the prefill-cache
this.lastInputValue = '';
this.isQuickOpen = true;
return;
}
let resultPromise: Promise<void>;
let resultPromiseDone = false;
if (handlerDescriptor) {
this.isQuickOpen = false;
resultPromise = this.handleSpecificHandler(quickOpenWidget, handlerDescriptor, value, pendingResultsInvocationToken);
}
// Otherwise handle default handlers if no specific handler present
else {
this.isQuickOpen = true;
// Cache the value for prefilling the quickOpen next time is opened
this.lastInputValue = trimmedValue;
resultPromise = this.handleDefaultHandler(quickOpenWidget, defaultHandlerDescriptor, value, pendingResultsInvocationToken);
}
// Remember as the active one
this.previousActiveHandlerDescriptor = handlerDescriptor;
// Progress if task takes a long time
setTimeout(() => {
if (!resultPromiseDone && !pendingResultsInvocationToken.isCancellationRequested) {
quickOpenWidget.getProgressBar().infinite().show();
}
}, instantProgress ? 0 : 800);
// Promise done handling
resultPromise.then(() => {
resultPromiseDone = true;
if (!pendingResultsInvocationToken.isCancellationRequested) {
quickOpenWidget.getProgressBar().hide();
}
pendingResultsInvocationTokenSource.dispose();
}, (error: any) => {
resultPromiseDone = true;
pendingResultsInvocationTokenSource.dispose();
errors.onUnexpectedError(error);
this.notificationService.error(types.isString(error) ? new Error(error) : error);
});
}
private async handleDefaultHandler(quickOpenWidget: QuickOpenWidget, handler: QuickOpenHandlerDescriptor, value: string, token: CancellationToken): Promise<void> {
// Fill in history results if matching and we are configured to search in history
let matchingHistoryEntries: QuickOpenEntry[];
if (value && !this.searchInEditorHistory) {
matchingHistoryEntries = [];
} else {
matchingHistoryEntries = this.editorHistoryHandler.getResults(value, token);
}
if (matchingHistoryEntries.length > 0) {
matchingHistoryEntries[0] = new EditorHistoryEntryGroup(matchingHistoryEntries[0], nls.localize('historyMatches', "recently opened"), false);
}
// Resolve
const resolvedHandler = await this.resolveHandler(handler);
const quickOpenModel = new QuickOpenModel(matchingHistoryEntries, this.actionProvider);
let inputSet = false;
// If we have matching entries from history we want to show them directly and not wait for the other results to come in
// This also applies when we used to have entries from a previous run and now there are no more history results matching
const previousInput = quickOpenWidget.getInput();
const wasShowingHistory = previousInput?.entries?.some(e => e instanceof EditorHistoryEntry || e instanceof EditorHistoryEntryGroup);
if (wasShowingHistory || matchingHistoryEntries.length > 0) {
(async () => {
if (resolvedHandler.hasShortResponseTime()) {
await timeout(QuickOpenController.MAX_SHORT_RESPONSE_TIME);
}
if (!token.isCancellationRequested && !inputSet) {
quickOpenWidget.setInput(quickOpenModel, { autoFocusFirstEntry: true });
inputSet = true;
}
})();
}
// Get results
const result = await resolvedHandler.getResults(value, token);
if (!token.isCancellationRequested) {
// now is the time to show the input if we did not have set it before
if (!inputSet) {
quickOpenWidget.setInput(quickOpenModel, { autoFocusFirstEntry: true });
inputSet = true;
}
// merge history and default handler results
const handlerResults = result?.entries || [];
this.mergeResults(quickOpenWidget, quickOpenModel, handlerResults, types.withNullAsUndefined(resolvedHandler.getGroupLabel()));
}
}
private mergeResults(quickOpenWidget: QuickOpenWidget, quickOpenModel: QuickOpenModel, handlerResults: QuickOpenEntry[], groupLabel: string | undefined): void {
// Remove results already showing by checking for a "resource" property
const mapEntryToResource = this.mapEntriesToResource(quickOpenModel);
const additionalHandlerResults: QuickOpenEntry[] = [];
for (const result of handlerResults) {
const resource = result.getResource();
if (!result.mergeWithEditorHistory() || !resource || !mapEntryToResource[resource.toString()]) {
additionalHandlerResults.push(result);
}
}
// Show additional handler results below any existing results
if (additionalHandlerResults.length > 0) {
const autoFocusFirstEntry = (quickOpenModel.getEntries().length === 0); // the user might have selected another entry meanwhile in local history (see https://github.com/Microsoft/vscode/issues/20828)
const useTopBorder = quickOpenModel.getEntries().length > 0;
additionalHandlerResults[0] = new QuickOpenEntryGroup(additionalHandlerResults[0], groupLabel, useTopBorder);
quickOpenModel.addEntries(additionalHandlerResults);
quickOpenWidget.refresh(quickOpenModel, { autoFocusFirstEntry });
}
// Otherwise if no results are present (even from histoy) indicate this to the user
else if (quickOpenModel.getEntries().length === 0) {
quickOpenModel.addEntries([new PlaceholderQuickOpenEntry(nls.localize('noResultsFound1', "No results found"))]);
quickOpenWidget.refresh(quickOpenModel, { autoFocusFirstEntry: true });
}
}
private async handleSpecificHandler(quickOpenWidget: QuickOpenWidget, handlerDescriptor: QuickOpenHandlerDescriptor, value: string, token: CancellationToken): Promise<void> {
const resolvedHandler = await this.resolveHandler(handlerDescriptor);
// Remove handler prefix from search value
value = value.substr(handlerDescriptor.prefix.length);
// Return early if the handler can not run in the current environment and inform the user
const canRun = resolvedHandler.canRun();
if (types.isUndefinedOrNull(canRun) || (typeof canRun === 'boolean' && !canRun) || typeof canRun === 'string') {
const placeHolderLabel = (typeof canRun === 'string') ? canRun : nls.localize('canNotRunPlaceholder', "This quick open handler can not be used in the current context");
const model = new QuickOpenModel([new PlaceholderQuickOpenEntry(placeHolderLabel)], this.actionProvider);
this.showModel(quickOpenWidget, model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: quickOpenWidget.getQuickNavigateConfiguration() }), types.withNullAsUndefined(resolvedHandler.getAriaLabel()));
return;
}
// Support extra class from handler
const extraClass = resolvedHandler.getClass();
if (extraClass) {
quickOpenWidget.setExtraClass(extraClass);
}
// When handlers change, clear the result list first before loading the new results
if (this.previousActiveHandlerDescriptor !== handlerDescriptor) {
this.clearModel(quickOpenWidget);
}
// Receive Results from Handler and apply
const result = await resolvedHandler.getResults(value, token);
if (!token.isCancellationRequested) {
if (!result || !result.entries.length) {
const model = new QuickOpenModel([new PlaceholderQuickOpenEntry(resolvedHandler.getEmptyLabel(value))]);
this.showModel(quickOpenWidget, model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: quickOpenWidget.getQuickNavigateConfiguration() }), types.withNullAsUndefined(resolvedHandler.getAriaLabel()));
} else {
this.showModel(quickOpenWidget, result, resolvedHandler.getAutoFocus(value, { model: result, quickNavigateConfiguration: quickOpenWidget.getQuickNavigateConfiguration() }), types.withNullAsUndefined(resolvedHandler.getAriaLabel()));
}
}
}
private showModel(quickOpenWidget: QuickOpenWidget, model: IModel<any>, autoFocus?: IAutoFocus, ariaLabel?: string): void {
// If the given model is already set in the widget, refresh and return early
if (quickOpenWidget.getInput() === model) {
quickOpenWidget.refresh(model, autoFocus);
return;
}
// Otherwise just set it
quickOpenWidget.setInput(model, autoFocus, ariaLabel);
}
private clearModel(quickOpenWidget: QuickOpenWidget): void {
this.showModel(quickOpenWidget, new QuickOpenModel(), undefined);
}
private mapEntriesToResource(model: QuickOpenModel): { [resource: string]: QuickOpenEntry; } {
const entries = model.getEntries();
const mapEntryToPath: { [path: string]: QuickOpenEntry; } = {};
entries.forEach((entry: QuickOpenEntry) => {
const resource = entry.getResource();
if (resource) {
mapEntryToPath[resource.toString()] = entry;
}
});
return mapEntryToPath;
}
private async resolveHandler(handler: QuickOpenHandlerDescriptor): Promise<QuickOpenHandler> {
let result = this.doResolveHandler(handler);
const id = handler.getId();
if (!this.handlerOnOpenCalled.has(id)) {
const original = result;
this.handlerOnOpenCalled.add(id);
result = original.then(resolved => {
this.mapResolvedHandlersToPrefix.set(id, original);
resolved.onOpen();
return resolved;
});
this.mapResolvedHandlersToPrefix.set(id, result);
}
try {
return await result;
} catch (error) {
this.mapResolvedHandlersToPrefix.delete(id);
throw new Error(`Unable to instantiate quick open handler ${handler.getId()}: ${JSON.stringify(error)}`);
}
}
private doResolveHandler(handler: QuickOpenHandlerDescriptor): Promise<QuickOpenHandler> {
const id = handler.getId();
// Return Cached
if (this.mapResolvedHandlersToPrefix.has(id)) {
return this.mapResolvedHandlersToPrefix.get(id)!;
}
// Otherwise load and create
const result = Promise.resolve(handler.instantiate(this.instantiationService));
this.mapResolvedHandlersToPrefix.set(id, result);
return result;
}
layout(dimension: Dimension): void {
if (this.quickOpenWidget) {
this.quickOpenWidget.layout(dimension);
}
}
}
class PlaceholderQuickOpenEntry extends QuickOpenEntryGroup {
private placeHolderLabel: string;
constructor(placeHolderLabel: string) {
super();
this.placeHolderLabel = placeHolderLabel;
}
getLabel(): string {
return this.placeHolderLabel;
}
}
class EditorHistoryHandler {
private scorerCache: ScorerCache;
constructor(
@IHistoryService private readonly historyService: IHistoryService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IFileService private readonly fileService: IFileService
) {
this.scorerCache = Object.create(null);
}
getResults(searchValue?: string, token?: CancellationToken): QuickOpenEntry[] {
// Massage search for scoring
const query = prepareQuery(searchValue || '');
// Just return all if we are not searching
const history = this.historyService.getHistory();
if (!query.value) {
return history.map(input => this.instantiationService.createInstance(EditorHistoryEntry, input));
}
// Otherwise filter by search value and sort by score. Include matches on description
// in case the user is explicitly including path separators.
const accessor = query.containsPathSeparator ? MatchOnDescription : DoNotMatchOnDescription;
return history
// For now, only support to match on inputs that provide resource information
.filter(input => {
let resource: URI | undefined;
if (input instanceof EditorInput) {
resource = resourceForEditorHistory(input, this.fileService);
} else {
resource = (input as IResourceEditorInput).resource;
}
return !!resource;
})
// Conver to quick open entries
.map(input => this.instantiationService.createInstance(EditorHistoryEntry, input))
// Make sure the search value is matching
.filter(e => {
const itemScore = scoreItem(e, query, false, accessor, this.scorerCache);
if (!itemScore.score) {
return false;
}
e.setHighlights(itemScore.labelMatch || [], itemScore.descriptionMatch);
return true;
})
// Sort by score and provide a fallback sorter that keeps the
// recency of items in case the score for items is the same
.sort((e1, e2) => compareItemsByScore(e1, e2, query, false, accessor, this.scorerCache));
}
}
class EditorHistoryItemAccessorClass extends QuickOpenItemAccessorClass {
constructor(private allowMatchOnDescription: boolean) {
super();
}
getItemDescription(entry: QuickOpenEntry): string | undefined {
return this.allowMatchOnDescription ? entry.getDescription() : undefined;
}
}
const MatchOnDescription = new EditorHistoryItemAccessorClass(true);
const DoNotMatchOnDescription = new EditorHistoryItemAccessorClass(false);
export class EditorHistoryEntryGroup extends QuickOpenEntryGroup {
// Marker class
}
export class EditorHistoryEntry extends EditorQuickOpenEntry {
private input: IEditorInput | IResourceEditorInput;
private resource: URI | undefined;
private label: string;
private description?: string;
private icon: string;
constructor(
input: IEditorInput | IResourceEditorInput,
@IEditorService editorService: IEditorService,
@IModeService private readonly modeService: IModeService,
@IModelService private readonly modelService: IModelService,
@ITextFileService private readonly textFileService: ITextFileService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@ILabelService labelService: ILabelService,
@IFileService fileService: IFileService,
@IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService
) {
super(editorService);
this.input = input;
if (input instanceof EditorInput) {
this.resource = resourceForEditorHistory(input, fileService);
this.label = input.getName();
this.description = input.getDescription();
this.icon = this.getDirtyIndicatorForEditor(input);
} else {
const resourceEditorInput = input as IResourceEditorInput;
this.resource = resourceEditorInput.resource;
this.label = resources.basenameOrAuthority(resourceEditorInput.resource);
this.description = labelService.getUriLabel(resources.dirname(this.resource), { relative: true });
this.icon = this.getDirtyIndicatorForEditor(resourceEditorInput);
}
}
private getDirtyIndicatorForEditor(input: EditorInput | IResourceEditorInput): string {
let signalDirty = false;
if (input instanceof EditorInput) {
signalDirty = input.isDirty() && !input.isSaving();
} else {
signalDirty = this.textFileService.isDirty(input.resource) && this.filesConfigurationService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY;
}
return signalDirty ? 'codicon codicon-circle-filled' : '';
}
getIcon(): string {
return this.icon;
}
getLabel(): string {
return this.label;
}
getLabelOptions(): IIconLabelValueOptions {
return {
extraClasses: getIconClasses(this.modelService, this.modeService, this.resource)
};
}
getAriaLabel(): string {
return nls.localize('entryAriaLabel', "{0}, recently opened", this.getLabel());
}
getDescription(): string | undefined {
return this.description;
}
getResource(): URI | undefined {
return this.resource;
}
getInput(): IEditorInput | IResourceEditorInput {
return this.input;
}
run(mode: Mode, context: IEntryRunContext): boolean {
if (mode === Mode.OPEN) {
const sideBySide = !context.quickNavigateConfiguration && (context.keymods.alt || context.keymods.ctrlCmd);
const pinned = !this.configurationService.getValue<IWorkbenchEditorConfiguration>().workbench.editor.enablePreviewFromQuickOpen || context.keymods.alt;
if (this.input instanceof EditorInput) {
this.editorService.openEditor(this.input, { pinned }, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
} else {
this.editorService.openEditor({ resource: (this.input as IResourceEditorInput).resource, options: { pinned } }, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
}
return true;
}
return super.run(mode, context);
}
}
function resourceForEditorHistory(input: EditorInput, fileService: IFileService): URI | undefined {
const resource = input ? input.resource : undefined;
// For the editor history we only prefer resources that are either untitled or
// can be handled by the file service which indicates they are editable resources.
if (resource && (fileService.canHandleResource(resource) || resource.scheme === Schemas.untitled)) {
return resource;
}
return undefined;
}
export class RemoveFromEditorHistoryAction extends Action {
static readonly ID = 'workbench.action.removeFromEditorHistory';
static readonly LABEL = nls.localize('removeFromEditorHistory', "Remove From History");
constructor(
id: string,
label: string,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IModelService private readonly modelService: IModelService,
@IModeService private readonly modeService: IModeService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IHistoryService private readonly historyService: IHistoryService
) {
super(id, label);
}
async run(): Promise<any> {
interface IHistoryPickEntry extends IQuickPickItem {
input: IEditorInput | IResourceEditorInput;
}
const history = this.historyService.getHistory();
const picks: IHistoryPickEntry[] = history.map(h => {
const entry = this.instantiationService.createInstance(EditorHistoryEntry, h);
return <IHistoryPickEntry>{
input: h,
iconClasses: getIconClasses(this.modelService, this.modeService, entry.getResource()),
label: entry.getLabel(),
description: entry.getDescription()
};
});
const pick = await this.quickInputService.pick(picks, { placeHolder: nls.localize('pickHistory', "Select an editor entry to remove from history"), matchOnDescription: true });
if (pick) {
this.historyService.remove(pick.input);
}
}
}
registerSingleton(IQuickOpenService, QuickOpenController, true);

View File

@@ -1,205 +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 * as nls from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ContextKeyExpr, RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { Disposable } from 'vs/base/common/lifecycle';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { Registry } from 'vs/platform/registry/common/platform';
const inQuickOpenKey = 'inQuickOpen';
export const InQuickOpenContextKey = new RawContextKey<boolean>(inQuickOpenKey, false);
export const inQuickOpenContext = ContextKeyExpr.has(inQuickOpenKey);
export const defaultQuickOpenContextKey = 'inFilesPicker';
export const defaultQuickOpenContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(defaultQuickOpenContextKey));
export const QUICKOPEN_ACTION_ID = 'workbench.action.quickOpen';
export const QUICKOPEN_ACION_LABEL = nls.localize('quickOpen', "Go to File...");
CommandsRegistry.registerCommand({
id: QUICKOPEN_ACTION_ID,
handler: async function (accessor: ServicesAccessor, prefix: string | null = null) {
const quickOpenService = accessor.get(IQuickOpenService);
await quickOpenService.show(typeof prefix === 'string' ? prefix : undefined);
},
description: {
description: `Quick open`,
args: [{
name: 'prefix',
schema: {
'type': 'string'
}
}]
}
});
export const QUICKOPEN_FOCUS_SECONDARY_ACTION_ID = 'workbench.action.quickOpenPreviousEditor';
CommandsRegistry.registerCommand(QUICKOPEN_FOCUS_SECONDARY_ACTION_ID, async function (accessor: ServicesAccessor, prefix: string | null = null) {
const quickOpenService = accessor.get(IQuickOpenService);
await quickOpenService.show(undefined, { autoFocus: { autoFocusSecondEntry: true } });
});
export class BaseQuickOpenNavigateAction extends Action {
constructor(
id: string,
label: string,
private next: boolean,
private quickNavigate: boolean,
@IQuickOpenService private readonly quickOpenService: IQuickOpenService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IKeybindingService private readonly keybindingService: IKeybindingService
) {
super(id, label);
}
async run(): Promise<void> {
const keys = this.keybindingService.lookupKeybindings(this.id);
const quickNavigate = this.quickNavigate ? { keybindings: keys } : undefined;
this.quickOpenService.navigate(this.next, quickNavigate);
this.quickInputService.navigate(this.next, quickNavigate);
}
}
export function getQuickNavigateHandler(id: string, next?: boolean): ICommandHandler {
return accessor => {
const keybindingService = accessor.get(IKeybindingService);
const quickOpenService = accessor.get(IQuickOpenService);
const quickInputService = accessor.get(IQuickInputService);
const keys = keybindingService.lookupKeybindings(id);
const quickNavigate = { keybindings: keys };
quickOpenService.navigate(!!next, quickNavigate);
quickInputService.navigate(!!next, quickNavigate);
};
}
export class QuickOpenNavigateNextAction extends BaseQuickOpenNavigateAction {
static readonly ID = 'workbench.action.quickOpenNavigateNext';
static readonly LABEL = nls.localize('quickNavigateNext', "Navigate Next in Quick Open");
constructor(
id: string,
label: string,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, true, true, quickOpenService, quickInputService, keybindingService);
}
}
export class QuickOpenNavigatePreviousAction extends BaseQuickOpenNavigateAction {
static readonly ID = 'workbench.action.quickOpenNavigatePrevious';
static readonly LABEL = nls.localize('quickNavigatePrevious', "Navigate Previous in Quick Open");
constructor(
id: string,
label: string,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, false, true, quickOpenService, quickInputService, keybindingService);
}
}
export class QuickOpenSelectNextAction extends BaseQuickOpenNavigateAction {
static readonly ID = 'workbench.action.quickOpenSelectNext';
static readonly LABEL = nls.localize('quickSelectNext', "Select Next in Quick Open");
constructor(
id: string,
label: string,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, true, false, quickOpenService, quickInputService, keybindingService);
}
}
export class QuickOpenSelectPreviousAction extends BaseQuickOpenNavigateAction {
static readonly ID = 'workbench.action.quickOpenSelectPrevious';
static readonly LABEL = nls.localize('quickSelectPrevious', "Select Previous in Quick Open");
constructor(
id: string,
label: string,
@IQuickOpenService quickOpenService: IQuickOpenService,
@IQuickInputService quickInputService: IQuickInputService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(id, label, false, false, quickOpenService, quickInputService, keybindingService);
}
}
// TODO@Ben delete eventually when quick open is implemented using quick input
export class LegacyQuickInputQuickOpenController extends Disposable {
private readonly inQuickOpenWidgets: Record<string, boolean> = Object.create(null);
private readonly inQuickOpenContext = InQuickOpenContextKey.bindTo(this.contextKeyService);
constructor(
@IQuickOpenService private readonly quickOpenService: IQuickOpenService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IQuickInputService private readonly quickInputService: IQuickInputService
) {
super();
this.registerListeners();
}
private registerListeners(): void {
this._register(this.quickOpenService.onShow(() => this.inQuickOpen('quickOpen', true)));
this._register(this.quickOpenService.onHide(() => this.inQuickOpen('quickOpen', false)));
this._register(this.quickOpenService.onShow(() => this.quickInputService.hide(true)));
this._register(this.quickInputService.onShow(() => {
this.quickOpenService.close();
this.inQuickOpen('quickInput', true);
}));
this._register(this.quickInputService.onHide(() => {
this.inQuickOpen('quickInput', false);
}));
}
private inQuickOpen(widget: 'quickInput' | 'quickOpen', open: boolean) {
if (open) {
this.inQuickOpenWidgets[widget] = true;
} else {
delete this.inQuickOpenWidgets[widget];
}
if (Object.keys(this.inQuickOpenWidgets).length) {
if (!this.inQuickOpenContext.get()) {
this.inQuickOpenContext.set(true);
}
} else {
if (this.inQuickOpenContext.get()) {
this.inQuickOpenContext.reset();
}
}
}
}
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LegacyQuickInputQuickOpenController, LifecyclePhase.Ready);

View File

@@ -26,7 +26,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { MenuBar } from 'vs/base/browser/ui/menu/menubar';
import { MenuBar, IMenuBarOptions } from 'vs/base/browser/ui/menu/menubar';
import { SubmenuAction, Direction } from 'vs/base/browser/ui/menu/menu';
import { attachMenuStyler } from 'vs/platform/theme/common/styler';
import { assign } from 'vs/base/common/objects';
@@ -510,30 +510,11 @@ export class CustomMenubarControl extends MenubarControl {
}
if (firstTime) {
const webActions = [];
const webMenu = this.menuService.createMenu(MenuId.WebMenuActions, this.contextKeyService);
for (const groups of webMenu.getActions()) {
const [, actions] = groups;
for (const action of actions) {
action.label = mnemonicMenuLabel(this.calculateActionLabel(action));
webActions.push(action);
}
}
this.menubar = this._register(new MenuBar(
this.container, {
enableMnemonics: this.currentEnableMenuBarMnemonics,
disableAltFocus: this.currentDisableMenuBarAltFocus,
visibility: this.currentMenubarVisibility,
getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id),
compactMode: this.currentCompactMenuMode
}, webActions.length > 0 ? webActions : undefined));
this.menubar = this._register(new MenuBar(this.container, this.getMenuBarOptions()));
this.accessibilityService.alwaysUnderlineAccessKeys().then(val => {
this.alwaysOnMnemonics = val;
if (this.menubar) {
this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics, compactMode: this.currentCompactMenuMode });
}
this.menubar?.update(this.getMenuBarOptions());
});
this._register(this.menubar.onFocusStateChange(focused => {
@@ -559,9 +540,7 @@ export class CustomMenubarControl extends MenubarControl {
this._register(attachMenuStyler(this.menubar, this.themeService));
} else {
if (this.menubar) {
this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics, compactMode: this.currentCompactMenuMode });
}
this.menubar?.update(this.getMenuBarOptions());
}
// Update the menu actions
@@ -632,6 +611,35 @@ export class CustomMenubarControl extends MenubarControl {
}
}
private getMenuBarOptions(): IMenuBarOptions {
return {
enableMnemonics: this.currentEnableMenuBarMnemonics,
disableAltFocus: this.currentDisableMenuBarAltFocus,
visibility: this.currentMenubarVisibility,
getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id),
alwaysOnMnemonics: this.alwaysOnMnemonics,
compactMode: this.currentCompactMenuMode,
getCompactMenuActions: () => {
if (!isWeb) {
return []; // only for web
}
const webNavigationActions: IAction[] = [];
const webNavigationMenu = this.menuService.createMenu(MenuId.MenubarWebNavigationMenu, this.contextKeyService);
for (const groups of webNavigationMenu.getActions()) {
const [, actions] = groups;
for (const action of actions) {
action.label = mnemonicMenuLabel(this.calculateActionLabel(action));
webNavigationActions.push(action);
}
}
webNavigationMenu.dispose();
return webNavigationActions;
}
};
}
protected onDidChangeWindowFocus(hasFocus: boolean): void {
super.onDidChangeWindowFocus(hasFocus);
@@ -694,8 +702,6 @@ export class CustomMenubarControl extends MenubarControl {
this.container.style.height = `${dimension.height}px`;
}
if (this.menubar) {
this.menubar.update({ enableMnemonics: this.currentEnableMenuBarMnemonics, disableAltFocus: this.currentDisableMenuBarAltFocus, visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), alwaysOnMnemonics: this.alwaysOnMnemonics, compactMode: this.currentCompactMenuMode });
}
this.menubar?.update(this.getMenuBarOptions());
}
}

View File

@@ -3,28 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* File icon themeable OLD tree style */
.file-icon-themable-tree .monaco-tree-row .content {
display: flex;
}
.file-icon-themable-tree .monaco-tree-row .content::before {
background-size: 16px;
background-position: 50% 50%;
background-repeat: no-repeat;
padding-right: 6px;
width: 16px;
height: 22px;
display: inline-block;
vertical-align: top;
content: ' ';
}
.file-icon-themable-tree.align-icons-and-twisties .monaco-tree-row:not(.has-children) .content::before,
.file-icon-themable-tree.hide-arrows .monaco-tree-row .content::before {
display: none;
}
/* File icons in trees */
.file-icon-themable-tree.align-icons-and-twisties .monaco-tl-twistie:not(.force-twistie):not(.collapsible),

View File

@@ -13,9 +13,8 @@ import { append, $, trackFocus, toggleClass, EventType, isAncestor, Dimension, a
import { IDisposable, combinedDisposable, dispose, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { firstIndex } from 'vs/base/common/arrays';
import { IAction } from 'vs/base/common/actions';
import { IActionViewItem, ActionsOrientation, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IActionViewItem, ActionsOrientation, Separator, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
import { Registry } from 'vs/platform/registry/common/platform';
import { prepareActions } from 'vs/workbench/browser/actions';
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';

View File

@@ -3,20 +3,16 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as DOM from 'vs/base/browser/dom';
import { IAction } from 'vs/base/common/actions';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IViewDescriptor, IViewDescriptorService } from 'vs/workbench/common/views';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService, IFileIconTheme } from 'vs/platform/theme/common/themeService';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ViewPaneContainer, ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { WorkbenchTree, IListService } from 'vs/platform/list/browser/listService';
import { ITreeConfiguration, ITreeOptions } from 'vs/base/parts/tree/browser/tree';
import { Event } from 'vs/base/common/event';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
@@ -145,30 +141,3 @@ export abstract class FilterViewPaneContainer extends ViewPaneContainer {
abstract getTitle(): string;
}
export class FileIconThemableWorkbenchTree extends WorkbenchTree {
constructor(
container: HTMLElement,
configuration: ITreeConfiguration,
options: ITreeOptions,
@IContextKeyService contextKeyService: IContextKeyService,
@IListService listService: IListService,
@IThemeService themeService: IThemeService,
@IConfigurationService configurationService: IConfigurationService,
@IInstantiationService instantiationService: IInstantiationService
) {
super(container, configuration, { ...options, ...{ showTwistie: false, twistiePixels: 12 } }, contextKeyService, listService, themeService, instantiationService, configurationService);
DOM.addClass(container, 'file-icon-themable-tree');
DOM.addClass(container, 'show-file-icons');
const onFileIconThemeChange = (fileIconTheme: IFileIconTheme) => {
DOM.toggleClass(container, 'align-icons-and-twisties', fileIconTheme.hasFileIcons && !fileIconTheme.hasFolderIcons);
DOM.toggleClass(container, 'hide-arrows', fileIconTheme.hidesExplorerArrows === true);
};
this.disposables.push(themeService.onDidFileIconThemeChange(onFileIconThemeChange));
onFileIconThemeChange(themeService.getFileIconTheme());
}
}

View File

@@ -0,0 +1,41 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { ICommandHandler } from 'vs/platform/commands/common/commands';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
export const inQuickPickContextKeyValue = 'inQuickOpen';
export const InQuickPickContextKey = new RawContextKey<boolean>(inQuickPickContextKeyValue, false);
export const inQuickPickContext = ContextKeyExpr.has(inQuickPickContextKeyValue);
export const defaultQuickAccessContextKeyValue = 'inFilesPicker';
export const defaultQuickAccessContext = ContextKeyExpr.and(inQuickPickContext, ContextKeyExpr.has(defaultQuickAccessContextKeyValue));
export interface IWorkbenchQuickAccessConfiguration {
workbench: {
commandPalette: {
history: number;
preserveInput: boolean;
},
quickOpen: {
enableExperimentalNewVersion: boolean;
preserveInput: boolean;
}
};
}
export function getQuickNavigateHandler(id: string, next?: boolean): ICommandHandler {
return accessor => {
const keybindingService = accessor.get(IKeybindingService);
const quickInputService = accessor.get(IQuickInputService);
const keys = keybindingService.lookupKeybindings(id);
const quickNavigate = { keybindings: keys };
quickInputService.navigate(!!next, quickNavigate);
};
}

View File

@@ -1,339 +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 { localize } from 'vs/nls';
import { mixin, assign } from 'vs/base/common/objects';
import { first } from 'vs/base/common/arrays';
import { startsWith } from 'vs/base/common/strings';
import { isString, assertIsDefined, withNullAsUndefined } from 'vs/base/common/types';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { Mode, IEntryRunContext, IAutoFocus, IModel, IQuickNavigateConfiguration } from 'vs/base/parts/quickopen/common/quickOpen';
import { QuickOpenEntry, QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { EditorOptions, EditorInput, IEditorInput } from 'vs/workbench/common/editor';
import { IResourceEditorInput, IEditorOptions } from 'vs/platform/editor/common/editor';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { IConstructorSignature0, IInstantiationService, BrandedService } from 'vs/platform/instantiation/common/instantiation';
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { CancellationToken } from 'vs/base/common/cancellation';
export const CLOSE_ON_FOCUS_LOST_CONFIG = 'workbench.quickOpen.closeOnFocusLost';
export const PRESERVE_INPUT_CONFIG = 'workbench.quickOpen.preserveInput';
export const ENABLE_EXPERIMENTAL_VERSION_CONFIG = 'workbench.quickOpen.enableExperimentalNewVersion';
export const SEARCH_EDITOR_HISTORY = 'search.quickOpen.includeHistory';
export interface IWorkbenchQuickOpenConfiguration {
workbench: {
commandPalette: {
history: number;
preserveInput: boolean;
},
quickOpen: {
enableExperimentalNewVersion: boolean;
preserveInput: boolean;
}
};
}
export class QuickOpenHandler {
/**
* A quick open handler returns results for a given input string. The resolved promise
* returns an instance of quick open model. It is up to the handler to keep and reuse an
* instance of the same model across multiple calls. This helps in situations where the user is
* narrowing down a search and the model is just filtering some items out.
*
* As such, returning the same model instance across multiple searches will yield best
* results in terms of performance when many items are shown.
*/
getResults(searchValue: string, token: CancellationToken): Promise<IModel<any> | null> {
return Promise.resolve(null);
}
/**
* The ARIA label to apply when this quick open handler is active in quick open.
*/
getAriaLabel(): string | null {
return null;
}
/**
* Extra CSS class name to add to the quick open widget to do custom styling of entries.
*/
getClass(): string | null {
return null;
}
/**
* Indicates if the handler can run in the current environment. Return a string if the handler cannot run but has
* a good message to show in this case.
*/
canRun(): boolean | string {
return true;
}
/**
* Hints to the outside that this quick open handler typically returns results fast.
*/
hasShortResponseTime(): boolean {
return false;
}
/**
* Indicates if the handler wishes the quick open widget to automatically select the first result entry or an entry
* based on a specific prefix match.
*/
getAutoFocus(searchValue: string, context: { model: IModel<QuickOpenEntry>, quickNavigateConfiguration?: IQuickNavigateConfiguration }): IAutoFocus {
return {};
}
/**
* Indicates to the handler that the quick open widget has been opened.
*/
onOpen(): void {
return;
}
/**
* Indicates to the handler that the quick open widget has been closed. Allows to free up any resources as needed.
* The parameter canceled indicates if the quick open widget was closed with an entry being run or not.
*/
onClose(canceled: boolean): void {
return;
}
/**
* Allows to return a label that will be placed to the side of the results from this handler or null if none.
*/
getGroupLabel(): string | null {
return null;
}
/**
* Allows to return a label that will be used when there are no results found
*/
getEmptyLabel(searchString: string): string {
if (searchString.length > 0) {
return localize('noResultsMatching', "No results matching");
}
return localize('noResultsFound2', "No results found");
}
}
export interface QuickOpenHandlerHelpEntry {
prefix: string;
description: string;
needsEditor: boolean;
}
/**
* A lightweight descriptor of a quick open handler.
*/
export class QuickOpenHandlerDescriptor {
prefix: string;
description?: string;
contextKey?: string;
helpEntries?: QuickOpenHandlerHelpEntry[];
instantProgress: boolean;
private id: string;
private ctor: IConstructorSignature0<QuickOpenHandler>;
public static create<Services extends BrandedService[]>(ctor: { new(...services: Services): QuickOpenHandler }, id: string, prefix: string, contextKey: string | undefined, description: string, instantProgress?: boolean): QuickOpenHandlerDescriptor;
public static create<Services extends BrandedService[]>(ctor: { new(...services: Services): QuickOpenHandler }, id: string, prefix: string, contextKey: string | undefined, helpEntries: QuickOpenHandlerHelpEntry[], instantProgress?: boolean): QuickOpenHandlerDescriptor;
public static create<Services extends BrandedService[]>(ctor: { new(...services: Services): QuickOpenHandler }, id: string, prefix: string, contextKey: string | undefined, param: string | QuickOpenHandlerHelpEntry[], instantProgress: boolean = false): QuickOpenHandlerDescriptor {
return new QuickOpenHandlerDescriptor(ctor as IConstructorSignature0<QuickOpenHandler>, id, prefix, contextKey, param, instantProgress);
}
private constructor(ctor: IConstructorSignature0<QuickOpenHandler>, id: string, prefix: string, contextKey: string | undefined, param: string | QuickOpenHandlerHelpEntry[], instantProgress: boolean = false) {
this.ctor = ctor;
this.id = id;
this.prefix = prefix;
this.contextKey = contextKey;
this.instantProgress = instantProgress;
if (isString(param)) {
this.description = param;
} else {
this.helpEntries = param;
}
}
getId(): string {
return this.id;
}
instantiate(instantiationService: IInstantiationService): QuickOpenHandler {
return instantiationService.createInstance(this.ctor);
}
}
export const Extensions = {
Quickopen: 'workbench.contributions.quickopen'
};
export interface IQuickOpenRegistry {
/**
* Registers a quick open handler to the platform.
*/
registerQuickOpenHandler(descriptor: QuickOpenHandlerDescriptor): void;
/**
* Registers a default quick open handler to fallback to.
*/
registerDefaultQuickOpenHandler(descriptor: QuickOpenHandlerDescriptor): void;
/**
* Get all registered quick open handlers
*/
getQuickOpenHandlers(): QuickOpenHandlerDescriptor[];
/**
* Get a specific quick open handler for a given prefix.
*/
getQuickOpenHandler(prefix: string): QuickOpenHandlerDescriptor | null;
/**
* Returns the default quick open handler.
*/
getDefaultQuickOpenHandler(): QuickOpenHandlerDescriptor;
}
class QuickOpenRegistry implements IQuickOpenRegistry {
private handlers: QuickOpenHandlerDescriptor[] = [];
private defaultHandler: QuickOpenHandlerDescriptor | undefined;
registerQuickOpenHandler(descriptor: QuickOpenHandlerDescriptor): void {
this.handlers.push(descriptor);
// sort the handlers by decreasing prefix length, such that longer
// prefixes take priority: 'ext' vs 'ext install' - the latter should win
this.handlers.sort((h1, h2) => h2.prefix.length - h1.prefix.length);
}
registerDefaultQuickOpenHandler(descriptor: QuickOpenHandlerDescriptor): void {
this.defaultHandler = descriptor;
}
getQuickOpenHandlers(): QuickOpenHandlerDescriptor[] {
return this.handlers.slice(0);
}
getQuickOpenHandler(text: string): QuickOpenHandlerDescriptor | null {
return text ? (first<QuickOpenHandlerDescriptor>(this.handlers, h => startsWith(text, h.prefix)) || null) : null;
}
getDefaultQuickOpenHandler(): QuickOpenHandlerDescriptor {
return assertIsDefined(this.defaultHandler);
}
}
Registry.add(Extensions.Quickopen, new QuickOpenRegistry());
export interface IEditorQuickOpenEntry {
/**
* The editor input used for this entry when opening.
*/
getInput(): IResourceEditorInput | IEditorInput | undefined;
/**
* The editor options used for this entry when opening.
*/
getOptions(): IEditorOptions | undefined;
}
/**
* A subclass of quick open entry that will open an editor with input and options when running.
*/
export class EditorQuickOpenEntry extends QuickOpenEntry implements IEditorQuickOpenEntry {
constructor(private _editorService: IEditorService) {
super();
}
get editorService() {
return this._editorService;
}
getInput(): IResourceEditorInput | IEditorInput | undefined {
return undefined;
}
getOptions(): IEditorOptions | undefined {
return undefined;
}
run(mode: Mode, context: IEntryRunContext): boolean {
const hideWidget = (mode === Mode.OPEN);
if (mode === Mode.OPEN || mode === Mode.OPEN_IN_BACKGROUND) {
const sideBySide = context.keymods.ctrlCmd;
let openOptions: IEditorOptions | undefined;
if (mode === Mode.OPEN_IN_BACKGROUND) {
openOptions = { pinned: true, preserveFocus: true };
} else if (context.keymods.alt) {
openOptions = { pinned: true };
}
const input = this.getInput();
if (input instanceof EditorInput) {
let opts = this.getOptions();
if (opts) {
opts = mixin(opts, openOptions, true);
} else if (openOptions) {
opts = EditorOptions.create(openOptions);
}
this.editorService.openEditor(input, withNullAsUndefined(opts), sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
} else {
const resourceEditorInput = <IResourceEditorInput>input;
if (openOptions) {
resourceEditorInput.options = assign(resourceEditorInput.options || Object.create(null), openOptions);
}
this.editorService.openEditor(resourceEditorInput, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
}
}
return hideWidget;
}
}
/**
* A subclass of quick open entry group that provides access to editor input and options.
*/
export class EditorQuickOpenEntryGroup extends QuickOpenEntryGroup implements IEditorQuickOpenEntry {
getInput(): IEditorInput | IResourceEditorInput | undefined {
return undefined;
}
getOptions(): IEditorOptions | undefined {
return undefined;
}
}
export class QuickOpenAction extends Action {
private prefix: string;
constructor(
id: string,
label: string,
prefix: string,
@IQuickOpenService protected readonly quickOpenService: IQuickOpenService
) {
super(id, label);
this.prefix = prefix;
}
async run(): Promise<void> {
this.quickOpenService.show(this.prefix);
}
}

View File

@@ -55,7 +55,6 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
const listHighlightForegroundColor = theme.getColor(listHighlightForeground);
if (listHighlightForegroundColor) {
collector.addRule(`
.monaco-workbench .monaco-tree .monaco-tree-row .monaco-highlighted-label .highlight,
.monaco-workbench .monaco-list .monaco-list-row .monaco-highlighted-label .highlight {
color: ${listHighlightForegroundColor};
}
@@ -115,7 +114,6 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
.monaco-workbench [tabindex="-1"]:focus,
.monaco-workbench .synthetic-focus,
.monaco-workbench select:focus,
.monaco-workbench .monaco-tree.focused.no-focused-item:focus:before,
.monaco-workbench .monaco-list:not(.element-focused):focus:before,
.monaco-workbench input[type="button"]:focus,
.monaco-workbench input[type="text"]:focus,
@@ -143,11 +141,6 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
outline-width: 1px;
}
.hc-black .monaco-tree.focused.no-focused-item:focus:before {
outline-width: 1px;
outline-offset: -2px;
}
.hc-black .synthetic-focus input {
background: transparent; /* Search input focus fix when in high contrast */
}

View File

@@ -17,6 +17,16 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
registry.registerConfiguration({
...workbenchConfigurationNodeBase,
'properties': {
'workbench.editor.titleScrollbarSizing': {
type: 'string',
enum: ['default', 'large'],
enumDescriptions: [
nls.localize('workbench.editor.titleScrollbarSizing.default', "The default size."),
nls.localize('workbench.editor.titleScrollbarSizing.large', "Increases the size, so it can be grabed more easily with the mouse")
],
description: nls.localize('tabScrollbarHeight', "Controls the height of the scrollbars used for tabs and breadcrumbs in the editor title area."),
default: 'default',
},
'workbench.editor.showTabs': {
'type': 'boolean',
'description': nls.localize('showEditorTabs', "Controls whether opened editors should show in tabs or not."),
@@ -179,11 +189,6 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
'description': nls.localize('workbench.quickOpen.preserveInput', "Controls whether the last typed input to Quick Open should be restored when opening it the next time."),
'default': false
},
'workbench.quickOpen.enableExperimentalNewVersion': {
'type': 'boolean',
'description': nls.localize('workbench.quickOpen.enableExperimentalNewVersion', "Will use the new quick open implementation for testing purposes."),
'default': true
},
'workbench.settings.openDefaultSettings': {
'type': 'boolean',
'description': nls.localize('openDefaultSettings', "Controls whether opening settings also opens an editor showing all default settings."),

View File

@@ -16,7 +16,6 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { isWindows, isLinux, isWeb, isNative, isMacintosh } from 'vs/base/common/platform';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions';
import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions';
import { Position, Parts, IWorkbenchLayoutService, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
import { IStorageService, WillSaveStateReason, StorageScope } from 'vs/platform/storage/common/storage';
@@ -217,7 +216,6 @@ export class Workbench extends Layout {
}
private startRegistries(accessor: ServicesAccessor): void {
Registry.as<IActionBarRegistry>(ActionBarExtensions.Actionbar).start(accessor);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).start(accessor);
Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories).start(accessor);
Registry.as<ILanguageAssociationRegistry>(LanguageExtensions.LanguageAssociations).start(accessor);