diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index c112e06..a5f9468 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -21,9 +21,6 @@ jobs: with: python-version: 3.7 - - name: Install Pandoc - run: sudo apt-get install pandoc - - name: Install dependencies run: | python -m pip install --upgrade pip @@ -53,7 +50,7 @@ jobs: matrix: os: [ubuntu-latest] python-version: [3.6, 3.7, 3.8] - + pandoc-version: [2.9.2, 2.14.0.3] runs-on: ${{ matrix.os }} steps: @@ -64,8 +61,9 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Install Pandoc - run: sudo apt-get install pandoc pandoc-citeproc + - uses: r-lib/actions/setup-pandoc@master + with: + pandoc-version: ${{ matrix.pandoc-version }} - name: Install Python dependencies run: | @@ -81,7 +79,7 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} file: ./coverage.xml - + merge-deps: needs: - lint diff --git a/README.md b/README.md index 75ee357..5a4c86e 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The footnotes extension is how citations are linked for now. - `bib_command` - The command for your bibliography, defaults to `\bibliography` - `full_bib_command` - The command for your bibliography, defaults to `\full_bibliography` - `csl_file` - Bibtex CSL file to format the citation with, defaults to None, using a built in plain format instead -- `unescape_for_arithmatex` - Optional; set to `True` to avoid the `\(` `\)` [issue](https://github.com/shyamd/mkdocs-bibtex/issues/3) with [pymdownx.arithmatex](https://facelessuser.github.io/pymdown-extensions/extensions/arithmatex/) +- `unescape_for_arithmatex` - Optional; set to `True` to avoid the `\(` `\)` [issue](https://github.com/shyamd/mkdocs-bibtex/issues/3) with [pymdownx.arithmatex](https://facelessuser.github.io/pymdown-extensions/extensions/arithmatex/) ## Usage diff --git a/mkdocs_bibtex/plugin.py b/mkdocs_bibtex/plugin.py index c4585c8..defd7ea 100644 --- a/mkdocs_bibtex/plugin.py +++ b/mkdocs_bibtex/plugin.py @@ -1,6 +1,5 @@ -import glob -import os.path import re +from pathlib import Path import tempfile from collections import OrderedDict @@ -30,12 +29,15 @@ class BibTexPlugin(BasePlugin): """ config_scheme = [ - ("bib_file", config_options.Type(str, required=False)), - ("bib_dir", config_options.Type(str, required=False)), - ("cite_style", config_options.Type(str, default="plain")), + ("bib_file", config_options.File(exists=True, required=False)), + ("bib_dir", config_options.Dir(exists=True, required=False)), + ( + "cite_style", + config_options.Choice(choices=["plain", "pandoc"], default="plain"), + ), ("bib_command", config_options.Type(str, default="\\bibliography")), ("full_bib_command", config_options.Type(str, default="\\full_bibliography")), - ("csl_file", config_options.Type(str, required=False)), + ("csl_file", config_options.File(exists=True, required=False)), ("unescape_for_arithmatex", config_options.Type(bool, required=False)), ] @@ -48,25 +50,19 @@ def on_config(self, config): """ Loads bibliography on load of config """ - config_path = os.path.dirname(config.config_file_path) bibfiles = [] if self.config.get("bib_file", None) is not None: - bibfiles.append(get_path(self.config["bib_file"], config_path)) + bibfiles.append(self.config["bib_file"]) elif self.config.get("bib_dir", None) is not None: - bibfiles.extend( - glob.glob( - get_path(os.path.join(self.config["bib_dir"], "*.bib"), config_path) - ) - ) + bibfiles.extend(Path(self.config["bib_dir"]).glob("*.bib")) else: raise Exception("Must supply a bibtex file or directory for bibtex files") # load bibliography data refs = {} for bibfile in bibfiles: - bibfile = get_path(bibfile, config_path) bibdata = parse_file(bibfile) refs.update(bibdata.entries) @@ -158,7 +154,7 @@ def format_citations(self, citations): entry_text = formatted_entry.text.render(backend) entry_text = entry_text.replace("\n", " ") if self.unescape_for_arithmatex: - entry_text = entry_text.replace('\(', '(').replace('\)', ')') + entry_text = entry_text.replace("\(", "(").replace("\)", ")") # Local reference list for this file references[key] = entry_text # Global reference list for all files @@ -179,41 +175,49 @@ def full_bibliography(self): return "\n".join(full_bibliography) -def get_path(path, base_path): - if path is None: - return None - elif os.path.isabs(path): - return path - else: - return os.path.abspath(os.path.join(base_path, path)) - - def to_markdown_pandoc(entry, csl_path): """ Converts the PyBtex entry into formatted markdown citation text """ bibtex_string = BibliographyData(entries={entry.key: entry}).to_string("bibtex") - citation_text = """ + if tuple(int(ver) for ver in pypandoc.get_pandoc_version().split(".")) >= ( + 2, + 11, + ): + markdown = pypandoc.convert_text( + source=bibtex_string, + to="markdown-citations", + format="bibtex", + extra_args=[ + "--citeproc", + "--csl", + csl_path, + ], + ) + + citation_regex = re.compile( + r"\{\.csl-left-margin\}\[(.*)\]\{\.csl-right-inline\}" + ) + citation = citation_regex.findall(" ".join(markdown.split("\n")))[0] + else: + # Older citeproc-filter version of pandoc + with tempfile.TemporaryDirectory() as tmpdir: + bib_path = Path(tmpdir).joinpath("temp.bib") + with open(bib_path, "w") as bibfile: + bibfile.write(bibtex_string) + citation_text = """ --- nocite: '@*' --- """ - with tempfile.TemporaryDirectory() as tmpdir: - bib_path = os.path.join(tmpdir, "temp.bib") - with open(bib_path, "w") as bibfile: - bibfile.write(bibtex_string) - - # Call Pandoc. - markdown = pypandoc.convert_text( - source=citation_text, - to="markdown_strict-citations", - format="md", - extra_args=["--csl", csl_path, "--bibliography", bib_path], - filters=["pandoc-citeproc"], - ) - - # TODO: Perform this extraction better - markdown = markdown.split("\n")[0][2:] + markdown = pypandoc.convert_text( + source=citation_text, + to="markdown_strict", + format="md", + extra_args=["--csl", csl_path, "--bibliography", bib_path], + filters=["pandoc-citeproc"], + ) - return str(markdown) + citation = markdown.replace("\n", " ")[4:] + return citation diff --git a/mkdocs_bibtex/test_plugin.py b/mkdocs_bibtex/test_plugin.py index 86b8da3..4c53c24 100644 --- a/mkdocs_bibtex/test_plugin.py +++ b/mkdocs_bibtex/test_plugin.py @@ -24,13 +24,13 @@ def test_unescape_for_arithmatex(self): self.plugin.unescape_for_arithmatex = True self.assertIn( "First Author and Second Author\. Test Title (TT)\. *Testing Journal (TJ)*, 2019", - self.plugin.format_citations(test_data.entries.items())["test"] + self.plugin.format_citations(test_data.entries.items())["test"], ) self.plugin.unescape_for_arithmatex = False self.assertIn( "First Author and Second Author\. Test Title \(TT\)\. *Testing Journal \(TJ\)*, 2019", - self.plugin.format_citations(test_data.entries.items())["test"] + self.plugin.format_citations(test_data.entries.items())["test"], ) def test_config_one_bibtex_file(self): @@ -62,6 +62,20 @@ def test_format_citations(self): ) # TODO: Check CSL + def test_long_citation(self): + test_data = parse_file(os.path.join(test_files_dir, "long_cite.bib")) + self.plugin.csl_file = None + self.assertIn( + "Benjamin L\\. De Bivort and Bruno Van Swinderen", + self.plugin.format_citations(test_data.entries.items())["Bivort2016"], + ) + + self.plugin.csl_file = os.path.join(test_files_dir, "nature.csl") + self.assertIn( + "De Bivort, B. L. & Van Swinderen", + self.plugin.format_citations(test_data.entries.items())["Bivort2016"], + ) + def test_full_bibliography(self): test_data = parse_file(os.path.join(test_files_dir, "single.bib")) self.plugin.csl_file = None diff --git a/test_files/long_cite.bib b/test_files/long_cite.bib new file mode 100644 index 0000000..2a7fa9e --- /dev/null +++ b/test_files/long_cite.bib @@ -0,0 +1,13 @@ +@article{Bivort2016, + title = {Evidence for Selective Attention in the Insect Brain}, + author = {De Bivort, Benjamin L. and Van Swinderen, Bruno}, + year = {2016}, + volume = {15}, + pages = {1--7}, + issn = {22145753}, + doi = {10.1016/j.cois.2016.02.007}, + abstract = {The capacity for selective attention appears to be required by any animal responding to an environment containing multiple objects, although this has been difficult to study in smaller animals such as insects. Clear operational characteristics of attention however make study of this crucial brain function accessible to any animal model. Whereas earlier approaches have relied on freely behaving paradigms placed in an ecologically relevant context, recent tethered preparations have focused on brain imaging and electrophysiology in virtual reality environments. Insight into brain activity during attention-like behavior has revealed key elements of attention in the insect brain. Surprisingly, a variety of brain structures appear to be involved, suggesting that even in the smallest brains attention might involve widespread coordination of neural activity.}, + journal = {Current Opinion in Insect Science}, + keywords = {attention,bees,drosophila,insects}, + pmid = {27436727} +}