How to clear the Terminal Console in JavaScript - javascript

I am creating a RPG CLI Game with JavaScript and Node.js. I have multiple pages (menu to choose options from, the actual fight...) and I need that every time a page changes everything on the console dissapears so that it always starts at the top of the console.
I need this every time I execute the script or choose one of the options on the menu, I need that it always starts at the top of the console.
My code so far:
// Imports
import readline from "readline"
import start from "./menu/start.js"
import load from "./menu/load.js"
import exit from "./menu/exit.js"
// Run function
const run = (args) => {
const pause = (ms = 500) => new Promise((r) => setTimeout(r, ms))
async function welcomeMenu() {
console.log(`
+-----------------------------+
| Welcome ! |
+-----------------------------+
`)
await pause()
console.log(`
1. Start game 👍
2. Load game 💾
3. Exit ❌
`)
await pause()
// Taking user input
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
})
rl.question("Your choice (1-3): ", (input) => {
if (input == 1) {
start()
rl.close()
} else if (input == 2) {
load()
rl.close()
} else if (input == 3) {
exit()
rl.close()
} else {
rl.question("Your choice (1-3): ", input)
}
})
}
welcomeMenu()
}
export default run
I just need help with clearing the console.
I tried with console.clear(); but it didn't work.

Just use console-clear library from npm: npmjs.com/package/console-clear
In your Terminal, do npm install --save console-clear.
Then, seeing as you use ESM, you'll need to do: import clear from "console-clear".
Then just call it where you want to clear the console: clear() or clear(true)
Hope I helped

Related

nodeJS - Communicate with an electron app running in the background through a CLI

as an example of what I'm trying to achieve, consider launching VS Code from the terminal. The code <file-name> command opens an instance of vs code if not only running, or tells it to open a file otherwise. Also, once opened, the user can use the terminal session for other tasks again (as if the process was disowned).
My script needs to interact with my electron app in the same way, with the only difference being that my app will be in the tray and not visible in the dock.
.
The solution only needs to work on linux
Use a unix socket server for inter-process-communication.
In electron
const handleIpc = (conn) => {
conn.setEncoding('utf8');
conn.on('data',(line) => {
let args = line.split(' ');
switch(args[0]) {
case 'hey':
conn.write('whatsup\n');
break;
default: conn.write('new phone who this?\n');
}
conn.end();
})
}
const server = net.createServer(handleIpc);
server.listen('/tmp/my-app.sock');
Then your CLI is:
#!/usr/bin/node
const net = require('net');
let args = process.argv;
args.shift(); // Drop /usr/bin/node
args.shift(); // Drop script path
let line = args.join(' ');
net.connect('/tmp/my-app.sock',(conn)=>{
conn.setEncoding('utf8');
conn.on('data',(response)=>{
console.log(response);
process.exit(0);
});
conn.write(line+'\n');
}).on('error',(err)=>{
console.error(err);
process.exit(1);
});
If I understand correctly, you want to keep only one instance of your app and to handle attempts to launch another instance. In old versions of Electron, app.makeSingleInstance(callback) was used to achieve this. As for Electron ...v13 - v15, app.requestSingleInstanceLock() with second-instance event is used. Here is an example how to use it:
const { app } = require('electron');
let myWindow = null;
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Someone tried to run a second instance
// Do the stuff, for example, focus the window
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore()
myWindow.focus()
}
})
// Create myWindow, load the rest of the app, etc...
app.whenReady().then(() => {
myWindow = createWindow();
})
}
So when someone will launch ./app arg1 arg2 at the second time, the callback will be called. By the way, this solution is cross-platform.

How can we read random number of lines data from nodejs stdin?

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

Discord.js Cooldowns with Time Remaining using Command Handler

