Skip to content

Commit e2b3e3a

Browse files
Initial commit
0 parents  commit e2b3e3a

35 files changed

+1073
-0
lines changed

.gitattributes

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Text
2+
*.php text eol=lf
3+
*.md text eol=lf
4+
*.html text eol=lf
5+
*.xml text eol=lf
6+
*.yml text eol=lf
7+
*.json text eol=lf
8+
*.gitattributes text eol=lf
9+
*.gitignore text eol=lf

.github/workflows/ci.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
env:
10+
PHP_VERSION: 8.3
11+
12+
jobs:
13+
lint:
14+
name: Lint with parallel-lint and PHPCS
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
20+
- name: Setup PHP
21+
uses: shivammathur/setup-php@v2
22+
with:
23+
php-version: ${{ env.PHP_VERSION }}
24+
tools: composer
25+
26+
- name: Install composer dependencies
27+
run: composer install
28+
29+
- name: Run parallel-lint
30+
run: vendor/bin/parallel-lint . --exclude vendor
31+
32+
- name: Run phpcs
33+
run: vendor/bin/phpcs -p -s
34+
35+
test-highlight:
36+
name: "PHPUnit"
37+
runs-on: ubuntu-latest
38+
strategy:
39+
fail-fast: false
40+
matrix:
41+
php: [8.3, 8.4]
42+
commonmark: ["^2.7"]
43+
python: [3.11, 3.12, 3.13]
44+
pygments: ["2.17.*", "2.18.*", "2.19.*"]
45+
46+
steps:
47+
- name: Checkout
48+
uses: actions/checkout@v4
49+
50+
- name: Setup Python
51+
uses: "actions/setup-python@v5"
52+
with:
53+
python-version: "${{ matrix.python }}"
54+
55+
- name: Setup PHP
56+
uses: shivammathur/setup-php@v2
57+
with:
58+
php-version: ${{ matrix.php }}
59+
tools: composer
60+
61+
- name: Set league/commonmark version
62+
run: composer require "league/commonmark:${{ matrix.commonmark }}"
63+
64+
- name: Install composer dependencies
65+
run: composer install
66+
67+
- name: Report python version
68+
run: python3 --version
69+
70+
- name: Install pip
71+
run: sudo apt-get install -y python3-pip
72+
73+
- name: Install pygments
74+
run: pip install Pygments==${{ matrix.pygments }} --break-system-packages
75+
76+
- name: Run phpunit
77+
run: vendor/bin/phpunit

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Composer
2+
composer.lock
3+
vendor
4+
5+
# Tests
6+
.phpunit.result.cache
7+
8+
# Code coverage reports
9+
html-coverage

.phpcs.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0"?>
2+
<ruleset>
3+
<rule ref="./vendor/danielescherzer/common-phpcs/src"/>
4+
<file>.</file>
5+
<arg name="extensions" value="php"/>
6+
<arg name="encoding" value="UTF-8"/>
7+
</ruleset>

