[^:]+?):)?'. '(?P[^}|]+?)'. '(?:[|](?P[^}]+))?'. '}/', array($this, 'markupSymbol'), $text); } public function markupSymbol($matches) { if (!$this->isFlatText($matches[0])) { return $matches[0]; } $type = (string)idx($matches, 'type'); $name = (string)$matches['name']; $title = (string)idx($matches, 'title'); // Collapse sequences of whitespace into a single space. $type = preg_replace('/\s+/', ' ', trim($type)); $name = preg_replace('/\s+/', ' ', trim($name)); $title = preg_replace('/\s+/', ' ', trim($title)); $ref = array(); if (strpos($type, '@') !== false) { list($type, $book) = explode('@', $type, 2); $ref['type'] = trim($type); $ref['book'] = trim($book); } else { $ref['type'] = $type; } if (strpos($name, '@') !== false) { list($name, $context) = explode('@', $name, 2); $ref['name'] = trim($name); $ref['context'] = trim($context); } else { $ref['name'] = $name; } $ref['title'] = nonempty($title, $name); foreach ($ref as $key => $value) { if ($value === '') { unset($ref[$key]); } } $engine = $this->getEngine(); $token = $engine->storeText(''); $key = self::KEY_RULE_ATOM_REF; $data = $engine->getTextMetadata($key, array()); $data[$token] = $ref; $engine->setTextMetadata($key, $data); return $token; } public function didMarkupText() { $engine = $this->getEngine(); $key = self::KEY_RULE_ATOM_REF; $data = $engine->getTextMetadata($key, array()); $renderer = $engine->getConfig('diviner.renderer'); foreach ($data as $token => $ref_dict) { $ref = DivinerAtomRef::newFromDictionary($ref_dict); $title = $ref->getTitle(); $href = null; if ($renderer) { // Here, we're generating documentation. If possible, we want to find // the real atom ref so we can render the correct default title and // render invalid links in an alternate style. $ref = $renderer->normalizeAtomRef($ref); if ($ref) { $title = nonempty($ref->getTitle(), $ref->getName()); $href = $renderer->getHrefForAtomRef($ref); } } else { // Here, we're generating comment text or something like that. Just // link to Diviner and let it sort things out. $href = id(new PhutilURI('/diviner/find/')) ->setQueryParams( array( 'book' => $ref->getBook(), 'name' => $ref->getName(), 'type' => $ref->getType(), 'context' => $ref->getContext(), 'jump' => true, )); } // TODO: This probably is not the best place to do this. Move it somewhere // better when it becomes more clear where it should actually go. if ($ref) { switch ($ref->getType()) { case 'function': case 'method': $title = $title.'()'; break; } } if ($this->getEngine()->isTextMode()) { if ($href) { $link = $title.' <'.PhabricatorEnv::getProductionURI($href).'>'; } else { $link = $title; } } else if ($href) { $link = $this->newTag( 'a', array( 'class' => 'atom-ref', 'href' => $href, ), $title); } else { $link = $this->newTag( 'span', array( 'class' => 'atom-ref-invalid', ), $title); } $engine->overwriteStoredText($token, $link); } } }