I am looking to make a cool down system for discord bot commands using discord.js. I am looking for it to show the time remaining left on the cool down when the user tries to do the command. Currently I have it so it does a cool down using the command handler so that I just have to add "timeout: '10000'," although I cant seem to find a way to get it show the time remaining by using this system.
This is the code that I currently have in my message.js file so that is can be used with the command handler so that I do not have to write the timeout code on every command file. Code below is the whole message.js file.
const Timeout = new Set();
const { MessageEmbed } = require('discord.js')
const {prefix} = require('../../config.json')
const ms = require('ms')
module.exports=async(bot, message)=>{
if(message.author.bot) return;
if(!message.content.toLowerCase().startsWith(prefix)) return;
if(!message.member) message.member = await message.guild.fetchMember(messsage);
if(!message.guild) return;
const args = message.content.slice(prefix.length).trim().split(/ +/g);
const cmd = args.shift().toLowerCase();
if(cmd.length === 0) return;
let command = bot.commands.get(cmd);
if(!command) command = bot.commands.get(bot.aliases.get(cmd));
if(command){
if(command.timeout){
if(Timeout.has(`${message.author.id}${command.name}`)){
return message.reply(`**Slow down, you can only use this command every ${ms(command.timeout)}!**`)
} else {
command.run(bot, message, args);
Timeout.add(`${message.author.id}${command.name}`)
setTimeout(() => {
Timeout.delete(`${message.author.id}${command.name}`)
}, command.timeout);
}
} else {
command.run(bot, message, args)
}
}
}
Current response is above in bold text.
For reference, the message.js file is referenced in the following code in my index.js file.
bot.on('message', async message =>{
require('./events/guild/message')(bot, message)
})
The following is what I have to put at the beginning of each command file, with a simple command example shown for reference.
const Discord = require('discord.js');
module.exports={
name: 'test',
category: 'info',
timeout: '15000', //This would result in a 15 second cooldown as time is in ms.
run: async(bot, message, args) =>{
message.channel.send(`test`)
}
}
To conclude, I am looking to keep my system, but instead of it saying "Slow down, you can only use this command every 15000! (For example above) I would like it to say something in the lines of "Slow it down, you can use this command again in 10s.
The default cooldown is 15s.
If I'm not mistaken you want to convert every 15000 into every 15s?
You already have the ms module so looks like you are just confused how to use it:
If it receives a string it converts it into ms, if it receives a number it converts it into a readable format like 1d 2h 3m,
In your module.exports you have it a string, so make it a number and everything is fixed.
That string might also intercept with setTimeout(func, time)
If for some reason you don't want to change the module.exports.timeout into a string, before you call ms, you will have to do parseInt(command.timeout)
code:
let command = bot.commands.get(cmd) || bot.commands.get(bot.aliases.get(cmd));
if (!command) return;
if (!command.timeout) return command.run(bot, message, args);
//if you changed it to a number in module.exports you don't have to parseInt it
const timeout = parseInt(command.timeout);
if (Timeout.has(`${message.author.id}${command.name}`)) {
return message.reply(`**Slow down, you can only use this command every ${ms(timeout)}!**`)
} else {
command.run(bot, message, args);
Timeout.add(`${message.author.id}${command.name}`)
setTimeout(() => {
Timeout.delete(`${message.author.id}${command.name}`)
}, timeout);
}
Second part:
You will need to track when you set the timeout, the issue with using the Set class is that it's
not a key value based, so there's two options:
Set.add({ key: key, time: Date.now()}) or use Discord.Collection / Map
First: still using Set, setting objects instead:
const timeout = command.timeout;
const key = message.author.id + command.name;
let found;
for(const e of Timeout) {
if(e.key === key) {
found = e;
//possibly bad practice, arguable
break;
}
}
if(found) {
const timePassed = Date.now() - found.time;
const timeLeft = timeout - timePassed;
//the part at this command has a default cooldown of, did you want to hard code 15s? or have it be the commands.config.timeout?
return message.reply(`**Slow down, you can use this command again in ${ms(timeLeft)} This command has a default cooldown of ${timeout}!**`)
} else {
command.run(bot, message, args);
Timeout.add({ key, time: Date.now() });
setTimeout(() => {
Timeout.delete(key);
}, timeout);
}
Second: Discord.Collection or Map works too since its just an extended class from that
I'm going with Map, if you use Collection just do:
const { MessageEmbed, Collection } = require("discord.js");
const Timeout = new Collection();
Map code:
const Timeout = new Map();
After code:
const timeout = command.timeout;
const key = message.author.id + command.name;
const found = Timeout.get(key);
if(found) {
const timePassed = Date.now() - found;
const timeLeft = timeout - timePassed;
//the part at this command has a default cooldown of, did you want to hard code 15s? or have it be the commands.config.timeout?
return message.reply(`**Slow down, you can use this command again in ${ms(timeLeft)} This command has a default cooldown of ${timeout}!**`);
} else {
command.run(bot, message, args);
Timeout.set(key, Date.now());
setTimeout(() => {
Timeout.delete(key);
}, timeout);
}

