Browse Source

update parser to have quarto-only functionality

pull/200/head
J S 2 years ago
parent
commit
9d6431cbe8
  1. 25
      src/Literate.jl
  2. 73
      test/runtests.jl

25
src/Literate.jl

@ -46,7 +46,7 @@ CodeChunk() = CodeChunk(String[], false)
ismdline(line) = (occursin(r"^\h*#$", line) || occursin(r"^\h*# .*$", line)) && !occursin(r"^\h*##", line) ismdline(line) = (occursin(r"^\h*#$", line) || occursin(r"^\h*# .*$", line)) && !occursin(r"^\h*##", line)
function parse(content; allow_continued = true) function parse(flavor::AbstractFlavor, content; allow_continued = true)
lines = collect(eachline(IOBuffer(content))) lines = collect(eachline(IOBuffer(content)))
chunks = Chunk[] chunks = Chunk[]
@ -76,9 +76,14 @@ function parse(content; allow_continued = true)
if !(chunks[end] isa CodeChunk) if !(chunks[end] isa CodeChunk)
push!(chunks, CodeChunk()) push!(chunks, CodeChunk())
end end
# remove "## " and "##\n", strip the leading "#" from "## xyz" and "##| xyz" # remove "## " and "##\n" (strips leading "#" for code comments)
# Note: accepts only standard space character (not no-break space U+00A0) if flavor isa QuartoFlavor
line = replace(replace(line, r"^(\h*)#(#(:? |\|).*)$" => s"\1\2"), r"^(\h*#)#$" => s"\1") # for Quarto, strip leading "#" from code cell commands, eg, "##| echo: true" -> "#| echo: true"
line = replace(replace(line, r"^(\h*)#(#(:? |\|).*)$" => s"\1\2"), r"^(\h*#)#$" => s"\1")
else
# all other flavors
line = replace(replace(line, r"^(\h*)#(# .*)$" => s"\1\2"), r"^(\h*#)#$" => s"\1")
end
push!(chunks[end].lines, line) push!(chunks[end].lines, line)
end end
end end
@ -285,12 +290,12 @@ function edit_commit(inputfile, user_config)
end end
# Default to DefaultFlavor() setting # Default to DefaultFlavor() setting
pick_codefence(flavor::AbstractFlavor,execute::Bool,name::AbstractString)=pick_codefence(DefaultFlavor(),execute,name) pick_codefence(flavor::AbstractFlavor, execute::Bool, name::AbstractString)=pick_codefence(DefaultFlavor(), execute,name)
pick_codefence(flavor::DefaultFlavor,execute::Bool,name::AbstractString)=("````julia" => "````") pick_codefence(flavor::DefaultFlavor, execute::Bool, name::AbstractString)=("````julia" => "````")
pick_codefence(flavor::DocumenterFlavor,execute::Bool,name::AbstractString)=(execute ? pick_codefence(flavor::DocumenterFlavor,execute::Bool, name::AbstractString)=(execute ?
pick_codefence(DefaultFlavor(),execute,name) : ("````@example $(name)" => "````") pick_codefence(DefaultFlavor(), execute,name) : ("````@example $(name)" => "````")
) )
pick_codefence(flavor::QuartoFlavor,execute::Bool,name::AbstractString)=(execute ? pick_codefence(flavor::QuartoFlavor, execute::Bool, name::AbstractString)=(execute ?
error("QuartoFlavor does not support argument execute=true!") : ("```{julia}" => "```") error("QuartoFlavor does not support argument execute=true!") : ("```{julia}" => "```")
) )
@ -490,7 +495,7 @@ function preprocessor(inputfile, outputdir; user_config, user_kwargs, type)
content = replace_default(content, type; config=config) content = replace_default(content, type; config=config)
# parse the content into chunks # parse the content into chunks
chunks = parse(content; allow_continued = type !== :nb) chunks = parse(config["flavor"], content; allow_continued = type !== :nb)
return chunks, config return chunks, config
end end

73
test/runtests.jl

