Why Sponsor Oils? | source | all docs for version 0.24.0 | all versions | oilshell.org
ul-table
is an HTML processor that lets you write tables as bulleted
lists, in Markdown.
To make this table:
Shell | Version |
---|---|
bash | 5.2 |
OSH | 0.25.0 |
You write:
<table>
- thead
- Shell
- Version
- tr
- [bash](https://www.gnu.org/software/bash/)
- 5.2
- tr
- [OSH](https://oils.pub/)
- 0.25.0
</table>
Any Markdown processor will produce this:
And then our ul-table
plugin transforms that into the table shown.
So the conversion takes 2 steps. The intermediate form is what sourcehut
or Github will show, because they currently don't support ul-table
.
This is good, because it means that ul-table
degrades gracefully! You can
use it anywhere without worrying about breakage.
ul-table
Because it's tedious to read, write, and edit <tr>
and <td>
and </td>
and
</tr>
. Aligning columns is also tedious in HTML.
Design goals:
You make tables with a two-level Markdown list, between <table>
tags.
The top level list contains either:
thead |
zero or one, at the beginning |
tr |
zero or more, after thead |
The second level contains the contents of cells, but you don't write td
or <td>
.
(This format looks similar to tables in reStructuredText).
As mentioned, it takes two steps to convert:
<table> <ul> <li> ... </li> </ul> </table>
structure.ul-table
plugin transforms that into a
<table> <tr> <td> </td> </tr> </table>
structure, which is a normal HTML
table.So ul-table
is an HTML processor, not a Markdown processor. But it's
meant to be used with Markdown.
Here's the equivalent in CommonMark:
<table>
<thead>
<tr>
<td>Shell</td>
<td>Version</td>
</tr>
</thead>
<tr>
<td>
<!-- be careful not to indent this 4 spaces! -->
[bash](https://www.gnu.org/software/bash/)
</td>
<td>5.2</td>
</tr>
<tr>
<td>
[OSH](https://oils.pub/)
</td>
<td>0.25.0</td>
</tr>
</table>
It uses the rule where you can embed Markdown inside HTML inside Markdown.
With ul-table
, you don't need this mutual nesting.
The ul-table
text is also shorter!
Trivia: with CommonMark, you get an extra <p>
element:
<td>
<p>OSH</p>
</td>
ul-table
can produce simpler HTML:
<td>
OSH
</td>
To make the table look nice, I add a <style>
tag, inside Markdown:
<style>
table {
margin: 0 auto;
}
td {
padding-left: 1em;
padding-right: 1em;
}
</style>
HTML attributes like <tr class=foo>
and <td id=bar>
let you format and
style your table.
You can add attributes to cells, columns, and rows.
Name | Age |
---|---|
Alice | 42 |
Bob | 9 |
Add cell attributes with a cell-attrs
tag after the cell contents:
- thead
- Name
- Age
- tr
- Alice
- 42 <cell-attrs class=hi />
- tr
- Bob
- 9
It's important that cell-attrs
is a self-closing tag:
<cell-attrs /> # Yes
<cell-attrs> # No: this is an opening tag
How does this work? ul-table
takes the attributes from <cell-attrs />
, and
puts it on the generated <td>
.
Name | Age |
---|---|
Alice | 42 |
Bob | 9 |
To add attributes to every cell in a column, put <cell-attrs />
in the
thead
section:
- thead
- Name
- Age <cell-attrs class=num />
- tr
- Alice
- 42 <!-- this cell gets class=num -->
- tr
- Bob
- 9 <!-- this cells gets class=num -->
This is particularly useful for aligning numbers to the right:
<style>
.num {
align: right;
}
</style>
If the same attribute appears in a column in both thead
and tr
, the values
are concatenated, with a space. Example:
<td class="from-thead from-tr">
Name | Age |
---|---|
Alice | 42 |
Bob | 9 |
To add row attributes, put <row-attrs />
after the - tr
:
- thead
- Name
- Age
- tr
- Alice
- 42
- tr <row-attrs class="special-row" />
- Bob
- 9
Here's an example that uses more features. Source code of this table: doc/ul-table.md.
Shell | Version | Example Code | ||||
---|---|---|---|---|---|---|
bash | 5.2 |
|
||||
dash | 1.5 | Inline HTML | ||||
mksh | 4.0 |
|
||||
zsh | 3.6 | Unordered List
|
||||
yash | 1.0 | Ordered List
|
||||
This is paragraph one. This is paragraph two |
Another cell with ... ... multiple paragraphs. |
Another table:
OSH | YSH |
---|---|
|
|
x | y |
Here are some quirks I ran into when creating ul-tables.
(1) CommonMark doesn't allow empty list items:
- thead
-
- above is not rendered as a list item
You can work around this by using a comment, or invisible character:
- tr
- <!-- empty -->
- above is OK
- tr
-
- also OK
(2) Similarly, a cell with a literal hyphen may need a comment or space in front of it:
- tr
- <!-- hyphen --> -
- -
Related discussions:
Github-flavored Markdown has an non-standard extension for tables:
This style is hard to read and write, especially with large tables:
| Command | Description |
| --- | --- |
| git status | List all new or modified files |
| git diff | Show file differences that haven't been staged |
Our style is less noisy, and more easily editable:
<table>
- thead
- Command
- Description
- tr
- git status
- List all new or modified files
- tr
- git diff
- Show file differences that haven't been staged
</table>
Here is a long page describing how to make tables on Wikipedia:
I created the equivalent of the opening example:
{| class="wikitable"
! Shell !! Version
|-
| [https://www.gnu.org/software/bash/ Bash] || 5.2
|-
| [https://www.oilshell.org/ OSH] || 0.25.0
|}
In general, it has more "ASCII art", and invents a lot of new syntax.
I prefer ul-table
because it reuses Markdown and HTML syntax.
ul-table
is a nice way of writing and maintaining HTML tables. The appendix
has links and details.
TODO: I would like someone to produce a DOM-based implementation!
Our implementation is pretty low-level. It's meant to avoid the "big load anti-pattern" (allocating too much), so it's a necessarily more verbose.
A DOM-based implementation should be much less than 1000 lines.
ul-table
.
I converted the tables in these September posts to ul-table
:
The markup was much shorter and simpler after conversion!
TODO:
<th>
is like <td>
, but it belongs in <thead><tr>
. Browsers make it
bold and centered.class=
on <colgroup>
and <col>
and align columns left and
right.
class=
on every <td>
cell instead.ul-table
solves this with "inherited" <cell-attrs />
in the thead
section.tfoot
?tbody
?We could help users edit well-formed tables with enforced column names:
- thead
- <cell-attrs ult-name=name /> Name
- <cell-attrs ult-name=age /> Age
- tr
- <cell-attrs ult-name=name /> Hi
- <cell-attrs ult-name=age /> 5
This is a bit verbose, but may be worth it for large tables.
Less verbose syntax idea:
- thead
- <ult col=NAME /> <cell-attrs class=foo /> Name
- <ult col=AGE /> Age
- tr
- <ult col=NAME /> Hi
- <ult col=AGE /> 5
Even less verbose:
- thead
- {NAME} Name
- {AGE} Age
- tr
- {NAME} Hi
- {AGE} 5
The obvious problem is that we might want the literal text {NAME}
in the
header. It's unlikely, but possible.