Search code examples
htmlluamarkdownpandoc

Convertng Markdown admonition syntax to HTML, using Lua for Pandoc


The Markdown admonition syntax is based on https://python-markdown.github.io/extensions/admonition/:

!!! note Important note
    You should note that the title will be automatically capitalized.

The Pandoc documentation is very poorly explained and badly written. I've trained myself with the following questions:

I attempted to build in Lua:

function Para (para)
  if para.content[1].text == "!!!" and para.content[1].text == "note" then
    return pandoc.Plain(
      {pandoc.RawInline('html', '<div class="admonition note">')} ..
      {pandoc.RawInline('html', '<p class="admonition-title">')} ..
      para.content[2].text ..
      {pandoc.RawInline('html', '</p>')} ..
      para.content[3].text ..
      {pandoc.RawInline('html', '</div>')}
    )
  elseif para.content[1].text == "!!!" and para.content[1].text == "danger" then
    return pandoc.Plain(
      {pandoc.RawInline('html', '<div class="admonition danger">')} ..
      {pandoc.RawInline('html', '<p class="admonition-title">')} ..
      para.content[2].text ..
      {pandoc.RawInline('html', '</p>')} ..
      para.content[3].text ..
      {pandoc.RawInline('html', '</div>')}
    )
  end
end

I would expect:

<div class="admonition note">
<p class="admonition-title">Important note</p>
<p>You should note that the title will be automatically capitalized.</p>
</div>

Update 1

It almost worked, I just didn't like para.content[number].text because I need to surround "Important note" for admonition title and to catch the whole sentence after that admonition title for a paragraph.

function Para(para)
  if para.content[1].text == '!!!' and para.content[2].tag == 'Space' and para.content[3].text == 'note' then
    return pandoc.RawInline('html',
      '<div class="admonition note">'
        .. '\n\t' ..
        '<p class="admonition-title">' 
          .. para.content[5].text .. 
        '</p>'
        .. '\n\t' ..
        para.content[5].text ..
        '\n' .. 
      '</div>')
  elseif para.content[1].text == '!!!' and para.content[2].tag == 'Space' and para.content[3].text == 'danger' then
    return pandoc.Emph {pandoc.Str "Danger"}
  end
end

Update 2

Your answer worked, but doesn't work with two codes:

  1. When no title, it looks like:
!!! important ""

But it gave an output:

<div class="admonition important ““"><p class="admonition-title">IMPORTANT</p>
admonition with no title
</div>

You can notice important ““". If I want to use "" to hide the title, it would give an output: <div class="admonition important"><p class="admonition-title no-title">IMPORTANT</p></div>.

  1. When I want to include one than paragraphs, containing italic, bold, blockquote, code, etc., your filter takes only the first paragraph, therefore, ignores the rest of the text. You can see the the reference: https://github.com/qjebbs/vscode-markdown-extended#admonition. It should look like in HTML:
<div class="admonition important"><p class="admonition-title">IMPORTANT</p>
<p> Here is the first paragraph with a <code>code</code>...</p>
<p> Here is the second paragraph with <i>italic</i> and <b>boild</b>...
<pre><code class="language-css">.css { color: black; }</code></pre>
<blockquote>
Accidit in puncto, quod non contingit in anno
</blockquote>
Julius Caesarus
</div>

Update 3

Please forgive me for failing to deliver the full CSS code for you before. Get the full code below:

@font-face {
    font-family: "Material Icons";
    font-style: normal;
    font-weight: 400;
    src: local("Material Icons"), local("MaterialIcons-Regular"), url("data:application/x-font-woff;charset=utf-8;base64,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") format("woff");
}

.admonition {
    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12), 0 3px 1px -2px rgba(0, 0, 0, .2);
    position: relative;
    margin: 1.5625em 0;
    padding: 0 1.2rem;
    border-left: .4rem solid rgba(68, 138, 255, .8);
    border-radius: .2rem;
    background-color: rgba(255, 255, 255, 0.05);
    overflow: auto;
}

