diff --git a/Manifest.toml b/Manifest.toml new file mode 100644 index 00000000..dcbe3b59 --- /dev/null +++ b/Manifest.toml @@ -0,0 +1,161 @@ +# This file is machine-generated - editing it directly is not advised + +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[BibTeX]] +git-tree-sha1 = "f434dde47e2c755c7cf9472bd394d1c074d7f475" +repo-rev = "master" +repo-url = "https://github.com/mpastell/BibTeX.jl.git" +uuid = "0c132655-f423-5f6f-9a5a-d55cfa15b9d7" +version = "0.0.0" + +[[Codecs]] +deps = ["Test"] +git-tree-sha1 = "70885e5e038cba1c4c17a84ad6c40756e10a4fb5" +uuid = "19ecbf4d-ef7c-5e4b-b54a-0a0ff23c5aed" +version = "0.5.0" + +[[Compat]] +deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] +git-tree-sha1 = "49269e311ffe11ac5b334681d212329002a9832a" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "1.5.1" + +[[Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[DelimitedFiles]] +deps = ["Mmap"] +uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" + +[[Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[DocStringExtensions]] +deps = ["LibGit2", "Markdown", "Pkg", "Test"] +git-tree-sha1 = "1df01539a1c952cef21f2d2d1c092c2bcf0177d7" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.6.0" + +[[Highlights]] +deps = ["DocStringExtensions", "InteractiveUtils", "REPL", "Test"] +git-tree-sha1 = "286ff83d696dd92748e603a3219618d9e407e872" +uuid = "eafb193a-b7ab-5a9e-9068-77385905fa72" +version = "0.3.1" + +[[InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[IteratorInterfaceExtensions]] +deps = ["Test"] +git-tree-sha1 = "5484e5ede2a4137b9643f4d646e8e7b87b794415" +uuid = "82899510-4779-5014-852e-03e436cf321d" +version = "0.1.1" + +[[JSON]] +deps = ["Dates", "Distributed", "Mmap", "Sockets", "Test", "Unicode"] +git-tree-sha1 = "1f7a25b53ec67f5e9422f1f551ee216503f4a0fa" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.20.0" + +[[LibGit2]] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[LinearAlgebra]] +deps = ["Libdl"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[Mustache]] +deps = ["Printf", "Tables", "Test"] +git-tree-sha1 = "3cc9a0b673519c5c39186e636d747facb12bf075" +uuid = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70" +version = "0.5.11" + +[[Pkg]] +deps = ["Dates", "LibGit2", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" + +[[Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[Random]] +deps = ["Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[Requires]] +deps = ["Test"] +git-tree-sha1 = "f6fbf4ba64d295e146e49e021207993b6b48c7d1" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "0.5.2" + +[[SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[SharedArrays]] +deps = ["Distributed", "Mmap", "Random", "Serialization"] +uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[SparseArrays]] +deps = ["LinearAlgebra", "Random"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[[Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[TableTraits]] +deps = ["IteratorInterfaceExtensions", "Test"] +git-tree-sha1 = "eba4b1d0a82bdd773307d652c6e5f8c82104c676" +uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" +version = "0.4.1" + +[[Tables]] +deps = ["IteratorInterfaceExtensions", "LinearAlgebra", "Requires", "TableTraits", "Test"] +git-tree-sha1 = "5aa45584645393c1717e0cc1f0362c2ea81470a9" +uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +version = "0.1.17" + +[[Test]] +deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[YAML]] +deps = ["Codecs", "Compat"] +git-tree-sha1 = "3bde77cee95cce0c0b9b18813d85e18e8ed4f415" +uuid = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" +version = "0.3.2" diff --git a/Project.toml b/Project.toml index f364c160..eff461c7 100644 --- a/Project.toml +++ b/Project.toml @@ -1,30 +1,31 @@ name = "Weave" uuid = "44d3d7a6-8a23-5bf8-98c5-b353f8df5ec9" -version="0.7.2" +version = "0.7.2" [deps] -Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" -Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" -Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" -REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" +BibTeX = "0c132655-f423-5f6f-9a5a-d55cfa15b9d7" Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" -Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" -JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" Highlights = "eafb193a-b7ab-5a9e-9068-77385905fa72" +JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" Mustache = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70" -YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" Requires = "ae029012-a4dd-5104-9daa-d747884805df" +Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" +YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" [compat] Highlights = ">=0.3.1" +Mustache = ">=0.4.1" Plots = ">=0.19.0" YAML = ">=0.3.0" -Mustache = ">=0.4.1" [extras] -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] test = ["Test", "Plots"] diff --git a/REQUIRE b/REQUIRE index 1e4c8694..341e4ce5 100644 --- a/REQUIRE +++ b/REQUIRE @@ -5,3 +5,4 @@ Mustache YAML Compat 0.25.0 Requires +BibTeX diff --git a/src/Weave.jl b/src/Weave.jl index fe8cd92f..f01bdabf 100644 --- a/src/Weave.jl +++ b/src/Weave.jl @@ -103,6 +103,11 @@ function weave(source ; doctype = :auto, css != nothing && (doc.css = css) template != nothing && (doc.template = template) + WeaveMarkdown.reset_parser() + if haskey(doc.header, "bibliography") + WeaveMarkdown.init_parser(joinpath(dirname(source), doc.header["bibliography"])) + end + try doc = run(doc, doctype = doctype, mod = mod, @@ -130,7 +135,7 @@ function weave(source ; doctype = :auto, rm(mdname) elseif doc.doctype == "md2pdf" success = run_latex(doc, outname, latex_cmd) - success && rm(doc.fig_path, force = true, recursive = true) + rm(doc.fig_path, force = true, recursive = true) success || return outname = get_outname(out_path, doc, ext = "pdf") end @@ -141,6 +146,7 @@ function weave(source ; doctype = :auto, # @warn("Something went wrong during weaving") # println(e) finally + WeaveMarkdown.reset_parser() doctype == :auto && (doctype = detect_doctype(doc.source)) if occursin("pandoc2pdf", doctype) && cache == :off rm(doc.fig_path, force = true, recursive = true) diff --git a/src/WeaveMarkdown/bibliography.jl b/src/WeaveMarkdown/bibliography.jl new file mode 100644 index 00000000..16d79c2b --- /dev/null +++ b/src/WeaveMarkdown/bibliography.jl @@ -0,0 +1,25 @@ +import Mustache + +function list_references(m::MIME"text/html") + tpl = Mustache.template_from_file(joinpath(@__DIR__, "../../templates/html_citations.tpl")) + refs = Dict() + for key in keys(CITATIONS[:refnumbers]) + refs[CITATIONS[:refnumbers][key]] = key + end + io = IOBuffer() + write(io, "
    ") + for i in 1:length(refs) + ref = CITATIONS[:references][refs[i]] + ref[ref["type"]] = "true" + ref["author"] = replace(ref["author"], r"\sand\s"i => ", ") + for key in keys(ref) + ref[key] = replace(ref[key], r"\{|\}" => "") + ref[key] = replace(ref[key], "--" => "–") + end + write(io, "
  1. ") + write(io, Mustache.render(tpl, ref)) + write(io, "
  2. ") + end + write(io, "
