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

Refactor commands [WIP] #234

Merged
merged 57 commits into from
Jun 5, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
83afbcf
Begin command refactor.
johnfn May 29, 2016
13fdd4c
Add the remaining keys.
johnfn May 29, 2016
f160a86
Passing most tests.
johnfn May 29, 2016
49b8a2f
Finish up normal mode rewrite.
johnfn May 29, 2016
7675cb6
Refactor actions to return positions.
johnfn May 29, 2016
bf5c42e
Refactor Normal & Visual mode to use same actions
johnfn May 29, 2016
7d15fff
Rewrite modes to take Actions, not key presses.
johnfn May 29, 2016
ee15155
Make operators inherit from a common base class.
johnfn May 29, 2016
409822f
Track action state in ModeHandler and write core processing fn.
johnfn May 30, 2016
a6d01bd
Remove a bunch of stuff.
johnfn May 30, 2016
c6db2d5
Respect modes for actions.
johnfn May 30, 2016
0b52969
Make all state transitions into Actions.
johnfn May 30, 2016
06ae75f
Clean up, fix <esc>.
johnfn May 30, 2016
3f2df04
Add x/X actions.
johnfn May 30, 2016
e0eb20c
Handle a lot of weird edge cases.
johnfn May 31, 2016
97c615c
Add a special case JUST for de.
johnfn May 31, 2016
8fe79c9
Add C.
johnfn May 31, 2016
b87a41a
Shove everything in one massive class.
johnfn May 31, 2016
f6d90dd
Fix cw.
johnfn May 31, 2016
bc8d0fe
Fix cW as well.
johnfn May 31, 2016
5bde23c
Pass all [operator][motion] normal mode tests!
johnfn May 31, 2016
c3683f0
Begin adding/rewriting visual mode tests.
johnfn May 31, 2016
8a6c826
Fix all visual mode tests!
johnfn May 31, 2016
0fce025
Fix a bug with deleting in Visual Mode.
johnfn Jun 2, 2016
da30a64
Fix gg, and refactor some logic along the way.
johnfn Jun 2, 2016
e84f583
Add test for gg.
johnfn Jun 2, 2016
beef8a6
Refactor a lot of deletes to use DeleteOperator.
johnfn Jun 2, 2016
87a3d99
Make DeleteOperator inclusive/exclusive.
johnfn Jun 2, 2016
8019bbe
Remove an unused function.
johnfn Jun 2, 2016
4b43b73
Fix off-by-one in reverse ranges.
johnfn Jun 2, 2016
a9476af
Add VimState, keep track of desired column again.
johnfn Jun 2, 2016
35eefbe
Clean up desiredColumn and add test.
johnfn Jun 2, 2016
4982f4b
Nest ActionState within VimState.
johnfn Jun 2, 2016
1114f9b
Nest ActionState within VimState and return VimState from actions.
johnfn Jun 2, 2016
9e055d6
Don't pass ActionState, only VimState.
johnfn Jun 2, 2016
a6c2144
Refactor the 'ready to run' logic.
johnfn Jun 3, 2016
af00ab7
Fix dl at end of line and add test.
johnfn Jun 3, 2016
b7ecb56
Add commands like $ force desiredColumn to EOL.
johnfn Jun 3, 2016
00cad54
Handle the returned VimState in a unified way.
johnfn Jun 3, 2016
7410857
Simplify logic.
johnfn Jun 3, 2016
f9fed66
Update mode via VimState.
johnfn Jun 3, 2016
f837304
Remove unnecessary parameter.
johnfn Jun 3, 2016
0f3fa9e
Remove handleDeactivation, which caused weird bugs.
johnfn Jun 3, 2016
e905f40
Stop passing in modeHandler to actions.
johnfn Jun 3, 2016
0fc8e94
Add a bunch of commands.
johnfn Jun 3, 2016
efc6133
Add 2 more commands back.
johnfn Jun 3, 2016
37a6abb
Add x operator in visual mode.
johnfn Jun 3, 2016
1a0cbb9
Add yank and put back.
johnfn Jun 3, 2016
e0e6974
Add text object and remove concept of inclusive/exclusive motions.
johnfn Jun 4, 2016
b662bad
Totally remove position options.
johnfn Jun 4, 2016
85b6d8c
Text objects work with d/c/y!!
johnfn Jun 5, 2016
88f2e57
Add iw text object.
johnfn Jun 5, 2016
3143f14
Fix an 'aw' bug.
johnfn Jun 5, 2016
d320241
Make "aw" motion work and pass tests.
johnfn Jun 5, 2016
cab7dd4
Fix iw motion.
johnfn Jun 5, 2016
668dfa1
Add put test and pass all tests.
johnfn Jun 5, 2016
3ce1c28
Fix all tslint errors.
johnfn Jun 5, 2016
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
Prev Previous commit
Next Next commit
Add text object and remove concept of inclusive/exclusive motions.
  • Loading branch information