.admonition>p {
    margin-top: .8rem;
}

.admonition>.admonition-title {
    margin: 0 -1.2rem;
    padding: .8rem 1.2rem .8rem 3.6rem;
    border-bottom: 1px solid rgba(68, 138, 255, .2);
    background-color: rgba(68, 138, 255, .1);
    font-weight: 700;
}

.admonition>.admonition-title:before {
    position: absolute;
    left: 1.2rem;
    font-size: 1.5rem;
    color: rgba(68, 138, 255, .8);
    content: "\E3C9";
}

.admonition>.admonition-title:before {
    font-family: Material Icons;
    font-style: normal;
    font-variant: normal;
    font-weight: 400;
    line-height: 2rem;
    text-transform: none;
    white-space: nowrap;
    speak: none;
    word-wrap: normal;
    direction: ltr;
}

.admonition.summary,
.admonition.abstract,
.admonition.tldr {
    border-left-color: rgba(0, 176, 255, .8);
}

.admonition.summary>.admonition-title,
.admonition.abstract>.admonition-title,
.admonition.tldr>.admonition-title {
    background-color: rgba(0, 176, 255, .1);
    border-bottom-color: rgba(0, 176, 255, .2);
}

.admonition.summary>.admonition-title:before,
.admonition.abstract>.admonition-title:before,
.admonition.tldr>.admonition-title:before {
    color: rgba(0, 176, 255, 1);
    ;
    content: "\E8D2";
}

.admonition.hint,
.admonition.tip {
    border-left-color: rgba(0, 191, 165, .8);
}

.admonition.hint>.admonition-title,
.admonition.tip>.admonition-title {
    background-color: rgba(0, 191, 165, .1);
    border-bottom-color: rgba(0, 191, 165, .2);
}

.admonition.hint>.admonition-title:before,
.admonition.tip>.admonition-title:before {
    color: rgba(0, 191, 165, 1);
    content: "\E80E";
}

.admonition.info,
.admonition.todo {
    border-left-color: rgba(0, 184, 212, .8);
}

.admonition.info>.admonition-title,
.admonition.todo>.admonition-title {
    background-color: rgba(0, 184, 212, .1);
    border-bottom-color: rgba(0, 184, 212, .2);
}

.admonition.info>.admonition-title:before,
.admonition.todo>.admonition-title:before {
    color: rgba(0, 184, 212, 1);
    ;
    content: "\E88E";
}

.admonition.success,
.admonition.check,
.admonition.done {
    border-left-color: rgba(0, 200, 83, .8);
}

.admonition.success>.admonition-title,
.admonition.check>.admonition-title,
.admonition.done>.admonition-title {
    background-color: rgba(0, 200, 83, .1);
    border-bottom-color: rgba(0, 200, 83, .2);
}

.admonition.success>.admonition-title:before,
.admonition.check>.admonition-title:before,
.admonition.done>.admonition-title:before {
    color: rgba(0, 200, 83, 1);
    ;
    content: "\E876";
}

.admonition.question,
.admonition.help,
.admonition.faq {
    border-left-color: rgba(100, 221, 23, .8);
}

.admonition.question>.admonition-title,
.admonition.help>.admonition-title,
.admonition.faq>.admonition-title {
    background-color: rgba(100, 221, 23, .1);
    border-bottom-color: rgba(100, 221, 23, .2);
}

.admonition.question>.admonition-title:before,
.admonition.help>.admonition-title:before,
.admonition.faq>.admonition-title:before {
    color: rgba(100, 221, 23, 1);
    ;
    content: "\E887";
}

.admonition.warning,
.admonition.attention,
.admonition.caution {
    border-left-color: rgba(255, 145, 0, .8);
}

.admonition.warning>.admonition-title,
.admonition.attention>.admonition-title,
.admonition.caution>.admonition-title {
    background-color: rgba(255, 145, 0, .1);
    border-bottom-color: rgba(255, 145, 0, .2);
}

