diff options
Diffstat (limited to 'examples/data/plugins')
-rw-r--r-- | examples/data/plugins/bind.py | 63 | ||||
-rw-r--r-- | examples/data/plugins/cmd_expand.py | 6 | ||||
-rw-r--r-- | examples/data/plugins/completion.py | 129 | ||||
-rw-r--r-- | examples/data/plugins/config.py | 129 | ||||
-rw-r--r-- | examples/data/plugins/keycmd.py | 121 | ||||
-rw-r--r-- | examples/data/plugins/mode.py | 204 | ||||
-rw-r--r-- | examples/data/plugins/on_event.py | 69 | ||||
-rw-r--r-- | examples/data/plugins/on_set.py | 92 | ||||
-rw-r--r-- | examples/data/plugins/plugin_template.py | 76 | ||||
-rw-r--r-- | examples/data/plugins/progress_bar.py | 152 |
10 files changed, 373 insertions, 668 deletions
diff --git a/examples/data/plugins/bind.py b/examples/data/plugins/bind.py index a1a5d89..5b13476 100644 --- a/examples/data/plugins/bind.py +++ b/examples/data/plugins/bind.py @@ -11,10 +11,6 @@ And it is also possible to execute a function on activation: import sys import re -import pprint - -# Hold the bind dicts for each uzbl instance. -UZBLS = {} # Commonly used regular expressions. MOD_START = re.compile('^<([A-Z][A-Za-z0-9-_]*)>').match @@ -62,9 +58,9 @@ class Bindlet(object): if self.last_mode: mode, self.last_mode = self.last_mode, None - self.uzbl.set_mode(mode) + self.uzbl.config['mode'] = mode - self.uzbl.set('keycmd_prompt') + del self.uzbl.config['keycmd_prompt'] def stack(self, bind, args, depth): @@ -76,10 +72,10 @@ class Bindlet(object): return - current_mode = self.uzbl.get_mode() - if current_mode != 'stack': - self.last_mode = current_mode - self.uzbl.set_mode('stack') + mode = self.uzbl.config.get('mode', None) + if mode != 'stack': + self.last_mode = mode + self.uzbl.config['mode'] = 'stack' self.stack_binds = [bind,] self.args += args @@ -97,7 +93,7 @@ class Bindlet(object): self.uzbl.clear_keycmd() if prompt: - self.uzbl.set('keycmd_prompt', prompt) + self.uzbl.config['keycmd_prompt'] = prompt if set and is_cmd: self.uzbl.send(set) @@ -111,7 +107,7 @@ class Bindlet(object): the filtered stack list and modkey & non-stack globals.''' if mode is None: - mode = self.uzbl.get_mode() + mode = self.uzbl.config.get('mode', None) if not mode: mode = 'global' @@ -145,24 +141,6 @@ class Bindlet(object): self.globals.append(bind) -def add_instance(uzbl, *args): - UZBLS[uzbl] = Bindlet(uzbl) - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_bindlet(uzbl): - '''Return the bind tracklet for the given uzbl instance.''' - - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - def ismodbind(glob): '''Return True if the glob specifies a modbind.''' @@ -324,7 +302,7 @@ def exec_bind(uzbl, bind, *args, **kargs): def mode_bind(uzbl, modes, glob, handler=None, *args, **kargs): '''Add a mode bind.''' - bindlet = get_bindlet(uzbl) + bindlet = uzbl.bindlet if not hasattr(modes, '__iter__'): modes = unicode(modes).split(',') @@ -400,7 +378,8 @@ def mode_changed(uzbl, mode): '''Clear the stack on all non-stack mode changes.''' if mode != 'stack': - get_bindlet(uzbl).reset() + uzbl.bindlet.reset() + uzbl.clear_keycmd() def match_and_exec(uzbl, bind, depth, keylet, bindlet): @@ -440,7 +419,7 @@ def match_and_exec(uzbl, bind, depth, keylet, bindlet): args = bindlet.args + args exec_bind(uzbl, bind, *args) if not has_args or on_exec: - uzbl.set_mode() + del uzbl.config['mode'] bindlet.reset() uzbl.clear_current() @@ -448,7 +427,7 @@ def match_and_exec(uzbl, bind, depth, keylet, bindlet): def key_event(uzbl, keylet, mod_cmd=False, on_exec=False): - bindlet = get_bindlet(uzbl) + bindlet = uzbl.bindlet depth = bindlet.depth for bind in bindlet.get_binds(): t = bind[depth] @@ -463,12 +442,14 @@ def key_event(uzbl, keylet, mod_cmd=False, on_exec=False): # Return to the previous mode if the KEYCMD_EXEC keycmd doesn't match any # binds in the stack mode. if on_exec and not mod_cmd and depth and depth == bindlet.depth: - uzbl.set_mode() + del uzbl.config['mode'] +# plugin init hook def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ + '''Export functions and connect handlers to events.''' + + connect_dict(uzbl, { 'BIND': parse_bind, 'MODE_BIND': parse_mode_bind, 'MODE_CHANGED': mode_changed, @@ -481,12 +462,10 @@ def init(uzbl): for mod_cmd in range(2): for on_exec in range(2): event = events[mod_cmd][on_exec] - uzbl.connect(event, key_event, bool(mod_cmd), bool(on_exec)) + connect(uzbl, event, key_event, bool(mod_cmd), bool(on_exec)) - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ + export_dict(uzbl, { 'bind': bind, 'mode_bind': mode_bind, - 'get_bindlet': get_bindlet, + 'bindlet': Bindlet(uzbl), }) diff --git a/examples/data/plugins/cmd_expand.py b/examples/data/plugins/cmd_expand.py index 3f6ae2b..b007975 100644 --- a/examples/data/plugins/cmd_expand.py +++ b/examples/data/plugins/cmd_expand.py @@ -35,8 +35,6 @@ def cmd_expand(uzbl, cmd, args): return cmd - +# plugin init hook def init(uzbl): - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export('cmd_expand', cmd_expand) + export(uzbl, 'cmd_expand', cmd_expand) diff --git a/examples/data/plugins/completion.py b/examples/data/plugins/completion.py index 8cea203..e8c7f34 100644 --- a/examples/data/plugins/completion.py +++ b/examples/data/plugins/completion.py @@ -1,19 +1,10 @@ '''Keycmd completion.''' -# A list of functions this plugin exports to be used via uzbl object. -__export__ = ['start_completion', 'get_completion_dict'] - import re -# Holds the per-instance completion dicts. -UZBLS = {} - # Completion level NONE, ONCE, LIST, COMPLETE = range(4) -# Default instance dict. -DEFAULTS = {'completions': [], 'level': NONE, 'lock': False} - # The reverse keyword finding re. FIND_SEGMENT = re.compile("(\@[\w_]+|set[\s]+[\w_]+|[\w_]+)$").findall @@ -21,39 +12,17 @@ FIND_SEGMENT = re.compile("(\@[\w_]+|set[\s]+[\w_]+|[\w_]+)$").findall LIST_FORMAT = "<span> %s </span>" ITEM_FORMAT = "<span @hint_style>%s</span>%s" - def escape(str): return str.replace("@", "\@") -def add_instance(uzbl, *args): - UZBLS[uzbl] = dict(DEFAULTS) - - # Make sure the config keys for all possible completions are known. - uzbl.send('dump_config_as_events') - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_completion_dict(uzbl): - '''Get data stored for an instance.''' - - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - def get_incomplete_keyword(uzbl): '''Gets the segment of the keycmd leading up to the cursor position and uses a regular expression to search backwards finding parially completed keywords or @variables. Returns a null string if the correct completion conditions aren't met.''' - keylet = uzbl.get_keylet() + keylet = uzbl.keylet left_segment = keylet.keycmd[:keylet.cursor] partial = (FIND_SEGMENT(left_segment) + ['',])[0].lstrip() if partial.startswith('set '): @@ -65,9 +34,8 @@ def get_incomplete_keyword(uzbl): def stop_completion(uzbl, *args): '''Stop command completion and return the level to NONE.''' - d = get_completion_dict(uzbl) - d['level'] = NONE - uzbl.set('completion_list') + uzbl.completion.level = NONE + del uzbl.config['completion_list'] def complete_completion(uzbl, partial, hint, set_completion=False): @@ -99,46 +67,46 @@ def update_completion_list(uzbl, *args): if not partial: return stop_completion(uzbl) - d = get_completion_dict(uzbl) - if d['level'] < LIST: + if uzbl.completion.level < LIST: return - hints = [h for h in d['completions'] if h.startswith(partial)] + hints = filter(lambda h: h.startswith(partial), uzbl.completion) if not hints: - return uzbl.set('completion_list') + del uzbl.config['completion_list'] + return j = len(partial) l = [ITEM_FORMAT % (escape(h[:j]), h[j:]) for h in sorted(hints)] - uzbl.set('completion_list', LIST_FORMAT % ' '.join(l)) + uzbl.config['completion_list'] = LIST_FORMAT % ' '.join(l) def start_completion(uzbl, *args): - d = get_completion_dict(uzbl) - if d['lock']: + comp = uzbl.completion + if comp.locked: return (partial, set_completion) = get_incomplete_keyword(uzbl) if not partial: return stop_completion(uzbl) - if d['level'] < COMPLETE: - d['level'] += 1 + if comp.level < COMPLETE: + comp.level += 1 - hints = [h for h in d['completions'] if h.startswith(partial)] + hints = filter(lambda h: h.startswith(partial), comp) if not hints: return elif len(hints) == 1: - d['lock'] = True + comp.lock() complete_completion(uzbl, partial, hints[0], set_completion) - d['lock'] = False + comp.unlock() return - elif partial in hints and d['level'] == COMPLETE: - d['lock'] = True + elif partial in hints and comp.level == COMPLETE: + comp.lock() complete_completion(uzbl, partial, partial, set_completion) - d['lock'] = False + comp.unlock() return smalllen, smallest = sorted([(len(h), h) for h in hints])[0] @@ -156,51 +124,56 @@ def start_completion(uzbl, *args): common += char if common: - d['lock'] = True + comp.lock() partial_completion(uzbl, partial, partial+common) - d['lock'] = False + comp.unlock() update_completion_list(uzbl) -def add_builtins(uzbl, args): +def add_builtins(uzbl, builtins): '''Pump the space delimited list of builtin commands into the builtin list.''' - completions = get_completion_dict(uzbl)['completions'] - builtins = filter(None, map(unicode.strip, args.split(" "))) - for builtin in builtins: - if builtin not in completions: - completions.append(builtin) + uzbl.completion.update(builtins.split()) def add_config_key(uzbl, key, value): '''Listen on the CONFIG_CHANGED event and add config keys to the variable list for @var<Tab> like expansion support.''' - completions = get_completion_dict(uzbl)['completions'] - key = "@%s" % key - if key not in completions: - completions.append(key) + uzbl.completion.add("@%s" % key) + + +class Completions(set): + def __init__(self): + set.__init__(self) + self.locked = False + self.level = NONE + + def lock(self): + self.locked = True + + def unlock(self): + self.locked = False def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ - 'BUILTINS': add_builtins, - 'CONFIG_CHANGED': add_config_key, - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'KEYCMD_CLEARED': stop_completion, - 'KEYCMD_EXEC': stop_completion, - 'KEYCMD_UPDATE': update_completion_list, - 'START_COMPLETION': start_completion, - 'STOP_COMPLETION': stop_completion, + '''Export functions and connect handlers to events.''' + + export_dict(uzbl, { + 'completion': Completions(), + 'start_completion': start_completion, }) - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ - 'get_completion_dict': get_completion_dict, - 'start_completion': start_completion, + connect_dict(uzbl, { + 'BUILTINS': add_builtins, + 'CONFIG_CHANGED': add_config_key, + 'KEYCMD_CLEARED': stop_completion, + 'KEYCMD_EXEC': stop_completion, + 'KEYCMD_UPDATE': update_completion_list, + 'START_COMPLETION': start_completion, + 'STOP_COMPLETION': stop_completion, }) + + uzbl.send('dump_config_as_events') diff --git a/examples/data/plugins/config.py b/examples/data/plugins/config.py index 4a848a3..ed2d761 100644 --- a/examples/data/plugins/config.py +++ b/examples/data/plugins/config.py @@ -1,97 +1,90 @@ -import re -import types +from re import compile +from types import BooleanType +from UserDict import DictMixin -__export__ = ['set', 'get_config'] - -VALIDKEY = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$").match -TYPECONVERT = {'int': int, 'float': float, 'str': unicode} - -UZBLS = {} - - -def escape(value): - '''A real escaping function may be required.''' - - return unicode(value) +valid_key = compile('^[A-Za-z0-9_\.]+$').match +types = {'int': int, 'float': float, 'str': unicode} +escape = lambda s: unicode(s).replace('\n', '\\n') +class Config(DictMixin): + def __init__(self, uzbl): + self.uzbl = uzbl -def set(uzbl, key, value='', config=None, force=False): - '''Sends a: "set key = value" command to the uzbl instance. If force is - False then only send a set command if the values aren't equal.''' + # Create the base dict and map allowed methods to `self`. + self.data = data = {} - if type(value) == types.BooleanType: - value = int(value) + methods = ['__contains__', '__getitem__', '__iter__', + '__len__', 'get', 'has_key', 'items', 'iteritems', + 'iterkeys', 'itervalues', 'values'] - else: - value = unicode(value) + for method in methods: + setattr(self, method, getattr(data, method)) - if not VALIDKEY(key): - raise KeyError("%r" % key) - value = escape(value) - if '\n' in value: - value = value.replace("\n", "\\n") + def __setitem__(self, key, value): + self.set(key, value) - if not force: - if config is None: - config = get_config(uzbl) + def __delitem__(self, key): + self.set(key) - if key in config and config[key] == value: - return + def update(self, other=None, **kwargs): + if other is None: + other = {} - uzbl.send('set %s = %s' % (key, value)) + for (key, value) in dict(other).items() + kwargs.items(): + self[key] = value -class ConfigDict(dict): - def __init__(self, uzbl): - self._uzbl = uzbl + def set(self, key, value='', force=False): + '''Generates a `set <key> = <value>` command string to send to the + current uzbl instance. - def __setitem__(self, key, value): - '''Makes "config[key] = value" a wrapper for the set function.''' + Note that the config dict isn't updated by this function. The config + dict is only updated after a successful `VARIABLE_SET ..` event + returns from the uzbl instance.''' - set(self._uzbl, key, value, config=self) + assert valid_key(key) + if type(value) == BooleanType: + value = int(value) -def add_instance(uzbl, *args): - UZBLS[uzbl] = ConfigDict(uzbl) + else: + value = escape(value) + if not force and key in self and self[key] == value: + return -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del uzbl + self.uzbl.send(u'set %s = %s' % (key, value)) -def get_config(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) +def parse_set_event(uzbl, args): + '''Parse `VARIABLE_SET <var> <type> <value>` event and load the + (key, value) pair into the `uzbl.config` dict.''' - return UZBLS[uzbl] + (key, type, raw_value) = (args.split(' ', 2) + ['',])[:3] + assert valid_key(key) + assert type in types -def variable_set(uzbl, args): - config = get_config(uzbl) + new_value = types[type](raw_value) + old_value = uzbl.config.get(key, None) - key, type, value = list(args.split(' ', 2) + ['',])[:3] - old = config[key] if key in config else None - value = TYPECONVERT[type](value) + # Update new value. + uzbl.config.data[key] = new_value - dict.__setitem__(config, key, value) + if old_value != new_value: + uzbl.event('CONFIG_CHANGED', key, new_value) - if old != value: - uzbl.event("CONFIG_CHANGED", key, value) + # Cleanup null config values. + if type == 'str' and not new_value: + del uzbl.config.data[key] +# plugin init hook def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'VARIABLE_SET': variable_set, - }) - - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ - 'get_config': get_config, - 'set': set, - }) + export(uzbl, 'config', Config(uzbl)) + connect(uzbl, 'VARIABLE_SET', parse_set_event) + +# plugin cleanup hook +def cleanup(uzbl): + uzbl.config.data.clear() diff --git a/examples/data/plugins/keycmd.py b/examples/data/plugins/keycmd.py index c119077..b600afe 100644 --- a/examples/data/plugins/keycmd.py +++ b/examples/data/plugins/keycmd.py @@ -1,8 +1,5 @@ import re -# Hold the keylets. -UZBLS = {} - # Keycmd format which includes the markup for the cursor. KEYCMD_FORMAT = "%s<span @cursor_style>%s</span>%s" MODCMD_FORMAT = "<span> %s </span>" @@ -38,9 +35,6 @@ class Keylet(object): self.ignores = {} self.additions = {} - # Keylet string repr cache. - self._repr_cache = None - def get_keycmd(self): '''Get the keycmd-part of the keylet.''' @@ -106,9 +100,6 @@ class Keylet(object): def __repr__(self): '''Return a string representation of the keylet.''' - if self._repr_cache: - return self._repr_cache - l = [] if self.is_modcmd: l.append('modcmd=%r' % self.get_modcmd()) @@ -119,8 +110,7 @@ class Keylet(object): if self.keycmd: l.append('keycmd=%r' % self.get_keycmd()) - self._repr_cache = '<Keylet(%s)>' % ', '.join(l) - return self._repr_cache + return '<keylet(%s)>' % ', '.join(l) def add_modmap(uzbl, key, map): @@ -140,7 +130,7 @@ def add_modmap(uzbl, key, map): ''' assert len(key) - modmaps = get_keylet(uzbl).modmaps + modmaps = uzbl.keylet.modmaps if key[0] == "<" and key[-1] == ">": key = key[1:-1] @@ -171,7 +161,7 @@ def add_key_ignore(uzbl, glob): ''' assert len(glob) > 1 - ignores = get_keylet(uzbl).ignores + ignores = uzbl.keylet.ignores glob = "<%s>" % glob.strip("<> ") restr = glob.replace('*', '[^\s]*') @@ -197,7 +187,7 @@ def add_modkey_addition(uzbl, modkeys, result): ... ''' - additions = get_keylet(uzbl).additions + additions = uzbl.keylet.additions modkeys = set(modkeys) assert len(modkeys) and result and result not in modkeys @@ -220,65 +210,34 @@ def modkey_addition_parse(uzbl, modkeys): add_modkey_addition(uzbl, keys[:-1], keys[-1]) -def add_instance(uzbl, *args): - '''Create the Keylet object for this uzbl instance.''' - - UZBLS[uzbl] = Keylet() - - -def del_instance(uzbl, *args): - '''Delete the Keylet object for this uzbl instance.''' - - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_keylet(uzbl): - '''Return the corresponding keylet for this uzbl instance.''' - - # Startup events are not correctly captured and sent over the uzbl socket - # yet so this line is needed because the INSTANCE_START event is lost. - if uzbl not in UZBLS: - add_instance(uzbl) - - keylet = UZBLS[uzbl] - keylet._repr_cache = False - return keylet - - def clear_keycmd(uzbl): '''Clear the keycmd for this uzbl instance.''' - k = get_keylet(uzbl) + k = uzbl.keylet k.keycmd = '' k.cursor = 0 - k._repr_cache = False - uzbl.set('keycmd') - uzbl.set('raw_keycmd') + del uzbl.config['keycmd'] uzbl.event('KEYCMD_CLEARED') def clear_modcmd(uzbl, clear_held=False): '''Clear the modcmd for this uzbl instance.''' - k = get_keylet(uzbl) + k = uzbl.keylet k.modcmd = '' k.is_modcmd = False - k._repr_cache = False if clear_held: k.ignored = set() k.held = set() - uzbl.set('modcmd') - uzbl.set('raw_modcmd') + del uzbl.config['modcmd'] uzbl.event('MODCMD_CLEARED') def clear_current(uzbl): '''Clear the modcmd if is_modcmd else clear keycmd.''' - k = get_keylet(uzbl) - if k.is_modcmd: + if uzbl.keylet.is_modcmd: clear_modcmd(uzbl) else: @@ -296,7 +255,6 @@ def focus_changed(uzbl, *args): def update_event(uzbl, k, execute=True): '''Raise keycmd & modcmd update events.''' - config = uzbl.get_config() keycmd, modcmd = k.get_keycmd(), k.get_modcmd() if k.is_modcmd: @@ -305,32 +263,28 @@ def update_event(uzbl, k, execute=True): else: uzbl.event('KEYCMD_UPDATE', k) - if 'modcmd_updates' not in config or config['modcmd_updates'] == '1': + if uzbl.config.get('modcmd_updates', '1') == '1': new_modcmd = k.get_modcmd() if not new_modcmd: - uzbl.set('modcmd', config=config) - uzbl.set('raw_modcmd', config=config) + del uzbl.config['modcmd'] elif new_modcmd == modcmd: - uzbl.set('raw_modcmd', escape(modcmd), config=config) - uzbl.set('modcmd', MODCMD_FORMAT % uzbl_escape(modcmd), - config=config) + uzbl.config['modcmd'] = MODCMD_FORMAT % uzbl_escape(modcmd) - if 'keycmd_events' in config and config['keycmd_events'] != '1': + if uzbl.config.get('keycmd_events', '1') != '1': return new_keycmd = k.get_keycmd() if not new_keycmd: - uzbl.set('keycmd', config=config) - uzbl.set('raw_keycmd', config=config) + del uzbl.config['keycmd'] elif new_keycmd == keycmd: # Generate the pango markup for the cursor in the keycmd. curchar = keycmd[k.cursor] if k.cursor < len(keycmd) else ' ' chunks = [keycmd[:k.cursor], curchar, keycmd[k.cursor+1:]] value = KEYCMD_FORMAT % tuple(map(uzbl_escape, chunks)) - uzbl.set('keycmd', value, config=config) - uzbl.set('raw_keycmd', escape(keycmd), config=config) + + uzbl.config['keycmd'] = value def inject_str(str, index, inj): @@ -344,7 +298,7 @@ def get_keylet_and_key(uzbl, key, add=True): by the modmapping or modkey addition rules. Return None if the key is ignored.''' - keylet = get_keylet(uzbl) + keylet = uzbl.keylet key = keylet.modmap_key(key) if len(key) == 1: return (keylet, key) @@ -385,12 +339,11 @@ def key_press(uzbl, key): k.cursor += 1 elif not k.held and len(key) == 1: - config = uzbl.get_config() - if 'keycmd_events' in config and config['keycmd_events'] != '1': + + if uzbl.config.get('keycmd_events', '1') != '1': k.keycmd = '' k.cursor = 0 - uzbl.set('keycmd', config=config) - uzbl.set('raw_keycmd', config=config) + del uzbl.config['keycmd'] return k.keycmd = inject_str(k.keycmd, k.cursor, key) @@ -429,9 +382,8 @@ def key_release(uzbl, key): def set_keycmd(uzbl, keycmd): '''Allow setting of the keycmd externally.''' - k = get_keylet(uzbl) + k = uzbl.keylet k.keycmd = keycmd - k._repr_cache = None k.cursor = len(keycmd) update_event(uzbl, k, False) @@ -439,9 +391,8 @@ def set_keycmd(uzbl, keycmd): def inject_keycmd(uzbl, keycmd): '''Allow injecting of a string into the keycmd at the cursor position.''' - k = get_keylet(uzbl) + k = uzbl.keylet k.keycmd = inject_str(k.keycmd, k.cursor, keycmd) - k._repr_cache = None k.cursor += len(keycmd) update_event(uzbl, k, False) @@ -449,9 +400,8 @@ def inject_keycmd(uzbl, keycmd): def append_keycmd(uzbl, keycmd): '''Allow appening of a string to the keycmd.''' - k = get_keylet(uzbl) + k = uzbl.keylet k.keycmd += keycmd - k._repr_cache = None k.cursor = len(k.keycmd) update_event(uzbl, k, False) @@ -460,7 +410,7 @@ def keycmd_strip_word(uzbl, sep): ''' Removes the last word from the keycmd, similar to readline ^W ''' sep = sep or ' ' - k = get_keylet(uzbl) + k = uzbl.keylet if not k.keycmd: return @@ -475,7 +425,7 @@ def keycmd_strip_word(uzbl, sep): def keycmd_backspace(uzbl, *args): '''Removes the character at the cursor position in the keycmd.''' - k = get_keylet(uzbl) + k = uzbl.keylet if not k.keycmd: return @@ -487,7 +437,7 @@ def keycmd_backspace(uzbl, *args): def keycmd_delete(uzbl, *args): '''Removes the character after the cursor position in the keycmd.''' - k = get_keylet(uzbl) + k = uzbl.keylet if not k.keycmd: return @@ -499,8 +449,7 @@ def keycmd_exec_current(uzbl, *args): '''Raise a KEYCMD_EXEC with the current keylet and then clear the keycmd.''' - k = get_keylet(uzbl) - uzbl.event('KEYCMD_EXEC', k) + uzbl.event('KEYCMD_EXEC', uzbl.keylet) clear_keycmd(uzbl) @@ -508,7 +457,7 @@ def set_cursor_pos(uzbl, index): '''Allow setting of the cursor position externally. Supports negative indexing and relative stepping with '+' and '-'.''' - k = get_keylet(uzbl) + k = uzbl.keylet if index == '-': cursor = k.cursor - 1 @@ -530,18 +479,16 @@ def set_cursor_pos(uzbl, index): update_event(uzbl, k, False) +# plugin init hook def init(uzbl): - '''Connect handlers to uzbl events.''' + '''Export functions and connect handlers to events.''' - # Event handling hooks. - uzbl.connect_dict({ + connect_dict(uzbl, { 'APPEND_KEYCMD': append_keycmd, 'FOCUS_GAINED': focus_changed, 'FOCUS_LOST': focus_changed, 'IGNORE_KEY': add_key_ignore, 'INJECT_KEYCMD': inject_keycmd, - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, 'KEYCMD_BACKSPACE': keycmd_backspace, 'KEYCMD_DELETE': keycmd_delete, 'KEYCMD_EXEC_CURRENT': keycmd_exec_current, @@ -554,9 +501,7 @@ def init(uzbl): 'SET_KEYCMD': set_keycmd, }) - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ + export_dict(uzbl, { 'add_key_ignore': add_key_ignore, 'add_modkey_addition': add_modkey_addition, 'add_modmap': add_modmap, @@ -564,8 +509,8 @@ def init(uzbl): 'clear_current': clear_current, 'clear_keycmd': clear_keycmd, 'clear_modcmd': clear_modcmd, - 'get_keylet': get_keylet, 'inject_keycmd': inject_keycmd, + 'keylet': Keylet(), 'set_cursor_pos': set_cursor_pos, 'set_keycmd': set_keycmd, }) diff --git a/examples/data/plugins/mode.py b/examples/data/plugins/mode.py index 54d865a..e0de706 100644 --- a/examples/data/plugins/mode.py +++ b/examples/data/plugins/mode.py @@ -1,176 +1,68 @@ -import sys -import re +from collections import defaultdict -__export__ = ['set_mode', 'get_mode', 'set_mode_config', 'get_mode_config'] +def parse_mode_config(uzbl, args): + '''Parse `MODE_CONFIG <mode> <var> = <value>` event and update config if + the `<mode>` is the current mode.''' -UZBLS = {} + ustrip = unicode.strip + args = unicode(args) -DEFAULTS = { - 'mode': '', - 'modes': { - 'insert': { - 'forward_keys': True, - 'keycmd_events': False, - 'modcmd_updates': False, - 'mode_indicator': 'I'}, - 'command': { - 'forward_keys': False, - 'keycmd_events': True, - 'modcmd_updates': True, - 'mode_indicator': 'C'}}} + assert args.strip(), "missing mode config args" + (mode, args) = map(ustrip, (args.strip().split(' ', 1) + ['',])[:2]) -FINDSPACES = re.compile("\s+") -VALID_KEY = re.compile("^[\w_]+$").match + assert args.strip(), "missing mode config set arg" + (key, value) = map(ustrip, (args.strip().split('=', 1) + [None,])[:2]) + assert key and value is not None, "invalid mode config set syntax" + uzbl.mode_config[mode][key] = value + if uzbl.config.get('mode', None) == mode: + uzbl.config[key] = value -def add_instance(uzbl, *args): - UZBLS[uzbl] = dict(DEFAULTS) +def default_mode_updated(uzbl, var, mode): + if mode and not uzbl.config.get('mode', None): + logger.debug('setting mode to default %r' % mode) + uzbl.config['mode'] = mode -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - -def get_mode_dict(uzbl): - '''Return the mode dict for an instance.''' - - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def get_mode_config(uzbl, mode): - '''Return the mode config for a given mode.''' - - modes = get_mode_dict(uzbl)['modes'] - if mode not in modes: - modes[mode] = {} - - return modes[mode] - - -def get_mode(uzbl): - return get_mode_dict(uzbl)['mode'] - - -def mode_changed(uzbl, mode): - '''The mode has just been changed, now set the per-mode config.''' - - if get_mode(uzbl) != mode: +def mode_updated(uzbl, var, mode): + if not mode: + mode = uzbl.config.get('default_mode', 'command') + logger.debug('setting mode to default %r' % mode) + uzbl.config['mode'] = mode return - config = uzbl.get_config() - mode_config = get_mode_config(uzbl, mode) - for (key, value) in mode_config.items(): - uzbl.set(key, value, config=config) - - if 'mode_indicator' not in mode_config: - config['mode_indicator'] = mode - - uzbl.clear_keycmd() - uzbl.clear_modcmd() - - -def set_mode(uzbl, mode=None): - '''Set the mode and raise the MODE_CHANGED event if the mode has changed. - Fallback on the default mode if no mode argument was given and the default - mode is not null.''' - - config = uzbl.get_config() - mode_dict = get_mode_dict(uzbl) - if mode is None: - mode_dict['mode'] = '' - if 'default_mode' in config: - mode = config['default_mode'] - - else: - mode = 'command' - - if not VALID_KEY(mode): - raise KeyError("invalid mode name: %r" % mode) - - if 'mode' not in config or config['mode'] != mode: - config['mode'] = mode + # Load mode config + mode_config = uzbl.mode_config.get(mode, None) + if mode_config: + uzbl.config.update(mode_config) - elif mode_dict['mode'] != mode: - mode_dict['mode'] = mode - uzbl.event("MODE_CHANGED", mode) + uzbl.send('event MODE_CONFIRM %s' % mode) -def config_changed(uzbl, key, value): - '''Check for mode related config changes.''' +def confirm_change(uzbl, mode): + if mode and uzbl.config.get('mode', None) == mode: + uzbl.event('MODE_CHANGED', mode) - value = None if not value else value - if key == 'default_mode': - if not get_mode(uzbl): - set_mode(uzbl, value) - elif key == 'mode': - set_mode(uzbl, value) - - -def set_mode_config(uzbl, mode, key, value): - '''Set mode specific configs. If the mode being modified is the current - mode then apply the changes on the go.''' - - assert VALID_KEY(mode) and VALID_KEY(key) - - mode_config = get_mode_config(uzbl, mode) - mode_config[key] = value - - if get_mode(uzbl) == mode: - uzbl.set(key, value) - - -def mode_config(uzbl, args): - '''Parse mode config events.''' - - split = map(unicode.strip, FINDSPACES.split(args.lstrip(), 1)) - if len(split) != 2: - raise SyntaxError('invalid mode config syntax: %r' % args) - - mode, set = split - split = map(unicode.strip, set.split('=', 1)) - if len(split) != 2: - raise SyntaxError('invalid set syntax: %r' % args) - - key, value = split - set_mode_config(uzbl, mode, key, value) - - -def toggle_modes(uzbl, modes): - '''Toggle or cycle between or through a list of modes.''' - - assert len(modes.strip()) - - modelist = filter(None, map(unicode.strip, modes.split(' '))) - mode = get_mode(uzbl) - - index = 0 - if mode in modelist: - index = (modelist.index(mode)+1) % len(modelist) - - set_mode(uzbl, modelist[index]) +# plugin init hook +def init(uzbl): + require('config') + require('on_set') + # Usage `uzbl.mode_config[mode][key] = value` + export(uzbl, 'mode_config', defaultdict(dict)) -def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ - 'CONFIG_CHANGED': config_changed, - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'MODE_CHANGED': mode_changed, - 'MODE_CONFIG': mode_config, - 'TOGGLE_MODES': toggle_modes, + connect_dict(uzbl, { + 'MODE_CONFIG': parse_mode_config, + 'MODE_CONFIRM': confirm_change, }) - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ - 'get_mode': get_mode, - 'get_mode_config': get_mode_config, - 'set_mode': set_mode, - 'set_mode_config': set_mode_config, - }) +# plugin after hook +def after(uzbl): + uzbl.on_set('mode', mode_updated) + uzbl.on_set('default_mode', default_mode_updated) + +# plugin cleanup hook +def cleanup(uzbl): + uzbl.mode_config.clear() diff --git a/examples/data/plugins/on_event.py b/examples/data/plugins/on_event.py index b9c504a..5142275 100644 --- a/examples/data/plugins/on_event.py +++ b/examples/data/plugins/on_event.py @@ -20,36 +20,11 @@ Usage: import sys import re -__export__ = ['get_on_events', 'on_event'] - -UZBLS = {} - - -def error(msg): - sys.stderr.write('on_event plugin: error: %s\n' % msg) - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = {} - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_on_events(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - def event_handler(uzbl, *args, **kargs): '''This function handles all the events being watched by various on_event definitions and responds accordingly.''' - events = get_on_events(uzbl) + events = uzbl.on_events event = kargs['on_event'] if event not in events: return @@ -65,9 +40,9 @@ def on_event(uzbl, event, cmd): '''Add a new event to watch and respond to.''' event = event.upper() - events = get_on_events(uzbl) + events = uzbl.on_events if event not in events: - uzbl.connect(event, event_handler, on_event=event) + connect(uzbl, event, event_handler, on_event=event) events[event] = [] cmds = events[event] @@ -80,28 +55,28 @@ def parse_on_event(uzbl, args): Syntax: "event ON_EVENT <EVENT_NAME> commands".''' - if not args: - return error("missing on_event arguments") - - split = args.split(' ', 1) - if len(split) != 2: - return error("invalid ON_EVENT syntax: %r" % args) + args = args.strip() + assert args, 'missing on event arguments' - event, cmd = split - on_event(uzbl, event, cmd) + (event, command) = (args.split(' ', 1) + ['',])[:2] + assert event and command, 'missing on event command' + on_event(uzbl, event, command) +# plugin init hook def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'ON_EVENT': parse_on_event, - }) + '''Export functions and connect handlers to events.''' + + connect(uzbl, 'ON_EVENT', parse_on_event) - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ - 'get_on_events': get_on_events, - 'on_event': on_event, + export_dict(uzbl, { + 'on_event': on_event, + 'on_events': {}, }) + +# plugin cleanup hook +def cleanup(uzbl): + for handlers in uzbl.on_events.values(): + del handlers[:] + + uzbl.on_events.clear() diff --git a/examples/data/plugins/on_set.py b/examples/data/plugins/on_set.py new file mode 100644 index 0000000..130b816 --- /dev/null +++ b/examples/data/plugins/on_set.py @@ -0,0 +1,92 @@ +from re import compile +from functools import partial + +valid_glob = compile('^[A-Za-z0-9_\*\.]+$').match + +def make_matcher(glob): + '''Make matcher function from simple glob.''' + + pattern = "^%s$" % glob.replace('*', '[^\s]*') + return compile(pattern).match + + +def exec_handlers(uzbl, handlers, key, arg): + '''Execute the on_set handlers that matched the key.''' + + for handler in handlers: + if callable(handler): + handler(key, arg) + + else: + uzbl.send(uzbl.cmd_expand(handler, [key, arg])) + + +def check_for_handlers(uzbl, key, arg): + '''Check for handlers for the current key.''' + + for (matcher, handlers) in uzbl.on_sets.values(): + if matcher(key): + exec_handlers(uzbl, handlers, key, arg) + + +def on_set(uzbl, glob, handler, prepend=True): + '''Add a new handler for a config key change. + + Structure of the `uzbl.on_sets` dict: + { glob : ( glob matcher function, handlers list ), .. } + ''' + + assert valid_glob(glob) + + while '**' in glob: + glob = glob.replace('**', '*') + + if callable(handler): + orig_handler = handler + if prepend: + handler = partial(handler, uzbl) + + else: + orig_handler = handler = unicode(handler) + + if glob in uzbl.on_sets: + (matcher, handlers) = uzbl.on_sets[glob] + handlers.append(handler) + + else: + matcher = make_matcher(glob) + uzbl.on_sets[glob] = (matcher, [handler,]) + + uzbl.logger.info('on set %r call %r' % (glob, orig_handler)) + + +def parse_on_set(uzbl, args): + '''Parse `ON_SET <glob> <command>` event then pass arguments to the + `on_set(..)` function.''' + + (glob, command) = (args.split(' ', 1) + [None,])[:2] + assert glob and command and valid_glob(glob) + on_set(uzbl, glob, command) + + +# plugins init hook +def init(uzbl): + require('config') + require('cmd_expand') + + export_dict(uzbl, { + 'on_sets': {}, + 'on_set': on_set, + }) + + connect_dict(uzbl, { + 'ON_SET': parse_on_set, + 'CONFIG_CHANGED': check_for_handlers, + }) + +# plugins cleanup hook +def cleanup(uzbl): + for (matcher, handlers) in uzbl.on_sets.values(): + del handlers[:] + + uzbl.on_sets.clear() diff --git a/examples/data/plugins/plugin_template.py b/examples/data/plugins/plugin_template.py deleted file mode 100644 index 565a999..0000000 --- a/examples/data/plugins/plugin_template.py +++ /dev/null @@ -1,76 +0,0 @@ -'''Plugin template.''' - -# Holds the per-instance data dict. -UZBLS = {} - -# The default instance dict. -DEFAULTS = {} - - -def add_instance(uzbl, *args): - '''Add a new instance with default config options.''' - - UZBLS[uzbl] = dict(DEFAULTS) - - -def del_instance(uzbl, *args): - '''Delete data stored for an instance.''' - - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_myplugin_dict(uzbl): - '''Get data stored for an instance.''' - - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def myplugin_function(uzbl, *args, **kargs): - '''Custom plugin function which is exported by the __export__ list at the - top of the file for use by other functions/callbacks.''' - - print "My plugin function arguments:", args, kargs - - # Get the per-instance data object. - data = get_myplugin_dict(uzbl) - - # Function logic goes here. - - -def myplugin_event_parser(uzbl, args): - '''Parses MYPLUGIN_EVENT raised by uzbl or another plugin.''' - - print "Got MYPLUGIN_EVENT with arguments: %r" % args - - # Parsing logic goes here. - - -def init(uzbl): - '''The main function of the plugin which is used to attach all the event - hooks that are going to be used throughout the plugins life. This function - is called each time a UzblInstance() object is created in the event - manager.''' - - # Make a dictionary comprising of {"EVENT_NAME": handler, ..} to the event - # handler stack: - uzbl.connect_dict({ - # event name function - 'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance, - 'MYPLUGIN_EVENT': myplugin_event_parser, - }) - - # Or connect a handler to an event manually and supply additional optional - # arguments: - #uzbl.connect("MYOTHER_EVENT", myother_event_parser, True, limit=20) - - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.connect_dict({ - # external name function - 'myplugin_function': myplugin_function, - }) diff --git a/examples/data/plugins/progress_bar.py b/examples/data/plugins/progress_bar.py index 89ba175..b2edffc 100644 --- a/examples/data/plugins/progress_bar.py +++ b/examples/data/plugins/progress_bar.py @@ -1,39 +1,7 @@ -import sys +UPDATES = 0 -UZBLS = {} - -DEFAULTS = {'width': 8, - 'done': '=', - 'pending': '.', - 'format': '[%d%a%p]%c', - 'spinner': '-\\|/', - 'sprites': 'loading', - 'updates': 0, - 'progress': 100} - - -def error(msg): - sys.stderr.write("progress_bar plugin: error: %s\n" % msg) - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = dict(DEFAULTS) - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_progress_config(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def update_progress(uzbl, prog=None): - '''Updates the progress_format variable on LOAD_PROGRESS update. +def update_progress(uzbl, progress=None): + '''Updates the progress.output variable on LOAD_PROGRESS update. The current substitution options are: %d = done char * done @@ -44,116 +12,82 @@ def update_progress(uzbl, prog=None): %t = percent pending %o = int pending %r = sprites + + Default configuration options: + progress.format = [%d>%p]%c + progress.width = 8 + progress.done = = + progress.pending = + progress.spinner = -\|/ + progress.sprites = loading ''' - prog_config = get_progress_config(uzbl) - config = uzbl.get_config() + global UPDATES - if prog is None: - prog = prog_config['progress'] + if progress is None: + UPDATES = 0 + progress = 100 else: - prog = int(prog) - prog_config['progress'] = prog + UPDATES += 1 + progress = int(progress) - prog_config['updates'] += 1 - format = prog_config['format'] - width = prog_config['width'] + # Get progress config vars. + format = uzbl.config.get('progress.format', '[%d>%p]%c') + width = int(uzbl.config.get('progress.width', 8)) + done_symbol = uzbl.config.get('progress.done', '=') + pend = uzbl.config.get('progress.pending', None) + pending_symbol = pend if pend else ' ' # Inflate the done and pending bars to stop the progress bar # jumping around. if '%c' in format or '%i' in format: count = format.count('%c') + format.count('%i') - width += (3-len(str(prog))) * count + width += (3-len(str(progress))) * count if '%t' in format or '%o' in format: count = format.count('%t') + format.count('%o') - width += (3-len(str(100-prog))) * count + width += (3-len(str(100-progress))) * count - done = int(((prog/100.0)*width)+0.5) + done = int(((progress/100.0)*width)+0.5) pending = width - done if '%d' in format: - format = format.replace('%d', prog_config['done']*done) + format = format.replace('%d', done_symbol * done) if '%p' in format: - format = format.replace('%p', prog_config['pending']*pending) + format = format.replace('%p', pending_symbol * pending) if '%c' in format: - format = format.replace('%c', '%d%%' % prog) + format = format.replace('%c', '%d%%' % progress) if '%i' in format: - format = format.replace('%i', '%d' % prog) + format = format.replace('%i', '%d' % progress) if '%t' in format: - format = format.replace('%t', '%d%%' % (100-prog)) + format = format.replace('%t', '%d%%' % (100-progress)) if '%o' in format: - format = format.replace('%o', '%d' % (100-prog)) + format = format.replace('%o', '%d' % (100-progress)) if '%s' in format: - spinner = prog_config['spinner'] - spin = '-' if not spinner else spinner - index = 0 if prog == 100 else prog_config['updates'] % len(spin) - char = '\\\\' if spin[index] == '\\' else spin[index] - format = format.replace('%s', char) + spinner = uzbl.config.get('progress.spinner', '-\\|/') + index = 0 if progress == 100 else UPDATES % len(spinner) + spin = '\\\\' if spinner[index] == '\\' else spinner[index] + format = format.replace('%s', spin) if '%r' in format: - sprites = prog_config['sprites'] - sprites = '-' if not sprites else sprites - index = int(((prog/100.0)*len(sprites))+0.5)-1 + sprites = uzbl.config.get('progress.sprites', 'loading') + index = int(((progress/100.0)*len(sprites))+0.5)-1 sprite = '\\\\' if sprites[index] == '\\' else sprites[index] format = format.replace('%r', sprite) - if 'progress_format' not in config or config['progress_format'] != format: - config['progress_format'] = format - - -def progress_config(uzbl, args): - '''Parse PROGRESS_CONFIG events from the uzbl instance. - - Syntax: event PROGRESS_CONFIG <key> = <value> - ''' - - split = args.split('=', 1) - if len(split) != 2: - return error("invalid syntax: %r" % args) - - key, value = map(unicode.strip, split) - prog_config = get_progress_config(uzbl) - - if key not in prog_config: - return error("key error: %r" % args) - - if type(prog_config[key]) == type(1): - try: - value = int(value) - - except: - return error("invalid type: %r" % args) - - elif not value: - value = ' ' - - prog_config[key] = value - update_progress(uzbl) - - -def reset_progress(uzbl, args): - '''Reset the spinner counter, reset the progress int and re-draw the - progress bar on LOAD_COMMIT.''' - - prog_dict = get_progress_config(uzbl) - prog_dict['updates'] = prog_dict['progress'] = 0 - update_progress(uzbl) - + if uzbl.config.get('progress.output', None) != format: + uzbl.config['progress.output'] = format +# plugin init hook def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'LOAD_COMMIT': reset_progress, + connect_dict(uzbl, { + 'LOAD_COMMIT': lambda uzbl, uri: update_progress(uzbl), 'LOAD_PROGRESS': update_progress, - 'PROGRESS_CONFIG': progress_config, }) |