collator.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import os
  2. import vim
  3. from glob import glob
  4. from itertools import chain
  5. from subprocess import check_output
  6. bib_extensions = ["bib",
  7. "bibtex",
  8. "ris",
  9. "json",
  10. "enl",
  11. "wos",
  12. "medline",
  13. "copac",
  14. "xml"]
  15. class SourceCollator():
  16. def __init__(self, fname=None, query=None, sources="bcg", extra_sources=([], []), **extra_args):
  17. # nvim's python host doesn't change the directory the same way vim does
  18. if vim.eval('has("nvim")') == '1':
  19. os.chdir(vim.eval('expand("%:p:h")'))
  20. self.fname = fname
  21. self.query = query
  22. self.sources = sources
  23. self.extra_sources = extra_sources
  24. self.extra_args = extra_args
  25. def find_bibfiles(self):
  26. def curdir_by_name_search():
  27. """
  28. Search for bibiographies with the same name as the current file in the
  29. current dir.
  30. """
  31. if self.fname in (None, ""): return []
  32. file_name_prefix = os.path.splitext(self.fname)[0]
  33. search_paths = [file_name_prefix + "." + f for f in bib_extensions]
  34. bibfiles = [os.path.abspath(f) for f in search_paths if os.path.exists(f)]
  35. return bibfiles
  36. def curdir_all_search():
  37. """
  38. Search for any other bibliographies in the current dir.
  39. Note: This does not stop bibliographies picked up in b_search() from being found.
  40. """
  41. relative_bibfiles = []
  42. for ext in bib_extensions:
  43. relative_bibfiles.extend(glob("*."+ext))
  44. bibfiles = [os.path.abspath(f) for f in relative_bibfiles]
  45. return bibfiles
  46. def git_search():
  47. """
  48. Search for any bibliographies in the git repository.
  49. """
  50. try:
  51. root_dir = check_output(['git', 'rev-parse', '--show-toplevel']).decode().strip()
  52. except:
  53. return []
  54. git_files = check_output(['git', 'ls-tree',
  55. '-r', '--full-tree', '--name-only',
  56. 'HEAD']).decode().split('\n')
  57. relpaths = []
  58. for f in git_files:
  59. ext = os.path.splitext(f)[1]
  60. if ext != '' and ext[1:] in bib_extensions:
  61. relpaths.append(f)
  62. bibfiles = [os.path.join(root_dir, f) for f in relpaths]
  63. return bibfiles
  64. def pandoc_local_search():
  65. """
  66. Search for bibliographies in the pandoc data dirs.
  67. """
  68. if os.path.exists(os.path.expandvars("$HOME/.pandoc/")):
  69. b = os.path.expandvars("$HOME/.pandoc/")
  70. elif os.path.exists(os.path.expandvars("%APPDATA%/pandoc/")):
  71. b = os.path.expandvars("%APPDATA%/pandoc/")
  72. else:
  73. return []
  74. search_paths = [b + "default." + f for f in bib_extensions]
  75. bibfiles = [os.path.abspath(f) for f in search_paths if os.path.exists(f)]
  76. return bibfiles
  77. def texmf_search():
  78. """
  79. Search for bibliographies in the texmf data dirs.
  80. """
  81. texmf = check_output(["kpsewhich", "-var-value", "TEXMFHOME"]).rstrip()
  82. if os.path.exists(texmf):
  83. search_paths = (texmf.decode() + "/**/*." + f for f in bib_extensions)
  84. relative_bibfiles = (glob(f, recursive=True) for f in search_paths)
  85. bibfiles = [os.path.abspath(f) for f in chain.from_iterable(relative_bibfiles)]
  86. return bibfiles
  87. return []
  88. def explicit_global_search():
  89. """
  90. Add bibliographies defined in pandoc#biblio#bibs,
  91. passed to the collator through the extra_sources argument
  92. """
  93. return self.extra_sources[0]
  94. search_methods = {"b": curdir_by_name_search,
  95. "c": curdir_all_search,
  96. "l": pandoc_local_search,
  97. "t": texmf_search,
  98. "g": explicit_global_search,
  99. "G": git_search}
  100. bibfiles = []
  101. for f in self.sources:
  102. bibfiles.extend(search_methods.get(f, list)())
  103. # add buffer-local bibliographies, defined in b:pandoc_biblio_bibs,
  104. # passed to the collator through the extra_sources argument
  105. bibfiles.extend(self.extra_sources[1])
  106. # check if the items in bibfiles are readable and not directories
  107. # also, ensure items are unique
  108. if bibfiles != []:
  109. bibfiles = list(set(filter(lambda f : os.access(f, os.R_OK) and not os.path.isdir(f), bibfiles)))
  110. return bibfiles
  111. def collate(self):
  112. """
  113. Retrieves the data from the sources.
  114. Should be overriden by sub-classes.
  115. """
  116. pass