diff --git a/css/base.css b/css/base.css index b05e8c3..54468b1 100644 --- a/css/base.css +++ b/css/base.css @@ -3,6 +3,10 @@ margin: 20px auto; font-family: 'Arial', sans-serif; } +.vimulator input { + position: absolute; + left: -9999px; +} .vimulator pre { position: relative; z-index: 2; diff --git a/js/base.js b/js/base.js index 49435bf..8c65891 100644 --- a/js/base.js +++ b/js/base.js @@ -36,9 +36,15 @@ Vimulator.Base.prototype.bindKeyListeners = function () { var vim = this; + this.input = $('').appendTo(this.container) + .focus() + .blur(function () { + $(this).focus(); + }); + // Use keyup for special characters like escape $(window).keyup(function (e) { - if (e.keyCode === 27) { + if (e.keyCode < 32) { vim.keyPress(e.keyCode); return false; } @@ -136,13 +142,35 @@ return this.lines[this.cursor.row]; }; - Vimulator.Base.prototype.appendText = function (text) { - line = this.currentLine(); - this.lines[this.cursor.row] = - line.substr(0, this.cursor.col) + - text + - line.substr(this.cursor.col); - this.cursor.col += text.length; + Vimulator.Base.prototype.appendChr = function (chr) { + var line; + + if (chr === Vimulator.Utils.Keys.BACKSPACE) { + this.removeChr(); + } else { + line = this.currentLine(); + this.lines[this.cursor.row] = + line.substr(0, this.cursor.col) + + chr + + line.substr(this.cursor.col); + this.cursor.col += 1; + } + }; + + Vimulator.Base.prototype.removeChr = function () { + var line = this.currentLine(); + + if (this.cursor.col === 0 && this.cursor.row > 0) { + this.moveCursorRelative(-1, '$'); + this.cursor.col += 1; //FIXME + this.lines[this.cursor.row] += line; + this.removeRows(this.cursor.row + 1, this.cursor.row + 2); + } else if (this.cursor.col > 0) { + this.lines[this.cursor.row] = + line.substr(0, this.cursor.col - 1) + + line.substr(this.cursor.col); + this.cursor.col -= 1; + } }; Vimulator.Base.prototype.insertRowBelow = function (text, index) { diff --git a/js/insert_mode.js b/js/insert_mode.js index b6848cd..68ad7eb 100644 --- a/js/insert_mode.js +++ b/js/insert_mode.js @@ -28,7 +28,7 @@ return op; } else { this.vim.registers["."] += key; - this.vim.appendText(key); + this.vim.appendChr(key); } }; }()); diff --git a/js/utils.js b/js/utils.js index cf6313e..903bc7a 100644 --- a/js/utils.js +++ b/js/utils.js @@ -4,8 +4,9 @@ Vimulator.Utils = {}; Vimulator.Utils.Keys = K = { - ESC: '\u001B', - RETURN: '\u000D' + BACKSPACE: '\u0008', + RETURN: '\u000D', + ESC: '\u001B' }; Vimulator.Utils.pluralize = function (count, word) { diff --git a/tests/acceptance/insertion.js b/tests/acceptance/insertion.js index d1237c1..222fe6d 100644 --- a/tests/acceptance/insertion.js +++ b/tests/acceptance/insertion.js @@ -95,3 +95,26 @@ describe("Substituting lines with S", function () { expect(currentText()).toBe("1 and 2\nThird\nFourth"); }); }); + +describe("Deleting characters with backspace", function () { + it("deletes a character before the cursor", function () { + reset("Hello world!!1"); + pressKeys("A" + BACKSPACE + BACKSPACE + ESC); + expect(currentText()).toBe("Hello world!"); + expect(cursorPosition()).toEqual({row: 0, col: 11}); + }); + + it("deletes line breaks", function () { + reset("First line\nSecond line\nThird line"); + pressKeys("ja" + BACKSPACE + BACKSPACE + ESC); + expect(currentText()).toBe("First lineecond line\nThird line"); + expect(cursorPosition()).toEqual({row: 0, col: 9}); + }); + + it("does not delete beyond the end of the document", function () { + reset("Hello world"); + pressKeys("gI" + BACKSPACE + BACKSPACE + ESC); + expect(currentText()).toBe("Hello world"); + expect(cursorPosition()).toEqual({row: 0, col: 0}); + }); +}); diff --git a/tests/acceptance/repeat.js b/tests/acceptance/repeat.js index 3d54bf1..4725b76 100644 --- a/tests/acceptance/repeat.js +++ b/tests/acceptance/repeat.js @@ -23,6 +23,11 @@ describe("Repeating the last command with .", function () { expect(currentText()).toBe("Here ore some words, they ore all here"); }); + it("repeats backspaces", function () { + pressKeys("ea" + BACKSPACE + ESC + "e.e."); + expect(currentText()).toBe("Her ar som words, they are all here"); + }); + it("does not repeat motions", function () { pressKeys("3l"); expect(cursorPosition()).toEqual({row: 0, col: 3}); diff --git a/tests/helpers.js b/tests/helpers.js index 6488910..db89777 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -1,5 +1,6 @@ ESC = '\u001B'; RETURN = '\u000D'; +BACKSPACE = '\u0008'; function pressKeys(keys) { jQuery.each(keys.split(''), function (i, key) { diff --git a/tests/unit/insert_mode.js b/tests/unit/insert_mode.js index a1c103e..b22f03f 100644 --- a/tests/unit/insert_mode.js +++ b/tests/unit/insert_mode.js @@ -13,7 +13,7 @@ describe("InsertMode", function () { vim = jasmine.createSpyObj("vim", [ "moveCursorRelative", "setMode", - "appendText" + "appendChr" ]); vim.registers = {}; im = new Vimulator.InsertMode(vim); @@ -33,7 +33,7 @@ describe("InsertMode", function () { for (i = 0; i < chars.length; i +=1) { chr = chars[i]; im.keyPress(chr); - expect(vim.appendText).toHaveBeenCalledWith(chr); + expect(vim.appendChr).toHaveBeenCalledWith(chr); } });