fix(@embark/cockpit): Fix cockpit not suggesting console commands

This PR fixes a number of issues relating to the cockpit console.

#### Console commands display in cockpit console
Fix cockpit console not displaying console usage commands that included “<usage option>”. For example “resolve <name>” would not display the “<name>” part, as it was attempting to write this in as HTML (ansi-to-html conversion).

This was fixed by replacing any instances of “<usage>” with “[usage]”. Please note that future usage strings should not contain text wrapped in “<>”.

#### Autosuggestions for “web.eth.” not appearing
Fix “web3.eth.” not suggesting members of `web3.eth`. This was due to a `Object.keys(web3.eth)` throwing `'getOwnPropertyDescriptor' on proxy: trap returned descriptor for property 'defaultAccount' that is incompatible with the existing property in the proxy target` in the console. Changing `Object.keys` to `Object.getOwnPropertyDescriptor` solved the problem.

#### Fix autosuggestion of known console commands (ie from plugins)
Fix known console commands (ie from  plugins) not being autosuggested. For example, typing “web”, should autosuggest `webserver start/stop`,  `log webserver on`, and `log webserver off`.

This PR adds in support for registered console commands (from plugins).
This commit is contained in:
emizzle 2019-02-20 15:03:27 +11:00 committed by Pascal Precht
parent cb5a346b9f
commit 2df4970810
7 changed files with 31 additions and 15 deletions

View File

@ -1,4 +1,5 @@
import { Logger } from "./logger"; import { Logger } from "./logger";
import { Plugins } from "./plugins";
export interface Events { export interface Events {
on: any; on: any;
@ -25,6 +26,7 @@ export interface Embark {
solc: string; solc: string;
} }
}; };
plugins: Plugins;
reloadConfig(): void; reloadConfig(): void;
}; };
registerActionForEvent(name: string, action: (callback: () => void) => void): void; registerActionForEvent(name: string, action: (callback: () => void) => void): void;

View File

