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) { if ($this->getEngine()->isHTMLMailMode()) { $href = PhabricatorEnv::getProductionURI($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); } }
public function findAtomByRef(DivinerAtomRef $ref) { if ($ref->getBook() != $this->getConfig('name')) { return null; } if ($this->atomNameMap === null) { $name_map = array(); foreach ($this->getPublishCache()->getIndex() as $hash => $dict) { $name_map[$dict['name']][$hash] = $dict; } $this->atomNameMap = $name_map; } $name = $ref->getName(); if (empty($this->atomNameMap[$name])) { return null; } $candidates = $this->atomNameMap[$name]; foreach ($candidates as $key => $dict) { $candidates[$key] = DivinerAtomRef::newFromDictionary($dict); if ($ref->getType()) { if ($candidates[$key]->getType() != $ref->getType()) { unset($candidates[$key]); } } if ($ref->getContext()) { if ($candidates[$key]->getContext() != $ref->getContext()) { unset($candidates[$key]); } } } // If we have exactly one uniquely identifiable atom, return it. if (count($candidates) == 1) { return $this->getAtomFromNodeHash(last_key($candidates)); } return null; }
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { $where = array(); if ($this->ids) { $where[] = qsprintf($conn_r, 'id IN (%Ld)', $this->ids); } if ($this->phids) { $where[] = qsprintf($conn_r, 'phid IN (%Ls)', $this->phids); } if ($this->bookPHIDs) { $where[] = qsprintf($conn_r, 'bookPHID IN (%Ls)', $this->bookPHIDs); } if ($this->types) { $where[] = qsprintf($conn_r, 'type IN (%Ls)', $this->types); } if ($this->names) { $where[] = qsprintf($conn_r, 'name IN (%Ls)', $this->names); } if ($this->titles) { $hashes = array(); foreach ($this->titles as $title) { $slug = DivinerAtomRef::normalizeTitleString($title); $hash = PhabricatorHash::digestForIndex($slug); $hashes[] = $hash; } $where[] = qsprintf($conn_r, 'titleSlugHash in (%Ls)', $hashes); } if ($this->contexts) { $with_null = false; $contexts = $this->contexts; foreach ($contexts as $key => $value) { if ($value === null) { unset($contexts[$key]); $with_null = true; continue; } } if ($contexts && $with_null) { $where[] = qsprintf($conn_r, 'context IN (%Ls) OR context IS NULL', $contexts); } else { if ($contexts) { $where[] = qsprintf($conn_r, 'context IN (%Ls)', $contexts); } else { if ($with_null) { $where[] = qsprintf($conn_r, 'context IS NULL'); } } } } if ($this->indexes) { $where[] = qsprintf($conn_r, 'atomIndex IN (%Ld)', $this->indexes); } if ($this->isDocumentable !== null) { $where[] = qsprintf($conn_r, 'isDocumentable = %d', (int) $this->isDocumentable); } if ($this->isGhost !== null) { if ($this->isGhost) { $where[] = qsprintf($conn_r, 'graphHash IS NULL'); } else { $where[] = qsprintf($conn_r, 'graphHash IS NOT NULL'); } } if ($this->nodeHashes) { $where[] = qsprintf($conn_r, 'nodeHash IN (%Ls)', $this->nodeHashes); } if ($this->nameContains) { // NOTE: This `CONVERT()` call makes queries case-insensitive, since // the column has binary collation. Eventually, this should move into // fulltext. $where[] = qsprintf($conn_r, 'CONVERT(name USING utf8) LIKE %~', $this->nameContains); } if ($this->repositoryPHIDs) { $where[] = qsprintf($conn_r, 'repositoryPHID IN (%Ls)', $this->repositoryPHIDs); } $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); }
private function getEdges($node_hash) { $atom_cache = $this->getAtomCache(); $atom = $atom_cache->getAtom($node_hash); $refs = array(); // Make the atom depend on its own symbol, so that all atoms with the same // symbol are dirtied (e.g., if a codebase defines the function `f()` // several times, all of them should be dirtied when one is dirtied). $refs[DivinerAtomRef::newFromDictionary($atom)->toHash()] = true; foreach (array_merge($atom['extends'], $atom['links']) as $ref_dict) { $ref = DivinerAtomRef::newFromDictionary($ref_dict); if ($ref->getBook() == $atom['book']) { $refs[$ref->toHash()] = true; } } return array_keys($refs); }
public function getHrefForAtomRef(DivinerAtomRef $ref) { $depth = 1; $atom = $this->peekAtomStack(); if ($atom) { $depth = $this->getAtomHrefDepth($atom); } $href = str_repeat('../', $depth); $book = $ref->getBook(); $type = $ref->getType(); $name = $ref->getName(); $context = $ref->getContext(); $href .= $book . '/' . $type . '/'; if ($context !== null) { $href .= $context . '/'; } $href .= $name . '/index.html'; return $href; }
public static function newFromDictionary(array $dictionary) { $atom = id(new DivinerAtom())->setBook(idx($dictionary, 'book'))->setType(idx($dictionary, 'type'))->setName(idx($dictionary, 'name'))->setFile(idx($dictionary, 'file'))->setLine(idx($dictionary, 'line'))->setHash(idx($dictionary, 'hash'))->setLength(idx($dictionary, 'length'))->setContext(idx($dictionary, 'context'))->setLanguage(idx($dictionary, 'language'))->setParentHash(idx($dictionary, 'parentHash'))->setDocblockRaw(idx($dictionary, 'docblockRaw'))->setProperties(idx($dictionary, 'properties')); foreach (idx($dictionary, 'warnings', array()) as $warning) { $atom->addWarning($warning); } foreach (idx($dictionary, 'childHashes', array()) as $child) { $atom->addChildHash($child); } foreach (idx($dictionary, 'extends', array()) as $extends) { $atom->addExtends(DivinerAtomRef::newFromDictionary($extends)); } return $atom; }
public function setTitle($value) { $this->writeField('title', $value); if (strlen($value)) { $slug = DivinerAtomRef::normalizeTitleString($value); $hash = PhabricatorHash::digestForIndex($slug); $this->titleSlugHash = $hash; } else { $this->titleSlugHash = null; } return $this; }
public static function newFromDictionary(array $dict) { $obj = new DivinerAtomRef(); $obj->setBook(idx($dict, 'book')); $obj->setContext(idx($dict, 'context')); $obj->setType(idx($dict, 'type')); $obj->setName(idx($dict, 'name')); $obj->group = idx($dict, 'group'); $obj->index = idx($dict, 'index'); $obj->summary = idx($dict, 'summary'); $obj->title = idx($dict, 'title'); return $obj; }