How can I start a REPL that can access local variables in node.js?

Just like from IPython import embed; embed() but for node.
I want to open a REPL shell programmatically and be able to at least read the local variables. Being able to change them as well is a plus.
As far I know, the closest you can get is by using the repl built-in module (which is used by node inspect itself):
// ... your code you want to debug
const repl = require("repl");
const replServer = repl.start({
prompt: "Your Own Repl > ",
useGlobal: true
});
// Expose variables
const localVar = 42
replServer.context.localVar = localVar;
By running node index.js (assuming you saved the above content in index.js) we get access to this custom repl:
$ node index.js
Your Own Repl > localVar
42
Your Own Repl >
(To exit, press Ctrl+C again or Ctrl+D or type .exit)
Your Own Repl >
However, this does not work like a debugger tool, but really, it's only a REPL.
You can build a REPL similar to the built-in Deno REPL and and evaluate expressions using the dangerous eval function. Through it you'll be able to access local variables and other things (e.g. window).
repl.ts
import { readLines, writeAll } from "https://deno.land/std#0.106.0/io/mod.ts";
export default async function repl(evaluate: (x: string) => unknown) {
await writeOutput("exit using ctrl+d or close()\n");
await writeOutput("> ");
for await (const input of readInputs()) {
try {
const value = evaluate(input);
const output = `${Deno.inspect(value, { colors: !Deno.noColor })}\n`;
await writeOutput(output);
await writeOutput("> ");
} catch (error) {
await writeError(error);
}
}
}
async function* readInputs(): AsyncIterableIterator<string> {
yield* readLines(Deno.stdin);
}
async function writeOutput(output: string) {
await writeAll(Deno.stdout, new TextEncoder().encode(output));
}
async function writeError(error: unknown) {
await writeAll(Deno.stderr, new TextEncoder().encode(`Uncaught ${error}\n`));
}
repl_demo.ts
import repl from "./repl.ts";
let a = 1;
let b = 2;
let c = 3;
await repl((x) => eval(x));
example usage
% deno run repl_demo.ts
exit using ctrl+d or close()
> a
1
> a = 40
40
> a + b
42
For deno (Title says Node.js, tag deno) you can use Deno.run to execute deno and write to stdin and read from stdout.
The following will do:
const p = Deno.run({
cmd: ["deno"],
stdin: "piped",
stdout: "piped",
stderr: "piped"
});
async function read(waitForMessage) {
const reader = Deno.iter(p.stdout)
let res = '';
for await(const chunk of reader) {
res += new TextDecoder().decode(chunk);
console.log('Chunk', res, '---')
// improve this, you should wait until the last chunk
// is read in case of a command resulting in a big output
if(!waitForMessage)
return res;
else if(res.includes(waitForMessage))
return res;
}
}
async function writeCommand(command) {
const msg = new TextEncoder().encode(command + '\n');
console.log('Command: ', command)
const readPromise = read();
// write command
await p.stdin.write(msg);
// Wait for output
const value = await readPromise
return value;
}
// Wait for initial output:
// Deno 1.0.0
// exit using ctrl+d or close()
await read('ctrl+d or close()');
await writeCommand('let x = 5;')
let value = await writeCommand('x') // read x
console.log('Value: ', value)
await writeCommand('x = 6;')
value = await writeCommand('x') // read x
console.log('Value: ', value)
If you run that snippet, the output will be:
Command: let x = 5;
Command: x
Value: 5
Command: x = 6;
Command: x
Value: 6
There are some improvements to be made, such as handling stderr but you get the idea.
This feature doesn't currently exist but is being proposed in https://github.com/denoland/deno/issues/7938.
The vision being something along the lines of
Deno.eval("Deno.repl()")
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
//to be sure this context is here
const ev = eval.bind(this);
function ask() {
rl.question('>', (code) => {
console.log(ev(code));
ask();
});
}
ask();
this code ask a input with readLine module and every time a reponse is provided the code is executed and a new input is askef

How do I implement tab completion in node.js shell?

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

Categories

Resources