README.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# CommonMark Extension Pygment Highlighter
2+
3+
The `PygmentHighlighter` extension adds support for using pygments to style
4+
blocks of code in Markdown documents.
5+
6+
## Installation
7+
8+
This extension can be installed from packagist via composer:
9+
10+
```bash
11+
composer require danielescherzer/commonmark-ext-pygments-highlighter
12+
```
13+
14+
It depends on
15+
16+
* `league/commonmark` (version 2.7 or above; all lower versions have security
17+
issues)
18+
* `ramsey/pygments` (version 3.0 or above)
19+
20+
Separately (not enforced via composer) you need to have python and the pygments
21+
python library installed. The extension is currently tested against
22+
23+
* Python 3.11, 3.12, and 3.13
24+
* Pygments 2.17, 2.18, and 2.19
25+
26+
The pygments command is assumed to be at `pygmentize` (in the PATH); if this is
27+
not the case configure the correct path in the extension setup, see the
28+
configuration section below.
29+
30+
## Syntax and results
31+
32+
Sample Markdown input:
33+
34+
````markdown
35+
```php
36+
<?php
37+
class User {
38+
private int $id;
39+
private string $name;
40+
41+
public function __construct( int $id, string $name ) {
42+
$this->id = $id;
43+
$this->name = $name;
44+
}
45+
}
46+
```
47+
````
48+
49+
Result:
50+
51+
```html
52+
<div class="pygments-highlight"><div class="highlight"><pre><span></span><span class="cp">&lt;?php</span>
53+
<span class="k">class</span> <span class="nc">User</span> <span class="p">{</span>
54+
<span class="k">private</span> <span class="nx">int</span> <span class="nv">$id</span><span class="p">;</span>
55+
<span class="k">private</span> <span class="nx">string</span> <span class="nv">$name</span><span class="p">;</span>
56+
57+
<span class="k">public</span> <span class="k">function</span> <span class="fm">__construct</span><span class="p">(</span> <span class="nx">int</span> <span class="nv">$id</span><span class="p">,</span> <span class="nx">string</span> <span class="nv">$name</span> <span class="p">)</span> <span class="p">{</span>
58+
<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">id</span> <span class="o">=</span> <span class="nv">$id</span><span class="p">;</span>
59+
<span class="nv">$this</span><span class="o">-&gt;</span><span class="na">name</span> <span class="o">=</span> <span class="nv">$name</span><span class="p">;</span>
60+
<span class="p">}</span>
61+
<span class="p">}</span>
62+
</pre></div>
63+
</div>
64+
```
65+
66+
## Usage
67+
68+
Configure your `Environment` as usual and simply add an instance of the
69+
`PygmentsHighlighterExtension`:
70+
71+
```php
72+
<?php
73+
74+
use DanielEScherzer\CommonMarkPygmentsHighlighter\PygmentsHighlighterExtension;
75+
use League\CommonMark\Environment\Environment;
76+
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
77+
use League\CommonMark\MarkdownConverter;
78+
79+
// These are the defaults for the extension, you can change them
80+
$config = [
81+
'pygments_highlight' => [
82+
'pygmentize_path' => null, // Use `pygmentize` from PATH
83+
'on_exception' => 'warn',
84+
],
85+
];
86+
87+
// Configure the Environment with the desired extensions
88+
$environment = new Environment( $config );
89+
$environment->addExtension( new CommonMarkCoreExtension() );
90+
$environment->addExtension( new PygmentsHighlighterExtension() );
91+
92+
// And convert your markdown
93+
$converter = new MarkdownConverter($environment);
94+
echo $converter->convert("```php\n<?php\necho 'testing...';\n```");
95+
```
96+
97+
## Configuration
98+
99+
This extension can be configured by providing a `pygments_highlight` array
100+
with the following options (defaults shown above):
101+
102+
### `pygmentize_path`
103+
104+
The path to the pygmentize command, or null to use the default (`pygmentize`).
105+
106+
### `on_exception`
107+
108+
If the attempt to use the pygmentize command fails, this value controls the
109+
behavior of the rendererer. By default, it is set to 'warn' - it can be:
110+
111+
* 'warn' - show a warning and render the code with the CommonMark-provided
112+
default output
113+
* 'ignore' - render the code with the CommonMark-provided default output
114+
* 'throw' - rethrow the exception with the failure details
115+
116+
## Adding styles
117+
118+
This extension just adds the various classes for the output to be made
119+
colorful, you still need to add CSS targetting the code. The `ramsey/pygments`
120+
library offers a method to get an entire stylesheet for any of the pygments
121+
built-in styles, or you can build your own styling.
122+
123+
All of the highlighted code output from this extension will be within a
124+
div with the `pygments-highlight` class, so your CSS rules can be scoped to
125+
only elements within the `.pygments-highlight` selector.

