Is it possible to push text to prompt input? - node.js

I am using the prompt module, node version 12.4.0
I am wondering if its possible to push a string to the 'input field' of a prompt.get()
The following script displays a (double) "prompt: "
After 5 seconds, it inserts the text "This is a test"
When an enter command is given, the string is not recognized as input.
It isn't possible to edit the string before pressing enter either.
(type anything before 5 sec and press enter, and the input WILL display)
End-goal: to have commands send to prompt from external source, but give the end user the ability to modify the commands before entering.
I tried process.stdout.write, process.stdin.write
I also tried to replace process.std*.write with prompt.std*.write
The answer might be os-specific, but I have tried this code both under Win10 x64 as well as Linux
const prompt = require("prompt");
function myFunc() {
process.stdin.write("This is a test");
}
setTimeout(myFunc, 5000);
prompt.get({
properties: {
test: {
description: "prompt"
}
}
}, (err, result)=> {
console.log("input: "+ result.test);
});
actual result:
~/Nodejs/temp$ node index.js
prompt: prompt: This is a test
input:
~/Nodejs/temp$
desired result:
~/Nodejs/temp$ node index.js
prompt: prompt: This is a test
input: This is a test
~/Nodejs/temp$

After digging into how the prompt module works, I 'solved' this myself.
prompt uses readline behind the curtains, and readline has a .write function that does what I need, send editable text to the prompt.
prompt itself does not extend this function, and since it hasnt been maintained for 3 years, I switched to readline instead.
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: 'prompt> '
});
rl.prompt();
rl.on('line', (line) => {
console.log(line);
rl.prompt();
}).on('close', () => {
console.log('Have a great day!');
process.exit(0);
});
// simulate external input, and write to prompt>
function myFunc() {
rl.write("This is a test");
}
setTimeout(myFunc, 5000);

Related

Nodejs Is there a way to kill a process then start it again

So I'm working on a little project and I want something that lets me restart a process Since I start it by requiring the file so like
switch (start) {
case "-dev":
require("./path/to/file")
break;
}
and I want to have a function that when you type rs in the console it will restart it without the user needing to run node . -dev again. So Something like nodemon but not...
I have this but I don't know how to fully do something like it
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
let cmd = function () {
rl.question('', function (answer) {
switch (answer) {
case "rs":
process.exit()
require("./path/to/file")
}
cmd();
});
};
cmd();
but that wouldn't work.. That's why I'm confused
Note: I do not want to use Nodemon
There is a module named child_process on NPM. A function available is spawn. The spawn command is able to run programs and get output from them. The second there is output, it closes. Note that it opens in a new window. Here is my proposed code to restart your application
var cmd = childprocess.spawn("cmd", [ "/k", "start", "cmd", "/k", "node", ".", "-dev"]);
cmd.stdout.on("data", () => {
process.exit()
})
This feels like a clunky solution, but it does work.
More information on the child_process module

Node.js readline module: stop reprinting the line just read

I'm using the readline module in Node (12) to accept user input as such:
import * as readline from "readline";
process.stdin.setEncoding('utf-8');
console.log("input is a TTY?",process.stdin.isTTY);
const rl = readline.createInterface({input: process.stdin, output: process.stdout, prompt: '> '});
rl.prompt();
rl.on('line' ,inputLine => { inputStringLines.push(inputLine); rl.prompt(); });
rl.on('close',() => { console.log('input has closed'); main(); });
The lines are correctly captured into my inputStringLines array but annoyingly, the process is printing out every line just read:
How can I get rid of the extra lines (the ones without the > prompt)
I fixed it by changing how run my script. Before, I used nodemon with node's -r ts-node/register option. The issue went away when I switched to using ts-node-dev to execute the script.
Note also that process.stdin.isTTY is now correctly set whereas it was undefined before (look at the first line in the image below, vs in the original post)
Still don't know the root cause, but I'm happy to move on.

NodeJS: Make it possible for user input when running child_process

I'm trying to create a Node script that will ask the user a few questions, save the input and using the answers run a mvn archetype:generate command to install their environment.
I got as far to where I get the Maven command running. But when Maven asks for user input for values such as groupId and `` I can enter the values, give an [enter] and that's where it stops.
It doesn't take input and process them. All it does is display it, as the CLI does, but doesn't accept them.
Here's a snippet of code with the values for user input pre-filled:
var spawn = require('child_process').spawn;
var answerCollection = {
"name": "nameOfMyArchetype", //answer of inquiry
"version": "1.2.3.4" //answer of inquiry
};
var cmd = "mvn";
var args = [
"archetype:generate",
"-DarchetypeArtifactId=" + answerCollection.name,
"-DarchetypeGroupId=com.backbase.expert.tools",
"-DarchetypeVersion=" + answerCollection.version
];
var runCmd = function(cmd, args, callback) {
var child = spawn(cmd, args);
child.stdin.pipe(process.stdin);
child.stdout.pipe(process.stdout);
child.stdout.on('end', function(res) {
console.log("stdout:end");
callback(res);
});
child.stderr.on('data', function(text) {
console.log("stderr:data");
console.log(data);
});
child.stderr.on('exit', function(data) {
console.log("stderr:exit");
console.log(data);
});
};
So far I've tried the above code with child_process and spawn = require('child_process').spawn('bash').
Question: Is there any other way to make sure I can trigger a script and if that returns with a prompt and asks for input I can type and enter and the script will continue?
From Facebook I got this tip to use cross-spawn, instead of child_process:
From Robert Haritonov:
Use cross-spawn: spawn('bower', bowerCommand, {stdio:'inherit'}).on('close', function () {});
This works perfectly well and provides exactly the behaviour I need.

