mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
ebook-convert: Make TAB completion (Linux only) faster
This commit is contained in:
parent
080f70c309
commit
0c30aed24c
@ -11,6 +11,7 @@ resources/localization
|
|||||||
resources/images.qrc
|
resources/images.qrc
|
||||||
resources/recipes.pickle
|
resources/recipes.pickle
|
||||||
resources/scripts.pickle
|
resources/scripts.pickle
|
||||||
|
resources/ebook-convert-complete.pickle
|
||||||
setup/installer/windows/calibre/build.log
|
setup/installer/windows/calibre/build.log
|
||||||
src/calibre/translations/.errors
|
src/calibre/translations/.errors
|
||||||
src/cssutils/.svn/
|
src/cssutils/.svn/
|
||||||
|
@ -11,7 +11,7 @@ import sys, os, textwrap, subprocess, shutil, tempfile, atexit
|
|||||||
from setup import Command, islinux, basenames, modules, functions, \
|
from setup import Command, islinux, basenames, modules, functions, \
|
||||||
__appname__, __version__
|
__appname__, __version__
|
||||||
|
|
||||||
TEMPLATE = '''\
|
HEADER = '''\
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -20,6 +20,9 @@ Do not modify it unless you know what you are doing.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
'''
|
||||||
|
|
||||||
|
TEMPLATE = HEADER+'''
|
||||||
sys.path.insert(0, {path!r})
|
sys.path.insert(0, {path!r})
|
||||||
|
|
||||||
sys.resources_location = {resources!r}
|
sys.resources_location = {resources!r}
|
||||||
@ -29,6 +32,18 @@ from {module} import {func!s}
|
|||||||
sys.exit({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):
|
class Develop(Command):
|
||||||
|
|
||||||
description = textwrap.dedent('''\
|
description = textwrap.dedent('''\
|
||||||
@ -117,7 +132,8 @@ class Develop(Command):
|
|||||||
self.write_template(opts, 'calibre_postinstall', 'calibre.linux', 'main')
|
self.write_template(opts, 'calibre_postinstall', 'calibre.linux', 'main')
|
||||||
|
|
||||||
def write_template(self, opts, name, mod, func):
|
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,
|
module=mod, func=func,
|
||||||
path=self.path, resources=self.resources,
|
path=self.path, resources=self.resources,
|
||||||
extensions=self.extensions)
|
extensions=self.extensions)
|
||||||
|
@ -10,6 +10,18 @@ import os, cPickle
|
|||||||
|
|
||||||
from setup import Command, basenames
|
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):
|
class Resources(Command):
|
||||||
|
|
||||||
def get_recipes(self):
|
def get_recipes(self):
|
||||||
@ -45,9 +57,42 @@ class Resources(Command):
|
|||||||
f = open(dest, 'wb')
|
f = open(dest, 'wb')
|
||||||
cPickle.dump(recipes, f, -1)
|
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):
|
def clean(self):
|
||||||
for x in ('scripts', 'recipes'):
|
for x in ('scripts', 'recipes', 'ebook-convert-complete'):
|
||||||
x = self.j(self.RESOURCES, x+'.pickle')
|
x = self.j(self.RESOURCES, x+'.pickle')
|
||||||
if os.path.exists(x):
|
if os.path.exists(x):
|
||||||
os.remove(x)
|
os.remove(x)
|
||||||
|
@ -12,12 +12,47 @@ BASH completion for calibre commands that are too complex for simple
|
|||||||
completion.
|
completion.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import sys, os, shlex, glob, re
|
import sys, os, shlex, glob, re, cPickle
|
||||||
from functools import partial
|
|
||||||
|
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):
|
def split(src):
|
||||||
try:
|
try:
|
||||||
@ -47,10 +82,10 @@ def get_opts_from_parser(parser, prefix):
|
|||||||
if x.startswith(prefix):
|
if x.startswith(prefix):
|
||||||
yield x
|
yield x
|
||||||
for o in parser.option_list:
|
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 g in parser.option_groups:
|
||||||
for o in g.option_list:
|
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):
|
def send(ans):
|
||||||
pat = re.compile('([^0-9a-zA-Z_./-])')
|
pat = re.compile('([^0-9a-zA-Z_./-])')
|
||||||
@ -74,6 +109,8 @@ class EbookConvert(object):
|
|||||||
self.words = words
|
self.words = words
|
||||||
self.prefix = prefix
|
self.prefix = prefix
|
||||||
self.previous = words[-2 if prefix else -1]
|
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)
|
self.complete(wc)
|
||||||
|
|
||||||
def complete(self, wc):
|
def complete(self, wc):
|
||||||
@ -82,41 +119,42 @@ class EbookConvert(object):
|
|||||||
elif wc == 3:
|
elif wc == 3:
|
||||||
self.complete_output()
|
self.complete_output()
|
||||||
else:
|
else:
|
||||||
from calibre.ebooks.conversion.cli import create_option_parser
|
q = list(self.words[1:3])
|
||||||
from calibre.utils.logging import Log
|
q = [os.path.splitext(x)[0 if x.startswith('.') else 1].partition('.')[-1].lower() for x in q]
|
||||||
log = Log()
|
if not q[1]:
|
||||||
log.outputs = []
|
q[1] = 'oeb'
|
||||||
ans = []
|
q = tuple(q)
|
||||||
if not self.prefix or self.prefix.startswith('-'):
|
if q in self.cache:
|
||||||
try:
|
ans = [x for x in self.cache[q] if x.startswith(self.prefix)]
|
||||||
parser, _ = create_option_parser(self.words[:3], log)
|
else:
|
||||||
ans += list(get_opts_from_parser(parser, self.prefix))
|
from calibre.ebooks.conversion.cli import create_option_parser
|
||||||
except:
|
from calibre.utils.logging import Log
|
||||||
pass
|
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('-'):
|
if self.previous.startswith('-'):
|
||||||
ans += list(files_and_dirs(self.prefix, None))
|
ans += list(files_and_dirs(self.prefix, None))
|
||||||
send(ans)
|
send(ans)
|
||||||
|
|
||||||
def complete_input(self):
|
def complete_input(self):
|
||||||
from calibre.ebooks.conversion.plumber import supported_input_formats
|
ans = list(files_and_dirs(self.prefix, self.cache['input_fmts']))
|
||||||
ans = list(files_and_dirs(self.prefix, supported_input_formats()))
|
ans += [t for t in self.cache['input_recipes'] if
|
||||||
from calibre.web.feeds.recipes import recipes
|
t.startswith(self.prefix)]
|
||||||
ans += [t.title+'.recipe ' for t in recipes if
|
|
||||||
(t.title+'.recipe').startswith(self.prefix)]
|
|
||||||
send(ans)
|
send(ans)
|
||||||
|
|
||||||
def complete_output(self):
|
def complete_output(self):
|
||||||
from calibre.customize.ui import available_output_formats
|
fmts = self.cache['output']
|
||||||
fmts = available_output_formats()
|
|
||||||
ans = list(files_and_dirs(self.prefix, fmts))
|
ans = list(files_and_dirs(self.prefix, fmts))
|
||||||
ans += ['.'+x+' ' for x in fmts if ('.'+x).startswith(self.prefix)]
|
ans += ['.'+x+' ' for x in fmts if ('.'+x).startswith(self.prefix)]
|
||||||
send(ans)
|
send(ans)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def main(args=sys.argv):
|
def main(args=sys.argv):
|
||||||
comp_line, pos = os.environ['COMP_LINE'], int(os.environ['COMP_POINT'])
|
comp_line, pos = os.environ['COMP_LINE'], int(os.environ['COMP_POINT'])
|
||||||
module = split(comp_line)[0].split(os.sep)[-1]
|
module = split(comp_line)[0].split(os.sep)[-1]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user