@moleculer/vorpal
Version:
Node's first framework for building immersive CLI apps.
190 lines (145 loc) • 4.37 kB
JavaScript
'use strict';
var _ = require('lodash');
var LocalStorage = require('node-localstorage').LocalStorage;
var path = require('path');
var os = require('os'); // Number of command histories kept in persistent storage
var HISTORY_SIZE = 500;
var temp = path.normalize(path.join(os.tmpdir(), '/.local_storage'));
var DEFAULT_STORAGE_PATH = temp;
var History = function History() {
this._storageKey = undefined; // Prompt Command History
// Histctr moves based on number of times 'up' (+= ctr)
// or 'down' (-= ctr) was pressed in traversing
// command history.
this._hist = [];
this._histCtr = 0; // When in a 'mode', we reset the
// history and store it in a cache until
// exiting the 'mode', at which point we
// resume the original history.
this._histCache = [];
this._histCtrCache = 0;
};
/**
* Initialize the history with local storage data
* Called from setId when history id is set
*/
History.prototype._init = function () {
if (!this._storageKey) {
return;
} // Load history from local storage
var persistedHistory = JSON.parse(this._localStorage.getItem(this._storageKey));
if (_.isArray(persistedHistory)) {
Array.prototype.push.apply(this._hist, persistedHistory);
}
};
/**
* Set id for this history instance.
* Calls init internally to initialize
* the history with the id.
*/
History.prototype.setId = function (id) {
// Initialize a localStorage instance with default
// path if it is not initialized
if (!this._localStorage) {
this._localStorage = new LocalStorage(DEFAULT_STORAGE_PATH);
}
this._storageKey = 'cmd_history_' + id;
this._init();
};
/**
* Initialize a local storage instance with
* the path if not already initialized.
*
* @param path
*/
History.prototype.setStoragePath = function (path) {
if (!this._localStorage) {
this._localStorage = new LocalStorage(path);
}
};
/**
* Get previous history. Called when up is pressed.
*
* @return {String}
*/
History.prototype.getPreviousHistory = function () {
this._histCtr++;
this._histCtr = this._histCtr > this._hist.length ? this._hist.length : this._histCtr;
return this._hist[this._hist.length - this._histCtr];
};
/**
* Get next history. Called when down is pressed.
*
* @return {String}
*/
History.prototype.getNextHistory = function () {
this._histCtr--; // Return empty prompt if the we dont have any history to show
if (this._histCtr < 1) {
this._histCtr = 0;
return '';
}
return this._hist[this._hist.length - this._histCtr];
};
/**
* Peek into history, without changing state
*
* @return {String}
*/
History.prototype.peek = function (depth) {
depth = depth || 0;
return this._hist[this._hist.length - 1 - depth];
};
/**
* A new command was submitted. Called when enter is pressed and the prompt is not empty.
*
* @param cmd
*/
History.prototype.newCommand = function (cmd) {
// Always reset history when new command is executed.
this._histCtr = 0; // Don't store command in history if it's a duplicate.
if (this._hist[this._hist.length - 1] === cmd) {
return;
} // Push into history.
this._hist.push(cmd); // Only persist history when not in mode
if (this._storageKey && !this._inMode) {
var persistedHistory = this._hist;
var historyLen = this._hist.length;
if (historyLen > HISTORY_SIZE) {
persistedHistory = this._hist.slice(historyLen - HISTORY_SIZE - 1, historyLen - 1);
} // Add to local storage
this._localStorage.setItem(this._storageKey, JSON.stringify(persistedHistory));
}
};
/**
* Called when entering a mode
*/
History.prototype.enterMode = function () {
// Reassign the command history to a
// cache, replacing it with a blank
// history for the mode.
this._histCache = _.clone(this._hist);
this._histCtrCache = parseFloat(this._histCtr);
this._hist = [];
this._histCtr = 0;
this._inMode = true;
};
/**
* Called when exiting a mode
*/
History.prototype.exitMode = function () {
this._hist = this._histCache;
this._histCtr = this._histCtrCache;
this._histCache = [];
this._histCtrCache = 0;
this._inMode = false;
};
/**
* Clears the command history
* (Currently only used in unit test)
*/
History.prototype.clear = function () {
if (this._storageKey) {
this._localStorage.removeItem(this._storageKey);
}
};
module.exports = History;