mirror of
https://github.com/VSCodeVim/Vim.git
synced 2024-09-11 12:25:59 +03:00
Implement ; and , (#674)
* Implement ; and , * Trying to fix travis ci agent (which does not handle clipboard tests well) * fix tslint errors * cleanup * more cleanup * even more cleanup * and more cleanup
This commit is contained in:
parent
660df9aa65
commit
69ff80c3f6
@ -54,8 +54,8 @@ Status | Command | Description
|
||||
:white_check_mark: |:1234: F{char} | to the Nth occurrence of {char} to the left
|
||||
:white_check_mark: |:1234: t{char} | till before the Nth occurrence of {char} to the right
|
||||
:white_check_mark: |:1234: T{char} | till before the Nth occurrence of {char} to the left
|
||||
|:1234: ; | repeat the last "f", "F", "t", or "T" N times
|
||||
|:1234: , | repeat the last "f", "F", "t", or "T" N times in opposite direction
|
||||
:white_check_mark: |:1234: ; | repeat the last "f", "F", "t", or "T" N times
|
||||
:white_check_mark: |:1234: , | repeat the last "f", "F", "t", or "T" N times in opposite direction
|
||||
|
||||
## Up-down motions
|
||||
|
||||
|
@ -156,6 +156,13 @@ export abstract class BaseMovement extends BaseAction {
|
||||
|
||||
canBePrefixedWithCount = false;
|
||||
|
||||
/**
|
||||
* Whether we should change lastRepeatableMovement in VimState.
|
||||
*/
|
||||
public canBeRepeatedWithSemicolon(vimState: VimState, result: Position | IMovement) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we should change desiredColumn in VimState.
|
||||
*/
|
||||
@ -1992,6 +1999,10 @@ class MoveFindForward extends BaseMovement {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public canBeRepeatedWithSemicolon(vimState: VimState, result: Position | IMovement) {
|
||||
return !vimState.recordedState.operator || !(isIMovement(result) && result.failed);
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
@ -2009,6 +2020,10 @@ class MoveFindBackward extends BaseMovement {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public canBeRepeatedWithSemicolon(vimState: VimState, result: Position | IMovement) {
|
||||
return !vimState.recordedState.operator || !(isIMovement(result) && result.failed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2031,6 +2046,10 @@ class MoveTilForward extends BaseMovement {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public canBeRepeatedWithSemicolon(vimState: VimState, result: Position | IMovement) {
|
||||
return !vimState.recordedState.operator || !(isIMovement(result) && result.failed);
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
@ -2048,6 +2067,59 @@ class MoveTilBackward extends BaseMovement {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public canBeRepeatedWithSemicolon(vimState: VimState, result: Position | IMovement) {
|
||||
return !vimState.recordedState.operator || !(isIMovement(result) && result.failed);
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
class MoveRepeat extends BaseMovement {
|
||||
keys = [";"];
|
||||
|
||||
public async execActionWithCount(position: Position, vimState: VimState, count: number): Promise<Position | IMovement> {
|
||||
const movement = VimState.lastRepeatableMovement;
|
||||
if (movement) {
|
||||
const result = await movement.execActionWithCount(position, vimState, count);
|
||||
/**
|
||||
* For t<character> and T<character> commands vim executes ; as 2;
|
||||
* This way the cursor will get to the next instance of <character>
|
||||
*/
|
||||
if (result instanceof Position && position.isEqual(result) && count <= 1) {
|
||||
return await movement.execActionWithCount(position, vimState, 2);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@RegisterAction
|
||||
class MoveRepeatReversed extends BaseMovement {
|
||||
keys = [","];
|
||||
static reverseMotionMapping : Map<Function, () => BaseMovement> = new Map([
|
||||
[MoveFindForward, () => new MoveFindBackward()],
|
||||
[MoveFindBackward, () => new MoveFindForward()],
|
||||
[MoveTilForward, () => new MoveTilBackward()],
|
||||
[MoveTilBackward, () => new MoveTilForward()]
|
||||
]);
|
||||
|
||||
public async execActionWithCount(position: Position, vimState: VimState, count: number): Promise<Position | IMovement> {
|
||||
const movement = VimState.lastRepeatableMovement;
|
||||
if (movement) {
|
||||
const reverse = MoveRepeatReversed.reverseMotionMapping.get(movement.constructor)();
|
||||
reverse.keysPressed = [reverse.keys[0], movement.keysPressed[1]];
|
||||
|
||||
let result = await reverse.execActionWithCount(position, vimState, count);
|
||||
// For t<character> and T<character> commands vim executes ; as 2;
|
||||
if (result instanceof Position && position.isEqual(result) && count <= 1) {
|
||||
result = await reverse.execActionWithCount(position, vimState, 2);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
|
@ -54,6 +54,8 @@ export class VimState {
|
||||
|
||||
public historyTracker: HistoryTracker;
|
||||
|
||||
public static lastRepeatableMovement : BaseMovement | undefined = undefined;
|
||||
|
||||
/**
|
||||
* The keystroke sequence that made up our last complete action (that can be
|
||||
* repeated with '.').
|
||||
@ -850,6 +852,10 @@ export class ModeHandler implements vscode.Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
if (movement.canBeRepeatedWithSemicolon(vimState, result)) {
|
||||
VimState.lastRepeatableMovement = movement;
|
||||
}
|
||||
|
||||
vimState.recordedState.count = 0;
|
||||
|
||||
let stop = vimState.cursorPosition;
|
||||
|
@ -23,7 +23,7 @@ Globals.isTesting = true;
|
||||
testRunner.configure({
|
||||
ui: 'tdd',
|
||||
useColors: true,
|
||||
timeout: 2500,
|
||||
timeout: 4000,
|
||||
});
|
||||
|
||||
module.exports = testRunner;
|
||||
|
@ -44,7 +44,7 @@ suite("register", () => {
|
||||
newTest({
|
||||
title: "Can use two registers together",
|
||||
start: ['|one', "two"],
|
||||
keysPressed: '"*yyjyy"*pp',
|
||||
keysPressed: '"ayyj"byy"ap"bp',
|
||||
end: ["one", "two", "one", "|two"],
|
||||
});
|
||||
|
||||
|
49
test/register/repeatableMovement.test.ts
Normal file
49
test/register/repeatableMovement.test.ts
Normal file
@ -0,0 +1,49 @@
|
||||
"use strict";
|
||||
|
||||
import { ModeHandler } from "../../src/mode/modeHandler";
|
||||
import { setupWorkspace, cleanUpWorkspace, assertEqualLines } from '../testUtils';
|
||||
import { getTestingFunctions } from '../testSimplifier';
|
||||
|
||||
suite("register", () => {
|
||||
let modeHandler: ModeHandler = new ModeHandler();
|
||||
|
||||
let {
|
||||
newTest,
|
||||
newTestOnly,
|
||||
} = getTestingFunctions(modeHandler);
|
||||
|
||||
setup(async () => {
|
||||
await setupWorkspace();
|
||||
});
|
||||
|
||||
suiteTeardown(cleanUpWorkspace);
|
||||
|
||||
newTest({
|
||||
title: "Can repeat f<character>",
|
||||
start: ['|abc abc abc'],
|
||||
keysPressed: 'fa;',
|
||||
end: ['abc abc |abc'],
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: "Can repeat reversed F<character>",
|
||||
start: ['|abc abc abc'],
|
||||
keysPressed: 'fa$,',
|
||||
end: ['abc abc |abc'],
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: "Can repeat t<character>",
|
||||
start: ['|abc abc abc'],
|
||||
keysPressed: 'tc;',
|
||||
end: ['abc a|bc abc'],
|
||||
});
|
||||
|
||||
newTest({
|
||||
title: "Can repeat N times reversed t<character>",
|
||||
start: ['|abc abc abc abc'],
|
||||
keysPressed: 'tc$3,',
|
||||
end: ['abc| abc abc abc'],
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in New Issue
Block a user