r39587 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r39586‎ | r39587 | r39588 >
Date:14:44, 18 August 2008
Author:dantman
Status:old
Tags:
Comment:
Committing today's work the LinkHooks' new parser.

Don't expect this to work completely yet, there is likely going to be a lot of refactoring before a final version is complete.
Modified paths:
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/parser/CoreLinkFunctions.php (added) (history)
  • /trunk/phase3/includes/parser/Parser_LinkHooks.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/parser/Parser_LinkHooks.php
@@ -181,4 +181,201 @@
182182 'deps' => $deps );
183183 }
184184
 185+ /**
 186+ * Process [[ ]] wikilinks
 187+ * @return LinkHolderArray
 188+ *
 189+ * @private
 190+ */
 191+ function replaceInternalLinks2( &$s ) {
 192+ global $wgContLang;
 193+
 194+ wfProfileIn( __METHOD__ );
 195+
 196+ wfProfileIn( __METHOD__.'-setup' );
 197+ static $tc = FALSE, $titleRegex;//$e1, $e1_img;
 198+ if( !$tc ) {
 199+ # the % is needed to support urlencoded titles as well
 200+ $tc = Title::legalChars() . '#%';
 201+ # Match a link having the form [[namespace:link|alternate]]trail
 202+ //$e1 = "/^([{$tc}]+)(?:\\|(.+?))?]](.*)\$/sD";
 203+ # Match cases where there is no "]]", which might still be images
 204+ //$e1_img = "/^([{$tc}]+)\\|(.*)\$/sD";
 205+ # Match a valid plain title
 206+ $titleRegex = "/^([{$tc}]+)$/sD";
 207+ }
 208+
 209+ $sk = $this->mOptions->getSkin();
 210+ $holders = new LinkHolderArray( $this );
 211+
 212+ if( is_null( $this->mTitle ) ) {
 213+ wfProfileOut( __METHOD__ );
 214+ wfProfileOut( __METHOD__.'-setup' );
 215+ throw new MWException( __METHOD__.": \$this->mTitle is null\n" );
 216+ }
 217+ $nottalk = !$this->mTitle->isTalkPage();
 218+
 219+ if($wgContLang->hasVariants()) {
 220+ $selflink = $wgContLang->convertLinkToAllVariants($this->mTitle->getPrefixedText());
 221+ } else {
 222+ $selflink = array($this->mTitle->getPrefixedText());
 223+ }
 224+ wfProfileOut( __METHOD__.'-setup' );
 225+
 226+ $offset = 0;
 227+ $offsetStack = array();
 228+ $markerReplacer = new LinkMarkerReplacer( array( &$this, 'replaceInternalLinksCallback' ) );
 229+ $markerReplacer->holders( $holders );
 230+ while( true ) {
 231+ $startBracketOffset = strpos( $s, '[[', $offset );
 232+ $endBracketOffset = strpos( $s, ']]', $offset );
 233+ # Finish when there are no more brackets
 234+ if( $startBracketOffset === false && $endBracketOffset === false ) break;
 235+ # Determine if the bracket is a starting or ending bracket
 236+ # When we find both, use the first one
 237+ elseif( $startBracketOffset !== false && $endBracketOffset !== false )
 238+ $isStart = $startBracketOffset <= $endBracketOffset;
 239+ # When we only found one, check which it is
 240+ else $isStart = $startBracketOffset !== false;
 241+ $bracketOffset = $isStart ? $startBracketOffset : $endBracketOffset;
 242+ if( $isStart ) {
 243+ /** Opening bracket **/
 244+ # Just push our current offset in the string onto the stack
 245+ $offsetStack[] = $startBracketOffset;
 246+ } else {
 247+ /** Closing bracket **/
 248+ # Pop the start pos for our current link zone off the stack
 249+ $startBracketOffset = array_pop($offsetStack);
 250+ # Just to clean up the code, lets place offsets on the outer ends
 251+ $endBracketOffset += 2;
 252+
 253+ # Only do logic if we actually have a opening bracket for this
 254+ if( isset($startBracketOffset) ) {
 255+ # Extract text inside the link
 256+ @list( $titleText, $paramText ) = explode('|',
 257+ substr($s, $startBracketOffset+2, $endBracketOffset-$startBracketOffset-4), 2);
 258+ # Create markers only for valid links
 259+ if( preg_match( $titleRegex, $titleText ) ) {
 260+ # Store the text for the marker
 261+ $marker = $markerReplacer->addMarker($titleText, $paramText);
 262+ # Replace the current link with the marker
 263+ $s = substr($s,0,$startBracketOffset).
 264+ $marker.
 265+ substr($s, $endBracketOffset);
 266+ # We have modified $s, because of this we need to set the
 267+ # offset manually since the end position is different now
 268+ $offset = $startBracketOffset+strlen($marker);
 269+ continue;
 270+ }
 271+ # ToDo: Some LinkHooks may allow recursive links inside of
 272+ # the link text, create a regex that also matches our
 273+ # <!-- LINKMARKER ### --> sequence in titles
 274+ # ToDO: Some LinkHooks use patterns rather than namespaces
 275+ # these need to be tested at this point here
 276+ }
 277+
 278+ }
 279+ # Bump our offset to after our current bracket
 280+ $offset = $bracketOffset+2;
 281+ }
 282+
 283+
 284+ # Now expand our tree
 285+ wfProfileIn( __METHOD__.'-expand' );
 286+ $s = $markerReplacer->expand( $s );
 287+ wfProfileOut( __METHOD__.'-expand' );
 288+
 289+ wfProfileOut( __METHOD__ );
 290+ return $holders;
 291+ }
 292+
 293+ function replaceInternalLinksCallback( $markerReplacer, $titleText, $paramText ) {
 294+ wfProfileIn( __METHOD__ );
 295+ $wt = isset($paramText) ? "[[$titleText|$paramText]]" : "[[$titleText]]";
 296+ wfProfileIn( __METHOD__."-misc" );
 297+ # Don't allow internal links to pages containing
 298+ # PROTO: where PROTO is a valid URL protocol; these
 299+ # should be external links.
 300+ if( preg_match('/^\b(?:' . wfUrlProtocols() . ')/', $titleText) ) {
 301+ wfProfileOut( __METHOD__ );
 302+ return $wt;
 303+ }
 304+
 305+ # Make subpage if necessary
 306+ if( $this->areSubpagesAllowed() ) {
 307+ $titleText = $this->maybeDoSubpageLink( $titleText, $paramText );
 308+ }
 309+
 310+ # Check for a leading colon and strip it if it is there
 311+ $leadingColon = $titleText[0] == ':';
 312+ if( $leadingColon ) $titleText = substr( $titleText, 1 );
 313+
 314+ wfProfileOut( __METHOD__."-misc" );
 315+ # Make title object
 316+ wfProfileIn( __METHOD__."-title" );
 317+ $title = Title::newFromText( $this->mStripState->unstripNoWiki($titleText) );
 318+ if( !$title ) {
 319+ wfProfileOut( __METHOD__."-title" );
 320+ wfProfileOut( __METHOD__ );
 321+ return $wt;
 322+ }
 323+ $ns = $title->getNamespace();
 324+ wfProfileOut( __METHOD__."-title" );
 325+
 326+ $callback = array( 'CoreLinkFunctions', 'defaultLinkHook' );
 327+ $args = array( $markerReplacer, $title, $titleText, &$paramText, &$leadingColon );
 328+ $return = call_user_func_array( $callback, $args );
 329+ if( $return === false ) {
 330+ # False (no link) was returned, output plain wikitext
 331+ # Build it again as the hook is allowed to modify $paramText
 332+ return isset($paramText) ? "[[$titleText|$paramText]]" : "[[$titleText]]";
 333+ } elseif( $return === true ) {
 334+ # True (treat as plain link) was returned, call the defaultLinkHook
 335+ $args = array( $markerReplacer, $title, $titleText, &$paramText, &$leadingColon );
 336+ $return = call_user_func_array( array( &$this, 'defaultLinkHook' ), $args );
 337+ }
 338+ # Content was returned, return it
 339+ return $return;
 340+ }
 341+
