Skip to content

Commit 3d27eee

Browse files
committed
readline: allow tabs in input
If tab completion is not being used, allow user to enter tab characters.
1 parent 1baba05 commit 3d27eee

File tree

2 files changed

+68
-13
lines changed

2 files changed

+68
-13
lines changed

lib/readline.js

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,7 @@ function Interface(input, output, completer, terminal) {
4747
}
4848
historySize = historySize || kHistorySize;
4949

50-
completer = completer || function() { return []; };
51-
52-
if (typeof completer !== 'function') {
50+
if (completer && typeof completer !== 'function') {
5351
throw new TypeError('Argument \'completer\' must be a function');
5452
}
5553

@@ -72,9 +70,12 @@ function Interface(input, output, completer, terminal) {
7270
this.historySize = historySize;
7371

7472
// Check arity, 2 - for async, 1 for sync
75-
this.completer = completer.length === 2 ? completer : function(v, callback) {
76-
callback(null, completer(v));
77-
};
73+
if (typeof completer === 'function') {
74+
this.completer = completer.length === 2 ?
75+
completer : function(v, callback) {
76+
callback(null, completer(v));
77+
};
78+
}
7879

7980
this.setPrompt('> ');
8081

@@ -344,9 +345,6 @@ Interface.prototype._normalWrite = function(b) {
344345
};
345346

346347
Interface.prototype._insertString = function(c) {
347-
//BUG: Problem when adding tabs with following content.
348-
// Perhaps the bug is in _refreshLine(). Not sure.
349-
// A hack would be to insert spaces instead of literal '\t'.
350348
if (this.cursor < this.line.length) {
351349
var beg = this.line.slice(0, this.cursor);
352350
var end = this.line.slice(this.cursor, this.line.length);
@@ -839,10 +837,6 @@ Interface.prototype._ttyWrite = function(s, key) {
839837
this._deleteRight();
840838
break;
841839

842-
case 'tab': // tab completion
843-
this._tabComplete();
844-
break;
845-
846840
case 'left':
847841
this._moveCursor(-1);
848842
break;
@@ -867,6 +861,14 @@ Interface.prototype._ttyWrite = function(s, key) {
867861
this._historyNext();
868862
break;
869863

864+
case 'tab':
865+
// If tab completion enabled, do that...
866+
if (typeof this.completer === 'function') {
867+
this._tabComplete();
868+
break;
869+
}
870+
// falls through
871+
870872
default:
871873
if (s instanceof Buffer)
872874
s = s.toString('utf-8');

test/parallel/test-readline-interface.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,59 @@ function isWarned(emitter) {
175175
assert.equal(callCount, expectedLines.length);
176176
rli.close();
177177

178+
// \t when there is no completer function should behave like an ordinary
179+
// character
180+
fi = new FakeInput();
181+
rli = new readline.Interface({ input: fi, output: fi, terminal: true });
182+
called = false;
183+
rli.on('line', function(line) {
184+
assert.equal(line, '\t');
185+
assert.strictEqual(called, false);
186+
called = true;
187+
});
188+
fi.emit('data', '\t');
189+
fi.emit('data', '\n');
190+
assert.ok(called);
191+
rli.close();
192+
193+
// \t does not become part of the input when there is a completer function
194+
fi = new FakeInput();
195+
var completer = function(line) {
196+
return [[], line];
197+
};
198+
rli = new readline.Interface({
199+
input: fi,
200+
output: fi,
201+
terminal: true,
202+
completer: completer
203+
});
204+
called = false;
205+
rli.on('line', function(line) {
206+
assert.equal(line, 'foo');
207+
assert.strictEqual(called, false);
208+
called = true;
209+
});
210+
fi.emit('data', '\tfo\to\t');
211+
fi.emit('data', '\n');
212+
assert.ok(called);
213+
rli.close();
214+
215+
// constructor throws if completer is not a function or undefined
216+
fi = new FakeInput();
217+
assert.throws(function() {
218+
readline.createInterface({
219+
input: fi,
220+
completer: 'string is not valid'
221+
});
222+
}, function(err) {
223+
if (err instanceof TypeError) {
224+
if (/Argument \'completer\' must be a function/.test(err)) {
225+
return true;
226+
}
227+
}
228+
return false;
229+
});
230+
178231
// sending a multi-byte utf8 char over multiple writes
179232
var buf = Buffer('☮', 'utf8');
180233
fi = new FakeInput();

0 commit comments

Comments
 (0)