I was looking for this feature in node.js and I haven't found it.
Can I implement it myself? As far as I know, node.js doesn't load any file at it's startup (like Bash does with .bashrc) and I haven't noticed any way to somehow override shell prompt.
Is there a way to implement it without writing custom shell?
You could monkey-patch the REPL. Note that you must use the callback version of the completer, otherwise it won't work correctly:
var repl = require('repl').start()
var _completer = repl.completer.bind(repl)
repl.completer = function(line, cb) {
// ...
_completer(line, cb)
}
Just as a reference.
readline module has readline.createInterface(options) method that accepts an optional completer function that makes a tab completion.
function completer(line) {
var completions = '.help .error .exit .quit .q'.split(' ')
var hits = completions.filter(function(c) { return c.indexOf(line) == 0 })
// show all completions if none found
return [hits.length ? hits : completions, line]
}
and
function completer(linePartial, callback) {
callback(null, [['123'], linePartial]);
}
link to the api docs: http://nodejs.org/api/readline.html#readline_readline_createinterface_options
You can implement tab functionality using completer function like below.
const readline = require('readline');
/*
* This function returns an array of matched strings that starts with given
* line, if there is not matched string then it return all the options
*/
var autoComplete = function completer(line) {
const completions = 'var const readline console globalObject'.split(' ');
const hits = completions.filter((c) => c.startsWith(line));
// show all completions if none found
return [hits.length ? hits : completions, line];
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
completer: autoComplete
});
rl.setPrompt("Type some character and press Tab key for auto completion....\n");
rl.prompt();
rl.on('line', (data) => {
console.log(`Received: ${data}`);
});
Reference :
https://self-learning-java-tutorial.blogspot.com/2018/10/nodejs-readlinecreateinterfaceoptions_2.html
Related
I'm trying to do the following two things sequentially in a Node.js app:
Get an arbitrary key as user input. (could be a character pressed, or any other key like arrow up/down...)
I'd like to ask the user for an arbitrary text input.
Each step works but if I chain them, the key entered first is always appended to the second input. Additionally the question is written to the console twice.
Here's the full code sample:
// sample.js
const readline = require("readline")
// Read a raw key from stdin as Promise
const getKey = () => new Promise((res) => {
process.stdin.setRawMode(true)
process.stdin.once('keypress', (str, key) => {
process.stdin.setRawMode(false)
res(key)
});
})
// Just promisify the "question" method
const getText = (interface, str) =>
new Promise(res => interface.question(str, res))
const main = async () => {
readline.emitKeypressEvents(process.stdin);
const interface = readline.createInterface({
input: process.stdin,
output: process.stdout
});
console.log("Press a key!")
const key = await getKey()
console.log(`\nYou pressed key "${key.name}"`)
const name = await getText(interface, "What's your name?\n")
console.log(`Your name is "${name}"`)
}
main()
And here's a sample CLI session screencast:
The expected behavior would be that those inputs don't interfere with eachother. Does anyone have a solution for this problem?
My assumtion was that the character from the first input is still unconsumed inside the stdin stream. But attempts to force to consume it were not successfull.
I am trying to run a simple program in Visual studio code terminal using node.js which requires reading inputs from the user and the operating on those inputs and printing the results.
I have tried many approaches but have not got success yet. I am using the following code:
process.stdin.resume();
process.stdin.setEncoding("ascii");
var input = "";
process.stdin.on("data", (c) => (input += c));
process.stdin.on("end", () => {
console.log(input);
});
process.stdin.on("SIGINT", () => {
console.log(input);
const { EOL } = require("os");
const lines = input.split(EOL); /*your input text, split by lines*/
console.log(lines);
});
I run the above code in VSCode using the in-built terminal with the command node filename.js. The program runs and keeps taking inputs but it never ends and never triggers "end" block or "SIGINT" block. Finally to stop the program I have to use ctrl+C.
Can someone please help me how to accomplish this as I want to practise solving www.codeforces.com problems on my local machine using VSCode+terminal?
This way it won't quit until you explicitly end the program. You can use process.exit() function to achieve that.
So your program should look like this :
process.stdin.resume();
process.stdin.setEncoding("ascii");
var input = "";
const inputLength = (Math.random()*10 +1) | 0;
console.log(inputLength);
let current=0;
process.stdin.on("data", (c) => {
input += c;
current++;
if(current>= inputLength){
console.clear();
console.log("reached max number of inputs");
console.log(input);
process.exit(0);
}
});
Here is the glitch link. You can test it opening console below and type node server.js
TBH, I don't understand what do you want to achieve, but you can write something like:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
})
rl.on('line', (input) => {
console.log(`Received: ${input}`);
});
when you hit enter, you will see you line. CTRL+C also works
readline is a part of the standard library
This question already has answers here:
Get user input through Node.js console
(6 answers)
Closed last month.
I'm working on a JS project running with node.js and I can't figure out how to get the prompt to work correctly for user input. I installed it from npm, followed the steps and I can get the program to prompt for user input but I can't store the result in a variable.
What I want is to prompt the user for his next move (up,down,left or right) every turn and use the result. I tried making a global move variable and affecting it in the prompt section, but it doesn't seem to work.
var Moving = function(maxMoves){
for(var n=maxMoves; n>0;){
var move;
var l;
//This would prompt for a direction (up,down,left,right)
move = prompt();
//And this would prompt for the number of tiles to advance;
l = prompt();
Direction(move,l);
n-=l;
}
};
Using require('prompt') or require('readline') are both good, easy ways to do this, but I wanted to find THE EASIEST WAY, and I didn't care about whether it is synchronous or asynchronous. Finding it took me longer than it should have, so maybe I can save people some time if they read this before digging any further.
Here you go:
# npm install readline-sync
var readline = require('readline-sync');
var name = readline.question("What is your name?");
console.log("Hi " + name + ", nice to meet you.");
Disclaimer: I am just spreading the word, here are my sources:
https://teamtreehouse.com/community/how-to-get-input-in-the-console-in-nodejs
How to take in text input from a keyboard and store it into a variable?
When you say "installed it from npm" I'm assuming you're referring to the prompt module from flatiron.
From their docs, as with most Node things, it looks like it exposes an asynchronous function, so you'll handle input inside the prompt callback:
var prompt = require('prompt');
//
// Start the prompt
//
prompt.start();
//
// Get two properties from the user: username and email
//
prompt.get(['username', 'email'], function (err, result) {
//
// Log the results.
//
console.log('Command-line input received:');
console.log(' username: ' + result.username);
console.log(' email: ' + result.email);
});
Storing it in a variable would be no different than accessing it from the result object above, but realize that since it's async it'll only be reliable available inside that callback.
you can use two packages readline and prompt
Here's a simple example with readline package https://nodejs.org/en/knowledge/command-line/how-to-prompt-for-command-line-input/
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('What is your name ? ', function (name) {
rl.question('Where do you live ? ', function (country) {
console.log(`${name}, is a citizen of ${country}`);
rl.close();
});
});
rl.on('close', function () {
console.log('\nBYE BYE !!!');
process.exit(0);
});
Here is an another example with prompt package. https://www.npmjs.com/package/prompt
const prompt = require('prompt');
prompt.start();
prompt.get(['username','email'], function (err, result) {
console.log('Command-line input received:');
console.log(' username: ' + result.username);
console.log(' email: ' + result.email);
});
inquirer module has a prompt function.
Use
const { prompt } = require('inquirer');
prompt([array] | object | string ')
Objective
Figure what is wrong with my code, or if underscore.js throttle works as it should.
Background
I have a huge list of postal codes in a file, and I am reading those codes and pasting them on console.
I am trying to use Underscore.js throttle() function, however my code stops after two runs (even though I have dozens), and the rest of the values are never printed.
Code
My code is in a very simple NodeJS project. I created a MCVE of the situation I am facing:
"use strict";
//requiremetns
let fs = require('fs');
let readLine = require('readline');
let _ = require('underscore');
//constants
const INPUT_FILE = 'dataset.txt';
const RADIX_CONVERSATION = 10;
const THROTTLE_DELAY = 500;
let init = function() {
let lineReader = readLine.createInterface({
input: fs.createReadStream(INPUT_FILE),
output: process.stdout,
terminal: false
});
let throttledRequestFn = _.throttle(requestFn, THROTTLE_DELAY);
lineReader.on('line', function(line) {
line = line.trim();
if (_.isNaN(parseInt(line, RADIX_CONVERSATION))) {
//Do some stuff
}
else {
throttledRequestFn('mahCountry', line);
}
});
};
let requestFn = function(country, postalCode){
console.log('request for ' + country + ' and postal ' + postalCode + ' done');
return false;
};
init();
Here I first start by reading the file, one line at a time. Then if the line I am reading is a number, I print something, otherwise nothing.
Following is a test file:
Vietnam
000000
100000
160000
170000
180000
200000
220000
230000
240000
250000
260000
270000
280000
290000
300000
310000
320000
330000
350000
360000
380000
390000
400000
410000
420000
430000
440000
460000
480000
510000
520000
530000
550000
560000
570000
580000
590000
600000
620000
630000
640000
650000
660000
670000
700000
790000
800000
810000
820000
830000
840000
850000
860000
870000
880000
890000
900000
910000
920000
930000
940000
950000
960000
970000
Question
The way I see it, my code should make 2 requests per second, with a 500 ms of delay between each one. It should print all the codes in the test file.
However, I never seen anything past the second value! Why is this happening?
The throttle function is working as intended. From the documentation:
Useful for rate-limiting events that occur faster than you can keep up with.
This means that your wrapped function will probably be called less often than you want.
What you actually want is probably some kind of queue. Underscore doesn't provide one, but the async library does: http://caolan.github.io/async/docs.html#.queue
let fs = require('fs');
let readLine = require('readline');
let _ = require('async');
// import the async library
let async = require('async');
const INPUT_FILE = 'dataset.txt';
const RADIX_CONVERSATION = 10;
// create the queue
var q = async.queue(function(task, callback) {
// make sure the queue task calls the callback only after the THROTTLE_DELAY
setTimeout(function () {
requestFn(task.country, task.postalCode);
callback();
}, THROTTLE_DELAY);
}, 1)
q.drain = function () {
console.log('all items have been processed');
};
let init = function () {
let lineReader = readLine.createInterface({
input: fs.createReadStream(INPUT_FILE),
output: process.stdout,
terminal: false
});
lineReader.on('line', function(line) {
line = line.trim();
if (_.isNaN(parseInt(line, RADIX_CONVERSATION))) {
// Do some stuff
}
else {
// Add the line to the Queue, to be executed later
q.push({country: 'mahCountry', postalCode: line});
}
});
};
let requestFn = function(country, postalCode){
console.log('request for ' + country + ' and postal ' + postalCode + ' done');
return false;
};
init();
Notice the use of setTimeout in the function that handles the elements in the queue. That way, you'll still only make one request every 500ms, but will be guaranteed to make all of them.
JavaScript developers who have spent time in languages like C often miss the ability to use certain types of introspection, like logging line numbers, and what method the current method was invoked from. Well if you're using V8 (Chrome, Node.js) you can employ the following.
Object.defineProperty(global, '__stack', {
get: function(){
var orig = Error.prepareStackTrace;
Error.prepareStackTrace = function(_, stack){ return stack; };
var err = new Error;
Error.captureStackTrace(err, arguments.callee);
var stack = err.stack;
Error.prepareStackTrace = orig;
return stack;
}
});
Object.defineProperty(global, '__line', {
get: function(){
return __stack[1].getLineNumber();
}
});
console.log(__line);
The above will log 19.
Combined with arguments.callee.caller you can get closer to the type of useful logging you get in C via macros.
The problem with the accepted answer, IMO, is that when you want to print something you might be using a logger, and when that is the case, using the accepted solution will always print the same line :)
Some minor changes will help avoiding such a case!
In our case, we're using Winston for logging, so the code looks like this (pay attention to the code-comments below):
/**
* Use CallSite to extract filename and number, for more info read: https://v8.dev/docs/stack-trace-api#customizing-stack-traces
* #returns {string} filename and line number separated by a colon
*/
const getFileNameAndLineNumber = () => {
const oldStackTrace = Error.prepareStackTrace;
try {
// eslint-disable-next-line handle-callback-err
Error.prepareStackTrace = (err, structuredStackTrace) => structuredStackTrace;
Error.captureStackTrace(this);
// in this example I needed to "peel" the first CallSites in order to get to the caller we're looking for
// in your code, the number of stacks depends on the levels of abstractions you're using
// in my code I'm stripping frames that come from logger module and winston (node_module)
const callSite = this.stack.find(line => line.getFileName().indexOf('/logger/') < 0 && line.getFileName().indexOf('/node_modules/') < 0);
return callSite.getFileName() + ':' + callSite.getLineNumber();
} finally {
Error.prepareStackTrace = oldStackTrace;
}
};