未验证 提交 5fb0f1ea 编写于 作者: A Alexandru Dima 提交者: GitHub

Merge pull request #66458 from usernamehw/json_if_validation

Autocomplete/validation `args` for keybindings.json
......@@ -86,7 +86,28 @@ export namespace EditorScroll_ {
* 'value': Number of units to move. Default is '1'.
* 'revealCursor': If 'true' reveals the cursor if it is outside view port.
`,
constraint: isEditorScrollArgs
constraint: isEditorScrollArgs,
schema: {
'type': 'object',
'required': ['to'],
'properties': {
'to': {
'type': 'string',
'enum': ['up', 'down']
},
'by': {
'type': 'string',
'enum': ['line', 'wrappedLine', 'page', 'halfPage']
},
'value': {
'type': 'number',
'default': 1
},
'revealCursor': {
'type': 'boolean',
}
}
}
}
]
};
......@@ -217,7 +238,20 @@ export namespace RevealLine_ {
'top', 'center', 'bottom'
\`\`\`
`,
constraint: isRevealLineArgs
constraint: isRevealLineArgs,
schema: {
'type': 'object',
'required': ['lineNumber'],
'properties': {
'lineNumber': {
'type': 'number',
},
'at': {
'type': 'string',
'enum': ['top', 'center', 'bottom']
}
}
}
}
]
};
......@@ -1691,10 +1725,11 @@ class EditorHandlerCommand extends Command {
private readonly _handlerId: string;
constructor(id: string, handlerId: string) {
constructor(id: string, handlerId: string, description?: ICommandHandlerDescription) {
super({
id: id,
precondition: null
precondition: null,
description: description
});
this._handlerId = handlerId;
}
......@@ -1767,12 +1802,26 @@ registerCommand(new EditorOrNativeTextInputCommand({
}));
registerCommand(new EditorHandlerCommand('default:' + Handler.Redo, Handler.Redo));
function registerOverwritableCommand(handlerId: string): void {
function registerOverwritableCommand(handlerId: string, description?: ICommandHandlerDescription): void {
registerCommand(new EditorHandlerCommand('default:' + handlerId, handlerId));
registerCommand(new EditorHandlerCommand(handlerId, handlerId));
registerCommand(new EditorHandlerCommand(handlerId, handlerId, description));
}
registerOverwritableCommand(Handler.Type);
registerOverwritableCommand(Handler.Type, {
description: `Type`,
args: [{
name: 'args',
schema: {
'type': 'object',
'required': ['text'],
'properties': {
'text': {
'type': 'string'
}
},
}
}]
});
registerOverwritableCommand(Handler.ReplacePreviousChar);
registerOverwritableCommand(Handler.CompositionStart);
registerOverwritableCommand(Handler.CompositionEnd);
......
......@@ -616,7 +616,29 @@ export namespace CursorMove {
* 'value': Number of units to move. Default is '1'.
* 'select': If 'true' makes the selection. Default is 'false'.
`,
constraint: isCursorMoveArgs
constraint: isCursorMoveArgs,
schema: {
'type': 'object',
'required': ['to'],
'properties': {
'to': {
'type': 'string',
'enum': ['left', 'right', 'up', 'down', 'wrappedLineStart', 'wrappedLineEnd', 'wrappedLineColumnCenter', 'wrappedLineFirstNonWhitespaceCharacter', 'wrappedLineLastNonWhitespaceCharacter', 'viewPortTop', 'viewPortCenter', 'viewPortBottom', 'viewPortIfOutside']
},
'by': {
'type': 'string',
'enum': ['line', 'wrappedLine', 'character', 'halfLine']
},
'value': {
'type': 'number',
'default': 1
},
'select': {
'type': 'boolean',
'default': false
}
}
}
}
]
};
......
......@@ -253,7 +253,27 @@ export class CodeActionCommand extends EditorCommand {
constructor() {
super({
id: CodeActionCommand.Id,
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider)
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),
description: {
description: `Trigger a code action`,
args: [{
name: 'args',
schema: {
'type': 'object',
'required': ['kind'],
'properties': {
'kind': {
'type': 'string'
},
'apply': {
'type': 'string',
'default': 'ifSingle',
'enum': ['first', 'ifSingle', 'never']
}
}
}
}]
}
});
}
......@@ -297,6 +317,25 @@ export class RefactorAction extends EditorAction {
when: ContextKeyExpr.and(
EditorContextKeys.writable,
contextKeyForSupportedActions(CodeActionKind.Refactor)),
},
description: {
description: 'Refactor...',
args: [{
name: 'args',
schema: {
'type': 'object',
'properties': {
'kind': {
'type': 'string'
},
'apply': {
'type': 'string',
'default': 'never',
'enum': ['first', 'ifSingle', 'never']
}
}
}
}]
}
});
}
......@@ -333,6 +372,25 @@ export class SourceAction extends EditorAction {
when: ContextKeyExpr.and(
EditorContextKeys.writable,
contextKeyForSupportedActions(CodeActionKind.Source)),
},
description: {
description: 'Source Action...',
args: [{
name: 'args',
schema: {
'type': 'object',
'properties': {
'kind': {
'type': 'string'
},
'apply': {
'type': 'string',
'default': 'never',
'enum': ['first', 'ifSingle', 'never']
}
}
}
}]
}
});
}
......
......@@ -519,7 +519,27 @@ class UnfoldAction extends FoldingAction<FoldingArguments> {
* 'direction': If 'up', unfold given number of levels up otherwise unfolds down.
* 'selectionLines': The start lines (0-based) of the editor selections to apply the unfold action to. If not set, the active selection(s) will be used.
`,
constraint: foldingArgumentsConstraint
constraint: foldingArgumentsConstraint,
schema: {
'type': 'object',
'properties': {
'levels': {
'type': 'number',
'default': 1
},
'direction': {
'type': 'string',
'enum': ['up', 'down'],
'default': 'down'
},
'selectionLines': {
'type': 'array',
'items': {
'type': 'number'
}
}
}
}
}
]
}
......@@ -584,7 +604,27 @@ class FoldAction extends FoldingAction<FoldingArguments> {
* 'direction': If 'up', folds given number of levels up otherwise folds down.
* 'selectionLines': The start lines (0-based) of the editor selections to apply the fold action to. If not set, the active selection(s) will be used.
`,
constraint: foldingArgumentsConstraint
constraint: foldingArgumentsConstraint,
schema: {
'type': 'object',
'properties': {
'levels': {
'type': 'number',
'default': 1
},
'direction': {
'type': 'string',
'enum': ['up', 'down'],
'default': 'down'
},
'selectionLines': {
'type': 'array',
'items': {
'type': 'number'
}
}
}
}
}
]
}
......
......@@ -8,6 +8,7 @@ import { TypeConstraint, validateConstraints } from 'vs/base/common/types';
import { ServicesAccessor, createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Event, Emitter } from 'vs/base/common/event';
import { LinkedList } from 'vs/base/common/linkedList';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
export const ICommandService = createDecorator<ICommandService>('commandService');
......@@ -37,7 +38,7 @@ export interface ICommand {
export interface ICommandHandlerDescription {
description: string;
args: { name: string; description?: string; constraint?: TypeConstraint; }[];
args: { name: string; description?: string; constraint?: TypeConstraint; schema?: IJSONSchema; }[];
returns?: string;
}
......
......@@ -65,7 +65,24 @@ export class OpenFolderAPICommand {
return executor.executeCommand('_files.windowOpen', { urisToOpen: [{ uri }], forceNewWindow });
}
}
CommandsRegistry.registerCommand(OpenFolderAPICommand.ID, adjustHandler(OpenFolderAPICommand.execute));
CommandsRegistry.registerCommand({
id: OpenFolderAPICommand.ID,
handler: adjustHandler(OpenFolderAPICommand.execute),
description: {
description: `Open a folder`,
args: [{
name: 'uri',
schema: {
'type': 'string'
}
}, {
name: 'forceNewWindow',
schema: {
'type': 'boolean'
}
}]
}
});
export class DiffAPICommand {
public static ID = 'vscode.diff';
......@@ -126,7 +143,31 @@ export class SetEditorLayoutAPICommand {
return executor.executeCommand('layoutEditorGroups', layout);
}
}
CommandsRegistry.registerCommand(SetEditorLayoutAPICommand.ID, adjustHandler(SetEditorLayoutAPICommand.execute));
CommandsRegistry.registerCommand({
id: SetEditorLayoutAPICommand.ID,
handler: adjustHandler(SetEditorLayoutAPICommand.execute),
description: {
description: 'Set Editor Layout',
args: [{
name: 'args',
schema: {
'type': 'object',
'required': ['groups'],
'properties': {
'orientation': {
'type': 'number',
'default': 0,
'enum': [0, 1]
},
'groups': {
'$ref': '#/definitions/editorGroupsSchema', // defined in keybindingService.ts ...
'default': [{}, {}],
}
}
}
}]
}
});
CommandsRegistry.registerCommand('_workbench.downloadResource', function (accessor: ServicesAccessor, resource: URI) {
const downloadService = accessor.get(IDownloadService);
......
......@@ -90,7 +90,24 @@ function registerActiveEditorMoveCommand(): void {
{
name: nls.localize('editorCommand.activeEditorMove.arg.name', "Active editor move argument"),
description: nls.localize('editorCommand.activeEditorMove.arg.description', "Argument Properties:\n\t* 'to': String value providing where to move.\n\t* 'by': String value providing the unit for move (by tab or by group).\n\t* 'value': Number value providing how many positions or an absolute position to move."),
constraint: isActiveEditorMoveArg
constraint: isActiveEditorMoveArg,
schema: {
'type': 'object',
'required': ['to'],
'properties': {
'to': {
'type': 'string',
'enum': ['left', 'right']
},
'by': {
'type': 'string',
'enum': ['tab', 'group']
},
'value': {
'type': 'number'
}
},
}
}
]
}
......
......@@ -19,12 +19,24 @@ export const defaultQuickOpenContext = ContextKeyExpr.and(inQuickOpenContext, Co
export const QUICKOPEN_ACTION_ID = 'workbench.action.quickOpen';
export const QUICKOPEN_ACION_LABEL = nls.localize('quickOpen', "Go to File...");
CommandsRegistry.registerCommand(QUICKOPEN_ACTION_ID, function (accessor: ServicesAccessor, prefix: string | null = null) {
CommandsRegistry.registerCommand({
id: QUICKOPEN_ACTION_ID,
handler: function (accessor: ServicesAccessor, prefix: string | null = null) {
const quickOpenService = accessor.get(IQuickOpenService);
return quickOpenService.show(typeof prefix === 'string' ? prefix : undefined).then(() => {
return undefined;
});
},
description: {
description: `Quick open`,
args: [{
name: 'prefix',
schema: {
'type': 'string'
}
}]
}
});
export const QUICKOPEN_FOCUS_SECONDARY_ACTION_ID = 'workbench.action.quickOpenPreviousEditor';
......
......@@ -54,7 +54,28 @@ class InsertSnippetAction extends EditorAction {
id: 'editor.action.insertSnippet',
label: nls.localize('snippet.suggestions.label', "Insert Snippet"),
alias: 'Insert Snippet',
precondition: EditorContextKeys.writable
precondition: EditorContextKeys.writable,
description: {
description: `Insert Snippet`,
args: [{
name: 'args',
schema: {
'type': 'object',
'properties': {
'snippet': {
'type': 'string'
},
'langId': {
'type': 'string',
},
'name': {
'type': 'string'
}
},
}
}]
}
});
}
......
......@@ -549,8 +549,20 @@ class TaskService extends Disposable implements ITaskService {
}
private registerCommands(): void {
CommandsRegistry.registerCommand('workbench.action.tasks.runTask', (accessor, arg) => {
CommandsRegistry.registerCommand({
id: 'workbench.action.tasks.runTask',
handler: (accessor, arg) => {
this.runTaskCommand(arg);
},
description: {
description: 'Run Task',
args: [{
name: 'args',
schema: {
'type': 'string',
}
}]
}
});
CommandsRegistry.registerCommand('workbench.action.tasks.reRunTask', (accessor, arg) => {
......
......@@ -514,7 +514,22 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, Fi
const sendSequenceTerminalCommand = new SendSequenceTerminalCommand({
id: SendSequenceTerminalCommand.ID,
precondition: null
precondition: null,
description: {
description: `Send Custom Sequence To Terminal`,
args: [{
name: 'args',
schema: {
'type': 'object',
'required': ['text'],
'properties': {
'text': {
'type': 'string'
}
},
}
}]
}
});
sendSequenceTerminalCommand.register();
......
......@@ -15,7 +15,7 @@ import { Keybinding, ResolvedKeybinding } from 'vs/base/common/keyCodes';
import { KeybindingParser } from 'vs/base/common/keybindingParser';
import { OS, OperatingSystem } from 'vs/base/common/platform';
import { ConfigWatcher } from 'vs/base/node/config';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { Extensions as ConfigExtensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
......@@ -280,6 +280,8 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
) {
super(contextKeyService, commandService, telemetryService, notificationService, statusBarService);
updateSchema();
let dispatchConfig = getDispatchConfig(configurationService);
configurationService.onDidChangeConfiguration((e) => {
let newDispatchConfig = getDispatchConfig(configurationService);
......@@ -573,6 +575,24 @@ let schema: IJSONSchema = {
'id': schemaId,
'type': 'array',
'title': nls.localize('keybindings.json.title', "Keybindings configuration"),
'definitions': {
'editorGroupsSchema': {
'type': 'array',
'items': {
'type': 'object',
'properties': {
'groups': {
'$ref': '#/definitions/editorGroupsSchema',
'default': [{}, {}]
},
'size': {
'type': 'number',
'default': 0.5
}
}
}
}
},
'items': {
'required': ['key'],
'type': 'object',
......@@ -593,13 +613,40 @@ let schema: IJSONSchema = {
'args': {
'description': nls.localize('keybindings.json.args', "Arguments to pass to the command to execute.")
}
}
},
'allOf': []
}
};
let schemaRegistry = Registry.as<IJSONContributionRegistry>(Extensions.JSONContribution);
schemaRegistry.registerSchema(schemaId, schema);
function updateSchema() {
const allCommands = CommandsRegistry.getCommands();
for (let commandId in allCommands) {
const commandDescription = allCommands[commandId].description;
if (!commandDescription || !commandDescription.args || commandDescription.args.length !== 1 || !commandDescription.args[0].schema) {
continue;
}
const argsSchema = commandDescription.args[0].schema;
const addition = {
'if': {
'properties': {
'command': { 'const': commandId }
}
},
'then': {
'properties': {
'args': argsSchema
}
}
};
schema['items']['allOf'].push(addition);
}
}
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigExtensions.Configuration);
const keyboardConfiguration: IConfigurationNode = {
'id': 'keyboard',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册