Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b3164ae

Browse filesBrowse files
diosneycjihrig
authored andcommitted
repl: add support for custom completions
Allow user code to override the default `complete()` function from `readline.Interface`. See: https://nodejs.org/api/readline.html#readline_use_of_the_completer_function Ref: nodejs/node-v0.x-archive#8484 PR-URL: #7527 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Lance Ball <lball@redhat.com>
1 parent c967af8 commit b3164ae
Copy full SHA for b3164ae

File tree

Expand file treeCollapse file tree

3 files changed

+80
-7
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+80
-7
lines changed
Open diff view settings
Collapse file

‎doc/api/repl.md‎

Copy file name to clipboardExpand all lines: doc/api/repl.md
+3Lines changed: 3 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,8 @@ added: v0.1.91
382382
`undefined`. Defaults to `false`.
383383
* `writer` {Function} The function to invoke to format the output of each
384384
command before writing to `output`. Defaults to [`util.inspect()`][].
385+
* `completer` {Function} An optional function used for custom Tab auto
386+
completion. See [`readline.InterfaceCompleter`][] for an example.
385387
* `replMode` - A flag that specifies whether the default evaluator executes
386388
all JavaScript commands in strict mode, default mode, or a hybrid mode
387389
("magic" mode.) Acceptable values are:
@@ -526,3 +528,4 @@ see: https://gist.github.com/2053342
526528
[`util.inspect()`]: util.html#util_util_inspect_object_options
527529
[here]: util.html#util_custom_inspect_function_on_objects
528530
[`readline.Interface`]: readline.html#readline_class_interface
531+
[`readline.InterfaceCompleter`]: readline.html#readline_use_of_the_completer_function
Collapse file

‎lib/repl.js‎

Copy file name to clipboardExpand all lines: lib/repl.js
+11-6Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -386,14 +386,15 @@ function REPLServer(prompt,
386386
self.bufferedCommand = '';
387387
self.lines.level = [];
388388

389-
function complete(text, callback) {
390-
self.complete(text, callback);
391-
}
389+
// Figure out which "complete" function to use.
390+
self.completer = (typeof options.completer === 'function')
391+
? options.completer
392+
: complete;
392393

393394
Interface.call(this, {
394395
input: self.inputStream,
395396
output: self.outputStream,
396-
completer: complete,
397+
completer: self.completer,
397398
terminal: options.terminal,
398399
historySize: options.historySize,
399400
prompt
@@ -706,6 +707,10 @@ function filteredOwnPropertyNames(obj) {
706707
return Object.getOwnPropertyNames(obj).filter(intFilter);
707708
}
708709

710+
REPLServer.prototype.complete = function() {
711+
this.completer.apply(this, arguments);
712+
};
713+
709714
// Provide a list of completions for the given leading text. This is
710715
// given to the readline interface for handling tab completion.
711716
//
@@ -716,7 +721,7 @@ function filteredOwnPropertyNames(obj) {
716721
//
717722
// Warning: This eval's code like "foo.bar.baz", so it will run property
718723
// getter code.
719-
REPLServer.prototype.complete = function(line, callback) {
724+
function complete(line, callback) {
720725
// There may be local variables to evaluate, try a nested REPL
721726
if (this.bufferedCommand !== undefined && this.bufferedCommand.length) {
722727
// Get a new array of inputed lines
@@ -975,7 +980,7 @@ REPLServer.prototype.complete = function(line, callback) {
975980

976981
callback(null, [completions || [], completeOn]);
977982
}
978-
};
983+
}
979984

980985

981986
/**
Collapse file

‎test/parallel/test-repl-tab-complete.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-repl-tab-complete.js
+66-1Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ testMe.complete('console.lo', common.mustCall(function(error, data) {
3232
assert.deepStrictEqual(data, [['console.log'], 'console.lo']);
3333
}));
3434

35-
// Tab Complete will return globaly scoped variables
35+
// Tab Complete will return globally scoped variables
3636
putIn.run(['};']);
3737
testMe.complete('inner.o', common.mustCall(function(error, data) {
3838
assert.deepStrictEqual(data, works);
@@ -283,3 +283,68 @@ if (typeof Intl === 'object') {
283283
testNonGlobal.complete('I', common.mustCall((error, data) => {
284284
assert.deepStrictEqual(data, builtins);
285285
}));
286+
287+
// To test custom completer function.
288+
// Sync mode.
289+
const customCompletions = 'aaa aa1 aa2 bbb bb1 bb2 bb3 ccc ddd eee'.split(' ');
290+
const testCustomCompleterSyncMode = repl.start({
291+
prompt: '',
292+
input: putIn,
293+
output: putIn,
294+
completer: function completerSyncMode(line) {
295+
const hits = customCompletions.filter((c) => {
296+
return c.indexOf(line) === 0;
297+
});
298+
// Show all completions if none found.
299+
return [hits.length ? hits : customCompletions, line];
300+
}
301+
});
302+
303+
// On empty line should output all the custom completions
304+
// without complete anything.
305+
testCustomCompleterSyncMode.complete('', common.mustCall((error, data) => {
306+
assert.deepStrictEqual(data, [
307+
customCompletions,
308+
''
309+
]);
310+
}));
311+
312+
// On `a` should output `aaa aa1 aa2` and complete until `aa`.
313+
testCustomCompleterSyncMode.complete('a', common.mustCall((error, data) => {
314+
assert.deepStrictEqual(data, [
315+
'aaa aa1 aa2'.split(' '),
316+
'a'
317+
]);
318+
}));
319+
320+
// To test custom completer function.
321+
// Async mode.
322+
const testCustomCompleterAsyncMode = repl.start({
323+
prompt: '',
324+
input: putIn,
325+
output: putIn,
326+
completer: function completerAsyncMode(line, callback) {
327+
const hits = customCompletions.filter((c) => {
328+
return c.indexOf(line) === 0;
329+
});
330+
// Show all completions if none found.
331+
callback(null, [hits.length ? hits : customCompletions, line]);
332+
}
333+
});
334+
335+
// On empty line should output all the custom completions
336+
// without complete anything.
337+
testCustomCompleterAsyncMode.complete('', common.mustCall((error, data) => {
338+
assert.deepStrictEqual(data, [
339+
customCompletions,
340+
''
341+
]);
342+
}));
343+
344+
// On `a` should output `aaa aa1 aa2` and complete until `aa`.
345+
testCustomCompleterAsyncMode.complete('a', common.mustCall((error, data) => {
346+
assert.deepStrictEqual(data, [
347+
'aaa aa1 aa2'.split(' '),
348+
'a'
349+
]);
350+
}));

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.