diff options
author | Mason Larobina <mason.larobina@gmail.com> | 2009-09-20 18:51:44 +0800 |
---|---|---|
committer | Mason Larobina <mason.larobina@gmail.com> | 2009-09-20 18:51:44 +0800 |
commit | 5de17212ff77e1021e2a87b528b51bab173efd8d (patch) | |
tree | 100d9ab957843c96ac8f4ec7d983aa57d2d2c756 /examples/data/uzbl/scripts | |
parent | 41540a5e1085c50fc3c6b5a7fab51ce4d1234926 (diff) |
Added new binding syntax which allows setting a customisable prompt mid-bind.
Diffstat (limited to 'examples/data/uzbl/scripts')
-rwxr-xr-x | examples/data/uzbl/scripts/event_manager.py | 33 | ||||
-rw-r--r-- | examples/data/uzbl/scripts/plugins/bind.py | 200 | ||||
-rw-r--r-- | examples/data/uzbl/scripts/plugins/keycmd.py | 10 |
3 files changed, 190 insertions, 53 deletions
diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index c9be9bb..c5f2eda 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -376,6 +376,17 @@ class UzblInstance(object): self._socket = sock + def _close_socket(self): + '''Close the socket used for communication with the uzbl instance. + This function is normally called upon receiving the INSTANCE_EXIT + event.''' + + if self._socket: + self._socket.close() + + self.uzbl_socket = self._socket = None + + def _flush(self): '''Flush messages from the outgoing queue to the uzbl instance.''' @@ -384,7 +395,7 @@ class UzblInstance(object): h = open(self.uzbl_fifo, 'w') while len(self._fifo_cmd_queue): msg = self._fifo_cmd_queue.pop(0) - print "Sending via fifo: %r" % msg + print '<-- %s' % msg h.write("%s\n" % msg) h.close() @@ -396,7 +407,7 @@ class UzblInstance(object): if self._socket: while len(self._socket_cmd_queue): msg = self._socket_cmd_queue.pop(0) - print "Sending via socket: %r" % msg + print '<-- %s' % msg self._socket.send("%s\n" % msg) @@ -424,7 +435,7 @@ class UzblInstance(object): handler = Handler(event, handler, *args, **kargs) self._handlers[event].append(handler) - print "New event handler:", handler + print handler return handler @@ -488,7 +499,7 @@ class UzblInstance(object): if not msg or msg[0] != "EVENT": # Not an event message - print raw.rstrip() + print "---", raw.rstrip() return event, args = msg[1], msg[3] @@ -558,10 +569,6 @@ class UzblInstance(object): def handle_event(self, event, args): '''Handle uzbl events internally before dispatch.''' - # Silence _printing_ of geo events while still debugging. - if event != "GEOMETRY_CHANGED": - print event, args - if event == 'FIFO_SET': self.uzbl_fifo = args self._flush() @@ -571,7 +578,9 @@ class UzblInstance(object): self._init_uzbl_socket(args) self._flush() - elif event == 'SHUTDOWN': + elif event == 'INSTANCE_EXIT': + self._close_socket() + self._running = False for (name, plugin) in self.plugins.items(): if hasattr(plugin, "cleanup"): plugin.cleanup(uzbl) @@ -608,6 +617,10 @@ class UzblInstance(object): def event(self, event, *args, **kargs): '''Raise a custom event.''' + # Silence _printing_ of geo events while still debugging. + if event != "GEOMETRY_CHANGED": + print "--> %s %s %s" % (event, args, '' if not kargs else kargs) + if event in self._handlers: for handler in self._handlers[event]: try: @@ -630,7 +643,7 @@ if __name__ == "__main__": help="print verbose output.") parser.add_option('-d', '--plugin-dir', dest='plugin_dir', action="store", - metavar="FILE", help="change plugin directory.") + metavar="DIR", help="change plugin directory.") parser.add_option('-p', '--load-plugins', dest="load", action="store", metavar="PLUGINS", help="comma separated list of plugins to load") diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index 2321679..eaa1d40 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -17,10 +17,18 @@ from event_manager import config, counter, iscallable, isiterable __export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] # Hold the bind lists per uzbl instance. -_UZBLS = {} +UZBLS = {} # Commonly used regular expressions. starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]+)>') +find_prompts = re.compile('<([^:>]*):>').split + +# For accessing a bind glob stack. +MOD_CMD, ON_EXEC, HAS_ARGS, GLOB = range(4) + + +class BindParseError(Exception): + pass def echo(msg): @@ -56,21 +64,45 @@ def sort_mods(glob): def add_instance(uzbl, *args): - _UZBLS[uzbl] = [] + UZBLS[uzbl] = {'binds': [], 'depth': 0, 'filter': [], + 'args': [], 'last_mode': ''} def del_instance(uzbl, *args): - if uzbl in _UZBLS: - del _UZBLS[uzbl] + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_bind_dict(uzbl): + '''Return the bind dict for the uzbl instance.''' + + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] def get_binds(uzbl): '''Return the bind list for the uzbl instance.''' - if uzbl not in _UZBLS: - add_instance(uzbl) + return get_bind_dict(uzbl)['binds'] + + +def get_stack_depth(uzbl): + '''Return the stack for the uzbl instance.''' + + return get_bind_dict(uzbl)['depth'] - return _UZBLS[uzbl] + +def get_filtered_binds(uzbl): + '''Return the bind list for the uzbl instance or return the filtered + bind list thats on the current stack.''' + + bind_dict = get_bind_dict(uzbl) + if bind_dict['depth']: + return list(bind_dict['filter']) + + return list(bind_dict['binds']) def del_bind(uzbl, bind): @@ -125,20 +157,35 @@ class Bind(object): self.glob = glob self.bid = self.nextbid() - # Is the binding a MODCMD or KEYCMD. - self.mod_bind = ismodbind(glob) + self.split = split = find_prompts(glob) + self.prompts = split[1::2] - # Execute the command on UPDATES or EXEC's. - self.on_exec = True if glob.endswith('_') else False + # Check that there is nothing like: fl*<int:>* + for glob in split[:-1:2]: + if glob.endswith('*'): + msg = "token '*' not at the end of a prompt bind: %r" % split + raise BindParseError(msg) - if glob[-1] in ['*', '_']: - self.has_args = True - glob = glob[:-1] + # Check that there is nothing like: fl<prompt1:><prompt2:>_ + for glob in split[2::2]: + if not glob: + msg = 'found null segment after first prompt: %r' % split + raise BindParseError(msg) - else: - self.has_args = False + self.stack = [] + + for glob in split[::2]: + # Is the binding a MODCMD or KEYCMD: + mod_cmd = ismodbind(glob) + + # Execute the command on UPDATES or EXEC's: + on_exec = True if glob.endswith('_') else False - self.match = glob + # Does the command store arguments: + has_args = True if glob[-1] in ['*', '_'] else False + glob = glob[:-1] if has_args else glob + + self.stack.append((mod_cmd, on_exec, has_args, glob)) def __repr__(self): @@ -173,11 +220,12 @@ def bind(uzbl, glob, handler, *args, **kargs): bind = Bind(glob, handler, *args, **kargs) binds.append(bind) + print bind uzbl.event('ADDED_BIND', bind) def parse_bind_event(uzbl, args): - '''Parse "event BIND fl* = js follownums.js" commands.''' + '''Break "event BIND fl* = js follownums.js" into (glob, command).''' split = map(str.strip, args.split('=', 1)) if len(split) != 2: @@ -187,68 +235,138 @@ def parse_bind_event(uzbl, args): bind(uzbl, glob, command) -def match_and_exec(uzbl, bind, keylet): +def set_stack_mode(uzbl, prompt): + if uzbl.get_mode() != 'stack': + uzbl.set_mode('stack') - keycmd = keylet.to_string() - if bind.has_args: - if not keycmd.startswith(bind.match): + if prompt: + prompt = "%s: " % prompt + + uzbl.set('keycmd_prompt', prompt) + + +def clear_stack(uzbl, mode): + bind_dict = get_bind_dict(uzbl) + if mode != "stack" and bind_dict['last_mode'] == "stack": + uzbl.set('keycmd_prompt', '') + + if mode != "stack": + bind_dict = get_bind_dict(uzbl) + bind_dict['filter'] = [] + bind_dict['depth'] = 0 + bind_dict['args'] = [] + + bind_dict['last_mode'] = mode + + +def filter_bind(uzbl, bind_dict, bind): + '''Remove a bind from the stack filter list.''' + + if bind in bind_dict['filter']: + bind_dict['filter'].remove(bind) + + if not bind_dict['filter']: + uzbl.set_mode() + + +def match_and_exec(uzbl, bind, depth, keycmd): + bind_dict = get_bind_dict(uzbl) + mode_cmd, on_exec, has_args, glob = bind.stack[depth] + + if has_args: + if not keycmd.startswith(glob): + filter_bind(uzbl, bind_dict, bind) return False - args = [keycmd[len(bind.match):],] + args = [keycmd[len(glob):],] - elif keycmd != bind.match: + elif keycmd != glob: + filter_bind(uzbl, bind_dict, bind) return False else: args = [] - uzbl.exec_handler(bind, *args) + execindex = len(bind.stack)-1 + if execindex == depth == 0: + uzbl.exec_handler(bind, *args) + if not has_args: + uzbl.clear_keycmd() + + return True - if not bind.has_args: - uzbl.clear_keycmd() + elif depth != execindex: + if bind_dict['depth'] == depth: + bind_dict['filter'] = [bind,] + bind_dict['args'] += args + bind_dict['depth'] = depth + 1 + + else: + if bind not in bind_dict['filter']: + bind_dict['filter'].append(bind) + + set_stack_mode(uzbl, bind.prompts[depth]) + return False + + args = bind_dict['args'] + args + uzbl.exec_handler(bind, *args) + if on_exec: + uzbl.set_mode() return True def keycmd_update(uzbl, keylet): - for bind in get_binds(uzbl): - if bind.mod_bind or bind.on_exec: + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if t[MOD_CMD] or t[ON_EXEC]: continue - match_and_exec(uzbl, bind, keylet) + match_and_exec(uzbl, bind, depth, keycmd) def keycmd_exec(uzbl, keylet): - for bind in get_binds(uzbl): - if bind.mod_bind or not bind.on_exec: + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if t[MOD_CMD] or not t[ON_EXEC]: continue - match_and_exec(uzbl, bind, keylet) + match_and_exec(uzbl, bind, depth, keycmd) def modcmd_update(uzbl, keylet): - for bind in get_binds(uzbl): - if not bind.mod_bind or bind.on_exec: + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if not t[MOD_CMD] or t[ON_EXEC]: continue - match_and_exec(uzbl, bind, keylet) + match_and_exec(uzbl, bind, depth, keycmd) def modcmd_exec(uzbl, keylet): - for bind in get_binds(uzbl): - if not bind.mod_bind or not bind.on_exec: + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if not t[MOD_CMD] or not t[ON_EXEC]: continue - match_and_exec(uzbl, bind, keylet) + match_and_exec(uzbl, bind, depth, keycmd) def init(uzbl): - connects = {'BIND': parse_bind_event, 'KEYCMD_UPDATE': keycmd_update, 'MODCMD_UPDATE': modcmd_update, 'KEYCMD_EXEC': keycmd_exec, - 'MODCMD_EXEC': modcmd_exec} + 'MODCMD_EXEC': modcmd_exec, + 'MODE_CHANGED': clear_stack} 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 6377905..886f38f 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -220,9 +220,15 @@ def key_press(uzbl, key): k.cmd += key else: - if len(key) == 1: + config = uzbl.get_config() + if 'keycmd_events' not in config or config['keycmd_events'] == '1': + if len(key) == 1: + cmdmod = True + k.cmd += key + + elif k.cmd: cmdmod = True - k.cmd += key + k.cmd = '' if cmdmod: update_event(uzbl, k) |