185342 }
 343+
 344+class LinkMarkerReplacer {
 345+
 346+ protected $markers, $nextId, $holders;
 347+
 348+ function __construct( $callback ) {
 349+ $this->nextId = 0;
 350+ $this->markers = array();
 351+ $this->callback = $callback;
 352+ $this->holders = null;
 353+ }
 354+
 355+ # Note: This is a bit of an ugly way to do this. It works for now, but before
 356+ # this feature becomes usable we should come up with a better arg list.
 357+ # $parser, $holders, and $linkMarkers appear to be 3 needed ones
 358+ function holders( $holders = null ) { return wfSetVar( $this->holders, $holders ); }
 359+
 360+ function addMarker($titleText, $paramText) {
 361+ $id = $this->nextId++;
 362+ $this->markers[$id] = array( $titleText, $paramText );
 363+ return "<!-- LINKMARKER $id -->";
 364+ }
 365+
 366+ function findMarker( $string ) {
 367+ return (bool) preg_match('/<!-- LINKMARKER [0-9]+ -->/', $string );
 368+ }
 369+
 370+ function expand( $string ) {
 371+ return StringUtils::delimiterReplaceCallback( "<!-- LINKMARKER ", " -->", array( &$this, 'callback' ), $string );
 372+ }
 373+
 374+ function callback( $m ) {
 375+ $id = intval($m[1]);
 376+ if( !array_key_exists($id, $this->markers) ) return $m[0];
 377+ $args = $this->markers[$id];
 378+ array_unshift( $args, $this );
 379+ return call_user_func_array( $this->callback, $args );
 380+ }
 381+
 382+}
