parent $user_interfaces object $help_interface var $root child_index 1 var $root owners [$] var $root owned [$help_interface] var $root fertile 1 var $has_commands commands [] var $has_commands shortcuts [] var $root inited 1 var $help_interface help_dict #[["*", $], ["help", $], ["**", $]] var $help_interface current_help $ var $root manager $help_interface var $root writable [$help_interface] var $root readable ['parameters, 'methods, 'code] var $root dbref 'help_interface var $old_command_environment verb_cache #[] var $old_command_environment command_cache [] var $old_command_environment shortcuts_cache [] method init_help if (caller() != $root) throw(~perm, "Caller is not $root."); current_help = $help_root; help_dict = #[["*", $help_root], ["help", $help_help], ["**", $user_help]]; . method help_dict return help_dict; . method match_help_path arg string; var current, node; current = current_help; for node in (explode(string)) current = (> .match_help_node(node, current) <); return current; . method match_help_node arg string, current; var node, sib, i; switch (string) { case ">": node = current; while (1) { if (node == $help_root) throw(~keynf, (current.help_name()) + " has no successor."); sib = (node.upnode()).subnodes(); i = node in sib; if (i && (i < listlen(sib))) return sib[i + 1]; node = node.upnode(); } case "<": node = current; while (1) { if (node == $help_root) throw(~keynf, (current.help_name()) + " has no predecessor."); sib = (node.upnode()).subnodes(); i = node in sib; if (i > 1) return sib[i - 1]; node = node.upnode(); } case "..": if (current == $help_root) throw(~keynf, "Top node has no supernode."); return current.upnode(); case "?": if (!(current.subnodes())) return (> .match_help_node(">", current) <); return (current.subnodes())[1]; } catch ~keynf { return help_dict[string]; } return (> current.match_menu(string) <); . method help_cmd arg string, [rest]; var command, matches, method; if (rest) string = rest[1]; else if (string == "help") string = ""; // if an extended command is present, put it in command, and the rest // of the line back into string command = "read"; if (string && ((string[1]) == "-")) { matches = match_regexp("^-([a-z]+)( +(.*))?", string); if (!matches) { sender().tell("invalid help syntax"); return; } command = substr(string, (matches[2])[1], (matches[2])[2]); if ((matches[4])[1]) string = substr(string, (matches[4])[1], (matches[4])[2]); else string = ""; } // now call the appropriate handler method = tosym(command + "_helpcmd"); catch ~methodnf { .(method)(sender(), string); } with handler { sender().tell(("\"" + command) + "\" is not a valid help subcommand."); } return; . method destroy_helpcmd arg source, string; // deletes the current node if (string) { source.tell("Usage: help -destroy"); } else if (current_help == $help_root) { source.tell("cannot destroy the root node"); } else { current_help = current_help.upnode(); current_help.destroy(); } . method relink_helpcmd arg source, string; var target, path; // relink a node to another location // usage: help -relink <path>" if (!string) { source.tell("Usage: help -relink <path>"); return; } else if (current_help == $help_root) { source.tell("Can't move the root node."); return; } // lookup the target node catch ~keynf { target = .match_help_path(string); } with handler { source.tell(("No help found on " + toliteral(string)) + "."); return; } // check for loops if (current_help == target) { source.tell("Can't link a node to itself."); } else if (current_help in (target.path())) { source.tell("Requested move would create a loop."); } else { // move the node current_help.set_upnode(target); path = [@current_help.path(), current_help]; path = "Help path: " + (path ? $list.to_string($list.map(path, 'help_name), " ") | "<none>"); source.tell(path); } . method add_helpcmd arg source, string; var matches, what, name, help_name, brief, text; // // add a new node // called by: $help.help_cmd // // usage: help -add name help-name brief < note-object // help -add name help-name brief : help-name << // // the first form takes the text from a note or similar object // the second form reads the text from the keyboard // // check the syntax matches = match_regexp("([^ ]+) (.*) < (.*)", string); if (!matches) matches = match_regexp("([^ ]+) (.*) <<", string); if (!matches) { source.tell("Invalid syntax for add subcommand. Please use one of:"); source.tell(" help -add help-name brief < note-object"); source.tell(" help -add help-name brief <<"); return; } // parse the match results name = substr(string, (matches[2])[1], (matches[2])[2]); brief = substr(string, (matches[3])[1], (matches[3])[2]); if ((matches[4])[1]) what = substr(string, (matches[4])[1], (matches[4])[2]); else what = ""; // see if we are getting text from keyboard or a note if (what) { // reading from note: get the text catch any { what = source.match_environment(what); text = what.text(); } with handler { source.tell("Couldn't get text from object " + what); return; } // create a subnode what = current_help.create_subnode(name, brief, text); source.tell(((("Created new help node " + (what.help_name())) + " [") + (what.brief())) + "]"); } else { // reading from keyboard: read the text source.tell("keyboard input not implemented yet"); } . method read_helpcmd arg source, string; // check for footnote access catch ~range { source.tell((("[:" + string) + ":] ") + (current_help.footnote(toint(string)))); return; } // lookup the node to be read catch ~keynf { current_help = .match_help_path(string); } with handler { source.tell(("No help found on " + toliteral(string)) + "."); return; } // dump the contents of the node source.tell(current_help.text()); // tell the user what the next node is, if any if (current_help.subnodes()) { source.tell(((("-----[ `??' to read " + (((current_help.subnodes())[1]).brief())) + " (") + (((current_help.subnodes())[1]).help_name())) + ") ]"); } else { catch ~keynf { string = .match_help_node("?", current_help); source.tell(((((("-----[ `??' to read " + (string.brief())) + " (") + ($list.to_string($list.map(string.path(), 'help_name), " "))) + " ") + (string.help_name())) + ") ]"); } with handler { source.tell("-----[ Last node. `?*' to return to the top. ]"); } } . method text_helpcmd arg source, string; var what, text; // change the text of a help node // usage: help -text note // help -text << if (!string) { source.tell("Usage: help -text note"); } else if (string == "<<") { source.tell("Keyboard input not implemented yet."); } else { // parse the object containing the text catch any { what = source.match_environment(string); text = what.text(); } with handler { source.tell("Couldn't get text from object " + string); return; } // install text current_help.set_text(text); source.tell("Updated text."); } . method name_helpcmd arg source, string; var exp, name, brief; // rename the node -- usage: help -name name brief if (!string) { source.tell("Usage: help -name <name> <brief>"); return; } // parse the arguments exp = explode(string); if (listlen(exp) < 2) source.tell("Usage: help -name <name> <brief>"); name = exp[1]; brief = substr(string, strlen(name) + 2); // set the names current_help.set_help_name(name); current_help.set_brief(brief); // tell the user what happened source.tell(((("node is now: " + (current_help.help_name())) + " [") + (current_help.brief())) + "]"); . method reset_help arg [rest]; if (!(.is_writable_by(sender()))) throw(~perm, "Not an owner"); current_help = $help_root; . method init_help_interface if (caller() != $root) throw(~perm, "Caller is not $root."); current_help = $help_root; help_dict = #[["*", $help_root], ["help", $help_help], ["**", $user_help]]; . method init_help_interface_old if (caller() != $root) throw(~perm, "Caller is not $root."); current_help = $help_root; help_dict = #[["*", $help_root], ["help", $help_help], ["**", $user_help]]; .