johnfn committed Jun 4, 2016
commit e0e69744c052c7810279e4451e5301ea5ea213de
46 changes: 27 additions & 19 deletions src/actions/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,9 +366,7 @@ class CommandEsc extends BaseCommand {
key = "<esc>";

public async exec(position: Position, vimState: VimState): Promise<VimState> {
if (vimState.currentMode === ModeName.Visual) {
vimState.cursorPosition = position;
} else {
if (vimState.currentMode !== ModeName.Visual) {
vimState.cursorPosition = position.getLeft();
}

Expand Down Expand Up @@ -484,7 +482,7 @@ class CommandInsertAtLineEnd extends BaseCommand {

public async exec(position: Position, vimState: VimState): Promise<VimState> {
const pos = new Position(position.line,
position.getLineEnd(PositionOptions.CharacterWiseInclusive).character, position.positionOptions);
position.getLineEnd().character + 1, position.positionOptions);

vimState.currentMode = ModeName.Insert;
vimState.cursorPosition = pos;
Expand Down Expand Up @@ -803,6 +801,31 @@ class ActionDeleteLineVisualMode extends BaseCommand {
}
}

@RegisterAction
class MovementAWordTextObject extends BaseMovement {
modes = [ModeName.Normal, ModeName.Visual];
key = "aw";

public async execAction(position: Position, vimState: VimState): Promise<VimState> {
if (vimState.currentMode === ModeName.Visual && !vimState.cursorPosition.isEqual(vimState.cursorStartPosition)) {
// TODO: This is kind of a bad way to do this.
return new MoveWordBegin().execAction(position, vimState);
}

let currentChar = TextEditor.getLineAt(position).text[position.character];

if (currentChar === ' ' || currentChar === '\t') {
vimState.cursorStartPosition = position.getLastWordEnd();
vimState.cursorPosition = position.getCurrentWordEnd();
} else {
vimState.cursorStartPosition = position.getWordLeft();
vimState.cursorPosition = position.getWordRight();
}

return vimState;
}
}

/*
// Doing this correctly is very difficult.
https://github.com/Microsoft/vscode/issues/7177
Expand Down Expand Up @@ -871,21 +894,6 @@ class ActionChangeCurrentWord {
}
}

@RegisterAction
class ActionChangeCurrentWordToNext {
modes = [ModeName.Normal];
key = "caw";

public async execAction(position: Position): Promise<VimState> {
motion.changeMode(MotionMode.Cursor);
let currentChar = TextEditor.getLineAt(motion.position).text[motion.position.character];
if (currentChar === ' ' || currentChar === '\t') {
await new ChangeOperator(modeHandler).run(motion.position.getLastWordEnd(), motion.position.getCurrentWordEnd());
} else {
await new ChangeOperator(modeHandler).run(motion.position.getWordLeft(), motion.position.getWordRight());
}
}
}

@RegisterAction
class ActionPaste {
Expand Down
36 changes: 28 additions & 8 deletions src/mode/modeHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,14 @@ export class VimState {
/**
* The position the cursor will be when this action finishes.
*/
public cursorPosition = new Position(0, 0, PositionOptions.CharacterWiseInclusive);
public cursorPosition = new Position(0, 0, PositionOptions.CharacterWiseExclusive);

/**
* The effective starting position of the movement, used along with cursorPosition to determine
* the range over which to run an Operator. May rarely be different than where the cursor
* actually starts e.g. if you use the "aw" text motion in the middle of a word.
*/
public cursorStartPosition = new Position(0, 0, PositionOptions.CharacterWiseExclusive);

/**
* The mode Vim will be in once this action finishes.
Expand Down Expand Up @@ -264,6 +271,8 @@ export class ModeHandler implements vscode.Disposable {
await (this.currentMode as any).handleAction(actionState);
this._vimState.actionState = new ActionState(this._vimState);

this._vimState.cursorPosition = this._motion.position.getRight();

return true;
} else {
// This is the ultimate failure case. Just insert the key into the document. This is
Expand Down Expand Up @@ -291,6 +300,11 @@ export class ModeHandler implements vscode.Disposable {
}

if (actionState.readyToExecute) {
if (this.currentMode.name !== ModeName.Visual &&
this.currentMode.name !== ModeName.VisualLine) {
this._vimState.cursorStartPosition = this._motion.position;
}

this._vimState = await this.executeState();

if (this._vimState.commandAction !== VimCommandActions.DoNothing) {
Expand All @@ -313,7 +327,7 @@ export class ModeHandler implements vscode.Disposable {
// Update mode

if (this._vimState.currentMode !== this.currentModeName) {
this.setCurrentModeByName(this._vimState.currentMode)
this.setCurrentModeByName(this._vimState.currentMode);
}

// Update cursor position
Expand All @@ -327,9 +341,14 @@ export class ModeHandler implements vscode.Disposable {
}

if (this.currentMode instanceof NormalMode) {
if (stop.character >= Position.getLineLength(stop.line)) {
stop = stop.getLeft();
this._vimState.cursorPosition = stop;
}

this._motion.moveTo(stop.line, stop.character);
} else if (this.currentMode instanceof VisualMode) {
await (this.currentMode as VisualMode).handleMotion(stop);
await (this.currentMode as VisualMode).handleMotion(this._vimState.cursorStartPosition, stop);
} else if (this.currentMode instanceof InsertMode) {
this._motion.moveTo(stop.line, stop.character);
} else {
Expand All @@ -356,21 +375,22 @@ export class ModeHandler implements vscode.Disposable {
}

private async executeState(): Promise<VimState> {
let start: Position, stop: Position;
let start = this._vimState.cursorStartPosition;
let stop = this._vimState.cursorPosition;
let actionState = this._vimState.actionState;
let newState: VimState;

if (actionState.command) {
return await actionState.command.exec(this._motion.position, this._vimState);
return await actionState.command.exec(stop, this._vimState);
}

start = this._motion.position;
if (actionState.movement) {
newState = actionState.operator ?
await actionState.movement.execActionForOperator(start, this._vimState) :
await actionState.movement.execAction (start, this._vimState);
await actionState.movement.execActionForOperator(stop, this._vimState) :
await actionState.movement.execAction (stop, this._vimState);

actionState = newState.actionState;
start = newState.cursorStartPosition;
stop = newState.cursorPosition;
}

Expand Down
3 changes: 2 additions & 1 deletion src/mode/modeVisual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ export class VisualMode extends Mode {
this.motion.select(this._selectionStart, this._selectionStop);
}

public async handleMotion(position: Position): Promise<boolean> {
public async handleMotion(start: Position, position: Position): Promise<boolean> {
this._selectionStop = position;
this._selectionStart = start;
this.motion.moveTo(this._selectionStart.line, this._selectionStart.character);

/**
Expand Down
40 changes: 11 additions & 29 deletions src/motion/position.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ export class Position extends vscode.Position {

constructor(line: number, character: number, options: PositionOptions) {
super(line, character);

this.positionOptions = options;
this.positionOptions = PositionOptions.CharacterWiseExclusive;

this._nonWordCharRegex = this.makeWordRegex(Position.NonWordCharacters);
this._nonBigWordCharRegex = this.makeWordRegex(Position.NonBigWordCharacters);
Expand Down Expand Up @@ -79,7 +78,7 @@ export class Position extends vscode.Position {
public getDown(desiredColumn: number) : Position {
if (this.getDocumentEnd().line !== this.line) {
let nextLine = this.line + 1;
let nextLineLength = Position.getLineLength(nextLine, this.positionOptions);
let nextLineLength = Position.getLineLength(nextLine);

return new Position(nextLine, Math.min(nextLineLength, desiredColumn), this.positionOptions);
}
Expand All @@ -93,7 +92,7 @@ export class Position extends vscode.Position {
public getUp(desiredColumn: number) : Position {
if (this.getDocumentBegin().line !== this.line) {
let prevLine = this.line - 1;
let prevLineLength = Position.getLineLength(prevLine, this.positionOptions);
let prevLineLength = Position.getLineLength(prevLine);

return new Position(prevLine, Math.min(prevLineLength, desiredColumn), this.positionOptions);
}
Expand Down Expand Up @@ -180,7 +179,7 @@ export class Position extends vscode.Position {
*/
public getLineEnd(opts: PositionOptions = null) : Position {
if (opts === null) { opts = this.positionOptions; }
return new Position(this.line, Position.getLineLength(this.line, opts), opts);
return new Position(this.line, Position.getLineLength(this.line), opts);
}

public getDocumentBegin() : Position {
Expand All @@ -190,7 +189,7 @@ export class Position extends vscode.Position {
public getDocumentEnd() : Position {
let lineCount = TextEditor.getLineCount();
let line = lineCount > 0 ? lineCount - 1 : 0;
let char = Position.getLineLength(line, this.positionOptions);
let char = Position.getLineLength(line);

return new Position(line, char, this.positionOptions);
}
Expand All @@ -203,8 +202,8 @@ export class Position extends vscode.Position {
}

// char
let charCount = Position.getLineLength(this.line, this.positionOptions);
if (this.character > charCount) {
let charCount = Position.getLineLength(this.line);
if (this.character > charCount + 1) {
return false;
}

Expand All @@ -226,8 +225,8 @@ export class Position extends vscode.Position {
/**
* Is this position at the end of the line?
*/
public isLineEnd() : boolean {
return this.character === Position.getLineLength(this.line, this.positionOptions);
public isLineEnd(): boolean {
return this.character >= Position.getLineLength(this.line);
}

public isAtDocumentEnd(): boolean {
Expand All @@ -246,19 +245,8 @@ export class Position extends vscode.Position {
return new Position(0, 0, this.positionOptions);
}

private static getLineLength(line: number, options: PositionOptions) : number {
switch (options) {
case PositionOptions.CharacterWiseExclusive:
// Valid Positions for Caret: [0, eol)
var len = TextEditor.readLineAt(line).length;
return len > 0 ? len - 1 : len;
case PositionOptions.CharacterWiseInclusive:
// Valid Positions for Caret: [0, eol]
return TextEditor.readLineAt(line).length;

default:
throw new Error("Unhandled PositionOptions: " + options);
}
public static getLineLength(line: number) : number {
return TextEditor.readLineAt(line).length;
}

private makeWordRegex(characterSet: string) : RegExp {
Expand Down Expand Up @@ -344,9 +332,6 @@ export class Position extends vscode.Position {
}

if (newCharacter !== undefined) {
if (this.positionOptions === PositionOptions.CharacterWiseInclusive) {
newCharacter++;
}
return new Position(currentLine, newCharacter, this.positionOptions);
}
}
Expand All @@ -360,9 +345,6 @@ export class Position extends vscode.Position {
let newCharacter = _.find(positions, index => index > this.character || currentLine !== this.line);

if (newCharacter !== undefined) {
if (this.positionOptions === PositionOptions.CharacterWiseInclusive) {
newCharacter++;
}
return new Position(currentLine, newCharacter, this.positionOptions);
}
}
Expand Down
18 changes: 5 additions & 13 deletions test/motion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,12 @@ suite("motion", () => {
};
});

test("char right: caret", () => {
let motion = new Motion(MotionMode.Caret);

motion = motion.moveTo(0, 7).right();
assert.equal(motion.position.line, 0);
assert.equal(motion.position.character, 7);
});

test("char right: cursor", () => {
test("char right", () => {
let motion = new Motion(MotionMode.Cursor);
motion = motion.moveTo(0, 8).right();
motion = motion.moveTo(0, 9).right();

assert.equal(motion.position.line, 0);
assert.equal(motion.position.character, 8);
assert.equal(motion.position.character, 9);
});

test("char left: should move cursor one column left", () => {
Expand Down Expand Up @@ -242,7 +234,7 @@ suite("word motion", () => {
test("last word on last line should go to end of document (special case!)", () => {
let motion = new Motion(MotionMode.Caret).moveTo(6, 6).wordRight();
assert.equal(motion.position.line, 6);
assert.equal(motion.position.character, 9);
assert.equal(motion.position.character, 10);
});

});
Expand Down Expand Up @@ -458,7 +450,7 @@ suite("paragraph motion", () => {
test("paragraph at end of document", () => {
let motion = new Motion(MotionMode.Caret).moveTo(7, 0).goToEndOfCurrentParagraph();
assert.equal(motion.position.line, 8);
assert.equal(motion.position.character, 2);
assert.equal(motion.position.character, 3);
});
});

Expand Down