Repository: tlienart/Franklin.jl
Pull request #674 (2020-10-25 21:45:46)

Better support for inline code and code blocks
* adds support for quadruple backtick blocks + small  refactoring around that to make things better, in theory we could add 6, 7, ... backticks but I thought that 5 was already good enough
* strip content of inline blocks so that we can  show a single tick without spurious whitespace

cc @fredrikekre since you might want to give this a  shot once it's in


Patch:
diff --git a/Project.toml b/Project.toml
index eed9ac85..effb7136 100644
--- a/Project.toml
+++ b/Project.toml
@@ -1,7 +1,7 @@
 name = "Franklin"
 uuid = "713c75ef-9fc9-4b05-94a9-213340da978e"
 authors = ["Thibaut Lienart <tlienart@me.com>"]
-version = "0.10.7"
+version = "0.10.8"
 
 [deps]
 Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
diff --git a/src/converter/markdown/blocks.jl b/src/converter/markdown/blocks.jl
index 1b51999f..f46526ba 100644
--- a/src/converter/markdown/blocks.jl
+++ b/src/converter/markdown/blocks.jl
@@ -12,7 +12,7 @@ function convert_block(β::AbstractBlock, lxdefs::Vector{LxDef})::AS
     βn = β.name
     βn ∈ MD_HEADER         && return convert_header(β, lxdefs)
 
-    βn == :CODE_INLINE     && return html_code_inline(content(β) |> htmlesc)
+    βn == :CODE_INLINE     && return html_code_inline(stent(β) |> htmlesc)
     βn == :CODE_BLOCK_LANG && return resolve_code_block(β.ss)
     βn == :CODE_BLOCK_IND  && return convert_indented_code_block(β.ss)
     βn == :CODE_BLOCK      && return html_code(stent(β), "{{fill lang}}")
diff --git a/src/parser/markdown/tokens.jl b/src/parser/markdown/tokens.jl
index 53336e0a..cacb4977 100644
--- a/src/parser/markdown/tokens.jl
+++ b/src/parser/markdown/tokens.jl
@@ -85,12 +85,15 @@ const MD_TOKENS = LittleDict{Char, Vector{TokenFinder}}(
               isexactly("_\$<_") => :MATH_I_CLOSE, # within mathenv (e.g. \R <> \mathbb R)
               incrlook(is_hr2)   => :HORIZONTAL_RULE,
              ],
