vivliostyle / vfm

⬇️ Open and extendable Markdown syntax and toolchain.
https://vivliostyle.github.io/vfm/#/vfm
Other
71 stars 12 forks source link

spec: Fenced blocks #5

Open MurakamiShinyu opened 4 years ago

MurakamiShinyu commented 4 years ago

Adopt fenced divs from Pandoc's Markdown, that allows special fenced syntax for div blocks. See the spec: Pandoc Extension: fenced_divs

... As with fenced code blocks, one can use either attributes in curly braces or a single unbraced word, which will be treated as a class name. The Div ends with another line containing a string of at least three consecutive colons. The fenced Div should be separated by blank lines from preceding and following blocks.

Example:

::::: {#special .sidebar}
Here is a paragraph.

And another.
:::::

Fenced divs can be nested. Opening fences are distinguished because they must have attributes:

::: Warning ::::::
This is a warning.

::: Danger
This is a warning within a warning.
:::
::::::::::::::::::

Fences without attributes are always closing fences. Unlike with fenced code blocks, the number of colons in the closing fence need not match the number in the opening fence. ...

Discussion

This "fenced divs" syntax is very similar to the walled block in the current VFM draft. I prefer "fenced divs" because:

MurakamiShinyu commented 4 years ago

Extend to HTML semantic elements

I'd like to change the issue title "Fenced divs" to "Fenced blocks" because I want to extend it for HTML semantic elements.

Examples:

:::::: section {.classA #idA role="doc-abstract" aria-label="Abstract"}
The **Abstract** section has a summary of the principal ideas, 
concepts and conclusions of the work.
::::::

will be converted to:

<section id="idA" class="classA" role="doc-abstract" aria-label="Abstract">
<p>The <strong>Abstract</strong> section has a summary of the principal ideas,
concepts and conclusions of the work.</p>
</section>

and

:::::: aside {role="doc-tip"}
### Tip
Helpful information that clarifies some aspect of the content
or assists in its comprehension.
::::::

will be converted to:

<aside role="doc-tip">
<h3>Tip</h3>
<p>Helpful information that clarifies some aspect of the content
or assists in its comprehension.</p>
</aside>

Update: syntax changed ::: {section .classA #idA…} to ::: section {.classA #idA…} because the tag name inside the curly braces might make confusion with attribute name without value specified.

MurakamiShinyu commented 4 years ago

Testing with pandoc, I found that ::: aside is converted to <div class="aside"> (not <aside>), but ::: section is converted to <section> (not <div class="section">). This behavior is different from what the pandoc document says: "a single unbraced word, which will be treated as a class name". I want to fix this inconsistency.

Proposal: the unbraced word is treated as element name if it is a valid HTML element name, otherwise treated as a class name (same as {.className}).

spring-raining commented 4 years ago

One of my concerns is that attribute list which we should allow (Obviously ::: {script="alert('XSS')"} have to be omitted), but this spec seems to be very useful!

uetchy commented 4 years ago

I had the same concern @spring-raining had. And that's why only classes are allowed in the original spec of walled blocks.

Too many freedoms sometimes could be harmful.

uetchy commented 4 years ago

I like the naming of Fenced blocks from @MurakamiShinyu. It sounds natural.

tk0miya commented 4 years ago

Proposal: the unbraced word is treated as element name if it is a valid HTML element name, otherwise treated as a class name (same as {.className}).

I prefer unbraced word is always considered as an element name, and braced words are considered as attributes (classes, IDs and attributes). It is consistent behavior. magical behavior would be useful, indeed. But it sometimes confuses readers.

MurakamiShinyu commented 4 years ago

I agree that relying on "valid HTML element names" is not a good idea. It will change by HTML spec updates. And also we should consider about Custom elements.

uetchy commented 4 years ago

So here is my take.

# Chapter 2

:::author
uetchy
:::
<h1>Chapter 2</h1>
<div class="author">
<p>uetchy</p>
</div>
.author {
  padding: 5px;
  border: 1px solid black;
  border-radius: 4px;
}

role support

Since we care about WCAG, role property must have special treatment. so here it is. @ is used because of its resemblance to a roll. any thoughts?

:::@doc-tip
### Tip
:::
<aside role="doc-tip">
<h3>Tip</h3>
</aside>
[role="doc-tip"] {
  background-color: yellow;
}

custom attributes

Maybe we need fine-grained control over these blocks, yet it's not so often. but it's always good to leave an option to users, isn't it?

:::alertbox {style="text-decoration: uppercase"}
Users beware!
:::

:::{#fig:signup}
1. Go to webiste
2. Click on `signup` button
:::
<div class="alertbox" style="text-decoration: uppercase">
<p>Users beware!</p>
</div>

<div id="signup" data-ref="fig">
<ul>
<li>Go to website</li>
<li>Click on <code>signup</code> button</li>
</ul>
</div>

latter uses cross-ref syntax.

kmuto commented 4 years ago

What will be happen on VFM when omitting open/close notation?

Pattern A:

:::author
I forgot to close.
Pattern B:

I forgot to open.
:::
uetchy commented 4 years ago

VFM just ignores them.

kmuto commented 4 years ago

OK, so...

:::div1
alpha
:::::div2
beta
::::::::
tk0miya commented 4 years ago

Just FYI: The fenced code block in commonmark is closed by the end of the document if no closing code-fence found. https://spec.commonmark.org/0.29/#example-96

MurakamiShinyu commented 3 years ago

現状の vfm の Fenced blocks 実装とその課題、Pandoc との比較

Fenced blocks は、Prior Art である Pandoc の fenced_divs と互換性があるとよい。

Pandoc の fenced_divs の仕様

https://pandoc.org/MANUAL.html#extension-fenced_divs

例:

::::: {#special .sidebar}
Here is a paragraph.

And another.
:::::

<div id="special" class="sidebar">
  <p>Here is a paragraph.</p>
  <p>And another.</p>
</div>

次はネストの例。開始のフェンスには属性指定があることで終了のフェンスと区別される(3つ以上連続するコロンの数は関係ない):

::: Warning ::::::
This is a warning.

::: Danger
This is a warning within a warning.
:::
::::::::::::::::::

<div class="Warning">
  <p>This is a warning.</p>
  <div class="Danger">
    <p>This is a warning within a warning.</p>
  </div>
</div>

内容が空の fenced div を試すと:

:::empty
:::

<div class="empty"></div>

現状の vfm の Fenced blocks をテストすると

しかし、現状の vfm パーサーの実装では、Pandoc のドキュメントにある次の例が処理できない:

::::: {#special .sidebar}
Here is a paragraph.

And another.
:::::

<p>::::: {#special .sidebar} Here is a paragraph.</p>
<p>And another. :::::</p>

Fenced blockへの {…} での属性指定は未サポート。ではクラス名だけを書く記法ではどうか:

::::: sidebar
Here is a paragraph.

And another.
:::::

<p>::::: sidebar Here is a paragraph.</p>
<p>And another. :::::</p>

どうも連続するコロンの数が3つよりも多いと fenced block として処理されないようである。コロンを3つに直したら:

::: sidebar
Here is a paragraph.

And another.
:::

<div class="sidebar">
  <p>Here is a paragraph.</p>
  <p>And another.</p>
</div>

ネストの例ではどうか。

::: Warning ::::::
This is a warning.

::: Danger
This is a warning within a warning.
:::
::::::::::::::::::

<p>::: Warning :::::: This is a warning.</p>
<div class="Danger"><p>This is a warning within a warning.</p></div>
<p>::::::::::::::::::</p>

これを次のように直したところ現状の vfm で処理できるようになった:

::: Warning
This is a warning.

:::: Danger
This is a warning within a warning.
::::
:::

<div class="Warning">
  <p>This is a warning.</p>
  <div class="Danger">
    <p>This is a warning within a warning.</p>
  </div>
</div>

内容が空の Fenced block を試すと、Fenced block として処理されない:

:::empty
:::

<p>:::empty :::</p>

ここまでで分かった問題点

現状の vfm のパーサーでは

見出しとの組み合わせの場合

Pandoc では、fenced div 内が見出しではじまる場合、fenced div で div ではなく section 要素が生成される。

例:

::: appendix
## Appendix A {#aaa .bbb data-ccc=ddd}

This is an appendix.
:::

<section id="aaa" class="bbb appendix" data-ccc="ddd">
  <h2 class="bbb" data-ccc="ddd">Appendix A</h2>
  <p>This is an appendix.</p>
</section>

pandocに --section-divs オプションを指定した場合の結果は:

<section id="aaa" class="level2 bbb appendix" data-ccc="ddd">
  <h2 class="bbb" data-ccc="ddd">Appendix A</h2>
  <p>This is an appendix.</p>
</section>

--section-divs オプションの有無にかかわらず、fenced div内が見出しではじまる場合は section 要素で囲まれ、見出しに指定された属性はsection要素にコピーされる。 class属性に levelN (N は見出しのレベル) が追加されることだけ --section-divs 指定があると違う。

現状のvfmでは

::: appendix
## Appendix A {#aaa .bbb data-ccc=ddd}

This is an appendix.
:::

<div class="appendix">
  <section id="aaa" class="bbb" data-ccc="ddd">
    <h2>Appendix A</h2>
    <p>This is an appendix.</p>
  </section>
</div>

vfm では見出しで自動的に section 要素が作られるが、Fenced block の div 要素の中にその section 要素ができる。あまりスマートでない。

role 属性について

現在の VFM の独自拡張で次のような記法で DPUB-ARIA の role 属性を指定できる:

:::@appendix
# Appendix A
:::

<section role="doc-appendix" id="appendix-a">
  <h1>Appendix A</h1>
</section>

この独自拡張仕様の見直しについては spec: WAI-ARIA role syntax (#28) にコメントする。 その要点は以下:

HTML 要素名を明示的に指定可能にする拡張案

(このコメントは長過ぎだったので次のコメント https://github.com/vivliostyle/vfm/issues/5#issuecomment-777996312 に移動)

akabekobeko commented 3 years ago

昨日の開発者会議を受けた #67 のとおり、本機能は v2 へ見送ります。

akabekobeko commented 3 years ago

VFM v2 は remark-parse v9 対応を想定しているので、その際は本機能を自前で実装せずに Pandoc 互換となる以下を採用するのがよさそう。

MurakamiShinyu commented 3 years ago

HTML 要素名を明示的に指定可能にする拡張案

(前のコメント https://github.com/vivliostyle/vfm/issues/5#issuecomment-768119623 が長過ぎだったので分割した)

Pandoc の fenced_divs では、基本は div 要素が作られ、最初の要素が見出しであれば div の代わりに section 要素が作られる。

これをさらに拡張して、ほかの HTML 要素名も指定可能にしたい。

拡張案:

例:

::: aside
Hello
:::

<aside class="aside">
  <p>Hello</p>
</aside>

属性の指定もある場合:

::: article {#aaa .bbb data-ccc="ddd"}
# The Article
:::

<article id="aaa" class="article bbb" data-ccc="ddd">
  <h1>The Article</h1>
</article>

波括弧囲みのクラス名指定だけの場合はそれを HTML 要素名にはしない:

::: {.aside}
Hello
:::

<div class="aside">
  <p>Hello</p>
</div>
::: {.aside}
# Hello
:::

<section class="aside" id="hello">
  <h1>Hello</h1>
</section>

Fenced block の ::: のあとの名前を HTML 要素名にすると不正な HTML になるような場合には、その名前を HTML 要素名とはしないでクラス名にする

::: span
# Hello
:::

<section class="span" id="hello">
  <h1>Hello</h1>
</section>

Fenced block の内容にインラインのテキストも可能にする拡張案

Fenced block の ::: のあとの名前が HTML 要素名で、その内容に段落(p)要素を持つことができないものである場合、Fenced block 内のテキストを段落要素にしないでインラインのテキストの扱いにする

::: small
This is a small notice.
:::

<small class="small">This is a small notice.</small>

Fenced block の終了を分かりやすくする拡張案

Fenced block の終了の ::: のあとに任意で /名前 を書けるようにすることで、ネストした fenced block の開始と終了のペアを分かりやすくできたらよいかもしれない。例:

::: aside
:::: Warning
This is a warning.

::::: Danger
This is a warning within a warning.
::::: /Danger
:::: /Warning
::: /aside
MurakamiShinyu commented 3 years ago

@akabekobeko

VFM v2 は remark-parse v9 対応を想定しているので、その際は本機能を自前で実装せずに Pandoc 互換となる以下を採用するのがよさそう。

remark-fenced-divs の readme に次の記述:

If you don't need Pandoc compatibility you should consider using remark-directive.

remark-fenced-divs あるいは remark-directive を検討するとよさそうですね。

remark-directive では

:::main{#readme}

<main id="readme">

になります。これは私の HTML 要素名を明示的に指定可能にする拡張案 と似ています。私の案では、

:::main{#readme}

<main class="main" id="readme">

となるのですが、要素名と同じものをclassにも出力するのは実績がある Pandoc となるべく互換にしようとしたためです。 しかし、remark-directive の拡張が多くの人が利用する標準になっていくのであれば、Pandoc互換にこだわる必要はありません。

akabekobeko commented 3 years ago

この記法は #67 により v1.0 では見送りとなりました。v2.0 で検討する場合は↑の @MurakamiShinyu さんコメントにあるとおり parser 変更があるため Pandoc 互換の benabel/remark-fenced-divs を検討予定です。

MurakamiShinyu commented 3 years ago

v2.0 で検討する場合は↑の @MurakamiShinyu さんコメントにあるとおり parser 変更があるため Pandoc 互換の benabel/remark-fenced-divs を検討予定です。

Pandoc 互換ではない remarkjs/remark-directive も検討するとよいです。

akabekobeko commented 3 years ago

はい。両方を候補にしましょう。ただし択一にしたいですね。

nosuke23 commented 2 years ago

Pandoc の fenced_divs では、基本は div 要素が作られ、最初の要素が見出しであれば div の代わりに section 要素が作られる。 これをさらに拡張して、ほかの HTML 要素名も指定可能にしたい。

MarkdownはHTMLの軽量マークアップ言語であり、HTMLによるドキュメント生成において比較的頻繁に用いられるセマンティックタグやタグ構造を、ドキュメントの執筆者にとって見やすく、書きやすいように設計されたものです。

:::main ... :::がその哲学に則っているかというとどうでしょう。多くのMarkdownユーザーにとって一般的でないし、他のMarkdown拡張と互換性がない上、<main>~</main>と書くのと記述量として大差がありません。

単純にPandoc互換を目的とするなら、Pandoc記法のサブセットにすべきかと。

MurakamiShinyu commented 1 year ago

Fenced blocksによって解決されると期待されている問題:

MurakamiShinyu commented 1 year ago

Pandoc 互換ではない remarkjs/remark-directive も検討するとよいです。

はい。両方を候補にしましょう。ただし択一にしたいですね。

Pandoc互換の https://github.com/benabel/remark-fenced-divs は、"ARCHIVED: This plugin has never been completely adapted for remark 13+." となっているので、今後 remark 13+ に移行予定のvfmには使えなさそう。

vfm v1→v2の仕様変更で、見出しのsection囲みでの属性の扱いについてPandoc互換をやめていることもあるし、Pandoc互換よりも remarkjs のエコシステムでポピュラーで使いやすいものを採用するのがよさそう。