@ -1,6 +1,6 @@
import Literate, JSON import Literate, JSON
import Literate: Chunk, MDChunk, CodeChunk import Literate: Chunk, MDChunk, CodeChunk
import Literate: pick_codefence import Literate: pick_codefence, DefaultFlavor, QuartoFlavor
using Test using Test
# compare content of two parsed chunk vectors # compare content of two parsed chunk vectors
@ -109,6 +109,8 @@ end
## Line 77 ## Line 77
## ##
## Line 79 ## Line 79
# Line 80: Quarto Specific
##| Line 81
""" """
expected_chunks = Chunk[ expected_chunks = Chunk[
MDChunk(["" => "Line 1"]), MDChunk(["" => "Line 1"]),
@ -146,10 +148,55 @@ end
CodeChunk(["Line 64", " # Line 65", " Line 66", "Line 67"], false), CodeChunk(["Line 64", " # Line 65", " Line 66", "Line 67"], false),
CodeChunk(["# Line 73", "#", "# Line 75"], false), CodeChunk(["# Line 73", "#", "# Line 75"], false),
CodeChunk([" # Line 77", " #", " # Line 79"], false), CodeChunk([" # Line 77", " #", " # Line 79"], false),
] MDChunk(["" => "Line 80: Quarto Specific"]),
parsed_chunks = Literate.parse(content) CodeChunk(["##| Line 81"], false)
]
parsed_chunks = Literate.parse(DefaultFlavor(), content)
compare_chunks(parsed_chunks, expected_chunks) compare_chunks(parsed_chunks, expected_chunks)
# QuartoFlavor parsing semantics
expected_chunks_quarto = Chunk[
MDChunk(["" => "Line 1"]),
CodeChunk(["Line 2"], false),
MDChunk(["" => "Line 3", "" => "","" => "Line 5"]),
CodeChunk(["Line 6", "","Line 8"], false),
MDChunk(["" => "Line 9"]),
MDChunk(["" => "Line 11"]),
CodeChunk(["Line 12"], false),
CodeChunk(["Line 14"], false),
MDChunk(["" => "Line 15"]),
MDChunk(["" => "Line 17"]),
CodeChunk(["Line 18"], false),
CodeChunk(["Line 20"], false),
MDChunk(["" => "Line 21"]),
CodeChunk(["Line 22", " Line 23", "Line 24"], false),
CodeChunk(["Line 26", " Line 27"], true),
CodeChunk(["Line 29"], false),
CodeChunk(["Line 31", " Line 32"], true),
MDChunk(["" => "Line 33"]),
CodeChunk(["Line 34"], false),
CodeChunk(["Line 36"], true),
CodeChunk([" Line 38"], true),
CodeChunk(["Line 40"], false),
CodeChunk(["Line 42", " Line 43"], true),
MDChunk(["" => "Line 44"]),
CodeChunk([" Line 45"], true),
MDChunk(["" => "Line 46"]),
CodeChunk(["Line 47"], false),
MDChunk(["" => "Line 48"]),
CodeChunk(["#Line 49", "Line 50"], false),
MDChunk(["" => "Line 53"]),
CodeChunk(["# Line 57", "Line 58", "# Line 59", "##Line 60"], false),
MDChunk([" " => "Line 62", " " => "# Line 63"]),
CodeChunk(["Line 64", " # Line 65", " Line 66", "Line 67"], false),
CodeChunk(["# Line 73", "#", "# Line 75"], false),
CodeChunk([" # Line 77", " #", " # Line 79"], false),
MDChunk(["" => "Line 80: Quarto Specific"]),
CodeChunk(["#| Line 81"], false) # parses correctly as code cell command
]
parsed_chunks = Literate.parse(QuartoFlavor(), content)
compare_chunks(parsed_chunks, expected_chunks_quarto)
# test leading/trailing whitespace removal # test leading/trailing whitespace removal
io = IOBuffer() io = IOBuffer()
iows = IOBuffer() iows = IOBuffer()
@ -166,7 +213,7 @@ end
foreach(x -> println(iows), 1:rand(2:5)) foreach(x -> println(iows), 1:rand(2:5))
end end
compare_chunks(Literate.parse(String(take!(io))), Literate.parse(String(take!(iows)))) compare_chunks(Literate.parse(DefaultFlavor(), String(take!(io))), Literate.parse(DefaultFlavor(), String(take!(iows))))
end # testset parser end # testset parser
@ -202,7 +249,6 @@ content = """
Source code only #src Source code only #src
## # Comment ## # Comment
## another comment ## another comment
##| echo: false Quarto parameters
#- #-
for i in 1:10 for i in 1:10
print(i) print(i)
@ -324,7 +370,6 @@ const GITLAB_ENV = Dict(
x + 3 x + 3
# # Comment # # Comment
# another comment # another comment
#| echo: false Quarto parameters
for i in 1:10 for i in 1:10
print(i) print(i)
@ -556,7 +601,6 @@ end end
x * 3 x * 3
# # Comment # # Comment
# another comment # another comment
#| echo: false Quarto parameters
```` ````
````@example inputfile; continued = true ````@example inputfile; continued = true
@ -1022,8 +1066,7 @@ end end
"x * 3\\n", "x * 3\\n",
"x * 3\\n", "x * 3\\n",
"# # Comment\\n", "# # Comment\\n",
"# another comment\\n", "# another comment"
"#| echo: false Quarto parameters"
], ],
""", """,
@ -1419,16 +1462,16 @@ end end
@test occursin("Link to binder: www.example3.com/file.jl", script) @test occursin("Link to binder: www.example3.com/file.jl", script)
# Test pick_codefence function # Test pick_codefence function
default_codefence=pick_codefence(Literate.DefaultFlavor(),true,"testname") default_codefence=pick_codefence(Literate.DefaultFlavor(), true, "testname")
@test default_codefence == ("````julia" => "````") @test default_codefence == ("````julia" => "````")
@test default_codefence == pick_codefence(Literate.FranklinFlavor(),true,"testname") @test default_codefence == pick_codefence(Literate.FranklinFlavor(), true, "testname")
@test default_codefence == pick_codefence(Literate.DocumenterFlavor(),true,"testname") @test default_codefence == pick_codefence(Literate.DocumenterFlavor(), true, "testname")
documenter_codefence = ("````@example testname" => "````") documenter_codefence = ("````@example testname" => "````")
@test documenter_codefence == pick_codefence(Literate.DocumenterFlavor(),false,"testname") @test documenter_codefence == pick_codefence(Literate.DocumenterFlavor(), false, "testname")
let expected_exception=ErrorException("QuartoFlavor does not support argument execute=true!") let expected_exception=ErrorException("QuartoFlavor does not support argument execute=true!")
@test_throws expected_exception pick_codefence(Literate.QuartoFlavor(),true,"testname") @test_throws expected_exception pick_codefence(Literate.QuartoFlavor(), true, "testname")
end end
@test ("```{julia}" => "```") == pick_codefence(Literate.QuartoFlavor(),false,"testname") @test ("```{julia}" => "```") == pick_codefence(Literate.QuartoFlavor(), false, "testname")
# Misc default configs # Misc default configs
create(; type, kw...) = Literate.create_configuration(inputfile; user_config=Dict(), user_kwargs=kw, type=type) create(; type, kw...) = Literate.create_configuration(inputfile; user_config=Dict(), user_kwargs=kw, type=type)

Loading…
Cancel
Save