From 8a52115e7da225174a12f078fa593fd684115531 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 21 Nov 2009 00:43:40 +0800 Subject: Alpha keycmd completion plugin commit. A few bugs remaining. --- examples/data/uzbl/plugins/completion.py | 175 +++++++++++++++++++++++++++++++ examples/data/uzbl/plugins/config.py | 2 +- examples/data/uzbl/plugins/keycmd.py | 3 +- 3 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 examples/data/uzbl/plugins/completion.py (limited to 'examples/data/uzbl/plugins') diff --git a/examples/data/uzbl/plugins/completion.py b/examples/data/uzbl/plugins/completion.py new file mode 100644 index 0000000..df3b139 --- /dev/null +++ b/examples/data/uzbl/plugins/completion.py @@ -0,0 +1,175 @@ +'''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 = range(3) + +# Default instance dict. +DEFAULTS = {'completions': [], 'level': NONE, 'lock': False} + +# The reverse keyword finding re. +FIND_SEGMENT = re.compile("(\@[\w_]+|[\w_]+)$").findall + +# Formats +LIST_FORMAT = "[ %s ]" +ITEM_FORMAT = "%s%s" + + +def escape(str): + return str.replace("@", "\@") + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = dict(DEFAULTS) + + +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_cmd(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() + left_segment = keylet.keycmd[:keylet.cursor] + return (FIND_SEGMENT(left_segment) + ['',])[0].lstrip() + + +def stop_completion(uzbl, *args): + d = get_completion_dict(uzbl) + d['level'] = NONE + uzbl.set('completion_list') + + +def complete_completion(uzbl, partial, hint): + '''Inject the remaining porition of the keyword into the keycmd then stop + the completioning.''' + + remainder = "%s " % hint[len(partial):] + uzbl.inject_keycmd(remainder) + stop_completion(uzbl) + + +def partial_completion(uzbl, partial, hint): + '''Inject a common portion of the hints into the keycmd.''' + + remainder = hint[len(partial):] + uzbl.inject_keycmd(remainder) + + +def start_completion(uzbl, start=True): + + d = get_completion_dict(uzbl) + if d['lock'] or not start and not d['level']: + return + + partial = get_incomplete_cmd(uzbl) + if not partial: + return stop_completion(uzbl) + + if d['level'] < LIST: + d['level'] += 1 + + hints = [h for h in d['completions'] if h.startswith(partial)] + if not hints: + return + + elif len(hints) == 1: + d['lock'] = True + complete_completion(uzbl, partial, hints[0]) + d['lock'] = False + return + + elif partial in hints: + d['lock'] = True + complete_completion(uzbl, partial, partial) + d['lock'] = False + return + + smalllen, smallest = sorted([(len(h), h) for h in hints])[0] + common = '' + for i in range(len(partial), smalllen): + char, same = smallest[i], True + for hint in hints: + if hint[i] != char: + same = False + break + + if not same: + break + + common += char + + if common: + d['lock'] = True + partial_completion(uzbl, partial, partial+common) + d['lock'] = False + + partial += common + if d['level'] == LIST: + j = len(partial) + l = [ITEM_FORMAT % (h[:j], h[j:]) for h in sorted(hints)] + print l + uzbl.set('completion_list', escape(LIST_FORMAT % ' '.join(l))) + + +def add_builtins(uzbl, args): + '''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) + + +def add_config_key(uzbl, key, value): + '''Listen on the CONFIG_CHANGED event and add config keys to the variable + list for @var like expansion support.''' + + completions = get_completion_dict(uzbl)['completions'] + key = "@%s" % key + if key not in completions: + completions.append(key) + + +def init(uzbl): + connects = { + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance, + 'BUILTINS': add_builtins, + 'CONFIG_CHANGED': add_config_key, + } + + # And connect the dicts event handlers to the handler stack. + uzbl.connect_dict(connects) + + for event in ['STOP_COMPLETION', 'KEYCMD_EXEC', 'KEYCMD_CLEAR']: + uzbl.connect(event, stop_completion) + + uzbl.connect('START_COMPLETION', + lambda uzbl, args: start_completion(uzbl)) + + uzbl.connect('KEYCMD_UPDATE', + lambda uzbl, args: start_completion(uzbl, False)) diff --git a/examples/data/uzbl/plugins/config.py b/examples/data/uzbl/plugins/config.py index 22803b4..57c2403 100644 --- a/examples/data/uzbl/plugins/config.py +++ b/examples/data/uzbl/plugins/config.py @@ -22,7 +22,7 @@ def get_config(uzbl): return UZBLS[uzbl] -def set(uzbl, key, value): +def set(uzbl, key, value=''): '''Sends a: "set key = value" command to the uzbl instance.''' if type(value) == types.BooleanType: diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 1d263d3..82c95f8 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -2,7 +2,8 @@ import re # Map these functions/variables in the plugins namespace to the uzbl object. __export__ = ['clear_keycmd', 'set_keycmd', 'set_cursor_pos', 'get_keylet', - 'clear_current', 'clear_modcmd', 'add_modmap', 'add_key_ignore'] + 'clear_current', 'clear_modcmd', 'add_modmap', 'add_key_ignore', + 'append_keycmd', 'inject_keycmd'] # Hold the keylets. UZBLS = {} -- cgit v1.2.3