From c10c4d15233103e86bd462875f5a251f5e8400c6 Mon Sep 17 00:00:00 2001 From: Code0x58 Date: Thu, 20 Nov 2014 10:02:54 +0000 Subject: [PATCH] Added readline completion for method names * Double tab on non-windows brings up a list of possible completions, on windows you have to use Ctrl+x * The command line is split on white-space so things like `help server.info` will work instead of just ` server.info` --- ma-shell.py | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/ma-shell.py b/ma-shell.py index 24d9449..e21e1e8 100755 --- a/ma-shell.py +++ b/ma-shell.py @@ -31,6 +31,7 @@ from optparse import OptionParser from xmlrpclib import ServerProxy, Fault, DateTime, ProtocolError import socket +import re try: import json except: @@ -40,8 +41,11 @@ print "(notice: json not found, please install simplejson)" try: import readline -except: - print "(notice: readline support not found)" + readline.parse_and_bind('TAB: complete') + # Press Ctrl+x to list plausible completions (mainly for windows which lacks double-tab) + readline.parse_and_bind('"\\C-x": possible-completions') +except StandardError as e: + print "(notice: readline support not found)", e class JSONDateEncoder(json.JSONEncoder): """JSON Encoder to support DateTime objects""" @@ -204,7 +208,9 @@ def execute(self, cmd, quiet=False): return True def run(self): - + if 'readline' in globals(): + self.old_completer = readline.get_completer() + readline.set_completer(self.completer) if self.args: self.execute(self.args, quiet=True) return @@ -224,11 +230,27 @@ def run(self): if not cmd: continue else: - cmd = cmd.strip().split(' ') + cmd = re.split(r'\s*', cmd.strip()) if not self.execute(cmd): break + if hasattr(self, 'old_completer'): + readline.set_completer(self.old_completer) + + def completer(self, text, state): + line = readline.get_line_buffer() + start = readline.get_begidx() + # Check that `text` has nothing but possibly some whitespace before it + if start > len(re.match(r'^\s*(?:help)?\s*', line).group(0)): + return + + if state == 0: + self.matches = filter((lambda m: m.startswith(text)), self.methods + ['help', 'quit']) + if state < len(self.matches): + return self.matches[state] + + return if __name__ == "__main__": main = Main()