├── .gitignore ├── LICENSE ├── README.md ├── code.txt ├── composer.json ├── demo.html ├── images ├── dark.png └── light.png ├── index.php └── src ├── Highlight.php └── theme.json /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /.idea 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 chrysu76 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Prettify 2 | 3 | Creates a syntax highlighted version of the given PHP code. 4 | 5 | ```bash 6 | # PHP 8 7 | composer require ghostff/php_prettify 8 | 9 | # Older PHP version 10 | composer require ghostff/php_prettify:5.4.093021 11 | composer require ghostff/php_prettify:7.0.093021 12 | ``` 13 | 14 | ```php 15 | ', (new Highlight)->render('$name = "foobar"'), ''; 20 | ```` 21 | 22 | #### Highlighting a file 23 | ```php 24 | ', (new Highlight) 29 | ->setTheme('bittr') // Sets code highlight theme. 30 | ->setStyle('body {margin:0;padding:0}') // Append css to default to style. 31 | ->setHighlight(22, ['style' => 'color:red']) // Add html attributes to selected line(tr). 32 | ->showLineNumber(1, false) // Show line number starting from line 1 and prevent selection of line number. 33 | ->render('code.txt', true), 34 | ''; 35 | ``` 36 | 37 | ![alt tag](https://github.com/Ghostff/php_prettify/blob/master/images/dark.png) 38 | -------------------------------------------------------------------------------- /code.txt: -------------------------------------------------------------------------------- 1 | bindings[$abstract]['shared']) && ($counter != 0)) 21 | { 22 | #cast to bool 23 | (bool) $shared = $this->bindings[$abstract]['shared']; 24 | } 25 | else 26 | { 27 | $counter--; 28 | $shared = false; 29 | } 30 | 31 | #function type dictation 32 | self::hash(hash('sha1', 'foobar'), $this->hash()); 33 | return (isset($this->instances[$abstract]) || $shared === true); 34 | } 35 | } 36 | 37 | enum Suit: string { 38 | case Clubs = '♣'; 39 | case Diamonds = '♦'; 40 | case Hearts = '♥'; 41 | case Spades = '♠'; 42 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ghostff/php_prettify", 3 | "description": "Creates a syntax highlighted version of the given PHP code.", 4 | "type": "library", 5 | "license": "MIT", 6 | "autoload": { 7 | "psr-4": { 8 | "ghostff\\Highlight\\": "src" 9 | } 10 | }, 11 | "authors": [ 12 | { 13 | "name": "ghostff", 14 | "email": "frankchris@hotmail.com" 15 | } 16 | ], 17 | "require": { 18 | "php": ">=8.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dayle Rees Colour Scheme Previews 5 | 23 | 24 | 25 |
26 |
default
27 |
28 |
1<?php
2
3namespace Text;
4use PhpPrettify as Php;
5
6class Text extends Namespace\TextProcess implements Php
7{
8    /**
9     * An array of the types that have been resolved.
10     *
11     * @var array
12     */
13    protected $resolved = array();
14
15    public function isShared(string $abstract, int &$counter): bool
16    {
17        self::init(mt_rand(1, 55), parent::__construct(), ROOT_DIR);
18        if (isset($this->bindings[$abstract]['shared']) && ($counter != 0))
19        {
20            #cast to bool
21            (bool) $shared = $this->bindings[$abstract]['shared'];
22        }
23        else
24        {
25            $counter--;
26            $shared = false;
27        }
28
29        #smart function type dictation
30        self::hash(hash('sha1', 'foobar'), $this->hash());
31        return (isset($this->instances[$abstract]) || $shared === true);
32    }
33}
29 |
30 |
31 |
32 |
bittr
33 |
34 |
1<?php
2
3namespace Text;
4use PhpPrettify as Php;
5
6class Text extends Namespace\TextProcess implements Php
7{
8    /**
9     * An array of the types that have been resolved.
10     *
11     * @var array
12     */
13    protected $resolved = array();
14
15    public function isShared(string $abstract, int &$counter): bool
16    {
17        self::init(mt_rand(1, 55), parent::__construct(), ROOT_DIR);
18        if (isset($this->bindings[$abstract]['shared']) && ($counter != 0))
19        {
20            #cast to bool
21            (bool) $shared = $this->bindings[$abstract]['shared'];
22        }
23        else
24        {
25            $counter--;
26            $shared = false;
27        }
28
29        #smart function type dictation
30        self::hash(hash('sha1', 'foobar'), $this->hash());
31        return (isset($this->instances[$abstract]) || $shared === true);
32    }
33}
35 |
36 |
37 |
38 |
dark
39 |
40 |
1<?php
2
3namespace Text;
4use PhpPrettify as Php;
5
6class Text extends Namespace\TextProcess implements Php
7{
8    /**
9     * An array of the types that have been resolved.
10     *
11     * @var array
12     */
13    protected $resolved = array();
14
15    public function isShared(string $abstract, int &$counter): bool
16    {
17        self::init(mt_rand(1, 55), parent::__construct(), ROOT_DIR);
18        if (isset($this->bindings[$abstract]['shared']) && ($counter != 0))
19        {
20            #cast to bool
21            (bool) $shared = $this->bindings[$abstract]['shared'];
22        }
23        else
24        {
25            $counter--;
26            $shared = false;
27        }
28
29        #smart function type dictation
30        self::hash(hash('sha1', 'foobar'), $this->hash());
31        return (isset($this->instances[$abstract]) || $shared === true);
32    }
33}
41 |
42 |
43 |
44 |
owerri
45 |
46 |
1<?php
2
3namespace Text;
4use PhpPrettify as Php;
5
6class Text extends Namespace\TextProcess implements Php
7{
8    /**
9     * An array of the types that have been resolved.
10     *
11     * @var array
12     */
13    protected $resolved = array();
14
15    public function isShared(string $abstract, int &$counter): bool
16    {
17        self::init(mt_rand(1, 55), parent::__construct(), ROOT_DIR);
18        if (isset($this->bindings[$abstract]['shared']) && ($counter != 0))
19        {
20            #cast to bool
21            (bool) $shared = $this->bindings[$abstract]['shared'];
22        }
23        else
24        {
25            $counter--;
26            $shared = false;
27        }
28
29        #smart function type dictation
30        self::hash(hash('sha1', 'foobar'), $this->hash());
31        return (isset($this->instances[$abstract]) || $shared === true);
32    }
33}
47 |
48 |
49 |
50 |
light
51 |
52 |
1<?php
2
3namespace Text;
4use PhpPrettify as Php;
5
6class Text extends Namespace\TextProcess implements Php
7{
8    /**
9     * An array of the types that have been resolved.
10     *
11     * @var array
12     */
13    protected $resolved = array();
14
15    public function isShared(string $abstract, int &$counter): bool
16    {
17        self::init(mt_rand(1, 55), parent::__construct(), ROOT_DIR);
18        if (isset($this->bindings[$abstract]['shared']) && ($counter != 0))
19        {
20            #cast to bool
21            (bool) $shared = $this->bindings[$abstract]['shared'];
22        }
23        else
24        {
25            $counter--;
26            $shared = false;
27        }
28
29        #smart function type dictation
30        self::hash(hash('sha1', 'foobar'), $this->hash());
31        return (isset($this->instances[$abstract]) || $shared === true);
32    }
33}
53 |
54 |
55 |
56 |
steady
57 |
58 |
1<?php
2
3namespace Text;
4use PhpPrettify as Php;
5
6class Text extends Namespace\TextProcess implements Php
7{
8    /**
9     * An array of the types that have been resolved.
10     *
11     * @var array
12     */
13    protected $resolved = array();
14
15    public function isShared(string $abstract, int &$counter): bool
16    {
17        self::init(mt_rand(1, 55), parent::__construct(), ROOT_DIR);
18        if (isset($this->bindings[$abstract]['shared']) && ($counter != 0))
19        {
20            #cast to bool
21            (bool) $shared = $this->bindings[$abstract]['shared'];
22        }
23        else
24        {
25            $counter--;
26            $shared = false;
27        }
28
29        #smart function type dictation
30        self::hash(hash('sha1', 'foobar'), $this->hash());
31        return (isset($this->instances[$abstract]) || $shared === true);
32    }
33}
59 |
60 |
61 |
62 |
imo
63 |
64 |
1<?php
2
3namespace Text;
4use PhpPrettify as Php;
5
6class Text extends Namespace\TextProcess implements Php
7{
8    /**
9     * An array of the types that have been resolved.
10     *
11     * @var array
12     */
13    protected $resolved = array();
14
15    public function isShared(string $abstract, int &$counter): bool
16    {
17        self::init(mt_rand(1, 55), parent::__construct(), ROOT_DIR);
18        if (isset($this->bindings[$abstract]['shared']) && ($counter != 0))
19        {
20            #cast to bool
21            (bool) $shared = $this->bindings[$abstract]['shared'];
22        }
23        else
24        {
25            $counter--;
26            $shared = false;
27        }
28
29        #smart function type dictation
30        self::hash(hash('sha1', 'foobar'), $this->hash());
31        return (isset($this->instances[$abstract]) || $shared === true);
32    }
33}
65 |
66 |
67 |
68 |
yola
69 |
70 |
1<?php
2
3namespace Text;
4use PhpPrettify as Php;
5
6class Text extends Namespace\TextProcess implements Php
7{
8    /**
9     * An array of the types that have been resolved.
10     *
11     * @var array
12     */
13    protected $resolved = array();
14
15    public function isShared(string $abstract, int &$counter): bool
16    {
17        self::init(mt_rand(1, 55), parent::__construct(), ROOT_DIR);
18        if (isset($this->bindings[$abstract]['shared']) && ($counter != 0))
19        {
20            #cast to bool
21            (bool) $shared = $this->bindings[$abstract]['shared'];
22        }
23        else
24        {
25            $counter--;
26            $shared = false;
27        }
28
29        #smart function type dictation
30        self::hash(hash('sha1', 'foobar'), $this->hash());
31        return (isset($this->instances[$abstract]) || $shared === true);
32    }
33}
71 |
72 |
73 |
74 |
git
75 |
76 |
1<?php
2
3namespace Text;
4use PhpPrettify as Php;
5
6class Text extends Namespace\TextProcess implements Php
7{
8    /**
9     * An array of the types that have been resolved.
10     *
11     * @var array
12     */
13    protected $resolved = array();
14
15    public function isShared(string $abstract, int &$counter): bool
16    {
17        self::init(mt_rand(1, 55), parent::__construct(), ROOT_DIR);
18        if (isset($this->bindings[$abstract]['shared']) && ($counter != 0))
19        {
20            #cast to bool
21            (bool) $shared = $this->bindings[$abstract]['shared'];
22        }
23        else
24        {
25            $counter--;
26            $shared = false;
27        }
28
29        #smart function type dictation
30        self::hash(hash('sha1', 'foobar'), $this->hash());
31        return (isset($this->instances[$abstract]) || $shared === true);
32    }
33}
77 |
78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /images/dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ghostff/php_prettify/a0d1b09e279272003f025f0913236591260e8193/images/dark.png -------------------------------------------------------------------------------- /images/light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ghostff/php_prettify/a0d1b09e279272003f025f0913236591260e8193/images/light.png -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | ', 6 | (new ghostff\Highlight\Highlight()) 7 | ->setTheme('bittr') // Sets code highlight theme. 8 | ->setStyle('body {margin:0;padding:0}') // Append css to default to style. 9 | // ->setHighlight(22, ['style' => 'color:red']) // Add html attributes to selected line(tr). 10 | // ->showLineNumber(1, false) // Show line number starting from line 1 and prevent selection of line number. 11 | ->render('code.txt', true), 12 | ''; 13 | 14 | ?> -------------------------------------------------------------------------------- /src/Highlight.php: -------------------------------------------------------------------------------- 1 | \()\b/'; 53 | private string $keywords_ptrn = '/(?\:|\:\<\/span\>)\s*(?:\\:)*(string|bool|array|float|int|callable|void|never)/'; 70 | private string $curly_braces_ptrn = '/[\{\}]/'; 71 | private string $parameter_type_ptrn = '/(?[\$|&])/'; 72 | private string $square_bracket_ptrn = '/\[|\]/'; 73 | private string $multi_line_comment_ptrn = '/\/\*|\*\//'; 74 | 75 | /** 76 | * check and highlight user defined or php pre defined function. 77 | * 78 | * @param string $code 79 | * @return string 80 | */ 81 | private function isFunction(string $code): string 82 | { 83 | return preg_replace_callback('/([n|t]?.?)\b(\w+)(?=\s\(|\()/', function (array $arg): string 84 | { 85 | $back = $arg[1]; 86 | $func = $arg[2]; 87 | if ($back == 'n ' || $back == 't;' || ($back == ':' && $func != 'array')) { 88 | return "{$back}custom_function}\" class=\"custom_function\">{$func}"; 89 | } 90 | elseif (function_exists($func)) { 91 | return "{$back}php_function}\" class=\"php_function\">{$func}"; 92 | } 93 | 94 | return $arg[0]; 95 | }, $code); 96 | } 97 | 98 | /** 99 | * processes supplied text 100 | * 101 | * @param string $code 102 | * @param string|null $file_name 103 | * @param bool $cache 104 | * @return string 105 | */ 106 | private function format(string $code, ?string $file_name, bool $cache): string 107 | { 108 | $code = str_replace( 109 | ['', '\\\\'], 110 | ['PP_PHP_LONG_TAG_OPEN', 'PP_PHP_SHORT_TAG_OPEN', 'PP_PHP_CLOSE_TAG', 'PP_PHP_DOUBLE_BACK_SLASH'], 111 | $code 112 | ); 113 | 114 | $code = htmlspecialchars($code, ENT_NOQUOTES); 115 | $new_code = null; 116 | $start_number = $this->start_line; 117 | $is_MLQ = false; #is_multi_line_quote 118 | $is_MLC = false; #is_multi_line_comment 119 | $QO = false; #quote_opened 120 | $QT = null; #qoute_type 121 | $separator = "\n"; 122 | $token = strtok($code, $separator); 123 | 124 | while ($token !== false) 125 | { 126 | $line = rtrim($token, PHP_EOL); 127 | if ($line == '') { 128 | $line = ' '; 129 | } 130 | 131 | $gui_line_number = $this->show_line_number ? "line_selectable ? '' : ' unselectable="on"') . ">{$start_number}" : ''; 132 | 133 | if (isset($this->highlight[$start_number])) 134 | { 135 | $highlight_attr = ''; 136 | foreach ($this->highlight[$start_number] as $key => $values) { 137 | $highlight_attr .= " {$key}=\"{$values}\""; 138 | } 139 | $gui_highlight = ""; 140 | } 141 | else 142 | { 143 | $gui_highlight = ''; 144 | } 145 | 146 | $new_code .= "{$gui_highlight}{$gui_line_number}"; 147 | if (! $is_MLQ) 148 | { 149 | if ($is_MLC) { 150 | $line = "multi_line_comment}\" class=\"strip multi_line_comment\">{$line}"; 151 | } 152 | 153 | $comment = $this->multi_line_comment; 154 | $line = preg_replace_callback($this->multi_line_comment_ptrn, function(array $matches) use (&$is_MLC, $comment): string { 155 | if ($matches[0] == '*/') { 156 | $is_MLC = false; 157 | return "{$matches[0]}"; 158 | } 159 | 160 | $is_MLC = true; 161 | return "{$matches[0]}"; 162 | }, $line); 163 | } 164 | 165 | if (! $is_MLC) 166 | { 167 | if ($is_MLQ) { 168 | $line = "quote}\" class=\"strip quote\">{$line}"; 169 | } 170 | 171 | #single line comment 172 | $SLC = false; 173 | $line = preg_replace_callback($this->quote_ptrn, function(array $matches) use (&$QO, &$is_MLQ, &$SLC, &$QT): string 174 | { 175 | if ($QO) { 176 | if ($QT == $matches[2]) { 177 | $is_MLQ = false; 178 | $QO = false; 179 | 180 | return "{$matches[0]}"; 181 | } 182 | 183 | return $matches[0]; 184 | } 185 | else { 186 | if ((strpos($matches[1], '//') !== false) || (strpos($matches[1], '#') !== false) || $SLC) { 187 | $SLC = true; 188 | return $matches[0]; 189 | } 190 | 191 | $QO = true; 192 | $QT = $matches[2]; 193 | $is_MLQ = true; 194 | 195 | return "{$matches[1]}quote}\" class=\"strip quote\">{$matches[2]}"; 196 | } 197 | }, $line); 198 | } 199 | 200 | $pattern = [ 201 | $this->operators_ptrn, 202 | $this->number_ptrn, 203 | $this->class_ptrn, 204 | preg_replace('/\s\s+/', '', $this->keywords_ptrn), 205 | $this->function_ptrn, 206 | $this->variable_ptrn, 207 | $this->cast_ptrn, 208 | $this->constant_ptrn, 209 | $this->parenthesis_ptrn, 210 | $this->curly_braces_ptrn, 211 | $this->null_ptrn, 212 | $this->self_ptrn, 213 | $this->parent_ptrn, 214 | $this->bool_ptrn, 215 | $this->attribute_ptrn, 216 | $this->comment_ptrn, 217 | $this->square_bracket_ptrn, 218 | $this->parameter_type_ptrn, 219 | $this->return_type_ptrn, 220 | '/PP_PHP_LONG_TAG_OPEN/', 221 | '/PP_PHP_SHORT_TAG_OPEN/', 222 | '/PP_PHP_CLOSE_TAG/', 223 | '/PP_PHP_DOUBLE_BACK_SLASH/' 224 | ]; 225 | 226 | $replacement = [ 227 | "operators}\" class=\"operators\">\$0", 228 | "number}\" class=\"number\">\$0", 229 | "class}\" class=\"number\">\$0", 230 | "keywords}\" class=\"keyword\">\$0", 231 | "function}\" class=\"function\">\$1", 232 | "variable}\" class=\"variable\">\$0", 233 | "cast}\" class=\"cast\">\$0", 234 | "constant}\" class=\"constant\">\$0", 235 | "parenthesis}\" class=\"parenthesis\">\$0", 236 | "curly_braces}\" class=\"curly_braces\">\$0", 237 | "null}\" class=\"null\">\$0", 238 | "self}\" class=\"self\">\$0", 239 | "parent}\" class=\"parent\">\$0", 240 | "bool}\" class=\"bool\">\$0", 241 | "attribute}\" class=\"attribute\">\$0", 242 | "comment}\" class=\"strip comment\">\$0", 243 | "square_bracket}\" class=\"square_bracket\">\$0", 244 | "parameter_type}\" class=\"parameter_type\">\$0", 245 | "return_type}\" class=\"return_type\">\$0", 246 | "tag_open}\" class=\"tag long\"><?php", 247 | "tag_open}\" class=\"tag short\"><?=", 248 | "tag_close}\" class=\"tag clode\">?>", 249 | '\\\\\\', 250 | ]; 251 | 252 | $line = $this->isFunction($line); 253 | $line = preg_replace($pattern, $replacement, $line); 254 | $new_code .= "{$line}"; 255 | $token = strtok($separator); 256 | $start_number++; 257 | } 258 | 259 | $new_code .= ''; 260 | $new_code = str_replace(['\"', '\\\'', ' '], ['"', '\'', '  '], $new_code); 261 | $pretty = "{$new_code}
"; 262 | 263 | if ($cache) { 264 | $this->cache($file_name, $pretty); 265 | } 266 | 267 | return $pretty; 268 | } 269 | 270 | /** 271 | * caches formatted strings and handles gc 272 | * 273 | * @param string $file_name 274 | * @param string|null $content 275 | * @return string 276 | */ 277 | private function cache(string $file_name, string $content = null): string 278 | { 279 | $file_name = $this->cache_path . DIRECTORY_SEPARATOR . "{$file_name}.cache"; 280 | if ($content == null) { 281 | return is_readable($file_name) ? file_get_contents($file_name) : ''; 282 | } 283 | 284 | if (! is_dir($this->cache_path)) { 285 | mkdir($this->cache_path, 0775, true); 286 | } 287 | 288 | if (is_writable($this->cache_path)) { 289 | file_put_contents($file_name, $content); 290 | } 291 | 292 | return ''; 293 | } 294 | 295 | /** 296 | * @param string $path 297 | * @return $this 298 | */ 299 | public function setCachePath(string $path): Highlight 300 | { 301 | $this->cache_path = $path; 302 | 303 | return $this; 304 | } 305 | 306 | /** 307 | * Sets global styles. (This should always be called after setTheme(if using any)) 308 | * 309 | * @param string $css 310 | * @param bool $override Keep default css or not. 311 | * @return $this 312 | */ 313 | public function setStyle(string $css, bool $override = false): Highlight 314 | { 315 | $this->style = $override ? $css : "{$this->style}{$css}"; 316 | 317 | return $this; 318 | } 319 | 320 | /** 321 | * displays line numbers 322 | * 323 | * @param int $start_line 324 | * @param bool $selectable If line should be selectable. 325 | * @return Highlight 326 | */ 327 | public function showLineNumber(int $start_line = 1, bool $selectable = true): Highlight 328 | { 329 | $this->start_line = $start_line; 330 | $this->line_selectable = $selectable; 331 | $this->show_line_number = true; 332 | 333 | return $this; 334 | } 335 | 336 | 337 | /** 338 | * adds html attributes to line table > tr 339 | * 340 | * @param int $line 341 | * @param array $attributes 342 | * @return Highlight 343 | */ 344 | public function setHighlight(int $line, array $attributes = []): Highlight 345 | { 346 | $this->highlight[$line] = $attributes; 347 | 348 | return $this; 349 | } 350 | 351 | /** 352 | * @param string $name 353 | * @return Highlight 354 | * @throws \Exception 355 | */ 356 | public function setTheme(string $name): Highlight 357 | { 358 | $theme_file = __DIR__ . DIRECTORY_SEPARATOR . 'theme.json'; 359 | if (file_exists($theme_file)) 360 | { 361 | $all_themes = json_decode(file_get_contents($theme_file), true, JSON_THROW_ON_ERROR); 362 | 363 | if (! isset($all_themes[$name])) { 364 | throw new \Exception("\"{$name}\" is not a valid theme name"); 365 | } 366 | 367 | $buildStyle = function (array $styles): string { 368 | $style = ''; 369 | foreach ($styles as $n => $v) { 370 | $style .= "{$n}:{$v};"; 371 | } 372 | return $style; 373 | }; 374 | 375 | foreach ($all_themes[$name] as $name => &$value) { 376 | $this->{$name} = is_array($value) ? $buildStyle($value) : $value; 377 | } 378 | } 379 | 380 | return $this; 381 | } 382 | 383 | /** 384 | * check if code is a file or a string then renders accordingly 385 | * 386 | * @param string $code 387 | * @param bool $is_file 388 | * @param bool $cache 389 | * @return string 390 | */ 391 | public function render(string $code, bool $is_file = false, bool $cache = false): string 392 | { 393 | if ($is_file) 394 | { 395 | if ($cache && ($cached = $this->cache($code)) !== null) { 396 | return $cached; 397 | } 398 | 399 | return $this->format(file_get_contents($code), $code, $cache); 400 | } 401 | 402 | return $this->format($code, null, $cache); 403 | } 404 | 405 | } 406 | -------------------------------------------------------------------------------- /src/theme.json: -------------------------------------------------------------------------------- 1 | { 2 | "bittr": { 3 | "style": ".CH-php{background-color:#2b303b;color:white}.CH-php .strip span{color:inherit !important;all:initial !important;all:unset !important}td[unselectable]{ user-select:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none; }", 4 | "keywords": { "color": "#26A6A6", "font-weight": "bold"}, 5 | "cast": { "color": "#038C8C" }, 6 | "null": { "color": "#FF5D38" }, 7 | "bool": { "color": "#FF5D38" }, 8 | "self": { "color": "#FF5D38" }, 9 | "quote": { "color": "#BCD42A" }, 10 | "class": { "color": "#dee3ec" }, 11 | "parent": { "color": "#FF5D38" }, 12 | "number": { "color": "#A4AC21" }, 13 | "attribute": { "color": "#FFFFFF", "opacity": "0.5" }, 14 | "comment": { "color": "#6e7a94", "font-style": "italic" }, 15 | "tag_open": { "color": "#F00000" }, 16 | "function": { "color": "#FFFFFF" }, 17 | "variable": { "color": "#aec2e0" }, 18 | "constant": { "color": "#8C4D03" }, 19 | "tag_close": { "color": "#F00000" }, 20 | "operators": { "color": "#26A6A6" }, 21 | "semi_colon": { "color": "#dee3ec" }, 22 | "parenthesis": { "color": "#FFFFFF" }, 23 | "return_type": { "color": "#FE648A" }, 24 | "php_function": { "color": "#6367A7" }, 25 | "curly_braces": { "color": "#dee3ec" }, 26 | "parameter_type": { "color": "#E3093F" }, 27 | "square_bracket": { "color": "#F46164" }, 28 | "custom_function": { "color": "#DAEFA2" }, 29 | "multi_line_comment": { "color": "#6e7a94", "font-style": "italic" } 30 | }, 31 | 32 | "dark": { 33 | "style": ".CH-php{background-color:#000000;color:white}.CH-php .strip span{color:inherit !important;all:initial !important;all:unset !important}td[unselectable]{ user-select:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none; }", 34 | "keywords": { "color": "#1CC3E8"}, 35 | "cast": { "color": "#038C8C" }, 36 | "null": { "color": "#68C244" }, 37 | "bool": { "color": "#68C244" }, 38 | "self": { "color": "#68C244" }, 39 | "quote": { "color": "#BCD42A" }, 40 | "class": { "color": "#dee3ec" }, 41 | "parent": { "color": "#FF5D38" }, 42 | "number": { "color": "#A4AC21" }, 43 | "attribute": { "color": "#FFFFFF", "opacity": "0.5" }, 44 | "comment": { "color": "#494B4D", "font-style": "italic" }, 45 | "tag_open": { "color": "#F00000" }, 46 | "function": { "color": "#FFFFFF" }, 47 | "variable": { "color": "#aec2e0" }, 48 | "constant": { "color": "#8C4D03" }, 49 | "tag_close": { "color": "#F00000" }, 50 | "operators": { "color": "#F08D24" }, 51 | "semi_colon": { "color": "#dee3ec" }, 52 | "parenthesis": { "color": "#FFFFFF" }, 53 | "return_type": { "color": "#FE648A" }, 54 | "php_function": { "color": "#6367A7" }, 55 | "curly_braces": { "color": "#dee3ec" }, 56 | "parameter_type": { "color": "#E3093F" }, 57 | "square_bracket": { "color": "#F46164" }, 58 | "custom_function": { "color": "#DAEFA2" }, 59 | "multi_line_comment": { "color": "#494B4D", "font-style": "italic" } 60 | }, 61 | 62 | 63 | "owerri": { 64 | "style": ".CH-php{background-color:#2E2B2C;color:white}.CH-php .strip span{color:inherit !important;all:initial !important;all:unset !important}td[unselectable]{ user-select:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none; }", 65 | "keywords": { "color": "#C491C4"}, 66 | "cast": { "color": "#038C8C" }, 67 | "null": { "color": "#ED1153" }, 68 | "bool": { "color": "#ED1153" }, 69 | "self": { "color": "#ED1153" }, 70 | "quote": { "color": "#B866FA" }, 71 | "class": { "color": "#dee3ec" }, 72 | "parent": { "color": "#FF5D38" }, 73 | "number": { "color": "#A4AC21" }, 74 | "attribute": { "color": "#FFFFFF", "opacity": "0.5" }, 75 | "comment": { "color": "#696363", "font-style": "italic" }, 76 | "tag_open": { "color": "#F00000" }, 77 | "function": { "color": "#FFFFFF" }, 78 | "variable": { "color": "#dee3ec" }, 79 | "constant": { "color": "#8C4D03" }, 80 | "tag_close": { "color": "#F00000" }, 81 | "operators": { "color": "#ED1153" }, 82 | "semi_colon": { "color": "#dee3ec" }, 83 | "parenthesis": { "color": "#FFFFFF" }, 84 | "return_type": { "color": "#FE648A" }, 85 | "php_function": { "color": "#6367A7" }, 86 | "curly_braces": { "color": "#dee3ec" }, 87 | "parameter_type": { "color": "#E3093F" }, 88 | "square_bracket": { "color": "#F46164" }, 89 | "custom_function": { "color": "#DAEFA2" }, 90 | "multi_line_comment": { "color": "#696363", "font-style": "italic" } 91 | }, 92 | 93 | "light": { 94 | "style": ".CH-php{background-color:#FFFFFF;color:black}.CH-php .strip span{color:inherit !important;all:initial !important;all:unset !important}td[unselectable]{ user-select:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none; }", 95 | "keywords": { "color": "#4ea1df"}, 96 | "cast": { "color": "#038C8C" }, 97 | "null": { "color": "#f66153" }, 98 | "bool": { "color": "#f66153" }, 99 | "self": { "color": "#f66153" }, 100 | "quote": { "color": "#4ea1df" }, 101 | "class": { "color": "#000000" }, 102 | "parent": { "color": "#FF5D38" }, 103 | "number": { "color": "#A4AC21" }, 104 | "attribute": { "color": "#000000", "opacity": "0.5" }, 105 | "comment": { "color": "#bbbbbb", "font-style": "italic" }, 106 | "tag_open": { "color": "#F00000" }, 107 | "function": { "color": "#555555" }, 108 | "variable": { "color": "#555555" }, 109 | "constant": { "color": "#8C4D03" }, 110 | "tag_close": { "color": "#F00000" }, 111 | "operators": { "color": "#ED1153" }, 112 | "semi_colon": { "color": "#555555" }, 113 | "parenthesis": { "color": "#555555" }, 114 | "return_type": { "color": "#FE648A" }, 115 | "php_function": { "color": "#6367A7" }, 116 | "curly_braces": { "color": "#555555" }, 117 | "parameter_type": { "color": "#E3093F" }, 118 | "square_bracket": { "color": "#F46164" }, 119 | "custom_function": { "color": "#808dd3" }, 120 | "multi_line_comment": { "color": "#bbbbbb", "font-style": "italic" } 121 | }, 122 | 123 | "steady": { 124 | "style": ".CH-php{background-color:#36312C;color:#EBD1B7}.CH-php .strip span{color:inherit !important;all:initial !important;all:unset !important}td[unselectable]{ user-select:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none; }", 125 | "keywords": { "color": "#95CC5E"}, 126 | "cast": { "color": "#038C8C" }, 127 | "null": { "color": "#DB784D" }, 128 | "bool": { "color": "#DB784D" }, 129 | "self": { "color": "#DB784D" }, 130 | "quote": { "color": "#F8BB39" }, 131 | "class": { "color": "#EBD1B7" }, 132 | "parent": { "color": "#FF5D38" }, 133 | "number": { "color": "#A4AC21" }, 134 | "attribute": { "color": "#FFFFFF", "opacity": "0.5" }, 135 | "comment": { "color": "#bbbbbb", "font-style": "italic" }, 136 | "tag_open": { "color": "#F00000" }, 137 | "function": { "color": "#EBD1B7" }, 138 | "variable": { "color": "#EBD1B7" }, 139 | "constant": { "color": "#8C4D03" }, 140 | "tag_close": { "color": "#F00000" }, 141 | "operators": { "color": "#ED1153" }, 142 | "semi_colon": { "color": "#555555" }, 143 | "parenthesis": { "color": "#EBD1B7" }, 144 | "return_type": { "color": "#FE648A" }, 145 | "php_function": { "color": "#6367A7" }, 146 | "curly_braces": { "color": "#EBD1B7" }, 147 | "parameter_type": { "color": "#E3093F" }, 148 | "square_bracket": { "color": "#F46164" }, 149 | "custom_function": { "color": "#60A365" }, 150 | "multi_line_comment": { "color": "#bbbbbb", "font-style": "italic" } 151 | }, 152 | 153 | 154 | "imo": { 155 | "style": ".CH-php{background-color:#FFFFFF;color:#555555}.CH-php .strip span{color:inherit !important;all:initial !important;all:unset !important}td[unselectable]{ user-select:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none; }", 156 | "keywords": { "color": "#445588"}, 157 | "cast": { "color": "#038C8C" }, 158 | "null": { "color": "#008080" }, 159 | "bool": { "color": "#008080" }, 160 | "self": { "color": "#008080" }, 161 | "quote": { "color": "#DD1144" }, 162 | "class": { "color": "#555555" }, 163 | "parent": { "color": "#FF5D38" }, 164 | "number": { "color": "#A4AC21" }, 165 | "attribute": { "color": "#000000", "opacity": "0.5" }, 166 | "comment": { "color": "#bbbbbb", "font-style": "italic" }, 167 | "tag_open": { "color": "#F00000" }, 168 | "function": { "color": "#555555" }, 169 | "variable": { "color": "#008080" }, 170 | "constant": { "color": "#8C4D03" }, 171 | "tag_close": { "color": "#F00000" }, 172 | "operators": { "color": "#ED1153" }, 173 | "semi_colon": { "color": "#555555" }, 174 | "parenthesis": { "color": "#555555" }, 175 | "return_type": { "color": "#FE648A" }, 176 | "php_function": { "color": "#6367A7" }, 177 | "curly_braces": { "color": "#555555" }, 178 | "parameter_type": { "color": "#E3093F" }, 179 | "square_bracket": { "color": "#F46164" }, 180 | "custom_function": { "color": "#445588" }, 181 | "multi_line_comment": { "color": "#bbbbbb", "font-style": "italic" } 182 | }, 183 | 184 | "yola": { 185 | "style": ".CH-php{background-color:#131c26;color:white}.CH-php .strip span{color:inherit !important;all:initial !important;all:unset !important}td[unselectable]{ user-select:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none; }", 186 | "keywords": { "color": "#88B7FF"}, 187 | "cast": { "color": "#C71FC1" }, 188 | "null": { "color": "#FFFFFF" }, 189 | "bool": { "color": "#1591D7" }, 190 | "self": { "color": "#88B7FF" }, 191 | "quote": { "color": "#6db679" }, 192 | "class": { "color": "#FFFFFF" }, 193 | "parent": { "color": "#FFFFFF" }, 194 | "number": { "color": "#FF4F51" }, 195 | "attribute": { "color": "#FFFFFF", "opacity": "0.5" }, 196 | "comment": { "color": "#B7B7B7", "font-style": "italic" }, 197 | "tag_open": { "color": "#EF62FC" }, 198 | "function": { "color": "#88B7FF" }, 199 | "variable": { "color": "#DB97E4" }, 200 | "constant": { "color": "#FFFFFF" }, 201 | "tag_close": { "color": "#EF62FC" }, 202 | "operators": { "color": "#FFFFFF" }, 203 | "semi_colon": { "color": "#555555" }, 204 | "parenthesis": { "color": "#FFFFFF" }, 205 | "return_type": { "color": "#FE648A" }, 206 | "php_function": { "color": "#6367A7" }, 207 | "curly_braces": { "color": "#FFFFFF" }, 208 | "parameter_type": { "color": "#f2368a" }, 209 | "square_bracket": { "color": "#FFFFFF" }, 210 | "custom_function": { "color": "#FFC13B" }, 211 | "multi_line_comment": { "color": "#B7B7B7", "font-style": "italic" } 212 | }, 213 | 214 | "git": { 215 | "style": ".CH-php{background-color:#FFFFFF;color:#555555}.CH-php .strip span{color:inherit !important;all:initial !important;all:unset !important}td[unselectable]{ user-select:none;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none; }", 216 | "keywords": { "color": "#a71d5d"}, 217 | "cast": { "color": "#C71FC1" }, 218 | "null": { "color": "#FFFFFF" }, 219 | "bool": { "color": "#1591D7" }, 220 | "self": { "color": "#5555555" }, 221 | "quote": { "color": "#183691" }, 222 | "class": { "color": "#795da3" }, 223 | "parent": { "color": "#555555" }, 224 | "number": { "color": "#FF4F51" }, 225 | "attribute": { "color": "#000000", "opacity": "0.5" }, 226 | "comment": { "color": "#969896", "font-style": "italic" }, 227 | "tag_open": { "color": "#555555" }, 228 | "function": { "color": "#a71d5d" }, 229 | "variable": { "color": "#555555" }, 230 | "constant": { "color": "#0086b3" }, 231 | "tag_close": { "color": "#555555" }, 232 | "operators": { "color": "#a71d5d" }, 233 | "semi_colon": { "color": "#555555" }, 234 | "parenthesis": { "color": "#555555" }, 235 | "return_type": { "color": "#0086b3" }, 236 | "php_function": { "color": "#0086b3" }, 237 | "curly_braces": { "color": "#555555" }, 238 | "parameter_type": { "color": "#0086b3" }, 239 | "square_bracket": { "color": "#555555" }, 240 | "custom_function": { "color": "#795da3" }, 241 | "multi_line_comment": { "color": "#969896", "font-style": "italic" } 242 | } 243 | } 244 | 245 | 246 | 247 | 248 | --------------------------------------------------------------------------------