") + return String(take!(io)) +end diff --git a/src/WeaveMarkdown/html.jl b/src/WeaveMarkdown/html.jl index 470ff7f4..9e59308c 100644 --- a/src/WeaveMarkdown/html.jl +++ b/src/WeaveMarkdown/html.jl @@ -1,4 +1,3 @@ -#module Markdown2HTML # Markdown to HTML writer, Modified from Julia Base.Markdown html writer using Markdown: MD, Header, Code, Paragraph, BlockQuote, Footnote, Admonition, List, HorizontalRule, Bold, Italic, Image, Link, LineBreak, @@ -230,10 +229,21 @@ function htmlinline(io::IO, comment::Comment) write(io, "") end +function htmlinline(io::IO, citations::Citations) + withtag(io, :span, :class => "citation") do + cites = [] + for c in citations.content + if c.no == 0 + push!(cites, "?") + else + push!(cites, c.no) + end + end + write(io, string("[", join(cites, ","), "]")) + end +end + htmlinline(io::IO, x) = tohtml(io, x) # API - html(md) = sprint(html, md) - -#end diff --git a/src/WeaveMarkdown/latex.jl b/src/WeaveMarkdown/latex.jl index 45fcf64b..c66a0cd9 100644 --- a/src/WeaveMarkdown/latex.jl +++ b/src/WeaveMarkdown/latex.jl @@ -9,12 +9,20 @@ function latex(io::IO, tex::Markdown.LaTeX) end #Remove comments that can occur inside a line -function latexinline(io, comment::WeaveMarkdown.Comment) +function latexinline(io, comment::Comment) write(io, "") end -function latex(io::IO, comment::WeaveMarkdown.Comment) +function latex(io::IO, comment::Comment) for line in split(comment.text, r"\r\n|\n") write(io, "% $line\n") end end + +function latexinline(io, citations::Citations) + cites = [] + for c in citations.content + push!(cites, c.key) + end + write(io, string("\\citep{", join(cites, ", "), "}")) +end diff --git a/src/WeaveMarkdown/markdown.jl b/src/WeaveMarkdown/markdown.jl index 5a70fa83..7cbd8ccd 100644 --- a/src/WeaveMarkdown/markdown.jl +++ b/src/WeaveMarkdown/markdown.jl @@ -2,11 +2,24 @@ module WeaveMarkdown using Markdown import Markdown: @trigger, @breaking, Code, MD, withstream, startswith, LaTeX +using BibTeX mutable struct Comment text::String end +mutable struct Citation + key::String + no::Int64 + bib::Dict +end + +Citation(key, no) = Citation(key, no, Dict()) + +mutable struct Citations + content::Array{Citation} +end + @breaking true -> function dollarmath(stream::IO, block::MD) withstream(stream) do @@ -61,8 +74,39 @@ function comment(stream::IO, md::MD) end end +@trigger '[' -> +function citation(stream::IO, md::MD) + withstream(stream) do + Markdown.startswith(stream, "[@") || return + text = Markdown.readuntil(stream, ']', match = '[') + text ≡ nothing && return + citations = strip.(split(text, ";")) + cites = Citation[] + for c in citations + c = replace(c, r"^@" => "") + #Check for matcthing bixtex key + if haskey(CITATIONS[:bibtex], c) + bib = CITATIONS[:bibtex][c] + # Check for repeated citations + if haskey(CITATIONS[:refnumbers], c) + no = CITATIONS[:refnumbers][c] + else + no = CITATIONS[:no] + CITATIONS[:refnumbers][c] = no + CITATIONS[:no] += 1 + end + push!(cites, Citation(c, no, bib)) + CITATIONS[:references][c] = bib + else + push!(cites, Citation(c, 0)) + end + end + return Citations(cites) + end +end + # Create own flavor and copy all the features from julia flavor -Markdown.@flavor weavemd [dollarmath, comment, topcomment] +Markdown.@flavor weavemd [dollarmath, comment, topcomment, citation] weavemd.breaking = [weavemd.breaking; Markdown.julia.breaking] weavemd.regular = [weavemd.regular; Markdown.julia.regular] for key in keys(Markdown.julia.inner) @@ -73,6 +117,34 @@ for key in keys(Markdown.julia.inner) end end +const CITATIONS = Dict{Symbol, Any}( + :no => 1, + :bibtex => Dict(), + :references => Dict(), + :refnumbers => Dict() + ) + +#Init dictionary for parsing citations +function init_parser(bibfile) + CITATIONS[:no] = 1 + header, refs = parse_bibtex(read(bibfile, String)) + CITATIONS[:bibtex] = refs + CITATIONS[:references] = Dict() + CITATIONS[:refnumbers] = Dict() +end + +function reset_parser() + CITATIONS[:no] = 1 + CITATIONS[:references] = Dict() + CITATIONS[:bibtex] = Dict() + CITATIONS[:refnumbers] = Dict() +end + +function parse(text) + Markdown.parse(text, flavor = weavemd); +end + include("html.jl") include("latex.jl") +include("bibliography.jl") end diff --git a/src/format.jl b/src/format.jl index c202635a..9706ddc7 100644 --- a/src/format.jl +++ b/src/format.jl @@ -77,9 +77,16 @@ function render_doc(formatted, doc::WeaveDoc, format::JMarkdown2HTML) template = Mustache.template_from_file(doc.template) end + if isempty(WeaveMarkdown.CITATIONS[:references]) + references = "" + else + references = WeaveMarkdown.list_references(MIME"text/html"()) + end + return Mustache.render(template; themecss = theme_css, highlightcss = css, body = formatted, header_script = doc.header_script, source = wsource, wtime = wtime, wversion = wversion, + references = references, [Pair(Symbol(k), v) for (k,v) in doc.header]...) end @@ -90,6 +97,15 @@ function render_doc(formatted, doc::WeaveDoc, format::JMarkdown2tex) wversion = "" wtime = string(Date(now())) + references = "" + if !isempty(WeaveMarkdown.CITATIONS[:references]) + bibfile = splitext(abspath(joinpath(dirname(doc.source), doc.header["bibliography"])))[1] + bibfile = replace(bibfile, "\\" => "/") + references = """ + \\bibliographystyle{unsrt} + \\bibliography{$bibfile} + """ + end if isempty(doc.template) template = Mustache.template_from_file(joinpath(dirname(@__FILE__), "../templates/julia_tex.tpl")) @@ -98,7 +114,7 @@ function render_doc(formatted, doc::WeaveDoc, format::JMarkdown2tex) end return Mustache.render(template; body = formatted, - highlight = highlight, + highlight = highlight, references = references, [Pair(Symbol(k), v) for (k,v) in doc.header]...) end diff --git a/src/pandoc.jl b/src/pandoc.jl index f4b5fdb7..f4fed365 100644 --- a/src/pandoc.jl +++ b/src/pandoc.jl @@ -1,4 +1,4 @@ - +import .WeaveMarkdown """ `pandoc2html(formatted::AbstractString, doc::WeaveDoc)` @@ -108,9 +108,17 @@ function run_latex(doc::WeaveDoc, outname, latex_cmd = "xelatex") old_wd = pwd() cd(doc.cwd) xname = basename(outname) + bibname = splitext(xname)[1] @info("Weaved code to $outname. Running $latex_cmd") textmp = mktempdir(".") try + out = read(`$latex_cmd -shell-escape $xname -aux-directory $textmp -include-directory $(doc.cwd)`, String) + if !isempty(WeaveMarkdown.CITATIONS[:references]) + cd(textmp) + out = read(`bibtex $bibname`, String) + cd("..") + out = read(`$latex_cmd -shell-escape $xname -aux-directory $textmp -include-directory $(doc.cwd)`, String) + end out = read(`$latex_cmd -shell-escape $xname -aux-directory $textmp -include-directory $(doc.cwd)`, String) out = read(`$latex_cmd -shell-escape $xname -aux-directory $textmp -include-directory $(doc.cwd)`, String) rm(xname) @@ -118,9 +126,11 @@ function run_latex(doc::WeaveDoc, outname, latex_cmd = "xelatex") cd(old_wd) return true catch e - @warn("Error converting document to pdf. Try running latex manually") + @info(e) + @warn("Error converting document to pdf. Try running with md2tex format and using latex manually") + rm(xname) + rm(textmp, recursive=true) cd(old_wd) - rm(textmp) return false end end diff --git a/templates/html_citations.tpl b/templates/html_citations.tpl new file mode 100644 index 00000000..778e531b --- /dev/null +++ b/templates/html_citations.tpl @@ -0,0 +1,3 @@ +{{#article}} +{{author}}. ({{year}}). {{title}}. {{journal}}. {{volume}}:{{{pages}}}. doi: {{{doi}}}. +{{/article}} diff --git a/templates/julia_html.tpl b/templates/julia_html.tpl index f665d58d..5e87fef5 100644 --- a/templates/julia_html.tpl +++ b/templates/julia_html.tpl @@ -38,6 +38,7 @@ {{{ :body }}} + {{{ :references }}}