diff options
author | Martin Fischer <martin@push-f.com> | 2022-12-03 07:07:55 +0100 |
---|---|---|
committer | Martin Fischer <martin@push-f.com> | 2022-12-03 08:50:45 +0100 |
commit | 46a390d6759065271b2158537691a53679c58989 (patch) | |
tree | 68afc83f78580794ca5f2d1875355ac7509ecef0 | |
parent | de6badb52bd58154baad30a73ec16e129d738fc2 (diff) |
-rw-r--r-- | Code.php | 41 | ||||
-rw-r--r-- | README.md | 45 | ||||
-rw-r--r-- | examples/languages.php | 3 | ||||
-rw-r--r-- | extension.json | 2 |
4 files changed, 70 insertions, 21 deletions
@@ -4,10 +4,12 @@ namespace MediaWiki\Extension\Code; use Content; use ErrorPageError; use ExtensionRegistry; +use FatalError; use Html; use MediaWiki\Content\Renderer\ContentParseParams; use MediaWiki\MediaWikiServices; use Parser; +use ParserOptions; use ParserOutput; use Sanitizer; use SpecialPage; @@ -70,15 +72,6 @@ function renderCode( string $code, $lang, $outputPage, ?array $tagAttrs = null ) $codeBlock = pre( $code, $tagAttrs ); } - foreach ( $lang['linkifiers'] as $regex => $href ) { - $codeBlock = preg_replace_callback( $regex, fn( $match ) => - Xml::element( 'a', [ - 'href' => str_replace( '$1', $match[0], $href ), - 'tabindex' => -1 - ], $match[0] ), - $codeBlock ); - } - $actions = ''; foreach ( $lang['actions'] as $action => $url ) { @@ -96,7 +89,34 @@ function renderCode( string $code, $lang, $outputPage, ?array $tagAttrs = null ) $actions .= Xml::closeElement( 'a' ) . ' '; } - return $codeBlock . $actions; + $additionalOutput = ''; + + $scribuntoModule = $lang['scribuntoModule'] ?? null; + if ( $scribuntoModule && ExtensionRegistry::getInstance()->isLoaded( 'Scribunto' ) ) { + $callFunction = static function ( Parser $parser, string $function, array $extraArgs = [] ) use ( $scribuntoModule, $code, $lang, $tagAttrs ) { + $args = [ $scribuntoModule, $function, $code, $lang['tag'], $tagAttrs == null ]; + $args = array_merge( $args, $extraArgs ); + if ( $tagAttrs ) { + $args = array_merge( $args, $tagAttrs ); + } + $frame = $parser->getPreprocessor()->newFrame(); + $res = $parser->callParserFunction( $frame, '#invoke', $args ); + if ( !$res['found'] ) { + throw new FatalError( "unexpected condition in Code extension: the Scribunto module is loaded but the #invoke parser function wasn't found" ); + } + return Sanitizer::removeSomeTags( $res['text'], [ 'extraTags' => [ 'a' ], 'extra' ] ); + }; + if ( $tagAttrs ) { + $parser = MediaWikiServices::getInstance()->getParser(); + } else { + $parser = MediaWikiServices::getInstance()->getParserFactory()->create(); + $parser->startExternalParse( null, ParserOptions::newFromAnon(), Parser::OT_HTML ); + } + $codeBlock = $callFunction( $parser, 'formatCode', [ $codeBlock ] ); + $additionalOutput = $callFunction( $parser, 'additionalOutput' ); + } + + return $codeBlock . $actions . $additionalOutput; } class ContentHandler extends TextContentHandler { @@ -118,7 +138,6 @@ class ContentHandler extends TextContentHandler { $lang = [ 'pygmentsLexer' => 'text', 'actions' => [], - 'linkifiers' => [], ]; } $out .= renderCode( $content->getText(), $lang, $output ); @@ -9,13 +9,14 @@ to provide the following (all in a configurable manner): * code actions e.g. automatically link the [WDQS] for SPARQL code blocks[^1] -* code linkification - e.g. automatically link Wikidata identifiers in code blocks - * code pages e.g. automatically higlight pages with names ending in `.rq` as SPARQL (and also display the code actions for them) +* customizable code display via Lua/[Scribunto] + e.g. automatically link Wikidata identifiers in code blocks + + ## Example configuration ```php @@ -28,13 +29,44 @@ $wgCode_languages[] = [ 'run' => 'https://query.wikidata.org/#$code', 'embed' => 'https://query.wikidata.org/embed.html#$code', ], - 'linkifiers' => [ - '/\\b[QP][0-9]+\\b/' => 'https://www.wikidata.org/entity/$1', - ], 'suffix' => '.rq', ]; ``` +## Customizable code display + +The display of code blocks can be customized via Lua/[Scribunto]. For example +if you specify e.g. `"scribuntoModule" => "QueryCode"` for a language then this +extension will additionally invoke the `Module:QueryCode` Scribunto module for +every code tag and code page. Such a module could look as follows: + +```lua +local p = {} + +p.formatCode = function(frame) + local code, tag, is_code_page = frame.args[1], frame.args[2], frame.args[3] + local formattedCode = frame.args[4] + formattedCode = formattedCode:gsub('[QP][0-9]+', function(m) + local a = mw.html.create('a') + a:attr('href', 'https://www.wikidata.org/entity/' .. m) + a:wikitext(m) + return tostring(a) + end) + return formattedCode; +end + +p.additionalOutput = function(frame) + local code, tag, is_code_page = frame.args[1], frame.args[2], frame.args[3] + -- HTML returned here is displayed after the code action links +end + +return p +``` + +Note that the returned strings are not parsed as Wikitext they must already be +HTML; any dangerous tags and attributes are removed via MediaWiki's builtin +`Sanitizer` class. + ## Linking code actions Code actions can be linked from other pages via the @@ -57,4 +89,5 @@ this bears the problem that `|` has to be escaped as `{{!}}`, which can be quite annoying for languages like SPARQL that use `|` as an operator. [SyntaxHighlight]: https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:SyntaxHighlight +[Scribunto]: https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:Scribunto [WDQS]: https://query.wikidata.org/ diff --git a/examples/languages.php b/examples/languages.php index 3710f86..6fc4317 100644 --- a/examples/languages.php +++ b/examples/languages.php @@ -5,8 +5,5 @@ $wgCode_languages[] = [ 'run' => 'https://query.wikidata.org/#$code', 'embed' => 'https://query.wikidata.org/embed.html#$code', ], - 'linkifiers' => [ - '/\\b[QP][0-9]+\\b/' => 'https://www.wikidata.org/entity/$1', - ], 'suffix' => '.rq', ]; diff --git a/extension.json b/extension.json index cfa2c2b..d1e3429 100644 --- a/extension.json +++ b/extension.json @@ -6,7 +6,7 @@ "author": "[https://push-f.com/ Martin Fischer]", "url": "https://www.mediawiki.org/wiki/Extension:Code", "version": "0.1.0", - "description": "Provides code pages, code actions and code linkification.", + "description": "Provides code pages, code actions and customizable code rendering.", "config_prefix": "wgCode_", "config": { "namespacesWithCodePages": { |