jgm / djot

A light markup language
https://djot.net
MIT License
1.66k stars 43 forks source link

More compact syntax for definition lists #128

Open matklad opened 1 year ago

matklad commented 1 year ago

Djot's block-oriented definition list syntax is very verbose and "porous" for simple cases. Compare Djot

: Name

  Alex Kladov

: GitHub

  <https://github.com/matklad>

: email

  See GitHub profile

With asciidoctor

Name:: Alex Kladov
Github:: https://github.com/matklad
email:: See GitHub profile

This seems like a tough problem: what I want here I think is making the blank like after the term optional, and maybe even allowing same-line definition, but that goes a bit against djot's grain

hellux commented 1 year ago

Making the blank line optional would break goal 7 (wrapping). However, a lone colon is not very common, it is usually immediately after a word.

Perhaps something similar to footnotes?

[:term]: first line
more optional lines

(maybe colon is not best character here, though)

As footnotes/reference definitions already allow the blank line to be omitted your example would look like

[:Name]: Alex Kladov
[:Github]: https://github.com/matklad
[:email]: See GitHub profile

However, one major difference to footnotes is that the term within the brackets may contain arbitrary inline content while for footnotes it may only be a tag. This would complicate the block level parsing.

This would also disallow multi-line terms, breaking goal 7 (wrapping) and goal 8 (uniformity).

chrisjsewell commented 1 year ago

+1 I'd note that restructured text has the similar: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#field-lists

:Date: 2001-08-16
:Version: 1
:Indentation: Since the field marker may be quite long, the second
   and subsequent lines of the field body do not have to line up
   with the first line, but they must be indented relative to the
   field name marker, and they must line up with each other.
bpj commented 1 year ago

I would suggest to adopt the MediaWiki definition list syntax:

; term 1a
; term 1b
: def 1a
: def 1b
: def 1c
; term 2
: def 2
; term 3
: def 3

It allows multiple terms after each other, uses somewhat natural punctuation — semicolon leader for terms and colon leader for definition — for the task and is super easy to parse even if extended to allow multiple line/block definitions by indentation because neither semicolon nor colon normally occurs at the start of a line.

Personally I have no problem with the blank line requirement since blank lines enhance readability but I think this syntax has advantages whether blank lines are required or not.

mtsknn commented 1 year ago

I would suggest to adopt the MediaWiki definition list syntax

I find it very difficult to distinguish between : and ; because they are so alike.

How about using e.g. single colons for the terms and two colons for the definitions?

: term 1a
: term 1b
:: def 1a
:: def 1b
:: def 1c
: term 2
:: def 2
: term 3
:: def 3

Lazy syntax:

: term 1a
spanning two lines
: term 1b
:: def 1a
:: def 1b
spanning
three lines

(Ideally the lazy syntax would be (auto-)formatted like so:)

: term 1a
  spanning two lines
: term 1b
:: def 1a
:: def 1b
   spanning
   three lines

No idea about parseability though.

jgm commented 1 year ago

I don't really like any of these suggestions, because they detract from the uniformity of the language. Currently definition lists work exactly like any other lists; the marker is : and the "term" is the first block after the :; the rest is the definition.

Aside from that issue, the only one of these that looks good is the rST syntax. However, that is not the rST syntax for definition lists; it is the syntax for field lists. We couldn't use that anyway, because we already use :TEXT: for something else, and because we need the ability to have the "term" part of a definition list item longer than a word. The general rST syntax for definition lists is this:

term
  definition

  continued

other term
  definition
hellux commented 1 year ago

I don't really like any of these suggestions, because they detract from the uniformity of the language. Currently definition lists work exactly like any other lists; the marker is : and the "term" is the first block after the :; the rest is the definition.

In my opinion, definition lists do not necessarily have to work exactly like lists because they are fundamentally different from lists. Each description item is a term (<dt>) and a description (<dd>) while a list item is only a list item, i.e. <li>.

Because they share the same syntax, one might think that they are similar. For example, in

: term

 description

- content

 more content

"description" is different from "term" but "more content" is just a continuation of "content". This is however not implied by the syntax, as it looks more or less identical in both cases.

matklad commented 1 year ago

the marker is : and the "term" is the first block after the :; the rest is the definition.

Ohhh, that's very neat, didn't realize that. I wonder if the solution here is some syntax/convention to force block-break inline.

To strawman, a converter can recognize

: Name :is: Alex Kladov

as two blocks, without adding extra sytnax and just special-casing :is: in the filter.

If I look at it this way, the problem looks very similar to what we have with tables: on the one hand, we want table cells to be blocks (to support arbitrary formatting). On the other hand, we want to be able to specify multiple cells on the same line for convenience.

As another strawman idea, what if we use || as a generic way to subdivide block into subblocks?

Table with row-per line

{.with-header,rows=3}
::: table
one || two || three

1 || 2 || 3
:::

Table with cell-per-line

{.with-header,rows=3}
::: table
one || two || three

|| 1 
|| 2 
|| 3
:::

Table with block content

{.with-header,rows=3}
::: table
one || two || three

```rust
fn rust_code_in_first_column() {}

:::: the last column contains a complex block block with a nested table

::::: table ... :::::

::::

:::

: Definiton || list

jgm commented 1 year ago

Interesting thought. It would give us a way (other than list tables) of having block-level content in tables, as well as a compact definition list syntax. A big drawback is the use of the English word table to write a table; I want to avoid that, and I would like a table to look like a table in the source. Another question is how you'd indicate the start of a new row. Really I think this is reinventing the mediawiki table syntax.

matklad commented 1 year ago

fleshed out the idea a bit more in https://github.com/jgm/djot/issues/27#issuecomment-1346808514