parent $help_root parent $user_interfaces object $help_ui var $root dbref 'help_ui var $root child_index 0 var $root fertile 1 var $root manager $help_ui var $root owned [$help_ui] var $root owners [$help_ui] var $root writable [] var $root readable ['parameters, 'methods, 'code] var $root inited 1 var $help_ui current_node 0 var $help_ui help_evaluator 0 var $help_ui help_path 0 var $has_commands commands [["@help *", 'help_cmd], ["@help-link *", 'help_link_cmd]] var $has_commands shortcuts [["?*", 'help_link_cmd, ["@help-link", 1]]] var $old_command_environment verb_cache #[] var $old_command_environment command_cache [["@help *", 'help_cmd], ["@help-link *", 'help_link_cmd]] var $old_command_environment shortcuts_cache [["?*", 'help_link_cmd, ["@help-link", 1]]] var $help_ui last_visited [] var $has_messages message_info #[] var $has_messages messages 0 method help_link_cmd arg cmd, what; var way, p, node; (> .perms(sender(), 'this) <); catch ~nodenf { if (!what) { // stick with the current node } else if (((what[1]) == "<") || ((what[1]) == ">")) { (> ._navigate_node_history(what) <); } else if ((what[1]) == "?") { return ._help_node_history(); } else { (> ._navigate_node(what) <); } } with handler { .tell((traceback()[1])[2]); return; } .build_help_page(); . method init_help_ui (> .perms(caller(), $root) <); current_node = $help.default_help_node(); last_visited = #[['pos, 1], ['nodes, [current_node]]]; . method current_node return current_node; . method add_link .perms(sender(), 'manager); . method help_cmd arg cmd, args; var cnode, n, nodes; (> .perms(sender(), 'this) <); args = args.explode(); if (args) { cnode = (| ._find_help_node(args[1], 'index) |); if (!cnode) return; for n in [2 .. listlen(args)] { cnode = (| ._find_help_node(args[n], 'downnodes) |); if (!cnode) return; } } else { cnode = $help.default_help_node(); } .set_help_node(cnode, 'new); .build_help_page(); . method build_node_data arg node; var vars, message; vars = $root_evaluator.fix_values(#[["downnodes", node.downnodes()], ["upnodes", node.upnodes()], ["title", node.title()]]); vars = dict_add(vars, "body", (node.body()).ctext()); message = .eval_message("help.format", vars); return message; . method eval_body return body.eval_cml(#[['evaluator, $help_evaluator], ['time, 'pre]]); . method build_help_page var out, len, clen, line, n; (> .perms(sender(), 'this) <); n = current_node; len = ((.linelen()) % 2) ? (.linelen()) - 1 | (.linelen()); .tell(((" " + (n.name())) + " ").center(len, "-")); .tell((n.body()).eval_ctext()); .tell(pad("", len, "-")); if (n.upnodes()) .tell("Up-nodes: " + (((n.upnodes()).map('name)).to_english())); if (n.downnodes()) .tell("Down-nodes: " + (((n.downnodes()).map('name)).to_english())); . method _find_help_node arg what, type; var pos, cnode; (> .perms(sender(), 'this) <); switch (type) { case 'index: cnode = $help_index.find_help_node(what); if (cnode) return cnode; else throw(~nodenf, ("Unable to find help on \"" + what) + "\"."); case 'link: if (what in dict_keys(current_node.links())) return (current_node.links())[what]; else throw(~nodenf, ("No node link \"" + what) + "\" found on current node."); default: if (current_node.(type)()) { if (strlen(what) == 1) { return current_node.(type)()[1]; } else { what = substr(what, 2); pos = what in (current_node.(type)().map('name)); if (pos) return current_node.(type)()[pos]; else throw(~nodenf, "No downnode named " + what); } } else { throw(~nodenf, ((("No " + tostr(type)) + " defined from node ") + (current_node.name())) + "."); } } . method _back_help_node var p; (> .perms(sender(), 'this) <); p = (last_visited['pos]) - 1; if (p) { last_visited.add('pos, p); return (last_visited['nodes])[p]; } else { .tell("There are no more help nodes to step back to, in your history."); throw(~stop, "", 'no_traceback); } . method _forward_help_node var p; (> .perms(sender(), 'this) <); p = (last_visited['pos]) + 1; if (p <= listlen(last_visited['nodes])) { last_visited.add('pos, p); return (last_visited['nodes])[p]; } else { .tell("There are no more help nodes to step forward to, in your history."); throw(~stop, "", 'no_traceback); } . method set_help_node arg node, type; var h, p, ns; // god this is getting UGLY, but I can't think right now (sigh) (> .perms(sender(), 'this) <); current_node = node; ns = last_visited['nodes]; p = last_visited['pos]; switch (type) { case 'back, 'forward: case 'new: // hardcode the history cap for now if (listlen(ns) >= 10) ns = delete(h, 1); ns = ns.union([node]); last_visited = last_visited.add('nodes, ns); } last_visited = last_visited.add('pos, node in ns); . method _navigate_node_history arg what; var way, p; (> .perms(sender(), 'this) <); way = ((what[1]) == "<") ? 'back | 'forward; if (strlen(what) == 1) { .set_help_node(.(tosym(("_" + tostr(way)) + "_help_node"))(), way); } else { what = substr(what, 2); p = what in ((last_visited['nodes]).map('name)); if (p) .set_help_node((last_visited['nodes])[p], way); else throw(~nodenf, ("There is no node \"" + what) + "\" in your history."); } . method _help_node_history var n, ns, p, l; (> .perms(sender(), 'this) <); ns = last_visited['nodes]; p = last_visited['pos]; .tell("Help node history:"); for n in [1 .. listlen(ns)] { if (p == n) l = "=> "; else l = " "; .tell(((l + pad(tostr(n) + ":", -2)) + " ") + ((ns[n]).name())); } .tell("--"); . method _navigate_node arg what; var n, ns, p; (> .perms(sender(), 'this) <); catch ~nodenf { n = ._find_help_node(what, 'link); } with handler { ns = (current_node.upnodes()) + (current_node.downnodes()); if (!ns) rethrow(error()); p = what in (ns.map('name)); if (!p) throw(~nodenf, ("No node found by the name \"" + what) + "\"."); n = ns[p]; } .set_help_node(n, 'new); .