Support abbreviating portal names when moving
[mudpy.git] / mudpy / command.py
index 95fb793..20b448c 100644 (file)
@@ -6,12 +6,13 @@
 
 import random
 import re
+import traceback
 import unicodedata
 
 import mudpy
 
 
-def chat(actor):
+def chat(actor, parameters):
     """Toggle chat mode."""
     mode = actor.get("mode")
     if not mode:
@@ -117,8 +118,13 @@ def error(actor, input_data):
     else:
         message = "Arglebargle, glop-glyf!?!"
 
-    # send the error message
-    actor.send(message)
+    # try to send the error message, and log if we can't
+    try:
+        actor.send(message)
+    except Exception:
+        mudpy.misc.log(
+            'Sending a command error to user %s raised exception...\n%s' % (
+                actor.owner.account.get("name"), traceback.format_exc()))
 
 
 def halt(actor, parameters):
@@ -161,7 +167,8 @@ def help(actor, parameters):
                 output = "$(red)"
             else:
                 output = "$(grn)"
-            output += parameters + "$(nrm) - " + description + "$(eol)$(eol)"
+            output = "%s%s$(nrm) - %s$(eol)$(eol)" % (
+                output, command.subkey, description)
 
             # add the help text if provided
             help_text = command.get("help")
@@ -194,23 +201,53 @@ def help(actor, parameters):
     # no specific command word was indicated
     else:
 
-        # give a sorted list of commands with descriptions if provided
-        output = "These are the commands available to you:$(eol)$(eol)"
-        sorted_commands = list(actor.universe.groups["command"].keys())
-        sorted_commands.sort()
-        for item in sorted_commands:
-            command = actor.universe.groups["command"][item]
+        # preamble text
+        output = ("These are the commands available to you [brackets indicate "
+                  "optional portion]:$(eol)$(eol)")
+
+        # list command names in alphabetical order
+        for command_name, command in sorted(
+                actor.universe.groups["command"].items()):
+
+            # skip over disallowed commands
             if actor.can_run(command):
-                description = command.get("description")
-                if not description:
-                    description = "(no short description provided)"
+
+                # start incrementing substrings
+                for position in range(1, len(command_name) + 1):
+
+                    # we've found our shortest possible abbreviation
+                    candidate = mudpy.misc.find_command(
+                            command_name[:position])
+                    try:
+                        if candidate.subkey == command_name:
+                            break
+                    except AttributeError:
+                        pass
+
+                # use square brackets to indicate optional part of command name
+                if position < len(command_name):
+                    abbrev = "%s[%s]" % (
+                        command_name[:position], command_name[position:])
+                else:
+                    abbrev = command_name
+
+                # supply a useful default if the short description is missing
+                description = command.get(
+                    "description", "(no short description provided)")
+
+                # administrative command names are in red, others in green
                 if command.get("administrative"):
-                    output += "   $(red)"
+                    color = "red"
                 else:
-                    output += "   $(grn)"
-                output += item + "$(nrm) - " + description + "$(eol)"
-        output += ('$(eol)Enter "help COMMAND" for help on a command '
-                   'named "COMMAND".')
+                    color = "grn"
+
+                # format the entry for this command
+                output = "%s   $(%s)%s$(nrm) - %s$(eol)" % (
+                    output, color, abbrev, description)
+
+        # add a footer with instructions on getting additional information
+        output = ('%s $(eol)Enter "help COMMAND" for help on a command named '
+                  '"COMMAND".' % output)
 
     # send the accumulated output to the user
     actor.send(output)
@@ -226,10 +263,12 @@ def look(actor, parameters):
 
 def move(actor, parameters):
     """Move the avatar in a given direction."""
-    if parameters in actor.universe.contents[actor.get("location")].portals():
-        actor.move_direction(parameters)
-    else:
-        actor.send("You cannot go that way.")
+    for portal in sorted(
+            actor.universe.contents[actor.get("location")].portals()):
+        if portal.startswith(parameters):
+            actor.move_direction(portal)
+            return(portal)
+    actor.send("You cannot go that way.")
 
 
 def preferences(actor, parameters):
@@ -270,14 +309,14 @@ def preferences(actor, parameters):
     actor.send(message)
 
 
-def quit(actor):
+def quit(actor, parameters):
     """Leave the world and go back to the main menu."""
     if actor.owner:
         actor.owner.state = "main_utility"
         actor.owner.deactivate_avatar()
 
 
-def reload(actor):
+def reload(actor, parameters):
     """Reload all code modules, configs and data."""
     if actor.owner:
 
@@ -422,9 +461,8 @@ def show(actor, parameters):
     elif arguments[0] == "version":
         message = repr(actor.universe.versions)
     elif arguments[0] == "time":
-        message = actor.universe.groups["internal"]["counters"].get(
-            "elapsed"
-        ) + " increments elapsed since the world was created."
+        message = "%s increments elapsed since the world was created." % (
+            str(actor.universe.groups["internal"]["counters"].get("elapsed")))
     elif arguments[0] == "groups":
         message = "These are the element groups:$(eol)"
         groups = list(actor.universe.groups.keys())