37 private $linkRenderer;
39 private $linkBatchFactory;
49 private $namespaceInfo;
66 private const MAX_ID_SIZE = 7;
90 $this->linkRenderer = $linkRenderer;
91 $this->linkBatchFactory = $linkBatchFactory;
92 $this->linkCache = $linkCache;
93 $this->repoGroup = $repoGroup;
94 $this->userLang = $userLang;
95 $this->contLang = $contLang;
96 $this->titleParser = $titleParser;
97 $this->namespaceInfo = $namespaceInfo;
98 $this->hookRunner =
new HookRunner( $hookContainer );
113 $samePage =
false, $wikiId =
false, $enableSectionLinks =
true
115 return $this->preprocessInternal( $comment,
false, $selfLinkTarget,
116 $samePage, $wikiId, $enableSectionLinks );
130 $samePage =
false, $wikiId =
false, $enableSectionLinks =
true
132 return $this->preprocessInternal( $comment,
true, $selfLinkTarget,
133 $samePage, $wikiId, $enableSectionLinks );
144 $this->flushLinkBatches();
145 return preg_replace_callback(
146 '/\x1b([0-9]{' . self::MAX_ID_SIZE .
'})/',
148 $callback = $this->links[(int)$m[1]] ??
null;
152 return '<!-- MISSING -->';
168 private function preprocessInternal( $comment, $unsafe, $selfLinkTarget, $samePage, $wikiId,
173 $comment = strtr( $comment,
"\n\x1b",
" " );
178 if ( $enableSectionLinks ) {
179 $comment = $this->doSectionLinks( $comment, $selfLinkTarget, $samePage, $wikiId );
181 return $this->doWikiLinks( $comment, $selfLinkTarget, $samePage, $wikiId );
200 private function doSectionLinks(
202 $selfLinkTarget =
null,
212 $comment = preg_replace_callback(
218 '!(?:(?<=(.)))?/\*\s*(.*?)\s*\*/(?:(?=(.)))?!',
219 function ( $match ) use ( &$append, $selfLinkTarget, $samePage, $wikiId ) {
221 $match += [
'',
'',
'',
'' ];
223 $pre = $match[1] !==
'';
225 $post = $match[3] !==
'';
228 $this->hookRunner->onFormatAutocomments(
229 $comment, $pre, $auto, $post,
233 if ( $comment !==
null ) {
237 if ( $selfLinkTarget ) {
239 # Remove links that a user may have manually put in the autosummary
240 # This could be improved by copying as much of Parser::stripSectionName as desired.
241 $section = str_replace( [
249 $sectionText = str_replace(
'[[',
'[[', $auto );
252 if ( $section !==
'' ) {
254 $sectionTitle =
new TitleValue(
NS_MAIN,
'', $section );
256 $sectionTitle = $selfLinkTarget->createFragmentTarget( $section );
258 $auto = $this->makeSectionLink(
260 $this->userLang->getArrow() . $this->userLang->getDirMark() . $sectionText,
266 # written summary $presep autocomment (summary )
267 $pre =
wfMessage(
'autocomment-prefix' )->inContentLanguage()->escaped();
270 # autocomment $postsep written summary ( summary)
271 $auto .=
wfMessage(
'colon-separator' )->inContentLanguage()->escaped();
274 $auto =
'<span dir="auto"><span class="autocomment">' . $auto .
'</span>';
275 $append .=
'</span>';
277 $comment = $pre . $auto;
282 return $comment . $append;
296 private function makeSectionLink(
297 LinkTarget $target, $text, $wikiId
299 if ( $wikiId !==
null && $wikiId !==
false && !$target->isExternal() ) {
303 $target->getNamespace() === 0
304 ? $target->getDBkey()
305 : $this->namespaceInfo->getCanonicalName( $target->getNamespace() ) .
306 ':' . $target->getDBkey(),
307 $target->getFragment()
313 return $this->linkRenderer->makePreloadedLink( $target,
new HtmlArmor( $text ),
'' );
334 private function doWikiLinks( $comment, $selfLinkTarget =
null, $samePage =
false, $wikiId =
false ) {
335 return preg_replace_callback(
338 \s*+ # ignore leading whitespace, the *+ quantifier disallows backtracking
339 :? # ignore optional leading colon
340 ([^[\]|]+) # 1. link target; page names cannot include [, ] or |
343 # Stop matching at ]] without relying on backtracking.
347 ([^[]*) # 3. link trail (the text up until the next link)
349 function ( $match ) use ( $selfLinkTarget, $samePage, $wikiId ) {
351 $medians .= preg_quote(
352 $this->namespaceInfo->getCanonicalName(
NS_MEDIA ),
'/' );
354 $medians .= preg_quote(
355 $this->contLang->getNsText(
NS_MEDIA ),
359 $comment = $match[0];
362 if ( strpos( $match[1],
'%' ) !==
false ) {
364 rawurldecode( $match[1] ),
365 [
'<' =>
'<',
'>' =>
'>' ]
370 if ( $match[2] !=
"" ) {
377 if ( preg_match(
'/^' . $medians .
'(.*)$/i', $match[1], $submatch ) ) {
379 $linkRegexp =
'/\[\[(.*?)\]\]/';
380 $linkTarget = $this->titleParser->makeTitleValueSafe(
NS_FILE, $submatch[1] );
382 $linkMarker = $this->addFileLink( $linkTarget, $text );
387 if ( isset( $match[1][0] ) && $match[1][0] ==
':' ) {
388 $match[1] = substr( $match[1], 1 );
391 if ( $match[1] !==
false && $match[1] !==
null && $match[1] !==
'' ) {
393 $this->contLang->linkTrail(),
397 $trail = $submatch[1];
401 $linkRegexp =
'/\[\[(.*?)\]\]' . preg_quote( $trail,
'/' ) .
'/';
408 $target = $this->titleParser->parseTitle( $linkTarget );
410 if ( $target->getText() ==
'' && !$target->isExternal()
411 && !$samePage && $selfLinkTarget
413 $target = $selfLinkTarget->createFragmentTarget( $target->getFragment() );
416 $linkMarker = $this->addPageLink( $target, $linkText . $inside, $wikiId );
417 $linkMarker .= $trail;
418 }
catch ( MalformedTitleException $e ) {
425 $comment = preg_replace(
447 private function addLinkMarker( $callback ) {
448 $nextId = count( $this->links );
449 if ( strlen( (
string)$nextId ) > self::MAX_ID_SIZE ) {
450 throw new \RuntimeException(
'Too many links in comment batch' );
452 $this->links[] = $callback;
453 return sprintf(
"\x1b%0" . self::MAX_ID_SIZE .
'd', $nextId );
465 private function addPageLink( LinkTarget $target, $text, $wikiId ) {
466 if ( $wikiId !==
null && $wikiId !==
false && !$target->isExternal() ) {
471 $target->getNamespace() === 0
472 ? $target->getDBkey()
473 : $this->namespaceInfo->getCanonicalName( $target->getNamespace() ) .
474 ':' . $target->getDBkey(),
475 $target->getFragment()
480 } elseif ( $this->linkCache->getGoodLinkID( $target ) ||
484 return $this->linkRenderer->makeKnownLink( $target,
new HtmlArmor( $text ) );
485 } elseif ( $this->linkCache->isBadLink( $target ) ) {
487 return $this->linkRenderer->makeBrokenLink( $target,
new HtmlArmor( $text ) );
491 if ( !$this->linkBatch ) {
492 $this->linkBatch = $this->linkBatchFactory->newLinkBatch();
493 $this->linkBatch->setCaller( __METHOD__ );
495 $this->linkBatch->addObj( $target );
496 return $this->addLinkMarker(
function () use ( $target, $text ) {
497 return $this->linkRenderer->makeLink( $target,
new HtmlArmor( $text ) );
508 private function addFileLink( LinkTarget $target, $html ) {
509 $this->fileBatch[] = [
512 return $this->addLinkMarker(
function () use ( $target, $html ) {
515 $this->files[$target->getDBkey()] ??
false,
524 private function flushLinkBatches() {
525 if ( $this->linkBatch ) {
526 $this->linkBatch->execute();
527 $this->linkBatch =
null;
529 if ( $this->fileBatch ) {
530 $this->files += $this->repoGroup->findFiles( $this->fileBatch );
531 $this->fileBatch = [];
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Implements some public methods and some protected utility functions which are required by multiple ch...
Marks HTML that shouldn't be escaped.
Base class for language-specific code.
Class representing a list of titles The execute() method checks them all for existence and adds them ...
Cache for article titles (prefixed DB keys) and ids linked from one source.
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
static guessSectionNameFromStrippedText( $text)
Like guessSectionNameFromWikiText(), but takes already-stripped text as input.
Prioritized list of file repositories.
A collection of static methods to play with strings.
static escapeRegexReplacement( $string)
Escape a string to make it suitable for inclusion in a preg_replace() replacement parameter.