Repository: PumasAI/QuartoNotebookRunner.jl (julia)

Issue:
Support inline code syntax
https://quarto.org/docs/computations/inline-code.html

Pull request description:
The behaviour of `AbstractString` printing and escaping needs to be decided on here. Worth seeing what the other languages actually do.

Patch:
diff --git a/src/server.jl b/src/server.jl
index 224e49f1..f3bec49d 100644
--- a/src/server.jl
+++ b/src/server.jl
@@ -575,13 +575,36 @@ function evaluate_raw_cells!(f::File, chunks::Vector, options::Dict; showprogres
                 ),
             )
         elseif chunk.type === :markdown
+            marker = "{julia} "
+            source = chunk.source
+            if contains(chunk.source, "`$marker")
+                parser = Parser()
+                for (node, enter) in parser(chunk.source)
+                    if enter && node.t isa CommonMark.Code
+                        if startswith(node.literal, marker)
+                            source_code = replace(node.literal, marker => "")
+                            expr = :(render($(source_code), $(chunk.file), $(chunk.line)))
+                            remote = Malt.remote_eval_fetch(f.worker, expr)
+                            if !isnothing(remote.error)
+                                error("Error rendering inline code: $(remote.error)")
+                            end
+                            processed = process_inline_results(remote.results)
+                            source = replace(
+                                source,
+                                "`$(node.literal)`" => "$processed";
+                                count = 1,
+                            )
+                        end
+                    end
+                end
+            end
             push!(
                 cells,
                 (;
                     id = string(nth),
                     cell_type = chunk.type,
                     metadata = (;),
-                    source = process_cell_source(chunk.source),
+                    source = process_cell_source(source),
                 ),
             )
         else
@@ -638,6 +661,24 @@ function extract_cell_options(source::AbstractString; file::AbstractString, line
     end
 end
 
+function process_inline_results(dict::Dict)
+    # A reduced set of mimetypes are available for inline use.
+    for (mime, func) in ["text/markdown" => String, "text/plain" => _escape_markdown]
+        if haskey(dict, mime)
+            payload = dict[mime]
+            if payload.error
+                error("Error rendering inline code: $(String(payload.data))")
+            else
+                return func(payload.data)
+            end
+        end
+    end
+    error("No valid mimetypes found in inline code results.")
+end
+
+_escape_markdown(s::AbstractString) = replace(s, r"([\\`*_{}[\]()#+\-.!|])" => s"\\\1")
+_escape_markdown(bytes::Vector{UInt8}) = _escape_markdown(String(bytes))
+
 """
     process_results(dict::Dict{String,Vector{UInt8}})
 
diff --git a/src/worker.jl b/src/worker.jl
index 0cf729d6..411cb88b 100644
--- a/src/worker.jl
+++ b/src/worker.jl
@@ -85,7 +85,7 @@ function worker_init(f::File)
             code::AbstractString,
             file::AbstractString,
             line::Integer,
-            cell_options::AbstractDict,
+            cell_options::AbstractDict = Dict{String,Any}(),
         )
             captured = Base.@invokelatest include_str(WORKSPACE[], code; file, line)
             results = Base.@invokelatest render_mimetypes(


Test patch:
diff --git a/test/testsets/inline_code.jl b/test/testsets/inline_code.jl
new file mode 100644
index 00000000..7b7d9fcb
--- /dev/null
+++ b/test/testsets/inline_code.jl
@@ -0,0 +1,65 @@
+include("../utilities/prelude.jl")
+
+@testset "Inline code" begin
+    mktempdir() do dir
+        qmd = joinpath(dir, "inline_code.qmd")
+        write(
+            qmd,
+            """
+            ---
+            title: "Inline code"
+            ---
+
+            ```{julia}
+            a = 1
+            ```
+
+            Some variables `{julia} a + 1`.
+
+            ```{julia}
+            struct Custom
+                value
+            end
+            Base.show(io::IO, ::MIME"text/markdown", c::Custom) = print(io, "*\$(c.value)*")
+            ```
+
+            Some custom markdown MIME type output `{julia} Custom("markdown")`.
+
+            ```{julia}
+            b = Text("*placeholder*")
+            ```
+
+            Some `Text` objects *`{julia} b`*. Escaped markdown syntax.
+
+            ```{julia}
+            c = "*placeholder*"
+            ```
+
+            Some plain `String`s `{julia} c`. Escaped markdown syntax.
+
+            > # A more complex expression `{julia} round(Int, 1.5)`.
+            """,
+        )
+
+        server = Server()
+        json = run!(server, qmd; showprogress = false)
+
+        cells = json.cells
+
+        cell = cells[3]
+        @test any(contains("Some variables 2."), cell.source)
+
+        cell = cells[5]
+        @test any(
+            contains("Some custom markdown MIME type output *markdown*."),
+            cell.source,
+        )
+
+        cell = cells[7]
+        @test any(contains("Some `Text` objects *\\*placeholder\\**."), cell.source)
+
+        cell = cells[9]
+        @test any(contains("Some plain `String`s \"\\*placeholder\\*\"."), cell.source)
+        @test any(contains("A more complex expression 2."), cell.source)
+    end
+end