diff options
author | 2009-09-11 19:39:21 +0800 | |
---|---|---|
committer | 2009-09-11 19:39:21 +0800 | |
commit | bdbd00854e36785c9d660e66180211b2b4d6fd73 (patch) | |
tree | fe7e1428606f928fd1dc8ad5f26b70ffa3658a48 | |
parent | 980dc1d7b30924fad2464c5fc1ad2801c67c670f (diff) |
Working bind plugin re-write & bindable space in keycmd plugin.
-rw-r--r-- | examples/data/uzbl/scripts/plugins/bind.py | 266 | ||||
-rw-r--r-- | examples/data/uzbl/scripts/plugins/keycmd.py | 51 |
2 files changed, 266 insertions, 51 deletions
diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index b44f706..98f7d4c 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -1,52 +1,260 @@ -'''Plugin provides support for classic uzbl binds. +'''Plugin provides support for binds in uzbl. For example: - bind ZZ = exit -> bind('ZZ', 'exit') - bind o _ = uri %s -> bind('o _', 'uri %s') - bind fl* = sh 'echo %s' -> bind('fl*', "sh 'echo %s'") - bind fl* = -> bind('fl*') + event BIND ZZ = exit -> bind('ZZ', 'exit') + event BIND o _ = uri %s -> bind('o _', 'uri %s') + event BIND fl* = sh 'echo %s' -> bind('fl*', "sh 'echo %s'") And it is also possible to execute a function on activation: bind('DD', myhandler) ''' -__export__ = ['bind',] +import sys +import re +from event_manager import config, counter, iscallable, isiterable -uzbls = {} +# Export these variables/functions to uzbl.<name> +__export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] +# Hold the bind lists per uzbl instance. +_UZBLS = {} -def bind(uzbl, glob, cmd=None): +# Commonly used regular expressions. +starts_with_mod = re.compile('^<([A-Za-z0-9-_]+|.)>') - if uzbl not in uzbls: - uzbls[uzbl] = {} - binds = uzbls[uzbl] - if not cmd: - if glob in binds.keys(): - echo("deleted bind: %r" % self.binds[glob]) - del binds[glob] +def echo(msg): + if config['verbose']: + print "plugin: bind:", msg - d = {'glob': glob, 'once': True, 'hasargs': True, 'cmd': cmd} - if glob.endswith('*'): - d['pre'] = glob.rstrip('*') - d['once'] = False +def error(msg): + sys.stderr.write("plugin: bind: error: %s" % msg) - elif glob.endswith('_'): - d['pre'] = glob.rstrip('_') + +def ismodbind(glob): + '''Return True if the glob specifies a modbind.''' + + return bool(starts_with_mod.match(glob)) + + +def sort_mods(glob): + '''Mods are sorted in the keylet.to_string() result so make sure that + bind commands also have their mod keys sorted.''' + + mods = [] + while True: + match = starts_with_mod.match(glob) + if not match: + break + + end = match.span()[1] + mods.append(glob[:end]) + glob = glob[end:] + + return "%s%s" % (''.join(sorted(mods)), glob) + + +def add_instance(uzbl, *args): + _UZBLS[uzbl] = [] + + # Until the inital event messages over socket bug is resolved put your + # bind events here: + uzbl.event("BIND", "ZZ = exit") + uzbl.event("BIND", "<Ctrl>q = exit") + uzbl.event("BIND", "<Ctrl><Alt>h = uri http://uzbl.org/") + uzbl.event("BIND", "rr = uri http://reddit.com") + + +def del_instance(uzbl, *args): + if uzbl in _UZBLS: + del _UZBLS[uzbl] + + +def get_binds(uzbl): + '''Return the bind list for the uzbl instance.''' + + if uzbl not in _UZBLS: + add_instance(uzbl) + + return _UZBLS[uzbl] + + +def del_bind(uzbl, bind): + '''Delete bind object if bind in the uzbl binds.''' + + binds = get_binds(uzbl) + if bind in binds: + binds.remove(bind) + uzbl.event("DELETED_BIND", bind) + return True + + return False + + +def del_bind_by_glob(uzbl, glob): + '''Delete bind by glob if bind in the uzbl binds.''' + + binds = get_binds(uzbl) + for bind in list(binds): + if bind.glob == glob: + binds.remove(bind) + uzbl.event("DELETED_BIND", bind) + return True + + return False + + +class Bind(object): + + nextbid = counter().next + + def __init__(self, glob, handler, *args, **kargs): + self.callable = iscallable(handler) + + if not glob: + raise ArgumentError('glob cannot be blank') + + if self.callable: + self.function = handler + self.args = args + self.kargs = kargs + + elif kargs: + raise ArgumentError("cannot supply kargs for uzbl commands") + + elif isiterable(handler): + self.commands = handler + + else: + self.commands = [handler,] + list(args) + + self.glob = glob + self.bid = self.nextbid() + + # Is the binding a MODCMD or KEYCMD. + self.mod_bind = ismodbind(glob) + + # Execute the command on UPDATES or EXEC's. + self.on_exec = True if glob.endswith('_') else False + + if glob[-1] in ['*', '_']: + self.has_args = True + glob = glob[:-1] + + else: + self.has_args = False + + self.match = glob + + + def __repr__(self): + args = ["glob=%r" % self.glob, "bid=%d" % self.bid] + + if self.callable: + args.append("function=%r" % self.function) + if self.args: + args.append("args=%r" % self.args) + + if self.kargs: + args.append("kargs=%r" % self.kargs) + + else: + cmdlen = len(self.commands) + cmds = self.commands[0] if cmdlen == 1 else self.commands + args.append("command%s=%r" % ("s" if cmdlen-1 else "", cmds)) + + return "<Bind(%s)>" % ', '.join(args) + + +def bind(uzbl, glob, handler, *args, **kargs): + '''Add a bind handler object.''' + + # Mods come from the keycmd sorted so make sure the modkeys in the bind + # command are sorted too. + glob = sort_mods(glob) + + del_bind_by_glob(uzbl, glob) + binds = get_binds(uzbl) + + bind = Bind(glob, handler, *args, **kargs) + binds.append(bind) + + uzbl.event('ADDED_BIND', bind) + + +def parse_bind_event(uzbl, args): + '''Parse "event BIND fl* = js follownums.js" commands.''' + + if len(args.split('=', 1)) != 2: + error('invalid bind format: %r' % args) + + glob, command = map(str.strip, args.split('=', 1)) + bind(uzbl, glob, command) + + +def match_and_exec(uzbl, bind, keylet): + + keycmd = keylet.to_string() + if bind.has_args: + if not keycmd.startswith(bind.match): + return False + + args = [keycmd[len(bind.match):],] + + elif keycmd != bind.match: + return False else: - d['pre'] = glob - d['hasargs'] = False + args = [] + + uzbl.exec_handler(bind, *args) + + if not bind.has_args: + uzbl.clear_keycmd() + + return True + + +def keycmd_update(uzbl, keylet): + for bind in get_binds(uzbl): + if bind.mod_bind or bind.on_exec: + continue + + match_and_exec(uzbl, bind, keylet) + + +def keycmd_exec(uzbl, keylet): + for bind in get_binds(uzbl): + if bind.mod_bind or not bind.on_exec: + continue + + match_and_exec(uzbl, bind, keylet) + + +def modcmd_update(uzbl, keylet): + for bind in get_binds(uzbl): + if not bind.mod_bind or bind.on_exec: + continue + + match_and_exec(uzbl, bind, keylet) + + +def modcmd_exec(uzbl, keylet): + for bind in get_binds(uzbl): + if not bind.mod_bind or not bind.on_exec: + continue - binds[glob] = d - print "added bind: %r" % d + match_and_exec(uzbl, bind, keylet) def init(uzbl): - uzbl.bind("test", lambda _: True) + connects = {'BIND': parse_bind_event, + 'KEYCMD_UPDATE': keycmd_update, + 'MODCMD_UPDATE': modcmd_update, + 'KEYCMD_EXEC': keycmd_exec, + 'MODCMD_EXEC': modcmd_exec} -def cleanup(uzbl): - if uzbl in uzbls: - del uzbl + for (event, handler) in connects.items(): + uzbl.connect(event, handler) diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index bd38e25..7d835d8 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -10,7 +10,11 @@ _RE_CACHE = {} _UZBLS = {} # Simple key names map. -_SIMPLEKEYS = {'Control': 'Ctrl', 'ISO_Left_Tab': 'Shift-Tab',} +_SIMPLEKEYS = { + 'Control': 'Ctrl', + 'ISO_Left_Tab': 'Shift-Tab', + 'space':'Space', +} def get_regex(regex): @@ -34,8 +38,8 @@ class Keylet(object): # to_string() string building cache. self._to_string = None - self._modcmd = False - self._wasmod = True + self.modcmd = False + self.wasmod = True def __repr__(self): @@ -56,7 +60,7 @@ class Keylet(object): else: self._to_string = ''.join(["<%s>" % key for key in self.held]) if self.cmd: - self._to_string += "+%s" % self.cmd + self._to_string += "%s" % self.cmd return self._to_string @@ -116,10 +120,10 @@ def clear_keycmd(uzbl): k.cmd = "" k._to_string = None - if k._modcmd: - k._wasmod = True + if k.modcmd: + k.wasmod = True - k._modcmd = False + k.modcmd = False uzbl.config['keycmd'] = "" uzbl.event("KEYCMD_CLEAR") @@ -127,7 +131,7 @@ def clear_keycmd(uzbl): def update_event(uzbl, keylet): '''Raise keycmd/modcmd update events.''' - if keylet._modcmd: + if keylet.modcmd: uzbl.config['keycmd'] = keylet.to_string() uzbl.event("MODCMD_UPDATE", keylet) @@ -164,17 +168,17 @@ def key_press(uzbl, key): return cmdmod = False - if k.held and k._wasmod: - k._modcmd = True - k._wasmod = False + if k.held and k.wasmod: + k.modcmd = True + k.wasmod = False cmdmod = True - if key == "space": + if k.cmd and key == "Space": if k.cmd: k.cmd += " " cmdmod = True - elif not k._modcmd and key == 'BackSpace': + elif not k.modcmd and key == 'BackSpace': if k.cmd: k.cmd = k.cmd[:-1] if not k.cmd: @@ -183,19 +187,22 @@ def key_press(uzbl, key): else: cmdmod = True - elif not k._modcmd and key == 'Return': + elif not k.modcmd and key == 'Return': uzbl.event("KEYCMD_EXEC", k) clear_keycmd(uzbl) + elif not k.modcmd and key == 'Escape': + clear_keycmd(uzbl) + elif not k.held and not k.cmd: - k._modcmd = True if len(key) > 1 else False + k.modcmd = True if len(key) > 1 else False k.held.append(key) k.held.sort() cmdmod = True - if not k._modcmd: + if not k.modcmd: k.cmd += key - elif k._modcmd: + elif k.modcmd: cmdmod = True if len(key) > 1: if key not in k.held: @@ -224,7 +231,7 @@ def key_release(uzbl, key): 1. Remove the key from the keylet held list. 2. If the key removed was a mod key and it was in a mod-command then raise a MODCMD_EXEC event then clear the keycmd. - 3. Stop trying to restore mod-command status with _wasmod if both the + 3. Stop trying to restore mod-command status with wasmod if both the keycmd and held list are empty/null. 4. Update the keycmd uzbl variable if anything changed.''' @@ -236,19 +243,19 @@ def key_release(uzbl, key): return cmdmod = False - if k._modcmd and key in k.held: + if k.modcmd and key in k.held: uzbl.event("MODCMD_EXEC", k) k.held.remove(key) k.held.sort() clear_keycmd(uzbl) - elif not k._modcmd and key in k.held: + elif not k.modcmd and key in k.held: k.held.remove(key) k.held.sort() cmdmod = True - if not k.held and not k.cmd and k._wasmod: - k._wasmod = False + if not k.held and not k.cmd and k.wasmod: + k.wasmod = False if cmdmod: update_event(uzbl, k) |