diff --git a/command-parse.html b/command-parse.html
index e79ef41..a7c67d6 100644
--- a/command-parse.html
+++ b/command-parse.html
@@ -136,6 +136,8 @@
whiteSpace: 'nowrap'
});
var row = $('
@@ -279,7 +303,8 @@
defaults: {
property: { value: "payload", required: true, validate: RED.validators.typedInput("propertyType") },
name: { value: "" },
- help_text: {value: ""}
+ help_text: {value: ""},
+ help_keyword: {value: "help"},
},
inputs: 1,
outputs: 2,
diff --git a/command-parse.js b/command-parse.js
index 504245b..a5c3dcf 100644
--- a/command-parse.js
+++ b/command-parse.js
@@ -2,10 +2,95 @@
module.exports = function (RED) {
"use strict";
+ function format_usage(usage, prefix) {
+ if (!prefix) {
+ prefix = [];
+ }
+ let out = "";
+ for (let k in usage) {
+ if (!usage.hasOwnProperty(k))
+ continue;
+ if(typeof usage[k] == "object"){
+ out += format_usage(usage[k], prefix.concat([k]));
+ } else {
+ let ext = k != "" ? [k] : [];
+ out += prefix.concat(ext).join(" ") + ": " + usage[k] + "\n";
+ }
+ }
+ return out;
+ }
+ function depth_first(n, path) {
+ if (!path) {
+ path = [n.id];
+ }
+ if (!n) {
+ return null;
+ }
+ let usage = {};
+ if (n.type == 'parser-consume') {
+ for (let r_idx in n.rules) {
+ let r = n.rules[r_idx];
+ let key;
+ if (r.t == "regex") {
+ if (r.match_name){
+ key = `[${r.match_name}]`;
+ } else {
+ key = `[espressione]`;
+ }
+ } else {
+ key = r.v;
+ }
+ if (r.help) {
+ usage[key] = r.help;
+ } else {
+ let sub_usage = {};
+ for (let wire of n.wires[r_idx]) {
+ if (path.indexOf(wire) === -1) {
+ let sub_n = RED.nodes.getNode(wire);
+ let tmp_sub_usage = depth_first(sub_n, path + [wire]);
+ if (tmp_sub_usage !== null) {
+ Object.assign(sub_usage, tmp_sub_usage);
+ }
+ }
+ }
+ usage[key] = sub_usage;
+ }
+ }
+ }
+ return usage;
+ }
+
function ParserEntryPoint(n) {
RED.nodes.createNode(this, n);
this.property = n.property;
this.help_text = n.help_text;
+ this.help_keyword = n.help_keyword;
+ this.genera_errore = function(msg) {
+ let out = "";
+ if (msg && msg.token_parser && msg.token_parser.consumed_tokens.length > 0) {
+ let offending_token = msg.token_parser.consumed_tokens[msg.token_parser.consumed_tokens.length - 1];
+ if (offending_token == "") {
+ offending_token = "(vuoto)";
+ }
+ out += msg.token_parser.consumed_tokens.slice(0, -1).join(" ") +`: comando non riconosciuto: ${offending_token}.\n`;
+ if (this.help_keyword) {
+ let help_command = msg.token_parser.consumed_tokens.slice(0, -1).concat([this.help_keyword]).join(" ");
+ out += `Usa '${help_command}' per la guida.\n`;
+ }
+ }
+ return out;
+ }
+ this.genera_help = function (root, msg) {
+ let usages = {};
+ if (!root) {
+ for (let wire of root.wires[0]) {
+ Object.assign(usages, depth_first(RED.nodes.getNode(wire)));
+ }
+ } else {
+ usages = depth_first(root);
+ }
+ return format_usage(usages, msg.token_parser.consumed_tokens.slice(0,-1));
+ };
this.on("input", msg => {
RED.util.evaluateNodeProperty(this.property, "msg", this, msg,
(err, value) => {
@@ -13,12 +98,17 @@ module.exports = function (RED) {
this.error(`Can't evaluate msg.${this.property}`);
} else {
let tokens = value.trim().toLowerCase().split(" ");
+ msg.regex_matches = {};
msg.token_parser = {
new_tokens: tokens,
consumed_tokens: [],
- help_message: this.help_text,
- on_error: (maybe_error) => {
- let err = maybe_error ? maybe_error : this.help_text;
+ help_keyword: this.help_keyword,
+ on_error: (msg, maybe_error) => {
+ let err = maybe_error ? maybe_error : this.genera_errore(msg);
+ this.send([undefined, err]);
+ },
+ on_help: (help_node, msg) => {
+ let err = this.genera_help(help_node, msg);
this.send([undefined, err]);
}
};
@@ -33,10 +123,10 @@ module.exports = function (RED) {
function ConsumaToken(n) {
RED.nodes.createNode(this, n);
this.rules = n.rules;
- this.behavior= n.behavior;
- this.checkall= n.checkall;
+ this.behavior = n.behavior;
+ this.checkall = n.checkall;
function check_rule(r, token) {
- switch(r.t){
+ switch (r.t) {
case "eq":
return token == r.v.toLowerCase();
case "regex":
@@ -47,10 +137,18 @@ module.exports = function (RED) {
this.on("input", msg => {
let token = msg.token_parser.new_tokens.shift() || "";
msg.token_parser.consumed_tokens.push(token);
+ if(token == msg.token_parser.help_keyword) {
+ msg.token_parser.on_help(this, msg);
+ return;
+ }
let out = [];
let n_matches = 0;
for (let r of this.rules) {
- if(check_rule(r, token)){
+ let matches = check_rule(r, token);
+ if (matches === true || matches.length > 0) {
+ if (matches.length > 0) {
+ msg.regex_matches[r.match_name] = matches;
+ }
out.push(msg);
n_matches += 1;
if (!this.checkall) {
@@ -61,7 +159,8 @@ module.exports = function (RED) {
}
}
if (n_matches == 0) {
- msg.token_parser.on_error();
+ msg.token_parser.on_error(msg);
+ return;
}
this.send(out);
});