Files
vscode-extension-samples/vim-sample/src/mappings.ts

196 lines
6.6 KiB
TypeScript
Raw Normal View History

2016-07-15 12:39:15 +02:00
/*---------------------------------------------------------------------------------------------
* 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 {TextEditor} from 'vscode';
2016-07-25 16:59:01 +02:00
import {Motion, Motions} from './motions';
2016-07-15 12:39:15 +02:00
import {Operator, Operators} from './operators';
2016-07-25 16:59:01 +02:00
import {IController, Command, AbstractCommandDescriptor} from './common';
2016-07-15 12:39:15 +02:00
const CHAR_TO_MOTION: { [char: string]: Motion; } = {};
function defineMotion(char: string, motion: Motion): void {
CHAR_TO_MOTION[char] = motion;
};
2016-07-19 12:57:26 +02:00
2016-07-25 16:59:01 +02:00
const CHAR_TO_MOTION_COMMAND: { [char: string]: AbstractCommandDescriptor; } = {};
function defineMotionCommand(char: string, motionCommand: AbstractCommandDescriptor): void {
2016-07-19 12:57:26 +02:00
CHAR_TO_MOTION_COMMAND[char] = motionCommand;
};
// Left-right motions
2016-07-21 21:13:00 +02:00
defineMotionCommand('h', Motions.Left);
defineMotionCommand('l', Motions.Right);
2016-07-19 12:57:26 +02:00
defineMotion('0', Motions.StartOfLine);
defineMotion('$', Motions.EndOfLine);
2016-07-21 21:13:00 +02:00
defineMotionCommand('g0', Motions.WrappedLineStart);
defineMotionCommand('g^', Motions.WrappedLineFirstNonWhiteSpaceCharacter);
defineMotionCommand('gm', Motions.WrappedLineColumnCenter);
defineMotionCommand('g$', Motions.WrappedLineEnd);
2016-07-27 11:05:23 +02:00
defineMotionCommand('g_', Motions.WrappedLineLastNonWhiteSpaceCharacter);
2016-07-21 21:13:00 +02:00
// Scroll motions
defineMotionCommand('zh', Motions.ScrollLeft);
defineMotionCommand('zl', Motions.ScrollRight);
defineMotionCommand('zH', Motions.ScrollLeftByHalfLine);
defineMotionCommand('zL', Motions.ScrollRightByHalfLine);
2016-07-19 12:57:26 +02:00
// Up-down motions
2016-07-15 12:39:15 +02:00
defineMotion('j', Motions.Down);
defineMotion('k', Motions.Up);
2016-07-21 21:13:00 +02:00
defineMotionCommand('gj', Motions.WrappedLineDown);
defineMotionCommand('gk', Motions.WrappedLineUp);
2016-07-15 12:39:15 +02:00
defineMotion('G', Motions.GoToLine);
defineMotion('gg', Motions.GoToFirstLine);
2016-07-21 21:13:00 +02:00
defineMotionCommand('H', Motions.ViewPortTop);
defineMotionCommand('M', Motions.ViewPortCenter);
defineMotionCommand('L', Motions.ViewPortBottom);
2016-07-19 12:57:26 +02:00
// Word motions
defineMotion('w', Motions.NextWordStart);
defineMotion('e', Motions.NextWordEnd);
2016-07-15 12:39:15 +02:00
2016-07-25 17:42:04 +02:00
// Tab motions
2016-07-25 16:59:01 +02:00
defineMotionCommand('tabm', Motions.MoveActiveEditor);
defineMotionCommand('tabm<', Motions.MoveActiveEditorLeft);
defineMotionCommand('tabm>', Motions.MoveActiveEditorRight);
defineMotionCommand('tabm<<', Motions.MoveActiveEditorFirst);
defineMotionCommand('tabm>>', Motions.MoveActiveEditorLast);
defineMotionCommand('tabm.', Motions.MoveActiveEditorCenter);
2016-07-15 12:39:15 +02:00
const CHAR_TO_OPERATOR: { [char: string]: Operator; } = {};
function defineOperator(char: string, operator: Operator): void {
CHAR_TO_OPERATOR[char] = operator;
};
defineOperator('x', Operators.DeleteCharUnderCursor);
defineOperator('i', Operators.Insert);
defineOperator('a', Operators.Append);
defineOperator('A', Operators.AppendEndOfLine);
defineOperator('d', Operators.DeleteTo);
defineOperator('p', Operators.Put);
defineOperator('r', Operators.Replace);
defineOperator('R', Operators.ReplaceMode);
defineOperator('c', Operators.Change);
defineOperator('v', Operators.Visual);
const CHAR_TO_COMMAND: { [char: string]: Command; } = {};
function defineCommand(char: string, commandId: string, args?: any): void {
CHAR_TO_COMMAND[char] = {commandId : commandId, args: args};
};
defineCommand('u', 'undo');
defineCommand('U', 'undo');
export interface IFoundOperator {
runNormal(controller: IController, editor:TextEditor): boolean;
runVisual(controller: IController, editor:TextEditor): boolean;
}
export class Mappings {
public static findMotion(input: string): Motion {
let parsed = _parseNumberAndString(input);
let motion = CHAR_TO_MOTION[parsed.input.substr(0, 1)];
if (!motion) {
motion = CHAR_TO_MOTION[parsed.input.substr(0, 2)];
if (!motion) {
return null;
}
}
return motion.repeat(parsed.hasRepeatCount, parsed.repeatCount);
}
2016-07-21 21:13:00 +02:00
public static findMotionCommand(input: string, isVisual: boolean = false): Command {
2016-07-15 12:39:15 +02:00
let parsed = _parseNumberAndString(input);
2016-07-25 17:42:04 +02:00
let command = Mappings.findMotionCommandFromNumberAndString(parsed, isVisual);
if (!command) {
parsed = _parseNumberAndString(input, false);
command= Mappings.findMotionCommandFromNumberAndString(parsed, isVisual);
}
return command;
}
private static findMotionCommandFromNumberAndString(numberAndString: INumberAndString, isVisual: boolean): Command {
let motionCommand = CHAR_TO_MOTION_COMMAND[numberAndString.input.substr(0, 1)];
2016-07-15 12:39:15 +02:00
if (!motionCommand) {
2016-07-25 17:42:04 +02:00
motionCommand = CHAR_TO_MOTION_COMMAND[numberAndString.input.substr(0, 2)];
2016-07-15 12:39:15 +02:00
}
2016-07-19 12:57:26 +02:00
if (!motionCommand) {
2016-07-25 17:42:04 +02:00
motionCommand = CHAR_TO_MOTION_COMMAND[numberAndString.input.substr(1, 2)];
2016-07-19 12:57:26 +02:00
}
if (!motionCommand) {
2016-07-25 17:42:04 +02:00
motionCommand = CHAR_TO_MOTION_COMMAND[numberAndString.input.substr(1, 3)];
2016-07-19 12:57:26 +02:00
}
2016-07-25 16:59:01 +02:00
if (!motionCommand) {
2016-07-25 17:42:04 +02:00
motionCommand = CHAR_TO_MOTION_COMMAND[numberAndString.input];
2016-07-25 16:59:01 +02:00
}
2016-07-25 17:42:04 +02:00
return motionCommand ? motionCommand.createCommand({ isVisual: isVisual, repeat: numberAndString.hasRepeatCount ? numberAndString.repeatCount : undefined}) : null;
2016-07-15 12:39:15 +02:00
}
public static findOperator(input: string): IFoundOperator {
let parsed = _parseNumberAndString(input);
let operator = CHAR_TO_OPERATOR[parsed.input.substr(0, 1)];
if (!operator) {
return null;
}
let operatorArgs = parsed.input.substr(1);
return {
2016-07-25 16:59:01 +02:00
runNormal: (controller: IController, editor: TextEditor) => {
2016-07-15 12:39:15 +02:00
return operator.runNormalMode(controller, editor, parsed.repeatCount, operatorArgs);
},
2016-07-25 16:59:01 +02:00
runVisual: (controller: IController, editor: TextEditor) => {
2016-07-15 12:39:15 +02:00
return operator.runVisualMode(controller, editor, operatorArgs);
}
};
}
public static findCommand(input: string): Command {
return CHAR_TO_COMMAND[input] || null;
}
public static isMotionPrefix(input: string): boolean {
if (input.length === 0) {
return true;
}
2016-07-21 21:13:00 +02:00
if (input === 'g' || input === 'v' || input === 'z') {
2016-07-15 12:39:15 +02:00
return true;
}
2016-07-21 21:13:00 +02:00
return /^[1-9]\d*v?g?z?$/.test(input);
2016-07-15 12:39:15 +02:00
}
}
2016-07-25 17:42:04 +02:00
function _parseNumberAndString(input: string, numberAtBeginning: boolean = true): INumberAndString {
if (numberAtBeginning) {
let repeatCountMatch = input.match(/^([1-9]\d*)/);
if (repeatCountMatch) {
return {
hasRepeatCount: true,
repeatCount: parseInt(repeatCountMatch[0], 10),
input: input.substr(repeatCountMatch[0].length)
};
}
} else {
let repeatCountMatch = input.match(/(\d+)$/);
if (repeatCountMatch) {
return {
hasRepeatCount: true,
repeatCount: parseInt(repeatCountMatch[1], 10),
input: input.substr(0, input.length - repeatCountMatch[1].length)
};
}
2016-07-25 16:59:01 +02:00
}
2016-07-15 12:39:15 +02:00
return {
hasRepeatCount: false,
repeatCount: 1,
input: input
}
}
interface INumberAndString {
hasRepeatCount: boolean;
repeatCount: number;
input: string;
}