diff --git a/lib/readline.js b/lib/readline.js index 303d5b0f21a..b44d27db544 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -307,6 +307,26 @@ function commonPrefix(strings) { } +Interface.prototype._wordLeft = function() { + if (this.cursor > 0) { + var leading = this.line.slice(0, this.cursor); + var match = leading.match(/([^\w\s]+|\w+|)\s*$/); + this.cursor -= match[0].length; + this._refreshLine(); + } +} + + +Interface.prototype._wordRight = function() { + if (this.cursor < this.line.length) { + var trailing = this.line.slice(this.cursor); + var match = trailing.match(/^(\s+|\W+|\w+)\s*/); + this.cursor += match[0].length; + this._refreshLine(); + } +} + + Interface.prototype._deleteLeft = function() { if (this.cursor > 0 && this.line.length > 0) { this.line = this.line.slice(0, this.cursor - 1) + @@ -325,6 +345,42 @@ Interface.prototype._deleteRight = function() { }; +Interface.prototype._deleteWordLeft = function() { + if (this.cursor > 0) { + var leading = this.line.slice(0, this.cursor); + var match = leading.match(/([^\w\s]+|\w+|)\s*$/); + leading = leading.slice(0, leading.length - match[0].length); + this.line = leading + this.line.slice(this.cursor, this.line.length); + this.cursor = leading.length; + this._refreshLine(); + } +} + + +Interface.prototype._deleteWordRight = function() { + if (this.cursor < this.line.length) { + var trailing = this.line.slice(this.cursor); + var match = trailing.match(/^(\s+|\W+|\w+)\s*/); + this.line = this.line.slice(0, this.cursor) + + trailing.slice(match[0].length); + this._refreshLine(); + } +} + + +Interface.prototype._deleteLineLeft = function() { + this.line = this.line.slice(this.cursor); + this.cursor = 0; + this._refreshLine(); +} + + +Interface.prototype._deleteLineRight = function() { + this.line = this.line.slice(0, this.cursor); + this._refreshLine(); +} + + Interface.prototype._line = function() { var line = this._addHistory(); this.output.write('\r\n'); @@ -374,7 +430,19 @@ Interface.prototype._ttyWrite = function(s, key) { var next_word, next_non_word, previous_word, previous_non_word; key = key || {}; - if (key.ctrl) { + if (key.ctrl && key.shift) { + /* Control and shift pressed */ + switch (key.name) { + case "backspace": + this._deleteLineLeft(); + break; + + case "delete": + this._deleteLineRight(); + break; + } + + } else if (key.ctrl) { /* Control key pressed */ switch (key.name) { @@ -406,8 +474,7 @@ Interface.prototype._ttyWrite = function(s, key) { break; case 'k': // delete from current to end of line - this.line = this.line.slice(0, this.cursor); - this._refreshLine(); + this._deleteLineRight(); break; case 'a': // go to the start of the line @@ -438,17 +505,6 @@ Interface.prototype._ttyWrite = function(s, key) { this._historyNext(); break; - case 'w': // delete backwards to a word boundary - if (this.cursor !== 0) { - var leading = this.line.slice(0, this.cursor); - var match = leading.match(/\s?((\W+|\w+)\s*)$/); - leading = leading.slice(0, leading.length - match[1].length); - this.line = leading + this.line.slice(this.cursor, this.line.length); - this.cursor = leading.length; - this._refreshLine(); - } - break; - case 'p': // previous history item this._historyPrev(); break; @@ -456,6 +512,26 @@ Interface.prototype._ttyWrite = function(s, key) { case 'z': process.kill(process.pid, 'SIGTSTP'); return; + + case 'w': // delete backwards to a word boundary + case 'backspace': + this._deleteWordLeft(); + break; + + case 'delete': // delete forward to a word boundary + this._deleteWordRight(); + break; + + case 'backspace': + this._deleteWordLeft(); + break; + + case 'left': + this._wordLeft(); + break; + + case 'right': + this._wordRight(); } } else if (key.meta) { @@ -463,81 +539,21 @@ Interface.prototype._ttyWrite = function(s, key) { switch (key.name) { case 'b': // backward word - if (this.cursor > 0) { - 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(); - } + this._wordLeft(); break; case 'f': // forward word - if (this.cursor < this.line.length) { - 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(); - } + this._wordRight(); break; case 'd': // delete forward word case 'delete': - if (this.cursor < this.line.length) { - 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.line = this.line.slice(this.cursor + - next_word + - next_non_word); - this.cursor = 0; - this._refreshLine(); - break; - } - } - this.line = ''; - this.cursor = 0; - this._refreshLine(); - } + this._deleteWordRight(); break; case 'backspace': // delete backwards to a word boundary - if (this.cursor !== 0) { - var leading = this.line.slice(0, this.cursor); - var match = leading.match(/\s?((\W+|\w+)\s*)$/); - leading = leading.slice(0, leading.length - match[1].length); - this.line = leading + this.line.slice(this.cursor, this.line.length); - this.cursor = leading.length; - this._refreshLine(); - } + this._deleteWordLeft(); break; - } } else {