Prompt module in NodeJS repeating the input

I'm making an application using NodeJS and its a CLI application; to get the input from the user, I'm using the "prompt" module. I can use it, but while typing in the prompt's prompt, each character is getting repeated, however the output is fine! The code is below. Please Help.
prompt.start();
prompt.get({
properties: {
name: {
description: "What is your name?".magenta
}
}
}, function (err, result) {
console.log("You said your name is: ".cyan + result.name.cyan);
});
IMAGE:
Before using the "prompt" module, I used the ReadLine interface; sadly I had the same problem. However, the fix was simple:
Remove the rli.close(); and then run it.
Then re-add the rli.close(); and it works!
Thanks mscdex for the input, though :)
FWIW if you just need simple prompting, you can use the built-in readline module's question() method (which does not exhibit the double output issue). Example:
var readline = require('readline');
var rli = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rli.question('What is your name? ', function(answer) {
console.log('You said your name is: ' + answer);
rli.close();
});

Clear terminal window in Node.js readline shell

I have a simple readline shell written in Coffeescript:
rl = require 'readline'
cli = rl.createInterface process.stdin, process.stdout, null
cli.setPrompt "hello> "
cli.on 'line', (line) ->
console.log line
cli.prompt()
cli.prompt()
Running this displays a prompt:
$ coffee cli.coffee
hello>
I would like to be able to hit Ctrl-L to clear the screen. Is this possible?
I have also noticed that I cannot hit Ctrl-L in either the node or coffee REPLs either.
I am running on Ubuntu 11.04.
You can watch for the keypress yourself and clear the screen.
process.stdin.on 'keypress', (s, key) ->
if key.ctrl && key.name == 'l'
process.stdout.write '\u001B[2J\u001B[0;0f'
Clearing is done with ASCII control sequences like those written here:
http://ascii-table.com/ansi-escape-sequences-vt-100.php
The first code \u001B[2J instructs the terminal to clear itself, and the second one \u001B[0;0f forces the cursor back to position 0,0.
Note
The keypress event is no longer part of the standard Node API in Node >= 0.10.x but you can use the keypress module instead.
In the MAC terminal, to clear the console in NodeJS, you just hit COMMAND+K just like in Google Developer Tools Console so I'm guessing that on Windows it would be CTRL+K.
This is the only answer that will clear the screen AND scroll history.
function clear() {
// 1. Print empty lines until the screen is blank.
process.stdout.write('\033[2J');
// 2. Clear the scrollback.
process.stdout.write('\u001b[H\u001b[2J\u001b[3J');
}
// Try this example to see it in action!
(function loop() {
let i = -40; // Print 40 lines extra.
(function printLine() {
console.log('line ' + (i + 41));
if (++i < process.stdout.columns) {
setTimeout(printLine, 40);
}
else {
clear();
setTimeout(loop, 3000);
}
})()
})()
The first line ensures the visible lines are always cleared.
The second line ensures the scroll history is cleared.
Try also:
var rl = require('readline');
rl.cursorTo(process.stdout, 0, 0);
rl.clearScreenDown(process.stdout);
On response to #loganfsmyth comment on his answer (thanks for the edit!).
I have been looking here and there and, besides of the wonderfull keypress module, there is a core module that makes possible to create a cli with all standard terminal behavior (all things we give for granted today such as history, options to provide an auto-complete function and input events such as keypress are there).
The module is readline (documentation). The good news is that all the standar behaviour is already done for us so there is no need to attach event handlers (i.e. history, clearing the screen on Ctrl+L, man if you provided the auto complete function it'll be on Tabpress).
Just as an example
var readline = require('readline')
, cli = readline.createInterface({
input : process.stdin,
output : process.stdout
});
var myPrompt = ' > myPropmt '
cli.setPrompt(myPrompt, myPrompt.length);
// prompt length so you can use "color" in your prompt
cli.prompt();
// Display ' > myPrompt ' with all standard features (history also!)
cli.on('line', function(cmd){ // fired each time the input has a new line
cli.prompt();
})
cli.input.on('keypress', function(key){ // self explanatory
// arguments is a "key" object
// with really nice properties such as ctrl : false
process.stdout.write(JSON.stringify(arguments))
});
Really good discovery.
The node version I'm using is v0.10.29. I have been looking at the changelog and it was there since 2010 (commit 10d8ad).
You can clear screen using console.log() and escape sequences.
cli.on 'line', (line) ->
if line == 'cls'
console.log("\033[2J\033[0f")
else
console.log line
cli.prompt()
Vorpal.js makes things like this really easy.
For an interactive CLI with a clear command as well as a REPL within the context of your application, do this:
var vorpal = require('vorpal')();
var repl = require('vorpal-repl');
vorpal
.delimiter('hello>')
.use(repl)
.show();
vorpal
.command('clear', 'Clears the screen.')
.action(function (args, cb) {
var blank = '';
for (var i = 0; i < process.stdout.rows; ++i) {
blank += '\n';
}
vorpal.ui.rewrite(blank);
vorpal.ui.rewrite('');
cb();
});
If you are using readline.createInterface you could do something like:
function clearPrompt() {
rl.setPrompt("");
rl.prompt();
}
Note this won't clear the entire terminal, just the readline prompt. Still useful if you want the user to keep their place in the terminal

Resources