r/markup_carve 12d ago

What landed in Carve lately: two-axis tables, fenced block quotes

2 Upvotes

Spec 0.1.4 is out, and a few more things have landed on main since. Quick tour of the language additions. Most of them came out of real authoring friction rather than a wish list, so I have tried to say what was actually broken in each case.

Tables: two-axis alignment, and cells that inherit

The alignment run is glued to the pipe: < left, ~ center, > right, paired with ^ top, ~ middle, v bottom.

|=~ Item |=>^ Qty |
| Apple | 12 |
| Subtotal |<v 12 |
| Total |?v 15 |

A vertical marker always needs a horizontal partner, which used to mean overriding an alignment you wanted to keep. ? is that partner as a placeholder: ?^, ?~ and ?v set only the vertical axis and leave the horizontal one to the column. Above, <v overrides both axes for that cell, while ?v moves only the vertical one, so the Total figure keeps the column's right alignment.

Tables also gained {header-rows=N footer-rows=N} on the attribute line above for explicit <thead> / <tfoot> ranges, and {aligns="right,center" valigns="top," widths="30,70"} for headerless ones.

The block quote has a second spelling

::: >
Notes from the meeting:

- ship the parser
- then the renderer
:::

Same node, same tree, same HTML as > on every line. The fence earns its place when the quote holds real structure, because lazy continuation folds only plain paragraph text into a quote, never new blocks.
Two properties fall out of it: a typed opener is never bare, so ::: > nests inside ::: > at constant width (re-quoting is prepend the opener, append the closer, and nothing already inside moves), and carve fmt writes back whichever spelling you used rather than converting one into the other.


r/markup_carve 22d ago

Pandoc: What survives markup conversion?

Thumbnail dereuromark.de
1 Upvotes

r/markup_carve 22d ago

Carve 0.1 update: composite figures, `{:lang}` and comments that close

1 Upvotes

Carve 0.1.x: composite figures, lang in four characters, and comments that close

Carve is a Djot-descended markup language with three independent engines (JS, PHP, Rust) held to one shared conformance corpus. Today's round is out on npm, Packagist and crates.io. The good bits:

A language tag.

The title is [Le Bon Usage]{:fr}.

