diff --git a/Project.toml b/Project.toml index f7ef4e0..1983d85 100644 --- a/Project.toml +++ b/Project.toml @@ -4,9 +4,6 @@ authors = ["Alberto Mengali "] version = "0.7.4" [deps] -AbstractPlutoDingetjes = "6e696c72-6542-2067-7265-42206c756150" -DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" @@ -15,9 +12,6 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" [compat] -AbstractPlutoDingetjes = "1.2" -DocStringExtensions = "0.9" -HypertextLiteral = "0.9" InteractiveUtils = "1" MacroTools = "0.5" Markdown = "1" diff --git a/docs/src/htl_combine.md b/docs/src/htl_combine.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs/src/other_functions.md b/docs/src/other_functions.md index c4893e4..e9d4246 100644 --- a/docs/src/other_functions.md +++ b/docs/src/other_functions.md @@ -1,6 +1,8 @@ # Other Functions This package also exports some additional convenience macros for simplifying package development aided by Pluto notebooks. +Additionally, the *non-exported* function [`hide_this_log`](@ref) can be used for sending javascript code through logs to Pluto and hide the corresponding log from view (without stopping the javascript code to execute) + ## Utilities Macros ```@docs @addmethod @@ -8,4 +10,9 @@ This package also exports some additional convenience macros for simplifying pac @only_out_nb @current_pluto_cell_id @current_pluto_notebook_file +``` + +## Utilities Functions +```@docs +PlutoDevMacros.hide_this_log ``` \ No newline at end of file diff --git a/src/PlutoDevMacros.jl b/src/PlutoDevMacros.jl index af7beb7..83bd759 100644 --- a/src/PlutoDevMacros.jl +++ b/src/PlutoDevMacros.jl @@ -1,19 +1,10 @@ module PlutoDevMacros -using MacroTools -using HypertextLiteral - -# export @only_in_nb, @only_out_nb, include_mapexpr, @skip_as_script -# export notebook_to_source - # This are from basics.jl export @only_in_nb, @only_out_nb, plutodump, @current_pluto_cell_id, @current_pluto_notebook_file, @addmethod include("basics.jl") -include("combine_htl/PlutoCombineHTL.jl") -const HTL = PlutoCombineHTL - include("html_helpers.jl") include("frompackage/FromPackage.jl") @@ -22,7 +13,6 @@ export @fromparent, @frompackage include("../notebooks/mapexpr.jl") # hasexpr, default_exprlist, include_mapexpr include("../notebooks/plutoinclude_macro.jl") # hasexpr, default_exprlist, include_mapexpr -# include("../notebooks/pluto_traits.jl") # This defines and exports the @plutotraits macro # function __init__() # if isdefined(Main, :PlutoRunner) diff --git a/src/combine_htl/PlutoCombineHTL.jl b/src/combine_htl/PlutoCombineHTL.jl deleted file mode 100644 index 0f7d73d..0000000 --- a/src/combine_htl/PlutoCombineHTL.jl +++ /dev/null @@ -1,53 +0,0 @@ -module PlutoCombineHTL - -using Random -using HypertextLiteral -using HypertextLiteral: Result, Bypass, Reprint, Render -using Markdown -using AbstractPlutoDingetjes: is_inside_pluto, AbstractPlutoDingetjes -using AbstractPlutoDingetjes.Display -using DocStringExtensions - -export make_node, make_html, make_script, formatted_code - -const LOCAL_MODULE_URL = Ref("https://cdn.jsdelivr.net/gh/disberd/PlutoDevMacros@$(pkgversion(@__MODULE__))/src/combine_htl/pluto_compat.js") - -include("typedef.jl") -include("helpers.jl") -include("constructors.jl") -include("js_events.jl") -# include("combine.jl") -include("show.jl") -# include("docstrings.jl") - -module WithTypes - _ex_names = ( - :PlutoCombineHTL, - :make_node, :make_html, :make_script, - :formatted_code, :print_html, :print_javascript, :to_string, - :ScriptContent, - :PrintToScript, - :Node, :DualNode, :CombinedNodes, :PlutoNode, :NormalNode, - :Script, :DualScript, :CombinedScripts, :PlutoScript, :NormalScript, - :SingleDisplayLocation, :DisplayLocation, :InsidePluto, :OutsidePluto, :InsideAndOutsidePluto, - :ShowWithPrintHTML, :AbstractHTML - ) - for n in _ex_names - eval(:(import ..PlutoCombineHTL: $n)) - eval(:(export $n)) - end -end - -module HelperFunctions - _ex_names = ( - :shouldskip, :haslisteners, :hasreturn, :returned_element, - :script_id, :add_pluto_compat, :hasinvalidation, :plutodefault, - :displaylocation, :children, :inner_node, - ) - for n in _ex_names - eval(:(import ..PlutoCombineHTL: $n)) - eval(:(export $n)) - end -end - -end \ No newline at end of file diff --git a/src/combine_htl/constructors.jl b/src/combine_htl/constructors.jl deleted file mode 100644 index 0ad2d4d..0000000 --- a/src/combine_htl/constructors.jl +++ /dev/null @@ -1,132 +0,0 @@ -# Abstract Constructors # - -Script(::InsidePluto) = PlutoScript -Script(::OutsidePluto) = NormalScript -Script(::InsideAndOutsidePluto) = DualScript - -Node(::InsidePluto) = PlutoNode -Node(::OutsidePluto) = NormalNode -Node(::InsideAndOutsidePluto) = DualNode - -# ScriptContent # - -## AbstractString constructor ## -function ScriptContent(s::AbstractString; kwargs...) - # We strip eventual leading newline or trailing `isspace` - str = strip_nl(s) - ael = get(kwargs, :addedEventListeners) do - contains(str, "addScriptEventListeners(") - end - ScriptContent(str, ael) -end - -## Result constructor ## -function ScriptContent(r::Result; iocontext = IOContext(devnull), kwargs...) - temp = IOContext(IOBuffer(), iocontext) - show(temp, r) - str_content = strip(String(take!(temp.io))) - isempty(str_content) && return ScriptContent() - n_matches = 0 - first_idx = 0 - first_offset = 0 - last_idx = 0 - start_regexp = r"]*>" - end_regexp = r"" - for m in eachmatch(r"]*>", str_content) - n_matches += 1 - n_matches > 1 && break - first_offset = m.offset - first_idx = first_offset + length(m.match) - m_end = match(end_regexp, str_content, first_idx) - m_end === nothing && error("No closing tag was found in the input") - last_idx = m_end.offset - 1 - end - if n_matches === 0 - @warn "No ") - @warn "The provided input also contained contents outside of the ") - return -end -print_html(io::IO, s::AbstractString; kwargs...) = write(io, strip_nl(s)) -function print_html(io::IO, n::NonScript{L}; pluto = plutodefault(n)) where L <: SingleDisplayLocation - _pluto = plutodefault(n) - # If the location doesn't match the provided kwarg we do nothing - xor(pluto, _pluto) && return - println(io, n.content) - return -end -print_html(io::IO, dn::DualNode; pluto = plutodefault(dn)) = print_html(io, inner_node(dn, displaylocation(pluto)); pluto) -function print_html(io::IO, cn::CombinedNodes; pluto = is_inside_pluto(io)) - for n in children(cn) - print_html(io, n; pluto) - end -end -function print_html(io::IO, swph::ShowWithPrintHTML; pluto = plutodefault(io, swph)) - l = displaylocation(pluto) - # We skip if the loction of pts is explicitly not compatible with l - shouldskip(swph, l) && return - print_html(io, swph.el; pluto) - return nothing -end -# If the ShowWithPrintHTML element is a function, we call it passing io and kwargs to it -function print_html(io::IO, swph::ShowWithPrintHTML{<:DisplayLocation, <:Function}; pluto = plutodefault(io, swph), kwargs...) - l = displaylocation(pluto) - # We skip if the loction of pts is explicitly not compatible with l - shouldskip(swph, l) && return - f = swph.el - f(io; pluto, kwargs...) - return nothing -end -# Catchall method reverting to show text/javascript -print_html(io::IO, x; kwargs...) = (@nospecialize; show(io, MIME"text/html"(), x)) - -## Formatted Code ## - -# We simulate the Pluto iocontext even outside Pluto if want to force printing as in pluto -_pluto_default_iocontext() = try - Main.PlutoRunner.default_iocontext -catch - function core_published_to_js(io, x) - write(io, "/* Here you'd have your published object on Pluto */") - return nothing - end - IOContext(devnull, - :color => false, - :limit => true, - :displaysize => (18, 88), - :is_pluto => true, - # :pluto_supported_integration_features => supported_integration_features, - :pluto_published_to_js => (io, x) -> core_published_to_js(io, x), - ) -end - -function to_string(element, ::M, args...; kwargs...) where M <: MIME - f = if M === MIME"text/javascript" - print_javascript - elseif M === MIME"text/html" - print_html - else - error("Unsupported mime $M provided as input") - end - to_string(element, f, args...; kwargs...) -end -function to_string(element, f::Function, io::IO = IOBuffer(); kwargs...) - iocontext = get(kwargs, :iocontext) do - pluto = get(kwargs, :pluto, is_inside_pluto()) - pluto ? _pluto_default_iocontext() : IOContext(devnull) - end - f(IOContext(io, iocontext), element; kwargs...) - code = String(take!(io)) - return code -end -function formatted_code(s::Union{Script, ScriptContent}, mime::MIME"text/javascript"; kwargs...) - codestring = to_string(s, mime; kwargs...) - Markdown.MD(Markdown.Code("js", codestring)) -end -function formatted_code(n::Node, mime::MIME"text/html"; kwargs...) - codestring = to_string(n, mime; kwargs...) - Markdown.MD(Markdown.Code("html", codestring)) -end -# Default MIMEs -default_mime(::ScriptContent) = MIME"text/javascript"() -default_mime(::Node) = MIME"text/html"() -formatted_code(s::Union{ScriptContent, Node}; kwargs...) = formatted_code(s, default_mime(s); kwargs...) -# Versions returning functions -formatted_code(mime::MIME; kwargs...) = x -> formatted_code(x, mime; kwargs...) -# This forces just the location using the DisplayLocation type -formatted_code(l::SingleDisplayLocation; kwargs...) = x -> formatted_code(x; pluto = plutodefault(l), kwargs...) -formatted_code(; kwargs...) = x -> formatted_code(x; kwargs...) # Default no argument version - -formatted_contents(args...; kwargs...) = formatted_code(args...; kwargs..., only_contents = true) - - -HypertextLiteral.content(n::Node) = HypertextLiteral.Render(ShowWithPrintHTML(n, InsideAndOutsidePluto())) - -#= Fix for Julia 1.10 -The `@generated` `print_script` from HypertextLiteral is broken in 1.10 -See [issue 33](https://github.com/JuliaPluto/HypertextLiteral.jl/issues/33) -We have to also define a method for `print_script` to avoid precompilation errors -=# - -HypertextLiteral.print_script(io::IO, val::ScriptContent) = show(io, MIME"text/javascript"(), val) -HypertextLiteral.print_script(io::IO, v::Vector{ScriptContent}) = for s in v - HypertextLiteral.print_script(io, s) -end - -HypertextLiteral.print_script(::IO, ::Script) = error("Interpolation of `Script` subtypes is not allowed within a script tag. -Use `make_node` to generate a ` -something_after -\"\"\")) -``` -When interpolating `wrapper` above inside another `@htl` macro as `@htl -""` it would be as equivalent to directly writing -`code...` inside the script. This is clearly only -beneficial if multiple `ScriptContent` variables are interpolated inside a -single - \"\"\") - lol = ScriptContent(@htl \"\"\" - - \"\"\") - @htl \"\"\" - - \"\"\" -end -``` -""" -struct ScriptContent - "Content of the script part" - content::String - "Flag indicating if the script has custom listeners added via the `addScriptEventListeners` function." - addedEventListeners::Bool -end - -## PlutoScript ## -""" -$TYPEDEF -# Fields -$TYPEDFIELDS - -## Note -Eventual elements that have to be returned from the script (this is a feature of -Pluto) should not be directly _returned_ from the script content but should be -simply assigned to a JS variable whose name is set to the `returned_element` -field. -This is necessary to prevent exiting early from a chain of Scripts. For example, the following code which is a valid JS code inside a Pluto cell to create a custom div as output: -```julia -@htl \"\"\" - -\"\"\" -``` -must be constructed when using `PlutoScript` as: -```julia -PlutoScript("let out = html`
MY DIV
`"; returned_element = "out") -``` - -# Additional Constructors - PlutoScript(body; kwargs...) - PlutoScript(body, invalidation; kwargs...) - -For the body and invalidation fields, the constructor also accepts inputs of -type `String`, `HypertextLiteral.Result` and `IOBuffer`, translating them into -`ScriptContent` internally. - - PlutoScript(s::PlutoScript; kwargs...) -This constructor is used to copy the elements from another PlutoScript with the -option of overwriting the fields provided as `kwargs` - -# Description - -This struct is used to create and compose scripts together with the `@htl` macro -from HypertextLiteral. - -It is intended for use inside Pluto notebooks to ease composition of bigger -scripts via smaller parts. - -When an PlutoScript is interpolated inside the `@htl` macro, the following code is generated: -```html - - \"\"\")) - @htl"\$script" -end -``` -is functionally equivalent of writing the following javascript code within the -script tag of the cell output -```js -function onClick(event) { - console.log('click: ',event) -} -function onKeyDown(event) { - console.log('keydown: ',event) -} -window.addEventListener('click', onClick) -window.addEventListener('keydown', onKeyDown) - -invalidation.then(() => { - window.removeEventListener('click', onClick) - window.removeEventListener('keydown', onKeyDown) -}) -``` - -See also: [`ScriptContent`](@ref), [`combine_scripts`](@ref) - -# Examples: -The following code: -```julia -let -a = PlutoScript("console.log('asd')") -b = PlutoScript(@htl(""), "console.log('lol')") -script = combine_scripts([a,b];id="test") -out = @htl("\$script") -end -``` -is equivalent to writing directly -```julia -@htl \"\"\" - -``` -""" -struct PlutoScript <: Script{InsidePluto} - "The main body of the script" - body::Union{Missing,ScriptContent} - "The code to be executed inside the invalidation promise. Defaults to `missing`" - invalidation::Union{Missing,ScriptContent} - "The id to assign to the script. Defaults to `missing`" - id::Union{Missing, String} - "The name of the JS element that is returned by the script. Defaults to `missing`" - returned_element::Union{Missing, String} - function PlutoScript(b,i,id::Union{Missing, Nothing, String}, returned_element; kwargs...) - body = ScriptContent(b; kwargs...) - invalidation = ScriptContent(i) - @assert invalidation === missing || invalidation.addedEventListeners === false "You can't have added event listeners in the invalidation script" - new(body,invalidation, something(id, missing), returned_element) - end -end - -## NormalScript -struct NormalScript <: Script{OutsidePluto} - "The main body of the script" - body::Union{Missing, ScriptContent} - "A flag to indicate if the script should include basic JS libraries available from Pluto. Defaults to `true`" - add_pluto_compat::Bool - "The id to assign to the script. Defaults to `missing`" - id::Union{Missing, String} - "The name of the JS element that is returned by the script. Defaults to `missing`" - returned_element::Union{Missing, String} - function NormalScript(b, add_pluto_compat, id, returned_element; kwargs...) - body = ScriptContent(b; kwargs...) - new(body, add_pluto_compat, something(id, missing), returned_element) - end -end - -## DualScript ## -@kwdef struct DualScript <: Script{InsideAndOutsidePluto} - inside_pluto::PlutoScript = PlutoScript() - outside_pluto::NormalScript = NormalScript() - function DualScript(i, o; kwargs...) - ip = PlutoScript(i; kwargs...) - op = NormalScript(o; kwargs...) - new(ip, op) - end -end - - -## PrintToScript -struct PrintToScript{D<:DisplayLocation, T} - el::T - PrintToScript(el::T, ::D) where {T, D<:DisplayLocation} = new{D,T}(el) -end - -## CombinedScripts ## -struct CombinedScripts <: Script{InsideAndOutsidePluto} - scripts::Vector{<:PrintToScript} - function CombinedScripts(v::Vector{<:PrintToScript}; returned_element = missing) - # We check for only one return expression and it being in the last script - return_count = 0 - return_idx = something(findfirst(x -> x isa Script, v), 0) - for (i, s) in enumerate(v) - # If no return is present we skip this script - hasreturn(s, InsidePluto()) || hasreturn(s, OutsidePluto()) || continue - return_count += 1 - return_idx = i - end - @assert return_count < 2 "More than one return expression was found while constructing the CombinedScripts. This is not allowed." - # If we don't have to set a custom returned_element we just create a new CombinedScripts - returned_element === missing && return new(v) - final_v = if return_idx === 0 - # We have to add a DualScript that just returns the element - new_v = vcat(v, DualScript(""; returned_element) |> PrintToScript) - else - new_v = copy(v) - dn = new_v[return_idx].el - new_v[return_idx] = DualScript(dn; returned_element) |> PrintToScript - new_v - end - new(final_v) - end -end -struct ShowWithPrintHTML{D<:DisplayLocation, T} <: AbstractHTML{D} - el::T - ShowWithPrintHTML(el::T, ::D) where {T, D<:DisplayLocation} = new{D,T}(el) -end - -# HTML Nodes # -# We use a custom IO to parse the HypertextLiteral.Result for removing newlines and checking if empty -@kwdef struct ParseResultIO <: IO - parts::Vector = [] -end -# Now we define custom print method to extract the Result parts. See -# https://github.com/JuliaPluto/HypertextLiteral.jl/blob/2bb465047afdfbb227171222049f315545c307fb/src/primitives.jl -for T in (Bypass, Render, Reprint) - Base.print(io::ParseResultIO, x::T) = shouldskip(x) || push!(io.parts, x) -end - -_isnewline(x) = x in ('\n', '\r') # This won't remove tabs and whitespace -strip_nl(s::AbstractString) = lstrip(_isnewline, rstrip(s)) -_remove_leading(x) = x -_remove_leading(x::Bypass{<:AbstractString}) = Bypass(lstrip(_isnewline, x.content)) -_remove_trailing(x) = x -_remove_trailing(x::Bypass{<:AbstractString}) = Bypass(rstrip(isspace, x.content)) -# We define PlutoNode and NormalNode -for (T, P) in ((:PlutoNode, :InsidePluto), (:NormalNode, :OutsidePluto)) - block = quote - struct $T <: NonScript{$P} - content::Result - empty::Bool - end - # Empty Constructor - $T() = $T(@htl(""), true) - # Constructor from Result - function $T(r::Result) - io = ParseResultIO() - # We don't use show directly to avoid the EscapeProxy here - r.content(io) - node = if isempty(io.parts) - $T(r, true) - else - # We try to eventually remove trailing and leading redundant spaces - xs = io.parts - xs[begin] = _remove_leading(xs[begin]) - xs[end] = _remove_trailing(xs[end]) - $T(Result(xs...), false) - end - return node - end - # Constructor from AbstractString - function $T(s::AbstractString) - str = strip_nl(s) - out = if isempty(str) - $T(@htl(""), true) - else - r = @htl("$(ShowWithPrintHTML(str))") - $T(r, false) - end - end - # No-op constructor - $T(t::$T) = t - # Generic constructor - $T(content) = $T(@htl("$content")) - end - # Create the function constructing from HypertextLiteral or HTML - eval(block) -end - -## DualNode -struct DualNode <: NonScript{InsideAndOutsidePluto} - inside_pluto::PlutoNode - outside_pluto::NormalNode - DualNode(i::PlutoNode, o::NormalNode) = new(i, o) -end - -## CombinedNodes -struct CombinedNodes <: NonScript{InsideAndOutsidePluto} - nodes::Vector{<:ShowWithPrintHTML} - function CombinedNodes(v::Vector) - swph_vec = map(v) do el - make_node(el) |> ShowWithPrintHTML - end - filtered = filter(swph_vec) do el - skip_both = shouldskip(el, InsidePluto()) && shouldskip(el, OutsidePluto()) - !skip_both - end - new(filtered) - end -end - -const Single = Union{SingleNode, SingleScript} -const Dual = Union{DualScript, DualNode} -const Combined = Union{CombinedScripts, CombinedNodes} - -function Base.getproperty(c::Combined, s::Symbol) - if s === :children - children(c) - else - getfield(c,s) - end -end diff --git a/src/frompackage/FromPackage.jl b/src/frompackage/FromPackage.jl index a0a1050..dcd4fdb 100644 --- a/src/frompackage/FromPackage.jl +++ b/src/frompackage/FromPackage.jl @@ -1,6 +1,5 @@ module FromPackage import ..PlutoDevMacros: @addmethod, _cell_data - using HypertextLiteral import Pkg import TOML diff --git a/src/frompackage/helpers.jl b/src/frompackage/helpers.jl index 56b4859..5f54d90 100644 --- a/src/frompackage/helpers.jl +++ b/src/frompackage/helpers.jl @@ -1,4 +1,3 @@ -import ..PlutoCombineHTL: make_html, make_script import ..PlutoDevMacros: hide_this_log function get_temp_module() @@ -267,15 +266,16 @@ _popup_style(id) = """ function html_reload_button(cell_id; text = "Reload @frompackage", err = false) id = string(cell_id) - container = @htl(""" + style_content = _popup_style(id) + html_content = """ - """) - make_script([container, hide_this_log()]) |> make_html + """ + # We make an HTML object combining this content and the hide_this_log functionality + return hide_this_log(html_content) end # Function to clean the filepath from the Pluto cell delimiter if present diff --git a/src/html_helpers.jl b/src/html_helpers.jl index 7a77de7..7d80721 100644 --- a/src/html_helpers.jl +++ b/src/html_helpers.jl @@ -1,11 +1,38 @@ -using .PlutoCombineHTL - +# This function just makes a random alphanumeric id always starting with letter R +randid() = "R" * string(rand(UInt32); base = 62) # This function, if appearing inside a capture log message in Pluto (not with # println, just the @info, @warn, etc ones), will hide itself. It is mostly used # in combination with other scripts to inject some javascript in the notebook # without having an ugly empty log below the cell -function hide_this_log() - body = """ +""" + hide_this_log(html_content::AbstractString = "") + hide_this_log(html::Docs.HTML) +Simple function that returns a `Docs.HTML` object which when sent to Pluto logs with e.g. `@info` (or any other loggin macro), will hide the log from view. + +It is mostly intended to send some javascript to the logs for execution but avoid having an empty log box hanging around below the cell. +The output of this function contains a script which will hide the specific log that contains it, and if no other logs are present, will also hide the log container in Pluto. + +The function also optionally accept some content that will be inserted just before the script for hiding the log. +The custom input can be provided as an AbstractString, or directly as an HTML object of type `Docs.HTML`, in which case it will simply extract the HTML contents as `String` from the `contents` field. +The provided content will be directly interpreted as HTML, meaning that any script will have to be surrounded by `") + 3 +end +``` +Which will correctly send the message to the console even if the cell output is not the javascript script: +![hide_this_log example gif](https://github.com/disberd/PlutoDevMacros.jl/assets/12846528/8208243b-62ce-437a-ae87-97e63ca94e12) +""" +function hide_this_log(content::AbstractString = ""; id = randid()) + this_contents = "" + Docs.HTML() do io + # We print the provided contents first + print(io, content) + # We now add our custom script to hide the log + print(io, this_contents) + end end +hide_this_log(html::Docs.HTML; kwargs...) = hide_this_log(html.content; kwargs...) diff --git a/test/TestPackage/src/TestPackage.jl b/test/TestPackage/src/TestPackage.jl index b0aeae0..2ff03ab 100644 --- a/test/TestPackage/src/TestPackage.jl +++ b/test/TestPackage/src/TestPackage.jl @@ -15,7 +15,7 @@ module SUBINIT end end -import TestPackage.SUBINIT: TEST_SUBINIT +using TestPackage.SUBINIT: TEST_SUBINIT include("notebook1.jl") diff --git a/test/basics.jl b/test/basics.jl index 5121638..8531ca3 100644 --- a/test/basics.jl +++ b/test/basics.jl @@ -3,6 +3,8 @@ import Pluto: update_save_run!, update_run!, WorkspaceManager, ClientSession, ServerSession, Notebook, Cell, project_relative_path, SessionActions, load_notebook, Configuration using PlutoDevMacros +using PlutoDevMacros: hide_this_log +using Test function noerror(cell; verbose=true) if cell.errored && verbose @@ -37,4 +39,8 @@ eval_in_nb(sn, expr) = WorkspaceManager.eval_fetch_in_workspace(sn, expr) @test noerror(cell) end SessionActions.shutdown(ss, nb) -end \ No newline at end of file +end + +html_content = "asd" +html = html"asd" +@test hide_this_log(html_content; id = "asd") == hide_this_log(html; id = "asd") \ No newline at end of file diff --git a/test/combinehtl_module.jl b/test/combinehtl_module.jl deleted file mode 100644 index 5af6607..0000000 --- a/test/combinehtl_module.jl +++ /dev/null @@ -1,528 +0,0 @@ -using Test -using PlutoDevMacros.PlutoCombineHTL.WithTypes -using PlutoDevMacros.PlutoCombineHTL: LOCAL_MODULE_URL -using PlutoDevMacros.HypertextLiteral -using PlutoDevMacros.PlutoCombineHTL: shouldskip, children, print_html, -script_id, inner_node, plutodefault, haslisteners, is_inside_pluto, hasreturn, -add_pluto_compat, hasinvalidation, displaylocation, returned_element, to_string, -formatted_contents -import PlutoDevMacros -using PlutoDevMacros.PlutoCombineHTL.AbstractPlutoDingetjes.Display - -@testset "make_script" begin - ds = make_script("test") - @test make_script(ds) === ds - @test ds isa DualScript - @test inner_node(ds, InsidePluto()).body == inner_node(ds, OutsidePluto()).body - @test ds.inside_pluto.body.content === "test" - ds = make_script("lol"; id = "asdfasdf") - @test script_id(ds, InsidePluto()) === "asdfasdf" - @test script_id(ds, OutsidePluto()) === "asdfasdf" - ds2 = make_script( - make_script(:pluto; body = "lol", id = "asdfasdf"), - make_script(:normal; body = "lol", id = "different"), - ) - @test ds.inside_pluto == ds2.inside_pluto - @test ds.outside_pluto != ds2.outside_pluto - - @test shouldskip(ScriptContent()) === true - @test ScriptContent(nothing) === missing - @test ScriptContent(missing) === missing - sc = ScriptContent("addScriptEventListeners('lol')") - @test sc.addedEventListeners === true - sc = ScriptContent("console.log('lol')") - @test sc.addedEventListeners === false - - - @test_logs (:warn, r"No - - """)) - @test_logs (:warn, r"The provided input also contained contents outside") make_script(@htl(""" - - magic - """)) - @test_throws "No closing " make_script(@htl("")) - @test !shouldskip(ds, InsidePluto()) - @test shouldskip(ds, OutsidePluto()) - @test shouldskip(ds.inside_pluto.body) - @test ds.inside_pluto.invalidation.content === "lol" - - ps = PlutoScript("asd", "lol") - @test PlutoScript(ps) === ps - @test ps.body.content === "asd" - @test ps.invalidation.content === "lol" - @test shouldskip(ps, InsidePluto()) === false - @test shouldskip(ps, OutsidePluto()) === true - - ns = NormalScript("lol") - @test NormalScript(ns) === ns - @test_throws "You can't construct" NormalScript(ps).body - - let ds = DualScript(ps) - @test ds.inside_pluto === ps - @test shouldskip(ds, OutsidePluto()) - end - let ds = DualScript(ns) - @test ds.outside_pluto === ns - @test shouldskip(ds, InsidePluto()) - end - - cs = make_script([ - "asd", - "lol", - ]) - @test !(hasreturn(cs, InsidePluto()) || hasreturn(cs, OutsidePluto())) - @test hasinvalidation(cs) === false - @test add_pluto_compat(cs) === true - @test cs isa CombinedScripts - @test CombinedScripts(cs) === cs - @test make_script(cs) === cs - @test children(CombinedScripts(ds)) == children(make_script([ds])) - - @test isempty(children(make_script([PlutoScript("asd")]))) === false - @test isempty(children(make_script([NormalScript("asd")]))) === false - - make_script(ShowWithPrintHTML(cs)) === cs - @test_throws "only valid if `T <: Script`" make_script(ShowWithPrintHTML("asd")) - - # Now we test that constructing a CombinedScripts with a return in not the last script or more returns errors. - ds1 = make_script(PlutoScript(;returned_element = "asd")) - ds2 = make_script("asd") - - @test_throws "More than one return" make_script([ - ds1, - ds2, - ds1, - ]) - ds3 = make_script(PlutoScript(;returned_element = "asd"), NormalScript(;returned_element = "boh")) - cs = make_script([ - ds2, - ds3 - ]; returned_element = "lol" - ) - @test returned_element(cs, InsidePluto()) === "lol" - @test returned_element(cs, OutsidePluto()) === "lol" - @test returned_element(ds3, InsidePluto()) === "asd" - @test returned_element(ds3, OutsidePluto()) === "boh" - - cs = make_script([ - PrintToScript(3) - ]; returned_element = "asd") - @test last(children(cs)).el isa DualScript - - @test make_script(:outside, ds2) === ds2.outside_pluto - @test make_script(:Inside, ds2) === ds2.inside_pluto - - pts = PrintToScript(3) - @test make_script(pts) === pts - @test make_node(pts) isa CombinedScripts - - @test PrintToScript(pts) === pts - @test_throws "You can't wrap" PrintToScript(PlutoNode("asd")) - - pts = PrintToScript("asd") - @test pts.el isa DualScript -end - -@testset "make_node" begin - dn = make_node() - @test dn isa DualNode - @test shouldskip(dn, InsidePluto()) && shouldskip(dn, OutsidePluto()) - - s = make_script("asd") - dn = make_node("asd") - @test make_node(s) === s - @test dn != s - @test make_node(dn) === dn - cn = make_node([ - "asd", - "", - "lol" - ]) - @test cn isa CombinedNodes - @test CombinedNodes(cn) === cn - @test length(children(cn)) === 2 # We skipped the second empty element - @test make_node(cn) === cn - - cn = CombinedNodes(dn) - dn_test = cn.children[1].el - @test dn_test == dn - - @test PlutoNode(dn.inside_pluto) === dn.inside_pluto - @test PlutoNode(@htl("")).empty === true - - nn = NormalNode("lol") - dn = DualNode(nn) - @test inner_node(dn, OutsidePluto()) === nn - @test shouldskip(dn, InsidePluto()) - - pn = PlutoNode("asd") - dn = DualNode(pn) - @test inner_node(dn, InsidePluto()) === pn - @test shouldskip(dn, OutsidePluto()) - @test shouldskip(dn, InsidePluto()) === false - - - dn = DualNode("asd", "lol") - @test inner_node(dn, InsidePluto()) == pn - @test inner_node(dn, OutsidePluto()) == nn - @test DualNode(dn) === dn - - function compare_content(n1, n2; pluto = missing) - io1 = IOBuffer() - io2 = IOBuffer() - print_html(io1, n1; pluto = pluto === missing ? plutodefault(n1) : pluto) - print_html(io2, n2; pluto = pluto === missing ? plutodefault(n2) : pluto) - String(take!(io1)) == String(take!(io2)) - end - - @test compare_content(make_node(HTML("asd")), make_node("asd")) - @test compare_content(NormalNode("asd"), NormalNode(ShowWithPrintHTML("asd"))) - @test compare_content(PlutoNode("asd"), NormalNode("asd")) - @test compare_content(PlutoNode("asd"), NormalNode("asd"); pluto = true) === false - @test compare_content(PlutoNode("asd"), NormalNode("asd"); pluto = false) === false - - function test_stripping(inp, expected) - dn = make_node(inp) - pn = inner_node(dn, InsidePluto()) - io = IOBuffer() - print_html(io, pn) - s = String(take!(io)) - s === expected - end - - @test test_stripping("\n\n a\n\n"," a\n") # Only leading newlines (\r or \n) are removed - @test test_stripping("\n\na \n\n","a\n") # Only leading newlines (\r or \n) are removed - @test test_stripping(@htl("lol"), "lol\n") - @test test_stripping(@htl(" - lol - - "), " lol\n") # lol is right offset by 4 spaces - - - @test isempty(children(make_node([PlutoNode("asd")]))) === false - @test isempty(children(make_node([NormalNode("asd")]))) === false - - @test make_node(:pluto, "asd") === PlutoNode("asd") - @test make_node(:outside; content = "lol") === NormalNode("lol") - @test make_node(:both, "asd", "lol") === DualNode("asd", "lol") - @test make_node(:both, "asd", "lol") === make_node("asd", "lol") -end - -@testset "Other Helpers" begin - @test shouldskip(3) === false - s = make_html(PlutoScript()) - @test s isa ShowWithPrintHTML - @test make_html(s) === s - for T in (HypertextLiteral.Render, HypertextLiteral.Bypass) - @test shouldskip(T("lol")) === false - @test shouldskip(T("")) === true - end - - # We should not skip a script it is empty content but with an id - @test shouldskip(PlutoScript(""), InsidePluto()) == true - @test shouldskip(PlutoScript(""; id = "lol"), InsidePluto()) == false - @test shouldskip(NormalScript(""; id = "lol"), OutsidePluto()) == false - ds = DualScript(""; id = "lol") - @test shouldskip(ds, InsidePluto()) == shouldskip(ds, OutsidePluto()) == false - - for l in (InsidePluto(), OutsidePluto()) - @test haslisteners(make_script("asd"), l) === false - end - s = "addScriptEventListeners('lol')" - @test haslisteners(make_script(s, "asd"), InsidePluto()) === true - @test haslisteners(make_script(s, "asd"), OutsidePluto()) === false - @test haslisteners(missing) === false - - @test_throws "can not identify a display location" displaylocation(:not_exist) - - @test hasreturn(make_script("asd","lol"), InsidePluto()) === false - @test hasreturn(make_script("asd","lol"), OutsidePluto()) === false - ds = make_script(PlutoScript(; returned_element = "asd"),"lol") - @test shouldskip(ds.inside_pluto) === false - @test hasreturn(ds, InsidePluto()) === true - @test hasreturn(ds, OutsidePluto()) === false - @test hasreturn(make_script(NormalScript(;returned_element = "lol")), OutsidePluto()) === true - @test hasreturn(make_script(NormalScript(;returned_element = "lol")), InsidePluto()) === false - - cs = make_script([ - "asd", - "lol", - ]) - cn = make_node([ - "asd", - "lol", - ]) - # Test getproperty - @test cs.children === children(cs) - @test cn.children === children(cn) - - # We test the abstract type constructors - @test Script(InsideAndOutsidePluto()) === DualScript - @test Script(InsidePluto()) === PlutoScript - @test Script(OutsidePluto()) === NormalScript - - @test Node(InsideAndOutsidePluto()) === DualNode - @test Node(InsidePluto()) === PlutoNode - @test Node(OutsidePluto()) === NormalNode - - ps = PlutoScript("asd") - ns = NormalScript("asd") - ds = make_script(ps,ns) - @test DualScript("asd") == ds - @test_throws "can't construct" PlutoScript(ns) - @test_throws "can't construct" NormalScript(ps) - - @test PlutoScript(ds) === ps - @test NormalScript(ds) === ns - - for D in (InsidePluto, OutsidePluto, InsideAndOutsidePluto) - @test plutodefault(D) === plutodefault(D()) - @test displaylocation(D()) === D() - end - io = IOBuffer() - swp1 = ShowWithPrintHTML(make_node("asd"); display_type = :pluto) - swp2 = ShowWithPrintHTML(make_node("asd"); display_type = :both) # :both is the default - @test plutodefault(io, swp1) === plutodefault(swp1) - @test plutodefault(io, swp2) === is_inside_pluto(io) !== plutodefault(swp1) - - @test displaylocation(PrintToScript(3)) === InsideAndOutsidePluto() - @test displaylocation(PrintToScript(PlutoScript("asd"))) === InsidePluto() - - swph = ShowWithPrintHTML(3) - @test PlutoCombineHTL._eltype(swph) === Int - @test shouldskip(swph, InsidePluto()) === false - - swph = ShowWithPrintHTML(3; display_type = :outside) - @test shouldskip(swph, InsidePluto()) === true - - @test add_pluto_compat(3) === false - @test hasinvalidation(3) === false - - @test haslisteners(PrintToScript(3)) === false - @test hasreturn(PrintToScript(3)) === false - - @test script_id(PlutoScript("asd"), OutsidePluto()) === missing - pts = PrintToScript(3) - @test script_id(pts) === missing - - @test_throws "You can't wrap object" ShowWithPrintHTML(PrintToScript(3)) -end - -@testset "Show methods" begin - ps = PlutoScript("asd", "lol") - s = to_string(ps, MIME"text/javascript"()) - hs = to_string(ps, MIME"text/html"()) - @test contains(s, r"JS Listeners .* PlutoDevMacros") === false # No listeners helpers should be added - @test contains(s, "invalidation.then(() => {\nlol") === true # Test that the invaliation script is printed - @test contains(hs, r"") - s = to_string(r, MIME"text/html"()) - @test contains(s, "