-    '`'  => [ isexactly("`", ('`',), false)  => :CODE_SINGLE, # `⎵
-              isexactly("``",('`',), false)  => :CODE_DOUBLE, # ``⎵*
-              isexactly("```", SPACE_CHAR)   => :CODE_TRIPLE, # ```⎵*
+    '`'  => [ isexactly("`",  ('`',), false)  => :CODE_SINGLE, # `⎵
+              isexactly("``", ('`',), false)  => :CODE_DOUBLE, # ``⎵*
+              # 3+ can be named
+              isexactly("```",   SPACE_CHAR) => :CODE_TRIPLE, # ```⎵*
+              is_language(3)                 => :CODE_LANG3,  # ```lang*
+              isexactly("````",  SPACE_CHAR) => :CODE_QUAD,   # ````⎵*
+              is_language(4)                 => :CODE_LANG4,  # ````lang*
               isexactly("`````", SPACE_CHAR) => :CODE_PENTA,  # `````⎵*
-              is_language()                  => :CODE_LANG,   # ```lang*
-              is_language2()                 => :CODE_LANG2,  # `````lang*
+              is_language(5)                 => :CODE_LANG5,  # `````lang*
              ],
     '*'  => [ incrlook(is_hr3)   => :HORIZONTAL_RULE,
              ]
@@ -140,9 +143,11 @@ const MD_OCB = [
     # ---------------------------------------------------------------------
     OCProto(:COMMENT,         :COMMENT_OPEN, (:COMMENT_CLOSE,)),
     OCProto(:MD_DEF_BLOCK,    :MD_DEF_TOML,  (:MD_DEF_TOML,)  ),
-    OCProto(:CODE_BLOCK_LANG, :CODE_LANG,    (:CODE_TRIPLE,)  ),
-    OCProto(:CODE_BLOCK_LANG, :CODE_LANG2,   (:CODE_PENTA,)   ),
+    OCProto(:CODE_BLOCK_LANG, :CODE_LANG3,   (:CODE_TRIPLE,)  ),
+    OCProto(:CODE_BLOCK_LANG, :CODE_LANG4,   (:CODE_QUAD,)    ),
+    OCProto(:CODE_BLOCK_LANG, :CODE_LANG5,   (:CODE_PENTA,)   ),
     OCProto(:CODE_BLOCK,      :CODE_TRIPLE,  (:CODE_TRIPLE,)  ),
+    OCProto(:CODE_BLOCK,      :CODE_QUAD,    (:CODE_QUAD,)    ),
     OCProto(:CODE_BLOCK,      :CODE_PENTA,   (:CODE_PENTA,)   ),
     OCProto(:CODE_INLINE,     :CODE_DOUBLE,  (:CODE_DOUBLE,)  ),
     OCProto(:CODE_INLINE,     :CODE_SINGLE,  (:CODE_SINGLE,)  ),
diff --git a/src/parser/tokens.jl b/src/parser/tokens.jl
index c5a64164..f26a340a 100644
--- a/src/parser/tokens.jl
+++ b/src/parser/tokens.jl
@@ -262,32 +262,23 @@ In combination with `incrlook`, checks to see if we have something that looks
 like a triple backtick followed by a valid combination of letter defining a
 language. Triggering char is a first backtick.
 """
-is_language() = incrlook(_is_language, _validate_language)
+is_language(j) = incrlook(_is_language(j), _validate_language(j))
 
-function _is_language(i::Int, c::Char)
-    i < 3  && return c == '`'  # ` followed by `` forms the opening ```
-    i == 3 && return α(c)      # must be a letter
-    return α(c, ('-',))        # can be a letter or a hyphen, for instance ```objective-c
+function _is_language(j)
+    λ(i::Int, c::Char) = begin
+        i < j  && return c == '`'  # ` followed by `` forms the opening ```
+        i == j && return α(c)      # must be a letter
+        return α(c, ('-',))        # can be a letter or a hyphen, for instance ```objective-c
+    end
+    return λ
 end
 
-_validate_language(stack::AS) = !isnothing(match(r"^```[a-zA-Z]", stack))
-
-"""
-$(SIGNATURES)
-
-See [`is_language`](@ref) but with 5 ticks.
-"""
-is_language2() = incrlook(_is_language2, _validate_language2)
-
-function _is_language2(i::Int, c::Char)
-    i < 5  && return c == '`'
-    i == 5 && return α(c)
-    return α(c, ('-',))
+function _validate_language(j)
+    rx = Regex("^$('`'^j)[a-zA-Z]")
+    λ(stack::AS) = !isnothing(match(rx, stack))
+    return λ
 end
 
-_validate_language2(stack::AS) = !isnothing(match(r"^`````[a-zA-Z]", stack))
-
-
 """
 $(SIGNATURES)
 
diff --git a/src/utils/vars.jl b/src/utils/vars.jl
index 5c7bdcbb..69c7c97e 100644
--- a/src/utils/vars.jl
+++ b/src/utils/vars.jl
@@ -199,14 +199,15 @@ const ALL_PAGE_VARS = Dict{String,PageVars}()
 
 Convenience function to get the value associated with a var available to a page
 corresponding to `rpath`. So for instance if `blog/index.md` has `@def var = 0`
-then this can be accessed with `pagevar("blog/index", "var")`.
+then this can be accessed with `pagevar("blog/index", "var")` or
+`pagevar("blog/index.md", "var")`.
 If `rpath` is not yet a key of `ALL_PAGE_VARS` then maybe the page hasn't been
 processed yet so force a pass over that page.
 """
 function pagevar(rpath::AS, name::Union{Symbol,String})
     # only split extension if it's .md or .html (otherwise can cause trouble
     # if there's a dot in the page name... not recommended but happens.)
-    rpc = splitext(rpath)[1]
+    rpc = splitext(rpath)
     if rpc[2] in (".md", ".html")
         rpath = rpc[1]
     end


Test patch:
diff --git a/test/parser/markdown-extra.jl b/test/parser/markdown-extra.jl
index 9c240721..e2edf142 100644
--- a/test/parser/markdown-extra.jl
+++ b/test/parser/markdown-extra.jl
@@ -27,6 +27,11 @@ end
     @test tokens[1].name == :CODE_TRIPLE
     @test tokens[2].name == :CODE_TRIPLE
 
+    st = raw"""A ```` B ```` C"""
+    tokens = F.find_tokens(st, F.MD_TOKENS, F.MD_1C_TOKENS)
+    @test tokens[1].name == :CODE_QUAD
+    @test tokens[2].name == :CODE_QUAD
+
     st = raw"""A ````` B ````` C"""
     tokens = F.find_tokens(st, F.MD_TOKENS, F.MD_1C_TOKENS)
     @test tokens[1].name == :CODE_PENTA
@@ -34,12 +39,12 @@ end
 
     st = raw"""A ```b B ``` C"""
     tokens = F.find_tokens(st, F.MD_TOKENS, F.MD_1C_TOKENS)
-    @test tokens[1].name == :CODE_LANG
+    @test tokens[1].name == :CODE_LANG3
     @test tokens[2].name == :CODE_TRIPLE
 
     st = raw"""A `````b B ````` C"""
     tokens = F.find_tokens(st, F.MD_TOKENS, F.MD_1C_TOKENS)
-    @test tokens[1].name == :CODE_LANG2
+    @test tokens[1].name == :CODE_LANG5
     @test tokens[2].name == :CODE_PENTA
 
     h = raw"""