log-with-statusbar
Version:
A light weight logger with a status bar on the bottom or the top that does not disappear with scrolling
312 lines (295 loc) • 8.09 kB
JavaScript
/**
* A light weight logger with a status bar on the bottom that does not disappear with scrolling
* The status bar can be multiple lines.
* Use setStatusBarText() function to set the lines.
* This is based on npm ololog package
* By: Ari Saif
*/
/**
* @module testModule
*/
const ansi = require("ansi"),
assert = require("assert"),
cursor = ansi(process.stdout),
{ cyan, yellow, red, blue } = require("ansicolor"),
getCursorPosition = require("cursor-pos");
const spinners = Object.assign({}, require("./spinners.json"));
var g_curPos;
var statusTextArray;
var linesToDelete = 0;
var g_enableStatusBar = true;
var g_position = "bottom";
var g_disableInput = true;
//-----------------------------------------------------------------------------
var default_ololog_configure = {
locate: false,
tag: (
lines,
{
level = "",
maxVerbosity = 1,
verbosity = 1,
enable = true,
levelColor = {
info: cyan,
warn: yellow,
error: red.bright.inverse,
debug: blue
}
}
) => {
if (!enable) {
return [];
}
const levelStr =
level && (levelColor[level] || (s => s))(level.toUpperCase());
if (verbosity <= maxVerbosity) {
if (level) {
// Add level only to the first line
let retVal = lines.map((l, i) => {
if (i === 0) {
return levelStr.padStart(6) + ": " + l;
} else {
return l;
}
});
return retVal;
} else {
return lines;
}
} else {
return [];
}
}
};
//-----------------------------------------------------------------------------
var default_ololog_methods = {
/**
*
* @param {Array} arrayOfStatusLines An array of values.
* Each value will be printed in a separate line.
* New lines will be escaped
* @returns {null}
*/
setStatusBarText(arrayOfStatusLines) {
assert(
Array.isArray(arrayOfStatusLines),
"Error: The parameter to setStatusBarText should be an array."
);
statusTextArray = arrayOfStatusLines;
renderStatusbar();
},
/**
*
* Returns the current status bar
* @returns {Array}
*/
getStatusBarText() {
return statusTextArray;
},
/**
*
* Adds one line to the status bar
* @returns null
*/
statusBarTextPush(text) {
if (statusTextArray && Array.isArray(statusTextArray)) {
statusTextArray.push(text);
} else {
statusTextArray = [text];
}
renderStatusbar();
},
/**
*
* Remove one line to the status bar
* @returns null
*/
statusBarTextPop() {
if (statusTextArray && Array.isArray(statusTextArray)) {
statusTextArray.pop();
renderStatusbar();
}
},
/**
* Sets the default verbosity
* We only print if verbosity is less than or equal maxVerbosity
* @param {Number} n
*/
verbosity(n) {
return this.configure({ tag: { verbosity: n } });
},
/**
* Sets the maximum verbosity
* We only print if verbosity is less than or equal maxVerbosity
* @param {Number} n
*/
maxVerbosity(n) {
return this.configure({ tag: { maxVerbosity: n } });
},
/**
* This function is kept only for compatibility. minVerbosity is deprecated.
* It now only changes maxVerbosity
* Sets the maximum verbosity
* We only print if verbosity is less than or equal maxVerbosity
* @param {Number} n
*/
minVerbosity(n) {
return this.configure({ tag: { maxVerbosity: n } });
},
/**
* Completely disables logging both scrollable and status bar
*/
enable() {
g_enableStatusBar = true;
return this.configure({ tag: { enable: true } });
},
/**
* Completely enables logging both scrollable and status bar
*/
disable() {
g_enableStatusBar = false;
return this.configure({ tag: { enable: false } });
},
/**
* Enables the status bar
*/
enableStatusBar() {
g_enableStatusBar = true;
printStatusbar();
},
/**
* Disables the status bar
*/
disableStatusBar() {
clearStatusBar();
g_enableStatusBar = false;
},
getSpinners() {
return spinners;
}
};
//-----------------------------------------------------------------------------
/**
* Clears the status bar text
*/
async function clearStatusBar() {
if (g_enableStatusBar) {
if (g_position === "bottom") {
for (let index = 0; index < linesToDelete; index++) {
cursor.up();
cursor.eraseLine();
}
} else if (g_position === "top") {
g_curPos = await getCursorPosition();
cursor.goto(1, 1);
for (let index = 0; index < linesToDelete; index++) {
cursor.eraseLine();
cursor.down();
}
}
}
}
//-----------------------------------------------------------------------------
/**
* Renders the status bar text
*/
function printStatusbar(curPos) {
if (g_enableStatusBar) {
if (g_position === "bottom") {
statusTextArray.forEach(l => {
let k = String.raw`${l}`;
k = k.replace(/\n/, "\\n");
k = k.substring(0, process.stdout.columns);
console.log(k);
});
} else if (g_position === "top") {
cursor.goto(1, 1);
statusTextArray.forEach(l => {
let k = String.raw`${l}`;
k = k.replace(/\n/, "\\n");
k = k.substring(0, process.stdout.columns);
console.log(k);
});
if (g_curPos) {
cursor.goto(1, g_curPos.row);
}
}
linesToDelete = statusTextArray.length;
}
}
function renderStatusbar() {
clearStatusBar();
printStatusbar();
}
//-----------------------------------------------------------------------------
var ololog = require("ololog").configure(default_ololog_configure);
var defaultConfig = {
enableStatusBar: true,
ololog_configure: default_ololog_configure,
ololog_methods: default_ololog_methods,
initialStatusTextArray: [
`Call log.setStatusBarText(["Your Text"]) to set this line.`
],
maxVerbosity: 1, //maximum verbosity level
verbosity: 1, //Default verbosity level
position: "bottom", // top or bottom
disableInput: false
};
//-----------------------------------------------------------------------------
module.exports = function(config = defaultConfig) {
var log = ololog.configure(
config.ololog_configure || defaultConfig.ololog_configure
);
var methods = config.ololog_methods || defaultConfig.ololog_methods;
statusTextArray =
config.initialStatusTextArray || defaultConfig.initialStatusTextArray;
g_enableStatusBar = config.enableStatusBar;
if (g_enableStatusBar === undefined || g_enableStatusBar === null) {
g_enableStatusBar = defaultConfig.enableStatusBar;
}
let maxVerbosity = config.maxVerbosity || defaultConfig.maxVerbosity;
let verbosity = config.verbosity || defaultConfig.verbosity;
g_position = config.position || defaultConfig.position;
g_disableInput = config.disableInput;
if (g_disableInput === undefined || g_disableInput === null) {
g_disableInput = defaultConfig.disableInput;
}
// We disable input so that pressing keys doesn't affect the displayed text
// Pressing keys while displaying status bar disturbs the output specially when showing
//the status bar on the top
if (g_disableInput) {
var keypress = require("keypress");
keypress(process.stdin);
process.stdin.on("keypress", function(ch, key) {
if (key && key.ctrl && key.name == "c") {
process.exit();
process.exi;
}
});
process.stdin.setRawMode(true);
process.stdin.resume();
}
log = log.configure({
"+render"(text) {
if (g_position === "bottom") {
clearStatusBar();
} else if (g_position === "top") {
}
return text;
},
"render+"(text) {
if (g_position === "bottom") {
printStatusbar();
} else if (g_position === "top") {
clearStatusBar();
printStatusbar();
}
return text;
}
});
log.methods(methods);
log = log.maxVerbosity(maxVerbosity);
log = log.verbosity(verbosity);
return log;
};