summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugin.py29
-rw-r--r--src/plugin_manager.py50
-rw-r--r--src/tabs.py20
-rw-r--r--src/windows.py18
4 files changed, 110 insertions, 7 deletions
diff --git a/src/plugin.py b/src/plugin.py
index 92adbc4b..137f704f 100644
--- a/src/plugin.py
+++ b/src/plugin.py
@@ -11,6 +11,11 @@ class PluginConfig(config.Config):
RawConfigParser.__init__(self, None)
self.read()
+ def get(self, option, default, section=None):
+ if not section:
+ section = self.module_name
+ return config.Config.get(self, option, default, section)
+
def read(self):
"""Read the config file"""
RawConfigParser.read(self, self.file_name)
@@ -96,6 +101,30 @@ class BasePlugin(object, metaclass=SafetyMetaclass):
"""
return self.plugin_manager.del_command(self.__module__, name)
+ def add_key(self, key, handler):
+ """
+ Add a global keybind
+ """
+ return self.plugin_manager.add_key(self.__module__, key, handler)
+
+ def del_key(self, key):
+ """
+ Remove a global keybind
+ """
+ return self.plugin_manager.del_key(self.__module__, key)
+
+ def add_tab_key(self, tab_type, key, handler):
+ """
+ Add a keybind only for a type of tab.
+ """
+ return self.plugin_manager.add_tab_key(self.__module__, tab_type, key, handler)
+
+ def del_tab_key(self, tab_type, key):
+ """
+ Remove a keybind added through add_tab_key.
+ """
+ return self.plugin_manager.del_tab_key(self.__module__, tab_type, key)
+
def add_tab_command(self, tab_type, name, handler, help, completion=None):
"""
Add a command only for a type of tab.
diff --git a/src/plugin_manager.py b/src/plugin_manager.py
index 437d8ee2..e3b786cb 100644
--- a/src/plugin_manager.py
+++ b/src/plugin_manager.py
@@ -36,6 +36,8 @@ class PluginManager(object):
self.commands = {} # module name -> dict of commands loaded for the module
self.event_handlers = {} # module name -> list of event_name/handler pairs loaded for the module
self.tab_commands = {} #module name -> dict of tab types; tab type -> commands loaded by the module
+ self.keys = {} # module name → dict of keys/handlers loaded for the module
+ self.tab_keys = {} #module name → dict of tab types; tab type → list of keybinds (tuples)
def load(self, name, notify=True):
if name in self.plugins:
@@ -61,6 +63,8 @@ class PluginManager(object):
self.modules[name] = module
self.commands[name] = {}
+ self.keys[name] = {}
+ self.tab_keys[name] = {}
self.tab_commands[name] = {}
self.event_handlers[name] = []
self.plugins[name] = module.Plugin(self, self.core, plugins_conf_dir)
@@ -72,16 +76,23 @@ class PluginManager(object):
try:
for command in self.commands[name].keys():
del self.core.commands[command]
+ for key in self.keys[name].keys():
+ del self.core.key_func[key]
for tab in list(self.tab_commands[name].keys()):
for command in self.tab_commands[name][tab]:
self.del_tab_command(name, getattr(tabs, tab), command[0])
del self.tab_commands[name][tab]
+ for tab in list(self.tab_keys[name].keys()):
+ for key in self.tab_keys[name][tab]:
+ self.del_tab_key(name, getattr(tabs, tab), key[0])
+ del self.tab_keys[name][tab]
for event_name, handler in self.event_handlers[name]:
self.del_event_handler(name, event_name, handler)
self.plugins[name].unload()
del self.plugins[name]
del self.commands[name]
+ del self.keys[name]
del self.tab_commands[name]
del self.event_handlers[name]
if notify:
@@ -122,6 +133,45 @@ class PluginManager(object):
if isinstance(tab, tab_type) and name in tab.commands:
del tab.commands[name]
+ def add_tab_key(self, module_name, tab_type, key, handler):
+ keys = self.tab_keys[module_name]
+ t = tab_type.__name__
+ if key in tab_type.plugin_keys:
+ return
+ if not t in keys:
+ keys[t] = []
+ keys[t].append((key, handler))
+ tab_type.plugin_keys[key] = handler
+ for tab in self.core.tabs:
+ if isinstance(tab, tab_type):
+ tab.update_keys()
+
+ def del_tab_key(self, module_name, tab_type, key):
+ keys = self.tab_keys[module_name]
+ t = tab_type.__name__
+ if not t in keys:
+ return
+ for _key in keys[t]:
+ if _key[0] == key:
+ keys[t].remove(_key)
+ del tab_type.plugin_keys[key]
+ for tab in self.core.tabs:
+ if isinstance(tab, tab_type) and key in tab.key_func:
+ del tab.key_func[key]
+
+ def add_key(self, module_name, key, handler):
+ if key in self.core.key_func:
+ raise Exception(_("Key '%s' already exists") % (key,))
+ keys = self.keys[module_name]
+ keys[key] = handler
+ self.core.key_func[key] = handler
+
+ def del_key(self, module_name, key):
+ if key in self.keys[module_name]:
+ del self.keys[module_name][key]
+ if key in self.core.key_func:
+ del self.core.commands[key]
+
def add_command(self, module_name, name, handler, help, completion=None):
if name in self.core.commands:
raise Exception(_("Command '%s' already exists") % (name,))
diff --git a/src/tabs.py b/src/tabs.py
index feb4be37..fd9755f6 100644
--- a/src/tabs.py
+++ b/src/tabs.py
@@ -228,6 +228,11 @@ class Tab(object):
if not c in self.commands:
self.commands[c] = self.plugin_commands[c]
+ def update_keys(self):
+ for k in self.plugin_keys:
+ if not k in self.key_func:
+ self.key_func[k] = self.plugin_keys[k]
+
def on_lose_focus(self):
"""
called when this tab loses the focus.
@@ -284,6 +289,7 @@ class ChatTab(Tab):
And also, add the /say command
"""
plugin_commands = {}
+ plugin_keys = {}
def __init__(self):
Tab.__init__(self)
self._text_buffer = TextBuffer()
@@ -308,6 +314,7 @@ class ChatTab(Tab):
_('Usage: /clear\nClear: Clear the current buffer.'), None)
self.chat_state = None
self.update_commands()
+ self.update_keys()
def last_words_completion(self):
"""
@@ -448,6 +455,7 @@ class MucTab(ChatTab):
"""
message_type = 'groupchat'
plugin_commands = {}
+ plugin_keys = {}
def __init__(self, jid, nick):
ChatTab.__init__(self)
self.own_nick = nick
@@ -490,6 +498,7 @@ class MucTab(ChatTab):
self.commands['names'] = (self.command_names, _('Usage: /names\nNames: Get the list of the users in the room, and the list of the people assuming the different roles.'), None)
self.resize()
self.update_commands()
+ self.update_keys()
def completion_nick(self, the_input):
"""Completion for /nick"""
@@ -905,7 +914,7 @@ class MucTab(ChatTab):
add_after = after
else:
add_after = ' '
- self.input.auto_completion(word_list, add_after)
+ self.input.auto_completion(word_list, add_after, quotify=False)
empty_after = self.input.get_text() == '' or (self.input.get_text().startswith('/') and not self.input.get_text().startswith('//'))
self.send_composing_chat_state(empty_after)
@@ -1264,6 +1273,7 @@ class PrivateTab(ChatTab):
"""
message_type = 'chat'
plugin_commands = {}
+ plugin_keys = {}
def __init__(self, name, nick):
ChatTab.__init__(self)
self.own_nick = nick
@@ -1283,6 +1293,7 @@ class PrivateTab(ChatTab):
self.parent_muc = self.core.get_tab_by_name(JID(name).bare, MucTab)
self.on = True
self.update_commands()
+ self.update_keys()
def completion(self):
self.complete_commands(self.input)
@@ -1462,6 +1473,7 @@ class RosterInfoTab(Tab):
A tab, splitted in two, containing the roster and infos
"""
plugin_commands = {}
+ plugin_keys = {}
def __init__(self):
Tab.__init__(self)
self.name = "Roster"
@@ -1497,6 +1509,7 @@ class RosterInfoTab(Tab):
self.commands['clear_infos'] = (self.command_clear_infos, _("Usage: /clear_infos\nClear Infos: Use this command to clear the info buffer."), None)
self.resize()
self.update_commands()
+ self.update_keys()
def resize(self):
if not self.visible:
@@ -1980,6 +1993,7 @@ class ConversationTab(ChatTab):
The tab containg a normal conversation (not from a MUC)
"""
plugin_commands = {}
+ plugin_keys = {}
additional_informations = {}
message_type = 'chat'
def __init__(self, jid):
@@ -2000,6 +2014,7 @@ class ConversationTab(ChatTab):
self.commands['info'] = (self.command_info, _('Usage: /info\nInfo: Get the status of the contact.'), None)
self.resize()
self.update_commands()
+ self.update_keys()
@staticmethod
def add_information_element(plugin_name, callback):
@@ -2168,6 +2183,7 @@ class MucListTab(Tab):
scrollable, and letting the user join them, etc
"""
plugin_commands = {}
+ plugin_keys = {}
def __init__(self, server):
Tab.__init__(self)
self.state = 'normal'
@@ -2188,6 +2204,8 @@ class MucListTab(Tab):
self.key_func['^M'] = self.join_selected
self.commands['close'] = (self.close, _("Usage: /close\nClose: Just close this tab."), None)
self.resize()
+ self.update_keys()
+ self.update_commands()
def refresh(self):
if self.need_resize:
diff --git a/src/windows.py b/src/windows.py
index d7471d40..bbae1ab7 100644
--- a/src/windows.py
+++ b/src/windows.py
@@ -940,7 +940,7 @@ class Input(Win):
self.rewrite_text()
return True
- def auto_completion(self, word_list, add_after):
+ def auto_completion(self, word_list, add_after, quotify=True):
"""
Complete the input, from a list of words
if add_after is None, we use the value defined in completion
@@ -948,6 +948,10 @@ class Input(Win):
completion (with no additional space)
"""
completion_type = config.get('completion', 'normal')
+ if quotify:
+ for i, word in enumerate(word_list[:]):
+ if ' ' in word:
+ word_list[i] = '"' + word + '"'
if completion_type == 'shell' and self.text != '':
self.shell_completion(word_list, add_after)
else:
@@ -975,10 +979,12 @@ class Input(Win):
begin = self.text[space_before_cursor+1:pos]
else:
begin = self.text[:pos]
- hit_list = [] # list of matching nicks
+ hit_list = [] # list of matching hits
for word in word_list:
if word.lower().startswith(begin.lower()):
hit_list.append(word)
+ elif word.startswith('"') and word.lower()[1:].startswith(begin.lower()):
+ hit_list.append(word)
if len(hit_list) == 0:
return
self.hit_list = hit_list
@@ -990,18 +996,18 @@ class Input(Win):
self.text = self.text[:pos-end] + self.text[pos:]
pos -= end
- nick = self.hit_list[0] # take the first hit
- self.text = self.text[:pos] + nick + after + self.text[pos:]
+ hit = self.hit_list[0] # take the first hit
+ self.text = self.text[:pos] + hit + after + self.text[pos:]
for i in range(end):
try:
self.key_left(reset=False)
except:
pass
- for i in range(len(nick + after)):
+ for i in range(len(hit + after)):
self.key_right(reset=False)
self.rewrite_text()
- self.last_completion = nick
+ self.last_completion = hit
def shell_completion(self, word_list, after):
"""