Implicitly support abbreviating commands
authorJeremy Stanley <fungi@yuggoth.org>
Mon, 6 May 2019 19:00:13 +0000 (19:00 +0000)
committerJeremy Stanley <fungi@yuggoth.org>
Mon, 6 May 2019 21:37:06 +0000 (21:37 +0000)
Match entered commands against initial substrings of a sorted list
of command keywords, effectively supporting abbreviated commands.
Also test it works.

mudpy/command.py
mudpy/misc.py
mudpy/tests/selftest.py

index 1138aa8..95fb793 100644 (file)
@@ -148,10 +148,7 @@ def help(actor, parameters):
     if parameters and actor.owner:
 
         # is the command word one for which we have data?
     if parameters and actor.owner:
 
         # is the command word one for which we have data?
-        if parameters in actor.universe.groups["command"]:
-            command = actor.universe.groups["command"][parameters]
-        else:
-            command = None
+        command = mudpy.misc.find_command(parameters)
 
         # only for allowed commands
         if actor.can_run(command):
 
         # only for allowed commands
         if actor.can_run(command):
index 50a9456..501d5b4 100644 (file)
@@ -1474,6 +1474,25 @@ def check_for_connection(listening_socket):
     return user
 
 
     return user
 
 
+def find_command(command_name):
+    """Try to find a command by name or abbreviation."""
+
+    # lowercase the command
+    command_name = command_name.lower()
+
+    command = None
+    if command_name in universe.groups["command"]:
+        # the command matches a command word for which we have data
+        command = universe.groups["command"][command_name]
+    else:
+        for candidate in sorted(universe.groups["command"]):
+            if candidate.startswith(command_name):
+                # the command matches the start of a command word
+                command = universe.groups["command"][candidate]
+                break
+    return command
+
+
 def get_menu(state, error=None, choices=None):
     """Show the correct menu text to a user."""
 
 def get_menu(state, error=None, choices=None):
     """Show the correct menu text to a user."""
 
@@ -1864,14 +1883,8 @@ def handler_active(user):
         else:
             command_name, parameters = first_word(input_data)
 
         else:
             command_name, parameters = first_word(input_data)
 
-        # lowercase the command
-        command_name = command_name.lower()
-
-        # the command matches a command word for which we have data
-        if command_name in universe.groups["command"]:
-            command = universe.groups["command"][command_name]
-        else:
-            command = None
+        # expand to an actual command
+        command = find_command(command_name)
 
         # if it's allowed, do it
         if actor.can_run(command):
 
         # if it's allowed, do it
         if actor.can_run(command):
index b73c13e..520f2fd 100644 (file)
@@ -215,6 +215,12 @@ test_admin_help = (
     (2, "This will save all active accounts", ""),
 )
 
     (2, "This will save all active accounts", ""),
 )
 
+test_abbrev = (
+    (0, "> ", "help mov"),
+    (0, r"Move in a specific direction\.", "mov north"),
+    (0, r"You exit to the north\.", ""),
+)
+
 test_reload = (
     (2, "> ", "reload"),
     (2, r"Reloading all code modules, configs and data\."
 test_reload = (
     (2, "> ", "reload"),
     (2, r"Reloading all code modules, configs and data\."
@@ -334,6 +340,7 @@ dialogue = (
     (test_telnet_unknown_option, "log unknown telnet option"),
     (test_admin_restriction, "restricted admin commands"),
     (test_admin_help, "admin help"),
     (test_telnet_unknown_option, "log unknown telnet option"),
     (test_admin_restriction, "restricted admin commands"),
     (test_admin_help, "admin help"),
+    (test_abbrev, "command abbreviation"),
     (test_reload, "reload"),
     (test_set_facet, "set facet"),
     (test_set_refused, "refuse altering read-only element"),
     (test_reload, "reload"),
     (test_set_facet, "set facet"),
     (test_set_refused, "refuse altering read-only element"),