commit
2465f821ba
@ -9,7 +9,7 @@ from .. import color
|
|||||||
from .. import pretty
|
from .. import pretty
|
||||||
|
|
||||||
|
|
||||||
def parser(subparsers):
|
def parser(subparsers, conf):
|
||||||
parser = subparsers.add_parser('add', help='add a paper to the repository')
|
parser = subparsers.add_parser('add', help='add a paper to the repository')
|
||||||
parser.add_argument('bibfile', nargs='?', default=None,
|
parser.add_argument('bibfile', nargs='?', default=None,
|
||||||
help='bibtex file')
|
help='bibtex file')
|
||||||
|
@ -3,7 +3,7 @@ from .. import config
|
|||||||
from .. import content
|
from .. import content
|
||||||
|
|
||||||
|
|
||||||
def parser(subparsers):
|
def parser(subparsers, conf):
|
||||||
parser = subparsers.add_parser('conf',
|
parser = subparsers.add_parser('conf',
|
||||||
help='open the configuration in an editor')
|
help='open the configuration in an editor')
|
||||||
return parser
|
return parser
|
||||||
@ -17,7 +17,7 @@ def command(conf, args):
|
|||||||
# get modif from user
|
# get modif from user
|
||||||
ui.edit_file(config.get_confpath())
|
ui.edit_file(config.get_confpath())
|
||||||
|
|
||||||
new_conf = config.load_conf(check=False)
|
new_conf = config.load_conf()
|
||||||
try:
|
try:
|
||||||
config.check_conf(new_conf)
|
config.check_conf(new_conf)
|
||||||
ui.message('The configuration file was updated.')
|
ui.message('The configuration file was updated.')
|
||||||
|
@ -6,6 +6,8 @@ from .. import color
|
|||||||
from ..uis import get_ui
|
from ..uis import get_ui
|
||||||
from .. import content
|
from .. import content
|
||||||
from ..utils import resolve_citekey, resolve_citekey_list
|
from ..utils import resolve_citekey, resolve_citekey_list
|
||||||
|
from ..completion import CiteKeyCompletion
|
||||||
|
|
||||||
|
|
||||||
# doc --+- add $file $key [[-L|--link] | [-M|--move]] [-f|--force]
|
# doc --+- add $file $key [[-L|--link] | [-M|--move]] [-f|--force]
|
||||||
# +- remove $key [$key [...]] [-f|--force]
|
# +- remove $key [$key [...]] [-f|--force]
|
||||||
@ -13,35 +15,46 @@ from ..utils import resolve_citekey, resolve_citekey_list
|
|||||||
# +- open $key [-w|--with $cmd]
|
# +- open $key [-w|--with $cmd]
|
||||||
# supplements attach, open
|
# supplements attach, open
|
||||||
|
|
||||||
def parser(subparsers):
|
def parser(subparsers, conf):
|
||||||
doc_parser = subparsers.add_parser('doc', help='manage the document relating to a publication')
|
doc_parser = subparsers.add_parser(
|
||||||
doc_subparsers = doc_parser.add_subparsers(title='document actions', help='actions to interact with the documents',
|
'doc',
|
||||||
dest='action')
|
help='manage the document relating to a publication')
|
||||||
|
doc_subparsers = doc_parser.add_subparsers(
|
||||||
|
title='document actions', dest='action',
|
||||||
|
help='actions to interact with the documents')
|
||||||
doc_subparsers.required = True
|
doc_subparsers.required = True
|
||||||
|
|
||||||
add_parser = doc_subparsers.add_parser('add', help='add a document to a publication')
|
add_parser = doc_subparsers.add_parser('add', help='add a document to a publication')
|
||||||
add_parser.add_argument('-f', '--force', action='store_true', dest='force', default=False,
|
add_parser.add_argument('-f', '--force', action='store_true', dest='force', default=False,
|
||||||
help='force overwriting an already assigned document')
|
help='force overwriting an already assigned document')
|
||||||
add_parser.add_argument('document', nargs=1, help='document file to assign')
|
add_parser.add_argument('document', nargs=1, help='document file to assign')
|
||||||
add_parser.add_argument('citekey', nargs=1, help='citekey of the publication')
|
add_parser.add_argument('citekey', nargs=1, help='citekey of the publication'
|
||||||
|
).completer = CiteKeyCompletion(conf)
|
||||||
add_exclusives = add_parser.add_mutually_exclusive_group()
|
add_exclusives = add_parser.add_mutually_exclusive_group()
|
||||||
add_exclusives.add_argument('-L', '--link', action='store_false', dest='link', default=False,
|
add_exclusives.add_argument(
|
||||||
help='do not copy document files, just create a link')
|
'-L', '--link', action='store_false', dest='link', default=False,
|
||||||
add_exclusives.add_argument('-M', '--move', action='store_true', dest='move', default=False,
|
help='do not copy document files, just create a link')
|
||||||
help='move document instead of of copying (ignored if --link)')
|
add_exclusives.add_argument(
|
||||||
|
'-M', '--move', action='store_true', dest='move', default=False,
|
||||||
|
help='move document instead of of copying (ignored if --link)')
|
||||||
|
|
||||||
remove_parser = doc_subparsers.add_parser('remove', help='remove assigned documents from publications')
|
remove_parser = doc_subparsers.add_parser('remove', help='remove assigned documents from publications')
|
||||||
remove_parser.add_argument('citekeys', nargs='+', help='citekeys of the publications')
|
remove_parser.add_argument('citekeys', nargs='+', help='citekeys of the publications'
|
||||||
remove_parser.add_argument('-f', '--force', action='store_true', dest='force', default=False,
|
).completer = CiteKeyCompletion(conf)
|
||||||
help='force removing assigned documents')
|
remove_parser.add_argument('-f', '--force', action='store_true', dest='force',
|
||||||
|
default=False,
|
||||||
|
help='force removing assigned documents')
|
||||||
|
|
||||||
# favor key+ path over: key
|
# favor key+ path over: key
|
||||||
export_parser = doc_subparsers.add_parser('export', help='export assigned documents to given path')
|
export_parser = doc_subparsers.add_parser('export', help='export assigned documents to given path')
|
||||||
export_parser.add_argument('citekeys', nargs='+', help='citekeys of the documents to export')
|
export_parser.add_argument('citekeys', nargs='+',
|
||||||
|
help='citekeys of the documents to export'
|
||||||
|
).completer = CiteKeyCompletion(conf)
|
||||||
export_parser.add_argument('path', nargs=1, help='directory to export the files to')
|
export_parser.add_argument('path', nargs=1, help='directory to export the files to')
|
||||||
|
|
||||||
open_parser = doc_subparsers.add_parser('open', help='open an assigned document')
|
open_parser = doc_subparsers.add_parser('open', help='open an assigned document')
|
||||||
open_parser.add_argument('citekey', nargs=1, help='citekey of the document to open')
|
open_parser.add_argument('citekey', nargs=1, help='citekey of the document to open'
|
||||||
|
).completer = CiteKeyCompletion(conf)
|
||||||
open_parser.add_argument('-w', '--with', dest='cmd', help='command to open the file with')
|
open_parser.add_argument('-w', '--with', dest='cmd', help='command to open the file with')
|
||||||
|
|
||||||
return doc_parser
|
return doc_parser
|
||||||
|
@ -4,15 +4,19 @@ from .. import repo
|
|||||||
from ..uis import get_ui
|
from ..uis import get_ui
|
||||||
from ..endecoder import EnDecoder
|
from ..endecoder import EnDecoder
|
||||||
from ..utils import resolve_citekey
|
from ..utils import resolve_citekey
|
||||||
|
from ..completion import CiteKeyCompletion
|
||||||
|
|
||||||
|
|
||||||
def parser(subparsers):
|
def parser(subparsers, conf):
|
||||||
parser = subparsers.add_parser('edit',
|
parser = subparsers.add_parser(
|
||||||
help='open the paper bibliographic file in an editor')
|
'edit',
|
||||||
parser.add_argument('-m', '--meta', action='store_true', default=False,
|
help='open the paper bibliographic file in an editor')
|
||||||
help='edit metadata')
|
parser.add_argument(
|
||||||
parser.add_argument('citekey',
|
'-m', '--meta', action='store_true', default=False,
|
||||||
help='citekey of the paper')
|
help='edit metadata')
|
||||||
|
parser.add_argument(
|
||||||
|
'citekey',
|
||||||
|
help='citekey of the paper').completer = CiteKeyCompletion(conf)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,12 +4,15 @@ from .. import repo
|
|||||||
from ..uis import get_ui
|
from ..uis import get_ui
|
||||||
from .. import endecoder
|
from .. import endecoder
|
||||||
from ..utils import resolve_citekey_list
|
from ..utils import resolve_citekey_list
|
||||||
|
from ..completion import CiteKeyCompletion
|
||||||
|
|
||||||
def parser(subparsers):
|
|
||||||
|
def parser(subparsers, conf):
|
||||||
parser = subparsers.add_parser('export', help='export bibliography')
|
parser = subparsers.add_parser('export', help='export bibliography')
|
||||||
# parser.add_argument('-f', '--bib-format', default='bibtex',
|
# parser.add_argument('-f', '--bib-format', default='bibtex',
|
||||||
# help='export format')
|
# help='export format')
|
||||||
parser.add_argument('citekeys', nargs='*', help='one or several citekeys')
|
parser.add_argument('citekeys', nargs='*', help='one or several citekeys'
|
||||||
|
).completer = CiteKeyCompletion(conf)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ from ..uis import get_ui
|
|||||||
from ..content import system_path, read_text_file
|
from ..content import system_path, read_text_file
|
||||||
|
|
||||||
|
|
||||||
def parser(subparsers):
|
def parser(subparsers, conf):
|
||||||
parser = subparsers.add_parser('import',
|
parser = subparsers.add_parser('import',
|
||||||
help='import paper(s) to the repository')
|
help='import paper(s) to the repository')
|
||||||
parser.add_argument('bibpath',
|
parser.add_argument('bibpath',
|
||||||
|
@ -9,7 +9,8 @@ from ..repo import Repository
|
|||||||
from ..content import system_path, check_directory
|
from ..content import system_path, check_directory
|
||||||
from .. import config
|
from .. import config
|
||||||
|
|
||||||
def parser(subparsers):
|
|
||||||
|
def parser(subparsers, conf):
|
||||||
parser = subparsers.add_parser('init',
|
parser = subparsers.add_parser('init',
|
||||||
help="initialize the pubs directory")
|
help="initialize the pubs directory")
|
||||||
parser.add_argument('-p', '--pubsdir', default=None,
|
parser.add_argument('-p', '--pubsdir', default=None,
|
||||||
|
@ -10,7 +10,7 @@ class InvalidQuery(ValueError):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def parser(subparsers):
|
def parser(subparsers, conf):
|
||||||
parser = subparsers.add_parser('list', help="list papers")
|
parser = subparsers.add_parser('list', help="list papers")
|
||||||
parser.add_argument('-k', '--citekeys-only', action='store_true',
|
parser.add_argument('-k', '--citekeys-only', action='store_true',
|
||||||
default=False, dest='citekeys',
|
default=False, dest='citekeys',
|
||||||
|
@ -2,19 +2,19 @@ from .. import repo
|
|||||||
from .. import content
|
from .. import content
|
||||||
from ..uis import get_ui
|
from ..uis import get_ui
|
||||||
from ..utils import resolve_citekey
|
from ..utils import resolve_citekey
|
||||||
|
from ..completion import CiteKeyCompletion
|
||||||
|
|
||||||
|
|
||||||
def parser(subparsers):
|
def parser(subparsers, conf):
|
||||||
parser = subparsers.add_parser('note',
|
parser = subparsers.add_parser('note',
|
||||||
help='edit the note attached to a paper')
|
help='edit the note attached to a paper')
|
||||||
parser.add_argument('citekey',
|
parser.add_argument('citekey',
|
||||||
help='citekey of the paper')
|
help='citekey of the paper'
|
||||||
|
).completer = CiteKeyCompletion(conf)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
def command(conf, args):
|
def command(conf, args):
|
||||||
"""
|
|
||||||
"""
|
|
||||||
|
|
||||||
ui = get_ui()
|
ui = get_ui()
|
||||||
rp = repo.Repository(conf)
|
rp = repo.Repository(conf)
|
||||||
|
@ -3,13 +3,16 @@ from .. import color
|
|||||||
from ..uis import get_ui
|
from ..uis import get_ui
|
||||||
from ..utils import resolve_citekey_list
|
from ..utils import resolve_citekey_list
|
||||||
from ..p3 import ustr
|
from ..p3 import ustr
|
||||||
|
from ..completion import CiteKeyCompletion
|
||||||
|
|
||||||
def parser(subparsers):
|
|
||||||
|
def parser(subparsers, conf):
|
||||||
parser = subparsers.add_parser('remove', help='removes a publication')
|
parser = subparsers.add_parser('remove', help='removes a publication')
|
||||||
parser.add_argument('-f', '--force', action='store_true', default=None,
|
parser.add_argument('-f', '--force', action='store_true', default=None,
|
||||||
help="does not prompt for confirmation.")
|
help="does not prompt for confirmation.")
|
||||||
parser.add_argument('citekeys', nargs='+',
|
parser.add_argument('citekeys', nargs='+',
|
||||||
help="one or several citekeys")
|
help="one or several citekeys"
|
||||||
|
).completer = CiteKeyCompletion(conf)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,13 +2,15 @@ from ..uis import get_ui
|
|||||||
from .. import color
|
from .. import color
|
||||||
from .. import repo
|
from .. import repo
|
||||||
from ..utils import resolve_citekey
|
from ..utils import resolve_citekey
|
||||||
|
from ..completion import CiteKeyCompletion
|
||||||
|
|
||||||
def parser(subparsers):
|
|
||||||
parser = subparsers.add_parser('rename', help='rename the citekey of a repository')
|
def parser(subparsers, conf):
|
||||||
parser.add_argument('citekey',
|
parser = subparsers.add_parser('rename',
|
||||||
help='current citekey')
|
help='rename the citekey of a repository')
|
||||||
parser.add_argument('new_citekey',
|
parser.add_argument('citekey', help='current citekey'
|
||||||
help='new citekey')
|
).completer = CiteKeyCompletion(conf)
|
||||||
|
parser.add_argument('new_citekey', help='new citekey')
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@ -26,7 +28,7 @@ def command(conf, args):
|
|||||||
paper = rp.pull_paper(key)
|
paper = rp.pull_paper(key)
|
||||||
rp.rename_paper(paper, args.new_citekey)
|
rp.rename_paper(paper, args.new_citekey)
|
||||||
ui.message("The '{}' citekey has been renamed into '{}'".format(
|
ui.message("The '{}' citekey has been renamed into '{}'".format(
|
||||||
color.dye_out(args.citekey, 'citekey'),
|
color.dye_out(args.citekey, 'citekey'),
|
||||||
color.dye_out(args.new_citekey, 'citekey')))
|
color.dye_out(args.new_citekey, 'citekey')))
|
||||||
|
|
||||||
rp.close()
|
rp.close()
|
||||||
|
@ -24,15 +24,17 @@ from ..uis import get_ui
|
|||||||
from .. import pretty
|
from .. import pretty
|
||||||
from .. import color
|
from .. import color
|
||||||
from ..utils import resolve_citekey
|
from ..utils import resolve_citekey
|
||||||
|
from ..completion import CiteKeyOrTagCompletion, TagModifierCompletion
|
||||||
|
|
||||||
|
|
||||||
def parser(subparsers):
|
def parser(subparsers, conf):
|
||||||
parser = subparsers.add_parser('tag', help="add, remove and show tags")
|
parser = subparsers.add_parser('tag', help="add, remove and show tags")
|
||||||
parser.add_argument('citekeyOrTag', nargs='?', default=None,
|
parser.add_argument('citekeyOrTag', nargs='?', default=None,
|
||||||
help='citekey or tag.')
|
help='citekey or tag.').completer = CiteKeyOrTagCompletion(conf)
|
||||||
parser.add_argument('tags', nargs='?', default=None,
|
parser.add_argument('tags', nargs='?', default=None,
|
||||||
help='If the previous argument was a citekey, then '
|
help='If the previous argument was a citekey, then '
|
||||||
'a list of tags separated by a +.')
|
'a list of tags separated by + and -.'
|
||||||
|
).completer = TagModifierCompletion(conf)
|
||||||
# TODO find a way to display clear help for multiple command semantics,
|
# TODO find a way to display clear help for multiple command semantics,
|
||||||
# indistinguisable for argparse. (fabien, 201306)
|
# indistinguisable for argparse. (fabien, 201306)
|
||||||
return parser
|
return parser
|
||||||
@ -70,6 +72,7 @@ def _tag_groups(tags):
|
|||||||
minus_tags.append(tag[1:])
|
minus_tags.append(tag[1:])
|
||||||
return set(plus_tags), set(minus_tags)
|
return set(plus_tags), set(minus_tags)
|
||||||
|
|
||||||
|
|
||||||
def command(conf, args):
|
def command(conf, args):
|
||||||
"""Add, remove and show tags"""
|
"""Add, remove and show tags"""
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@ import urllib
|
|||||||
|
|
||||||
from ..uis import get_ui
|
from ..uis import get_ui
|
||||||
|
|
||||||
def parser(subparsers):
|
|
||||||
|
def parser(subparsers, conf):
|
||||||
parser = subparsers.add_parser('websearch',
|
parser = subparsers.add_parser('websearch',
|
||||||
help="launch a search on Google Scholar")
|
help="launch a search on Google Scholar")
|
||||||
parser.add_argument("search_string", nargs = '*',
|
parser.add_argument("search_string", nargs = '*',
|
||||||
|
59
pubs/completion.py
Normal file
59
pubs/completion.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import re
|
||||||
|
try:
|
||||||
|
import argcomplete
|
||||||
|
except ImportError:
|
||||||
|
|
||||||
|
class FakeModule:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _fun(*args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __getattr__(self, _):
|
||||||
|
return self._fun
|
||||||
|
|
||||||
|
argcomplete = FakeModule()
|
||||||
|
|
||||||
|
from . import repo
|
||||||
|
|
||||||
|
|
||||||
|
def autocomplete(parser):
|
||||||
|
argcomplete.autocomplete(parser)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseCompleter(object):
|
||||||
|
|
||||||
|
def __init__(self, conf):
|
||||||
|
self.conf = conf
|
||||||
|
|
||||||
|
def __call__(self, **kwargs):
|
||||||
|
try:
|
||||||
|
return self._complete(**kwargs)
|
||||||
|
except Exception as e:
|
||||||
|
argcomplete.warn(e)
|
||||||
|
|
||||||
|
|
||||||
|
class CiteKeyCompletion(BaseCompleter):
|
||||||
|
|
||||||
|
def _complete(self, **kwargs):
|
||||||
|
rp = repo.Repository(self.conf)
|
||||||
|
return rp.citekeys
|
||||||
|
|
||||||
|
|
||||||
|
class CiteKeyOrTagCompletion(BaseCompleter):
|
||||||
|
|
||||||
|
def _complete(self, **kwargs):
|
||||||
|
rp = repo.Repository(self.conf)
|
||||||
|
return rp.citekeys.union(rp.get_tags())
|
||||||
|
|
||||||
|
|
||||||
|
class TagModifierCompletion(BaseCompleter):
|
||||||
|
|
||||||
|
regxp = r"[^:+-]*$" # prefix of tag after last separator
|
||||||
|
|
||||||
|
def _complete(self, prefix, **kwargs):
|
||||||
|
tags = repo.Repository(self.conf).get_tags()
|
||||||
|
start, _ = re.search(self.regxp, prefix).span()
|
||||||
|
partial_expr = prefix[:start]
|
||||||
|
t_prefix = prefix[start:]
|
||||||
|
return [partial_expr + t for t in tags if t.startswith(t_prefix)]
|
@ -1,2 +1,3 @@
|
|||||||
from .conf import get_confpath, load_default_conf, load_conf, save_conf, check_conf
|
from .conf import (get_confpath, load_default_conf, load_conf, save_conf,
|
||||||
|
check_conf, ConfigurationNotFound)
|
||||||
from .conf import default_open_cmd, post_process_conf
|
from .conf import default_open_cmd, post_process_conf
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import shutil
|
|
||||||
|
|
||||||
|
|
||||||
import configobj
|
import configobj
|
||||||
import validate
|
import validate
|
||||||
@ -11,6 +9,16 @@ from .spec import configspec
|
|||||||
|
|
||||||
DFT_CONFIG_PATH = os.path.expanduser('~/.pubsrc')
|
DFT_CONFIG_PATH = os.path.expanduser('~/.pubsrc')
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigurationNotFound(IOError):
|
||||||
|
|
||||||
|
def __init__(self, path):
|
||||||
|
super(ConfigurationNotFound, self).__init__(
|
||||||
|
"No configuration found at path {}. Maybe you need to initialize "
|
||||||
|
"your repository with `pubs init` or specify a --config argument."
|
||||||
|
"".format(path))
|
||||||
|
|
||||||
|
|
||||||
def post_process_conf(conf):
|
def post_process_conf(conf):
|
||||||
"""Do some post processing on the configuration"""
|
"""Do some post processing on the configuration"""
|
||||||
if conf['main']['docsdir'] == 'docsdir://':
|
if conf['main']['docsdir'] == 'docsdir://':
|
||||||
@ -50,14 +58,14 @@ def check_conf(conf):
|
|||||||
assert results == True, '{}'.format(results) # TODO: precise error dialog when parsing error
|
assert results == True, '{}'.format(results) # TODO: precise error dialog when parsing error
|
||||||
|
|
||||||
|
|
||||||
def load_conf(check=True, path=None):
|
def load_conf(path=None):
|
||||||
"""Load the configuration"""
|
"""Load the configuration"""
|
||||||
if path is None:
|
if path is None:
|
||||||
path = get_confpath(verify=True)
|
path = get_confpath(verify=True)
|
||||||
|
if not os.path.exists(path):
|
||||||
|
raise ConfigurationNotFound(path)
|
||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
conf = configobj.ConfigObj(f.readlines(), configspec=configspec)
|
conf = configobj.ConfigObj(f.readlines(), configspec=configspec)
|
||||||
if check:
|
|
||||||
check_conf(conf)
|
|
||||||
conf.filename = path
|
conf.filename = path
|
||||||
conf = post_process_conf(conf)
|
conf = post_process_conf(conf)
|
||||||
return conf
|
return conf
|
||||||
|
@ -14,7 +14,7 @@ class PapersPlugin(object):
|
|||||||
|
|
||||||
name = None
|
name = None
|
||||||
|
|
||||||
def get_commands(self, subparsers):
|
def get_commands(self, subparsers, conf):
|
||||||
"""Populates the parser with plugins specific command.
|
"""Populates the parser with plugins specific command.
|
||||||
Returns iterable of pairs (command name, command function to call).
|
Returns iterable of pairs (command name, command function to call).
|
||||||
"""
|
"""
|
||||||
|
@ -65,7 +65,7 @@ class AliasPlugin(PapersPlugin):
|
|||||||
for name, definition in conf['plugins']['alias'].items():
|
for name, definition in conf['plugins']['alias'].items():
|
||||||
self.aliases.append(Alias.create_alias(name, definition))
|
self.aliases.append(Alias.create_alias(name, definition))
|
||||||
|
|
||||||
def update_parser(self, subparsers):
|
def update_parser(self, subparsers, conf):
|
||||||
"""Add subcommand to the provided subparser"""
|
"""Add subcommand to the provided subparser"""
|
||||||
for alias in self.aliases:
|
for alias in self.aliases:
|
||||||
alias_parser = alias.parser(subparsers)
|
alias_parser = alias.parser(subparsers)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
# PYTHON_ARGCOMPLETE_OK
|
||||||
|
|
||||||
from pubs import pubs_cmd
|
from pubs import pubs_cmd
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from . import commands
|
|||||||
from . import update
|
from . import update
|
||||||
from . import plugins
|
from . import plugins
|
||||||
from .__init__ import __version__
|
from .__init__ import __version__
|
||||||
|
from .completion import autocomplete
|
||||||
|
|
||||||
|
|
||||||
CORE_CMDS = collections.OrderedDict([
|
CORE_CMDS = collections.OrderedDict([
|
||||||
@ -49,15 +50,18 @@ def execute(raw_args=sys.argv):
|
|||||||
conf_path = config.get_confpath(verify=False) # will be checked on load
|
conf_path = config.get_confpath(verify=False) # will be checked on load
|
||||||
|
|
||||||
# Loading config
|
# Loading config
|
||||||
if len(remaining_args) > 0 and remaining_args[0] != 'init':
|
try:
|
||||||
conf = config.load_conf(path=conf_path, check=False)
|
conf = config.load_conf(path=conf_path)
|
||||||
if update.update_check(conf, path=conf.filename):
|
if update.update_check(conf, path=conf.filename):
|
||||||
# an update happened, reload conf.
|
# an update happened, reload conf.
|
||||||
conf = config.load_conf(path=conf_path, check=False)
|
conf = config.load_conf(path=conf_path)
|
||||||
config.check_conf(conf)
|
config.check_conf(conf)
|
||||||
else:
|
except config.ConfigurationNotFound:
|
||||||
conf = config.load_default_conf()
|
if len(remaining_args) == 0 or remaining_args[0] == 'init':
|
||||||
conf.filename = conf_path
|
conf = config.load_default_conf()
|
||||||
|
conf.filename = conf_path
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
uis.init_ui(conf, force_colors=top_args.force_colors)
|
uis.init_ui(conf, force_colors=top_args.force_colors)
|
||||||
ui = uis.get_ui()
|
ui = uis.get_ui()
|
||||||
@ -70,14 +74,16 @@ def execute(raw_args=sys.argv):
|
|||||||
|
|
||||||
# Populate the parser with core commands
|
# Populate the parser with core commands
|
||||||
for cmd_name, cmd_mod in CORE_CMDS.items():
|
for cmd_name, cmd_mod in CORE_CMDS.items():
|
||||||
cmd_parser = cmd_mod.parser(subparsers)
|
cmd_parser = cmd_mod.parser(subparsers, conf)
|
||||||
cmd_parser.set_defaults(func=cmd_mod.command)
|
cmd_parser.set_defaults(func=cmd_mod.command)
|
||||||
|
|
||||||
# Extend with plugin commands
|
# Extend with plugin commands
|
||||||
plugins.load_plugins(conf, ui)
|
plugins.load_plugins(conf, ui)
|
||||||
for p in plugins.get_plugins().values():
|
for p in plugins.get_plugins().values():
|
||||||
p.update_parser(subparsers)
|
p.update_parser(subparsers, conf)
|
||||||
|
|
||||||
|
# Eventually autocomplete
|
||||||
|
autocomplete(parser)
|
||||||
# Parse and run appropriate command
|
# Parse and run appropriate command
|
||||||
args = parser.parse_args(remaining_args)
|
args = parser.parse_args(remaining_args)
|
||||||
args.prog = "pubs" # FIXME?
|
args.prog = "pubs" # FIXME?
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
import sys
|
||||||
from . import config
|
from . import config
|
||||||
from . import uis
|
from . import uis
|
||||||
from . import color
|
from . import color
|
||||||
@ -33,6 +34,7 @@ def update_check(conf, path=None):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def update(conf, code_version, repo_version, path=None):
|
def update(conf, code_version, repo_version, path=None):
|
||||||
"""Runs an update if necessary, and return True in that case."""
|
"""Runs an update if necessary, and return True in that case."""
|
||||||
if path is None:
|
if path is None:
|
||||||
|
30
readme.md
30
readme.md
@ -15,18 +15,20 @@ Pubs is built with the following principles in mind:
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Until pubs is uploaded to Pypi, the standard way to install it is to clone the repository and call `setup.py`.
|
Currently, the Pypi version is outdated. You can install the development version of `pubs`, which should be stable, with:
|
||||||
|
|
||||||
git clone https://github.com/pubs/pubs.git
|
pip install --upgrade git+https://github.com/pubs/pubs
|
||||||
cd pubs
|
|
||||||
sudo python setup.py install # remove sudo and add --user for local installation instead
|
If `pubs` is already installed, you can upgrade with:
|
||||||
|
|
||||||
|
pip install --upgrade git+https://github.com/pubs/pubs
|
||||||
|
|
||||||
Alternatively Arch Linux users can also use the [pubs-git](https://aur.archlinux.org/packages/pubs-git/) AUR package.
|
Alternatively Arch Linux users can also use the [pubs-git](https://aur.archlinux.org/packages/pubs-git/) AUR package.
|
||||||
|
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
Create your library (by default, goes to '~/.pubs/').
|
Create your library (by default, goes to `~/.pubs/`).
|
||||||
|
|
||||||
pubs init
|
pubs init
|
||||||
|
|
||||||
@ -88,15 +90,29 @@ The first command defines a new subcommand: `pubs open -w evince` will be execut
|
|||||||
The second starts with a bang: `!`, and is treated as a shell command.
|
The second starts with a bang: `!`, and is treated as a shell command.
|
||||||
|
|
||||||
|
|
||||||
|
## Autocompletion
|
||||||
|
|
||||||
|
For autocompletion to work, you need the [argcomplete](https://argcomplete.readthedocs.io) Python package, and Bash 4.2 or newer. For activating *bash* or *tsch* completion, consult the [argcomplete documentation](https://argcomplete.readthedocs.io/en/latest/#global-completion).
|
||||||
|
|
||||||
|
For *zsh* completion, the global activation is not supported but bash completion compatibility can be used for pubs. For that, add the following to your `.zshrc`:
|
||||||
|
|
||||||
|
# Enable and load bashcompinit
|
||||||
|
autoload -Uz compinit bashcompinit
|
||||||
|
compinit
|
||||||
|
bashcompinit
|
||||||
|
# Argcomplete explicit registration for pubs
|
||||||
|
eval "$(register-python-argcomplete pubs)"
|
||||||
|
|
||||||
|
|
||||||
## Need more help ?
|
## Need more help ?
|
||||||
|
|
||||||
You can access the self-documented configuration by using `pubs conf`, and all the commands's help is available with the `--help` option. Did not find an answer to your question? Drop us an issue. We may not answer right away (science comes first!) but we'll eventually look into it.
|
You can access the self-documented configuration by using `pubs conf`, and all the commands' help is available with the `--help` option. Did not find an answer to your question? Drop us an issue. We may not answer right away (science comes first!) but we'll eventually look into it.
|
||||||
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- python >= 2.7 or >= 3.3
|
- python >= 2.7 or >= 3.3
|
||||||
|
- [argcomplete](https://argcomplete.readthedocs.io) (optional, for autocompletion)
|
||||||
|
|
||||||
## Authors
|
## Authors
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class FakeSystemExit(Exception):
|
|||||||
SystemExit exceptions are replaced by FakeSystemExit in the execute_cmds()
|
SystemExit exceptions are replaced by FakeSystemExit in the execute_cmds()
|
||||||
function, so they can be catched by ExpectedFailure tests in Python 2.x.
|
function, so they can be catched by ExpectedFailure tests in Python 2.x.
|
||||||
|
|
||||||
If a code is accepted to raise SystemExit, catch FakeSystemExit instead.
|
If a code is expected to raise SystemExit, catch FakeSystemExit instead.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -151,6 +151,13 @@ class DataCommandTestCase(CommandTestCase):
|
|||||||
|
|
||||||
# Actual tests
|
# Actual tests
|
||||||
|
|
||||||
|
class TestAlone(CommandTestCase):
|
||||||
|
|
||||||
|
def test_alone_misses_command(self):
|
||||||
|
with self.assertRaises(FakeSystemExit):
|
||||||
|
self.execute_cmds(['pubs'])
|
||||||
|
|
||||||
|
|
||||||
class TestInit(CommandTestCase):
|
class TestInit(CommandTestCase):
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user