From bbcfb34662c7f3aee6dbee83b76a79b53479bda8 Mon Sep 17 00:00:00 2001 From: johnfn Date: Sun, 5 Jun 2016 23:29:37 -0700 Subject: [PATCH 1/3] Add f, F, t and T motions. --- src/actions/actions.ts | 57 +++++++++++++++++++++++++++++++++++++++++ src/mode/modeHandler.ts | 4 +-- src/motion/position.ts | 50 ++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 2 deletions(-) diff --git a/src/actions/actions.ts b/src/actions/actions.ts index c25e489c4e5..28b2fd25ebb 100644 --- a/src/actions/actions.ts +++ b/src/actions/actions.ts @@ -657,6 +657,63 @@ class MoveRight extends BaseMovement { } } +@RegisterAction +class MoveFindForward extends BaseMovement { + modes = [ModeName.Normal, ModeName.Visual, ModeName.VisualLine]; + keys = ["f", ""]; + + public async execAction(position: Position, vimState: VimState): Promise { + const toFind = vimState.actionState.keysPressed[1]; + + vimState.cursorPosition = position.findForwards(toFind); + + return vimState; + } +} + +@RegisterAction +class MoveFindBackward extends BaseMovement { + modes = [ModeName.Normal, ModeName.Visual, ModeName.VisualLine]; + keys = ["F", ""]; + + public async execAction(position: Position, vimState: VimState): Promise { + const toFind = vimState.actionState.keysPressed[1]; + + vimState.cursorPosition = position.findBackwards(toFind); + + return vimState; + } +} + + +@RegisterAction +class MoveTilForward extends BaseMovement { + modes = [ModeName.Normal, ModeName.Visual, ModeName.VisualLine]; + keys = ["t", ""]; + + public async execAction(position: Position, vimState: VimState): Promise { + const toFind = vimState.actionState.keysPressed[1]; + + vimState.cursorPosition = position.tilForwards(toFind); + + return vimState; + } +} + +@RegisterAction +class MoveTilBackward extends BaseMovement { + modes = [ModeName.Normal, ModeName.Visual, ModeName.VisualLine]; + keys = ["T", ""]; + + public async execAction(position: Position, vimState: VimState): Promise { + const toFind = vimState.actionState.keysPressed[1]; + + vimState.cursorPosition = position.tilBackwards(toFind); + + return vimState; + } +} + @RegisterAction class MoveLineEnd extends BaseMovement { modes = [ModeName.Normal, ModeName.Visual, ModeName.VisualLine]; diff --git a/src/mode/modeHandler.ts b/src/mode/modeHandler.ts index 8ddd7465209..f2b194ad881 100644 --- a/src/mode/modeHandler.ts +++ b/src/mode/modeHandler.ts @@ -292,8 +292,6 @@ export class ModeHandler implements vscode.Disposable { } } else if (action === KeypressState.WaitingOnKeys) { return true; - } else { - actionState.keysPressed = []; } if (action) { @@ -417,6 +415,8 @@ export class ModeHandler implements vscode.Disposable { this._vimState.actionState = new ActionState(this._vimState); } + actionState.keysPressed = []; + return !!action; } diff --git a/src/motion/position.ts b/src/motion/position.ts index 32195e35684..9cbb1547133 100644 --- a/src/motion/position.ts +++ b/src/motion/position.ts @@ -410,4 +410,54 @@ export class Position extends vscode.Position { return new Position(TextEditor.getLineCount() - 1, 0).getLineEnd(); } + + + private findHelper(char: string, count: number, direction: number): Position { + // -1 = backwards, +1 = forwards + const line = TextEditor.getLineAt(this); + let index = this.character; + + while (count && index !== -1) { + if (direction > 0) { + index = line.text.indexOf(char, index + direction); + } else { + index = line.text.lastIndexOf(char, index + direction); + } + count--; + } + + if (index > -1) { + return new Position(this.line, index); + } + + return null; + } + + public tilForwards(char: string, count: number = 1): Position { + const position = this.findHelper(char, count, +1); + if (!position) { return this; } + + return new Position(this.line, position.character - 1); + } + + public tilBackwards(char: string, count: number = 1): Position { + const position = this.findHelper(char, count, -1); + if (!position) { return this; } + + return new Position(this.line, position.character + 1); + } + + public findForwards(char: string, count: number = 1): Position { + const position = this.findHelper(char, count, +1); + if (!position) { return this; } + + return new Position(this.line, position.character); + } + + public findBackwards(char: string, count: number = 1): Position { + const position = this.findHelper(char, count, -1); + if (!position) { return this; } + + return position; + } } \ No newline at end of file From b3937344be62535ddd45c4d9977e60476537f950 Mon Sep 17 00:00:00 2001 From: johnfn Date: Sun, 5 Jun 2016 23:40:21 -0700 Subject: [PATCH 2/3] Add f/F tests. --- test/mode/modeNormal.test.ts | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/test/mode/modeNormal.test.ts b/test/mode/modeNormal.test.ts index 89c86fb4a16..e3077f88bea 100644 --- a/test/mode/modeNormal.test.ts +++ b/test/mode/modeNormal.test.ts @@ -366,4 +366,63 @@ suite("Mode Normal", () => { assertEqual(TextEditor.getSelection().start.character, 3, "caw is on wrong position"); await assert.equal(modeHandler.currentMode.name, ModeName.Insert, "didn't enter insert mode"); }); + + test("Can handle 'f'", async () => { + await modeHandler.handleMultipleKeyEvents( + 'itext text'.split('') + ); + + await modeHandler.handleMultipleKeyEvents([ + '', + '^', + 'f', 't' + ]); + + assertEqual(TextEditor.getSelection().start.character, 3, "f failed"); + }); + + test("Can handle 'f' twice", async () => { + await modeHandler.handleMultipleKeyEvents( + 'itext text'.split('') + ); + + await modeHandler.handleMultipleKeyEvents([ + '', + '^', + 'f', 't', + 'f', 't' + ]); + + assertEqual(TextEditor.getSelection().start.character, 5, "f failed"); + }); + + test("Can handle 'F'", async () => { + await modeHandler.handleMultipleKeyEvents( + 'itext text'.split('') + ); + + await modeHandler.handleMultipleKeyEvents([ + '', + '$', + 'F', 't' + ]); + + assertEqual(TextEditor.getSelection().start.character, 5, "F failed"); + }); + + test("Can handle 'F'", async () => { + await modeHandler.handleMultipleKeyEvents( + 'itext text'.split('') + ); + + await modeHandler.handleMultipleKeyEvents([ + '', + '$', + 'F', 't', + 'F', 't', + ]); + + assertEqual(TextEditor.getSelection().start.character, 3, "F failed"); + }); + }); From 8dea31b66cb2b40085b311f5822c0eb206f7a5df Mon Sep 17 00:00:00 2001 From: johnfn Date: Sun, 5 Jun 2016 23:44:36 -0700 Subject: [PATCH 3/3] Add t/T tests. --- test/mode/modeNormal.test.ts | 67 +++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/test/mode/modeNormal.test.ts b/test/mode/modeNormal.test.ts index e3077f88bea..3f7a62c87a5 100644 --- a/test/mode/modeNormal.test.ts +++ b/test/mode/modeNormal.test.ts @@ -410,7 +410,7 @@ suite("Mode Normal", () => { assertEqual(TextEditor.getSelection().start.character, 5, "F failed"); }); - test("Can handle 'F'", async () => { + test("Can handle 'F' twice", async () => { await modeHandler.handleMultipleKeyEvents( 'itext text'.split('') ); @@ -425,4 +425,69 @@ suite("Mode Normal", () => { assertEqual(TextEditor.getSelection().start.character, 3, "F failed"); }); + + + + test("Can handle 't'", async () => { + await modeHandler.handleMultipleKeyEvents( + 'itext text'.split('') + ); + + await modeHandler.handleMultipleKeyEvents([ + '', + '^', + 't', 't' + ]); + + assertEqual(TextEditor.getSelection().start.character, 2, "f failed"); + }); + + test("Can handle 't' twice", async () => { + await modeHandler.handleMultipleKeyEvents( + 'itext text'.split('') + ); + + await modeHandler.handleMultipleKeyEvents([ + '', + '^', + 't', 't', + 't', 't' + ]); + + // it does nothing the second time lawl + assertEqual(TextEditor.getSelection().start.character, 2, "f failed"); + }); + + test("Can handle 'T'", async () => { + await modeHandler.handleMultipleKeyEvents( + 'itext text'.split('') + ); + + await modeHandler.handleMultipleKeyEvents([ + '', + '$', + 'T', 't' + ]); + + assertEqual(TextEditor.getSelection().start.character, 6, "F failed"); + }); + + test("Can handle 'T' twice", async () => { + await modeHandler.handleMultipleKeyEvents( + 'itext text'.split('') + ); + + await modeHandler.handleMultipleKeyEvents([ + '', + '$', + 'T', 't', + 'T', 't', + ]); + + // it also does nothing the second time lawl lawl + assertEqual(TextEditor.getSelection().start.character, 6, "F failed"); + }); + + + });