Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git
M git/GitPacks.php
321321
    }
322322
323
    $compressed = fread( $fileHandle, self::MAX_READ );
324
    $delta      = @gzuncompress( $compressed ) ?: '';
323
    $inflator = inflate_init( ZLIB_ENCODING_DEFLATE );
325324
326
    $result = $this->applyDelta( $base, $delta );
325
    if( $inflator === false ) {
326
      return false;
327
    }
327328
328
    $chunkSize = 8192;
329
    $length    = strlen( $result );
329
    // 0: source size, 1: target size, 2: opcodes
330
    $headerState = 0;
331
    $buffer      = '';
330332
331
    for( $i = 0; $i < $length; $i += $chunkSize ) {
332
      $callback( substr( $result, $i, $chunkSize ) );
333
    while( !feof( $fileHandle ) ) {
334
      // Read small chunks to prevent memory spikes
335
      $chunk = fread( $fileHandle, 8192 );
336
337
      if( $chunk === false || $chunk === '' ) {
338
        break;
339
      }
340
341
      $data = @inflate_add( $inflator, $chunk );
342
343
      if( $data === false ) {
344
        break;
345
      }
346
347
      $buffer .= $data;
348
349
      // Process the buffer
350
      while( true ) {
351
        $bufLen = strlen( $buffer );
352
353
        if( $bufLen === 0 ) {
354
          break;
355
        }
356
357
        if( $headerState < 2 ) {
358
          $pos = 0;
359
360
          while( $pos < $bufLen && (ord( $buffer[$pos] ) & 128) ) {
361
            $pos++;
362
          }
363
364
          if( $pos === $bufLen && (ord( $buffer[$pos - 1] ) & 128) ) {
365
            break;
366
          }
367
368
          $pos++;
369
          $buffer = substr( $buffer, $pos );
370
          $headerState++;
371
          continue;
372
        }
373
374
        $opcode = ord( $buffer[0] );
375
376
        if( $opcode & 128 ) {
377
          $needed = 1;
378
          if( $opcode & 0x01 ) { $needed++; }
379
          if( $opcode & 0x02 ) { $needed++; }
380
          if( $opcode & 0x04 ) { $needed++; }
381
          if( $opcode & 0x08 ) { $needed++; }
382
          if( $opcode & 0x10 ) { $needed++; }
383
          if( $opcode & 0x20 ) { $needed++; }
384
          if( $opcode & 0x40 ) { $needed++; }
385
386
          if( $bufLen < $needed ) {
387
            break;
388
          }
389
390
          $off = 0;
391
          $len = 0;
392
          $p   = 1;
393
394
          if( $opcode & 0x01 ) { $off |= ord( $buffer[$p++] ); }
395
          if( $opcode & 0x02 ) { $off |= ord( $buffer[$p++] ) << 8; }
396
          if( $opcode & 0x04 ) { $off |= ord( $buffer[$p++] ) << 16; }
397
          if( $opcode & 0x08 ) { $off |= ord( $buffer[$p++] ) << 24; }
398
399
          if( $opcode & 0x10 ) { $len |= ord( $buffer[$p++] ); }
400
          if( $opcode & 0x20 ) { $len |= ord( $buffer[$p++] ) << 8; }
401
          if( $opcode & 0x40 ) { $len |= ord( $buffer[$p++] ) << 16; }
402
403
          if( $len === 0 ) { $len = 0x10000; }
404
405
          $callback( substr( $base, $off, $len ) );
406
          $buffer = substr( $buffer, $needed );
407
408
        } else {
409
          $len = $opcode & 127;
410
411
          if( $bufLen < 1 + $len ) {
412
            break;
413
          }
414
415
          $callback( substr( $buffer, 1, $len ) );
416
          $buffer = substr( $buffer, 1 + $len );
417
        }
418
      }
419
420
      if( inflate_get_status( $inflator ) === ZLIB_STREAM_END ) {
421
        break;
422
      }
333423
    }
334424
335425
    return true;
336426
  }
