From 84e59b05ff0a17178da9ecdb6c5d084e48b42763 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sun, 21 Aug 2016 15:27:53 +0200 Subject: =?UTF-8?q?Don=E2=80=99t=20call=20input=20completion()=20functions?= =?UTF-8?q?=20inside=20completion=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a placeholder object that can run it afterwards, so that we don’t have side effects inside those functions. --- doc/source/dev/overview.rst | 10 ++++-- plugins/admin.py | 3 +- plugins/alias.py | 3 +- plugins/bob.py | 3 +- plugins/irc.py | 5 +-- plugins/mpd_client.py | 3 +- plugins/otr.py | 5 +-- plugins/ping.py | 5 +-- plugins/quote.py | 3 +- plugins/reminder.py | 9 +++--- plugins/send_delayed.py | 3 +- plugins/tell.py | 5 +-- poezio/core/completions.py | 76 ++++++++++++++++++++++----------------------- poezio/core/structs.py | 16 +++++++++- poezio/plugin_manager.py | 6 ++-- poezio/tabs/basetabs.py | 9 ++++-- poezio/tabs/muctab.py | 31 +++++++++--------- poezio/tabs/rostertab.py | 31 +++++++++--------- 18 files changed, 129 insertions(+), 97 deletions(-) diff --git a/doc/source/dev/overview.rst b/doc/source/dev/overview.rst index fb880073..8711cbcd 100644 --- a/doc/source/dev/overview.rst +++ b/doc/source/dev/overview.rst @@ -88,9 +88,13 @@ structured as key (command name) -> tuple(command function, help string, complet Completions are a bit tricky, but it’s easy once you get used to it: They take an **Input** (a _windows_ class) as a parameter, named the_input -everywhere in the sources. To effectively have a completion, you have to call -**the_input.auto_completion()** or **the_input.new_completion()** with the relevant -parameters before returning from the function. +everywhere in the sources. To effectively have a completion, you have to create +a :py:class:`poezio.core.structs.Completion` object initialized with the +completion you want to call +(**the_input.auto_completion()** or **the_input.new_completion()**) with the +relevant parameters and return it with the function. Previously you would call +the function directly from the completion method, but having side effects +inside it makes it harder to test. .. code-block:: python diff --git a/plugins/admin.py b/plugins/admin.py index 01672014..8c632532 100644 --- a/plugins/admin.py +++ b/plugins/admin.py @@ -53,6 +53,7 @@ For affiliations from poezio.plugin import BasePlugin from poezio.tabs import MucTab +from poezio.core.structs import Completion class Plugin(BasePlugin): """ @@ -113,7 +114,7 @@ class Plugin(BasePlugin): compare_users = lambda x: x.last_talked word_list = [user.nick for user in sorted(tab.users, key=compare_users, reverse=True)\ if user.nick != tab.own_nick] - return the_input.auto_completion(word_list, '') + return Completion(the_input.auto_completion, word_list, '') diff --git a/plugins/alias.py b/plugins/alias.py index 839fa3d8..108fde54 100644 --- a/plugins/alias.py +++ b/plugins/alias.py @@ -66,6 +66,7 @@ Example of the syntax: from poezio.plugin import BasePlugin from poezio.common import shell_split +from poezio.core.structs import Completion class Plugin(BasePlugin): @@ -140,7 +141,7 @@ class Plugin(BasePlugin): "Completion for /unalias" aliases = [alias for alias in self.commands] aliases.sort() - return the_input.auto_completion(aliases, '', quotify=False) + return Completion(the_input.auto_completion, aliases, '', quotify=False) def get_command(self, name): """Returns the function associated with a command""" diff --git a/plugins/bob.py b/plugins/bob.py index b2a6441e..527692b3 100644 --- a/plugins/bob.py +++ b/plugins/bob.py @@ -22,6 +22,7 @@ Configuration options The time during which the file should stay in cache on the receiving side. """ +from poezio.core.structs import Completion from poezio.plugin import BasePlugin from poezio import tabs @@ -72,4 +73,4 @@ class Plugin(BasePlugin): mime_type = guess_type(filename)[0] if mime_type is not None and mime_type.startswith('image/'): images.append(filename) - return the_input.auto_completion(images, quotify=False) + return Completion(the_input.auto_completion, images, quotify=False) diff --git a/plugins/irc.py b/plugins/irc.py index 56ce5c9c..263d7d22 100644 --- a/plugins/irc.py +++ b/plugins/irc.py @@ -131,6 +131,7 @@ Example configuration from poezio.plugin import BasePlugin from poezio.decorators import command_args_parser +from poezio.core.structs import Completion from poezio import common from poezio import tabs @@ -270,7 +271,7 @@ class Plugin(BasePlugin): sections.remove(section) except: pass - return the_input.new_completion(sections, pos) + return Completion(the_input.new_completion, sections, pos) @command_args_parser.quoted(1, 1) def command_irc_join(self, args): @@ -375,6 +376,6 @@ class Plugin(BasePlugin): sections = self.config.sections() if 'irc' in sections: sections.remove('irc') - return the_input.new_completion(sections, 1) + return Completion(the_input.new_completion, sections, 1) diff --git a/plugins/mpd_client.py b/plugins/mpd_client.py index 82e94ad1..6115c0da 100644 --- a/plugins/mpd_client.py +++ b/plugins/mpd_client.py @@ -49,6 +49,7 @@ Usage from poezio.plugin import BasePlugin from poezio.common import shell_split +from poezio.core.structs import Completion from os.path import basename as base from poezio import tabs import mpd @@ -84,4 +85,4 @@ class Plugin(BasePlugin): self.api.information('Cannot send result (%s)' % s, 'Error') def completion_mpd(self, the_input): - return the_input.auto_completion(['full'], quotify=False) + return Completion(the_input.auto_completion, ['full'], quotify=False) diff --git a/plugins/otr.py b/plugins/otr.py index 562bc197..1f41cf71 100644 --- a/plugins/otr.py +++ b/plugins/otr.py @@ -194,6 +194,7 @@ from poezio.plugin import BasePlugin from poezio.tabs import ConversationTab, DynamicConversationTab, PrivateTab from poezio.theming import get_theme, dump_tuple from poezio.decorators import command_args_parser +from poezio.core.structs import Completion OTR_DIR = os.path.join(os.getenv('XDG_DATA_HOME') or '~/.local/share', 'poezio', 'otr') @@ -912,7 +913,7 @@ class Plugin(BasePlugin): Completion for /otr """ comp = ['start', 'fpr', 'ourfpr', 'refresh', 'end', 'trust', 'untrust'] - return the_input.new_completion(comp, 1, quotify=False) + return Completion(the_input.new_completion, comp, 1, quotify=False) @command_args_parser.quoted(1, 2) def command_smp(self, args): @@ -972,7 +973,7 @@ class Plugin(BasePlugin): def completion_smp(the_input): """Completion for /otrsmp""" if the_input.get_argument_position() == 1: - return the_input.new_completion(['ask', 'answer', 'abort'], 1, quotify=False) + return Completion(the_input.new_completion, ['ask', 'answer', 'abort'], 1, quotify=False) def get_tlv(tlvs, cls): """Find the instance of a class in a list""" diff --git a/plugins/ping.py b/plugins/ping.py index 066ad1f6..533053b7 100644 --- a/plugins/ping.py +++ b/plugins/ping.py @@ -27,6 +27,7 @@ from poezio.plugin import BasePlugin from poezio.roster import roster from poezio.common import safeJID from poezio.contact import Contact, Resource +from poezio.core.structs import Completion from poezio import tabs import time @@ -74,7 +75,7 @@ class Plugin(BasePlugin): users = [user.nick for user in self.api.current_tab().users] l = self.resources() users.extend(l) - return the_input.auto_completion(users, '', quotify=False) + return Completion(the_input.auto_completion, users, '', quotify=False) @command_args_parser.raw def command_private_ping(self, arg): @@ -115,5 +116,5 @@ class Plugin(BasePlugin): return l def completion_ping(self, the_input): - return the_input.auto_completion(self.resources(), '', quotify=False) + return Completion(the_input.auto_completion, self.resources(), '', quotify=False) diff --git a/plugins/quote.py b/plugins/quote.py index ba7f4ea3..a5ffd193 100644 --- a/plugins/quote.py +++ b/plugins/quote.py @@ -44,6 +44,7 @@ Options time of the message. """ +from poezio.core.structs import Completion from poezio.plugin import BasePlugin from poezio.xhtml import clean_text from poezio import common @@ -101,5 +102,5 @@ class Plugin(BasePlugin): messages = list(filter(message_match, messages)) elif len(args) > 1: return False - return the_input.auto_completion([clean_text(msg.txt) for msg in messages[::-1]], '') + return Completion(the_input.auto_completion, [clean_text(msg.txt) for msg in messages[::-1]], '') diff --git a/plugins/reminder.py b/plugins/reminder.py index a5ab1f00..f8a69f70 100644 --- a/plugins/reminder.py +++ b/plugins/reminder.py @@ -47,10 +47,11 @@ Will remind you to get up every 1 hour 23 minutes. """ +from poezio.core.structs import Completion from poezio.plugin import BasePlugin -import curses -from poezio import common from poezio import timed_events +from poezio import common +import curses class Plugin(BasePlugin): @@ -107,10 +108,10 @@ class Plugin(BasePlugin): if txt.endswith(' '): n += 1 if n == 2: - return the_input.auto_completion(["60", "5m", "15m", "30m", "1h", "10h", "1d"], '') + return Completion(the_input.auto_completion, ["60", "5m", "15m", "30m", "1h", "10h", "1d"], '') def completion_done(self, the_input): - return the_input.auto_completion(["%s" % key for key in self.tasks], '') + return Completion(the_input.auto_completion, ["%s" % key for key in self.tasks], '') def command_done(self, arg="0"): try: diff --git a/plugins/send_delayed.py b/plugins/send_delayed.py index 8c536ea8..299de6e2 100644 --- a/plugins/send_delayed.py +++ b/plugins/send_delayed.py @@ -19,6 +19,7 @@ This plugin adds a command to the chat tabs. """ from poezio.plugin import BasePlugin +from poezio.core.structs import Completion from poezio.decorators import command_args_parser from poezio import tabs from poezio import common @@ -54,7 +55,7 @@ class Plugin(BasePlugin): if txt.endswith(' '): n += 1 if n == 2: - return the_input.auto_completion(["60", "5m", "15m", "30m", "1h", "10h", "1d"], '') + return Completion(the_input.auto_completion, ["60", "5m", "15m", "30m", "1h", "10h", "1d"], '') def say(self, args=None): if not args: diff --git a/plugins/tell.py b/plugins/tell.py index 2b3eb0ce..ba638e82 100644 --- a/plugins/tell.py +++ b/plugins/tell.py @@ -20,6 +20,7 @@ This plugin defines two new commands for MUC tabs: :term:`/tell` and :term:`/unt """ from poezio.plugin import BasePlugin +from poezio.core.structs import Completion from poezio.decorators import command_args_parser from poezio import tabs @@ -77,6 +78,6 @@ class Plugin(BasePlugin): def completion_untell(self, the_input): tab = self.api.current_tab() if not tab in self.tabs: - return the_input.auto_completion([], '') - return the_input.auto_completion(list(self.tabs[tab]), '', quotify=False) + return Completion(the_input.auto_completion, [], '') + return Completion(the_input.auto_completion, list(self.tabs[tab]), '', quotify=False) diff --git a/poezio/core/completions.py b/poezio/core/completions.py index 7dd2c970..25c23dd6 100644 --- a/poezio/core/completions.py +++ b/poezio/core/completions.py @@ -15,8 +15,7 @@ from poezio.common import safeJID from poezio.config import config from poezio.roster import roster -from poezio.core.structs import POSSIBLE_SHOW - +from poezio.core.structs import POSSIBLE_SHOW, Completion class CompletionCore: def __init__(self, core): @@ -25,15 +24,14 @@ class CompletionCore: def help(self, the_input): """Completion for /help.""" commands = sorted(self.core.commands.keys()) + sorted(self.core.current_tab().commands.keys()) - return the_input.new_completion(commands, 1, quotify=False) - + return Completion(the_input.new_completion, commands, 1, quotify=False) def status(self, the_input): """ Completion of /status """ if the_input.get_argument_position() == 1: - return the_input.new_completion([status for status in POSSIBLE_SHOW], 1, ' ', quotify=False) + return Completion(the_input.new_completion, [status for status in POSSIBLE_SHOW], 1, ' ', quotify=False) def presence(self, the_input): @@ -42,9 +40,9 @@ class CompletionCore: """ arg = the_input.get_argument_position() if arg == 1: - return the_input.auto_completion([jid for jid in roster.jids()], '', quotify=True) + return Completion(the_input.auto_completion, [jid for jid in roster.jids()], '', quotify=True) elif arg == 2: - return the_input.auto_completion([status for status in POSSIBLE_SHOW], '', quotify=True) + return Completion(the_input.auto_completion, [status for status in POSSIBLE_SHOW], '', quotify=True) def theme(self, the_input): @@ -63,7 +61,7 @@ class CompletionCore: theme_files = [name[:-3] for name in names if name.endswith('.py') and name != '__init__.py'] if 'default' not in theme_files: theme_files.append('default') - return the_input.new_completion(theme_files, 1, '', quotify=False) + return Completion(the_input.new_completion, theme_files, 1, '', quotify=False) def win(self, the_input): @@ -72,7 +70,7 @@ class CompletionCore: for tab in self.core.tabs: l.extend(tab.matching_names()) l = [i[1] for i in l] - return the_input.new_completion(l, 1, '', quotify=False) + return Completion(the_input.new_completion, l, 1, '', quotify=False) def join(self, the_input): @@ -107,7 +105,7 @@ class CompletionCore: relevant_rooms.extend(sorted(room[0] for room in bookmarks.items() if room[1])) if the_input.last_completion: - return the_input.new_completion([], 1, quotify=True) + return Completion(the_input.new_completion, [], 1, quotify=True) if jid.user: # we are writing the server: complete the server @@ -116,18 +114,18 @@ class CompletionCore: if tab.joined: serv_list.append('%s@%s' % (jid.user, safeJID(tab.name).host)) serv_list.extend(relevant_rooms) - return the_input.new_completion(serv_list, 1, quotify=True) + return Completion(the_input.new_completion, serv_list, 1, quotify=True) elif args[1].startswith('/'): # we completing only a resource - return the_input.new_completion(['/%s' % self.core.own_nick], 1, quotify=True) + return Completion(the_input.new_completion, ['/%s' % self.core.own_nick], 1, quotify=True) else: - return the_input.new_completion(relevant_rooms, 1, quotify=True) + return Completion(the_input.new_completion, relevant_rooms, 1, quotify=True) def version(self, the_input): """Completion for /version""" comp = reduce(lambda x, y: x + [i.jid for i in y], (roster[jid].resources for jid in roster.jids() if len(roster[jid])), []) - return the_input.new_completion(sorted(comp), 1, quotify=False) + return Completion(the_input.new_completion, sorted(comp), 1, quotify=False) def list(self, the_input): @@ -137,7 +135,7 @@ class CompletionCore: if tab.name not in muc_serv_list: muc_serv_list.append(safeJID(tab.name).server) if muc_serv_list: - return the_input.new_completion(muc_serv_list, 1, quotify=False) + return Completion(the_input.new_completion, muc_serv_list, 1, quotify=False) def move_tab(self, the_input): @@ -146,7 +144,7 @@ class CompletionCore: if n == 1: nodes = [tab.name for tab in self.core.tabs if tab] nodes.remove('Roster') - return the_input.new_completion(nodes, 1, ' ', quotify=True) + return Completion(the_input.new_completion, nodes, 1, ' ', quotify=True) def runkey(self, the_input): @@ -156,7 +154,7 @@ class CompletionCore: list_ = [] list_.extend(self.core.key_func.keys()) list_.extend(self.core.current_tab().key_func.keys()) - return the_input.new_completion(list_, 1, quotify=False) + return Completion(the_input.new_completion, list_, 1, quotify=False) def bookmark(self, the_input): @@ -165,7 +163,7 @@ class CompletionCore: n = the_input.get_argument_position(quoted=True) if n == 2: - return the_input.new_completion(['true', 'false'], 2, quotify=True) + return Completion(the_input.new_completion, ['true', 'false'], 2, quotify=True) if n >= 3: return False @@ -185,23 +183,23 @@ class CompletionCore: if nick not in nicks: nicks.append(nick) jids_list = ['%s/%s' % (jid.bare, nick) for nick in nicks] - return the_input.new_completion(jids_list, 1, quotify=True) + return Completion(the_input.new_completion, jids_list, 1, quotify=True) muc_list = [tab.name for tab in self.core.get_tabs(tabs.MucTab)] muc_list.sort() muc_list.append('*') - return the_input.new_completion(muc_list, 1, quotify=True) + return Completion(the_input.new_completion, muc_list, 1, quotify=True) def remove_bookmark(self, the_input): """Completion for /remove_bookmark""" - return the_input.new_completion([bm.jid for bm in self.core.bookmarks], 1, quotify=False) + return Completion(the_input.new_completion, [bm.jid for bm in self.core.bookmarks], 1, quotify=False) def decline(self, the_input): """Completion for /decline""" n = the_input.get_argument_position(quoted=True) if n == 1: - return the_input.auto_completion(sorted(self.core.pending_invites.keys()), 1, '', quotify=True) + return Completion(the_input.auto_completion, sorted(self.core.pending_invites.keys()), 1, '', quotify=True) def bind(self, the_input): @@ -213,7 +211,7 @@ class CompletionCore: else: return False - return the_input.new_completion(args, n, '', quotify=False) + return Completion(the_input.new_completion, args, n, '', quotify=False) def message(self, the_input): @@ -230,7 +228,7 @@ class CompletionCore: for jid in roster.jids(): if not len(roster[jid]): l.append(jid) - return the_input.new_completion(l, 1, '', quotify=True) + return Completion(the_input.new_completion, l, 1, '', quotify=True) def invite(self, the_input): @@ -242,14 +240,14 @@ class CompletionCore: bares = sorted(roster[contact].bare_jid for contact in roster.jids() if len(roster[contact])) off = sorted(jid for jid in roster.jids() if jid not in bares) comp = comp + bares + off - return the_input.new_completion(comp, n, quotify=True) + return Completion(the_input.new_completion, comp, n, quotify=True) elif n == 2: rooms = [] for tab in self.core.get_tabs(tabs.MucTab): if tab.joined: rooms.append(tab.name) rooms.sort() - return the_input.new_completion(rooms, n, '', quotify=True) + return Completion(the_input.new_completion, rooms, n, '', quotify=True) def activity(self, the_input): @@ -257,20 +255,20 @@ class CompletionCore: n = the_input.get_argument_position(quoted=True) args = common.shell_split(the_input.text) if n == 1: - return the_input.new_completion(sorted(pep.ACTIVITIES.keys()), n, quotify=True) + return Completion(the_input.new_completion, sorted(pep.ACTIVITIES.keys()), n, quotify=True) elif n == 2: if args[1] in pep.ACTIVITIES: l = list(pep.ACTIVITIES[args[1]]) l.remove('category') l.sort() - return the_input.new_completion(l, n, quotify=True) + return Completion(the_input.new_completion, l, n, quotify=True) def mood(self, the_input): """Completion for /mood""" n = the_input.get_argument_position(quoted=True) if n == 1: - return the_input.new_completion(sorted(pep.MOODS.keys()), 1, quotify=True) + return Completion(the_input.new_completion, sorted(pep.MOODS.keys()), 1, quotify=True) def last_activity(self, the_input): @@ -281,7 +279,7 @@ class CompletionCore: if n >= 2: return False comp = reduce(lambda x, y: x + [i.jid for i in y], (roster[jid].resources for jid in roster.jids() if len(roster[jid])), []) - return the_input.new_completion(sorted(comp), 1, '', quotify=False) + return Completion(the_input.new_completion, sorted(comp), 1, '', quotify=False) def server_cycle(self, the_input): @@ -290,7 +288,7 @@ class CompletionCore: for tab in self.core.get_tabs(tabs.MucTab): serv = safeJID(tab.name).server serv_list.add(serv) - return the_input.new_completion(sorted(serv_list), 1, ' ') + return Completion(the_input.new_completion, sorted(serv_list), 1, ' ') def set(self, the_input): @@ -303,7 +301,7 @@ class CompletionCore: if '|' in args[1]: plugin_name, section = args[1].split('|')[:2] if plugin_name not in self.core.plugin_manager.plugins: - return the_input.new_completion([], n, quotify=True) + return Completion(the_input.new_completion, [], n, quotify=True) plugin = self.core.plugin_manager.plugins[plugin_name] end_list = ['%s|%s' % (plugin_name, section) for section in plugin.config.sections()] else: @@ -315,7 +313,7 @@ class CompletionCore: if '|' in args[1]: plugin_name, section = args[1].split('|')[:2] if plugin_name not in self.core.plugin_manager.plugins: - return the_input.new_completion([''], n, quotify=True) + return Completion(the_input.new_completion, [''], n, quotify=True) plugin = self.core.plugin_manager.plugins[plugin_name] end_list = set(plugin.config.options(section or plugin_name)) if plugin.config.default: @@ -334,7 +332,7 @@ class CompletionCore: if '|' in args[1]: plugin_name, section = args[1].split('|')[:2] if plugin_name not in self.core.plugin_manager.plugins: - return the_input.new_completion([''], n, quotify=True) + return Completion(the_input.new_completion, [''], n, quotify=True) plugin = self.core.plugin_manager.plugins[plugin_name] end_list = [str(plugin.config.get(args[2], '', section or plugin_name)), ''] else: @@ -344,7 +342,7 @@ class CompletionCore: end_list = [str(config.get(args[2], '', args[1])), ''] else: return False - return the_input.new_completion(end_list, n, quotify=True) + return Completion(the_input.new_completion, end_list, n, quotify=True) def set_default(self, the_input): @@ -355,13 +353,13 @@ class CompletionCore: if n >= len(args): args.append('') if n == 1 or (n == 2 and config.has_section(args[1])): - return self.set(the_input) + return Completion(self.set, the_input) return False def toggle(self, the_input): "Completion for /toggle" - return the_input.new_completion(config.options('Poezio'), 1, quotify=False) + return Completion(the_input.new_completion, config.options('Poezio'), 1, quotify=False) def bookmark_local(self, the_input): @@ -387,8 +385,8 @@ class CompletionCore: if nick not in nicks: nicks.append(nick) jids_list = ['%s/%s' % (jid.bare, nick) for nick in nicks] - return the_input.new_completion(jids_list, 1, quotify=True) + return Completion(the_input.new_completion, jids_list, 1, quotify=True) muc_list = [tab.name for tab in self.core.get_tabs(tabs.MucTab)] muc_list.append('*') - return the_input.new_completion(muc_list, 1, quotify=True) + return Completion(the_input.new_completion, muc_list, 1, quotify=True) diff --git a/poezio/core/structs.py b/poezio/core/structs.py index 82effd48..7d568f04 100644 --- a/poezio/core/structs.py +++ b/poezio/core/structs.py @@ -3,7 +3,7 @@ Module defining structures useful to the core class and related methods """ __all__ = ['ERROR_AND_STATUS_CODES', 'DEPRECATED_ERRORS', 'POSSIBLE_SHOW', - 'Status', 'Command'] + 'Status', 'Command', 'Completion'] # http://xmpp.org/extensions/xep-0045.html#errorstatus ERROR_AND_STATUS_CODES = { @@ -62,3 +62,17 @@ class Command: self.comp = comp self.short_desc = short_desc self.usage = usage + +class Completion: + """ + A completion result essentially currying the input completion call. + """ + __slots__ = ['func', 'args', 'kwargs', 'comp_list'] + def __init__(self, func, comp_list, *args, **kwargs): + self.func = func + self.comp_list = comp_list + self.args = args + self.kwargs = kwargs + + def run(self): + return self.func(self.comp_list, *self.args, **self.kwargs) diff --git a/poezio/plugin_manager.py b/poezio/plugin_manager.py index 8e08432b..11584b23 100644 --- a/poezio/plugin_manager.py +++ b/poezio/plugin_manager.py @@ -10,7 +10,7 @@ from os import path import logging from poezio import tabs -from poezio.core.structs import Command +from poezio.core.structs import Command, Completion from poezio.plugin import PluginAPI from poezio.config import config @@ -284,7 +284,7 @@ class PluginManager(object): and name != '__init__.py' and not name.startswith('.')] plugins_files.sort() position = the_input.get_argument_position(quoted=False) - return the_input.new_completion(plugins_files, position, '', + return Completion(the_input.new_completion, plugins_files, position, '', quotify=False) def completion_unload(self, the_input): @@ -292,7 +292,7 @@ class PluginManager(object): completion function that completes the name of loaded plugins """ position = the_input.get_argument_position(quoted=False) - return the_input.new_completion(sorted(self.plugins.keys()), position, + return Completion(the_input.new_completion, sorted(self.plugins.keys()), position, '', quotify=False) def on_plugins_dir_change(self, new_value): diff --git a/poezio/tabs/basetabs.py b/poezio/tabs/basetabs.py index dbd57aa4..5e753643 100644 --- a/poezio/tabs/basetabs.py +++ b/poezio/tabs/basetabs.py @@ -20,7 +20,7 @@ import string import time from xml.etree import cElementTree as ET -from poezio.core.structs import Command +from poezio.core.structs import Command, Completion from poezio import timed_events from poezio import windows from poezio import xhtml @@ -230,7 +230,10 @@ class Tab(object): if command.comp is None: return False # There's no completion function else: - return command.comp(the_input) + comp = command.comp(the_input) + if comp: + return comp.run() + return comp return False def execute_command(self, provided_text): @@ -633,7 +636,7 @@ class ChatTab(Tab): def completion_correct(self, the_input): if self.last_sent_message and the_input.get_argument_position() == 1: - return the_input.auto_completion([self.last_sent_message['body']], '', quotify=False) + return Completion(the_input.auto_completion, [self.last_sent_message['body']], '', quotify=False) @property def inactive(self): diff --git a/poezio/tabs/muctab.py b/poezio/tabs/muctab.py index 281237ad..e17ab18b 100644 --- a/poezio/tabs/muctab.py +++ b/poezio/tabs/muctab.py @@ -32,6 +32,7 @@ from poezio.logger import logger from poezio.roster import roster from poezio.theming import get_theme, dump_tuple from poezio.user import User +from poezio.core.structs import Completion SHOW_NAME = { @@ -243,7 +244,7 @@ class MucTab(ChatTab): comp.sort() userlist.extend(comp) - return the_input.auto_completion(userlist, quotify=False) + return Completion(the_input.auto_completion, userlist, quotify=False) def completion_info(self, the_input): """Completion for /info""" @@ -251,7 +252,7 @@ class MucTab(ChatTab): userlist = [] for user in sorted(self.users, key=compare_users, reverse=True): userlist.append(user.nick) - return the_input.auto_completion(userlist, quotify=False) + return Completion(the_input.auto_completion, userlist, quotify=False) def completion_nick(self, the_input): """Completion for /nick""" @@ -259,11 +260,11 @@ class MucTab(ChatTab): config.get('default_nick'), self.core.get_bookmark_nickname(self.name)] nicks = [i for i in nicks if i] - return the_input.auto_completion(nicks, '', quotify=False) + return Completion(the_input.auto_completion, nicks, '', quotify=False) def completion_recolor(self, the_input): if the_input.get_argument_position() == 1: - return the_input.new_completion(['random'], 1, '', quotify=False) + return Completion(the_input.new_completion, ['random'], 1, '', quotify=False) return True def completion_color(self, the_input): @@ -273,13 +274,13 @@ class MucTab(ChatTab): userlist = [user.nick for user in self.users] if self.own_nick in userlist: userlist.remove(self.own_nick) - return the_input.new_completion(userlist, 1, '', quotify=True) + return Completion(the_input.new_completion, userlist, 1, '', quotify=True) elif n == 2: colors = [i for i in xhtml.colors if i] colors.sort() colors.append('unset') colors.append('random') - return the_input.new_completion(colors, 2, '', quotify=False) + return Completion(the_input.new_completion, colors, 2, '', quotify=False) def completion_ignore(self, the_input): """Completion for /ignore""" @@ -287,7 +288,7 @@ class MucTab(ChatTab): if self.own_nick in userlist: userlist.remove(self.own_nick) userlist.sort() - return the_input.auto_completion(userlist, quotify=False) + return Completion(the_input.auto_completion, userlist, quotify=False) def completion_role(self, the_input): """Completion for /role""" @@ -296,10 +297,10 @@ class MucTab(ChatTab): userlist = [user.nick for user in self.users] if self.own_nick in userlist: userlist.remove(self.own_nick) - return the_input.new_completion(userlist, 1, '', quotify=True) + return Completion(the_input.new_completion, userlist, 1, '', quotify=True) elif n == 2: possible_roles = ['none', 'visitor', 'participant', 'moderator'] - return the_input.new_completion(possible_roles, 2, '', + return Completion(the_input.new_completion, possible_roles, 2, '', quotify=True) def completion_affiliation(self, the_input): @@ -313,11 +314,11 @@ class MucTab(ChatTab): if self.core.xmpp.boundjid.bare in jidlist: jidlist.remove(self.core.xmpp.boundjid.bare) userlist.extend(jidlist) - return the_input.new_completion(userlist, 1, '', quotify=True) + return Completion(the_input.new_completion, userlist, 1, '', quotify=True) elif n == 2: possible_affiliations = ['none', 'member', 'admin', 'owner', 'outcast'] - return the_input.new_completion(possible_affiliations, 2, '', + return Completion(the_input.new_completion, possible_affiliations, 2, '', quotify=True) @command_args_parser.quoted(1, 1, ['']) @@ -332,7 +333,7 @@ class MucTab(ChatTab): """Completion for /invite""" n = the_input.get_argument_position(quoted=True) if n == 1: - return the_input.new_completion(roster.jids(), 1, quotify=True) + return Completion(the_input.new_completion, roster.jids(), 1, quotify=True) def scroll_user_list_up(self): self.user_win.scroll_up() @@ -714,7 +715,7 @@ class MucTab(ChatTab): def completion_topic(self, the_input): if the_input.get_argument_position() == 1: - return the_input.auto_completion([self.topic], '', quotify=False) + return Completion(the_input.auto_completion, [self.topic], '', quotify=False) def completion_quoted(self, the_input): """Nick completion, but with quotes""" @@ -725,7 +726,7 @@ class MucTab(ChatTab): if user.nick != self.own_nick: word_list.append(user.nick) - return the_input.new_completion(word_list, 1, quotify=True) + return Completion(the_input.new_completion, word_list, 1, quotify=True) @command_args_parser.quoted(1, 1) def command_kick(self, args): @@ -914,7 +915,7 @@ class MucTab(ChatTab): def completion_unignore(self, the_input): if the_input.get_argument_position() == 1: users = [user.nick for user in self.ignores] - return the_input.auto_completion(users, quotify=False) + return Completion(the_input.auto_completion, users, quotify=False) def resize(self): """ diff --git a/poezio/tabs/rostertab.py b/poezio/tabs/rostertab.py index f8b3e906..64aae731 100644 --- a/poezio/tabs/rostertab.py +++ b/poezio/tabs/rostertab.py @@ -25,6 +25,7 @@ from poezio.decorators import refresh_wrapper from poezio.roster import RosterGroup, roster from poezio.theming import get_theme, dump_tuple from poezio.decorators import command_args_parser +from poezio.core.structs import Completion from poezio.tabs import Tab @@ -277,7 +278,7 @@ class RosterInfoTab(Tab): elif n == 2: return self.completion_file(2, the_input) elif n == 3: - return the_input.new_completion(['true', 'false'], n) + return Completion(the_input.new_completion, ['true', 'false'], n) @command_args_parser.quoted(1) def command_cert_disable(self, args): @@ -399,7 +400,7 @@ class RosterInfoTab(Tab): """ if the_input.get_argument_position() == 1: jids = roster.jids() - return the_input.new_completion(jids, 1, '', quotify=False) + return Completion(the_input.new_completion, jids, 1, '', quotify=False) @command_args_parser.quoted(0, 1) def command_unblock(self, args): @@ -429,7 +430,7 @@ class RosterInfoTab(Tab): if iq['type'] == 'error': return l = sorted(str(item) for item in iq['blocklist']['items']) - return the_input.new_completion(l, 1, quotify=False) + return Completion(the_input.new_completion, l, 1, quotify=False) if the_input.get_argument_position(): self.core.xmpp.plugin['xep_0191'].get_blocked(callback=on_result) @@ -544,7 +545,7 @@ class RosterInfoTab(Tab): if n == complete_number: if args[n-1] == '' or len(args) < n+1: home = os.getenv('HOME') or '/' - return the_input.new_completion([home, '/tmp'], n, quotify=True) + return Completion(the_input.new_completion, [home, '/tmp'], n, quotify=True) path_ = args[n] if path.isdir(path_): dir_ = path_ @@ -567,7 +568,7 @@ class RosterInfoTab(Tab): if not name.startswith('.'): end_list.append(value) - return the_input.new_completion(end_list, n, quotify=True) + return Completion(the_input.new_completion, end_list, n, quotify=True) @command_args_parser.ignored def command_clear(self): @@ -872,24 +873,24 @@ class RosterInfoTab(Tab): Completion for /remove """ jids = [jid for jid in roster.jids()] - return the_input.auto_completion(jids, '', quotify=False) + return Completion(the_input.auto_completion, jids, '', quotify=False) def completion_name(self, the_input): """Completion for /name""" n = the_input.get_argument_position() if n == 1: jids = [jid for jid in roster.jids()] - return the_input.new_completion(jids, n, quotify=True) + return Completion(the_input.new_completion, jids, n, quotify=True) return False def completion_groupadd(self, the_input): n = the_input.get_argument_position() if n == 1: jids = sorted(jid for jid in roster.jids()) - return the_input.new_completion(jids, n, '', quotify=True) + return Completion(the_input.new_completion, jids, n, '', quotify=True) elif n == 2: groups = sorted(group for group in roster.groups if group != 'none') - return the_input.new_completion(groups, n, '', quotify=True) + return Completion(the_input.new_completion, groups, n, '', quotify=True) return False def completion_groupmove(self, the_input): @@ -897,7 +898,7 @@ class RosterInfoTab(Tab): n = the_input.get_argument_position() if n == 1: jids = sorted(jid for jid in roster.jids()) - return the_input.new_completion(jids, n, '', quotify=True) + return Completion(the_input.new_completion, jids, n, '', quotify=True) elif n == 2: contact = roster[args[1]] if not contact: @@ -905,10 +906,10 @@ class RosterInfoTab(Tab): groups = list(contact.groups) if 'none' in groups: groups.remove('none') - return the_input.new_completion(groups, n, '', quotify=True) + return Completion(the_input.new_completion, groups, n, '', quotify=True) elif n == 3: groups = sorted(group for group in roster.groups) - return the_input.new_completion(groups, n, '', quotify=True) + return Completion(the_input.new_completion, groups, n, '', quotify=True) return False def completion_groupremove(self, the_input): @@ -916,7 +917,7 @@ class RosterInfoTab(Tab): n = the_input.get_argument_position() if n == 1: jids = sorted(jid for jid in roster.jids()) - return the_input.new_completion(jids, n, '', quotify=True) + return Completion(the_input.new_completion, jids, n, '', quotify=True) elif n == 2: contact = roster[args[1]] if contact is None: @@ -926,7 +927,7 @@ class RosterInfoTab(Tab): groups.remove('none') except ValueError: pass - return the_input.new_completion(groups, n, '', quotify=True) + return Completion(the_input.new_completion, groups, n, '', quotify=True) return False def completion_deny(self, the_input): @@ -936,7 +937,7 @@ class RosterInfoTab(Tab): """ jids = sorted(str(contact.bare_jid) for contact in roster.contacts.values() if contact.pending_in) - return the_input.new_completion(jids, 1, '', quotify=False) + return Completion(the_input.new_completion, jids, 1, '', quotify=False) @command_args_parser.quoted(0, 1) def command_accept(self, args): -- cgit v1.2.3