summaryrefslogtreecommitdiff
path: root/alot/commands/__init__.py
blob: c9a38b0d1734aaa6eccd89bd439f03bc839d5d81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import os
import sys
import glob
import shlex
import logging
import argparse
import cStringIO

import alot.settings


class Command(object):
    """base class for commands"""
    def __init__(self, prehook=None, posthook=None):
        self.prehook = prehook
        self.posthook = posthook
        self.undoable = False
        self.help = self.__doc__

    def apply(self, caller):
        pass


COMMANDS = {
    'search': {},
    'envelope': {},
    'bufferlist': {},
    'taglist': {},
    'thread': {},
    '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

def lookup_parser(cmdname, mode):
    return lookup_command(cmdname, mode)[1]

class CommandParseError(Exception):
    pass


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)


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 commandfactory(cmdline, mode='global'):
    # split commandname and parameters
    if not cmdline:
        return None
    logging.debug('mode:%s got commandline "%s"' % (mode, cmdline))
    args = shlex.split(cmdline.encode('utf-8'))
    args = map(lambda x: x.decode('utf-8'), args)  # get unicode strings
    logging.debug('ARGS: %s' % args)
    cmdname = args[0]
    args = args[1:]

    # unfold aliases
    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 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(parser)
    parms = vars(parser.parse_args(args))
    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

    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)


#def interpret_commandline(cmdline, mode):
#
#    elif cmd == 'compose':
#        h = {}
#        if params:
#            h = {'To': params}
#        return commandfactory(cmd, mode=mode, headers=h)
#    elif cmd == 'retag':
#        return commandfactory(cmd, mode=mode, tagsstring=params)
#    elif cmd == 'shellescape':
#        return commandfactory(cmd, mode=mode, commandstring=params)
#    elif cmd == 'edit':
#        filepath = os.path.expanduser(params)
#        if os.path.isfile(filepath):
#            return commandfactory(cmd, mode=mode, path=filepath)

__all__ = list(filename[:-3] for filename in glob.glob1(os.path.dirname(__file__), '*.py'))