Browse Source

Readline: use symbolic key names instead of ascii control codes

v0.7.4-release
Bert Belder 14 years ago
committed by Ryan Dahl
parent
commit
4475b76535
  1. 4
      lib/_debugger.js
  2. 192
      lib/readline.js
  3. 4
      lib/repl.js

4
lib/_debugger.js

@ -578,8 +578,8 @@ function Interface() {
}); });
this.stdin = process.openStdin(); this.stdin = process.openStdin();
this.stdin.addListener('data', function(chunk) { this.stdin.addListener('keypress', function(s, key) {
term.write(chunk); term.write(s, key);
}); });
term.setPrompt('debug> '); term.setPrompt('debug> ');

192
lib/readline.js

@ -177,15 +177,16 @@ Interface.prototype.resume = function() {
}; };
Interface.prototype.write = function(d) { Interface.prototype.write = function(d, key) {
if (this._closed) return; if (this._closed) return;
return this.enabled ? this._ttyWrite(d) : this._normalWrite(d); this.enabled ? this._ttyWrite(d, key) : this._normalWrite(d, key);
}; };
Interface.prototype._normalWrite = function(b) { Interface.prototype._normalWrite = function(b) {
// Very simple implementation right now. Should try to break on // Very simple implementation right now. Should try to break on
// new lines. // new lines.
if (b !== undefined)
this._onLine(b.toString()); this._onLine(b.toString());
}; };
@ -288,6 +289,28 @@ function commonPrefix(strings) {
return min; return min;
} }
Interface.prototype._deleteLeft = function() {
if (this.cursor > 0 && this.line.length > 0) {
this.line = this.line.slice(0, this.cursor - 1) +
this.line.slice(this.cursor, this.line.length);
this.cursor--;
this._refreshLine();
}
};
Interface.prototype._deleteRight = function() {
this.line = this.line.slice(0, this.cursor) +
this.line.slice(this.cursor + 1, this.line.length);
this._refreshLine();
}
Interface.prototype._line = function() {
var line = this._addHistory();
this.output.write('\r\n');
this._onLine(line);
};
Interface.prototype._historyNext = function() { Interface.prototype._historyNext = function() {
if (this.historyIndex > 0) { if (this.historyIndex > 0) {
this.historyIndex--; this.historyIndex--;
@ -325,11 +348,15 @@ Interface.prototype._attemptClose = function() {
// handle a write from the tty // handle a write from the tty
Interface.prototype._ttyWrite = function(b) { Interface.prototype._ttyWrite = function(s, key) {
switch (b[0]) { var next_word, next_non_word, previous_word, previous_non_word;
/* ctrl+c */ key = key || {};
case 3:
//process.kill(process.pid, "SIGINT"); if (key.ctrl) {
/* Control key pressed */
switch (key.name) {
case 'c':
if (this.listeners('SIGINT').length) { if (this.listeners('SIGINT').length) {
this.emit('SIGINT'); this.emit('SIGINT');
} else { } else {
@ -338,74 +365,58 @@ Interface.prototype._ttyWrite = function(b) {
} }
break; break;
case 4: // control-d, delete right or EOF case 'h': // delete left
this._deleteLeft();
break;
case 'd': // delete right or EOF
if (this.cursor === 0 && this.line.length === 0) { if (this.cursor === 0 && this.line.length === 0) {
this._attemptClose(); this._attemptClose();
} else if (this.cursor < this.line.length) { } else if (this.cursor < this.line.length) {
this.line = this.line.slice(0, this.cursor) + this._deleteRight();
this.line.slice(this.cursor + 1, this.line.length);
this._refreshLine();
}
break;
case 13: /* enter */
var line = this._addHistory();
this.output.write('\r\n');
this._onLine(line);
break;
case 127: /* backspace */
case 8: /* ctrl+h */
if (this.cursor > 0 && this.line.length > 0) {
this.line = this.line.slice(0, this.cursor - 1) +
this.line.slice(this.cursor, this.line.length);
this.cursor--;
this._refreshLine();
} }
break; break;
case 21: /* Ctrl+u, delete the whole line. */ case 'u': // delete the whole line
this.cursor = 0; this.cursor = 0;
this.line = ''; this.line = '';
this._refreshLine(); this._refreshLine();
break; break;
case 11: /* Ctrl+k, delete from current to end of line. */ case 'k': // delete from current to end of line
this.line = this.line.slice(0, this.cursor); this.line = this.line.slice(0, this.cursor);
this._refreshLine(); this._refreshLine();
break; break;
case 1: /* Ctrl+a, go to the start of the line */ case 'a': // go to the start of the line
this.cursor = 0; this.cursor = 0;
this._refreshLine(); this._refreshLine();
break; break;
case 5: /* ctrl+e, go to the end of the line */ case 'e': // go to the end of the line
this.cursor = this.line.length; this.cursor = this.line.length;
this._refreshLine(); this._refreshLine();
break; break;
case 2: // control-b, back one character case 'b': // back one character
if (this.cursor > 0) { if (this.cursor > 0) {
this.cursor--; this.cursor--;
this._refreshLine(); this._refreshLine();
} }
break; break;
case 6: // control-f, forward one character case 'f': // forward one character
if (this.cursor != this.line.length) { if (this.cursor != this.line.length) {
this.cursor++; this.cursor++;
this._refreshLine(); this._refreshLine();
} }
break; break;
case 14: // control-n, next history item case 'n': // next history item
this._historyNext(); this._historyNext();
break; break;
case 23: // control-w, delete backwards to a word boundary case 'w': // delete backwards to a word boundary
if (this.cursor !== 0) { if (this.cursor !== 0) {
var leading = this.line.slice(0, this.cursor); var leading = this.line.slice(0, this.cursor);
var match = leading.match(/\s?((\W+|\w+)\s*)$/); var match = leading.match(/\s?((\W+|\w+)\s*)$/);
@ -416,25 +427,21 @@ Interface.prototype._ttyWrite = function(b) {
} }
break; break;
case 9: // tab, completion case 'p': // previous history item
if (this.completer) {
this._tabComplete();
}
break;
case 16: // control-p, previous history item
this._historyPrev(); this._historyPrev();
break; break;
case 26: /* ctrl+z */ case 'z':
process.kill(process.pid, 'SIGTSTP'); process.kill(process.pid, 'SIGTSTP');
return; return;
}
case 27: /* escape sequence */ } else if (key.meta) {
var next_word, next_non_word, previous_word, previous_non_word; /* Meta key pressed */
if (b[1] === 98 && this.cursor > 0) { switch (key.name) {
// meta-b - backward word case 'b': // backward word
if (this.cursor > 0) {
previous_word = this.line.slice(0, this.cursor) previous_word = this.line.slice(0, this.cursor)
.split('').reverse().join('') .split('').reverse().join('')
.search(/\w/); .search(/\w/);
@ -450,9 +457,11 @@ Interface.prototype._ttyWrite = function(b) {
} }
this.cursor = 0; this.cursor = 0;
this._refreshLine(); this._refreshLine();
}
break;
} else if (b[1] === 102 && this.cursor < this.line.length) { case 'f': // forward word
// meta-f - forward word if (this.cursor < this.line.length) {
next_word = this.line.slice(this.cursor, this.line.length).search(/\w/); next_word = this.line.slice(this.cursor, this.line.length).search(/\w/);
if (next_word !== -1) { if (next_word !== -1) {
next_non_word = this.line.slice(this.cursor + next_word, next_non_word = this.line.slice(this.cursor + next_word,
@ -465,9 +474,11 @@ Interface.prototype._ttyWrite = function(b) {
} }
this.cursor = this.line.length; this.cursor = this.line.length;
this._refreshLine(); this._refreshLine();
}
break;
} else if (b[1] === 100 && this.cursor < this.line.length) { case 'd': // delete forward word
// meta-d delete forward word if (this.cursor < this.line.length) {
next_word = this.line.slice(this.cursor, this.line.length).search(/\w/); next_word = this.line.slice(this.cursor, this.line.length).search(/\w/);
if (next_word !== -1) { if (next_word !== -1) {
next_non_word = this.line.slice(this.cursor + next_word, next_non_word = this.line.slice(this.cursor + next_word,
@ -484,63 +495,78 @@ Interface.prototype._ttyWrite = function(b) {
this.line = ''; this.line = '';
this.cursor = 0; this.cursor = 0;
this._refreshLine(); this._refreshLine();
}
break;
}
} else {
/* No modifier keys used */
switch (key.name) {
case 'enter':
this._line();
break;
case 'backspace':
this._deleteLeft();
break;
case 'delete':
this._deleteRight();
break;
case 'tab': // tab completion
if (this.completer) {
this._tabComplete();
}
break;
} else if (b[1] === 91 && b[2] === 68) { case 'left':
// left arrow
if (this.cursor > 0) { if (this.cursor > 0) {
this.cursor--; this.cursor--;
this.output.moveCursor(-1, 0); this.output.moveCursor(-1, 0);
} }
break;
} else if (b[1] === 91 && b[2] === 67) { case 'right':
// right arrow
if (this.cursor != this.line.length) { if (this.cursor != this.line.length) {
this.cursor++; this.cursor++;
this.output.moveCursor(1, 0); this.output.moveCursor(1, 0);
} }
break;
} else if ((b[1] === 91 && b[2] === 72) || case 'home':
(b[1] === 79 && b[2] === 72) ||
(b[1] === 91 && b[2] === 55) ||
(b[1] === 91 && b[2] === 49 && (b[3] && b[3] === 126))) {
// home
this.cursor = 0; this.cursor = 0;
this._refreshLine(); this._refreshLine();
} else if ((b[1] === 91 && b[2] === 70) || break;
(b[1] === 79 && b[2] === 70) ||
(b[1] === 91 && b[2] === 56) || case 'end':
(b[1] === 91 && b[2] === 52 && (b[3] && b[3] === 126))) {
// end
this.cursor = this.line.length; this.cursor = this.line.length;
this._refreshLine(); this._refreshLine();
break;
} else if (b[1] === 91 && b[2] === 65) { case 'up':
// up arrow
this._historyPrev(); this._historyPrev();
break;
} else if (b[1] === 91 && b[2] === 66) { case 'down':
// down arrow
this._historyNext(); this._historyNext();
} else if (b[1] === 91 && b[2] === 51 && this.cursor < this.line.length) {
// delete right
this.line = this.line.slice(0, this.cursor) +
this.line.slice(this.cursor + 1, this.line.length);
this._refreshLine();
}
break; break;
default: default:
var c = b.toString('utf8'); if (Buffer.isBuffer(s))
var lines = c.split(/\r\n|\n|\r/); s = s.toString('utf-8');
if (s) {
var lines = s.split(/\r\n|\n|\r/);
for (var i = 0, len = lines.length; i < len; i++) { for (var i = 0, len = lines.length; i < len; i++) {
if (i > 0) { if (i > 0) {
this._ttyWrite(new Buffer([13])); this._line();
} }
this._insertString(lines[i]); this._insertString(lines[i]);
} }
break; }
}
} }
}; };

4
lib/repl.js

@ -90,8 +90,8 @@ function REPLServer(prompt, stream) {
} }
}); });
self.inputStream.addListener('data', function(chunk) { self.inputStream.addListener('keypress', function(s, key) {
rli.write(chunk); rli.write(s, key);
}); });
rli.addListener('line', function(cmd) { rli.addListener('line', function(cmd) {

Loading…
Cancel
Save