@ -118,7 +118,7 @@ class Console {
"swarm".cyan + " - " + __("instantiated swarm-api object configured to the current environment (available if swarm is enabled)"), "swarm".cyan + " - " + __("instantiated swarm-api object configured to the current environment (available if swarm is enabled)"),
"web3".cyan + " - " + __("instantiated web3.js object configured to the current environment"), "web3".cyan + " - " + __("instantiated web3.js object configured to the current environment"),
"EmbarkJS".cyan + " - " + __("EmbarkJS static functions for Storage, Messages, Names, etc."), "EmbarkJS".cyan + " - " + __("EmbarkJS static functions for Storage, Messages, Names, etc."),
"log <process> on/off".cyan + " - " + __("Activate or deactivate the logs of a sub-process. Options: blockchain, ipfs, webserver"), "log [process] on/off".cyan + " - " + __("Activate or deactivate the logs of a sub-process. Options: blockchain, ipfs, webserver"),
]; ];
helpDescriptions.forEach((helpDescription) => { helpDescriptions.forEach((helpDescription) => {
let matches = [] as string[]; let matches = [] as string[];
@ -139,6 +139,12 @@ class Console {
} }
private executeCmd(cmd: string, callback: any) { private executeCmd(cmd: string, callback: any) {
// if this is the embark console process, send the command to the process
// running all the needed services (ie the process running `embark run`)
if (this.isEmbarkConsole) {
return this.ipc.request("console:executeCmd", cmd, callback);
}
if (!(cmd.split(" ")[0] === "history" || cmd === __("history"))) { if (!(cmd.split(" ")[0] === "history" || cmd === __("history"))) {
this.saveHistory(cmd); this.saveHistory(cmd);
} }
@ -180,12 +186,6 @@ class Console {
return callback(null, output); return callback(null, output);
} }
// if this is the embark console process, send the command to the process
// running all the needed services (ie the process running `embark run`)
if (this.isEmbarkConsole) {
return this.ipc.request("console:executeCmd", cmd, callback);
}
this.events.request("runcode:eval", cmd, (err: Error, result: any) => { this.events.request("runcode:eval", cmd, (err: Error, result: any) => {
if (err) { if (err) {
return callback(err.message); return callback(err.message);
@ -242,7 +242,7 @@ class Console {
const [_cmdName, length] = cmd.split(" "); const [_cmdName, length] = cmd.split(" ");
this.getHistory(length, callback); this.getHistory(length, callback);
}, },
usage: "history <optionalLength>", usage: "history [optionalLength]",
}); });
} }

View File

@ -52,6 +52,16 @@ export default class Suggestions {
}); });
} }
private formatMatches(matches: any): string {
if (Array.isArray(matches)) {
return matches.join(", ");
}
if (typeof matches === "function") {
return "";
}
return matches || "";
}
public getSuggestions(cmd: string, cb: (results: SuggestionsList) => any) { public getSuggestions(cmd: string, cb: (results: SuggestionsList) => any) {
if (cmd === "") { return cb([]); } if (cmd === "") { return cb([]); }
const suggestions: SuggestionsList = []; const suggestions: SuggestionsList = [];
@ -67,6 +77,10 @@ export default class Suggestions {
suggestions.push({value: "profile " + contract.className, command_type: "embark command", description: "profile " + contract.className + " contract"}); suggestions.push({value: "profile " + contract.className, command_type: "embark command", description: "profile " + contract.className + " contract"});
}); });
const plugins = this.embark.config.plugins.getPluginsProperty("console", "console");
for (const plugin of plugins) {
suggestions.push({value: plugin.usage || this.formatMatches(plugin.matches), command_type: "plugin command", description: plugin.description});
}
suggestions.push({value: "help", command_type: "embark command", description: "displays quick list of some of the available embark commands"}); suggestions.push({value: "help", command_type: "embark command", description: "displays quick list of some of the available embark commands"});
suggestions.push({value: "versions", command_type: "embark command", description: "display versions in use for libraries and tools like web3 and solc"}); suggestions.push({value: "versions", command_type: "embark command", description: "display versions in use for libraries and tools like web3 and solc"});
suggestions.push({value: "ipfs", command_type: "javascript object", description: "instantiated js-ipfs object configured to the current environment (available if ipfs is enabled)"}); suggestions.push({value: "ipfs", command_type: "javascript object", description: "instantiated js-ipfs object configured to the current environment (available if ipfs is enabled)"});
@ -81,7 +95,7 @@ export default class Suggestions {
try { try {
const toRemove: string = "." + cmd.split(".").reverse()[0]; const toRemove: string = "." + cmd.split(".").reverse()[0];
const cmdToSearch: string = cmd.replace((new RegExp(toRemove + "$")), ""); const cmdToSearch: string = cmd.replace((new RegExp(toRemove + "$")), "");
return this.events.request("runcode:eval", "Object.keys(" + cmdToSearch + ")", (err: any, result: any) => { return this.events.request("runcode:eval", "Object.getOwnPropertyNames(" + cmdToSearch + ")", (err: any, result: any) => {
try { try {
if (Array.isArray(result)) { if (Array.isArray(result)) {
result.forEach((match: string) => { result.forEach((match: string) => {

View File

@ -250,7 +250,7 @@ class TransactionDebugger {
const filename: string = this.txTracker[this.lastTx].contract.filename; const filename: string = this.txTracker[this.lastTx].contract.filename;
startDebug(txHash, filename, callback); startDebug(txHash, filename, callback);
}, },
usage: "debug <txHash>", usage: "debug [txHash]",
}); });
this.embark.registerConsoleCommand({ this.embark.registerConsoleCommand({

View File

@ -91,7 +91,7 @@ class ENS {
registerConsoleCommands() { registerConsoleCommands() {
this.embark.registerConsoleCommand({ this.embark.registerConsoleCommand({
usage: 'resolve <name>', usage: 'resolve [name]',
description: __('Resolves an ENS name'), description: __('Resolves an ENS name'),
matches: (cmd) => { matches: (cmd) => {
let [cmdName] = cmd.split(' '); let [cmdName] = cmd.split(' ');
@ -104,7 +104,7 @@ class ENS {
}); });
this.embark.registerConsoleCommand({ this.embark.registerConsoleCommand({
usage: 'lookup <address>', usage: 'lookup [address]',
description: __('Lookup an ENS address'), description: __('Lookup an ENS address'),
matches: (cmd) => { matches: (cmd) => {
let [cmdName] = cmd.split(' '); let [cmdName] = cmd.split(' ');
@ -118,7 +118,7 @@ class ENS {
this.embark.registerConsoleCommand({ this.embark.registerConsoleCommand({
usage: 'registerSubDomain <subDomain> <address>', usage: 'registerSubDomain [subDomain] [address]',
description: __('Register an ENS sub-domain'), description: __('Register an ENS sub-domain'),
matches: (cmd) => { matches: (cmd) => {
let [cmdName] = cmd.split(' '); let [cmdName] = cmd.split(' ');

View File

@ -13,7 +13,7 @@ class PluginCommand {
registerCommand() { registerCommand() {
this.embark.registerConsoleCommand({ this.embark.registerConsoleCommand({
description: "Installs a plugin in the Dapp. eg: plugin install embark-solc", description: "Installs a plugin in the Dapp. eg: plugin install embark-solc",
usage: "plugin install <package>", usage: "plugin install [package]",
matches: (cmd) => { matches: (cmd) => {
const [cmdName] = cmd.split(' '); const [cmdName] = cmd.split(' ');
return cmdName === 'plugin'; return cmdName === 'plugin';

View File

@ -71,7 +71,7 @@ class Profiler {
registerConsoleCommand() { registerConsoleCommand() {
this.embark.registerConsoleCommand({ this.embark.registerConsoleCommand({
description: "Outputs the function profile of a contract", description: "Outputs the function profile of a contract",
usage: "profile <contractName>", usage: "profile [contractName]",
matches: (cmd) => { matches: (cmd) => {
const [cmdName] = cmd.split(' '); const [cmdName] = cmd.split(' ');
return cmdName === 'profile'; return cmdName === 'profile';