.admonition.attention>.admonition-title:before {
    color: rgba(255, 145, 0, 1);
    content: "\E417";
}

.admonition.warning>.admonition-title:before,
.admonition.caution>.admonition-title:before {
    color: rgba(255, 145, 0, 1);
    content: "\E002";
}

.admonition.failure,
.admonition.fail,
.admonition.missing {
    border-left-color: rgba(255, 82, 82, .8);
}

.admonition.failure>.admonition-title,
.admonition.fail>.admonition-title,
.admonition.missing>.admonition-title {
    background-color: rgba(255, 82, 82, .1);
    border-bottom-color: rgba(255, 82, 82, .2);
}

.admonition.failure>.admonition-title:before,
.admonition.fail>.admonition-title:before,
.admonition.missing>.admonition-title:before {
    color: rgba(255, 82, 82, 1);
    ;
    content: "\E14C";
}

.admonition.danger,
.admonition.error,
.admonition.bug {
    border-left-color: rgba(255, 23, 68, .8);
}

.admonition.danger>.admonition-title,
.admonition.error>.admonition-title,
.admonition.bug>.admonition-title {
    background-color: rgba(255, 23, 68, .1);
    border-bottom-color: rgba(255, 23, 68, .2);
}

.admonition.danger>.admonition-title:before {
    color: rgba(255, 23, 68, 1);
    content: "\E3E7";
}

.admonition.error>.admonition-title:before {
    color: rgba(255, 23, 68, 1);
    content: "\E14C";
}

.admonition.bug>.admonition-title:before {
    color: rgba(255, 23, 68, 1);
    content: "\E868";
}

.admonition.example,
.admonition.snippet {
    border-left-color: rgba(0, 184, 212, .8);
}

.admonition.example>.admonition-title,
.admonition.snippet>.admonition-title {
    background-color: rgba(0, 184, 212, .1);
    border-bottom-color: rgba(0, 184, 212, .2);
}

.admonition.example>.admonition-title:before,
.admonition.snippet>.admonition-title:before {
    color: rgba(0, 184, 212, 1);
    ;
    content: "\E242";
}

.admonition.quote,
.admonition.cite {
    border-left-color: rgba(158, 158, 158, .8);
}

.admonition.quote>.admonition-title,
.admonition.cite>.admonition-title {
    background-color: rgba(158, 158, 158, .1);
    border-bottom-color: rgba(158, 158, 158, .2);
}

.admonition.quote>.admonition-title:before,
.admonition.cite>.admonition-title:before {
    color: rgba(158, 158, 158, 1);
    ;
    content: "\E244";
}

.no-title
{
    display: none;
}

I had acknowledged of Pandoc's new Markdown syntax definition, but it is a bad idea to use dl, dt and dd for admonitions because they are designed for definitions, dictionaries, and glossaries. But anyway, I also tested with and without a Markdown syntax : and it wasn't what I expected.

With your updated Lua code, here is the result (click the image to enlarge):

result

In the second admonition, your filter didn't remove the title.

Expected:

expected

You can compare the images and understand it easily.

I prepared Markdown and HTML codes for you.

Here is the Markdown code:

<!-- With title -->
!!! note "Pay attention!"
    Title for notes

    some code and text
    
    ```C
    int main(){
        puts("Hello World!");
    }
    ```

    It is a good code.

    !!! danger "Be careful!"
    Title for denger
    
    some code and text

    ```python
    print
    ```

    It is not a good

<!-- Without title -->
!!! note ""
    Title for notes

    some code and text

    ```C
    int main(){
        puts("Hello World!");
    }
    ```

    It is a good code.

    !!! danger "Be careful!"
    Title for denger
    
    some code and text

    ```python
    print
    ```

    It is not a good