composer.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"name": "danielescherzer/commonmark-ext-pygments-highlighter",
3+
"description": "CommonMark extension for code highlighting with Pygments",
4+
"type": "commonmark-extension",
5+
"authors": [
6+
{
7+
"name": "Daniel E Scherzer",
8+
"homepage": "https://github.com/DanielEScherzer"
9+
}
10+
],
11+
"license": "MIT",
12+
"require": {
13+
"php": "^8.3 || ^8.4",
14+
"league/commonmark": "^2.7",
15+
"ramsey/pygments": "^3.0"
16+
},
17+
"require-dev": {
18+
"danielescherzer/common-phpcs": "0.0.2",
19+
"phpunit/phpunit": "~12.0",
20+
"php-parallel-lint/php-parallel-lint": "^1.4",
21+
"symfony/yaml": "6.4.* || 7.2.* || 7.3.*"
22+
},
23+
"autoload": {
24+
"psr-4": {
25+
"DanielEScherzer\\CommonMarkPygmentsHighlighter\\": "src/"
26+
}
27+
},
28+
"scripts": {
29+
"parallel-lint": "parallel-lint . --exclude vendor",
30+
"phpcs": "phpcs -p -s",
31+
"phpunit": "php -d extension=pcov.so -d pcov.enabled=1 -d pcov.directory=. vendor/bin/phpunit",
32+
"phpunit:update-expected": "TESTS_UPDATE_EXPECTED=1 php vendor/bin/phpunit",
33+
"lint": [
34+
"@parallel-lint",
35+
"@phpcs"
36+
],
37+
"test": [
38+
"@phpunit",
39+
"@lint"
40+
]
41+
},
42+
"config": {
43+
"allow-plugins": {
44+
"dealerdirect/phpcodesniffer-composer-installer": true
45+
}
46+
}
47+
}

phpunit.xml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd"
5+
backupGlobals="true"
6+
colors="false"
7+
beStrictAboutOutputDuringTests="true"
8+
displayDetailsOnTestsThatTriggerDeprecations="true"
9+
displayDetailsOnTestsThatTriggerErrors="true"
10+
displayDetailsOnTestsThatTriggerNotices="true"
11+
displayDetailsOnTestsThatTriggerWarnings="true"
12+
displayDetailsOnPhpunitDeprecations="true"
13+
requireCoverageMetadata="true"
14+
>
15+
<testsuites>
16+
<testsuite name="commonmark-ext-pygments-highlighter">
17+
<directory>./tests</directory>
18+
</testsuite>
19+
</testsuites>
20+
<source>
21+
<include>
22+
<directory>./src</directory>
23+
</include>
24+
</source>
25+
<coverage includeUncoveredFiles="true">
26+
<report>
27+
<html outputDirectory="html-coverage" />
28+
</report>
29+
</coverage>
30+
</phpunit>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
declare( strict_types = 1 );
3+
4+
namespace DanielEScherzer\CommonMarkPygmentsHighlighter;
5+
6+
use League\CommonMark\Environment\EnvironmentBuilderInterface;
7+
use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
8+
use League\CommonMark\Extension\ConfigurableExtensionInterface;
9+
use League\Config\ConfigurationBuilderInterface;
10+
use Nette\Schema\Expect;
11+
12+
class PygmentsHighlighterExtension implements ConfigurableExtensionInterface {
13+
14+
public function configureSchema(
15+
ConfigurationBuilderInterface $builder
16+
): void {
17+
$builder->addSchema( 'pygments_highlight', Expect::structure( [
18+
'pygmentize_path' => Expect::anyOf(
19+
Expect::string(),
20+
Expect::null()
21+
)->default( null ),
22+
'on_exception' => Expect::anyOf(
23+
PygmentsHighlighterRenderer::ON_EXCEPTION_IGNORE,
24+
PygmentsHighlighterRenderer::ON_EXCEPTION_WARN,
25+
PygmentsHighlighterRenderer::ON_EXCEPTION_THROW
26+
)->default( PygmentsHighlighterRenderer::ON_EXCEPTION_WARN ),
27+
] ) );
28+
}
29+
30+
public function register( EnvironmentBuilderInterface $environment ): void {
31+
$environment->addRenderer(
32+
FencedCode::class,
33+
new PygmentsHighlighterRenderer(),
34+
// Higher priority than CommonMark
35+
10
36+
);
37+
}
38+
}

0 commit comments

Comments
 (0)