markup-carve/carve-php

PHP parser for Carve, a human-centered lightweight markup language derived from djot-php.

Maintainers

Package info

github.com/markup-carve/carve-php

Homepage

pkg:composer/markup-carve/carve-php

Fund package maintenance!

dereuromark

Statistics

Installs: 246

Dependents: 1

Suggesters: 0

Stars: 0

Open Issues: 3

dev-main 2026-06-14 20:33 UTC

README

PHP parser and renderer for Carve, a post-Markdown lightweight markup language with visual mnemonics and human-centered design.

Status

Carve's syntax is implemented - the delimiter swaps, table changes, captions, and custom extension syntax - and passes the shared Carve spec corpus.

Origins

Carve-PHP is a hard fork of djot-php by the PHP Collective. The fork preserves the architecture, AST, renderer pipeline, profiles, and extensions, and replaces Djot's syntax rules with Carve's. The MIT license carries over; copyright lines remain in LICENSE.

For the original Djot implementation, use php-collective/djot instead.

Installation

composer require markup-carve/carve-php

Usage

use Carve\CarveConverter;

$converter = new CarveConverter();
$html = $converter->toHtml('# Hello /Carve/');

Besides HTML, the same AST renders to Markdown, plain text, and ANSI via the CarveConverter::markdown(), ::plainText(), and ::ansi() factories:

$markdown = CarveConverter::markdown()->convert('# Hello /Carve/');
$ansi = CarveConverter::ansi()->convert('# Hello /Carve/');

CLI

The package ships a bin/carve executable that reads Carve from a file or stdin and writes the rendered output to stdout. HTML is the default; pass a format flag for another output:

bin/carve README.crv > README.html   # HTML (default)
bin/carve --markdown README.crv      # Markdown
bin/carve --plain README.crv         # plain text
bin/carve --ansi README.crv          # ANSI-colored terminal text
echo '# Hello' | bin/carve           # render from stdin

--html / --markdown (--md) / --plain (--plain-text) / --ansi select the format. -o FILE writes to a file; -w/--warnings and --strict report parse warnings (exit 1 under --strict); -x/--xhtml and -s/--safe apply to HTML output only. Run bin/carve --help for the full list.

Sandbox

Try this implementation live in the Carve sandbox - explore syntax and extensions, inspect output, and share snippets via pastebin-style links. It also powers the wp-carve WordPress plugin.

Extension Matchers

Carve-PHP supports parse-stage extension matchers alongside render hooks and document transforms. Matchers are tried only where core syntax declines, so core parsing always wins first.

use Carve\CarveConverter;
use Carve\Node\Inline\Text;
use Carve\Parser\MatcherContext;

$converter = new CarveConverter();

$converter->getParser()->getInlineParser()->addInlineMatcher(
    function (string $text, int $pos, MatcherContext $ctx): ?array {
        if (!preg_match('/\G\{\{([a-z]+)\}\}/', $text, $m, 0, $pos)) {
            return null;
        }

        return ['node' => new Text('VAR:' . $m[1]), 'end' => $pos + strlen($m[0])];
    },
);

MatcherContext exposes definition tables (getReference(), hasFootnote(), getAbbreviation()) and recursive parse helpers (parseInlines(), parseBlocks()). Matchers run by descending priority, then registration order. addInlinePattern() and addBlockPattern() remain available as regex sugar over the same matcher contract.

The normative extension contract lives in carve/docs/extensions.md. Extensions bundled with this package (such as PlusBulletExtension) are documented in docs/extensions.md.

License

MIT — see LICENSE.