summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2011-11-14 00:56:15 +0100
committerFlorent Le Coz <louiz@louiz.org>2011-11-14 00:56:15 +0100
commitf0f9f670b9084761023ba9c594b97a0ad37581ed (patch)
treea6a3b72d68f0f5783875cd721ce5e6686009078a
parent3ea5eb6163181ba016cfddcc616a171d7f309e76 (diff)
parent920c43dae25b06fd843dc8f8cbbf5e6bc5bf91c0 (diff)
downloadpoezio-f0f9f670b9084761023ba9c594b97a0ad37581ed.tar.gz
poezio-f0f9f670b9084761023ba9c594b97a0ad37581ed.tar.bz2
poezio-f0f9f670b9084761023ba9c594b97a0ad37581ed.tar.xz
poezio-f0f9f670b9084761023ba9c594b97a0ad37581ed.zip
Merge branch 'master' of http://git.louiz.org/poezio
-rw-r--r--doc/en/plugins.txt43
-rw-r--r--doc/en/plugins/gpg.txt2
-rw-r--r--plugins/mpd_client.py2
-rw-r--r--plugins/reminder.py56
-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
8 files changed, 208 insertions, 12 deletions
diff --git a/doc/en/plugins.txt b/doc/en/plugins.txt
index 87f09cb7..f31086dc 100644
--- a/doc/en/plugins.txt
+++ b/doc/en/plugins.txt
@@ -61,16 +61,47 @@ Everything else is handled by that _auto_completion()_ method (checking what
special completion for that command, just pass None (the default value).
*del_command*:: +self+, +name+ +
-This command removes a tab command added by your plugin.
+This method removes a command added by your plugin.
* _name_: (string) the name of the command you want to remove.
+*add_key*:: +self+, +key+, +handler+ +
+This method adds a global keyboard shortcut on _key_ that will call _handler_.
+You can get the keys with _python3 src/keyboard.py_.
+
+* _key_: String representing the key press in curses.
+* _handler_: Method called whenever _key_ is pressed.
+
+*del_key*:: +self+, +key+ +
+This method deletes a keyboard shortcut previously added by your plugin.
+
+* _key_: String representing the key press in curses.
+
+*add_tab_key*:: +self+, +tab_type+, +key+, +handler+ +
+This method adds a tab-custom command to poezio. For example you can add _^G_
+keybind that the user could call in a specific tab when the plugin is loaded.
+
+* _tab_type_: You have to _import tabs_ in order to get tabs types. The
+ following are possible:
+** _tabs.MucTab_: The MultiUserChat tabs
+** _tabs.PrivateTab_: The Private tabs
+** _tabs.ConversationTab_: The Roster tab
+** _tabs.RosterInfoTab_: The MultiUserChat, Private, and Conversation tabs
+** _tabs.ChatTab_: The MultiUserChat, Private, and Conversation tabs
+** _tabs.MucListTab_: The MultiUserChat list tabs
+* _key_: (string) the curses representation of the keypress (see above).
+* _handler_: (function) the handler to be called when the keypress is found.
+
+*del_tab_command*:: +self+, +tab_type+, +key+
+This method removes a tab command added by your plugin.
+
+* _key_: (string) the name of the keybind you want to remove.
+* _tab_type_: the type of tab (see help for _add_key_command_)
*add_tab_command*:: +self+, +tab_type+, +name+, +handler+, +help+, +completion+ +
-This method adds a tab-custom command to poezio. For example you can add /dou
+This method adds a tab-custom command to poezio. For example you can add a /dou
command that the user could call in a specific tab when the plugin is loaded.
-
* _tab_type_: You have to _import tabs_ in order to get tabs types. The
following are possible:
** _tabs.MucTab_: The MultiUserChat tabs
@@ -95,6 +126,12 @@ Everything else is handled by that _auto_completion()_ method (checking what
strings match, how to cycle between matches, etc). If you don’t want any
special completion for that command, just pass None (the default value).
+*del_tab_command*:: +self+, +tab_type+, +name+
+This method removes a tab command added by your plugin.
+
+* _name_: (string) the name of the command you want to remove.
+* _tab_type_: the type of tab (see help for _add_tab_command_)
+
*add_event_handler**: +self+, +event_name+, +handler+ +position+
This methods adds a callback that will be called whenever the given event
occurs. <<example-2,ex 2>>
diff --git a/doc/en/plugins/gpg.txt b/doc/en/plugins/gpg.txt
index 9e87b6c7..70a6fd15 100644
--- a/doc/en/plugins/gpg.txt
+++ b/doc/en/plugins/gpg.txt
@@ -35,7 +35,7 @@ default), and fill it like this:
[source,python]
---------------------------------------------------------------------
-[Poezio]
+[gpg]
keyid = 091F9C78
passphrase = your OPTIONAL passphrase
diff --git a/plugins/mpd_client.py b/plugins/mpd_client.py
index b56e0d7f..833599ae 100644
--- a/plugins/mpd_client.py
+++ b/plugins/mpd_client.py
@@ -21,7 +21,7 @@ class Plugin(BasePlugin):
s = '%(artist)s - %(title)s (%(album)s)' % current
if 'full' in args:
pourcentage = int(current_time / float(current['time']) * 10)
- s += ' \x192[\x191' + '-'*(pourcentage-1) + '\x193+' + '\x191' + '-' * (10-pourcentage-1) + '\x192]\x19o'
+ s += ' \x192}[\x191}' + '-'*(pourcentage-1) + '\x193}+' + '\x191}' + '-' * (10-pourcentage-1) + '\x192}]\x19o'
if not self.core.send_message('%s' % (s,)):
self.core.information('Cannot send result (%s), this is not a conversation tab' % result)
diff --git a/plugins/reminder.py b/plugins/reminder.py
new file mode 100644
index 00000000..eb63efde
--- /dev/null
+++ b/plugins/reminder.py
@@ -0,0 +1,56 @@
+from plugin import BasePlugin
+import curses
+import common
+import timed_events
+
+class Plugin(BasePlugin):
+
+ def init(self):
+ self.add_command('remind', self.command_remind, "Usage: /reminder <time in seconds> <todo>\nReminder: remind you of <todo> every <time> seconds..", None)
+ self.add_command('done', self.command_done, "Usage: /done <id>\nDone: Stop reminding you do the task identified by <id>", None)
+ self.add_command('tasks', self.command_tasks, "Usage: /tasks\nTasks: List all the current tasks and their ids.", None)
+ self.tasks = {}
+ self.count = 0
+
+ def command_remind(self, arg):
+ args = common.shell_split(arg)
+ if len(args) < 2:
+ return
+ try:
+ time = int(args[0])
+ except:
+ return
+
+ self.tasks[self.count] = (time, args[1])
+ timed_event = timed_events.DelayedEvent(time, self.remind, self.count)
+ self.core.add_timed_event(timed_event)
+ self.count += 1
+
+ def command_done(self, arg="0"):
+ try:
+ id = int(arg)
+ except:
+ return
+ if not id in self.tasks:
+ return
+
+ del self.tasks[id]
+
+ def command_tasks(self, arg):
+ s = ''
+ for key in self.tasks:
+ s += '%s: %s\n' % key, self.tasks[key][1]
+ if s:
+ self.core.information(s, 'Info')
+
+ def remind(self, id=0):
+ if not id in self.tasks:
+ return
+ self.core.information('Task %s: %s' % (id, self.tasks[id][1]), 'Info')
+ if self.config.get('beep', '') == 'true':
+ curses.beep()
+ timed_event = timed_events.DelayedEvent(self.tasks[id][0], self.remind, id)
+ self.core.add_timed_event(timed_event)
+
+
+
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):
"""