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

Cursor Motions #56

Merged
merged 2 commits into from
Nov 30, 2015
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
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Vim emulation for Visual Studio Code.
* Command Palette: `:`
* Navigation: `h`, `j`, `k`, `l`
* Indentation: `>>`, `<<`
* Deletion: `dd`, `dw`
* Deletion: `dd`, `dw`, `db`
* Editing: `u`, `ctrl+r`
* File Operations: `:q`, `:w`

Expand All @@ -40,7 +40,20 @@ In no particular order:

## Contributions

Contributions are extremely welcomed! Take a look at [Extension API](https://code.visualstudio.com/docs/extensionAPI/overview) on how to get started and our current [ssues](https://github.com/VSCodeVim/Vim/issues) to see what we are working on next.
Contributions are extremely welcomed!
Take a look at [Extension API](https://code.visualstudio.com/docs/extensionAPI/overview) on how to get started and our current [issues](https://github.com/VSCodeVim/Vim/issues) to see what we are working on next.

### Getting started

1. Install [Visual Studio Code](https://code.visualstudio.com/).
2. Fork the repo.
3. Run `npm install` to install all the dependencies.
4. Create a topic branch.
5. Run tests:
* Ensure tslint passes by running: `gulp`
* Ensure tests pass by running extension tests within Visual Studio Code
5. Squash your commits.
6. Submit your PR

## License

Expand Down
2 changes: 1 addition & 1 deletion extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as cc from './src/cmd_line/lexer';
import ModeHandler from "./src/mode/modeHandler";
import {ModeName} from "./src/mode/mode";

var modeHandler;
var modeHandler : ModeHandler;

// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
Expand Down
96 changes: 96 additions & 0 deletions src/cursor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import * as vscode from "vscode";
import TextEditor from "./textEditor";

export default class Cursor {
private static prevColumn: number = 0;

static move(position: vscode.Position) {
const newSelection = new vscode.Selection(position, position);
vscode.window.activeTextEditor.selection = newSelection;
}

static currentPosition(): vscode.Position {
return vscode.window.activeTextEditor.selection.active;
}

static left() : vscode.Position {
let pos = this.currentPosition();
let column = pos.character;

if (column > 0) {
column--;
}

this.prevColumn = column;
return new vscode.Position(pos.line, column);
}

static right() : vscode.Position {
let pos = this.currentPosition();
let column = pos.character;

if (column < TextEditor.ReadLine(pos.line).length) {
column++;
}

this.prevColumn = column;
return new vscode.Position(pos.line, column);
}

static down() : vscode.Position {
let pos = this.currentPosition();
let line = pos.line;
let column = this.prevColumn;

if (!Cursor.isLastLine(line)) {
let nextLineMaxColumn = TextEditor.ReadLine(++line).length - 1;

if (nextLineMaxColumn < 0) {
nextLineMaxColumn = 0;
}

if (nextLineMaxColumn < this.prevColumn) {
column = nextLineMaxColumn;
}
}

return new vscode.Position(line, column);
}

static up() : vscode.Position {
let pos = this.currentPosition();
let line = pos.line;
let column = this.prevColumn;

if (line !== 0) {
let nextLineMaxColumn = TextEditor.ReadLine(--line).length - 1;

if (nextLineMaxColumn < 0) {
nextLineMaxColumn = 0;
}

if (nextLineMaxColumn < this.prevColumn) {
column = nextLineMaxColumn;
}
}

return new vscode.Position(line, column);
}

static lineBegin() : vscode.Position {
let pos = this.currentPosition();
return new vscode.Position(pos.line, 0);
}

static lineEnd() : vscode.Position {
let pos = this.currentPosition();
const lineLength = TextEditor.ReadLine(pos.line).length;

return new vscode.Position(pos.line, lineLength);
}

private static isLastLine(line: number): boolean {
return (vscode.window.activeTextEditor.document.lineCount + 1) === line;
}
}

23 changes: 12 additions & 11 deletions src/mode/modeInsert.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
import * as vscode from 'vscode';
import {ModeName, Mode} from './mode';
import TextEditor from './../textEditor';
import Cursor from './../cursor';

export default class InsertMode extends Mode {
private activationKeyHandler : { [ key : string] : (position : vscode.Position) => vscode.Position; } = {};
private activationKeyHandler : { [ key : string] : () => vscode.Position; } = {};

constructor() {
super(ModeName.Insert);

this.activationKeyHandler = {
// insert at cursor
"i" : (position) => { return position; },
"i" : () => { return Cursor.currentPosition(); },

// insert at the beginning of the line
"I" : (position) => { return new vscode.Position(position.line, 0); },
"I" : () => { return Cursor.lineEnd(); },

// append after the cursor
"a" : (position) => { return new vscode.Position(position.line, position.character + 1); },
"a" : () => { return Cursor.right(); },

// append at the end of the line
"A" : (position) => { return TextEditor.GetEndOfLine(position); },
"A" : () => { return Cursor.lineEnd(); },

// open blank line below current line
"o" : (position) => {
"o" : () => {
vscode.commands.executeCommand("editor.action.insertLineAfter");
return new vscode.Position(position.line + 1, 0);
return Cursor.down();
},

// open blank line above current line
"O" : (position) => {
"O" : () => {
vscode.commands.executeCommand("editor.action.insertLineBefore");
return new vscode.Position(position.line, 0);
return Cursor.up();
}
};
}
Expand All @@ -40,8 +41,8 @@ export default class InsertMode extends Mode {
}

HandleActivation(key : string) : void {
var newPosition = this.activationKeyHandler[key](TextEditor.GetCurrentPosition());
TextEditor.SetCurrentPosition(newPosition);
var newPosition = this.activationKeyHandler[key]();
Cursor.move(newPosition);
}

HandleKeyEvent(key : string) : void {
Expand Down
102 changes: 48 additions & 54 deletions src/mode/modeNormal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,66 +2,60 @@ import * as _ from 'lodash';
import * as vscode from 'vscode';
import {ModeName, Mode} from './mode';
import {showCmdLine} from './../cmd_line/main';
import TextEditor from './../textEditor';
import Cursor from './../cursor';

export default class CommandMode extends Mode {
private keyHandler : { [key : string] : () => void; } = {};
private keyHandler : { [key : string] : () => void; } = {};

constructor() {
super(ModeName.Normal);
constructor() {
super(ModeName.Normal);

this.keyHandler = {
":" : () => { showCmdLine(); },
"u" : () => { vscode.commands.executeCommand("undo"); },
"ctrl+r" : () => { vscode.commands.executeCommand("redo"); },
"h" : () => { TextEditor.CursorLeft(); },
"j" : () => { TextEditor.CursorDown(); },
"k" : () => { TextEditor.CursorUp(); },
"l" : () => { TextEditor.CursorRight(); },
"w" : () => { vscode.commands.executeCommand("cursorWordRight"); },
"b" : () => { vscode.commands.executeCommand("cursorWordLeft"); },
">>" : () => { vscode.commands.executeCommand("editor.action.indentLines"); },
"<<" : () => { vscode.commands.executeCommand("editor.action.outdentLines"); },
"dd" : () => { vscode.commands.executeCommand("editor.action.deleteLines"); },
"dw" : () => { vscode.commands.executeCommand("deleteWordRight"); },
"db" : () => { vscode.commands.executeCommand("deleteWordLeft"); },
"esc": () => { vscode.commands.executeCommand("workbench.action.closeMessages"); }
};
}
this.keyHandler = {
":" : () => { showCmdLine(); },
"u" : () => { vscode.commands.executeCommand("undo"); },
"ctrl+r" : () => { vscode.commands.executeCommand("redo"); },
"h" : () => { Cursor.move(Cursor.left()); },
"j" : () => { Cursor.move(Cursor.down()); },
"k" : () => { Cursor.move(Cursor.up()); },
"l" : () => { Cursor.move(Cursor.right()); },
"w" : () => { vscode.commands.executeCommand("cursorWordRight"); },
"b" : () => { vscode.commands.executeCommand("cursorWordLeft"); },
">>" : () => { vscode.commands.executeCommand("editor.action.indentLines"); },
"<<" : () => { vscode.commands.executeCommand("editor.action.outdentLines"); },
"dd" : () => { vscode.commands.executeCommand("editor.action.deleteLines"); },
"dw" : () => { vscode.commands.executeCommand("deleteWordRight"); },
"db" : () => { vscode.commands.executeCommand("deleteWordLeft"); },
"esc": () => { vscode.commands.executeCommand("workbench.action.closeMessages"); }
};
}

ShouldBeActivated(key : string, currentMode : ModeName) : boolean {
if (key === 'esc' || key === 'ctrl+[') {
TextEditor.CursorLeft();
return true;
}
}
ShouldBeActivated(key : string, currentMode : ModeName) : boolean {
if (key === 'esc' || key === 'ctrl+[') {
Cursor.move(Cursor.left());
return true;
}
}

HandleActivation(key : string) : void {
// do nothing
}
HandleActivation(key : string) : void {
// do nothing
}

HandleKeyEvent(key : string) : void {
this.keyHistory.push(key);
HandleKeyEvent(key : string) : void {
this.keyHistory.push(key);

let keyHandled = false;

let keysPressed = this.keyHistory.join('');
if (this.keyHandler[keysPressed] !== undefined) {
keyHandled = true;
this.keyHandler[keysPressed]();
} else {
for (let window = 1; window <= this.keyHistory.length; window++) {
keysPressed = _.takeRight(this.keyHistory, window).join('');
if (this.keyHandler[keysPressed] !== undefined) {
keyHandled = true;
this.keyHandler[keysPressed]();
break;
}
}
}

if (keyHandled) {
this.keyHistory = [];
}
}
let keyHandled = false;

for (let window = this.keyHistory.length; window > 0; window--) {
let keysPressed = _.takeRight(this.keyHistory, window).join('');
if (this.keyHandler[keysPressed] !== undefined) {
keyHandled = true;
this.keyHandler[keysPressed]();
break;
}
}

if (keyHandled) {
this.keyHistory = [];
}
}
}
Loading