如何在 Markdown Julia 中使用内插字符串的固定宽度格式?

How can I have fixed-width format of an interpolated string in markdown Julia?

假设我有一个变量filename = "/home/jimmy/logger.log"。我想要一些这样的降价文档:

md"""
The output is logged at `$(filename)`
"""

我知道有两种解决方法:

第一个:

Markdown.parse("The output is logged at `" * filename * "`")

第二个:

str = "The output is logged at `$(filename)`"
md"$str"

有没有办法直接告诉markdown宏在反引号解析之前做字符串插值?

这令人费解,但我想我明白了。不,没有办法让 @md_str 宏先进行字符串插值,但我在下面有一个解决方法。

我花了一段时间才意识到,当使用 f"arg"f`arg` 语法调用 @f_str@f_cmd 宏时,它接收原始字符串 raw"arg" 作为参数而不是表达式 :("arg") 否则宏会得到:

julia> macro showarg_str(x) show(x) end;

julia> showarg"text$var"
"text$var"
julia> @showarg_str("text$var")
:("text$(var)")

此行为 is definedjulia-paser.scm 解析器中。

但是像 md"$expr" 这样的代码显示的是计算后的 expr 而不是原始字符串 raw"$expr"!这是怎么回事?事实证明 $expr 在通过 Markdown 模块中的自定义代码解析为 Markdown 期间被解析为表达式;这是 largely implemented in interp.jl. According to the documentation 这是有意而为的,以便 Markdown 树存储表达式而不是评估这些表达式的字符串。从理论上讲,这有助于高级自定义功能。实际上,这让我头疼。

现在,使用 Markdown.parse 似乎可以如您所愿。因为作为常规函数而不是宏,Markdown.parse 接收内插字符串,而不是原始字符串或表达式:

julia> Markdown.parse("The output is logged at `$(filename)`") |> show
The output is logged at `/home/jimmy/logger.log`

但是,由于 $ 处理在 Markdown.parse 中再次发生,所以有 undesirable/unintuitive 行为是这样的:

julia> Markdown.parse(raw"$filename") |> show
:filename

以下内容未记录,但我认为改变此行为的最佳方法是在 Markdown.flavors 中定义和自定义新的 Markdown 风格,然后使用此风格作为参数调用 Markdown.parse .在 flavor 的配置中,我们只需要停止在解析期间调用 blockinterpinterp。可以这样做:

let
    config = deepcopy(Markdown.flavors[:julia])
    filter!(!=(Markdown.blockinterp), config.regular)
    filter!(!=(Markdown.interp), get(config.inner, '$', []))
    Markdown.flavors[:julia_nointerp] = config
end

为了允许 Markdown 模块在此配置之后而不是之前加载,我们可以将其放入一个方便的函数中:

function md(str, flavor=:julia_nointerp)
    @isdefined(Markdown) || error("the Markdown module must be loaded. Try `using Markdown`.")
    if flavor == :julia_nointerp && !haskey(Markdown.flavors, :julia_nointerp)
        config = deepcopy(Markdown.flavors[:julia])
        filter!(!=(Markdown.blockinterp), config.regular)
        filter!(!=(Markdown.interp), get(config.inner, '$', []))
        Markdown.flavors[:julia_nointerp] = config
    end
    return Markdown.parse(str; flavor=flavor)
end

现在您可以调用 md("markdown code") 来使用标准字符串插值进行 Markdown 解析,而不是 md"markdown code" 执行的特殊 $ 解析:

julia> filename = "/home/jimmy/logger.log";

julia> md("The output is logged at `$(filename)`") |> show
The output is logged at `/home/jimmy/logger.log`

julia> md("The output is logged at `$(filename)`") |> typeof
Markdown.MD

julia> md("The output is logged at `$(filename)`").content
1-element Array{Any,1}:
 Markdown.Paragraph(Any["The output is logged at ", Markdown.Code("", "/home/jimmy/logger.log")])

P.S.: 我不建议将 md 变成宏或尝试修改 @md_str 宏,因为:(1) 一个函数就足够了,并且 (2)使用函数意味着用户可以确定在将参数传递给 md.

之前会发生标准字符串插值