Path: blob/master/src/applications/diffusion/remarkup/DiffusionSourceLinkRemarkupRule.php
12241 views
<?php12final class DiffusionSourceLinkRemarkupRule3extends PhutilRemarkupRule {45const KEY_SOURCELINKS = 'diffusion.links';67public function getPriority() {8return 200.0;9}1011public function apply($text) {12return preg_replace_callback(13'@{(?:src|source)\b((?:[^}\\\\]+|\\\\.)*)}@m',14array($this, 'markupSourceLink'),15$text);16}1718public function markupSourceLink(array $matches) {19$engine = $this->getEngine();20$text_mode = $engine->isTextMode();21$mail_mode = $engine->isHTMLMailMode();2223if (!$this->isFlatText($matches[0]) || $text_mode || $mail_mode) {24// We could do better than this in text mode and mail mode, but focus25// on web mode first.26return $matches[0];27}2829$metadata_key = self::KEY_SOURCELINKS;30$metadata = $engine->getTextMetadata($metadata_key, array());3132$token = $engine->storeText($matches[0]);3334$metadata[] = array(35'token' => $token,36'raw' => $matches[0],37'input' => $matches[1],38);3940$engine->setTextMetadata($metadata_key, $metadata);4142return $token;43}4445public function didMarkupText() {46$engine = $this->getEngine();47$metadata_key = self::KEY_SOURCELINKS;48$metadata = $engine->getTextMetadata($metadata_key, array());4950if (!$metadata) {51return;52}5354$viewer = $engine->getConfig('viewer');55if (!$viewer) {56return;57}5859$defaults = array(60'repository' => null,61'line' => null,62'commit' => null,63'ref' => null,64);6566$tags = array();67foreach ($metadata as $ref) {68$token = $ref['token'];69$raw = $ref['raw'];70$input = $ref['input'];7172$pattern =73'(^'.74'[\s,]*'.75'(?:"(?P<quotedpath>(?:[^\\\\"]+|\\.)+)"|(?P<rawpath>[^\s,]+))'.76'[\s,]*'.77'(?P<options>.*)'.78'\z)';79$matches = null;80if (!preg_match($pattern, $input, $matches)) {81$hint_text = pht(82'Missing path, expected "{src path ...}" in: %s',83$raw);84$hint = $this->newSyntaxHint($hint_text);8586$engine->overwriteStoredText($token, $hint);87continue;88}8990$path = idx($matches, 'rawpath');91if (!strlen($path)) {92$path = idx($matches, 'quotedpath');93$path = stripcslashes($path);94}9596$parts = explode(':', $path, 2);97if (count($parts) == 2) {98$repository = nonempty($parts[0], null);99$path = $parts[1];100} else {101$repository = null;102$path = $parts[0];103}104105$options = $matches['options'];106107$parser = new PhutilSimpleOptions();108$options = $parser->parse($options) + $defaults;109110foreach ($options as $key => $value) {111if (!array_key_exists($key, $defaults)) {112$hint_text = pht(113'Unknown option "%s" in: %s',114$key,115$raw);116$hint = $this->newSyntaxHint($hint_text);117118$engine->overwriteStoredText($token, $hint);119continue 2;120}121}122123if ($options['repository'] !== null) {124$repository = $options['repository'];125}126127if ($repository === null) {128$hint_text = pht(129'Missing repository, expected "{src repository:path ...}" '.130'or "{src path repository=...}" in: %s',131$raw);132$hint = $this->newSyntaxHint($hint_text);133134$engine->overwriteStoredText($token, $hint);135continue;136}137138$tags[] = array(139'token' => $token,140'raw' => $raw,141'identifier' => $repository,142'path' => $path,143'options' => $options,144);145}146147if (!$tags) {148return;149}150151$query = id(new PhabricatorRepositoryQuery())152->setViewer($viewer)153->withIdentifiers(ipull($tags, 'identifier'));154155$query->execute();156157$repository_map = $query->getIdentifierMap();158159foreach ($tags as $tag) {160$token = $tag['token'];161162$identifier = $tag['identifier'];163$repository = idx($repository_map, $identifier);164if (!$repository) {165// For now, just bail out here. Ideally, we should distingiush between166// restricted and invalid repositories.167continue;168}169170$drequest = DiffusionRequest::newFromDictionary(171array(172'user' => $viewer,173'repository' => $repository,174));175176$options = $tag['options'];177178$line = $options['line'];179$commit = $options['commit'];180$ref_name = $options['ref'];181182$link_uri = $drequest->generateURI(183array(184'action' => 'browse',185'path' => $tag['path'],186'commit' => $commit,187'line' => $line,188'branch' => $ref_name,189));190191$view = id(new DiffusionSourceLinkView())192->setRepository($repository)193->setPath($tag['path'])194->setURI($link_uri);195196if ($line !== null) {197$view->setLine($line);198}199200if ($commit !== null) {201$view->setCommit($commit);202}203204if ($ref_name !== null) {205$view->setRefName($ref_name);206}207208$engine->overwriteStoredText($token, $view);209}210}211212private function newSyntaxHint($text) {213return id(new PHUITagView())214->setType(PHUITagView::TYPE_SHADE)215->setColor('red')216->setIcon('fa-exclamation-triangle')217->setName($text);218}219220}221222223