And the HTML code:

  <!-- With title -->

  <div class="admonition note">
    <p class="admonition-title">Pay attention!</p>

    <p>Title for notes</p>
    <p>some code and text</p>
    <div class="sourceCode" id="cb1">
      <pre class="sourceCode C"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">(){</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    puts<span class="op">(</span><span class="st">&quot;Hello World!&quot;</span><span class="op">);</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre>
    </div>
    <p>It is a good code.</p>
    <div class="admonition danger">
      <p class="admonition-title">Be careful!</p>

      <p>Title for denger</p>
      <p>some code and text</p>
      <div class="sourceCode" id="cb2">
        <pre
          class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">&quot;!!!&quot;</span>)</span></code></pre>
      </div>
      <p>It is not a good code.</p>
    </div>

  </div>

  <!-- Without title -->

  <div class="admonition note">
    <p class="admonition-title no-title">Pay attention!</p>

    <p>Title for notes</p>
    <p>some code and text</p>
    <div class="sourceCode" id="cb3">
      <pre class="sourceCode C"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">(){</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    puts<span class="op">(</span><span class="st">&quot;Hello World!&quot;</span><span class="op">);</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre>
    </div>
    <p>It is a good code.</p>
    <div class="admonition danger">
      <p class="admonition-title">Be careful!</p>

      <p>Title for denger</p>
      <p>some code and text</p>
      <div class="sourceCode" id="cb4">
        <pre
          class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">&quot;!!!&quot;</span>)</span></code></pre>
      </div>
      <p>It is not a good code.</p>
    </div>

  </div>

