diff --git a/cmd/cmd.js b/cmd/cmd.js index b72fd5e3..63a1a07d 100644 --- a/cmd/cmd.js +++ b/cmd/cmd.js @@ -36,6 +36,8 @@ process.env.NODE_PATH = utils.joinPath(process.env.EMBARK_PATH, 'node_modules') (process.env.NODE_PATH || ''); process.env.DEFAULT_DIAGRAM_PATH = utils.joinPath(process.env.DAPP_PATH, 'diagram.svg'); +process.env.DEFAULT_CMD_HISTORY_PATH = utils.joinPath(process.env.DAPP_PATH, '.embark', 'cmd_history'); +process.env.DEFAULT_CMD_HISTORY_SIZE = 20; class Cmd { constructor() { diff --git a/cmd/dashboard/command_history.js b/cmd/dashboard/command_history.js index 0acb499b..962fdeda 100644 --- a/cmd/dashboard/command_history.js +++ b/cmd/dashboard/command_history.js @@ -1,7 +1,12 @@ +let fs = require('../../lib/core/fs'); + class CommandHistory { - constructor() { + constructor(options = {}) { + this.cmdHistoryFile = options.cmdHistoryFile + || process.env.DEFAULT_CMD_HISTORY_PATH; this.history = []; this.pointer = -1; + this.loadHistory(); } addCommand(cmd) { @@ -24,6 +29,16 @@ class CommandHistory { this.pointer++; return this.history[this.pointer]; } -} + loadHistory() { + if (fs.existsSync(this.cmdHistoryFile)) { + fs.readFileSync(this.cmdHistoryFile) + .toString() + .split('\n') + .reverse() + .forEach((cmd) => { this.addCommand(cmd); }) + } + } + +} module.exports = CommandHistory; diff --git a/cmd/dashboard/repl.js b/cmd/dashboard/repl.js index 3dac64ca..d18b3d78 100644 --- a/cmd/dashboard/repl.js +++ b/cmd/dashboard/repl.js @@ -1,5 +1,6 @@ const repl = require("repl"); const util = require("util"); +let fs = require('../../lib/core/fs'); class REPL { constructor(options) { @@ -28,6 +29,12 @@ class REPL { writer: this.enhancedWriter.bind(this) }); + this.events.request('console:history', (err, history) => { + history + .split('\n') + .forEach((cmd) => { this.replServer.history.push(cmd); }); + }); + this.events.request("runcode:getContext", (context) => { this.replServer.context = context; }); diff --git a/lib/modules/console/index.js b/lib/modules/console/index.js index d38a96d6..0cf40668 100644 --- a/lib/modules/console/index.js +++ b/lib/modules/console/index.js @@ -1,3 +1,4 @@ +let fs = require('../../core/fs'); let utils = require('../../utils/utils'); const EmbarkJS = require('embarkjs'); const IpfsApi = require('ipfs-api'); @@ -5,18 +6,24 @@ const Web3 = require('web3'); class Console { constructor(_embark, options) { + this.embark = _embark; this.events = options.events; this.plugins = options.plugins; this.version = options.version; this.logger = options.logger; this.ipc = options.ipc; this.config = options.config; + this.history = []; + this.cmdHistoryFile = options.cmdHistoryFile || process.env.DEFAULT_CMD_HISTORY_PATH; + this.loadHistory(); if (this.ipc.isServer()) { this.ipc.on('console:executeCmd', this.executeCmd.bind(this)); } this.events.setCommandHandler("console:executeCmd", this.executeCmd.bind(this)); + this.events.setCommandHandler("console:history", (cb) => this.getHistory(process.env.DEFAULT_CMD_HISTORY_SIZE, cb)); this.registerEmbarkJs(); + this.registerConsoleCommands(); } processEmbarkCmd (cmd) { @@ -26,6 +33,7 @@ class Console { '', __('possible commands are:'), 'versions - ' + __('display versions in use for libraries and tools like web3 and solc'), + 'history - ' + __('display console commands history'), // TODO: only if the blockchain is actually active! // will need to pass te current embark state here 'ipfs - ' + __('instantiated js-ipfs object configured to the current environment (available if ipfs is enabled)'), @@ -44,6 +52,10 @@ class Console { } executeCmd(cmd, callback) { + if (!(cmd.split(' ')[0] === 'history' || cmd === __('history'))) { + this.history.push(cmd); + this.saveHistory(); + } var pluginCmds = this.plugins.getPluginsProperty('console', 'console'); for (let pluginCmd of pluginCmds) { let pluginResult = pluginCmd.call(this, cmd, {}); @@ -112,6 +124,50 @@ class Console { return acc; }, ''); } + + registerConsoleCommands() { + this.embark.registerConsoleCommand((cmd, _options) => { + let [cmdName, length] = cmd.split(' '); + return { + match: () => cmdName === 'history', + process: (callback) => this.getHistory(length, callback) + }; + }); + } + + loadHistory() { + if (fs.existsSync(this.cmdHistoryFile)) { + fs.readFileSync(this.cmdHistoryFile) + .toString() + .split('\n') + .reverse() + .forEach((cmd) => { this.history.push(cmd); }); + } + } + + getHistory(_length, callback) { + if (typeof _length === "string") { + _length = parseInt(_length, 10); + if (isNaN(_length)) return callback("Invalid argument. Please provide an integer."); + } + let length = _length || process.env.DEFAULT_CMD_HISTORY_SIZE; + return callback(null, this.history + .slice(Math.max(0, this.history.length - length)) + .filter(line => line.trim()) + .reverse() + .join('\n')); + } + + saveHistory() { + if (fs.existsSync(utils.dirname(this.cmdHistoryFile))) { + fs.writeFileSync(this.cmdHistoryFile, + this.history + .slice(Math.max(0, this.history.length - process.env.DEFAULT_CMD_HISTORY_SIZE)) + .reverse() + .filter(line => line.trim()) + .join('\n')); + } + } } module.exports = Console; diff --git a/test/console.js b/test/console.js index f02d4a99..dc1e936e 100644 --- a/test/console.js +++ b/test/console.js @@ -9,7 +9,20 @@ describe('embark.Console', function() { let ipc = new IPC({ipcRole: 'none'}); let plugins = new Plugins({plugins: {}}); let events = {once: () => {}, setCommandHandler: () => {}, emit: () => {}}; - let console = new Console({}, {plugins, version, ipc, events}); + let embarkObject = { + events: events, + logger: plugins.logger, + registerConsoleCommand: (cmd, opt) => {}, + embarkConfig: { + options: { + solc: { + "optimize": true, + "optimize-runs": 200 + } + } + } + } + let console = new Console(embarkObject, {plugins, version, ipc, events}); describe('#executeCmd', function() {