--- a/alexandria.py Mon Apr 12 12:30:37 2010 -0700
+++ b/alexandria.py Mon May 31 19:53:56 2010 -0700
@@ -60,7 +60,11 @@
initDatabase(path, not found)
-laopts = [('l', 'label', [], 'label of the document'),
+# cfg because of the middleware
+def _complete_label(cfg, prefix, **opts):
+ return [t.name for t in Tag.query.filter(Tag.name.startswith(unicode(prefix))).order_by(asc(Tag.name)).all()]
+
+laopts = [('l', 'label', [], 'label of the document', _complete_label),
('a', 'author', [], 'author of the document')]
latopts = laopts + [('t', 'title', '', 'paper title')]
@@ -371,7 +375,7 @@
if 'database' in kwargs:
del kwargs['database']
- func(cfg, *args, **kwargs)
+ return func(cfg, *args, **kwargs)
return inner
--- a/opster.py Mon Apr 12 12:30:37 2010 -0700
+++ b/opster.py Mon May 31 19:53:56 2010 -0700
@@ -2,7 +2,7 @@
'''Command line arguments parser
'''
-import sys, traceback, getopt, types, textwrap, inspect
+import sys, traceback, getopt, types, textwrap, inspect, os
from itertools import imap
__all__ = ['command', 'dispatch']
@@ -123,13 +123,24 @@
cmdtable['help'] = (help_(cmdtable, globaloptions), [], '[TOPIC]')
help_func = cmdtable['help'][0]
+ cmdtable['_completion'] = (completion_,
+ [('b', 'bash', False, 'Output bash competion'),
+ ('z', 'zsh', False, 'Output zsh completion')],
+ '--bash OR --zsh')
+ autocomplete(cmdtable, args, middleware)
+
try:
name, func, args, kwargs = catcher(
lambda: _dispatch(args, cmdtable, globaloptions),
help_func)
- return catcher(
- lambda: call_cmd(name, middleware(func))(*args, **kwargs),
- help_func)
+ if name == '_completion': # skip middleware
+ return catcher(
+ lambda: call_cmd(name, func)(*args, **kwargs),
+ help_func)
+ else:
+ return catcher(
+ lambda: call_cmd(name, middleware(func))(*args, **kwargs),
+ help_func)
except Abort:
return -1
@@ -271,7 +282,8 @@
argmap, defmap, state = {}, {}, {}
shortlist, namelist, funlist = '', [], []
- for short, name, default, comment in options:
+ for o in options:
+ short, name, default, comment = o[:4] # might have the fifth completer element
if short and len(short) != 1:
raise FOError('Short option should be only a single'
' character: %s' % short)
@@ -312,6 +324,8 @@
state[name] = defmap[name](val)
elif t is types.IntType:
state[name] = int(val)
+ elif t is types.FloatType:
+ state[name] = float(val)
elif t is types.StringType:
state[name] = val
elif t is types.ListType:
@@ -324,6 +338,89 @@
return state, args
+# --------
+# Autocomplete system
+# --------
+
+# Borrowed from PIP
+def autocomplete(cmdtable, args, middleware):
+ """Command and option completion.
+
+ Enable by sourcing one of the completion shell scripts (bash or zsh).
+ """
+
+ # Don't complete if user hasn't sourced bash_completion file.
+ if not os.environ.has_key('OPSTER_AUTO_COMPLETE'):
+ return
+ cwords = os.environ['COMP_WORDS'].split()[1:]
+ cword = int(os.environ['COMP_CWORD'])
+
+ try:
+ current = cwords[cword-1]
+ except IndexError:
+ current = ''
+
+ commands = []
+ for k in cmdtable.keys():
+ commands += aliases_(k)
+
+ # command
+ if cword == 1:
+ print ' '.join(filter(lambda x: x.startswith(current), commands))
+
+ # command options
+ elif cwords[0] in commands:
+ idx = -2 if current else -1
+ options = []
+ aliases, (cmd, opts, usage) = findcmd(cwords[0], cmdtable)
+
+ for o in opts:
+ short, long, default, help = o[:4]
+ completer = o[4] if len(o) > 4 else None
+ short, long = '-%s' % short, '--%s' % long
+ options += [short,long]
+
+ if (cwords[idx] in [short,long]) and completer:
+ args = middleware(completer)(current)
+ print ' '.join(args),
+
+ print ' '.join((o for o in options if o.startswith(current)))
+
+ sys.exit(1)
+
+def completion_(**opts):
+ """Outputs the completion script for bash or zsh."""
+
+ (head, prog_name) = os.path.split(sys.argv[0])
+
+ if opts['bash']:
+ print """
+# opster bash completion start
+_opster_completion()
+{
+ COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\
+ COMP_CWORD=$COMP_CWORD \\
+ OPSTER_AUTO_COMPLETE=1 $1 ) )
+}
+complete -o default -F _opster_completion %s
+# opster bash completion end
+ """ % prog_name
+
+ if opts['zsh']:
+ print """
+# opster zsh completion start
+function _opster_completion {
+ local words cword
+ read -Ac words
+ read -cn cword
+ reply=( $( COMP_WORDS="$words[*]" \\
+ COMP_CWORD=$(( cword-1 )) \\
+ OPSTER_AUTO_COMPLETE=1 $words[1] ) )
+}
+compctl -K _opster_completion %s
+# opster zsh completion end
+ """ % prog_name
+
# --------
# Subcommand system
@@ -365,6 +462,9 @@
return (cmd, cmd and info[0] or None, args, options)
+def aliases_(cmdtable_key):
+ return cmdtable_key.lstrip("^~").split("|")
+
def findpossible(cmd, table):
"""
Return cmd -> (aliases, command table entry)
@@ -372,7 +472,7 @@
"""
choice = {}
for e in table.keys():
- aliases = e.lstrip("^~").split("|")
+ aliases = aliases_(e)
found = None
if cmd in aliases:
found = cmd
@@ -411,8 +511,9 @@
args, varargs, varkw, defaults = inspect.getargspec(func)
for name, option in zip(args[-len(defaults):], defaults):
try:
- sname, default, hlp = option
- yield (sname, name.replace('_', '-'), default, hlp)
+ sname, default, hlp = option[:3]
+ completer = option[3] if len(option) > 3 else None
+ yield (sname, name.replace('_', '-'), default, hlp, completer)
except TypeError:
pass