Technology8 min read

Docs that grow up: what Carve does after the first draft

By · Published by Everything Blog

In short

Syntax and Formatting**: Carve ensures that Markdown files are formatted correctly, including syntax highlighting, tables, and code blocks. **Source-to-Source Conversion**: Carve converts Markdown files to other formats (e.g., HTML, PDF) and vice versa, maintaining the formatting and structure. **Multiple Authors**: The guide includes three authors, ensuring that the documentation is reviewed and updated by multiple contributors.

Key points

  • **Syntax and Formatting**: Carve ensures that Markdown files are formatted correctly, inc…: **Syntax and Formatting**: Carve ensures that Markdown files are formatted correctly, including syntax highlighting, tables, and code blocks.
  • **Source-to-Source Conversion**: Carve converts Markdown files to other formats (e.g., HT…: **Source-to-Source Conversion**: Carve converts Markdown files to other formats (e.g., HTML, PDF) and vice versa, maintaining the formatting and structure.
  • **Multiple Authors**: The guide includes three authors, ensuring that the documentation i…: **Multiple Authors**: The guide includes three authors, ensuring that the documentation is reviewed and updated by multiple contributors.

Sources checked by our analysis pipeline: 1

The first Carve articles covered the syntax, tables with merged cells, numbered figures and citations, safe rendering and one source for many outputs, what survives a Pandoc conversion and moving an existing Markdown file over. This time, the guide has thirty steps and three authors. Its installation section appears in other files, and the same source has to produce a Markdown README.

If you write how-to guides

Code inside a numbered step, without re-indenting it

In CommonMark, the fence and its code lines have to be indented to the list item’s content column. Paste the fence flush left and it falls outside the step.

In Carve, a +

on its own line attaches the next block to the item above it. The code keeps its own indentation:

. Create the configuration file.

+

```js

export default {

server: { port: 3000 },

}

```

. Start the server.

Live, on this page:

- Create the configuration file.

export default {server: { port: 3000 },}

- Start the server.

.

numbers the steps for you, so inserting a step never means renumbering the rest. carve fmt

rewrites the +

form into an indented list; the flush-left form is useful while writing and pasting.

Show a code change as a diff, and keep the syntax highlighting

A ```diff

block in Markdown loses the language: your JavaScript turns into green and red plain text. In Carve the language stays on the fence and the diff is an attribute:

{.diff}

```js

const icon = document.querySelector('.file-entry > .icon')

- icon.classList.add('icon-file-text')

+ icon.classList.remove('icon-file-text')

```

Live:

const icon = document.querySelector('.file-entry > .icon')

- icon.classList.add('icon-file-text')

+ icon.classList.remove('icon-file-text')

Readers see JavaScript, with the removed and added lines marked.

Explain a line of code without a comment in the code

“Line 2 retries the request” stops being true the moment someone adds a line above it. Callouts tie the explanation to the line itself:

```php

$client = new Client($token); <1>

$client->retry(3)->send($payload); <2>

```

<1> The token comes from your account settings.

<2> Retries only on network errors, never on a 4xx response.

The markers render as numbered badges and the notes below explain them. Without the callout extension, the code stays a code block and the notes appear as ordinary text.

One install step for npm, Composer and Cargo

Docs that serve several ecosystems often repeat the same install step three times. The code-group extension puts the commands in tabs:

::: code-group

```bash [npm]

npm install @markup-carve/carve

```

```bash [Composer]

composer require markup-carve/carve-php

```

```bash [Cargo]

cargo add carve-lang

```

:::

Live, click the tabs:

npm install @markup-carve/carve

composer require markup-carve/carve-php

cargo add carve-lang

A renderer without code-group support shows all three blocks in order. The commands remain available in plain HTML and print.

Paste a spreadsheet export as a table

If a table is maintained in a spreadsheet, you don’t have to retype it as a pipe table. Export it as CSV, paste it into a fence and put {table}

above it:

{table}

```csv

Plan,Seats,Price per month

Starter,1,"$0"

Team,10,"$49, billed yearly"

```

Live:

Plan,Seats,Price per month

Starter,1,"$0"

Team,10,"$49, billed yearly"

The first row becomes the header, and quoted fields may contain commas and line breaks. Tab-separated data works the same way with a tsv

fence. Without {table}

the fence stays an ordinary code block. A fence with broken quoting also stays code, so a bad export shows up as raw CSV instead of a table with shifted columns.

If the export already lives in data/plans.csv

, keep it there and include it as CSV:

{table}

{{ data/plans.csv @code:csv }}

If a team maintains the docs

Write the requirements section once

Requirements appear in the install guide, the upgrade guide and the README. Copying them into each file invites drift. An include keeps one source:

# Installing on Linux

{{ shared/requirements.crv }}

## Next steps

{{ shared/first-run.crv @shift:1 }}

@shift:1

moves the included headings down one level, so the same file fits under a #

in one guide and a ##

in another. When you need a single file to hand over, carve flatten

expands every include into one self-contained document.

Includes need a processor with access to the files. Without one, the directive stays unexpanded; carve --safe

also disables expansion.

A merge that understands lists

The base requirements say PHP 8.2 and Composer 2. On separate branches, one colleague bumps PHP and the other bumps Composer:

Version x:

## Requirements

- PHP 8.3 or later

- Composer 2

- A database

Version y:

## Requirements

- PHP 8.2 or later

- Composer 2.7

- A database

Git sees two changes to neighboring lines and reports a conflict. carve merge base.crv ours.crv theirs.crv

compares the document structure instead: two different list items changed, so it combines them without a conflict:

## Requirements

- PHP 8.3 or later

- Composer 2.7

- A database

When both sides change the same item, it stops and names the conflict. With a small wrapper script it works as a Git merge driver for *.crv

files.

carve merge

also ignores rewrapping. If one colleague reflows a paragraph to 80 columns while another fixes a word in it, Git reports a conflict on those lines. carve merge

keeps the fixed word without a conflict.

Let an assistant edit the docs, and check its work

An assistant that edits a doc by rewriting the whole file can change lines nobody asked it to touch. The Carve MCP server gives it tools that edit one block at a time:

carve_reviewed_edit

replaces the exact bytes of one block or heading section and leaves every other byte untouched. It shows the patch before writing, checks local links and includes afterwards, and returns an undo receipt.carve_undo_reviewed_edit

restores the original bytes from that receipt.carve_review_workspace

checks a whole docs folder: cross-file links, include targets and line ranges.

The same review runs in CI without an assistant:

$ carve-mcp-review --root docs --strict

It exits non-zero on a broken link or include, and its JSON output lists every file it read.

Review comments that live in the text

Reviewing prose in a pull request means commenting on line numbers that move with every push. Carve has review markup in the sentence itself:

The import runs {-every night-}{+every hour+} and

keeps {~30~>90~} days of history.{#Check the retention number with ops.#}

Live:

The import runs every nightevery hour and keeps 3090 days of history.Check the retention number with ops.

Deletions, insertions, substitutions and comments render as marked-up changes for the reviewer, and accepting them is an ordinary edit. Private author notes that should never render use %%

instead.

If one document goes to several places

Know what each output format dropped

Markdown export can silently lose features from a Carve document. Carve reports those losses, and --strict-losses

turns one into a failed build:

Choose a plan:

a. Starter

b. Team

c. Enterprise

$ carve render --markdown --strict-losses plans.crv

plans.crv:3:1 list-style-dropped - Wrote a lower-alpha ordered list as decimal while rendering markdown

plans.crv: 1 render loss

Markdown has no lettered lists, so the build fails and says why, instead of shipping “1. 2. 3.” where the source said “a. b. c.”. If the loss is acceptable for that target, --allow-loss list-style-dropped

lets it through on purpose.

Merged table cells get the same check. Markdown tables have no spans, and the flattened table still looks like a normal one:

| Plan | Storage | Support |

|---------|---------|---------|

| Starter | 1 GB | Email |

| Team | 10 GB | < |

$ carve render --markdown --strict-losses plans-table.crv

plans-table.crv:4:12 table-span-flattened - Flattened a spanning table cell into separate cells

plans-table.crv: 1 render loss

In HTML, Team’s “10 GB” spans the Storage and Support columns. The Markdown output puts “10 GB” under Storage and leaves Support empty, and the build fails with that report.

Slides from the same markup

reveal-carve turns a Carve file into a reveal.js deck. Everything above works on slides, plus a few things only a talk needs: %% toc

writes the agenda with per-slide minutes, the PDF and the handout unfold tabs and spoilers so nothing hides behind a click on paper, and reveal-carve pdf deck.crv

exports from the command line.

Also there when you need it

[Ctrl]{kbd}

for keyboard keys, as in Ctrl + S, and[JSON]{abbr="JavaScript Object Notation"}

for abbreviations: hover over JSON.- A fenced blockquote for long quotations, without

>

on every line. - Line blocks for addresses and verse, where each line break matters.

- Unknown extensions degrade to their content: a site without a diagram renderer still shows the diagram source.

- Editors: the document converts to and from ProseMirror/Tiptap, and HTML imports report what did not carry over.

Try it

Paste the self-contained syntax samples into the playground and compare output formats. Choose the JavaScript engine for the code-group example. For includes, save the files locally and run carve render --include-root . guide.crv

. Use the same CLI for carve merge

; reviewed edits need the Carve MCP server.

Leave a Reply

Original source: www.dereuromark.de

Technology