2012-01-28 16:22:18 +00:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Wikitext scripting infrastructure for MediaWiki: hooks.
|
|
|
|
* Copyright (C) 2009-2012 Victor Vasiliev <vasilvv@gmail.com>
|
2018-10-29 13:33:03 +00:00
|
|
|
* https://www.mediawiki.org/
|
2012-01-28 16:22:18 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
|
|
*/
|
|
|
|
|
2018-01-10 14:19:13 +00:00
|
|
|
use MediaWiki\MediaWikiServices;
|
2018-03-22 10:06:15 +00:00
|
|
|
use UtfNormal\Validator;
|
2018-01-21 04:42:48 +00:00
|
|
|
use Wikimedia\PSquare;
|
2017-05-31 10:09:48 +00:00
|
|
|
|
2012-01-28 16:22:18 +00:00
|
|
|
/**
|
2012-04-06 05:04:30 +00:00
|
|
|
* Hooks for the Scribunto extension.
|
2012-01-28 16:22:18 +00:00
|
|
|
*/
|
2012-04-06 05:04:30 +00:00
|
|
|
class ScribuntoHooks {
|
2017-06-24 00:53:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Define content handler constant upon extension registration
|
|
|
|
*/
|
|
|
|
public static function onRegistration() {
|
|
|
|
define( 'CONTENT_MODEL_SCRIBUNTO', 'Scribunto' );
|
|
|
|
}
|
|
|
|
|
2013-03-20 16:30:26 +00:00
|
|
|
/**
|
|
|
|
* Get software information for Special:Version
|
2014-10-10 09:02:03 +00:00
|
|
|
*
|
|
|
|
* @param array &$software
|
2013-03-20 16:30:26 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2014-10-10 09:02:03 +00:00
|
|
|
public static function getSoftwareInfo( array &$software ) {
|
2013-03-20 16:30:26 +00:00
|
|
|
$engine = Scribunto::newDefaultEngine();
|
|
|
|
$engine->setTitle( Title::makeTitle( NS_SPECIAL, 'Version' ) );
|
|
|
|
$engine->getSoftwareInfo( $software );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-01-28 16:22:18 +00:00
|
|
|
/**
|
|
|
|
* Register parser hooks.
|
2014-10-10 09:02:03 +00:00
|
|
|
*
|
2017-09-24 17:38:14 +00:00
|
|
|
* @param Parser &$parser
|
2012-06-15 23:34:35 +00:00
|
|
|
* @return bool
|
2012-01-28 16:22:18 +00:00
|
|
|
*/
|
2014-10-10 09:02:03 +00:00
|
|
|
public static function setupParserHook( Parser &$parser ) {
|
2014-11-18 19:56:33 +00:00
|
|
|
$parser->setFunctionHook( 'invoke', 'ScribuntoHooks::invokeHook', Parser::SFH_OBJECT_ARGS );
|
2012-01-28 16:22:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2012-04-04 06:10:32 +00:00
|
|
|
* Called when the interpreter is to be reset.
|
2014-07-07 18:46:59 +00:00
|
|
|
*
|
2017-09-24 17:38:14 +00:00
|
|
|
* @param Parser &$parser
|
2012-01-28 16:22:18 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2014-10-10 09:02:03 +00:00
|
|
|
public static function clearState( Parser &$parser ) {
|
2012-04-06 05:04:30 +00:00
|
|
|
Scribunto::resetParserEngine( $parser );
|
2012-01-28 16:22:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-11-15 00:13:19 +00:00
|
|
|
/**
|
|
|
|
* Called when the parser is cloned
|
|
|
|
*
|
2014-10-10 09:02:03 +00:00
|
|
|
* @param Parser $parser
|
2012-11-15 00:13:19 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2014-10-10 09:02:03 +00:00
|
|
|
public static function parserCloned( Parser $parser ) {
|
2012-11-15 00:13:19 +00:00
|
|
|
$parser->scribunto_engine = null;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-01-28 16:22:18 +00:00
|
|
|
/**
|
2012-04-04 06:10:32 +00:00
|
|
|
* Hook function for {{#invoke:module|func}}
|
2012-01-28 16:46:15 +00:00
|
|
|
*
|
2017-09-24 17:38:14 +00:00
|
|
|
* @param Parser &$parser
|
2014-10-10 09:02:03 +00:00
|
|
|
* @param PPFrame $frame
|
|
|
|
* @param array $args
|
2012-06-15 23:34:35 +00:00
|
|
|
* @throws MWException
|
|
|
|
* @throws ScribuntoException
|
2012-01-28 16:22:18 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
2014-10-10 09:02:03 +00:00
|
|
|
public static function invokeHook( Parser &$parser, PPFrame $frame, array $args ) {
|
2015-10-24 23:54:11 +00:00
|
|
|
global $wgScribuntoGatherFunctionStats;
|
|
|
|
|
2012-01-28 16:22:18 +00:00
|
|
|
try {
|
2012-05-22 03:56:07 +00:00
|
|
|
if ( count( $args ) < 2 ) {
|
|
|
|
throw new ScribuntoException( 'scribunto-common-nofunction' );
|
|
|
|
}
|
|
|
|
$moduleName = trim( $frame->expand( $args[0] ) );
|
2012-04-06 05:04:30 +00:00
|
|
|
$engine = Scribunto::getParserEngine( $parser );
|
2014-09-16 03:25:53 +00:00
|
|
|
|
2012-04-05 07:58:02 +00:00
|
|
|
$title = Title::makeTitleSafe( NS_MODULE, $moduleName );
|
2014-09-16 03:25:53 +00:00
|
|
|
if ( !$title || !$title->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
|
2015-06-26 16:37:34 +00:00
|
|
|
throw new ScribuntoException( 'scribunto-common-nosuchmodule',
|
2017-06-15 17:19:00 +00:00
|
|
|
[ 'args' => [ $moduleName ] ] );
|
2012-01-28 16:22:18 +00:00
|
|
|
}
|
2012-04-05 07:58:02 +00:00
|
|
|
$module = $engine->fetchModuleFromParser( $title );
|
Added more Lua environment features
Package library:
* Added a simulation of the Lua 5.1 package library.
* Removed mw.import(), replaced it with a package loader. Packages can be
retrieved from the wiki, using require('Module:Foo'), or from files
distributed with Scribunto, using require('foo'). The "Module:" prefix allows
for source compatibility with existing Lua code.
* Added a couple of libraries from LuaForge: luabit and stringtools.
* Made fetchModuleFromParser() return null on error instead of throwing an
exception, to more easily support the desired behaviour of the package loader,
which needs to return null on error.
* Renamed mw.setupEnvironment() to mw.setup() since it is setting up things
other than the environment now.
* In MWServer:handleRegisterLibrary(), remove the feature which interprets dots
in library names, since LuaSandbox doesn't support this.
Improved module isolation and related refactoring:
* Expose restricted versions of getfenv() and setfenv() to user Lua code.
Requires luasandbox r114952.
* Don't cache the export list returned by module execution for later function
calls. This breaks isolation of #invoke calls, since the local variables are
persistent.
* Removed ScribuntoFunctionBase and its children, since it doesn't really have
a purpose if it can't cache anything. Instead, invoke functions using a module
method called invoke().
* Removed Module::initialize(), replaced it with a validate() function. This is
a more elegant interface and works better with the new module caching scheme.
* Use a Status object for the return value of Engine::validate() instead of an
array. Use the formatting facilities of the Status class.
Other:
* Removed "too many returns" error, doesn't fit in with Lua conventions.
* Use the standalone engine by default, so that the extension will work without
configuration for more people.
* Added an accessor for $engine->interpreter
* Fix mw.clone() to correctly clone metatables
* If the standalone interpreter exits due to an error, there are some contexts
where the initial error will be caught and ignored, and the user will see the
error from checkValid() instead. In this case, rethrow the original error for
a more informative message.
* Load mw.lua into the initial standalone environment, to reduce code
duplication between mw.lua and MWServer.lua.
* Fixed a bug in Scribunto_LuaStandaloneInterpreter::handleCall() for functions
that return no results.
* Fixed a bug in encodeLuaVar() for strings with "\r". Added test case.
* In MWServer.lua, don't call error() for internal errors, instead just print
the error and exit. This avoids a protocol violation when an error is
encountered from within handleCall().
* Added lots of documentation. Lua doc comments are in LuaDoc format.
Change-Id: Ie2fd572c362bedf02f45d3fa5352a5280e034740
2012-04-18 03:46:18 +00:00
|
|
|
if ( !$module ) {
|
2015-06-26 16:37:34 +00:00
|
|
|
throw new ScribuntoException( 'scribunto-common-nosuchmodule',
|
2017-06-15 17:19:00 +00:00
|
|
|
[ 'args' => [ $moduleName ] ] );
|
2012-04-05 07:58:02 +00:00
|
|
|
}
|
2012-05-22 03:56:07 +00:00
|
|
|
$functionName = trim( $frame->expand( $args[1] ) );
|
|
|
|
|
2014-09-06 19:32:28 +00:00
|
|
|
$bits = $args[1]->splitArg();
|
2012-05-22 03:56:07 +00:00
|
|
|
unset( $args[0] );
|
|
|
|
unset( $args[1] );
|
2014-09-06 19:32:28 +00:00
|
|
|
|
|
|
|
// If $bits['index'] is empty, then the function name was parsed as a
|
|
|
|
// key=value pair (because of an equals sign in it), and since it didn't
|
|
|
|
// have an index, we don't need the index offset.
|
|
|
|
$childFrame = $frame->newChild( $args, $title, $bits['index'] === '' ? 0 : 1 );
|
2015-10-24 23:54:11 +00:00
|
|
|
|
|
|
|
if ( $wgScribuntoGatherFunctionStats ) {
|
|
|
|
$u0 = $engine->getResourceUsage( $engine::CPU_SECONDS );
|
|
|
|
$result = $module->invoke( $functionName, $childFrame );
|
|
|
|
$u1 = $engine->getResourceUsage( $engine::CPU_SECONDS );
|
|
|
|
|
|
|
|
if ( $u1 > $u0 ) {
|
2017-07-08 13:42:23 +00:00
|
|
|
$timingMs = (int)( 1000 * ( $u1 - $u0 ) );
|
2015-10-24 23:54:11 +00:00
|
|
|
// Since the overhead of stats is worst when when #invoke
|
|
|
|
// calls are very short, don't process measurements <= 20ms.
|
|
|
|
if ( $timingMs > 20 ) {
|
|
|
|
self::reportTiming( $moduleName, $functionName, $timingMs );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$result = $module->invoke( $functionName, $childFrame );
|
|
|
|
}
|
|
|
|
|
2018-03-22 10:06:15 +00:00
|
|
|
return Validator::cleanUp( strval( $result ) );
|
2015-06-26 16:37:34 +00:00
|
|
|
} catch ( ScribuntoException $e ) {
|
2017-06-15 17:19:00 +00:00
|
|
|
$trace = $e->getScriptTraceHtml( [ 'msgOptions' => [ 'content' ] ] );
|
|
|
|
$html = Html::element( 'p', [], $e->getMessage() );
|
2012-04-23 11:36:13 +00:00
|
|
|
if ( $trace !== false ) {
|
2012-10-06 23:42:39 +00:00
|
|
|
$html .= Html::element( 'p',
|
2017-06-15 17:19:00 +00:00
|
|
|
[],
|
2012-10-06 23:42:39 +00:00
|
|
|
wfMessage( 'scribunto-common-backtrace' )->inContentLanguage()->text()
|
|
|
|
) . $trace;
|
2014-06-30 17:38:46 +00:00
|
|
|
} else {
|
|
|
|
$html .= Html::element( 'p',
|
2017-06-15 17:19:00 +00:00
|
|
|
[],
|
2014-06-30 17:38:46 +00:00
|
|
|
wfMessage( 'scribunto-common-no-details' )->inContentLanguage()->text()
|
|
|
|
);
|
2012-04-23 11:36:13 +00:00
|
|
|
}
|
|
|
|
$out = $parser->getOutput();
|
2015-01-23 21:36:55 +00:00
|
|
|
$errors = $out->getExtensionData( 'ScribuntoErrors' );
|
|
|
|
if ( $errors === null ) {
|
|
|
|
// On first hook use, set up error array and output
|
2017-06-15 17:19:00 +00:00
|
|
|
$errors = [];
|
2012-09-06 04:56:42 +00:00
|
|
|
$parser->addTrackingCategory( 'scribunto-common-error-category' );
|
2015-01-23 21:36:55 +00:00
|
|
|
$out->addModules( 'ext.scribunto.errors' );
|
2012-04-23 11:36:13 +00:00
|
|
|
}
|
2015-01-23 21:36:55 +00:00
|
|
|
$errors[] = $html;
|
|
|
|
$out->setExtensionData( 'ScribuntoErrors', $errors );
|
|
|
|
$out->addJsConfigVars( 'ScribuntoErrors', $errors );
|
|
|
|
$id = 'mw-scribunto-error-' . ( count( $errors ) - 1 );
|
2014-06-30 17:38:46 +00:00
|
|
|
$parserError = htmlspecialchars( $e->getMessage() );
|
2012-04-23 11:36:13 +00:00
|
|
|
|
|
|
|
// #iferror-compatible error element
|
2014-07-07 18:46:59 +00:00
|
|
|
return "<strong class=\"error\"><span class=\"scribunto-error\" id=\"$id\">" .
|
2018-09-03 18:08:53 +00:00
|
|
|
$parserError . "</span></strong>";
|
2012-01-28 16:22:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-24 23:54:11 +00:00
|
|
|
/**
|
|
|
|
* Record stats on slow function calls.
|
|
|
|
*
|
|
|
|
* @param string $moduleName
|
|
|
|
* @param string $functionName
|
|
|
|
* @param int $timing Function execution time in milliseconds.
|
|
|
|
*/
|
|
|
|
public static function reportTiming( $moduleName, $functionName, $timing ) {
|
2015-10-29 22:53:10 +00:00
|
|
|
global $wgScribuntoGatherFunctionStats, $wgScribuntoSlowFunctionThreshold;
|
2015-10-24 23:54:11 +00:00
|
|
|
|
|
|
|
if ( !$wgScribuntoGatherFunctionStats ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-29 22:53:10 +00:00
|
|
|
$threshold = $wgScribuntoSlowFunctionThreshold;
|
|
|
|
if ( !( is_float( $threshold ) && $threshold > 0 && $threshold < 1 ) ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-24 23:54:11 +00:00
|
|
|
static $cache;
|
|
|
|
|
|
|
|
if ( !$cache ) {
|
2018-01-10 14:19:13 +00:00
|
|
|
$cache = ObjectCache::getLocalServerInstance( CACHE_NONE );
|
|
|
|
|
2015-10-24 23:54:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// To control the sampling rate, we keep a compact histogram of
|
2015-10-29 22:53:10 +00:00
|
|
|
// observations in APC, and extract the Nth percentile (specified
|
|
|
|
// via $wgScribuntoSlowFunctionThreshold; defaults to 0.90).
|
2018-02-09 18:46:05 +00:00
|
|
|
// We need APC and \Wikimedia\PSquare to do that.
|
2017-05-31 10:09:48 +00:00
|
|
|
if ( !class_exists( PSquare::class ) || $cache instanceof EmptyBagOStuff ) {
|
2015-10-24 23:54:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-09 18:46:05 +00:00
|
|
|
$cacheVersion = '1';
|
|
|
|
$key = $cache->makeGlobalKey( __METHOD__, $cacheVersion, $threshold );
|
2015-10-24 23:54:11 +00:00
|
|
|
|
|
|
|
// This is a classic "read-update-write" critical section with no
|
|
|
|
// mutual exclusion, but the only consequence is that some samples
|
|
|
|
// will be dropped. We only need enough samples to estimate the
|
|
|
|
// the shape of the data, so that's fine.
|
2017-05-31 10:09:48 +00:00
|
|
|
$ps = $cache->get( $key ) ?: new PSquare( $threshold );
|
2015-10-24 23:54:11 +00:00
|
|
|
$ps->addObservation( $timing );
|
|
|
|
$cache->set( $key, $ps, 60 );
|
|
|
|
|
|
|
|
if ( $ps->getCount() < 1000 || $timing < $ps->getValue() ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static $stats;
|
|
|
|
|
|
|
|
if ( !$stats ) {
|
2018-01-10 14:19:13 +00:00
|
|
|
$stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
|
2015-10-24 23:54:11 +00:00
|
|
|
}
|
|
|
|
|
2015-10-30 01:59:26 +00:00
|
|
|
$metricKey = sprintf( 'scribunto.traces.%s__%s__%s', wfWikiId(), $moduleName, $functionName );
|
|
|
|
$stats->timing( $metricKey, $timing );
|
2015-10-24 23:54:11 +00:00
|
|
|
}
|
|
|
|
|
2012-06-15 23:34:35 +00:00
|
|
|
/**
|
2014-10-10 09:02:03 +00:00
|
|
|
* @param Title $title
|
|
|
|
* @param string &$languageCode
|
2012-06-15 23:34:35 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2014-10-10 09:02:03 +00:00
|
|
|
public static function getCodeLanguage( Title $title, &$languageCode ) {
|
2012-04-06 05:04:30 +00:00
|
|
|
global $wgScribuntoUseCodeEditor;
|
2014-09-16 03:25:53 +00:00
|
|
|
if ( $wgScribuntoUseCodeEditor && $title->hasContentModel( CONTENT_MODEL_SCRIBUNTO )
|
2013-02-20 22:00:42 +00:00
|
|
|
) {
|
2012-04-06 05:04:30 +00:00
|
|
|
$engine = Scribunto::newDefaultEngine();
|
2015-06-21 04:38:39 +00:00
|
|
|
if ( $engine->getCodeEditorLanguage() ) {
|
2014-10-10 09:02:03 +00:00
|
|
|
$languageCode = $engine->getCodeEditorLanguage();
|
2012-02-06 22:14:47 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2014-07-07 18:46:59 +00:00
|
|
|
|
2012-02-06 22:14:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
2012-01-28 16:22:18 +00:00
|
|
|
|
|
|
|
/**
|
2013-02-20 22:00:42 +00:00
|
|
|
* Set the Scribunto content handler for modules
|
2014-10-10 09:02:03 +00:00
|
|
|
*
|
|
|
|
* @param Title $title
|
|
|
|
* @param string &$model
|
2012-01-28 16:46:15 +00:00
|
|
|
* @return bool
|
2012-01-28 16:22:18 +00:00
|
|
|
*/
|
2014-10-10 09:02:03 +00:00
|
|
|
public static function contentHandlerDefaultModelFor( Title $title, &$model ) {
|
2015-06-21 04:38:39 +00:00
|
|
|
if ( $title->getNamespace() == NS_MODULE && !Scribunto::isDocPage( $title ) ) {
|
2014-09-16 03:25:53 +00:00
|
|
|
$model = CONTENT_MODEL_SCRIBUNTO;
|
2012-01-28 16:22:18 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-14 12:42:42 +00:00
|
|
|
/**
|
|
|
|
* Adds report of number of evaluations by the single wikitext page.
|
|
|
|
*
|
2014-10-10 09:02:03 +00:00
|
|
|
* @param Parser $parser
|
|
|
|
* @param ParserOutput $output
|
2013-03-14 12:42:42 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2014-10-10 09:02:03 +00:00
|
|
|
public static function reportLimitData( Parser $parser, ParserOutput $output ) {
|
2013-03-14 12:42:42 +00:00
|
|
|
if ( Scribunto::isParserEnginePresent( $parser ) ) {
|
|
|
|
$engine = Scribunto::getParserEngine( $parser );
|
|
|
|
$engine->reportLimitData( $output );
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Formats the limit report data
|
|
|
|
*
|
2014-10-10 09:02:03 +00:00
|
|
|
* @param string $key
|
2017-09-24 17:38:14 +00:00
|
|
|
* @param mixed &$value
|
2014-10-10 09:02:03 +00:00
|
|
|
* @param string &$report
|
|
|
|
* @param bool $isHTML
|
|
|
|
* @param bool $localize
|
2013-03-14 12:42:42 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public static function formatLimitData( $key, &$value, &$report, $isHTML, $localize ) {
|
|
|
|
$engine = Scribunto::newDefaultEngine();
|
|
|
|
return $engine->formatLimitData( $key, $value, $report, $isHTML, $localize );
|
|
|
|
}
|
|
|
|
|
2014-07-07 18:46:59 +00:00
|
|
|
/**
|
2017-03-30 16:57:38 +00:00
|
|
|
* EditPage::showStandardInputs:options hook
|
2014-10-10 09:02:03 +00:00
|
|
|
*
|
|
|
|
* @param EditPage $editor
|
2017-03-30 16:57:38 +00:00
|
|
|
* @param OutputPage $output
|
2017-09-24 17:38:14 +00:00
|
|
|
* @param int &$tab Current tabindex
|
2014-10-10 09:02:03 +00:00
|
|
|
* @return bool
|
2012-07-03 02:56:55 +00:00
|
|
|
*/
|
2017-03-30 16:57:38 +00:00
|
|
|
public static function showStandardInputsOptions( EditPage $editor, OutputPage $output, &$tab ) {
|
2014-09-16 03:25:53 +00:00
|
|
|
if ( $editor->getTitle()->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
|
2017-03-30 16:57:38 +00:00
|
|
|
$output->addModules( 'ext.scribunto.edit' );
|
2015-08-24 20:38:46 +00:00
|
|
|
$editor->editFormTextAfterTools .= '<div id="mw-scribunto-console"></div>';
|
2013-02-20 22:00:42 +00:00
|
|
|
}
|
2012-07-14 04:23:42 +00:00
|
|
|
return true;
|
2015-03-27 16:32:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* EditPage::showReadOnlyForm:initial hook
|
|
|
|
*
|
|
|
|
* @param EditPage $editor
|
|
|
|
* @param OutputPage $output
|
2017-09-24 17:38:14 +00:00
|
|
|
* @return bool
|
2015-03-27 16:32:19 +00:00
|
|
|
*/
|
|
|
|
public static function showReadOnlyFormInitial( EditPage $editor, OutputPage $output ) {
|
2014-09-16 03:25:53 +00:00
|
|
|
if ( $editor->getTitle()->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
|
|
|
|
$output->addModules( 'ext.scribunto.edit' );
|
2015-08-24 21:13:31 +00:00
|
|
|
$editor->editFormTextAfterContent .= '<div id="mw-scribunto-console"></div>';
|
2015-03-27 16:32:19 +00:00
|
|
|
}
|
|
|
|
return true;
|
2012-07-14 04:23:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* EditPageBeforeEditButtons hook
|
2014-10-10 09:02:03 +00:00
|
|
|
*
|
2017-09-24 17:38:14 +00:00
|
|
|
* @param EditPage &$editor
|
|
|
|
* @param array &$buttons Button array
|
|
|
|
* @param int &$tabindex Current tabindex
|
2014-10-10 09:02:03 +00:00
|
|
|
* @return bool
|
2012-07-14 04:23:42 +00:00
|
|
|
*/
|
2014-10-10 09:02:03 +00:00
|
|
|
public static function beforeEditButtons( EditPage &$editor, array &$buttons, &$tabindex ) {
|
2014-09-16 03:25:53 +00:00
|
|
|
if ( $editor->getTitle()->hasContentModel( CONTENT_MODEL_SCRIBUNTO ) ) {
|
|
|
|
unset( $buttons['preview'] );
|
2013-02-20 22:00:42 +00:00
|
|
|
}
|
2012-07-03 02:56:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-06-15 23:34:35 +00:00
|
|
|
/**
|
2016-10-13 18:39:33 +00:00
|
|
|
* @param IContextSource $context
|
|
|
|
* @param Content $content
|
|
|
|
* @param Status $status
|
2012-06-15 23:34:35 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2016-10-13 18:39:33 +00:00
|
|
|
public static function validateScript( IContextSource $context, Content $content,
|
|
|
|
Status $status
|
|
|
|
) {
|
|
|
|
$title = $context->getTitle();
|
2012-01-28 16:22:18 +00:00
|
|
|
|
2016-10-13 18:39:33 +00:00
|
|
|
if ( !$content instanceof ScribuntoContent ) {
|
2013-02-20 22:00:42 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-04-09 04:39:06 +00:00
|
|
|
/** @suppress PhanUndeclaredMethod */
|
2016-10-13 18:39:33 +00:00
|
|
|
$validateStatus = $content->validate( $title );
|
|
|
|
if ( $validateStatus->isOK() ) {
|
2012-07-03 02:56:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
2012-01-28 16:22:18 +00:00
|
|
|
|
2016-10-13 18:39:33 +00:00
|
|
|
$status->merge( $validateStatus );
|
|
|
|
|
|
|
|
if ( isset( $validateStatus->scribunto_error->params['module'] ) ) {
|
|
|
|
$module = $validateStatus->scribunto_error->params['module'];
|
|
|
|
$line = $validateStatus->scribunto_error->params['line'];
|
2012-07-03 02:56:55 +00:00
|
|
|
if ( $module === $title->getPrefixedDBkey() && preg_match( '/^\d+$/', $line ) ) {
|
2016-10-13 18:39:33 +00:00
|
|
|
$out = $context->getOutput();
|
2016-08-31 07:31:26 +00:00
|
|
|
$out->addInlineScript( 'window.location.hash = ' . Xml::encodeJsVar( "#mw-ce-l$line" ) );
|
2012-04-23 11:36:13 +00:00
|
|
|
}
|
2012-01-28 16:22:18 +00:00
|
|
|
}
|
2012-01-28 16:46:15 +00:00
|
|
|
|
2012-01-28 16:22:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
Added tests and fixed bugs
* Added unit tests for the two Lua interpreter classes
* Fixed a bug in checkType()
* Have Scribunto_LuaSandboxInterpreter throw an exception on construct
when the extension doesn't exist, to match the standalone behaviour.
* In Scribunto_LuaSandboxInterpreter, removed debugging statements
accidentally left in.
* Convert LuaSandboxTimeoutError to the appropriate common error
message.
* Moved the option munging from the sandbox engine to the interpreter,
so that the interpreter can be unit tested separately.
* Use /bin/sh instead of bash for lua_ulimit.sh, since dash is smaller
and still supports ulimit.
* Use exec to run the lua binary, so that the vsize of the shell doesn't
add to the memory limit.
* Added a quit function to the standalone interpreter. Unused at present.
* Don't add a comma after the last element of a table in a Lua
expression.
* Make the SIGXCPU detection work: proc_open() runs the command via a
shell, which reports signals in the child via the exit status, so
proc_get_status() will never return a valid termsig element.
* In MWServer:call(), fixed a bug causing the return values to be
wrapped in an array.
* Fixed a misunderstanding of what select() does.
* In MWServer:getStatus(), fixed indexes so that vsize will be correct.
Removed RSS, since it wasn't used anyway and turns out to be measured
in multiples of the page size, and I couldn't be bothered trying to
fetch that from getconf. Return the PID and vsize as numbers rather
than strings.
* Added a simple table dump feature to MWServer:debug().
* Fixed brackets in MWServer:tostring().
* Added missing Linux 32-bit binary.
Change-Id: Ibf5f4656b1c0a9f81287d363184c3fe9d2abdafd
2012-04-16 04:41:08 +00:00
|
|
|
|
2013-02-20 22:00:42 +00:00
|
|
|
/**
|
2014-10-10 09:02:03 +00:00
|
|
|
* @param Article &$article
|
|
|
|
* @param bool &$outputDone
|
|
|
|
* @param bool &$pcache
|
|
|
|
* @return bool
|
2013-02-20 22:00:42 +00:00
|
|
|
*/
|
2014-10-10 09:02:03 +00:00
|
|
|
public static function showDocPageHeader( Article &$article, &$outputDone, &$pcache ) {
|
2013-02-20 22:00:42 +00:00
|
|
|
$title = $article->getTitle();
|
2013-03-08 17:01:50 +00:00
|
|
|
if ( Scribunto::isDocPage( $title, $forModule ) ) {
|
2016-08-31 07:31:26 +00:00
|
|
|
$article->getContext()->getOutput()->addHTML(
|
2013-03-08 17:01:50 +00:00
|
|
|
wfMessage( 'scribunto-doc-page-header', $forModule->getPrefixedText() )->parseAsBlock()
|
2013-02-20 22:00:42 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2012-01-28 16:22:18 +00:00
|
|
|
}
|