Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remappings not applying with operators that enter insert mode #3090

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 */