Index: trunk/phase3/includes/parser/CoreLinkFunctions.php
@@ -0,0 +1,27 @@
 2+<?php
 3+
 4+/**
 5+ * Various core link functions, registered in Parser::firstCallInit()
 6+ * @ingroup Parser
 7+ */
 8+class CoreLinkFunctions {
 9+ static static function register( $parser ) {
 10+
 11+
 12+ }
 13+
 14+ static function defaultLinkHook( $markers, Title $title, $titleText, &$displayText = null, &$leadingColon = false ) {
 15+ # Warning: This hook should NEVER return true as it is the fallback
 16+ # default for when other hooks return true
 17+ if( $markers->findMarker( $displayText ) ) {
 18+ # There are links inside of the displayText
 19+ # For backwards compatibility the deepest links are dominant so this
 20+ # link should not be handled
 21+ $displayText = $markers->expand($displayText);
 22+ # Return false so that this link is reverted back to WikiText
 23+ return false;
 24+ }
 25+ return $markers->holders()->makeHolder( $title, isset($displayText) ? $displayText : $titleText, '', '', '' );
 26+ }
 27+
 28+}
Property changes on: trunk/phase3/includes/parser/CoreLinkFunctions.php
___________________________________________________________________
Added: svn:eol-style
129 + native
Index: trunk/phase3/includes/AutoLoader.php
@@ -356,9 +356,11 @@
357357 'UtfNormal' => 'includes/normal/UtfNormal.php',
358358
359359 # includes/parser
 360+ 'CoreLinkFunctions' => 'includes/parser/CoreLinkFunctions.php',
360361 'CoreParserFunctions' => 'includes/parser/CoreParserFunctions.php',
361362 'DateFormatter' => 'includes/parser/DateFormatter.php',
362363 'LinkHolderArray' => 'includes/parser/LinkHolderArray.php',
 364+ 'LinkMarkerReplacer' => 'includes/parser/LinkMarkerReplacer.php',
363365 'OnlyIncludeReplacer' => 'includes/parser/Parser.php',
364366 'PPDAccum_Hash' => 'includes/parser/Preprocessor_Hash.php',
365367 'PPDPart' => 'includes/parser/Preprocessor_DOM.php',

Status & tagging log