diff --git a/src/calibre/utils/complete.py b/src/calibre/utils/complete.py new file mode 100644 index 0000000000..11ee0dcb0e --- /dev/null +++ b/src/calibre/utils/complete.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai +from __future__ import with_statement + +__license__ = 'GPL v3' +__copyright__ = '2009, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + + +''' +BASH completion for calibre commands that are too complex for simple +completion. +''' + +import sys, os, shlex, glob +from functools import partial + +from calibre import prints + +debug = partial(prints, file=sys.stderr) + +def split(src): + try: + return shlex.split(src) + except ValueError: + try: + return shlex.split(src+'"') + except ValueError: + return shlex.split(src+"'") + + +def files_and_dirs(prefix, allowed_exts=[]): + for i in glob.iglob(prefix+'*'): + _, ext = os.path.splitext(i) + ext = ext.lower().replace('.', '') + if os.path.isdir(i): + yield i+os.sep + elif allowed_exts is None or ext in allowed_exts: + yield i+' ' + +def get_opts_from_parser(parser, prefix): + def do_opt(opt): + for x in opt._long_opts: + if x.startswith(prefix): + yield x + for x in opt._short_opts: + if x.startswith(prefix): + yield x + for o in parser.option_list: + for x in do_opt(o): yield x + for g in parser.option_groups: + for o in g.option_list: + for x in do_opt(o): yield x + +def send(ans): + for x in sorted(set(ans)): + x = x.replace(' ', '\\ ') + if x.endswith('\\ '): + x = x[:-2]+' ' + prints(x) + + + +class EbookConvert(object): + + def __init__(self, comp_line, pos): + words = split(comp_line[:pos]) + char_before = comp_line[pos-1] + prefix = words[-1] if words[-1].endswith(char_before) else '' + wc = len(words) + if not prefix: + wc += 1 + self.words = words + self.prefix = prefix + self.previous = words[-2 if prefix else -1] + self.complete(wc) + + def complete(self, wc): + if wc == 2: + self.complete_input() + elif wc == 3: + self.complete_output() + else: + from calibre.ebooks.conversion.cli import create_option_parser + from calibre.utils.logging import Log + log = Log() + log.outputs = [] + ans = [] + if not self.prefix or self.prefix.startswith('-'): + try: + parser, _ = create_option_parser(self.words[:3], log) + ans += list(get_opts_from_parser(parser, self.prefix)) + except: + pass + if self.previous.startswith('-'): + ans += list(files_and_dirs(self.prefix, None)) + send(ans) + + def complete_input(self): + from calibre.ebooks.conversion.plumber import supported_input_formats + ans = list(files_and_dirs(self.prefix, supported_input_formats())) + from calibre.web.feeds.recipes import recipes + ans += [t.title+'.recipe ' for t in recipes if + (t.title+'.recipe').startswith(self.prefix)] + send(ans) + + def complete_output(self): + from calibre.customize.ui import available_output_formats + fmts = available_output_formats() + ans = list(files_and_dirs(self.prefix, fmts)) + ans += ['.'+x+' ' for x in fmts if ('.'+x).startswith(self.prefix)] + send(ans) + + + + + + +def main(args=sys.argv): + comp_line, pos = os.environ['COMP_LINE'], int(os.environ['COMP_POINT']) + module = split(comp_line)[0].split(os.sep)[-1] + if module == 'ebook-convert': + EbookConvert(comp_line, pos) + + return 0 + + +if __name__ == '__main__': + raise sys.exit(main())