new object $has_commands: $root; var $root inited = 1; var $has_commands shortcuts = #[]; var $has_commands commands = #[]; public method .init_has_commands() { var i; shortcuts = []; commands = []; for i in (this().parents()) { (| shortcuts += i.shortcuts().to_list() |); (| commands += i.commands().to_list() |); } shortcuts = shortcuts.to_dict(); commands = commands.to_dict(); }; public method .shortcuts() { return shortcuts || #[]; }; public method .commands() { return commands || #[]; }; public method .match_command() { arg line; var word; // This method will return a list of length three. // 1. command as matched (may be a shortcut character) // 2. associated symbol (which is probably a method name) // 3. the rest of the line, (minus command) // First try to match the shortcuts (quick) catch ~keynf { return [.shortcuts()[line[1]], line[1], substr(line, 2)]; } // Now try to match an actual command catch ~keynf { word = (| substr(line, 1, stridx(line, " ", 1)-1) |) || line; return [.commands()[word], word, (| substr(line, word.length() + 2) |) || ""]; } // No match return 0; }; public method .parse_line() { arg line; var cmd, ret; if ((cmd = .match_command(line))) { catch any { ret = .(cmd[1])(line, cmd[2], cmd[3]); } with { switch (error()) { case ~numargs: return "Wrong number of arguments."; default: rethrow(error()); } } return ret; } else { return "No such command."; } };