ebook-convert: Make TAB completion (Linux only) faster

This commit is contained in:
Kovid Goyal 2009-09-18 00:00:18 -06:00
parent 080f70c309
commit 0c30aed24c
4 changed files with 131 additions and 31 deletions

View File

@ -11,6 +11,7 @@ resources/localization
resources/images.qrc
resources/recipes.pickle
resources/scripts.pickle
resources/ebook-convert-complete.pickle
setup/installer/windows/calibre/build.log
src/calibre/translations/.errors
src/cssutils/.svn/

View File

@ -11,7 +11,7 @@ import sys, os, textwrap, subprocess, shutil, tempfile, atexit
from setup import Command, islinux, basenames, modules, functions, \
__appname__, __version__
TEMPLATE = '''\
HEADER = '''\
#!/usr/bin/env python
"""
@ -20,6 +20,9 @@ Do not modify it unless you know what you are doing.
"""
import sys
'''
TEMPLATE = HEADER+'''
sys.path.insert(0, {path!r})
sys.resources_location = {resources!r}
@ -29,6 +32,18 @@ from {module} import {func!s}
sys.exit({func!s}())
'''
COMPLETE_TEMPLATE = HEADER+'''
import os
sys.path.insert(0, {path!r})
sys.path.insert(0, os.path.join({path!r}, 'calibre', 'utils'))
import complete
sys.path = sys.path[1:]
sys.resources_location = {resources!r}
sys.extensions_location = {extensions!r}
sys.exit(complete.main())
'''
class Develop(Command):
description = textwrap.dedent('''\
@ -117,7 +132,8 @@ class Develop(Command):
self.write_template(opts, 'calibre_postinstall', 'calibre.linux', 'main')
def write_template(self, opts, name, mod, func):
script = TEMPLATE.format(
template = COMPLETE_TEMPLATE if name == 'calibre-complete' else TEMPLATE
script = template.format(
module=mod, func=func,
path=self.path, resources=self.resources,
extensions=self.extensions)

View File

@ -10,6 +10,18 @@ import os, cPickle
from setup import Command, basenames
def get_opts_from_parser(parser):
def do_opt(opt):
for x in opt._long_opts:
yield x
for x in opt._short_opts:
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
class Resources(Command):
def get_recipes(self):
@ -45,9 +57,42 @@ class Resources(Command):
f = open(dest, 'wb')
cPickle.dump(recipes, f, -1)
dest = self.j(self.RESOURCES, 'ebook-convert-complete.pickle')
files = []
for x in os.walk(self.j(self.SRC, 'calibre')):
for f in x[-1]:
if f.endswith('.py'):
files.append(self.j(x[0], f))
if self.newer(dest, files):
self.info('\tCreating ebook-convert-complete.pickle')
complete = {}
from calibre.ebooks.conversion.plumber import supported_input_formats
complete['input_fmts'] = set(supported_input_formats())
from calibre.web.feeds.recipes import recipes
complete['input_recipes'] = [t.title+'.recipe ' for t in recipes]
from calibre.customize.ui import available_output_formats
complete['output'] = set(available_output_formats())
from calibre.ebooks.conversion.cli import create_option_parser
from calibre.utils.logging import Log
log = Log()
#log.outputs = []
for inf in supported_input_formats():
if inf in ('zip', 'rar', 'oebzip'):
continue
for ouf in available_output_formats():
of = ouf if ouf == 'oeb' else 'dummy.'+ouf
p = create_option_parser(('ec', 'dummy1.'+inf, of, '-h'),
log)[0]
complete[(inf, ouf)] = [x+' 'for x in
get_opts_from_parser(p)]
cPickle.dump(complete, open(dest, 'wb'), -1)
def clean(self):
for x in ('scripts', 'recipes'):
for x in ('scripts', 'recipes', 'ebook-convert-complete'):
x = self.j(self.RESOURCES, x+'.pickle')
if os.path.exists(x):
os.remove(x)

View File

@ -12,12 +12,47 @@ BASH completion for calibre commands that are too complex for simple
completion.
'''
import sys, os, shlex, glob, re
from functools import partial
import sys, os, shlex, glob, re, cPickle
def prints(*args, **kwargs):
'''
Print unicode arguments safely by encoding them to preferred_encoding
Has the same signature as the print function from Python 3, except for the
additional keyword argument safe_encode, which if set to True will cause the
function to use repr when encoding fails.
'''
file = kwargs.get('file', sys.stdout)
sep = kwargs.get('sep', ' ')
end = kwargs.get('end', '\n')
enc = 'utf-8'
safe_encode = kwargs.get('safe_encode', False)
for i, arg in enumerate(args):
if isinstance(arg, unicode):
try:
arg = arg.encode(enc)
except UnicodeEncodeError:
if not safe_encode:
raise
arg = repr(arg)
if not isinstance(arg, str):
try:
arg = str(arg)
except ValueError:
arg = unicode(arg)
if isinstance(arg, unicode):
try:
arg = arg.encode(enc)
except UnicodeEncodeError:
if not safe_encode:
raise
arg = repr(arg)
file.write(arg)
if i != len(args)-1:
file.write(sep)
file.write(end)
from calibre import prints
debug = partial(prints, file=sys.stderr)
def split(src):
try:
@ -47,10 +82,10 @@ def get_opts_from_parser(parser, prefix):
if x.startswith(prefix):
yield x
for o in parser.option_list:
for x in do_opt(o): yield x
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
for x in do_opt(o): yield x+' '
def send(ans):
pat = re.compile('([^0-9a-zA-Z_./-])')
@ -74,6 +109,8 @@ class EbookConvert(object):
self.words = words
self.prefix = prefix
self.previous = words[-2 if prefix else -1]
self.cache = cPickle.load(open(os.path.join(sys.resources_location,
'ebook-convert-complete.pickle'), 'rb'))
self.complete(wc)
def complete(self, wc):
@ -82,41 +119,42 @@ class EbookConvert(object):
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
q = list(self.words[1:3])
q = [os.path.splitext(x)[0 if x.startswith('.') else 1].partition('.')[-1].lower() for x in q]
if not q[1]:
q[1] = 'oeb'
q = tuple(q)
if q in self.cache:
ans = [x for x in self.cache[q] if x.startswith(self.prefix)]
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)]
ans = list(files_and_dirs(self.prefix, self.cache['input_fmts']))
ans += [t for t in self.cache['input_recipes'] if
t.startswith(self.prefix)]
send(ans)
def complete_output(self):
from calibre.customize.ui import available_output_formats
fmts = available_output_formats()
fmts = self.cache['output']
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]