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]];
.