diff options
Diffstat (limited to 'alot/commands/__init__.py')
-rw-r--r-- | alot/commands/__init__.py | 251 |
1 files changed, 138 insertions, 113 deletions
diff --git a/alot/commands/__init__.py b/alot/commands/__init__.py index c67ad2a2..0adb75f3 100644 --- a/alot/commands/__init__.py +++ b/alot/commands/__init__.py @@ -1,6 +1,9 @@ import os +import sys import glob import logging +import argparse +import cStringIO import alot.settings @@ -26,140 +29,162 @@ COMMANDS = { 'global': {}, } +def lookup_command(cmdname, mode): + """returns commandclass, argparser and forcedparams + for `cmdname` in `mode`""" + if cmdname in COMMANDS[mode]: + return COMMANDS[mode][cmdname] + elif cmdname in COMMANDS['global']: + return COMMANDS['global'][cmdname] + else: + return None, None, None -class registerCommand(object): - def __init__(self, mode, name, defaultparms): - self.mode = mode - self.name = name - self.defaultparms = defaultparms +def lookup_parser(cmdname, mode): + return lookup_command(cmdname, mode)[1] - def __call__(self, klass): - COMMANDS[self.mode][self.name] = (klass, self.defaultparms) - return klass +class CommandParseError(Exception): + pass -def register(klass): - COMMANDS['classes'] = klass - return klass +class CommandArgumentParser(argparse.ArgumentParser): + """ArgumentParser that raises `CommandParseError` + instead of printing to sys.stderr""" + def exit(self, message): + raise CommandParseError(message) + def error(self, message): + raise CommandParseError(message) -def commandfactory(cmdname, mode='global', **kwargs): - if cmdname in COMMANDS[mode]: - (cmdclass, parms) = COMMANDS[mode][cmdname] - elif cmdname in COMMANDS['global']: - (cmdclass, parms) = COMMANDS['global'][cmdname] - else: - logging.error('there is no command %s' % cmdname) - parms = parms.copy() - parms.update(kwargs) - for (key, value) in kwargs.items(): - if callable(value): - parms[key] = value() - else: - parms[key] = value - parms['prehook'] = alot.settings.hooks.get('pre_' + cmdname) - parms['posthook'] = alot.settings.hooks.get('post_' + cmdname) - - logging.debug('cmd parms %s' % parms) - return cmdclass(**parms) +class registerCommand(object): + def __init__(self, mode, name, forced={}, arguments=[]): + self.argparser = CommandArgumentParser(prog=name, add_help=False) + for args,kwargs in arguments: + self.argparser.add_argument(*args,**kwargs) + self.mode = mode + self.name = name + self.forced = forced + def __call__(self, klass): + COMMANDS[self.mode][self.name] = (klass, self.argparser, self.forced) + return klass -def interpret_commandline(cmdline, mode): - # TODO: use argparser here! +def commandfactory(cmdline, mode='global'): + # split commandname and parameters if not cmdline: return None logging.debug('mode:%s got commandline "%s"' % (mode, cmdline)) args = cmdline.split(' ', 1) - cmd = args[0] + cmdname = args[0] if args[1:]: - params = args[1] + argstring = args[1] else: - params = '' + argstring = '' # unfold aliases - if alot.settings.config.has_option('command-aliases', cmd): - cmd = alot.settings.config.get('command-aliases', cmd) + if alot.settings.config.has_option('command-aliases', cmdname): + cmdname = alot.settings.config.get('command-aliases', cmdname) # allow to shellescape without a space after '!' - if cmd.startswith('!'): - params = cmd[1:] + ' ' + params - cmd = 'shellescape' + if cmdname.startswith('!'): + argstring = cmdname[1:] + ' ' + argstring + cmdname = 'shellescape' + + # get class, argparser and forced parameter + (cmdclass, parser, forcedparms) = lookup_command(cmdname,mode) + if cmdclass is None: + msg = 'unknown command: %s' % cmdname + logging.debug(msg) + raise CommandParseError(msg) + + logging.debug('PARSE: %s' % argstring) + #logging.debug(parser) + parms = vars(parser.parse_args(argstring.split())) + logging.debug('PARMS: %s' % parms) + logging.debug(parms) + + parms.update(forcedparms) + # still needed? + #for (key, value) in kwargs.items(): + # if callable(value): + # parms[key] = value() + # else: + # parms[key] = value - # check if this command makes sense in current mode - if cmd not in COMMANDS[mode] and cmd not in COMMANDS['global']: - logging.debug('unknown command: %s' % (cmd)) - return None + parms['prehook'] = alot.settings.hooks.get('pre_' + cmdname) + parms['posthook'] = alot.settings.hooks.get('post_' + cmdname) - if cmd == 'search': - return commandfactory(cmd, mode=mode, query=params) - if cmd in ['move', 'sendkey']: - return commandfactory(cmd, mode=mode, key=params) - elif cmd == 'compose': - h = {} - if params: - h = {'To': params} - return commandfactory(cmd, mode=mode, headers=h) - elif cmd == 'attach': - return commandfactory(cmd, mode=mode, path=params) - elif cmd == 'help': - return commandfactory(cmd, mode=mode, commandline=params) - elif cmd == 'forward': - return commandfactory(cmd, mode=mode, inline=(params == '--inline')) - elif cmd == 'prompt': - return commandfactory(cmd, mode=mode, startstring=params) - elif cmd == 'refine': - if mode == 'search': - return commandfactory(cmd, mode=mode, query=params) - elif mode == 'envelope': - return commandfactory(cmd, mode=mode, key=params) - - elif cmd == 'retag': - return commandfactory(cmd, mode=mode, tagsstring=params) - elif cmd == 'shellescape': - return commandfactory(cmd, mode=mode, commandstring=params) - elif cmd == 'set': - key, value = params.split(' ', 1) - return commandfactory(cmd, mode=mode, key=key, value=value) - elif cmd == 'toggletag': - return commandfactory(cmd, mode=mode, tags=params.split()) - elif cmd == 'fold': - return commandfactory(cmd, mode=mode, all=(params == '--all')) - elif cmd == 'unfold': - return commandfactory(cmd, mode=mode, all=(params == '--all')) - elif cmd == 'save': - args = params.split(' ') - allset = False - pathset = None - if args: - if args[0] == '--all': - allset = True - pathset = ' '.join(args[1:]) - else: - pathset = params - return commandfactory(cmd, mode=mode, all=allset, path=pathset) - elif cmd == 'edit': - filepath = os.path.expanduser(params) - if os.path.isfile(filepath): - return commandfactory(cmd, mode=mode, path=filepath) - elif cmd == 'print': - args = [a.strip() for a in params.split()] - return commandfactory(cmd, mode=mode, - whole_thread=('--thread' in args), - separately=('--separately' in args)) - elif cmd == 'pipeto': - return commandfactory(cmd, mode=mode, command=params) - - elif not params and cmd in ['exit', 'flush', 'pyshell', 'taglist', - 'bclose', 'compose', 'openfocussed', - 'closefocussed', 'bnext', 'bprevious', 'retag', - 'refresh', 'bufferlist', 'refineprompt', - 'reply', 'open', 'groupreply', 'bounce', - 'openthread', 'toggleheaders', 'send', - 'cancel', 'reedit', 'select', 'retagprompt']: - return commandfactory(cmd, mode=mode) - else: - return None + logging.debug('cmd parms %s' % parms) + return cmdclass(**parms) + + +#def interpret_commandline(cmdline, mode): +# +# elif cmd == 'compose': +# h = {} +# if params: +# h = {'To': params} +# return commandfactory(cmd, mode=mode, headers=h) +# elif cmd == 'attach': +# return commandfactory(cmd, mode=mode, path=params) +# elif cmd == 'help': +# return commandfactory(cmd, mode=mode, commandline=params) +# elif cmd == 'forward': +# return commandfactory(cmd, mode=mode, inline=(params == '--inline')) +# elif cmd == 'prompt': +# return commandfactory(cmd, mode=mode, startstring=params) +# elif cmd == 'refine': +# if mode == 'search': +# return commandfactory(cmd, mode=mode, query=params) +# elif mode == 'envelope': +# return commandfactory(cmd, mode=mode, key=params) +# +# elif cmd == 'retag': +# return commandfactory(cmd, mode=mode, tagsstring=params) +# elif cmd == 'shellescape': +# return commandfactory(cmd, mode=mode, commandstring=params) +# elif cmd == 'set': +# key, value = params.split(' ', 1) +# return commandfactory(cmd, mode=mode, key=key, value=value) +# elif cmd == 'toggletag': +# return commandfactory(cmd, mode=mode, tags=params.split()) +# elif cmd == 'fold': +# return commandfactory(cmd, mode=mode, all=(params == '--all')) +# elif cmd == 'unfold': +# return commandfactory(cmd, mode=mode, all=(params == '--all')) +# elif cmd == 'save': +# args = params.split(' ') +# allset = False +# pathset = None +# if args: +# if args[0] == '--all': +# allset = True +# pathset = ' '.join(args[1:]) +# else: +# pathset = params +# return commandfactory(cmd, mode=mode, all=allset, path=pathset) +# elif cmd == 'edit': +# filepath = os.path.expanduser(params) +# if os.path.isfile(filepath): +# return commandfactory(cmd, mode=mode, path=filepath) +# elif cmd == 'print': +# args = [a.strip() for a in params.split()] +# return commandfactory(cmd, mode=mode, +# whole_thread=('--thread' in args), +# separately=('--separately' in args)) +# elif cmd == 'pipeto': +# return commandfactory(cmd, mode=mode, command=params) +# +# elif not params and cmd in ['exit', 'flush', 'pyshell', 'taglist', +# 'bclose', 'compose', 'openfocussed', +# 'closefocussed', 'bnext', 'bprevious', 'retag', +# 'refresh', 'bufferlist', 'refineprompt', +# 'reply', 'open', 'groupreply', 'bounce', +# 'openthread', 'toggleheaders', 'send', +# 'cancel', 'reedit', 'select', 'retagprompt']: +# return commandfactory(cmd, mode=mode) +# else: +# return None __all__ = list(filename[:-3] for filename in glob.glob1(os.path.dirname(__file__), '*.py')) |