Go to the documentation of this file.
25 const HIGHLIGHT_MAX_LINES = 1000;
28 const HIGHLIGHT_MAX_BYTES = 102400;
31 const HIGHLIGHT_CSS_CLASS =
'mw-highlight';
34 const CACHE_VERSION = 2;
38 'text/javascript' =>
'javascript',
39 'application/json' =>
'javascript',
50 static $lexers =
null;
52 if (
$lang ===
null ) {
57 $lexers = require __DIR__ .
'/../SyntaxHighlight.lexers.php';
60 $lexer = strtolower(
$lang );
62 if ( isset( $lexers[$lexer] ) ) {
70 if ( isset( $geshi2pygments[$lexer] ) ) {
71 $lexer = $geshi2pygments[$lexer];
72 if ( in_array( $lexer, $lexers ) ) {
86 foreach ( [
'source',
'syntaxhighlight' ] as $tag ) {
87 $parser->
setHook( $tag, [
'SyntaxHighlight',
'parserHook' ] );
102 $out = $parser->mStripState->unstripNoWiki( $text );
105 $out = preg_replace(
'/^\n+/',
'', rtrim( $out ) );
108 if ( isset(
$args[
'enclose'] ) ) {
109 if (
$args[
'enclose'] ===
'none' ) {
110 $args[
'inline'] =
true;
112 unset(
$args[
'enclose'] );
115 $lexer =
$args[
'lang'] ??
'';
118 if ( !$result->isGood() ) {
119 $parser->addTrackingCategory(
'syntaxhighlight-error-category' );
121 $out = $result->getValue();
125 if ( !isset( $htmlAttribs[
'class'] ) ) {
126 $htmlAttribs[
'class'] = self::HIGHLIGHT_CSS_CLASS;
128 $htmlAttribs[
'class'] .=
' ' . self::HIGHLIGHT_CSS_CLASS;
130 if ( !( isset( $htmlAttribs[
'dir'] ) && $htmlAttribs[
'dir'] ===
'rtl' ) ) {
131 $htmlAttribs[
'dir'] =
'ltr';
134 if ( isset(
$args[
'inline'] ) ) {
137 $out = str_replace(
"\n",
' ', $out );
142 $htmlAttribs[
'class'] .=
' ' .
'mw-content-' . $htmlAttribs[
'dir'];
149 if ( preg_match(
'/^<div class="?mw-highlight"?>(.*)<\/div>$/s', trim( $out ), $m ) ) {
150 $out = trim( $m[1] );
152 throw new MWException(
'Unexpected output from Pygments encountered' );
158 $marker = $parser::MARKER_PREFIX .
'-syntaxhighlightinner-' .
159 sprintf(
'%08X', $parser->mMarkerIndex++ ) . $parser::MARKER_SUFFIX;
160 $parser->mStripState->addNoWiki( $marker, $out );
170 $parser->getOutput()->addModuleStyles(
'ext.pygments' );
179 global $wgPygmentizePath;
182 if ( $wgPygmentizePath ===
false ) {
183 $wgPygmentizePath = __DIR__ .
'/../pygments/pygmentize';
186 return $wgPygmentizePath;
195 return htmlspecialchars( $code, ENT_NOQUOTES );
200 [
'class' => self::HIGHLIGHT_CSS_CLASS ],
227 if ( $lexer ===
null &&
$lang !==
null ) {
228 $status->warning(
'syntaxhighlight-error-unknown-language',
$lang );
232 if ( $code ===
'' ) {
237 $length = strlen( $code );
238 if ( strlen( $code ) > self::HIGHLIGHT_MAX_BYTES ) {
242 'syntaxhighlight-error-exceeds-size-limit',
244 self::HIGHLIGHT_MAX_BYTES
246 } elseif ( Shell::isDisabled() ) {
249 $status->warning(
'syntaxhighlight-error-pygments-invocation-failure' );
251 'MediaWiki determined that it cannot invoke Pygments. ' .
252 'As a result, SyntaxHighlight_GeSHi will not perform any syntax highlighting. ' .
253 'See the debug log for details: ' .
254 'https://www.mediawiki.org/wiki/Manual:$wgDebugLogFile'
258 $inline = isset(
$args[
'inline'] );
261 $code = trim( $code );
264 if ( $lexer ===
null ) {
271 'cssclass' => self::HIGHLIGHT_CSS_CLASS,
272 'encoding' =>
'utf-8',
276 if ( isset(
$args[
'line'] ) ) {
277 $options[
'linenos'] =
'inline';
280 if ( $lexer ===
'php' && strpos( $code,
'<?php' ) ===
false ) {
281 $options[
'startinline'] = 1;
285 if ( isset(
$args[
'highlight'] ) ) {
288 $options[
'hl_lines'] = implode(
' ',
$lines );
293 if ( isset(
$args[
'start'] ) && ctype_digit(
$args[
'start'] ) ) {
294 $options[
'linenostart'] = (int)
$args[
'start'];
298 $options[
'nowrap'] = 1;
301 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
303 $output =
$cache->getWithSetCallback(
306 function ( $oldValue, &$ttl ) use ( $code, $lexer, $options, &$error ) {
308 foreach ( $options as $k => $v ) {
309 $optionPairs[] =
"{$k}={$v}";
311 $result = Shell::command(
312 self::getPygmentizePath(),
315 '-O', implode(
',', $optionPairs )
318 ->restrict( Shell::RESTRICT_DEFAULT | Shell::NO_NETWORK )
321 if ( $result->getExitCode() != 0 ) {
322 $ttl = WANObjectCache::TTL_UNCACHEABLE;
323 $error = $result->getStderr();
327 return $result->getStdout();
331 if ( $error !==
null || $output ===
null ) {
332 $status->warning(
'syntaxhighlight-error-pygments-invocation-failure' );
333 wfWarn(
'Failed to invoke Pygments: ' . $error );
343 $output = trim( $output );
346 $status->value = $output;
360 return md5(
"{$code}|{$lexer}|{$optionString}|" . self::CACHE_VERSION );
374 $values = array_map(
'trim', explode(
',', $lineSpec ) );
375 foreach ( $values as $value ) {
376 if ( ctype_digit( $value ) ) {
378 } elseif ( strpos( $value,
'-' ) !==
false ) {
379 list( $start, $end ) = array_map(
'trim', explode(
'-', $value ) );
381 for ( $i = intval( $start ); $i <= $end; $i++ ) {
386 if ( count(
$lines ) > self::HIGHLIGHT_MAX_LINES ) {
387 $lines = array_slice(
$lines, 0, self::HIGHLIGHT_MAX_LINES );
406 return ctype_digit( $start ) &&
407 ctype_digit( $end ) &&
410 $end - $start < self::HIGHLIGHT_MAX_LINES;
431 if ( !$generateHtml ) {
438 $models = $extension->getAttribute(
'SyntaxHighlightModels' );
440 if ( !isset( $models[$model] ) ) {
444 $lexer = $models[$model];
456 $output =
$wgParser->parse( $text,
$title, $options,
true,
true, $revId );
460 if ( !$status->isOK() ) {
463 $out = $status->getValue();
466 $output->
setText(
'<div dir="ltr">' . $out .
'</div>' );
483 if ( !isset( self::$mimeLexers[$mime] ) ) {
487 $lexer = self::$mimeLexers[$mime];
489 if ( !$status->isOK() ) {
493 $out = $status->getValue();
494 if ( preg_match(
'/^<pre([^>]*)>/i', $out, $m ) ) {
496 $attrs[
'class'] .=
' api-pretty-content';
498 $out =
'<pre' . $encodedAttrs .
'>' . substr( $out, strlen( $m[0] ) );
501 $output->addModuleStyles(
'ext.pygments' );
502 $output->addHTML(
'<div dir="ltr">' . $out .
'</div>' );
520 'class' => ResourceLoaderSyntaxHighlightVisualEditorModule::class,
521 'localBasePath' => __DIR__ .
'/../modules',
522 'remoteExtPath' =>
'SyntaxHighlight_GeSHi/modules',
524 've-syntaxhighlight/ve.dm.MWSyntaxHighlightNode.js',
525 've-syntaxhighlight/ve.dm.MWBlockSyntaxHighlightNode.js',
526 've-syntaxhighlight/ve.dm.MWInlineSyntaxHighlightNode.js',
527 've-syntaxhighlight/ve.ce.MWSyntaxHighlightNode.js',
528 've-syntaxhighlight/ve.ce.MWBlockSyntaxHighlightNode.js',
529 've-syntaxhighlight/ve.ce.MWInlineSyntaxHighlightNode.js',
530 've-syntaxhighlight/ve.ui.MWSyntaxHighlightWindow.js',
531 've-syntaxhighlight/ve.ui.MWSyntaxHighlightDialog.js',
532 've-syntaxhighlight/ve.ui.MWSyntaxHighlightDialogTool.js',
533 've-syntaxhighlight/ve.ui.MWSyntaxHighlightInspector.js',
534 've-syntaxhighlight/ve.ui.MWSyntaxHighlightInspectorTool.js',
537 've-syntaxhighlight/ve.ce.MWSyntaxHighlightNode.css',
538 've-syntaxhighlight/ve.ui.MWSyntaxHighlightDialog.css',
539 've-syntaxhighlight/ve.ui.MWSyntaxHighlightInspector.css',
542 'ext.visualEditor.mwcore',
543 'oojs-ui.styles.icons-editing-advanced'
546 'syntaxhighlight-visualeditor-mwsyntaxhighlightinspector-code',
547 'syntaxhighlight-visualeditor-mwsyntaxhighlightinspector-language',
548 'syntaxhighlight-visualeditor-mwsyntaxhighlightinspector-none',
549 'syntaxhighlight-visualeditor-mwsyntaxhighlightinspector-showlines',
550 'syntaxhighlight-visualeditor-mwsyntaxhighlightinspector-startingline',
551 'syntaxhighlight-visualeditor-mwsyntaxhighlightinspector-title',
553 'targets' => [
'desktop',
'mobile' ],
563 return new GeSHi( self::highlight( $text,
$lang )->getValue() );
574 $geshi->parse_code();
578 class_alias( SyntaxHighlight::class,
'SyntaxHighlight_GeSHi' );
Set options of the Parser.
static parseHighlightLines( $lineSpec)
Take an input specifying a list of lines to highlight, returning a raw list of matching line numbers.
static makeCacheKeyHash( $code, $lexer, $options)
Construct a cache key for the results of a Pygments invocation.
static prepare( $text, $lang)
Backward-compatibility shim for extensions.
if(!isset( $args[0])) $lang
static parserHook( $text, $args, $parser)
Parser hook.
static safeEncodeTagAttributes( $assoc_array)
Build a partial tag string from an associative array of attribute names and values as returned by dec...
static getLexer( $lang)
Get the Pygments lexer name for a particular language.
static array $mimeLexers
Mapping of MIME-types to lexer names.
static onResourceLoaderRegisterModules(&$resourceLoader)
Conditionally register resource loader modules that depends on the VisualEditor MediaWiki extension.
static getPygmentizePath()
static buildHeadItem( $geshi)
Backward-compatibility shim for extensions.
static validHighlightRange( $start, $end)
Validate a provided input range.
static plainCodeWrap( $code, $inline)
Generic operation result class Has warning/error list, boolean status and arbitrary value.
static closeElement( $element)
Returns "</$element>".
setHook( $tag, callable $callback)
Create an HTML-style tag, e.g.
static onApiFormatHighlight(IContextSource $context, $text, $mime, $format)
Hook to provide syntax highlighting for API pretty-printed output.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
static getGeSHiToPygmentsMap()
static onContentGetParserOutput(Content $content, Title $title, $revId, ParserOptions $options, $generateHtml, ParserOutput &$output)
Hook into Content::getParserOutput to provide syntax highlighting for script content.
static validateAttributes( $attribs, $whitelist)
Take an array of attribute names and values and normalize or discard illegal values for the given whi...
addModuleStyles( $modules)
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Content object implementation for representing flat text.
static onParserFirstCallInit(Parser &$parser)
Register parser hook.
Interface for objects which can provide a MediaWiki context on request.
Base interface for content objects.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...
Represents a title within MediaWiki.
static highlight( $code, $lang=null, $args=[])
Highlight a code-block using a particular lexer.
static getContentText(Content $content=null)
Convenience function for getting flat text from a Content object.
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
$wgTextModelsToParse
Determines which types of text are parsed as wikitext.
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
static decodeTagAttributes( $text)
Return an associative array of attribute names and values from a partial tag string.
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).