提交 22773cb8 编写于 作者: J Johannes Rieken

replace ActionService with MenuService, merge both contribution points, add user friendly objects

上级 6ebdd1aa
......@@ -4,7 +4,7 @@
"description": "Markdown for VS Code",
"version": "0.2.0",
"publisher": "Microsoft",
"aiKey":"AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
"engines": {
"vscode": "^1.0.0"
},
......@@ -49,9 +49,15 @@
"icon": {
"light": "./media/Preview.svg",
"dark": "./media/Preview_inverse.svg"
},
"when": "resourceLangId == markdown",
"where": "editor/primary"
}
},
{
"command": "markdown.showPreviewToSide",
"title": "%markdown.previewMarkdownSide.title%",
"icon": {
"light": "./media/Preview.svg",
"dark": "./media/Preview_inverse.svg"
}
},
{
"command": "markdown.showSource",
......@@ -60,17 +66,22 @@
"icon": {
"light": "./media/ViewSource.svg",
"dark": "./media/ViewSource_inverse.svg"
},
"when": "resourceScheme == markdown",
"where": "editor/primary"
},
{
"command": "markdown.showPreviewToSide",
"title": "%markdown.previewMarkdownSide.title%",
"when": "resourceLangId == markdown",
"where": "editor/secondary"
}
}
],
"menus": {
"editor/primary": [
{
"when": "resourceLangId == markdown",
"command": "markdown.showPreview",
"alt": "markdown.showPreviewToSide"
},
{
"when": "resourceLangId == markdown",
"command": "markdown.showSource"
}
]
},
"keybindings": [
{
"command": "markdown.showPreview",
......@@ -83,17 +94,19 @@
"mac": "cmd+k v"
}
],
"snippets": [{
"language": "markdown",
"path": "./snippets/markdown.json"
}],
"snippets": [
{
"language": "markdown",
"path": "./snippets/markdown.json"
}
],
"configuration": {
"type": "object",
"title": "Markdown preview configuration",
"properties": {
"markdown.styles": {
"type": "array",
"default" : null,
"default": null,
"description": "A list of URLs or local paths to CSS style sheets to use from the markdown preview."
}
}
......
......@@ -7,18 +7,65 @@
import Actions = require('vs/base/common/actions');
import WinJS = require('vs/base/common/winjs.base');
import Assert = require('vs/base/common/assert');
import Descriptors = require('vs/platform/instantiation/common/descriptors');
import Instantiation = require('vs/platform/instantiation/common/instantiation');
import {KbExpr, IKeybindings} from 'vs/platform/keybinding/common/keybindingService';
import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation';
import {KbExpr, IKeybindings, IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
import {IDisposable} from 'vs/base/common/lifecycle';
import {createDecorator} from 'vs/platform/instantiation/common/instantiation';
export interface CommandAction {
id: string;
title: string;
category: string;
lightThemeIcon: string;
darkThemeIcon: string;
}
export interface MenuItem {
command: CommandAction;
alt?: CommandAction;
when?: KbExpr;
}
export enum MenuLocation {
EditorPrimary = 1,
EditorSecondary = 2
}
export namespace MenuLocation {
export function parse(value: string): MenuLocation {
switch (value) {
case 'editor/primary': return MenuLocation.EditorPrimary;
case 'editor/secondary': return MenuLocation.EditorSecondary;
}
}
}
export const IMenuService = createDecorator<IMenuService>('menuService');
export interface IMenuService {
export let IActionsService = createDecorator<IActionsService>('actionsService');
serviceId: any;
getMenuItems(loc: MenuLocation): MenuItem[];
getCommandActions(): CommandAction[];
}
export interface IActionsService {
serviceId: ServiceIdentifier<any>;
getActions(): Actions.IAction[];
export class ExecuteCommandAction extends Actions.Action {
constructor(
id: string,
label: string,
@IKeybindingService private _keybindingService: IKeybindingService) {
super(id, label);
}
run(...args: any[]): WinJS.TPromise<any> {
return this._keybindingService.executeCommand(this.id, ...args);
}
}
export class SyncActionDescriptor {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {localize} from 'vs/nls';
import {Action} from 'vs/base/common/actions';
import {join} from 'vs/base/common/paths';
import {values} from 'vs/base/common/collections';
import {IJSONSchema} from 'vs/base/common/jsonSchema';
import {IExtensionService, IExtensionDescription} from 'vs/platform/extensions/common/extensions';
import {IKeybindingService, KbExpr} from 'vs/platform/keybinding/common/keybindingService';
import {IExtensionPointUser, ExtensionsRegistry} from 'vs/platform/extensions/common/extensionsRegistry';
export type Locations = 'editor/primary' | 'editor/secondary' | 'explorer/context';
interface ThemableIcon {
dark: string;
light: string;
}
interface Command {
command: string;
title: string;
category?: string;
icon?: string | ThemableIcon;
when?: string;
where?: Locations;
}
function isThemableIcon(thing: any): thing is ThemableIcon {
return typeof thing === 'object' && thing && typeof (<ThemableIcon>thing).dark === 'string' && typeof (<ThemableIcon>thing).light === 'string';
}
export class ParsedCommand {
id: string;
title: string;
category: string;
lightThemeIcon: string;
darkThemeIcon: string;
when: KbExpr;
where: Locations;
constructor(extension: IExtensionDescription, id: string, title: string, category: string, icon: string | { dark: string, light: string }, when: string, where: Locations) {
this.id = id;
this.title = title;
this.category = category;
this.when = KbExpr.deserialize(when);
this.where = where;
if (!icon) {
// nothing
} else if (isThemableIcon(icon)) {
this.lightThemeIcon = join(extension.extensionFolderPath, icon.light);
this.darkThemeIcon = join(extension.extensionFolderPath, icon.dark);
} else {
this.lightThemeIcon = this.darkThemeIcon = join(extension.extensionFolderPath, icon);
}
}
}
namespace validation {
function isValidWhere(where: Locations, user: IExtensionPointUser<any>): boolean {
if (where && ['editor/primary', 'editor/secondary', 'explorer/context'].indexOf(where) < 0) {
user.collector.error(localize('optwhere', "property `where` can be omitted or must be a valid enum value"));
return false;
}
return true;
}
function isValidIcon(icon: string | ThemableIcon, user: IExtensionPointUser<any>): boolean {
if (typeof icon === 'undefined') {
return true;
}
if (typeof icon === 'string') {
return true;
}
if (typeof icon === 'object' && typeof (<ThemableIcon>icon).dark === 'string' && typeof (<ThemableIcon>icon).light === 'string') {
return true;
}
user.collector.error(localize('opticon', "property `icon` can be omitted or must be either a string or a literal like `{dark, light}`"));
return false;
}
export function isValidCommand(candidate: Command, user: IExtensionPointUser<any>): boolean {
if (!candidate) {
user.collector.error(localize('nonempty', "expected non-empty value."));
return false;
}
if (typeof candidate.command !== 'string') {
user.collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'command'));
return false;
}
if (typeof candidate.title !== 'string') {
user.collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'title'));
return false;
}
if (candidate.category && typeof candidate.category !== 'string') {
user.collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'category'));
return false;
}
if (candidate.when && typeof candidate.when !== 'string') {
user.collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'when'));
return false;
}
if (!isValidIcon(candidate.icon, user)) {
return false;
}
if (!isValidWhere(candidate.where, user)) {
return false;
}
return true;
}
}
namespace schema {
const commandType: IJSONSchema = {
type: 'object',
properties: {
command: {
description: localize('vscode.extension.contributes.commandType.command', 'Identifier of the command to execute'),
type: 'string'
},
title: {
description: localize('vscode.extension.contributes.commandType.title', 'Title by which the command is represented in the UI'),
type: 'string'
},
category: {
description: localize('vscode.extension.contributes.commandType.category', '(Optional) Category string by the command is grouped in the UI'),
type: 'string'
},
icon: {
description: localize('vscode.extension.contributes.commandType.icon', '(Optional) Icon which is used to represent the command in the UI. Either a file path or a themable configuration'),
anyOf: [
'string',
{
type: 'object',
properties: {
light: {
description: localize('vscode.extension.contributes.commandType.icon.light', 'Icon path when a light theme is used'),
type: 'string'
},
dark: {
description: localize('vscode.extension.contributes.commandType.icon.dark', 'Icon path when a dark theme is used'),
type: 'string'
}
}
}
]
},
when: {
description: localize('vscode.extension.contributes.commandType.context.when', "Condition that must be met in order to show the command."),
type: 'string'
},
where: {
description: localize('vscode.extension.contributes.commandType.context.where', "Menus and tool bars to which commands can be added, e.g. `editor title actions` or `explorer context menu`"),
enum: [
'editor/primary',
'editor/secondary'
]
}
}
};
export const commandContribution: IJSONSchema = {
description: localize('vscode.extension.contributes.commands', "Contributes commands to the command palette."),
oneOf: [
commandType,
{
type: 'array',
items: commandType
}
]
};
}
export const commands: ParsedCommand[] = [];
const _commandsById: { [id: string]: ParsedCommand } = Object.create(null);
function handleCommand(command: Command, user: IExtensionPointUser<any>): void {
if (validation.isValidCommand(command, user)) {
// store command globally
const parsedCommand = new ParsedCommand(user.description, command.command, command.title, command.category, command.icon, command.when, command.where);
if (_commandsById[parsedCommand.id]) {
user.collector.info(localize('command.overwrite', "Command `{0}` appears multiple times in the `commands` section.", parsedCommand.id));
}
_commandsById[parsedCommand.id] = parsedCommand;
}
}
ExtensionsRegistry.registerExtensionPoint<Command | Command[]>('commands', schema.commandContribution).setHandler(extensions => {
for (let extension of extensions) {
const {value} = extension;
if (Array.isArray<Command>(value)) {
for (let command of value) {
handleCommand(command, extension);
}
} else {
handleCommand(value, extension);
}
}
commands.push(...values(_commandsById));
Object.freeze(commands);
});
export class CommandAction extends Action {
constructor(
public command: ParsedCommand,
@IExtensionService extensionService: IExtensionService,
@IKeybindingService keybindingService: IKeybindingService
) {
super(command.id, command.title);
this.order = Number.MAX_VALUE;
const activationEvent = `onCommand:${command.id}`;
this._actionCallback = (...args: any[]) => {
return extensionService.activateByEvent(activationEvent).then(() => {
return keybindingService.executeCommand(command.id, ...args);
});
};
}
}
\ No newline at end of file
......@@ -5,114 +5,205 @@
'use strict';
import {localize} from 'vs/nls';
import {join} from 'vs/base/common/paths';
import {IJSONSchema} from 'vs/base/common/jsonSchema';
import {IExtensionMessageCollector, ExtensionsRegistry} from 'vs/platform/extensions/common/extensionsRegistry';
import {forEach} from 'vs/base/common/collections';
import {IExtensionPointUser, IExtensionMessageCollector, ExtensionsRegistry} from 'vs/platform/extensions/common/extensionsRegistry';
import {IUserFriendlyCommand, IUserFriendlyMenuItem, IUserFriendlyMenuLocation, MenuRegistry} from './menusService';
namespace schema {
export function isValidLocation(location: string, collector: IExtensionMessageCollector): boolean {
switch (location) {
case 'editor/primary':
case 'editor/secondary':
return true;
// --- menus contribution point
export function isValidMenuItems(menu: IUserFriendlyMenuItem[], collector: IExtensionMessageCollector): boolean {
if (!Array.isArray(menu)) {
collector.error(localize('requirearry', "menu items must be an arry"));
return false;
}
return false;
}
export function isValidMenuItem(item: MenuItem, collector: IExtensionMessageCollector): boolean {
for (let item of menu) {
if (typeof item.command !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'command'));
return false;
}
if (item.alt && typeof item.alt !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'alt'));
return false;
}
if (item.when && typeof item.when !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'when'));
return false;
}
}
return true;
}
export function isValidMenus(menu: Menus, collector: IExtensionMessageCollector): boolean {
for (let key in menu) {
if (menu.hasOwnProperty(key)) {
let value = <MenuItem[]> menu[key];
if (!isValidLocation(key, collector)) {
collector.warn(localize('invalid', "`{0}` is not a valid menu location", key));
continue;
}
if (!Array.isArray(value)) {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `Array`", key));
return false;
}
const menuItem: IJSONSchema = {
type: 'object',
properties: {
command: {
description: localize('vscode.extension.contributes.menuItem.command', 'Identifier of the command to execute'),
type: 'string'
},
alt: {
description: localize('vscode.extension.contributes.menuItem.alt', 'Identifier of an alternative command to execute'),
type: 'string'
},
when: {
description: localize('vscode.extension.contributes.menuItem.when', 'Condition which must be true to show this item'),
type: 'string'
}
}
};
for (let item of value) {
if (!isValidMenuItem(item, collector)) {
return false;
}
}
export const menusContribtion: IJSONSchema = {
description: localize('vscode.extension.contributes.menus', "Contributes menu items to predefined locations"),
type: 'object',
properties: {
'editor/primary': {
type: 'array',
items: menuItem
}
}
};
// --- commands contribution point
export function isValidCommand(command: IUserFriendlyCommand, collector: IExtensionMessageCollector): boolean {
if (!command) {
collector.error(localize('nonempty', "expected non-empty value."));
return false;
}
if (typeof command.command !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'command'));
return false;
}
if (typeof command.title !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'title'));
return false;
}
if (command.category && typeof command.category !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'category'));
return false;
}
if (!isValidIcon(command.icon, collector)) {
return false;
}
return true;
}
export const menus = <IJSONSchema>{
function isValidIcon(icon: string | { light: string; dark: string;}, collector: IExtensionMessageCollector): boolean {
if (typeof icon === 'undefined') {
return true;
}
if (typeof icon === 'string') {
return true;
} else if (typeof icon.dark === 'string' && typeof icon.light === 'string') {
return true;
}
collector.error(localize('opticon', "property `icon` can be omitted or must be either a string or a literal like `{dark, light}`"));
return false;
}
const commandType: IJSONSchema = {
type: 'object',
properties: {
command: {
description: localize('vscode.extension.contributes.commandType.command', 'Identifier of the command to execute'),
type: 'string'
},
title: {
description: localize('vscode.extension.contributes.commandType.title', 'Title by which the command is represented in the UI'),
type: 'string'
},
category: {
description: localize('vscode.extension.contributes.commandType.category', '(Optional) Category string by the command is grouped in the UI'),
type: 'string'
},
icon: {
description: localize('vscode.extension.contributes.commandType.icon', '(Optional) Icon which is used to represent the command in the UI. Either a file path or a themable configuration'),
anyOf: [
'string',
{
type: 'object',
properties: {
light: {
description: localize('vscode.extension.contributes.commandType.icon.light', 'Icon path when a light theme is used'),
type: 'string'
},
dark: {
description: localize('vscode.extension.contributes.commandType.icon.dark', 'Icon path when a dark theme is used'),
type: 'string'
}
}
}
]
}
}
};
}
export interface MenuItem {
command: string;
alt: string;
}
export interface Menus {
'editor/primary': MenuItem[];
'editor/secondary': MenuItem[];
export const commandsContribution: IJSONSchema = {
description: localize('vscode.extension.contributes.commands', "Contributes commands to the command palette."),
oneOf: [
commandType,
{
type: 'array',
items: commandType
}
]
};
}
ExtensionsRegistry.registerExtensionPoint<Menus>('menus', schema.menus).setHandler(extensions => {
ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: IUserFriendlyMenuItem[] }>('menus', schema.menusContribtion).setHandler(extensions => {
for (let extension of extensions) {
const {value} = extension;
const {value, collector} = extension;
if (schema.isValidMenus(value, extension.collector)) {
for (var key in value) {
if (value.hasOwnProperty(key)) {
MenusRegistry.registerMenuItems(MenuLocations.fromString(key), value[key]);
}
forEach(value, entry => {
if (!schema.isValidMenuItems(entry.value, collector)) {
return;
}
}
}
});
export enum MenuLocations {
EditorPrimary = 0,
EditorSecondary = 1
}
export namespace MenuLocations {
export function fromString(value: string): MenuLocations {
switch (value) {
case 'editor/primary': return MenuLocations.EditorPrimary;
case 'editor/secondary': return MenuLocations.EditorSecondary;
}
if (!MenuRegistry.registerMenuItems(<IUserFriendlyMenuLocation>entry.key, entry.value)) {
// ignored
}
});
}
}
});
export interface IMenuRegistry {
registerMenuItems(location: MenuLocations, items: MenuItem[]): void;
getMenuItems(location: MenuLocations): MenuItem[];
}
ExtensionsRegistry.registerExtensionPoint<IUserFriendlyCommand | IUserFriendlyCommand[]>('commands', schema.commandsContribution).setHandler(extensions => {
export const MenusRegistry: IMenuRegistry = new class {
function handleCommand(command: IUserFriendlyCommand, extension: IExtensionPointUser<any>) {
private _values: { [location: number]: MenuItem[] } = Object.create(null);
if (!schema.isValidCommand(command, extension.collector)) {
return;
}
registerMenuItems(location: MenuLocations, items: MenuItem[]): void {
let array = this._values[location];
if (array) {
array.push(...items);
let {icon} = command;
if (!icon) {
// ignore
} else if (typeof icon === 'string') {
command.icon = join(extension.description.extensionFolderPath, icon);
} else {
this._values[location] = items;
const light = join(extension.description.extensionFolderPath, icon.light);
const dark = join(extension.description.extensionFolderPath, icon.dark);
command.icon = { light, dark };
}
if (MenuRegistry.registerCommand(command)) {
extension.collector.info(localize('dup', "Command `{0}` appears multiple times in the `commands` section.", command.command));
}
}
getMenuItems(location: MenuLocations): MenuItem[] {
return this._values[location];
for (let extension of extensions) {
const {value} = extension;
if (Array.isArray<IUserFriendlyCommand>(value)) {
for (let command of value) {
handleCommand(command, extension);
}
} else {
handleCommand(value, extension);
}
}
};
});
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {values} from 'vs/base/common/collections';
import {KbExpr} from 'vs/platform/keybinding/common/keybindingService';
import {MenuLocation, CommandAction, MenuItem, IMenuService} from './actions';
export type IUserFriendlyMenuLocation = 'editor/primary' | 'editor/secondary';
export interface IUserFriendlyMenuItem {
command: string;
alt?: string;
when?: string;
}
export interface IUserFriendlyCommand {
command: string;
title: string;
category?: string;
icon?: string | { light: string; dark: string; };
}
export interface IMenuRegistry {
registerCommand(userCommand: IUserFriendlyCommand): boolean;
registerMenuItems(location: IUserFriendlyMenuLocation, items: IUserFriendlyMenuItem[]): boolean;
}
const _registry = new class {
private _commands: { [id: string]: CommandAction } = Object.create(null);
private _menuItems: { [loc: number]: IUserFriendlyMenuItem[] } = Object.create(null);
registerCommand(userCommand: IUserFriendlyCommand): boolean {
let {command, category, icon, title} = userCommand;
if (!icon) {
icon = '';
}
const old = this._commands[command];
this._commands[command] = {
id: command,
title,
category,
lightThemeIcon: typeof icon === 'string' ? icon : icon.light,
darkThemeIcon: typeof icon === 'string' ? icon : icon.dark
};
return old !== void 0;
}
registerMenuItems(location: IUserFriendlyMenuLocation, items: IUserFriendlyMenuItem[]): boolean {
const loc = MenuLocation.parse(location);
if (loc) {
let array = this._menuItems[loc];
if (!array) {
this._menuItems[loc] = items;
} else {
array.push(...items);
}
return true;
}
}
getMenuItems(loc: MenuLocation): MenuItem[] {
const menuItems = this._menuItems[loc];
if (menuItems) {
return menuItems.map(item => {
const when = KbExpr.deserialize(item.when);
const command = this._commands[item.command];
const alt = this._commands[item.alt];
return { when, command, alt };
});
}
}
getCommandActions(): CommandAction[] {
return values(this._commands);
}
};
export const MenuRegistry: IMenuRegistry = _registry;
export class MenuService implements IMenuService {
serviceId;
getMenuItems(loc: MenuLocation): MenuItem[] {
return _registry.getMenuItems(loc);
}
getCommandActions(): CommandAction[] {
return _registry.getCommandActions();
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {Registry} from 'vs/platform/platform';
import URI from 'vs/base/common/uri';
import {IAction, Action} from 'vs/base/common/actions';
import {BaseActionItem, ActionItem} from 'vs/base/browser/ui/actionbar/actionbar';
import {Scope, IActionBarRegistry, Extensions, ActionBarContributor} from 'vs/workbench/browser/actionBarRegistry';
import {IExtensionService} from 'vs/platform/extensions/common/extensions';
import {IThemeService} from 'vs/workbench/services/themes/common/themeService';
import {isLightTheme} from 'vs/platform/theme/common/themes';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
import {commands, CommandAction, Locations} from '../common/commandsExtensionPoint';
import {EditorInput} from 'vs/workbench/common/editor';
abstract class BaseActionBarContributor extends ActionBarContributor {
private _isReady: boolean = false;
constructor(
@IExtensionService private _extensionService: IExtensionService,
@IInstantiationService private _instantationService: IInstantiationService,
@IKeybindingService private _keybindingService: IKeybindingService
) {
super();
this._extensionService.onReady().then(() => this._isReady = true);
}
protected abstract _wheres(): { primary: Locations; secondary: Locations };
protected abstract _getResource(context: any): URI;
public hasActions(context: any): boolean {
return this._isReady && this._wheres().primary && this.getActions(context).length > 0;
}
public hasSecondaryActions(context: any): boolean {
return this._isReady && this._wheres().secondary && this.getSecondaryActions(context).length > 0;
}
public getActions(context: any): IAction[] {
return this._getActions(context, this._wheres().primary);
}
public getSecondaryActions(context: any): IAction[] {
return this._getActions(context, this._wheres().secondary);
}
private _getActions(context: any, where: Locations): IAction[] {
const result: IAction[] = [];
for (let command of commands) {
// console.log(command.id, command.when,
// this._keybindingService.contextMatchesRules(command.when),
// this._keybindingService.getContextValue('resourceLangId'),
// this._keybindingService.getContextValue('resourceScheme')
// );
if (command.where === where && this._keybindingService.contextMatchesRules(command.when)) {
let resource = this._keybindingService.getContextValue<URI>('resource');
result.push(this._instantationService.createInstance(class extends CommandAction {
run() {
return super.run(resource);
}
}, command));
}
}
return result;
}
public getActionItem(context: any, action: Action): BaseActionItem {
if (action instanceof CommandAction) {
return this._instantationService.createInstance(CommandActionItem, action);
}
}
}
class EditorContributor extends BaseActionBarContributor {
protected _wheres(): { primary: Locations; secondary: Locations } {
return { primary: 'editor/primary', secondary: 'editor/secondary' };
}
protected _getResource(context: any): URI {
const {input} = context;
if (input instanceof EditorInput) {
if (typeof input.getResource === 'function') {
const candidate = input.getResource();
if (candidate instanceof URI) {
return candidate;
}
}
}
}
}
class CommandActionItem extends ActionItem {
constructor(
action: CommandAction,
@IThemeService private _themeService: IThemeService
) {
super(undefined, action, {
icon: !!(action.command.lightThemeIcon || action.command.darkThemeIcon),
label: !(action.command.lightThemeIcon || action.command.darkThemeIcon)
});
this._themeService.onDidThemeChange(this._updateClass, this, this.callOnDispose);
}
_updateClass(): void {
super._updateClass();
const element = this.$e.getHTMLElement();
const {lightThemeIcon, darkThemeIcon} = (<CommandAction>this._action).command;
if (element.classList.contains('icon')) {
if (isLightTheme(this._themeService.getTheme())) {
element.style.backgroundImage = `url("${lightThemeIcon}")`;
} else {
element.style.backgroundImage = `url("${darkThemeIcon}")`;
}
}
}
onClick(event: Event): void {
super.onClick(event);
}
}
Registry.as<IActionBarRegistry>(Extensions.Actionbar).registerActionBarContributor(Scope.EDITOR, EditorContributor);
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {localize} from 'vs/nls';
import {IAction} from 'vs/base/common/actions';
import {IExtensionService} from 'vs/platform/extensions/common/extensions';
import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
import {IActionsService} from '../common/actions';
import {commands, CommandAction} from '../common/commandsExtensionPoint';
import 'vs/platform/actions/workbench/actionBarContributions';
export default class ActionsService implements IActionsService {
serviceId: any;
private _extensionsActions: IAction[];
constructor(
@IExtensionService private _extensionService: IExtensionService,
@IKeybindingService private _keybindingsService: IKeybindingService
) {
this._extensionService.onReady().then(() => this._extensionsActions = null);
}
getActions(): IAction[] {
if (!this._extensionsActions) {
this._extensionsActions = [];
for (let command of commands) {
const action = new CommandAction(command, this._extensionService, this._keybindingsService);
action.order = Number.MAX_VALUE;
action.label = command.category
? localize('category.label', "{0}: {1}", command.category, command.title)
: command.title;
this._extensionsActions.push(action);
}
}
return this._extensionsActions.slice(0);
}
}
......@@ -57,14 +57,15 @@ import {IEditorGroupService} from 'vs/workbench/services/group/common/groupServi
import {IHistoryService} from 'vs/workbench/services/history/common/history';
import {IEventService} from 'vs/platform/event/common/event';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {SyncDescriptor} from 'vs/platform/instantiation/common/descriptors';
import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection';
import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle';
import {IMessageService} from 'vs/platform/message/common/message';
import {IThreadService} from 'vs/platform/thread/common/thread';
import {MainThreadService} from 'vs/platform/thread/common/mainThreadService';
import {IStatusbarService} from 'vs/platform/statusbar/common/statusbar';
import {IActionsService} from 'vs/platform/actions/common/actions';
import ActionsService from 'vs/platform/actions/workbench/actionsService';
import {IMenuService} from 'vs/platform/actions/common/actions';
import {MenuService} from 'vs/platform/actions/common/menusService';
import {IContextMenuService} from 'vs/platform/contextview/browser/contextView';
interface WorkbenchParams {
......@@ -346,8 +347,8 @@ export class Workbench implements IPartService {
// Context Menu
serviceCollection.set(IContextMenuService, this.instantiationService.createInstance(ContextMenuService));
// Actions
serviceCollection.set(IActionsService, this.instantiationService.createInstance(ActionsService));
// Menus/Actions
serviceCollection.set(IMenuService, new SyncDescriptor(MenuService));
// Viewlet service (sidebar part)
this.sidebarPart = this.instantiationService.createInstance(SidebarPart, Identifiers.SIDEBAR_PART);
......
......@@ -16,7 +16,7 @@ import {IAction, Action} from 'vs/base/common/actions';
import {toErrorMessage} from 'vs/base/common/errors';
import {Mode, IEntryRunContext, IAutoFocus} from 'vs/base/parts/quickopen/common/quickOpen';
import {QuickOpenEntryGroup, IHighlight, QuickOpenModel} from 'vs/base/parts/quickopen/browser/quickOpenModel';
import {SyncActionDescriptor, IActionsService} from 'vs/platform/actions/common/actions';
import {SyncActionDescriptor, ExecuteCommandAction, IMenuService} from 'vs/platform/actions/common/actions';
import {IWorkbenchActionRegistry, Extensions as ActionExtensions} from 'vs/workbench/common/actionRegistry';
import {Registry} from 'vs/platform/platform';
import {QuickOpenHandler, QuickOpenAction} from 'vs/workbench/browser/quickopen';
......@@ -229,7 +229,7 @@ export class CommandsHandler extends QuickOpenHandler {
@IInstantiationService private instantiationService: IInstantiationService,
@IMessageService private messageService: IMessageService,
@IKeybindingService private keybindingService: IKeybindingService,
@IActionsService private actionsService: IActionsService
@IMenuService private menuService: IMenuService
) {
super();
}
......@@ -260,7 +260,7 @@ export class CommandsHandler extends QuickOpenHandler {
let editorEntries = this.editorActionsToEntries(editorActions, searchValue);
// Other Actions
let otherActions = this.actionsService.getActions();
let otherActions = this.menuService.getCommandActions().map(command => new ExecuteCommandAction(command.id, command.category ? nls.localize('', "{0}: {1}", command.category, command.title) : command.title, this.keybindingService));
let otherEntries = this.otherActionsToEntries(otherActions, searchValue);
// Concat
......
......@@ -16,7 +16,7 @@ import 'vs/editor/browser/editor.all';
// Languages
import 'vs/languages/languages.main';
// Extension Points
// Menus/Actions
import 'vs/platform/actions/common/menusExtensionPoint';
// Workbench
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册