diff --git a/lib/readline.js b/lib/readline.js index e8f4d542d52..b04b354ea82 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -15,7 +15,6 @@ var EventEmitter = require('events').EventEmitter; var stdio = process.binding('stdio'); - exports.createInterface = function (output, completer) { return new Interface(output, completer); }; @@ -347,10 +346,37 @@ Interface.prototype._ttyWrite = function (b) { return; case 27: /* escape sequence */ + var next_word, next_non_word, previous_word, previous_non_word; if (b[1] === 98 && this.cursor > 0) { // meta-b - backward word - + previous_word = this.line.slice(0, this.cursor) + .split('').reverse().join('') + .search(/\w/); + if (previous_word !== -1) { + previous_non_word = this.line.slice(0, this.cursor - previous_word) + .split('').reverse().join('') + .search(/\W/); + if (previous_non_word !== -1) { + this.cursor -= previous_word + previous_non_word; + this._refreshLine(); + break; + } + } + this.cursor = 0; + this._refreshLine(); } else if (b[1] === 102 && this.cursor < this.line.length) { // meta-f - forward word - + next_word = this.line.slice(this.cursor, this.line.length) + .search(/\w/); + if (next_word !== -1) { + next_non_word = this.line.slice(this.cursor + next_word, this.line.length) + .search(/\W/); + if (next_non_word !== -1) { + this.cursor += next_word + next_non_word; + this._refreshLine(); + break; + } + } + this.cursor = this.line.length; + this._refreshLine(); } else if (b[1] === 91 && b[2] === 68) { // left arrow if (this.cursor > 0) { this.cursor--; diff --git a/test/simple/test-readline.js b/test/simple/test-readline.js index af1b73cc0dd..a551ac209f1 100644 --- a/test/simple/test-readline.js +++ b/test/simple/test-readline.js @@ -5,7 +5,9 @@ var readline = require("readline"); var key = { xterm: { home: [27, 91, 72], - end: [27, 91, 70] + end: [27, 91, 70], + metab: [27, 98], + metaf: [27, 102] }, gnome: { home: [27, 79, 72], @@ -17,15 +19,21 @@ var key = { } }; -var fakestream = { - fd: 1, - write: function(bytes) { - } +var readlineFakeStream = function() { + var written_bytes = []; + var rl = readline.createInterface({ + fd: 1, + write: function(b) { + written_bytes.push(b); + }}, function (text) { + return [[], ""]; + }); + rl.written_bytes = written_bytes; + return rl; }; -var rl = readline.createInterface(fakestream, function (text) { - return [[], ""]; -}); +var rl = readlineFakeStream(); +var written_bytes_length, refreshed; rl.write('foo'); assert.equal(3, rl.cursor); @@ -41,3 +49,35 @@ rl.write(key.gnome.home); assert.equal(0, rl.cursor); rl.write(key.gnome.end); assert.equal(3, rl.cursor); + +rl = readlineFakeStream(); +rl.write('foo bar.hop/zoo'); +rl.write(key.xterm.home); +written_bytes_length = rl.written_bytes.length; +rl.write(key.xterm.metaf); +assert.equal(3, rl.cursor); +refreshed = written_bytes_length !== rl.written_bytes.length; +assert.equal(true, refreshed); +rl.write(key.xterm.metaf); +assert.equal(7, rl.cursor); +rl.write(key.xterm.metaf); +assert.equal(11, rl.cursor); +written_bytes_length = rl.written_bytes.length; +rl.write(key.xterm.metaf); +assert.equal(15, rl.cursor); +refreshed = written_bytes_length !== rl.written_bytes.length; +assert.equal(true, refreshed); +written_bytes_length = rl.written_bytes.length; +rl.write(key.xterm.metab); +assert.equal(12, rl.cursor); +refreshed = written_bytes_length !== rl.written_bytes.length; +assert.equal(true, refreshed); +rl.write(key.xterm.metab); +assert.equal(8, rl.cursor); +rl.write(key.xterm.metab); +assert.equal(4, rl.cursor); +written_bytes_length = rl.written_bytes.length; +rl.write(key.xterm.metab); +assert.equal(0, rl.cursor); +refreshed = written_bytes_length !== rl.written_bytes.length; +assert.equal(true, refreshed); \ No newline at end of file