phiki/phiki

Syntax highlighting using TextMate grammars in PHP.

v0.2.9 2024-10-19 17:15 UTC

README

Phiki

Phiki is a syntax highlighter written in PHP. It uses TextMate grammar files and Visual Studio Code themes to generate syntax highlighted code for the web and terminal.

Installation

Install Phiki via Composer:

composer require phiki/phiki

Getting Started

The fastest way to get started is with the codeToHtml() method.

use Phiki\Phiki;
use Phiki\Grammar\Grammar;
use Phiki\Theme\Theme;

$phiki = new Phiki();

$html = $phiki->codeToHtml(
    <<<'PHP'
    echo "Hello, world!";
    PHP,
    Grammar::Php,
    Theme::GithubDark,
);

This method takes in the code you want to highlight, the target language, as well as the theme you want to use. It then returns the generated HTML as a string.

Note

All of Phiki's styling is applied using inline style attributes, so there's no need to add any CSS to your project.

Supported Languages

Phiki ships with 200+ grammars and 50+ themes. To provide a clean developer experience, you can find all supported grammars and themes when using the Phiki\Grammar\Grammar and Phiki\Theme\Theme enums.

These files are auto-generated when pulling in grammar and theme files from remote repositories so are always up-to-date.

CommonMark Integration

Phiki provides a convenient extension for the excellent league/commonmark package so that you can start using it on your blog or documentation site with very little effort.

All you need to do is register the extension through a CommonMark Environment object.

use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\MarkdownConverter;
use Phiki\CommonMark\PhikiExtension;

$environment = new Environment;
$environment
    ->addExtension(new CommonMarkCoreExtension)
    ->addExtension(new PhikiExtension('github-dark'));

$converter = new MarkdownConverter($environment);
$output = $converter->convert(<<<'MD'
    ```html
    <p>Hello, world!</p>
    ```
    MD);

Laravel

If you're using Laravel's Str::markdown() or str()->markdown() methods, you can use the same CommonMark extension by passing it through to the method.

use Phiki\CommonMark\PhikiExtension;

Str::markdown('...', extensions: [
    new PhikiExtension('github-dark'),
]); 

Using custom languages and themes

To use a language or theme that Phiki doesn't support, you need to register it with a GrammarRepository or ThemeRepository.

This can be done by building a custom Environment object and telling Phiki to use this instead of the default one.

use Phiki\Environment\Environment;

$environment = Environment::default();

// Register a custom language.
$environment
    ->getGrammarRepository()
    ->register('my-language', __DIR__ . '/../path/to/grammar.json');

$environment
    ->getThemeRepository()
    ->register('my-theme', __DIR__ . '/../path/to/theme.json');

$phiki = new Phiki($environment);

$phiki->codeToHtml('...', 'my-language', 'my-theme');

Terminal Output

Phiki has support for generating output designed for use in the terminal. This is available through the codeToTerminal() method which accepts the same parameters as the codeToHtml() method.

echo $phiki->codeToTerminal('echo "Hello, world"!', Grammar::Php, Theme::GithubDark);

Line numbers

Each line has its own <span> element with a data-line attribute, so you can use CSS to display line numbers in the generated HTML. The benefit to this approach is that the text isn't selectable so you code snippets can be highlighted the same as before.

pre code span[data-line]::before {
    content: attr(data-line);
    display: inline-block;
    width: 1.7rem;
    margin-right: 1rem;
    color: #666;
    text-align: right;
}

These styles are of course just a guide. You can change the colors and sizing to your own taste.

Known Limitations & Implementation Notes

The implementation of this package is inspired by existing art, namely vscode-textmate. The main reason that implementing a TextMate-based syntax highlighter in PHP is a complex task is down to the fact that vscode-textmate (and the TextMate editor) uses the Oniguruma engine for handling regular expressions.

PHP uses the PCRE2 engine which doesn't have support for all of Oniguruma's features. To reduce the risk of broken RegExs, Phiki performs a series of transformations with solid success rates:

  • Properly escape unescaped forward-slashes (/).
  • Translate \h and \H to PCRE equivalents.
  • Translate \p{xx} to PCRE-compatible versions.
  • Escape invalid leading range characters ([-...]).
  • Properly escape unescaped close-set characters (]).
  • Translate unsupported Unicode escape sequences (\uXXXX).

One of the biggest differences between PCRE2 and Oniguruma is that Oniguruma has support for "variable-length lookbehinds". Variable-length lookbehinds, both positive and negative, are normally created when a quantifier such as + or * is used inside of the lookbehind.

PCRE2 does not support these types of lookbehinds and they're essentially impossible to translate into PCRE2-compatible equivalents. In these cases, Phiki also performs a series of manual "patches" on grammar files to get RegExs as close as possible to the intended output.

These patches are not perfect – there is still a chance of running into errors in your application when highlighting code! If you do encounter an error with a message like the one below, please check the Issues page or create a new issue with information about the grammar / language you're highlighting and a reproduction case.

preg_match(): Compilation failed: length of lookbehind assertion is not limited at offset...

Credits