Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional fixes to eval workflow #255

Merged
merged 3 commits into from
Oct 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/converter/md.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ function convert_md(mds::String, pre_lxdefs::Vector{LxDef}=Vector{LxDef}();
lxcontext = LxContext(lxcoms, lxdefs, braces)
hstring = convert_inter_html(inter_html, mblocks, lxcontext)

#> if there's code, assemble it so that can be shown or loaded in one shot
codes = LOCAL_PAGE_VARS["jd_code_scope"].first.codes
if !isempty(codes)
set_var!(LOCAL_PAGE_VARS, "jd_code",
strip(prod(c*"\n" for c in codes)))
end

# Return the string + judoc variables
return hstring, jd_vars
end
Expand Down
48 changes: 32 additions & 16 deletions src/converter/md_blocks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function convert_block(β::AbstractBlock, lxcontext::LxContext)::AS
β isa HTML_SPCH && return ifelse(isempty(β.r), β.ss, β.r)
# Return relevant interpolated string based on case
βn = β.name
βn ∈ MD_HEADER && return convert_header(β)
βn ∈ MD_HEADER && return convert_header(β)
βn == :CODE_INLINE && return html_code_inline(content(β) |> htmlesc)
βn == :CODE_BLOCK_LANG && return convert_code_block(β.ss)
βn == :CODE_BLOCK_IND && return convert_indented_code_block(β.ss)
Expand Down Expand Up @@ -131,19 +131,26 @@ const MESSAGE_FILE_GEN = "# This file was generated by JuDoc, do not modify it.
"""Convenience function to increment the eval' code block counter"""
increment_code_head() = (LOCAL_PAGE_VARS["jd_code_head"].first[] += 1)

"""Convenience function to mark `jd_code_eval` as true (subsequent blocks will be evaled)"""
toggle_jd_code_eval() = (LOCAL_PAGE_VARS["jd_code_eval"].first[] = true)

"""
$SIGNATURES

Helper function to eval a code block, write it where appropriate, and finally return
a resolved block that can be displayed in the html.
"""
function eval_and_resolve_code(code::AS, rpath::AS; eval::Bool=true)::String
function eval_and_resolve_code(code::AS, rpath::AS;
eval::Bool=true, nopush::Bool=false)::String
# Here we have a julia code block that was provided with a script path
# It will consequently be
# 1. written to script file unless it's already there
# 2. eval with redirect (unless file+output already there)
# 3. inserted after cleaning out lines (see resolve_lx_input)

# start by adding it to code scope
nopush || push!(LOCAL_PAGE_VARS["jd_code_scope"].first, rpath, code)

# form the path
path = resolve_assets_rpath(rpath; canonical=true, code=true)

Expand All @@ -164,7 +171,7 @@ function eval_and_resolve_code(code::AS, rpath::AS; eval::Bool=true)::String
end

write(path, MESSAGE_FILE_GEN * code)
print(rpad("\r→ evaluating code [...] ($(CUR_PATH[]), $rpath)", 79)*"\r")
print(rpad("\r→ evaluating code [...] ($(CUR_PATH[]), $rpath)", 79))
# - execute the code while redirecting stdout to file
Logging.disable_logging(Logging.LogLevel(3_000))
open(out_path, "w") do outf # for stdout
Expand Down Expand Up @@ -208,9 +215,17 @@ function convert_code_block(ss::SubString)::String
# path currently has an indicative `:` we don't care about
rpath = rpath[2:end]

# extract handles of relevant local page variables
reeval = LOCAL_PAGE_VARS["reeval"].first # full page re-eval
eval = LOCAL_PAGE_VARS["jd_code_eval"].first[] # eval toggle from given point
freeze = LOCAL_PAGE_VARS["freezecode"].first
scope = LOCAL_PAGE_VARS["jd_code_scope"].first
head = increment_code_head()

# In the case of forced re-eval, we don't care about the
# code scope just force-reeval everything sequentially
if FORCE_REEVAL[] || LOCAL_PAGE_VARS["reeval"].first
if FORCE_REEVAL[] || reeval || eval
length(scope.codes) ≥ head && purgefrom!(scope, head)
return eval_and_resolve_code(code, rpath)
end

Expand All @@ -219,48 +234,49 @@ function convert_code_block(ss::SubString)::String
# the case then there will be a check to see if the relevant
# files exist, if they don't exist the code *will* be eval'ed
# (see `eval_and_resolve_code`)
if FULL_PASS[] || LOCAL_PAGE_VARS["freezecode"].first
if FULL_PASS[] || freeze
length(scope.codes) ≥ head && purgefrom!(scope, head)
return eval_and_resolve_code(code, rpath, eval=false)
end

# Here we're either in
# A. full pass but with forced-reeval
# B. local pass with non-frozen code

# handle for dictionary of eval'ed code blocks (scope)
code_scope = LOCAL_PAGE_VARS["jd_code_scope"].first

# check if the page we're looking at is in scope
if CUR_PATH[] != CUR_PATH_WITH_EVAL[]
# we're necessarily at the first code block of the page.
# need to re-instantiate a code scope; note that if we
# are here then necessarily a def_LOCAL_PAGE_VARS was
# called, so LOCAL_PAGE_VARS["jd_code_head"] points to 1
reset!(code_scope, rpath, code)
reset!(scope)
# keep track that the page is now in scope
CUR_PATH_WITH_EVAL[] = CUR_PATH[]
# flag rest of page as to be eval-ed (might be stale)
toggle_jd_code_eval()
# eval and resolve code
return eval_and_resolve_code(code, rpath)
end

# we're in scope, compare the code block with the
# current code scope and act appropriately
head = increment_code_head()
ncodes = length(code_scope.codes)
ncodes = length(scope.codes)

# there is only one case where we might not add and eval
# --> if c ≤ length(code_dict) -- code block may be among seen ones
# --> code == code_dict[rpath] -- the content matches exactly
if (head ≤ ncodes)
if (code_scope.rpaths[head] == rpath && code == code_scope.codes[head])
if (scope.rpaths[head] == rpath && code == scope.codes[head])
# resolve with no eval (the function will check if the files are
# present and if they're not, there will be an evaluation)
return eval_and_resolve_code(code, rpath; eval=false)
return eval_and_resolve_code(code, rpath; eval=false, nopush=true)
else
# all further blocks are stale
purgeafter!(code_scope, head-1)
# purge subsequent code blocks as stale
purgefrom!(scope, head)
# flag rest of page as to be eval-ed (stale)
toggle_jd_code_eval()
end
end
push!(code_scope, rpath, code)
return eval_and_resolve_code(code, rpath)
end

Expand Down
21 changes: 11 additions & 10 deletions src/jd_vars.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ DEVNOTE: marked as constant for perf reasons but can be modified since Dict.
"""
const GLOBAL_PAGE_VARS = PageVars()


"""
$(SIGNATURES)

Expand Down Expand Up @@ -50,16 +49,16 @@ function push!(cs::CodeScope, rpath::SubString, code::SubString)::Nothing
end

"""Convenience function to (re)start a code scope."""
function reset!(cs::CodeScope, rpath::SubString, code::SubString)::Nothing
cs.rpaths = [rpath]
cs.codes = [code]
function reset!(cs::CodeScope)::Nothing
cs.rpaths = []
cs.codes = []
return nothing
end

"""Convenience function to clear arrays beyond an index"""
function purgeafter!(cs::CodeScope, head::Int)::Nothing
cs.rpaths = cs.rpaths[1:head]
cs.codes = cs.codes[1:head]
"""Convenience function to purge code scope from head"""
function purgefrom!(cs::CodeScope, head::Int)
cs.rpaths = cs.rpaths[1:head-1]
cs.codes = cs.codes[1:head-1]
return nothing
end

Expand Down Expand Up @@ -126,8 +125,10 @@ is processed.

# Internal vars for code blocks
LOCAL_PAGE_VARS["jd_code_scope"] = code_scope
LOCAL_PAGE_VARS["jd_code_head"] = Pair(Ref(0), (Ref{Int},))
LOCAL_PAGE_VARS["reeval"] = Pair(false, (Bool,)) # whether to always re-evals all on pg
LOCAL_PAGE_VARS["jd_code_head"] = Pair(Ref(0), (Ref{Int},))
LOCAL_PAGE_VARS["jd_code_eval"] = Pair(Ref(false), (Ref{Bool},)) # toggle reeval
LOCAL_PAGE_VARS["reeval"] = Pair(false, (Bool,)) # always reeval on pg
LOCAL_PAGE_VARS["jd_code"] = Pair("", (String,)) # just the script

# If there are GLOBAL vars that are defined, they take precedence
local_keys = keys(LOCAL_PAGE_VARS)
Expand Down
16 changes: 16 additions & 0 deletions test/global/eval.jl
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ end
<pre><code>8</code></pre>
""")

@test J.LOCAL_PAGE_VARS["jd_code"].first == """
a = 5
println(a)

a += 3
println(a)"""

h = raw"""
@def hascode = true
@def reeval = true
Expand Down Expand Up @@ -174,4 +181,13 @@ end
println(a)</code></pre>
<pre><code>9</code></pre>
""")
@test J.LOCAL_PAGE_VARS["jd_code"].first == """
a = 5
println(a)

a += 1
println(a)

a += 3
println(a)"""
end