From 64bd35d95fdf1c75bbef58b0947695c812ccfe33 Mon Sep 17 00:00:00 2001 From: Fomafix Date: Sun, 8 Dec 2024 10:42:50 +0000 Subject: [PATCH] Create new class Hooks and use this for HookHandlers Change-Id: I7eaea1d3664dc5d9ac986b34732f45432b76e5be --- extension.json | 2 +- includes/Hooks.php | 190 +++++++++++++++++++++++++++++++++++ includes/SyntaxHighlight.php | 185 +--------------------------------- 3 files changed, 193 insertions(+), 184 deletions(-) create mode 100644 includes/Hooks.php diff --git a/extension.json b/extension.json index 5e447cb4..3fa12d3f 100644 --- a/extension.json +++ b/extension.json @@ -84,7 +84,7 @@ }, "HookHandlers": { "main": { - "class": "MediaWiki\\SyntaxHighlight\\SyntaxHighlight" + "class": "MediaWiki\\SyntaxHighlight\\Hooks" } }, "ParsoidModules": [ diff --git a/includes/Hooks.php b/includes/Hooks.php new file mode 100644 index 00000000..e9758c6f --- /dev/null +++ b/includes/Hooks.php @@ -0,0 +1,190 @@ + Mapping of MIME-types to lexer names. */ + private static $mimeLexers = [ + 'text/javascript' => 'javascript', + 'application/json' => 'javascript', + 'text/xml' => 'xml', + ]; + + /** + * Register parser hook + * + * @param Parser $parser + */ + public function onParserFirstCallInit( $parser ) { + $parser->setHook( 'source', [ SyntaxHighlight::class, 'parserHookSource' ] ); + $parser->setHook( 'syntaxhighlight', [ SyntaxHighlight::class, 'parserHook' ] ); + } + + /** + * Hook into Content::getParserOutput to provide syntax highlighting for + * script content. + * + * @param Content $content + * @param Title $title + * @param int $revId + * @param ParserOptions $options + * @param bool $generateHtml + * @param ParserOutput &$parserOutput + * @return bool + * @since MW 1.21 + */ + public function onContentGetParserOutput( $content, $title, + $revId, $options, $generateHtml, &$parserOutput + ) { + // Hope that the "SyntaxHighlightModels" attribute does not contain silly types. + if ( !( $content instanceof TextContent ) ) { + // Oops! Non-text content? Let MediaWiki handle this. + return true; + } + + if ( !$generateHtml ) { + // Nothing special for us to do, let MediaWiki handle this. + return true; + } + + // Determine the SyntaxHighlight language from the page's + // content model. Extensions can extend the default CSS/JS + // mapping by setting the SyntaxHighlightModels attribute. + $extension = ExtensionRegistry::getInstance(); + $models = $extension->getAttribute( 'SyntaxHighlightModels' ) + [ + CONTENT_MODEL_CSS => 'css', + CONTENT_MODEL_JAVASCRIPT => 'javascript', + ]; + $model = $content->getModel(); + if ( !isset( $models[$model] ) ) { + // We don't care about this model, carry on. + return true; + } + $lexer = $models[$model]; + $text = $content->getText(); + + $config = MediaWikiServices::getInstance()->getMainConfig(); + // Parse using the standard parser to get links etc. into the database, HTML is replaced below. + // We could do this using $content->fillParserOutput(), but alas it is 'protected'. + if ( in_array( $model, $config->get( MainConfigNames::TextModelsToParse ), true ) ) { + $parserOutput = MediaWikiServices::getInstance()->getParser() + ->parse( $text, $title, $options, true, true, $revId ); + } + + $status = SyntaxHighlight::highlight( $text, $lexer, [ 'line' => true, 'linelinks' => 'L' ] ); + if ( !$status->isOK() ) { + return true; + } + $out = $status->getValue(); + + $parserOutput->addModuleStyles( SyntaxHighlight::getModuleStyles() ); + $parserOutput->addModules( [ 'ext.pygments.view' ] ); + $parserOutput->setText( $out ); + + // Inform MediaWiki that we have parsed this page and it shouldn't mess with it. + return false; + } + + /** + * Hook to provide syntax highlighting for API pretty-printed output + * + * @param IContextSource $context + * @param string $text + * @param string $mime + * @param string $format + * @since MW 1.24 + * @return bool + */ + public function onApiFormatHighlight( $context, $text, $mime, $format ) { + if ( !isset( self::$mimeLexers[$mime] ) ) { + return true; + } + + $lexer = self::$mimeLexers[$mime]; + $status = SyntaxHighlight::highlight( $text, $lexer ); + if ( !$status->isOK() ) { + return true; + } + + $out = $status->getValue(); + if ( preg_match( '/^]*)>/i', $out, $m ) ) { + $attrs = Sanitizer::decodeTagAttributes( $m[1] ); + $attrs['class'] .= ' api-pretty-content'; + $encodedAttrs = Sanitizer::safeEncodeTagAttributes( $attrs ); + $out = '' . substr( $out, strlen( $m[0] ) ); + } + $output = $context->getOutput(); + $output->addModuleStyles( SyntaxHighlight::getModuleStyles() ); + $output->addHTML( '
' . $out . '
' ); + + // Inform MediaWiki that we have parsed this page and it shouldn't mess with it. + return false; + } + + /** + * Hook to add Pygments version to Special:Version + * + * @see https://www.mediawiki.org/wiki/Manual:Hooks/SoftwareInfo + * @param array &$software + */ + public function onSoftwareInfo( &$software ) { + try { + $software['[https://pygments.org/ Pygments]'] = Pygmentize::getVersion(); + } catch ( PygmentsException $e ) { + // pass + } + } + + /** + * Hook to register ext.pygments.view module. + * @param ResourceLoader $rl + */ + public function onResourceLoaderRegisterModules( ResourceLoader $rl ): void { + $rl->register( 'ext.pygments.view', [ + 'localBasePath' => MW_INSTALL_PATH . '/extensions/SyntaxHighlight_GeSHi/modules', + 'remoteExtPath' => 'SyntaxHighlight_GeSHi/modules', + 'scripts' => array_merge( [ + 'pygments.linenumbers.js', + 'pygments.links.js', + 'pygments.copy.js' + ], ExtensionRegistry::getInstance()->isLoaded( 'Scribunto' ) ? [ + 'pygments.links.scribunto.js' + ] : [] ), + 'styles' => [ + 'pygments.copy.less' + ], + 'messages' => [ + 'syntaxhighlight-button-copy', + 'syntaxhighlight-button-copied' + ], + 'dependencies' => [ + 'mediawiki.util', + 'mediawiki.Title' + ] + ] ); + } +} diff --git a/includes/SyntaxHighlight.php b/includes/SyntaxHighlight.php index 1bc166fe..d3c8a353 100644 --- a/includes/SyntaxHighlight.php +++ b/includes/SyntaxHighlight.php @@ -18,26 +18,12 @@ namespace MediaWiki\SyntaxHighlight; -use MediaWiki\Api\Hook\ApiFormatHighlightHook; -use MediaWiki\Content\Content; -use MediaWiki\Content\Hook\ContentGetParserOutputHook; -use MediaWiki\Content\TextContent; -use MediaWiki\Context\IContextSource; -use MediaWiki\Hook\ParserFirstCallInitHook; -use MediaWiki\Hook\SoftwareInfoHook; use MediaWiki\Html\Html; use MediaWiki\Json\FormatJson; -use MediaWiki\MainConfigNames; use MediaWiki\MediaWikiServices; use MediaWiki\Parser\Parser; -use MediaWiki\Parser\ParserOptions; -use MediaWiki\Parser\ParserOutput; use MediaWiki\Parser\Sanitizer; -use MediaWiki\Registration\ExtensionRegistry; -use MediaWiki\ResourceLoader\Hook\ResourceLoaderRegisterModulesHook; -use MediaWiki\ResourceLoader\ResourceLoader; use MediaWiki\Status\Status; -use MediaWiki\Title\Title; use RuntimeException; use Wikimedia\ObjectCache\WANObjectCache; use Wikimedia\Parsoid\Core\ContentMetadataCollectorStringSets as CMCSS; @@ -45,13 +31,7 @@ use Wikimedia\Parsoid\DOM\DocumentFragment; use Wikimedia\Parsoid\Ext\ExtensionTagHandler; use Wikimedia\Parsoid\Ext\ParsoidExtensionAPI; -class SyntaxHighlight extends ExtensionTagHandler implements - ParserFirstCallInitHook, - ContentGetParserOutputHook, - ResourceLoaderRegisterModulesHook, - ApiFormatHighlightHook, - SoftwareInfoHook -{ +class SyntaxHighlight extends ExtensionTagHandler { /** @var string CSS class for syntax-highlighted code. Public as used by the updateCSS maintenance script. */ public const HIGHLIGHT_CSS_CLASS = 'mw-highlight'; @@ -59,13 +39,6 @@ class SyntaxHighlight extends ExtensionTagHandler implements /** @var int Cache version. Increment whenever the HTML changes. */ private const CACHE_VERSION = 2; - /** @var array Mapping of MIME-types to lexer names. */ - private static $mimeLexers = [ - 'text/javascript' => 'javascript', - 'application/json' => 'javascript', - 'text/xml' => 'xml', - ]; - /** * Returns the maximum number of lines that may be selected for highlighting * @@ -121,16 +94,6 @@ class SyntaxHighlight extends ExtensionTagHandler implements return null; } - /** - * Register parser hook - * - * @param Parser $parser - */ - public function onParserFirstCallInit( $parser ) { - $parser->setHook( 'source', [ self::class, 'parserHookSource' ] ); - $parser->setHook( 'syntaxhighlight', [ self::class, 'parserHook' ] ); - } - /** * Parser hook for to add deprecated tracking category * @@ -147,7 +110,7 @@ class SyntaxHighlight extends ExtensionTagHandler implements /** * @return string[] */ - private static function getModuleStyles(): array { + public static function getModuleStyles(): array { return [ 'ext.pygments' ]; } @@ -545,148 +508,4 @@ class SyntaxHighlight extends ExtensionTagHandler implements $start < $end && $end - $start < self::getMaxLines(); } - - /** - * Hook into Content::getParserOutput to provide syntax highlighting for - * script content. - * - * @param Content $content - * @param Title $title - * @param int $revId - * @param ParserOptions $options - * @param bool $generateHtml - * @param ParserOutput &$parserOutput - * @return bool - * @since MW 1.21 - */ - public function onContentGetParserOutput( $content, $title, - $revId, $options, $generateHtml, &$parserOutput - ) { - // Hope that the "SyntaxHighlightModels" attribute does not contain silly types. - if ( !( $content instanceof TextContent ) ) { - // Oops! Non-text content? Let MediaWiki handle this. - return true; - } - - if ( !$generateHtml ) { - // Nothing special for us to do, let MediaWiki handle this. - return true; - } - - // Determine the SyntaxHighlight language from the page's - // content model. Extensions can extend the default CSS/JS - // mapping by setting the SyntaxHighlightModels attribute. - $extension = ExtensionRegistry::getInstance(); - $models = $extension->getAttribute( 'SyntaxHighlightModels' ) + [ - CONTENT_MODEL_CSS => 'css', - CONTENT_MODEL_JAVASCRIPT => 'javascript', - ]; - $model = $content->getModel(); - if ( !isset( $models[$model] ) ) { - // We don't care about this model, carry on. - return true; - } - $lexer = $models[$model]; - $text = $content->getText(); - - $config = MediaWikiServices::getInstance()->getMainConfig(); - // Parse using the standard parser to get links etc. into the database, HTML is replaced below. - // We could do this using $content->fillParserOutput(), but alas it is 'protected'. - if ( in_array( $model, $config->get( MainConfigNames::TextModelsToParse ), true ) ) { - $parserOutput = MediaWikiServices::getInstance()->getParser() - ->parse( $text, $title, $options, true, true, $revId ); - } - - $status = self::highlight( $text, $lexer, [ 'line' => true, 'linelinks' => 'L' ] ); - if ( !$status->isOK() ) { - return true; - } - $out = $status->getValue(); - - $parserOutput->addModuleStyles( self::getModuleStyles() ); - $parserOutput->addModules( [ 'ext.pygments.view' ] ); - $parserOutput->setText( $out ); - - // Inform MediaWiki that we have parsed this page and it shouldn't mess with it. - return false; - } - - /** - * Hook to provide syntax highlighting for API pretty-printed output - * - * @param IContextSource $context - * @param string $text - * @param string $mime - * @param string $format - * @since MW 1.24 - * @return bool - */ - public function onApiFormatHighlight( $context, $text, $mime, $format ) { - if ( !isset( self::$mimeLexers[$mime] ) ) { - return true; - } - - $lexer = self::$mimeLexers[$mime]; - $status = self::highlight( $text, $lexer ); - if ( !$status->isOK() ) { - return true; - } - - $out = $status->getValue(); - if ( preg_match( '/^]*)>/i', $out, $m ) ) { - $attrs = Sanitizer::decodeTagAttributes( $m[1] ); - $attrs['class'] .= ' api-pretty-content'; - $encodedAttrs = Sanitizer::safeEncodeTagAttributes( $attrs ); - $out = '' . substr( $out, strlen( $m[0] ) ); - } - $output = $context->getOutput(); - $output->addModuleStyles( self::getModuleStyles() ); - $output->addHTML( '
' . $out . '
' ); - - // Inform MediaWiki that we have parsed this page and it shouldn't mess with it. - return false; - } - - /** - * Hook to add Pygments version to Special:Version - * - * @see https://www.mediawiki.org/wiki/Manual:Hooks/SoftwareInfo - * @param array &$software - */ - public function onSoftwareInfo( &$software ) { - try { - $software['[https://pygments.org/ Pygments]'] = Pygmentize::getVersion(); - } catch ( PygmentsException $e ) { - // pass - } - } - - /** - * Hook to register ext.pygments.view module. - * @param ResourceLoader $rl - */ - public function onResourceLoaderRegisterModules( ResourceLoader $rl ): void { - $rl->register( 'ext.pygments.view', [ - 'localBasePath' => MW_INSTALL_PATH . '/extensions/SyntaxHighlight_GeSHi/modules', - 'remoteExtPath' => 'SyntaxHighlight_GeSHi/modules', - 'scripts' => array_merge( [ - 'pygments.linenumbers.js', - 'pygments.links.js', - 'pygments.copy.js' - ], ExtensionRegistry::getInstance()->isLoaded( 'Scribunto' ) ? [ - 'pygments.links.scribunto.js' - ] : [] ), - 'styles' => [ - 'pygments.copy.less' - ], - 'messages' => [ - 'syntaxhighlight-button-copy', - 'syntaxhighlight-button-copied' - ], - 'dependencies' => [ - 'mediawiki.util', - 'mediawiki.Title' - ] - ] ); - } }