Skip to content

Commit

Permalink
Merge pull request #3090 from shawnaxsom/bugfix/remap-operators-in-in…
Browse files Browse the repository at this point in the history
…sert-mode

Remappings not applying when operators that enter insert mode
  • Loading branch information
xconverge authored Oct 5, 2018
2 parents 5070d1e + 7db8fca commit 0b0bad5
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 10 deletions.
8 changes: 6 additions & 2 deletions src/mode/modeHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,18 +311,22 @@ export class ModeHandler implements vscode.Disposable {
try {
// Take the count prefix out to perform the correct remapping.
const withinTimeout = now - this.vimState.lastKeyPressedTimestamp < configuration.timeout;
const isOperatorCombination = this.vimState.recordedState.operator;

let handled = false;

/**
* Check that
*
* 1) We are not already performing a nonrecursive remapping.
* 2) We haven't timed out of our previous remapping.
* 2) We aren't in normal mode performing on an operator
* Note: ciwjj should be remapped if jj -> <Esc> in insert mode
* dd should not remap the second "d", if d -> "_d in normal mode
* 3) We haven't timed out of our previous remapping.
*/
if (
!this.vimState.isCurrentlyPerformingRemapping &&
!this.vimState.recordedState.operator &&
(!isOperatorCombination || this.vimState.currentMode !== ModeName.Normal) &&
(withinTimeout || this.vimState.recordedState.commandList.length === 1)
) {
handled = await this._remappers.sendKey(
Expand Down
119 changes: 111 additions & 8 deletions test/configuration/remapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ suite('Remapper', () => {
let modeHandler: ModeHandler;
let vimState: VimState;
const leaderKey = '\\';
const insertModeKeyBindings: IKeyRemapping[] = [
const defaultInsertModeKeyBindings: IKeyRemapping[] = [
{
before: ['j', 'j'],
after: ['<Esc>'],
},
];
const normalModeKeyBindings: IKeyRemapping[] = [
const defaultNormalModeKeyBindings: IKeyRemapping[] = [
{
before: ['leader', 'w'],
commands: [
Expand Down Expand Up @@ -55,7 +55,7 @@ suite('Remapper', () => {
after: ['$'],
},
];
const visualModeKeyBindings: IKeyRemapping[] = [
const defaultVisualModeKeyBindings: IKeyRemapping[] = [
{
before: ['leader', 'c'],
commands: [
Expand Down Expand Up @@ -87,22 +87,36 @@ suite('Remapper', () => {
}
}

setup(async () => {
const setupWithBindings = async ({
insertModeKeyBindings,
normalModeKeyBindings,
visualModeKeyBindings,
}: {
insertModeKeyBindings?: IKeyRemapping[];
normalModeKeyBindings?: IKeyRemapping[];
visualModeKeyBindings?: IKeyRemapping[];
}) => {
let configuration = new Configuration();
configuration.leader = leaderKey;
configuration.insertModeKeyBindings = insertModeKeyBindings;
configuration.normalModeKeyBindings = normalModeKeyBindings;
configuration.visualModeKeyBindings = visualModeKeyBindings;
configuration.insertModeKeyBindings = insertModeKeyBindings || [];
configuration.normalModeKeyBindings = normalModeKeyBindings || [];
configuration.visualModeKeyBindings = visualModeKeyBindings || [];

await setupWorkspace(configuration);
modeHandler = await getAndUpdateModeHandler();
vimState = modeHandler.vimState;
});
};

teardown(cleanUpWorkspace);

test('getLongestedRemappedKeySequence', async () => {
// setup
await setupWithBindings({
insertModeKeyBindings: defaultInsertModeKeyBindings,
normalModeKeyBindings: defaultNormalModeKeyBindings,
visualModeKeyBindings: defaultVisualModeKeyBindings,
});

let remappings: { [key: string]: IKeyRemapping } = {
abc: { before: ['a', 'b', 'c'] },
de: { before: ['d', 'e'] },
Expand All @@ -119,6 +133,12 @@ suite('Remapper', () => {
});

test('getMatchingRemap', async () => {
await setupWithBindings({
insertModeKeyBindings: defaultInsertModeKeyBindings,
normalModeKeyBindings: defaultNormalModeKeyBindings,
visualModeKeyBindings: defaultVisualModeKeyBindings,
});

const testCases = [
{
// able to match number in normal mode
Expand Down Expand Up @@ -158,6 +178,7 @@ suite('Remapper', () => {
input: 'jj',
mode: ModeName.Insert,
expectedAfter: '<Esc>',
expectedAfterMode: ModeName.Normal,
},
{
// able to match with preceding keystrokes in insert mode
Expand All @@ -166,6 +187,16 @@ suite('Remapper', () => {
input: 'hello world jj',
mode: ModeName.Insert,
expectedAfter: '<Esc>',
expectedAfterMode: ModeName.Normal,
},
{
// able to match with preceding keystrokes in insert mode
before: 'jj',
after: '<Esc>',
input: 'ifoo<Esc>ciwjj',
mode: ModeName.Insert,
expectedAfter: '<Esc>',
expectedAfterMode: ModeName.Normal,
},
];

Expand Down Expand Up @@ -197,13 +228,24 @@ suite('Remapper', () => {
} else {
assert.equal(actual, undefined);
}

if (testCase.expectedAfterMode) {
assertEqual(modeHandler.currentMode.name, testCase.expectedAfterMode);
assertEqual(modeHandler.vimState.currentMode, testCase.expectedAfterMode);
}
}
});

test('jj -> <Esc> through modehandler', async () => {
const expectedDocumentContent = 'lorem ipsum';

// setup
await setupWithBindings({
insertModeKeyBindings: defaultInsertModeKeyBindings,
normalModeKeyBindings: defaultNormalModeKeyBindings,
visualModeKeyBindings: defaultVisualModeKeyBindings,
});

let remapper = new Remappers();

const edit = new vscode.WorkspaceEdit();
Expand Down Expand Up @@ -233,6 +275,12 @@ suite('Remapper', () => {

test('0 -> :wq through modehandler', async () => {
// setup
await setupWithBindings({
insertModeKeyBindings: defaultInsertModeKeyBindings,
normalModeKeyBindings: defaultNormalModeKeyBindings,
visualModeKeyBindings: defaultVisualModeKeyBindings,
});

let remapper = new Remappers();
assertEqual(modeHandler.currentMode.name, ModeName.Normal);

Expand All @@ -251,6 +299,12 @@ suite('Remapper', () => {

test('leader, w -> closeActiveEditor in normal mode through modehandler', async () => {
// setup
await setupWithBindings({
insertModeKeyBindings: defaultInsertModeKeyBindings,
normalModeKeyBindings: defaultNormalModeKeyBindings,
visualModeKeyBindings: defaultVisualModeKeyBindings,
});

let remapper = new Remappers();
assertEqual(modeHandler.currentMode.name, ModeName.Normal);

Expand All @@ -269,6 +323,12 @@ suite('Remapper', () => {

test('leader, c -> closeActiveEditor in visual mode through modehandler', async () => {
// setup
await setupWithBindings({
insertModeKeyBindings: defaultInsertModeKeyBindings,
normalModeKeyBindings: defaultNormalModeKeyBindings,
visualModeKeyBindings: defaultVisualModeKeyBindings,
});

let remapper = new Remappers();
assertEqual(modeHandler.currentMode.name, ModeName.Normal);

Expand All @@ -289,6 +349,13 @@ suite('Remapper', () => {
});

test('d -> black hole register delete in normal mode through modehandler', async () => {
// setup
await setupWithBindings({
insertModeKeyBindings: defaultInsertModeKeyBindings,
normalModeKeyBindings: defaultNormalModeKeyBindings,
visualModeKeyBindings: defaultVisualModeKeyBindings,
});

assert.equal(modeHandler.currentMode.name, ModeName.Normal);

await modeHandler.handleMultipleKeyEvents(['<Esc>', 'g', 'g']);
Expand All @@ -300,13 +367,22 @@ suite('Remapper', () => {
actual = await Register.get(vimState);
assert.equal(actual.text, expected);

// act
await modeHandler.handleMultipleKeyEvents(['d', 'd']);

// assert
actual = await Register.get(vimState);
assert.equal(actual.text, expected);
});

test('d -> black hole register delete in normal mode through modehandler', async () => {
// setup
await setupWithBindings({
insertModeKeyBindings: defaultInsertModeKeyBindings,
normalModeKeyBindings: defaultNormalModeKeyBindings,
visualModeKeyBindings: defaultVisualModeKeyBindings,
});

assert.equal(modeHandler.currentMode.name, ModeName.Normal);

await modeHandler.handleMultipleKeyEvents(['<Esc>', 'g', 'g']);
Expand All @@ -318,11 +394,38 @@ suite('Remapper', () => {
actual = await Register.get(vimState);
assert.equal(actual.text, expected);

// act
await modeHandler.handleMultipleKeyEvents(['d', 'w']);

// assert
actual = await Register.get(vimState);
assert.equal(actual.text, expected);
});

test('jj -> <Esc> after ciw operator through modehandler', async () => {
// setup
await setupWithBindings({
insertModeKeyBindings: [
{
before: ['j', 'j'],
after: ['<Esc>'],
},
],
});

assert.equal(modeHandler.currentMode.name, ModeName.Normal);
await modeHandler.handleMultipleKeyEvents(['<Esc>', 'g', 'g']);
await modeHandler.handleMultipleKeyEvents(['i', 'word1 word2', '<Esc>', '0']);
assert.equal(modeHandler.currentMode.name, ModeName.Normal);

// act
await modeHandler.handleMultipleKeyEvents(['c', 'i', 'w']);
assert.equal(modeHandler.currentMode.name, ModeName.Insert);
await modeHandler.handleMultipleKeyEvents(['j', 'j']);

// assert
assert.equal(modeHandler.currentMode.name, ModeName.Normal);
});
});

/* tslint:enable:no-string-literal */

0 comments on commit 0b0bad5

Please sign in to comment.