337427
338
  private function streamDecompression( $fileHandle, callable $callback ): bool {
428
  private function streamDecompression(
429
    $fileHandle,
430
    callable $callback
431
  ): bool {
339432
    $inflator = inflate_init( ZLIB_ENCODING_DEFLATE );
340433
M pages/FilePage.php
44
55
class FilePage extends BasePage {
6
  private const MAX_HIGHLIGHT_SIZE = 65536;
7
  private const MAX_DISPLAY_SIZE = 524288;
8
69
  private $currentRepo;
710
  private $git;
...
8487
      if( !$file->renderMedia( $renderer, $rawUrl ) ) {
8588
        if( $file->isText() ) {
86
          if( $size > 524288 ) {
89
          if( $size > self::MAX_DISPLAY_SIZE ) {
8790
            ob_start();
8891
            $file->renderSize( $renderer );
...
100103
            } );
101104
102
            echo '<div class="blob-content"><pre class="blob-code">' .
103
                 $file->highlight( $renderer, $content ) . '</pre></div>';
105
            if( $size > self::MAX_HIGHLIGHT_SIZE ) {
106
              echo '<div class="blob-content"><pre class="blob-code">' .
107
                   htmlspecialchars( $content ) . '</pre></div>';
108
            } else {
109
              echo '<div class="blob-content"><pre class="blob-code">' .
110
                   $file->highlight( $renderer, $content ) . '</pre></div>';
111
            }
104112
          }
105113
        } else {
M render/Highlighter.php
44
class Highlighter {
55
  private string $content;
6
  private string $lang;
6
  private string $language;
77
  private array $rules;
8
9
  public function __construct( string $filename, string $content, string $mediaType ) {
10
    $this->content = $content;
118
12
    $this->lang = $this->detectLanguage( $mediaType, $filename );
13
    $this->rules = LanguageDefinitions::get( $this->lang ) ?? [];
9
  public function __construct(
10
    string $filename,
11
    string $content,
12
    string $mediaType
13
  ) {
14
    $this->content  = $content;
15
    $this->language = $this->detectLanguage( $mediaType, $filename );
16
    $this->rules    = LanguageDefinitions::get( $this->language ) ?? [];
1417
  }
1518
1619
  public function render(): string {
17
    if( empty( $this->rules ) ) {
18
      return htmlspecialchars( $this->content );
19
    }
20
    $result = htmlspecialchars( $this->content );
2021
21
    $patterns = [];
22
    if( !empty( $this->rules ) ) {
23
      $patterns = [];
2224
23
    foreach( $this->rules as $name => $pattern ) {
24
      $delim = $pattern[0];
25
      $inner = substr( $pattern, 1, strrpos( $pattern, $delim ) - 1 );
26
      $inner = str_replace( '~', '\~', $inner );
25
      foreach( $this->rules as $name => $pattern ) {
26
        $delimiter = $pattern[0];
27
        $inner     = substr(
28
          $pattern,
29
          1,
30
          strrpos( $pattern, $delimiter ) - 1
31
        );
32
        $inner     = str_replace( '~', '\~', $inner );
2733
28
      $patterns[] = "(?P<{$name}>{$inner})";
29
    }
34
        $patterns[] = "(?P<{$name}>{$inner})";
35
      }
3036
31
    if( !in_array( $this->lang, ['markdown', 'rmd'] ) ) {
32
      $patterns[] = "(?P<punctuation>[\\{\\}\\(\\)\\[\\]\\;\\,])";
33
    }
37
      if( !in_array( $this->language, ['markdown', 'rmd'] ) ) {
38
        $patterns[] = "(?P<punctuation>[\\{\\}\\(\\)\\[\\]\\;\\,])";
39
      }
3440
35
    $patterns[] = "(?P<any>[\s\S])";
36
    $combined = '~' . implode( '|', $patterns ) . '~msu';
41
      $patterns[] = "(?P<any>[\s\S])";
42
      $combined   = '~' . implode( '|', $patterns ) . '~msu';
3743
38
    $result = preg_replace_callback( $combined, function( $matches ) {
39
      foreach( $matches as $key => $value ) {
40
        if( !is_numeric( $key ) && $value !== '' ) {
41
          if( $key === 'any' ) {
42
            return htmlspecialchars( $value );
43
          }
44
      $processed = preg_replace_callback( $combined, function( $matches ) {
45
        $output = htmlspecialchars( $matches[0] );
4446
45
          if( $key === 'string_interp' ) {
46
            return $this->renderInterpolatedString( $value );
47
          }
47
        foreach( $matches as $key => $value ) {
48
          if( !is_numeric( $key ) && $value !== '' ) {
49
            if( $key === 'any' ) {
50
              $output = htmlspecialchars( $value );
51
            } elseif( $key === 'string_interp' ) {
52
              $output = $this->renderInterpolatedString( $value );
53
            } elseif( $key === 'math' ) {
54
              $output = $this->renderMath( $value );
55
            } else {
56
              $output = $this->wrap( $value, 'hl-' . $key );
57
            }
4858
49
          if( $key === 'math' ) {
50
            return $this->renderMath( $value );
59
            break;
5160
          }
52
53
          return '<span class="hl-' . $key . '">' . htmlspecialchars( $value ) . '</span>';
5461
        }
55
      }
5662
57
      return htmlspecialchars( $matches[0] );
58
    }, $this->content );
63
        return $output;
64
      }, $this->content );
5965
60
    return $result ?? htmlspecialchars( $this->content );
66
      if( $processed !== null ) {
67
        $result = $processed;
68
      }
69
    }
70
71
    return $result;
6172
  }
6273
6374
  private function renderInterpolatedString( string $content ): string {
6475
    $pattern = '/(\$\{[a-zA-Z0-9_]+\}|\$[a-zA-Z0-9_]+)/';
65
    $parts   = preg_split( $pattern, $content, -1, PREG_SPLIT_DELIM_CAPTURE );
66
    $output  = '<span class="hl-string">';
67
68
    foreach( $parts as $part ) {
69
      if( $part === '' ) continue;
70
71
      if( str_starts_with( $part, '${' ) && str_ends_with( $part, '}' ) ) {
72
        $inner = substr( $part, 2, -1 );
73
        $output .= '<span class="hl-interp-punct">${</span>';
74
        $output .= '<span class="hl-variable">' . htmlspecialchars( $inner ) . '</span>';
75
        $output .= '<span class="hl-interp-punct">}</span>';
76
      } elseif( str_starts_with( $part, '$' ) && strlen( $part ) > 1 ) {
77
         $output .= '<span class="hl-interp-punct">$</span>';
78
         $output .= '<span class="hl-variable">' . htmlspecialchars( substr( $part, 1 ) ) . '</span>';
79
      } else {
80
        $output .= htmlspecialchars( $part );
81
      }
82
    }
8376
84
    $output .= '</span>';
77
    return $this->processSegments( $content, $pattern, function( $part ) {
78
        $out = htmlspecialchars( $part );
8579
86
    return $output;
80
        if( str_starts_with( $part, '${' ) && str_ends_with( $part, '}' ) ) {
81
            $inner = substr( $part, 2, -1 );
82
            $out   = $this->wrap( '${', 'hl-interp-punct', false ) .
83
                     $this->wrap( $inner, 'hl-variable' ) .
84
                     $this->wrap( '}', 'hl-interp-punct', false );
85
        } elseif( str_starts_with( $part, '$' ) && strlen( $part ) > 1 ) {
86
            $inner = substr( $part, 1 );
87
            $out   = $this->wrap( '$', 'hl-interp-punct', false ) .
88
                     $this->wrap( $inner, 'hl-variable' );
89
        } else {
90
            $out = $this->wrap( $part, 'hl-string' );
91
        }
92
        return $out;
93
    });
8794
  }
8895
8996
  private function renderMath( string $content ): string {
90
    $parts = preg_split( '/(`[^`]+`)/', $content, -1, PREG_SPLIT_DELIM_CAPTURE );
97
    return $this->processSegments( $content, '/(`[^`]+`)/', function( $part ) {
98
        if( str_starts_with( $part, '`' ) && str_ends_with( $part, '`' ) ) {
99
            return $this->wrap( $part, 'hl-function' );
100
        }
101
        return $this->wrap( $part, 'hl-math' );
102
    });
103
  }
104
105
  private function processSegments(
106
    string $content,
107
    string $pattern,
108
    callable $callback
109
  ): string {
110
    $parts  = preg_split( $pattern, $content, -1, PREG_SPLIT_DELIM_CAPTURE );
91111
    $output = '';
92112
93113
    foreach( $parts as $part ) {
94
      if( $part === '' ) continue;
95
96
      if( str_starts_with( $part, '`' ) && str_ends_with( $part, '`' ) ) {
97
        $output .= '<span class="hl-function">' . htmlspecialchars( $part ) . '</span>';
98
      } else {
99
        $output .= '<span class="hl-math">' . htmlspecialchars( $part ) . '</span>';
114
      if( $part !== '' ) {
115
        $output .= $callback( $part );
100116
      }
101117
    }
102118
103119
    return $output;
104120
  }
105121
106
  private function detectLanguage( string $mediaType, string $filename ): string {
107
    $lang = match( $mediaType ) {
108
      'text/x-php', 'application/x-php', 'application/x-httpd-php' => 'php',
109
      'text/html' => 'html',
110
      'text/css' => 'css',
111
      'application/javascript', 'text/javascript', 'text/x-javascript' => 'javascript',
112
      'application/json', 'text/json', 'application/x-json' => 'json',
113
      'application/xml', 'text/xml', 'image/svg+xml' => 'xml',
114
      'text/x-shellscript', 'application/x-sh' => 'bash',
115
      'text/x-c', 'text/x-csrc' => 'c',
116
      'text/x-c++src', 'text/x-c++', 'text/x-cpp' => 'cpp',
117
      'text/x-java', 'text/x-java-source', 'application/java-archive' => 'java',
118
      'text/x-python', 'application/x-python-code' => 'python',
119
      'text/x-ruby', 'application/x-ruby' => 'ruby',
120
      'text/x-go', 'text/go' => 'go',
121
      'text/rust', 'text/x-rust' => 'rust',
122
      'text/x-lua', 'text/lua' => 'lua',
123
      'text/markdown', 'text/x-markdown' => 'markdown',
124
      'text/x-r', 'text/x-r-source', 'application/R' => 'r',
125
      'application/sql', 'text/sql', 'text/x-sql' => 'sql',
126
      'text/yaml', 'text/x-yaml', 'application/yaml' => 'yaml',
127
      'application/typescript', 'text/typescript' => 'typescript',
128
      'text/x-gradle' => 'gradle',
129
      'text/x-tex', 'application/x-tex' => 'tex',
130
      default => null
122
  private function wrap(
123
    string $content,
124
    string $className,
125
    bool $escape = true
126
  ): string {
127
    $safeContent = $escape ? htmlspecialchars( $content ) : $content;
128
    return '<span class="' . $className . '">' . $safeContent . '</span>';
129
  }
130
131
  private function detectLanguage(
132
    string $mediaType,
133
    string $filename
134
  ): string {
135
    $basename  = basename( $filename );
136
    $extension = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
137
    $language  = null;
138
139
    $language = match( $basename ) {
140
      'Containerfile',
141
      'Dockerfile'    => 'containerfile',
142
      'Makefile'      => 'makefile',
143
      'Jenkinsfile'   => 'groovy',
144
      default         => null
131145
    };
132146
133
    if( $lang !== null ) {
134
      return $lang;
147
    if( $language === null ) {
148
      $language = match( $extension ) {
149
        'php', 'phtml', 'php8', 'php7' => 'php',
150
        'c', 'h'                       => 'c',
151
        'cpp', 'hpp', 'cc', 'cxx'      => 'cpp',
152
        'cs', 'csx'                    => 'csharp',
153
        'java'                         => 'java',
154
        'kt', 'kts'                    => 'kotlin',
155
        'scala', 'sc'                  => 'scala',
156
        'groovy', 'gvy'                => 'groovy',
157
        'js', 'jsx', 'mjs'             => 'javascript',
158
        'ts', 'tsx'                    => 'typescript',
159
        'dart'                         => 'dart',
160
        'swift'                        => 'swift',
161
        'go'                           => 'go',
162
        'rs'                           => 'rust',
163
        'py', 'pyw'                    => 'python',
164
        'rb', 'erb'                    => 'ruby',
165
        'pl', 'pm', 't'                => 'perl',
166
        'lua'                          => 'lua',
167
        'sh', 'bash', 'zsh'            => 'bash',
168
        'ps1', 'psm1', 'psd1'          => 'powershell',
169
        'bat', 'cmd'                   => 'batch',
170
        'md', 'markdown'               => 'markdown',
171
        'rmd'                          => 'rmd',
172
        'r'                            => 'r',
173
        'xml', 'svg'                   => 'xml',
174
        'html', 'htm'                  => 'html',
175
        'css'                          => 'css',
176
        'json', 'lock'                 => 'json',
177
        'sql'                          => 'sql',
178
        'yaml', 'yml'                  => 'yaml',
179
        'gradle'                       => 'gradle',
180
        'tex', 'sty', 'cls', 'ltx'     => 'tex',
181
        'properties', 'prop'           => 'properties',
182
        'ini', 'cfg', 'conf'           => 'ini',
183
        'toml'                         => 'toml',
184
        'dockerfile'                   => 'dockerfile',
185
        'mk', 'mak'                    => 'makefile',
186
        'diff', 'patch'                => 'diff',
187
        default                        => null
188
      };
135189
    }
136190
137
    $ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
191
    if( $language === null ) {
192
       $language = match( $mediaType ) {
193
        'text/x-php', 'application/x-php',
194
        'application/x-httpd-php'           => 'php',
195
        'text/html'                         => 'html',
196
        'text/css'                          => 'css',
197
        'application/javascript',
198
        'text/javascript',
199
        'text/x-javascript'                 => 'javascript',
200
        'application/json', 'text/json',
201
        'application/x-json'                => 'json',
202
        'application/xml', 'text/xml',
203
        'image/svg+xml'                     => 'xml',
204
        'text/x-shellscript',
205
        'application/x-sh'                  => 'bash',
206
        'text/x-c', 'text/x-csrc'           => 'c',
207
        'text/x-c++src', 'text/x-c++',
208
        'text/x-cpp'                        => 'cpp',
209
        'text/x-csharp'                     => 'csharp',
210
        'text/x-java',
211
        'text/x-java-source',
212
        'application/java-archive'          => 'java',
213
        'text/x-kotlin'                     => 'kotlin',
214
        'text/x-scala'                      => 'scala',
215
        'text/x-swift'                      => 'swift',
216
        'text/x-python',
217
        'application/x-python-code'         => 'python',
218
        'text/x-ruby', 'application/x-ruby' => 'ruby',
219
        'text/x-perl', 'application/x-perl' => 'perl',
220
        'text/x-go', 'text/go'              => 'go',
221
        'text/rust', 'text/x-rust'          => 'rust',
222
        'text/x-lua', 'text/lua'            => 'lua',
223
        'text/markdown',
224
        'text/x-markdown'                   => 'markdown',
225
        'text/x-r', 'text/x-r-source',
226
        'application/R'                     => 'r',
227
        'application/sql', 'text/sql',
228
        'text/x-sql'                        => 'sql',
229
        'text/yaml', 'text/x-yaml',
230
        'application/yaml'                  => 'yaml',
231
        'application/typescript',
232
        'text/typescript'                   => 'typescript',
233
        'text/x-gradle'                     => 'gradle',
234
        'text/x-tex', 'application/x-tex'   => 'tex',
235
        'text/x-java-properties',
236
        'text/properties'                   => 'properties',
237
        'text/ini', 'application/x-ini'     => 'ini',
238
        'application/toml', 'text/toml'     => 'toml',
239
        'text/x-diff', 'text/x-patch'       => 'diff',
240
        default                             => 'text'
241
      };
242
    }
138243
139
    return match( $ext ) {
140
      'php', 'phtml', 'php8', 'php7' => 'php',
141
      'c', 'h' => 'c',
142
      'cpp', 'hpp', 'cc', 'cxx' => 'cpp',
143
      'java' => 'java',
144
      'js', 'jsx', 'mjs' => 'javascript',
145
      'ts', 'tsx' => 'typescript',
146
      'go' => 'go',
147
      'rs' => 'rust',
148
      'py', 'pyw' => 'python',
149
      'rb', 'erb' => 'ruby',
150
      'lua' => 'lua',
151
      'sh', 'bash', 'zsh' => 'bash',
152
      'bat', 'cmd' => 'batch',
153
      'md', 'markdown' => 'markdown',
154
      'rmd' => 'rmd',
155
      'r' => 'r',
156
      'xml', 'svg' => 'xml',
157
      'html', 'htm' => 'html',
158
      'css' => 'css',
159
      'json', 'lock' => 'json',
160
      'sql' => 'sql',
161
      'yaml', 'yml' => 'yaml',
162
      'gradle' => 'gradle',
163
      'tex', 'sty', 'cls', 'ltx' => 'tex',
164
      default => 'text'
165
    };
244
    return $language;
166245
  }
167246
}
M render/LanguageDefinitions.php
1111
        'string_interp' => '/("(?:\\\\.|[^"\\\\])*"|""".*?""")/',
1212
        'string'        => '/(\'(?:\\\\.|[^\'\\\\])*\'|\'\'\'.*?\'\'\'|\/.*?\/)/',
13
        'keyword'       => '/\b(def|task|group|version|ext|return|if|else)\b/',
13
        'keyword'       => '/\b(?:def|task|group|version|ext|return|if|else)\b/',
1414
        'function'      => '/\b(apply|plugin|sourceCompatibility|targetCompatibility|repositories|dependencies|test|plugins|buildscript|allprojects|subprojects|project|implementation|api|compileOnly|runtimeOnly|testImplementation|testRuntimeOnly|mavenCentral|google|jcenter|classpath)\b|\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\(|{)/',
1515
        'variable'      => '/(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{[^}]+\})/',
16
        'boolean'       => '/\b(true|false|null)\b/',
16
        'boolean'       => '/\b(?:true|false|null)\b/',
1717
        'number'        => '/' . $int . '/',
1818
      ],
...
2929
        'string'        => '/(\'(?:\\\\.|[^\'\\\\])*\')/',
3030
        'comment'       => '/(\/\/[^\r\n]*|#[^\r\n]*|\/\*.*?\*\/)/ms',
31
        'keyword'       => '/\b(class|abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|new|or|print|private|protected|public|require|require_once|return|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/',
31
        'keyword'       => '/\b(?:abstract|and|array|as|break|callable|case|catch|class|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|new|or|print|private|protected|public|readonly|require|require_once|return|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/',
3232
        'function'      => '/\b([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*(?=\()/',
3333
        'variable'      => '/(\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/',
3434
        'number'        => '/' . $int . '/',
3535
        'boolean'       => '/\b(true|false|null)\b/i',
3636
      ],
3737
      'bash' => [
3838
        'string_interp' => '/("(?:\\\\.|[^"\\\\])*")/',
3939
        'string'        => '/(\'.*?\')/',
4040
        'comment'       => '/(#[^\n]*)/',
41
        'keyword'       => '/(?<!-)\b(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|do|done|echo|elif|else|enable|esac|eval|exec|exit|export|fc|fg|fi|for|function|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|then|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while)\b/',
41
        'keyword'       => '/(?<!-)\b(?:alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|coproc|declare|dirs|disown|do|done|echo|elif|else|enable|esac|eval|exec|exit|export|fc|fg|fi|for|function|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|select|set|shift|shopt|source|suspend|test|then|time|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while)\b/',
4242
        'function'      => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
4343
        'variable'      => '/(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{[^}]+\})/',
4444
        'number'        => '/' . $int . '/',
4545
      ],
4646
      'batch' => [
4747
        'comment'  => '/((?i:rem)\b[^\n]*|::[^\n]*)/',
4848
        'string'   => '/("[^"]*")/',
49
        'keyword'  => '/(?i)\b(if|else|goto|for|in|do|exit|echo|pause|set|shift|start|cd|dir|copy|del|md|rd|cls|setlocal|endlocal|enabledelayedexpansion|defined|exist|not|errorlevel|setx|findstr|reg|nul|tokens|usebackq|equ|neq|lss|leq|gtr|geq)\b/',
49
        'keyword'  => '/(?i)\b(?:if|else|goto|for|in|do|exit|echo|pause|set|shift|start|cd|dir|copy|del|md|rd|cls|setlocal|endlocal|enabledelayedexpansion|defined|exist|not|errorlevel|setx|findstr|reg|nul|tokens|usebackq|equ|neq|lss|leq|gtr|geq)\b/',
5050
        'function' => '/(?i)\b(call)\b/',
5151
        'variable' => '/(![\w-]+!|%[\w\(\)-]+%|%%[~a-zA-Z]+|%[~a-zA-Z0-9]+)/',
...
5858
        'include'      => '/(^\s*#include[^\r\n]*)/m',
5959
        'preprocessor' => '/(^\s*#(?!include\b)[^\r\n]*)/m',
60
        'keyword'      => '/\b(auto|break|case|const|continue|default|do|else|enum|extern|for|goto|if|noreturn|register|return|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/',
61
        'type'         => '/\b(char|double|float|int|long|short|void)\b/',
60
        'keyword'      => '/\b(?:auto|break|case|const|continue|default|do|else|enum|extern|for|goto|if|noreturn|register|return|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/',
61
        'type'         => '/\b(?:char|double|float|int|long|short|void)\b/',
6262
        'function'     => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
6363
        'number'       => '/' . $int . '/',
6464
      ],
6565
      'cpp' => [
6666
        'string'       => '/' . $str . '/',
6767
        'comment'      => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
6868
        'include'      => '/(^\s*#include[^\r\n]*)/m',
6969
        'preprocessor' => '/(^\s*#(?!include\b)[^\r\n]*)/m',
70
        'keyword'      => '/\b(alignas|alignof|and|and_eq|asm|auto|bitand|bitor|break|case|catch|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|dynamic_cast|else|enum|explicit|export|extern|for|friend|goto|if|inline|mutable|namespace|new|noexcept|noreturn|not|not_eq|nullptr|operator|or|or_eq|private|protected|public|register|reinterpret_cast|return|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|using|virtual|volatile|while|xor|xor_eq)\b/',
71
        'type'         => '/\b(bool|char|char16_t|char32_t|double|float|int|long|short|signed|unsigned|void|wchar_t)\b/',
72
        'boolean'      => '/\b(true|false)\b/',
70
        'keyword'      => '/\b(?:alignas|alignof|and|and_eq|asm|auto|bitand|bitor|break|case|catch|class|co_await|co_return|co_yield|compl|concept|const|consteval|constexpr|constinit|const_cast|continue|decltype|default|delete|do|dynamic_cast|else|enum|explicit|export|extern|for|friend|goto|if|inline|mutable|namespace|new|noexcept|noreturn|not|not_eq|nullptr|operator|or|or_eq|private|protected|public|register|reinterpret_cast|requires|return|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|using|virtual|volatile|while|xor|xor_eq)\b/',
71
        'type'         => '/\b(?:bool|char|char16_t|char32_t|double|float|int|long|short|signed|unsigned|void|wchar_t)\b/',
72
        'boolean'      => '/\b(?:true|false)\b/',
7373
        'function'     => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
7474
        'number'       => '/' . $int . '/',
7575
      ],
7676
      'java' => [
7777
        'class'    => '/(@[a-zA-Z_][a-zA-Z0-9_]*)/',
7878
        'string'   => '/' . $str . '/',
7979
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
80
        'keyword'  => '/\b(abstract|assert|break|case|catch|class|const|continue|default|do|else|enum|extends|final|finally|for|goto|if|implements|import|instanceof|interface|native|new|package|private|protected|public|return|static|strictfp|super|switch|synchronized|this|throw|throws|transient|try|void|volatile|while)\b/',
81
        'type'     => '/\b(boolean|byte|char|double|float|int|long|short|void)\b/',
82
        'boolean'  => '/\b(true|false|null)\b/',
80
        'keyword'  => '/\b(?:abstract|assert|break|case|catch|class|const|continue|default|do|else|enum|extends|final|finally|for|goto|if|implements|import|instanceof|interface|native|new|non-sealed|package|permits|private|protected|public|record|return|sealed|static|strictfp|super|switch|synchronized|this|throw|throws|transient|try|var|void|volatile|while|yield)\b/',
81
        'type'     => '/\b(?:boolean|byte|char|double|float|int|long|short|void)\b/',
82
        'boolean'  => '/\b(?:true|false|null)\b/',
8383
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
8484
        'number'   => '/' . $int . '/',
8585
      ],
8686
      'go' => [
8787
        'string'   => '/("(?:\\\\.|[^"\\\\])*"|`.*?`)/s',
8888
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
89
        'keyword'  => '/\b(break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go|goto|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/',
90
        'boolean'  => '/\b(true|false|nil|iota)\b/',
89
        'keyword'  => '/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go|goto|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/',
90
        'boolean'  => '/\b(?:true|false|nil|iota)\b/',
9191
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
9292
        'number'   => '/' . $int . '/',
9393
      ],
9494
      'rust' => [
9595
        'string'   => '/' . $str . '/',
9696
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
97
        'keyword'  => '/\b(as|break|const|continue|crate|else|enum|extern|fn|for|if|impl|in|let|loop|match|mod|move|mut|pub|ref|return|self|Self|static|struct|super|trait|type|unsafe|use|where|while|async|await|dyn)\b/',
98
        'boolean'  => '/\b(true|false)\b/',
97
        'keyword'  => '/\b(?:as|async|await|break|const|continue|crate|dyn|else|enum|extern|fn|for|if|impl|in|let|loop|match|mod|move|mut|pub|ref|return|self|Self|static|struct|super|trait|type|union|unsafe|use|where|while)\b/',
98
        'boolean'  => '/\b(?:true|false)\b/',
9999
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
100100
        'number'   => '/' . $int . '/',
101101
      ],
102102
      'python' => [
103103
        'string'   => '/(\'\'\'.*?\'\'\'|""".*?"""|"(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\')/s',
104104
        'comment'  => '/(#[^\r\n]*)/m',
105
        'keyword'  => '/\b(and|as|assert|async|await|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|raise|return|try|while|with|yield)\b/',
106
        'boolean'  => '/\b(False|None|True)\b/',
105
        'keyword'  => '/\b(?:and|as|assert|async|await|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|raise|return|try|while|with|yield)\b/',
106
        'boolean'  => '/\b(?:False|None|True)\b/',
107107
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
108108
        'number'   => '/' . $int . '/',
109109
      ],
110110
      'ruby' => [
111111
        'string_interp' => '/("(?:\\\\.|[^"\\\\])*")/',
112112
        'string'        => '/(\'(?:\\\\.|[^\'\\\\])*\')/',
113113
        'comment'       => '/(#[^\r\n]*)/m',
114
        'keyword'       => '/\b(alias|and|begin|break|case|class|def|defined|do|else|elsif|end|ensure|for|if|in|module|next|not|or|redo|rescue|retry|return|self|super|then|undef|unless|until|when|while|yield)\b/',
115
        'boolean'       => '/\b(true|false|nil)\b/',
114
        'keyword'       => '/\b(?:alias|and|begin|break|case|class|def|defined|do|else|elsif|end|ensure|for|if|in|module|next|not|or|redo|rescue|retry|return|self|super|then|undef|unless|until|when|while|yield)\b/',
115
        'boolean'       => '/\b(?:true|false|nil)\b/',
116116
        'function'      => '/\b([a-zA-Z_][a-zA-Z0-9_]*[?!]?)\s*(?=\()/',
117117
        'variable'      => '/(@[a-zA-Z_]\w*|\$[a-zA-Z_]\w*)/',
118118
        'number'        => '/' . $int . '/',
119119
      ],
120120
      'lua' => [
121121
        'string'   => '/("(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\'|\[\[.*?\]\])/s',
122122
        'comment'  => '/(--\[\[.*?\]\]|--[^\r\n]*)/ms',
123
        'keyword'  => '/\b(and|break|do|else|elseif|end|for|function|if|in|local|not|or|repeat|return|then|until|while)\b/',
124
        'boolean'  => '/\b(false|nil|true)\b/',
123
        'keyword'  => '/\b(?:and|break|do|else|elseif|end|for|function|if|in|local|not|or|repeat|return|then|until|while)\b/',
124
        'boolean'  => '/\b(?:false|nil|true)\b/',
125125
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
126126
        'number'   => '/' . $int . '/',
127127
      ],
128128
      'javascript' => [
129129
        'string'   => '/("(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\'|`(?:\\\\.|[^`\\\\])*`)/s',
130130
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
131
        'keyword'  => '/\b(async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|export|extends|finally|for|function|if|import|in|instanceof|new|return|super|switch|this|throw|try|typeof|var|void|while|with|yield|let|static|enum)\b/',
132
        'boolean'  => '/\b(true|false|null|undefined)\b/',
131
        'keyword'  => '/\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|if|import|in|instanceof|let|new|of|return|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/',
132
        'boolean'  => '/\b(?:true|false|null|undefined)\b/',
133133
        'function' => '/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*(?=\()/',
134134
        'number'   => '/' . $int . '/',
135135
      ],
136136
      'typescript' => [
137137
        'string'   => '/("(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\'|`(?:\\\\.|[^`\\\\])*`)/s',
138138
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
139
        'keyword'  => '/\b(any|as|break|case|catch|class|const|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|if|implements|import|in|instanceof|interface|let|module|namespace|new|of|package|private|protected|public|require|return|static|super|switch|this|throw|try|type|typeof|var|void|while|with|yield)\b/',
140
        'type'     => '/\b(boolean|number|string|void|any)\b/',
141
        'boolean'  => '/\b(true|false|null|undefined)\b/',
139
        'keyword'  => '/\b(?:abstract|any|as|break|case|catch|class|const|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|if|implements|import|in|instanceof|interface|is|let|module|namespace|new|of|package|private|protected|public|readonly|require|return|static|super|switch|this|throw|try|type|typeof|var|void|while|with|yield)\b/',
140
        'type'     => '/\b(?:boolean|number|string|void|any)\b/',
141
        'boolean'  => '/\b(?:true|false|null|undefined)\b/',
142142
        'function' => '/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*(?=\()/',
143143
        'number'   => '/' . $int . '/',
...
171171
        'string'   => '/(\'.*?\')/',
172172
        'comment'  => '/(--[^\r\n]*|\/\*.*?\*\/)/ms',
173
        'keyword'  => '/(?i)\b(SELECT|FROM|WHERE|INSERT|INTO|UPDATE|DELETE|JOIN|LEFT|RIGHT|INNER|OUTER|ON|GROUP|BY|ORDER|HAVING|LIMIT|OFFSET|CREATE|TABLE|DROP|ALTER|INDEX|KEY|PRIMARY|FOREIGN|CONSTRAINT|DEFAULT|NOT|AND|OR|IN|VALUES|SET|AS|DISTINCT|UNION|ALL|CASE|WHEN|THEN|ELSE|END)\b/',
173
        'keyword'  => '/(?i)\b(ADD|ALTER|AND|AS|ASC|BEGIN|BETWEEN|BY|CASE|CHECK|COLUMN|COMMIT|CONSTRAINT|CREATE|DATABASE|DEFAULT|DELETE|DESC|DISTINCT|DROP|ELSE|END|EXISTS|FOREIGN|FROM|FULL|FUNCTION|GRANT|GROUP|HAVING|IF|IN|INDEX|INNER|INSERT|INTO|IS|JOIN|KEY|LEFT|LIKE|LIMIT|NOT|NULL|OFFSET|ON|OR|ORDER|OUTER|PRIMARY|PROCEDURE|REFERENCES|REVOKE|RIGHT|ROLLBACK|SCHEMA|SELECT|SET|TABLE|THEN|TRANSACTION|TRIGGER|TRUNCATE|UNION|UNIQUE|UPDATE|VALUES|VIEW|WHEN|WHERE)\b/',
174174
        'boolean'  => '/(?i)\b(NULL|TRUE|FALSE)\b/',
175175
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
176176
        'number'   => '/' . $int . '/',
177177
      ],
178178
      'yaml' => [
179
        'string'    => '/' . $str . '/',
180
        'comment'   => '/(#[^\r\n]*)/m',
181
        'attribute' => '/^(\s*[a-zA-Z0-9_-]+:)/m',
179
        'comment'       => '/(#[^\r\n]*)/m',
180
        'variable'      => '/^(\s*[a-zA-Z0-9_-]+:)/m',
181
        'string_interp' => '/((?<=:)\s*[^\r\n]*)/',
182
        'number'        => '/' . $float . '/',
183
      ],
184
      'properties' => [
185
        'comment'       => '/(^[ \t]*[#!][^\r\n]*)/m',
186
        'variable'      => '/(^[ \t]*[^:=\s]+)(?=[ \t]*[:=])/m',
187
        'string_interp' => '/((?<=[=:])\s*[^\r\n]*)/',
188
      ],
189
      'ini' => [
190
        'comment'   => '/(^[ \t]*[;#][^\r\n]*)/m',
191
        'keyword'   => '/(^\[[^\]\r\n]+\])/m',
192
        'variable'  => '/(^[ \t]*[a-zA-Z0-9_\.\-]+)(?=\s*=)/m',
193
        'string'    => '/((?<==)\s*[^\r\n]*)/',
194
      ],
195
      'toml' => [
196
        'comment'   => '/(#[^\r\n]*)/',
197
        'keyword'   => '/(^\[[^\]\r\n]+\])/m',
198
        'variable'  => '/(\b[a-zA-Z0-9_-]+\b)(?=\s*=)/',
199
        'string'    => '/(' . $str . '|"""[\s\S]*?"""|\'\'\'[\s\S]*?\'\'\')/',
200
        'boolean'   => '/\b(true|false)\b/',
201
        'date'      => '/(\d{4}-\d{2}-\d{2}(?:[Tt ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?)/',
182202
        'number'    => '/' . $float . '/',
183203
      ],
184204
      'markdown' => [
185
        'code'     => '/(^(?:    |\t)[^\n]*(?:\n(?:    |\t)[^\n]*)*)/',
186
        'comment'  => '/(```[\s\S]*?```|~~~[\s\S]*?~~~)/',
187
        'math'     => '/(\$((?:[^`\n$]|`[^`\n]*`)+)\$)/',
188
        'keyword'  => '/^(#{1,6})(?=\s)/m',
189
        'string'   => '/(\*\*[^\n*]+\*\*|__[^\n_]+__)/',
205
        'code'      => '/(^(?:    |\t)[^\n]*(?:\n(?:    |\t)[^\n]*)*)/',
206
        'comment'   => '/(```[\s\S]*?```|~~~[\s\S]*?~~~)/',
207
        'math'      => '/(\$((?:[^`\n$]|`[^`\n]*`)+)\$)/',
208
        'keyword'   => '/^(#{1,6})(?=\s)/m',
209
        'string'    => '/(\*\*[^\n*]+\*\*|__[^\n_]+__)/',
190210
        'attribute' => '/(?<!\*)(\*[^\n*]+\*)(?!\*)|(?<!_)(_[^\n_]+_)(?!_)/',
191
        'function' => '/(`[^`\n]+`)/',
192
        'variable' => '/(\[[^\]]+\]\([^\)]+\))/',
193
        'operator' => '/^(\s*[-*+](?=\s)|\s*\d+\.(?=\s))/m',
211
        'function'  => '/(`[^`\n]+`)/',
212
        'variable'  => '/(\[[^\]]+\]\([^\)]+\))/',
213
        'operator'  => '/^(\s*[-*+](?=\s)|\s*\d+\.(?=\s))/m',
194214
      ],
195215
      'rmd' => [
196
        'code'     => '/(^(?:    |\t)[^\n]*(?:\n(?:    |\t)[^\n]*)*)/',
197
        'comment'  => '/(```\{r[^\}]*\}[\s\S]*?```)/',
198
        'math'     => '/(\$((?:[^`\n$]|`[^`\n]*`)+)\$)/',
199
        'keyword'  => '/^(#{1,6})(?=\s)/m',
200
        'string'   => '/(\*\*[^\n*]+\*\*|__[^\n_]+__)/',
216
        'code'      => '/(^(?:    |\t)[^\n]*(?:\n(?:    |\t)[^\n]*)*)/',
217
        'comment'   => '/(```\{r[^\}]*\}[\s\S]*?```)/',
218
        'math'      => '/(\$((?:[^`\n$]|`[^`\n]*`)+)\$)/',
219
        'keyword'   => '/^(#{1,6})(?=\s)/m',
220
        'string'    => '/(\*\*[^\n*]+\*\*|__[^\n_]+__)/',
201221
        'attribute' => '/(?<!\*)(\*[^\n*]+\*)(?!\*)|(?<!_)(_[^\n_]+_)(?!_)/',
202
        'function' => '/(`[^`\n]+`)/',
203
        'variable' => '/(\[[^\]]+\]\([^\)]+\))/',
204
        'operator' => '/^(\s*[-*+](?=\s)|\s*\d+\.(?=\s))/m',
222
        'function'  => '/(`[^`\n]+`)/',
223
        'variable'  => '/(\[[^\]]+\]\([^\)]+\))/',
224
        'operator'  => '/^(\s*[-*+](?=\s)|\s*\d+\.(?=\s))/m',
205225
      ],
206226
      'r' => [
207227
        'string'   => '/' . $str . '/',
208228
        'comment'  => '/(#[^\r\n]*)/m',
209
        'keyword'  => '/\b(if|else|repeat|while|function|for|in|next|break)\b/',
210
        'boolean'  => '/\b(TRUE|FALSE|NULL|Inf|NaN|NA)\b/',
229
        'keyword'  => '/\b(?:if|else|repeat|while|function|for|in|next|break)\b/',
230
        'boolean'  => '/\b(?:TRUE|FALSE|NULL|Inf|NaN|NA)\b/',
211231
        'function' => '/\b([a-zA-Z_.][a-zA-Z0-9_.]*)\s*(?=\()/',
232
        'number'   => '/' . $float . '/',
233
      ],
234
      'csharp' => [
235
        'string'       => '/(@"(?:""|[^"])*"|' . $str . ')/',
236
        'comment'      => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
237
        'preprocessor' => '/(^\s*#[^\r\n]*)/m',
238
        'keyword'      => '/\b(?:abstract|as|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while)\b/',
239
        'function'     => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
240
        'number'       => '/' . $int . '/',
241
      ],
242
      'kotlin' => [
243
        'string'   => '/("""[\s\S]*?"""|' . $str . ')/',
244
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
245
        'keyword'  => '/\b(?:as|break|class|continue|do|else|false|for|fun|if|in|interface|is|null|object|package|return|super|this|throw|true|try|typealias|typeof|val|var|when|while)\b/',
246
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
247
        'number'   => '/' . $int . '/',
248
      ],
249
      'scala' => [
250
        'string'   => '/("""[\s\S]*?"""|' . $str . ')/',
251
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
252
        'keyword'  => '/\b(?:abstract|case|catch|class|def|do|else|extends|false|final|finally|for|forSome|if|implicit|import|lazy|match|new|null|object|override|package|private|protected|return|sealed|super|this|throw|trait|try|true|type|val|var|while|with|yield)\b/',
253
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
254
        'number'   => '/' . $int . '/',
255
      ],
256
      'groovy' => [
257
        'string'        => '/(\'\'\'[\s\S]*?\'\'\'|""".*?"""|"(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\'|\/[^\/]+\/)/',
258
        'comment'       => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
259
        'keyword'       => '/\b(?:def|as|assert|break|case|catch|class|const|continue|default|do|else|enum|extends|false|finally|for|goto|if|implements|import|in|instanceof|interface|new|null|package|return|super|switch|this|throw|throws|trait|true|try|var|void|while)\b/',
260
        'function'      => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
261
        'number'        => '/' . $int . '/',
262
      ],
263
      'dart' => [
264
        'string'   => '/(r?\'\'\'[\s\S]*?\'\'\'|r?"""[\s\S]*?"""|"(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\')/',
265
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
266
        'keyword'  => '/\b(?:abstract|as|assert|async|await|break|case|catch|class|const|continue|default|do|else|enum|export|extends|extension|external|factory|false|final|finally|for|get|if|implements|import|in|interface|is|library|mixin|new|null|on|operator|part|rethrow|return|set|static|super|switch|sync|this|throw|true|try|typedef|var|void|while|with|yield)\b/',
267
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
268
        'number'   => '/' . $int . '/',
269
      ],
270
      'swift' => [
271
        'string'   => '/("""[\s\S]*?"""|' . $str . ')/',
272
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
273
        'keyword'  => '/\b(?:associatedtype|class|deinit|enum|extension|fileprivate|func|import|init|inout|internal|let|open|operator|private|protocol|public|rethrows|static|struct|subscript|typealias|var|break|case|continue|default|defer|do|else|fallthrough|for|guard|if|in|repeat|return|switch|where|while|as|Any|catch|false|is|nil|super|self|Self|throw|throws|true|try)\b/',
274
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
275
        'number'   => '/' . $int . '/',
276
      ],
277
      'perl' => [
278
        'comment'  => '/(#[^\r\n]*)/',
279
        'string'   => '/(' . $str . '|`[^`]*`)/',
280
        'variable' => '/([$@%](?:\{[a-zA-Z_]\w*\}|[a-zA-Z_]\w*))/',
281
        'keyword'  => '/\b(?:my|local|our|state|use|sub|package|if|else|elsif|unless|while|until|for|foreach|do|last|next|redo|goto|continue|return|print|printf|say|die|warn|eval|try|catch)\b/',
212282
        'number'   => '/' . $float . '/',
283
      ],
284
      'powershell' => [
285
        'comment'  => '/(<#[\s\S]*?#>|#[^\r\n]*)/',
286
        'string'   => '/(@"(?:""|[^"])*"@|@\'(?:[^[\'])*\'@|"(?:`.|[^"`])*"|\'(?:[^[\'])*\')/',
287
        'variable' => '/(\$[a-zA-Z0-9_]+)/',
288
        'keyword'  => '/(?i)\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|In|InlineScript|Hidden|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/',
289
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_-]*)\s*(?=\()/',
290
        'number'   => '/' . $int . '/',
291
      ],
292
      'dockerfile' => [
293
        'comment' => '/(#[^\r\n]*)/',
294
        'string'  => '/' . $str . '/',
295
        'keyword' => '/(?i)^\s*(?:FROM|MAINTAINER|RUN|CMD|LABEL|EXPOSE|ENV|ADD|COPY|ENTRYPOINT|VOLUME|USER|WORKDIR|ARG|ONBUILD|STOPSIGNAL|HEALTHCHECK|SHELL)\b/m',
296
      ],
297
      'containerfile' => [
298
        'comment' => '/(#[^\r\n]*)/',
299
        'string'  => '/' . $str . '/',
300
        'keyword' => '/(?i)^\s*(?:FROM|MAINTAINER|RUN|CMD|LABEL|EXPOSE|ENV|ADD|COPY|ENTRYPOINT|VOLUME|USER|WORKDIR|ARG|ONBUILD|STOPSIGNAL|HEALTHCHECK|SHELL)\b/m',
301
      ],
302
      'makefile' => [
303
        'comment'  => '/(#[^\r\n]*)/',
304
        'variable' => '/(\$+[{(][^})]+[})])/',
305
        'keyword'  => '/(?i)\b(?:include|define|endef|export|override|ifdef|ifndef|ifeq|ifneq|else|endif|vpath)\b/',
306
        'function' => '/^([a-zA-Z0-9._-]+):/m',
307
      ],
308
      'diff' => [
309
        'comment'  => '/^(?:---| \+\+\+|index|diff).*/m',
310
        'meta'     => '/^(?:@@).*/m',
311
        'inserted' => '/(^\+.*)/m',
312
        'deleted'  => '/(^-.*)/m',
213313
      ]
214314
    ];