usmanyunusov / nanospinner

🌀 The simplest and tiniest terminal spinner for Node.js
https://npm.im/nanospinner
ISC License
183 stars 15 forks source link

Feature Request: A way to use console methods while a spinner is running #14

Closed Mitsunee closed 2 years ago

Mitsunee commented 2 years ago

Current Behaviour:
console methods (like log, warn, table) print in a line that already contains a frame of the spinner.

Expected Behaviour:
No spinner is visible in the line a console method prints to

Suggestion:
Either a pause or togglePause method (pausing hides the spinner, leaving an empty line for any logger to print to) or a log method specifically for this use case.

usmanyunusov commented 2 years ago

You can give an example? I'll think about a solution

Mitsunee commented 2 years ago

Two examples I can give right now:

Context: log.table() is a tiny wrapper that checks if the argument is actually an object (or array) and uses console.log() instead of console.table() on non-objects. You can basically assume it's equivalent to console.table() here.

usmanyunusov commented 2 years ago

The release 0.4.0 has a new method .clear().

// check if svgo did anything, save changes and warn user
if (fileContent !== svg) {
  await writeFile(file, svg);
  spinner.clear()
  log.warn(`  '${basename(file)}' was not optimized.`);
}

spinner.success({
  text: `Built '${componentName}' for '${basename(file)}'.`
});
Mitsunee commented 2 years ago

I just tested the new method in a while loop and it doesn't seem like it ever renders inbetween clearing and console.log().

Can I re-render the spinner after logging with spinner.render()? If I understood correctly that should not advance the animation or spawn additional timeouts.

if (fileContent !== svg) {
  await writeFile(file, svg);
  spinner.clear();
  log.warn(`  '${basename(file)}' was not optimized.`);
  spinner.render();
}
usmanyunusov commented 2 years ago

Do I understand correctly, such a case?

import { createSpinner } from "nanospinner";

let spinner = createSpinner("Run test").start();

setTimeout(() => {
  spinner.clear();
  console.log("Warn!");
  spinner.start();
}, 1000);

setTimeout(() => {
  spinner.success();
}, 3000);

In this case, the spin will appear first, then the log will appear, then the spinner will continue to spin

Mitsunee commented 2 years ago

that looks exactly like what I wanted, thank you :)

usmanyunusov commented 2 years ago

You don't even need to call start. The spinner continues to spin after clean

Mitsunee commented 2 years ago

It sometimes flickers a tiny bit without calling start again as it's potentially not visible for a frame or two on a 60hz monitor (might be more noticeable on a higher refreshrate display?). I guess it's just a preference thing. I'm fine with calling start again though, I might add an argument to my logger to pass the current spinner so it handles the clearing and re-rendering internally.