diff --git a/docs/3-packages/04-markdown.md b/docs/3-packages/04-markdown.md
index 66e2d6807..d91cdecd0 100644
--- a/docs/3-packages/04-markdown.md
+++ b/docs/3-packages/04-markdown.md
@@ -3,7 +3,7 @@ title: Markdown
description: "Fast and extensible Markdown in PHP"
---
-`tempest/markdown` is a Markdown parser written in PHP. It's designed to be fast and extensible and has a bunch of additional features built-in like code highlighting, responsive images, tables, and frontmatter support.
+`tempest/markdown` is a Markdown parser for server-side Markdown parsing with PHP. It's designed to be fast and extensible, and has a bunch of extended Markdown features built-in like code highlighting, table and div support, responsive images, and frontmatter support.
## Quickstart
@@ -24,7 +24,9 @@ echo $parsed->frontMatter['title'];
echo $parsed->html;
```
-## Integrations
+## Extended features
+
+One thing that sets `tempest/markdown` apart from other Markdown implementations is that it comes with a bunch of extended features built-in.
### Code highlighting
@@ -41,7 +43,7 @@ $markdown = new Markdown(
);
```
-Language definitions work in both inline and pre code blocks:
+Language definitions work for both inline and multiline code blocks:
This is an inline PHP codeblock: `{php}echo "Hello";`
@@ -63,9 +65,28 @@ $markdown = new Markdown(
);
```
+### Frontmatter
+
+Add frontmatter like you're used to with other Markdown parsers
+
+```md
+---
+title: Markdown
+description: "Fast and extensible Markdown in PHP"
+---
+
+`tempest/markdown` is a Markdown parser for server-side Markdown parsing with PHP. It's designed to be fast and extensible, and has a bunch of extended Markdown features built-in like code highlighting, table and div support, responsive images, and frontmatter support.
+```
+
+```php
+$parsed = $markdown->parse($contents);
+
+echo $parsed->frontmatter['title'];
+```
+
### Responsive images
-`tempest/markdown` has support for responsive images powered by [`tempest/responsive-image`](/docs/packages/responsive-image). You'll need to configure the responsive image factory before being able to use it.
+`tempest/markdown` has support for responsive images powered by [`tempest/responsive-image`](/docs/packages/responsive-image). You'll need to configure the responsive image factory to enable this feature.
```php
use Tempest\Markdown\Markdown;
@@ -82,6 +103,207 @@ $markdown = new Markdown(
);
```
+When enabled, `tempest/markdown` will generate different versions of the same image, and add them as `srcset` entries in the generate HTML.
+
+```md
+
+```
+
+```html
+
+```
+
+Read more about responsive images [here](/docs/packages/responsive-image).
+
+### Tables
+
+Add tables like you're used to with other Markdown parsers.
+
+```
+| Package | Memory | Time to parse |
+|------------------------|----------|---------------|
+| tempest/markdown | 6.826mb | 13.273ms |
+| league/commonmark | 21.114mb | 56.993ms |
+| michelf/php-markdown | 7.343mb | 23.215ms |
+| erusev/parsedown-extra | 8.485mb | 15.163ms |
+```
+
+```html
+
+
+
+
+ | Package |
+ Memory |
+ Time to parse |
+
+
+
+
+ | tempest/markdown |
+ 6.826mb |
+ 13.273ms |
+
+
+
+
+
+
+```
+
+### Divs
+
+Use `:::` to create divs with optional classes:
+
+```
+:::alert
+This is an important message!
+:::
+```
+
+```html
+
+ This is an important message!
+
+```
+
+### Strikethrough
+
+Use `~~` to strikethrough text:
+
+```
+~~This was wrong~~
+```
+
+```html
+This was wrong
+```
+
+### Target blank links
+
+Prepend `*` to a link's URI to open the link in a new tab:
+
+```
+[Click me](*https://stitcher.io)
+```
+
+```html
+Click me
+```
+
+## Adding custom features
+
+`tempest/markdown` is meant to be extended. Adding custom parser rules is done in two steps: first you provide a `LexerRule`, this is a class that determines when your custom parsing logic should be triggered. Next you'll use a `Token` to render your selected Markdown code in any way you'd like.
+
+Let's work with an example. Say you want to add support for including custom HTML snippets. It could look something like this:
+
+```
+Hello world
+
+{{ snippets/call-to-action.html }}
+```
+
+The first step to adding this new feature is detecting when we run into our custom `{{ }}` syntax. This is done with a `LexerRule`. Let's call our implementation `SnippetRule`:
+
+```php
+use Tempest\Markdown\Lexer;
+use Tempest\Markdown\Rule;
+use Tempest\Markdown\Token;
+
+final readonly class SnippetRule implements Rule
+{
+ public function shouldLex(Lexer $lexer): bool
+ {
+ // Our rule takes effect as soon as we run into `{{`
+
+ return $lexer->comesNext('{{', length: 2);
+ }
+
+ public function lex(Lexer $lexer): ?Token
+ {
+ // We'll consume all { characters
+ $lexer->consumeWhile('{');
+
+ // Then we'll consume and store the snippet path itself until we encounter the closing } characters
+ $snippet = $lexer->consumeUntil('}');
+
+ // Then we'll consume the closing } characters
+ $lexer->consumeWhile('}');
+
+ // Finally, we return a token with the snippet
+ return new SnippetToken(trim($snippet));
+ }
+}
+```
+
+:::info
+For performance reasons, it's best to explcitly add the `{:hl-property:length:}` parameter to the `{:hl-property:comesNext:}` call. It's not required, but it will make parsing faster. If possible, also try not to rely on regex within your lexer rules, as it may become a performance bottleneck.
+:::
+
+So that's our rule implementation: we consumed our custom `{{ path }}` syntax, and created a token with that path. Let's take a look at the token implementation next.
+
+The token's responsibility is to parse the content into HTML.
+
+```php
+use Tempest\Markdown\Parser;
+use Tempest\Markdown\Token;
+use Tempest\View\Exceptions\ViewNotFound;
+use Tempest\View\ViewRenderer;
+use function Tempest\Container\get;
+
+final readonly class SnippetToken implements Token
+{
+ public function __construct(
+ public string $path,
+ ) {}
+
+ public function parse(Parser $parser): string
+ {
+ // Of course, you should add validation here depending on your use case
+
+ return file_get_contents($this->path);
+ }
+}
+```
+
+Finally, you should add your custom rule to the Markdown parser:
+
+```php
+use Tempest\Markdown\Markdown;
+
+$markdown = new Markdown();
+
+$markdown->prependRules(
+ new SnippetRule(),
+);
+```
+
+If needed, you can fully customize the Markdown parser by overwriting all rules:
+
+```php
+$markdown = new Markdown()->withRules(
+ new NewLineRule(),
+ new FrontMatterRule(),
+ new HeadingRule(),
+ new QuoteRule(),
+ new PreRule(),
+ new DivRule(),
+ new ThinRulerRule(),
+ new ThickRulerRule(),
+ new ListRule(),
+ new OrderedListRule(),
+ new TableRule(),
+ new HtmlRule(),
+ new ParagraphRule(),
+);
+```
+
+This way you have full control over how the parser works. For more inspiration, you can look at the [rules that come built-in with the package](https://github.com/tempestphp/markdown/tree/main/src/LexerRules).
+
## Performance
This package began as a challenge to make a more performant Markdown parser in pure PHP. The primary performance gain is from not relying on regex but instead using a simple lexer to tokenize Markdown files and convert them to HTML.
@@ -90,7 +312,7 @@ Benchmarks are included in this repo and can be run with `composer bench` after
| Package | Memory | Time to parse |
|------------------------|----------|---------------|
-| tempest/markdown | 5.944mb | 6.281ms |
+| tempest/markdown | 6.826mb | 13.273ms |
| league/commonmark | 21.114mb | 56.993ms |
| michelf/php-markdown | 7.343mb | 23.215ms |
| erusev/parsedown-extra | 8.485mb | 15.163ms |