Skip to content

Commit

Permalink
Implement 'RegisterPluginAction' to sneak plugin
Browse files Browse the repository at this point in the history
- Add default mappings for 'f','F','t','T' when config.sneakReplacesF is
set to true and remove them when it is false
- Add '<Plug>Sneak_t' and  '<Plug>Sneak_T' when config.sneakReplacesF
is set
- Add tests for this new 'till' movements
  • Loading branch information
berknam committed Jul 9, 2020
1 parent 967ec23 commit 7ff8e41
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 52 deletions.
21 changes: 0 additions & 21 deletions src/actions/motion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { VimError, ErrorCode } from '../error';
import { BaseMovement, SelectionType, IMovement, isIMovement } from './baseMotion';
import { globalState } from '../state/globalState';
import { reportSearch } from '../util/statusBarTextUtils';
import { SneakForward, SneakBackward } from './plugins/sneak';
import { Notation } from '../configuration/notation';
import { SearchDirection } from '../state/searchState';
import { StatusBar } from '../statusBar';
Expand Down Expand Up @@ -651,18 +650,6 @@ class MoveFindForward extends BaseMovement {
vimState: VimState,
count: number
): Promise<Position | IMovement> {
if (configuration.sneakReplacesF) {
const pos = await new SneakForward(
this.keysPressed.concat('\n'),
this.isRepeat
).execActionWithCount(position, vimState, count);
if (vimState.recordedState.operator && !isIMovement(pos)) {
return pos.getRight();
}

return pos;
}

count = count || 1;
const toFind = Notation.ToControlCharacter(this.keysPressed[1]);
let result = findHelper(position, toFind, count, 'forward');
Expand Down Expand Up @@ -691,14 +678,6 @@ class MoveFindBackward extends BaseMovement {
vimState: VimState,
count: number
): Promise<Position | IMovement> {
if (configuration.sneakReplacesF) {
return new SneakBackward(this.keysPressed.concat('\n'), this.isRepeat).execActionWithCount(
position,
vimState,
count
);
}

count = count || 1;
const toFind = Notation.ToControlCharacter(this.keysPressed[1]);
let result = findHelper(position, toFind, count, 'backward');
Expand Down
175 changes: 144 additions & 31 deletions src/actions/plugins/sneak.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
import * as vscode from 'vscode';
import { VimState } from '../../state/vimState';
import { configuration } from './../../configuration/configuration';
import { RegisterAction } from './../base';
import { RegisterAction, RegisterPluginAction } from './../base';
import { Position } from '../../common/motion/position';
import { BaseMovement, IMovement } from '../baseMotion';

@RegisterAction
export class SneakForward extends BaseMovement {
keys = [
['s', '<character>', '<character>'],
['z', '<character>', '<character>'],
];
import { BaseMovement, IMovement, isIMovement } from '../baseMotion';
import { Mode } from '../../mode/mode';

class SneakForward extends BaseMovement {
isJump = true;

public doesActionApply(vimState: VimState, keysPressed: string[]): boolean {
return configuration.sneak && super.doesActionApply(vimState, keysPressed);
}

public couldActionApply(vimState: VimState, keysPressed: string[]): boolean {
const startingLetter = vimState.recordedState.operator === undefined ? 's' : 'z';
return configuration.sneak && super.couldActionApply(vimState, keysPressed);
}

return (
configuration.sneak &&
super.couldActionApply(vimState, keysPressed) &&
keysPressed[0] === startingLetter
);
setRepeatMovements(vimState: VimState) {
vimState.lastSemicolonRepeatableMovement = new SneakForward(this.keysPressed, true);
vimState.lastCommaRepeatableMovement = new SneakBackward(this.keysPressed, true);
}

public async execAction(position: Position, vimState: VimState): Promise<Position | IMovement> {
if (!this.isRepeat) {
vimState.lastSemicolonRepeatableMovement = new SneakForward(this.keysPressed, true);
vimState.lastCommaRepeatableMovement = new SneakBackward(this.keysPressed, true);
this.setRepeatMovements(vimState);
}

const editor = vscode.window.activeTextEditor!;
Expand Down Expand Up @@ -71,28 +69,25 @@ export class SneakForward extends BaseMovement {
}
}

@RegisterAction
export class SneakBackward extends BaseMovement {
keys = [
['S', '<character>', '<character>'],
['Z', '<character>', '<character>'],
];
class SneakBackward extends BaseMovement {
isJump = true;

public doesActionApply(vimState: VimState, keysPressed: string[]): boolean {
return configuration.sneak && super.doesActionApply(vimState, keysPressed);
}

public couldActionApply(vimState: VimState, keysPressed: string[]): boolean {
const startingLetter = vimState.recordedState.operator === undefined ? 'S' : 'Z';
return configuration.sneak && super.couldActionApply(vimState, keysPressed);
}

return (
configuration.sneak &&
super.couldActionApply(vimState, keysPressed) &&
keysPressed[0] === startingLetter
);
setRepeatMovements(vimState: VimState) {
vimState.lastSemicolonRepeatableMovement = new SneakBackward(this.keysPressed, true);
vimState.lastCommaRepeatableMovement = new SneakForward(this.keysPressed, true);
}

public async execAction(position: Position, vimState: VimState): Promise<Position | IMovement> {
if (!this.isRepeat) {
vimState.lastSemicolonRepeatableMovement = new SneakBackward(this.keysPressed, true);
vimState.lastCommaRepeatableMovement = new SneakForward(this.keysPressed, true);
this.setRepeatMovements(vimState);
}

const editor = vscode.window.activeTextEditor!;
Expand Down Expand Up @@ -135,3 +130,121 @@ export class SneakBackward extends BaseMovement {
return position;
}
}

@RegisterPluginAction('sneak')
class SneakForwardNormalAndVisualMode extends SneakForward {
keys = ['<Plug>Sneak_s', '<character>', '<character>'];
pluginActionDefaultKeys = ['s'];
modes = [Mode.Normal, Mode.Visual, Mode.VisualLine, Mode.VisualBlock];
}

@RegisterPluginAction('sneak')
class SneakForwardOperatorPendingMode extends SneakForward {
keys = ['<Plug>Sneak_s', '<character>', '<character>'];
pluginActionDefaultKeys = ['z'];
modes = [Mode.OperatorPendingMode];
}

@RegisterPluginAction('sneak')
class SneakBackwardNormalAndVisualMode extends SneakBackward {
keys = ['<Plug>Sneak_S', '<character>', '<character>'];
pluginActionDefaultKeys = ['S'];
modes = [Mode.Normal, Mode.Visual, Mode.VisualLine, Mode.VisualBlock];
}

@RegisterPluginAction('sneak')
class SneakBackwardOperatorPendingMode extends SneakBackward {
keys = ['<Plug>Sneak_S', '<character>', '<character>'];
pluginActionDefaultKeys = ['Z'];
modes = [Mode.OperatorPendingMode];
}

@RegisterPluginAction('sneak')
class SneakFForward extends SneakForward {
keys = ['<Plug>Sneak_f', '<character>'];
pluginActionDefaultKeys = [];

setRepeatMovements(vimState: VimState) {
vimState.lastSemicolonRepeatableMovement = new SneakFForward(this.keysPressed, true);
vimState.lastCommaRepeatableMovement = new SneakFBackward(this.keysPressed, true);
}

public async execAction(position: Position, vimState: VimState): Promise<Position | IMovement> {
this.keysPressed.push('');
const pos = await super.execAction(position, vimState);
if (vimState.recordedState.operator && !isIMovement(pos)) {
// if ran with an operator move right to include the searched character
return pos.getRight();
}

return pos;
}
}

@RegisterPluginAction('sneak')
class SneakFBackward extends SneakBackward {
keys = ['<Plug>Sneak_F', '<character>'];
pluginActionDefaultKeys = [];

setRepeatMovements(vimState: VimState) {
vimState.lastSemicolonRepeatableMovement = new SneakFBackward(this.keysPressed, true);
vimState.lastCommaRepeatableMovement = new SneakFForward(this.keysPressed, true);
}

public async execAction(position: Position, vimState: VimState): Promise<Position | IMovement> {
this.keysPressed.push('');
return super.execAction(position, vimState);
}
}

@RegisterPluginAction('sneak')
class SneakTForward extends SneakForward {
keys = ['<Plug>Sneak_t', '<character>'];
pluginActionDefaultKeys = [];

setRepeatMovements(vimState: VimState) {
vimState.lastSemicolonRepeatableMovement = new SneakTForward(this.keysPressed, true);
vimState.lastCommaRepeatableMovement = new SneakTBackward(this.keysPressed, true);
}

public async execAction(position: Position, vimState: VimState): Promise<Position | IMovement> {
this.keysPressed.push('');

if (this.isRepeat) {
position = position.getRightThroughLineBreaks(false);
}
const pos = await super.execAction(position, vimState);

if (!isIMovement(pos) && !vimState.recordedState.operator) {
// if not a failed movement and not an operator, go left of found character
return pos.getLeftThroughLineBreaks(false);
}

return pos;
}
}

@RegisterPluginAction('sneak')
class SneakTBackward extends SneakBackward {
keys = ['<Plug>Sneak_T', '<character>'];
pluginActionDefaultKeys = [];

setRepeatMovements(vimState: VimState) {
vimState.lastSemicolonRepeatableMovement = new SneakTBackward(this.keysPressed, true);
vimState.lastCommaRepeatableMovement = new SneakTForward(this.keysPressed, true);
}

public async execAction(position: Position, vimState: VimState): Promise<Position | IMovement> {
this.keysPressed.push('');
if (this.isRepeat) {
position = position.getLeftThroughLineBreaks(false);
}
const pos = await super.execAction(position, vimState);
if (!isIMovement(pos)) {
// if not a failed movement, go right of found character
return pos.getRightThroughLineBreaks(false);
}

return pos;
}
}
40 changes: 40 additions & 0 deletions src/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,46 @@ class Configuration implements IConfiguration {

this.clearKeyBindingsMaps();

// Create or remove the default mappings for 'f', 'F', 't' and 'T' for sneak
const sneakMappings = ['<Plug>Sneak_f', '<Plug>Sneak_F', '<Plug>Sneak_t', '<Plug>Sneak_T'];
if (this.sneakReplacesF) {
for (const sneakMap of sneakMappings) {
this.defaultnormalModeKeyBindingsNonRecursive.push({
before: [sneakMap[sneakMap.length - 1]],
after: [sneakMap],
});
this.defaultvisualModeKeyBindingsNonRecursive.push({
before: [sneakMap[sneakMap.length - 1]],
after: [sneakMap],
});
this.defaultoperatorPendingModeKeyBindingsNonRecursive.push({
before: [sneakMap[sneakMap.length - 1]],
after: [sneakMap],
});
}
} else {
for (const sneakMap of sneakMappings) {
let idx = this.defaultnormalModeKeyBindingsNonRecursive.findIndex(
(r) => r.after && r.after[0] === sneakMap && r.after.length === 1
);
if (idx > -1) {
this.defaultnormalModeKeyBindingsNonRecursive.splice(idx, 1);
}
idx = this.defaultvisualModeKeyBindingsNonRecursive.findIndex(
(r) => r.after && r.after[0] === sneakMap && r.after.length === 1
);
if (idx > -1) {
this.defaultvisualModeKeyBindingsNonRecursive.splice(idx, 1);
}
idx = this.defaultoperatorPendingModeKeyBindingsNonRecursive.findIndex(
(r) => r.after && r.after[0] === sneakMap && r.after.length === 1
);
if (idx > -1) {
this.defaultoperatorPendingModeKeyBindingsNonRecursive.splice(idx, 1);
}
}
}

const validatorResults = await configurationValidator.validate(configuration);

// wrap keys
Expand Down
2 changes: 2 additions & 0 deletions src/configuration/validators/remappingValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ export class RemappingValidator implements IConfigurationValidator {
return config.easymotion;
case 'replacewithregister':
return config.replaceWithRegister;
case 'sneak':
return config.sneak;
default:
return false;
}
Expand Down
14 changes: 14 additions & 0 deletions test/plugins/sneak.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,18 @@ suite('sneakReplacesF', () => {
keysPressed: 'Fa;',
end: ['apple', 'ban|ana', 'carrot'],
});

newTest({
title: 'sneakReplacesF forward till',
start: ['|apple', 'banana', 'carrot'],
keysPressed: 'ta;',
end: ['apple', 'ba|nana', 'carrot'],
});

newTest({
title: 'sneakReplacesF backward till',
start: ['apple', 'banana', '|carrot'],
keysPressed: 'Ta;',
end: ['apple', 'bana|na', 'carrot'],
});
});

0 comments on commit 7ff8e41

Please sign in to comment.