aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Mason Larobina <mason.larobina@gmail.com>2009-09-11 19:39:21 +0800
committerGravatar Mason Larobina <mason.larobina@gmail.com>2009-09-11 19:39:21 +0800
commitbdbd00854e36785c9d660e66180211b2b4d6fd73 (patch)
treefe7e1428606f928fd1dc8ad5f26b70ffa3658a48
parent980dc1d7b30924fad2464c5fc1ad2801c67c670f (diff)
Working bind plugin re-write & bindable space in keycmd plugin.
-rw-r--r--examples/data/uzbl/scripts/plugins/bind.py266
-rw-r--r--examples/data/uzbl/scripts/plugins/keycmd.py51
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)