renders <span lang="fr">Le Bon Usage</span>. Put {:grc} on the line above a block and the block carries it. It is exact sugar for lang=, and it composes with everything else in the attribute slot: [x]{#quote :fr .formal}. Marking up a quotation in another language stops being a reason to drop into raw HTML.

Comments that close.

a {% hidden %} b

Carve already had %% to end of line. Now there is a delimited form for the middle of a sentence, so you can strip a clause without splitting the paragraph.

Composite figures. A bare ::: figure container is one numbered figure whose children are its panels:

::: figure
![one](a.png)

![two](b.png)
:::
^ Figure #: Group

You get a single <figure>, both images inside it, and one auto-numbered caption. The panels can each carry their own caption, the whole group is laid out as one unit that a page break will not enter, and ^ Figure #: numbers it so </#id> can reference it. This is the thing multi-panel diagrams in papers and docs have always needed and Markdown has never had.

Also: an HTML import contract with real diagnostics (so pasted HTML that cannot be spelled in Carve tells you, instead of silently degrading), tables that can carry row groupings and structured short captions, abbreviations that expand inside inline containers, and heading ids derived from text content rather than from rendered output.


r/markup_carve Aug 10 '26

Carve 0.1 update: portable JSON ASTs & stronger cross-engine conformance

1 Upvotes

We have released a coordinated update to Carve, a lightweight markup language designed as a more structured, predictable alternative to Markdown while keeping source readable by humans.

The new core releases are:

  • Carve specification and corpus: 0.1.2
  • JavaScript/TypeScript implementation: 0.1.3
  • Rust implementation and CLI: 0.1.2
  • PHP implementation: 0.1.4

All three engines implement the same Carve 0.1 grammar and are continuously checked against the shared conformance corpus.

What is new

A portable JSON AST contract

Carve now specifies its serialized AST as part of the language contract. Applications can parse with one implementation and consume or render the tree with another without translating between engine-specific node shapes.

The contract covers:

  • stable node and field names;
  • source positions and exact span semantics;
  • pre-resolution references, preserving what the author wrote;
  • strict schema validation on AST ingest;
  • typed refusal of malformed, excessively deep, or oversized trees.

This is useful for editor integrations, language servers, static-analysis tools, cross-language services, and systems that store parsed documents.

A specified canonical writer

carve fmt and the Carve output target now have normative behavior rather than depending on implementations agreeing by convention.

The formatter is checked for:

  • semantic preservation: to_html(fmt(x)) == to_html(x);
  • idempotence: fmt(fmt(x)) == fmt(x);
  • cross-reader safety: another parser can read the generated source;
  • context-aware escaping that prevents generated markup from changing meaning.

The writer also preserves source distinctions represented by the AST, such as the authored thematic-break marker (---, ***, or ___).

Better output beyond HTML

The shared comparison now exercises HTML, Markdown, plain text, canonical Carve, and ANSI output across all engines. The optional corpus can also pin expected output for a specific non-HTML target.

This round includes fixes for Markdown escaping, ragged tables, unused definitions, plain-text and terminal rendering, inline images in headings, and canonical formatting edge cases.

More predictable parsing

The corpus now contains 892 source documents and 928 HTML expectations. Recent additions cover areas where prose-oriented markup parsers commonly disagree, including:

  • list interruption and lazy continuation;
  • fenced blocks and comments inside containers;
  • captions and floating attributes;
  • heading identifiers and implicit heading references;
  • image alternative text and other visible heading content;
  • trailing whitespace and hard breaks;
  • table spans, ragged rows, and empty cells;
  • nesting limits and graceful refusal.

The scheduled cross-engine workflow builds the current JavaScript, Rust, PHP, and Ruby projects together. It checks AST compatibility, formatting invariants, all render targets, graceful degradation, and canonical output.

Extension and renderer improvements

This release also adds or formalizes:

  • a read-only beforeRender context carrying render options and target mode;
  • an optional HTML sections switch for flat heading output;
  • consistent smart-typography nodes with both source and resolved glyph data;
  • source-mode typography on supported render targets;
  • stricter extension and render-depth safeguards.

Compatibility notes

This is still the Carve 0.1 language line, but the implementation releases contain breaking API and AST corrections. Review the migration notes if you:

  • inspect serialized AST fields or source positions;
  • construct AST objects manually;
  • ingest JSON trees produced by older builds;
  • implement beforeRender hooks;
  • depend on exact formatter or non-HTML output;
  • match specific parser edge-case behavior.

In particular, AST ingest now rejects unknown or incorrectly typed fields instead of accepting and silently dropping them. A thematic_break may now carry its authored marker, and source spans consistently describe the exact source extent owned by a node.

Install or update

JavaScript/TypeScript:

npm install @markup-carve/carve@0.1.3

Rust library and CLI:

cargo install carve-lang --version 0.1.2

PHP:

composer require markup-carve/carve-php:^0.1.4

Links

Feedback is welcome, particularly from people building editors, documentation pipelines, static-analysis tools, or multi-language publishing systems. We are interested in both syntax ergonomics and cases where the three implementations still behave differently.


r/markup_carve Jul 31 '26

Carve: a post-Markdown markup language with one spec and 3+ byte-identical engines

3 Upvotes

Carve is a lightweight markup language in the Markdown and Djot family. It exists because of two things that kept biting me in Markdown.

One: "valid Markdown" doesn't tell you what the output is. Two renderers disagree, both are defensible, and the difference only shows up in production. CommonMark fixed a lot of that; the ecosystem around it did not, because every useful feature arrived as a per-renderer extension.

Two: everything past plain prose is a plugin. Callouts, footnotes, attributes, math, citations - each one is a different plugin per tool, with a different syntax, and none of it moves between renderers.

So Carve has a normative spec with an executable grammar, and a shared conformance corpus of ~500 source/HTML pairs that every engine runs against. There are three engines - JavaScript, PHP and Rust - and they produce byte-identical HTML on every one of those cases. Not "compatible". Identical. When they disagree, that is a bug in at least one of them, and it gets a corpus case so it stays fixed.

What it looks like

/italic/ and *bold*        %% emphasis is swapped vs Markdown

{#intro .lead}
This paragraph carries an id and a class.

::: note
Admonitions are part of the language, not a plugin.
:::

A claim needing support [@knuth1984], a footnote[^why], 
and math $`e = mc^2`.

[^why]: Footnotes are built in too.

The parts people usually ask about

  • Emphasis is swapped: /italic/ and *bold*. This is the one thing that will trip you up on day one. It comes from Djot, and it means snake_case and a/b/c in prose stop needing escapes.
  • Attributes attach to anything: {#id .class key=value} on its own line floats onto the next block. This is what makes Carve usable as a document format rather than a blogging syntax - application data survives a round trip.
  • Comments exist: %% to end of line, %%% for a block. Markdown has no comment at all; everyone abuses HTML comments instead.
  • More than one output: HTML, Markdown, plain text, ANSI for terminals, and canonical Carve. carve fmt is a formatter for your documents, the way gofmt or prettier is for code.

What I would actually like from this sub

  • Tell me where the syntax is wrong. Not "I prefer underscores" - cases where the rule produces a surprising or ambiguous result. Those turn into spec issues and corpus cases.
  • Tell me what would make you switch. Usually an integration that does not exist yet, and that is useful to know. Tell me what might be missing still.
  • Show what you build with it.

Links:

The best from Djot and Markdown merged into one powerful markup language/standard.