alias.py 5.72 KB
Newer Older
1
"""
mathieui's avatar
mathieui committed
2
3
4
5
6
7
8
9
10
11
Usage
-----

This plugin defines two new global commands: :term:`/alias` and :term:`/unalias`.

.. glossary::

    /alias
        **Usage:** ``/alias <name> <command> [args]``

12
13
14
15
16
        This command will create a new command, named ``<name>`` (and callable
        with ``/name``), that runs ``/command``, with ``[args]`` as fixed
        args for the command.
        When you run the alias, you can also pass parameters to it, that will be
        given to the original command.
mathieui's avatar
mathieui committed
17
18
19

        Example: ::

20
            /alias toto say koin
mathieui's avatar
mathieui committed
21

22
        Will bind ``/say koin`` to ``/toto``, so this alias will work in any
mathieui's avatar
mathieui committed
23
24
25
26
27
28
        Chat tab. If someone calls it with ::

            /toto koin

        Poezio will then execute ``/say koin koin``.

29
30
31
32
33
34
35
36
37
38
39
40
        Also, you can rebind arguments arbitrarily, with the ``{}`` placeholder.
        For example, ::

            /alias toto say {} le {}
            /toto loulou coucou

        Will execute ``/say loulou le coucou``, because the ``{}`` are
        replaced with the command args, in the order they are given.

        Extra args are still added at the end of the command if provided
        (args used for the formatting are only used for the formatting).

mathieui's avatar
mathieui committed
41
42
43
44
    /unalias
        **Usage:** ``/unalias <name>``

        This command removes a defined alias.
45

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

Config
------

The aliases are stored inside the configuration file for the plugin.
You can either use the above commands or write it manually, and it
will be read when the plugin is loaded.


Example of the syntax:

.. code-block:: ini

    [alias]
    toto = say {} le {}
    j = join {}@conference.jabber.org/nick
    jp = say je proteste


65
66
"""

mathieui's avatar
mathieui committed
67
from plugin import BasePlugin
68
from common import shell_split
mathieui's avatar
mathieui committed
69

mathieui's avatar
mathieui committed
70
71
72

class Plugin(BasePlugin):
    def init(self):
73
        self.api.add_command('alias', self.command_alias,
74
75
76
                usage='<alias> <command> [args]',
                short='Create an alias command',
                help='Create an alias for <command> with [args].')
77
        self.api.add_command('unalias', self.command_unalias,
78
79
80
81
                usage='<alias>',
                help='Remove a previously created alias',
                short='Remove an alias',
                completion=self.completion_unalias)
mathieui's avatar
mathieui committed
82
        self.commands = {}
83
84
85
86
87
88
89
90
        self.load_conf()

    def load_conf(self):
        """
        load stored aliases on startup
        """
        for alias in self.config.options():
            full = self.config.get(alias, '')
mathieui's avatar
mathieui committed
91
            if full:
mathieui's avatar
mathieui committed
92
                self.command_alias(alias + ' ' + full, silent=True)
mathieui's avatar
mathieui committed
93

mathieui's avatar
mathieui committed
94
    def command_alias(self, line, silent=False):
95
96
97
        """
        /alias <alias> <command> [args]
        """
98
99
        arg = split_args(line)
        if not arg:
mathieui's avatar
mathieui committed
100
101
            if not silent:
                self.api.information('Alias: Not enough parameters', 'Error')
mathieui's avatar
mathieui committed
102
            return
103
        alias, command, args = arg
mathieui's avatar
mathieui committed
104

105
106
107
        if alias in self.commands:
            update = True
        elif alias in self.core.commands:
mathieui's avatar
mathieui committed
108
109
            if not silent:
                self.api.information('Alias: command already exists', 'Error')
mathieui's avatar
mathieui committed
110
            return
111
112
113
114
        else:
            update = False

        self.config.set(alias, command + ' ' + args)
mathieui's avatar
mathieui committed
115
116
        self.commands[alias] = command_wrapper(
                generic_command, lambda: self.get_command(command), args)
117
        self.api.del_command(alias)
mathieui's avatar
mathieui committed
118
119
120
        self.api.add_command(alias, self.commands[alias],
                             'This command is an alias for /%s %s' %
                                (alias, command))
121

mathieui's avatar
mathieui committed
122
123
124
125
126
127
        if not silent:
            if update:
                self.api.information('Alias /%s updated' % alias, 'Info')
            else:
                self.api.information('Alias /%s successfuly created' % alias,
                                 'Info')
mathieui's avatar
mathieui committed
128
129

    def command_unalias(self, alias):
130
131
132
        """
        /unalias <existing alias>
        """
mathieui's avatar
mathieui committed
133
134
        if alias in self.commands:
            del self.commands[alias]
135
            self.api.del_command(alias)
mathieui's avatar
mathieui committed
136
            self.config.remove(alias)
137
            self.api.information('Alias /%s successfuly deleted' % alias, 'Info')
mathieui's avatar
mathieui committed
138

139
    def completion_unalias(self, the_input):
140
        "Completion for /unalias"
141
142
143
144
        aliases = [alias for alias in self.commands]
        aliases.sort()
        return the_input.auto_completion(aliases, '', quotify=False)

mathieui's avatar
mathieui committed
145
146
147
148
149
    def get_command(self, name):
        """Returns the function associated with a command"""
        def dummy(args):
            """Dummy function called if the command doesn’t exist"""
            pass
150
151
152
        if name in self.commands:
            return dummy
        elif name in self.core.commands:
mathieui's avatar
mathieui committed
153
            return self.core.commands[name].func
154
        elif name in self.api.current_tab().commands:
mathieui's avatar
mathieui committed
155
            return self.api.current_tab().commands[name].func
mathieui's avatar
mathieui committed
156
        return dummy
157
158
159
160
161
162
163
164
165
166
167
168

def split_args(line):
    """
    Extract the relevant vars from the command line
    """
    arg = line.split()
    if len(arg) < 2:
        return None
    alias_pos = line.find(' ')
    alias = line[:alias_pos]
    end = line[alias_pos+1:]
    args_pos = end.find(' ')
mathieui's avatar
mathieui committed
169
170
171
172
173
174
    if args_pos == -1:
        command = end
        args = ''
    else:
        command = end[:args_pos]
        args = end[args_pos+1:]
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
    return (alias, command, args)

def generic_command(command, extra_args, args):
    """
    Function that will execute the command and set the relevant
    parameters (format string, etc).
    """
    args = shell_split(args)
    new_extra_args = extra_args.format(*args)
    count = extra_args.count('{}')
    args = args[count:]
    new_extra_args += ' '.join(args)
    return command()(new_extra_args)

def command_wrapper(func, command, extra_args):
    "set the predefined arguments"
    def wrapper(*args, **kwargs):
        return func(command, extra_args, *args, **kwargs)
    return wrapper