I'm making a simple CLI app with NodeJS using the Readline module. I want to autocomplete the user's input. For this, I'm using the autocompletion function of the module:
function completer(line) {
const completions = '.help .error .exit .quit .q'.split(' ');
const hits = completions.filter((c) => c.startsWith(line));
// show all completions if none found
return [hits.length ? hits : completions, line];
}
With this function, I'm able to complete one command but no several commands in the same line:
For example:
(CLI App) > .e<tab>
.error .exit
(CLI App) > .err<tab>
(CLI App) > .error
(CLI App) > .error .ex<tab>
.help .error .exit .quit .q
I modified the completer function to get only the autocompletion's suggestions of the current command that the user is writing:
function completer(line) {
const completions = '.help .error .exit .quit .q'.split(' ');
const hits = completions.filter((c) => c.startsWith(line.split(' ').slice(-1)));
return [hits.length ? hits : completions, line];
}
and I get the correct suggestions but the user input doesn't change:
(CLI App) > .e<tab>
.error .exit
(CLI App) > .err<tab>
(CLI App) > .error
(CLI App) > .error .ex<tab>
.exit
(CLI App) > .error .ex
Is there any way to solve this? Any assistance you can give would be very appreciated.
Thanks.
Using the Chris's tip I got a solution: replace the last part of the line
with the hit (when I only have one).
I calculate the length of the last part of the line
(the actual command that I want to autocomplete) to move the cursor to the begin of this command. Then, I get all the line minus the current command and I concat the hit. Finally, I set the cursor at the end of the line.
I tried to use methods from the docs without luck: readline.cursorTo(stream, x, y)
and readline.moveCursor(stream, dx, dy)
don't work for me.
Thereadline.clearLine(stream, dir)
method clear all the line and no 'to the right from cursor' (the behaviour that I want), despite of it's present in the doc.
function completer(line) {
const completions = '.help .error .exit .quit .q'.split(' ');
let cmds = line.split(' ');
const hits = completions.filter((c) => c.startsWith(cmds.slice(-1)));
if ((cmds.length > 1) && (hits.length === 1)) {
let lastCmd = cmds.slice(-1)[0];
let pos = lastCmd.length;
rl.line = line.slice(0, -pos).concat(hits[0]);
rl.cursor = rl.line.length + 1;
}
return [hits.length ? hits.sort() : completions.sort(), line];
}