Solution

  • Here is a lua filter like Python-Markdown's Admonition extension syntax.

    You can use many tags(CSS class names), and Quoted title ""

    the different in this filter is you can't use indent, for pandoc do not think !!! should have a indent, so pandoc will render badly if you use indent.

    !!! danger notes "title"
    You should note that the title will be automatically capitalized.
    ```haskell
    --code will be rendered
    main::IO ()
    main = main
    ```
    
    *Emph string* and **strong string**
    
    !!! important ""
    admonition with no title
    

    the lua filter

    function Para(para)
      if para.content[1] and para.content[1].text == '!!!' and 
        para.content[2] and para.content[2].tag == 'Space' and 
        para.content[3] and para.content[3].tag == 'Str' then
        local text = para.content[3].text -- default title is tag
        tags = text
        title = string.upper(text)
        i = 4
        -- parse tags
        while para.content[i] and para.content[i].tag ~= 'SoftBreak'
        do
          -- tags can only be string or spaces
          if para.content[i].tag == 'Str' then
            tags = tags .. para.content[i].text
          elseif para.content[i].tag == 'Space' then
            tags = tags .. ' '
          -- Quoted is title
          elseif para.content[i].tag == 'Quoted' then
            title = pandoc.utils.stringify(para.content[i].content)
          end
          i = i + 1
        end
        if para.content[i] and para.content[i].tag == 'SoftBreak' then
          body = pandoc.List({table.unpack(para.content, i+1)})
        else
          body = '' -- no body
        end
        return pandoc.Blocks( -- merge into blocks
          {
            pandoc.RawInline(
              'html','<div class="admonition ' .. tags .. '">' ..
              '<p class="admonition-title">' .. title .. '</p>'
            ),
            pandoc.Plain(body),
            pandoc.RawInline('html', '</div>')
          }
        )
      end
    end
    

    preview output(the first paragraph)

    $ pandoc test.md --lua-filter f.lua
    <div class="admonition danger notes "><p class="admonition-title">title</p>
    You should note that the title will be automatically capitalized.
    </div>
    

    you can add a stylesheet, for example H.html

    <style>
    div.note {
        background-color: #24502426;
    }
    div.danger {
        background-color: #8c24047a;
    }
    p.admonition-title {
        font-family: cursive;
    }
    </style>
    

    then run

    $ pandoc test.md --lua-filter f.lua -s -o main.html -H H.html
    

    Update 2

    update for empty title

    @Gustavo Reis pandoc read wrong indentation before filter processing the text, so my filter can't be nesting.If you want to change this, you can try definition lists which can be nesting

    function Para(para)
      if para.content[1] and para.content[1].text == '!!!' and 
        para.content[2] and para.content[2].tag == 'Space' and 
        para.content[3] and para.content[3].tag == 'Str' then
        local text = para.content[3].text -- default title is tag
        tags = text
        title = string.upper(text)
        i = 4
        -- parse tags
        while para.content[i] and para.content[i].tag ~= 'SoftBreak'
        do
          -- tags can only be string or spaces
          if para.content[i].tag == 'Str' then
            if para.content[i].text == '“”' then
              title = nil
            else
              tags = tags .. para.content[i].text
            end
          elseif para.content[i].tag == 'Space' then
            tags = tags .. ' '
          -- Quoted is title
          elseif para.content[i].tag == 'Quoted' then
            title = pandoc.utils.stringify(para.content[i].content)
          end
          i = i + 1
        end
        if para.content[i] and para.content[i].tag == 'SoftBreak' then
          body = pandoc.List({table.unpack(para.content, i+1)})
        else
          body = '' -- no body
        end
        if title==nil then
          title_html = '<p class="admonition-title no-title"/>'
        else
          title_html = '<p class="admonition-title">' .. title .. '</p>'
        end
        return pandoc.Blocks( -- merge into blocks
          {
            pandoc.RawInline(
              'html','<div class="admonition ' .. tags .. '">' .. title_html
            ),
            pandoc.Plain(body),
            pandoc.RawInline('html', '</div>')
          }
        )
      end
    end
    

    definition list example

    definition list example

    notes
    
    :   title for notes
    
        some code and text
        ```C
        int main(){
            puts("Hello World!");
        }
        ```
    
        denger
        :   title for denger
        
            some code and text
            ```python
            print('!!!!')
            ```
    

    Update 3

    in this update, I use definition list in markdown(with !!! syntax) and replace lua filter to javascript code.

    window.onload = function(){
        document.querySelectorAll('dl').forEach(n => n.classList.add('admonition'))
        let dts = document.querySelectorAll('dt');
        for(let dt of dts){
            let text = dt.innerText;
            let default_title = false;
            if (text.slice(0, 4)=='!!! '){
                let i = text.lastIndexOf('“');
                dt.classList.add('admonition-title');
                if (i == -1) {
                    i = text.length;
                    default_title = true;
                }
                let tags = text.slice(4, i).split(' ').filter((x)=>x.length);
                for (var j = tags.length - 1; j >= 0; j--) {
                    dt.parentNode.classList.add(tags[j]);
                }
                if (default_title) {
                    dt.innerText = tags[0] || "";
                }else{
                    let end = text.lastIndexOf('”');
                    if (end == -1) {
                        end = text.length;
                    }
                    dt.innerText = text.slice(i+1, end);
                    if (dt.innerText == '') {
                        dt.classList.add('no-title');
                    }
                }
            }         
        }
    }
    

    the markdown code

    <!-- With title -->
    !!! note "Pay attention!"
    :   Title for notes
    
        some code and text
        
        ```C
        int main(){
            puts("Hello World!");
        }
        ```
    
        It is a good code.
    
        !!! danger "Be careful!"
        :   Title for denger
        
            some code and text
        
            ```python
            print
            ```
        
            It is not a good
    
    <!-- Without title -->
    !!! note ""
    :   Title for notes
    
        some code and text
    
        ```C
        int main(){
            puts("Hello World!");
        }
        ```
    
        It is a good code.
    
        !!! danger "Be careful!"
        :   Title for denger
            
            some code and text
        
            ```python
            print
            ```
        
           It is not a good
    

    this CSS code is unchanged

    below is screenshot

    It seems that the effect of using dt, dl, dd is similar to using div