Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/diviner/atom/DivinerAtom.php b/src/applications/diviner/atom/DivinerAtom.php
index 22b0618162..b87a44bb31 100644
--- a/src/applications/diviner/atom/DivinerAtom.php
+++ b/src/applications/diviner/atom/DivinerAtom.php
@@ -1,374 +1,401 @@
<?php
final class DivinerAtom {
const TYPE_FILE = 'file';
const TYPE_ARTICLE = 'article';
const TYPE_METHOD = 'method';
+ const TYPE_CLASS = 'class';
+ const TYPE_FUNCTION = 'function';
+ const TYPE_INTERFACE = 'interface';
private $type;
private $name;
private $file;
private $line;
private $hash;
private $contentRaw;
private $length;
private $language;
private $docblockRaw;
private $docblockText;
private $docblockMeta;
private $warnings = array();
private $parentHash;
private $childHashes = array();
private $context;
private $extends = array();
private $links = array();
private $book;
private $properties = array();
/**
* Returns a sorting key which imposes an unambiguous, stable order on atoms.
*/
public function getSortKey() {
return implode(
"\0",
array(
$this->getBook(),
$this->getType(),
$this->getContext(),
$this->getName(),
$this->getFile(),
sprintf('%08', $this->getLine()),
));
}
public function setBook($book) {
$this->book = $book;
return $this;
}
public function getBook() {
return $this->book;
}
public function setContext($context) {
$this->context = $context;
return $this;
}
public function getContext() {
return $this->context;
}
public static function getAtomSerializationVersion() {
return 2;
}
public function addWarning($warning) {
$this->warnings[] = $warning;
return $this;
}
public function getWarnings() {
return $this->warnings;
}
public function setDocblockRaw($docblock_raw) {
$this->docblockRaw = $docblock_raw;
$parser = new PhutilDocblockParser();
list($text, $meta) = $parser->parse($docblock_raw);
$this->docblockText = $text;
$this->docblockMeta = $meta;
return $this;
}
public function getDocblockRaw() {
return $this->docblockRaw;
}
public function getDocblockText() {
if ($this->docblockText === null) {
throw new Exception("Call setDocblockRaw() before getDocblockText()!");
}
return $this->docblockText;
}
public function getDocblockMeta() {
if ($this->docblockMeta === null) {
throw new Exception("Call setDocblockRaw() before getDocblockMeta()!");
}
return $this->docblockMeta;
}
public function getDocblockMetaValue($key, $default = null) {
$meta = $this->getDocblockMeta();
return idx($meta, $key, $default);
}
public function setDocblockMetaValue($key, $value) {
$meta = $this->getDocblockMeta();
$meta[$key] = $value;
$this->docblockMeta = $meta;
return $this;
}
public function setType($type) {
$this->type = $type;
return $this;
}
public function getType() {
return $this->type;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function getName() {
return $this->name;
}
public function setFile($file) {
$this->file = $file;
return $this;
}
public function getFile() {
return $this->file;
}
public function setLine($line) {
$this->line = $line;
return $this;
}
public function getLine() {
return $this->line;
}
public function setContentRaw($content_raw) {
$this->contentRaw = $content_raw;
return $this;
}
public function getContentRaw() {
return $this->contentRaw;
}
public function setHash($hash) {
$this->hash = $hash;
return $this;
}
public function addLink(DivinerAtomRef $ref) {
$this->links[] = $ref;
return $this;
}
public function addExtends(DivinerAtomRef $ref) {
$this->extends[] = $ref;
return $this;
}
public function getLinkDictionaries() {
return mpull($this->links, 'toDictionary');
}
public function getExtendsDictionaries() {
return mpull($this->extends, 'toDictionary');
}
public function getExtends() {
return $this->extends;
}
public function getHash() {
if ($this->hash) {
return $this->hash;
}
$parts = array(
$this->getType(),
$this->getName(),
$this->getFile(),
$this->getLine(),
$this->getLength(),
$this->getLanguage(),
$this->getContentRaw(),
$this->getDocblockRaw(),
$this->getProperties(),
mpull($this->extends, 'toHash'),
mpull($this->links, 'toHash'),
);
return md5(serialize($parts)).'N';
}
public function setLength($length) {
$this->length = $length;
return $this;
}
public function getLength() {
return $this->length;
}
public function setLanguage($language) {
$this->language = $language;
return $this;
}
public function getLanguage() {
return $this->language;
}
public function addChildHash($child_hash) {
$this->childHashes[] = $child_hash;
return $this;
}
public function getChildHashes() {
return $this->childHashes;
}
public function setParentHash($parent_hash) {
if ($this->parentHash) {
throw new Exception("Atom already has a parent!");
}
$this->parentHash = $parent_hash;
return $this;
}
public function getParentHash() {
return $this->parentHash;
}
public function addChild(DivinerAtom $atom) {
$atom->setParentHash($this->getHash());
$this->addChildHash($atom->getHash());
return $this;
}
public function getURI() {
$parts = array();
$parts[] = phutil_escape_uri_path_component($this->getType());
if ($this->getContext()) {
$parts[] = phutil_escape_uri_path_component($this->getContext());
}
$parts[] = phutil_escape_uri_path_component($this->getName());
$parts[] = null;
return implode('/', $parts);
}
public function toDictionary() {
// NOTE: If you change this format, bump the format version in
// getAtomSerializationVersion().
return array(
'book' => $this->getBook(),
'type' => $this->getType(),
'name' => $this->getName(),
'file' => $this->getFile(),
'line' => $this->getLine(),
'hash' => $this->getHash(),
'uri' => $this->getURI(),
'length' => $this->getLength(),
'context' => $this->getContext(),
'language' => $this->getLanguage(),
'docblockRaw' => $this->getDocblockRaw(),
'warnings' => $this->getWarnings(),
'parentHash' => $this->getParentHash(),
'childHashes' => $this->getChildHashes(),
'extends' => $this->getExtendsDictionaries(),
'links' => $this->getLinkDictionaries(),
'ref' => $this->getRef()->toDictionary(),
'properties' => $this->getProperties(),
);
}
public function getRef() {
$group = null;
$title = null;
if ($this->docblockMeta) {
$group = $this->getDocblockMetaValue('group');
$title = $this->getDocblockMetaValue('title');
}
return id(new DivinerAtomRef())
->setBook($this->getBook())
->setContext($this->getContext())
->setType($this->getType())
->setName($this->getName())
->setTitle($title)
->setGroup($group);
}
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 getProperty($key, $default = null) {
return idx($this->properties, $key, $default);
}
public function setProperty($key, $value) {
$this->properties[$key] = $value;
}
public function getProperties() {
return $this->properties;
}
public function setProperties(array $properties) {
$this->properties = $properties;
return $this;
}
public static function getThisAtomIsNotDocumentedString($type) {
switch ($type) {
- case 'function':
+ case self::TYPE_FILE:
+ return pht('This file is not documented.');
+ case self::TYPE_FUNCTION:
return pht('This function is not documented.');
- case 'class':
+ case self::TYPE_CLASS:
return pht('This class is not documented.');
- case 'article':
+ case self::TYPE_ARTICLE:
return pht('This article is not documented.');
- case 'method':
+ case self::TYPE_METHOD:
return pht('This method is not documented.');
+ case self::TYPE_INTERFACE:
+ return pht('This interface is not documented.');
default:
phlog("Need translation for '{$type}'.");
return pht('This %s is not documented.', $type);
}
}
+ public static function getAtomTypeNameString($type) {
+ switch ($type) {
+ case self::TYPE_FILE:
+ return pht('File');
+ case self::TYPE_FUNCTION:
+ return pht('Function');
+ case self::TYPE_CLASS:
+ return pht('Class');
+ case self::TYPE_ARTICLE:
+ return pht('Article');
+ case self::TYPE_METHOD:
+ return pht('Method');
+ case self::TYPE_INTERFACE:
+ return pht('Interface');
+ default:
+ phlog("Need translation for '{$type}'.");
+ return ucwords($type);
+ }
+ }
+
}
diff --git a/src/applications/diviner/controller/DivinerAtomController.php b/src/applications/diviner/controller/DivinerAtomController.php
index 54d5f4c5dd..d381a53d03 100644
--- a/src/applications/diviner/controller/DivinerAtomController.php
+++ b/src/applications/diviner/controller/DivinerAtomController.php
@@ -1,308 +1,304 @@
<?php
final class DivinerAtomController extends DivinerController {
private $bookName;
private $atomType;
private $atomName;
private $atomContext;
private $atomIndex;
public function shouldAllowPublic() {
return true;
}
public function willProcessRequest(array $data) {
$this->bookName = $data['book'];
$this->atomType = $data['type'];
$this->atomName = $data['name'];
$this->atomContext = nonempty(idx($data, 'context'), null);
$this->atomIndex = nonempty(idx($data, 'index'), null);
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$book = id(new DivinerBookQuery())
->setViewer($viewer)
->withNames(array($this->bookName))
->executeOne();
if (!$book) {
return new Aphront404Response();
}
// TODO: This query won't load ghosts, because they'll fail `needAtoms()`.
// Instead, we might want to load ghosts and render a message like
// "this thing existed in an older version, but no longer does", especially
// if we add content like comments.
$symbol = id(new DivinerAtomQuery())
->setViewer($viewer)
->withBookPHIDs(array($book->getPHID()))
->withTypes(array($this->atomType))
->withNames(array($this->atomName))
->withContexts(array($this->atomContext))
->withIndexes(array($this->atomIndex))
->needAtoms(true)
->needExtends(true)
->executeOne();
if (!$symbol) {
return new Aphront404Response();
}
$atom = $symbol->getAtom();
$extends = $atom->getExtends();
$child_hashes = $atom->getChildHashes();
if ($child_hashes) {
$children = id(new DivinerAtomQuery())
->setViewer($viewer)
->withIncludeUndocumentable(true)
->withNodeHashes($child_hashes)
->execute();
} else {
$children = array();
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName($book->getShortTitle())
->setHref('/book/'.$book->getName().'/'));
$atom_short_title = $atom->getDocblockMetaValue(
'short',
$symbol->getTitle());
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName($atom_short_title));
$header = id(new PhabricatorHeaderView())
->setHeader($symbol->getTitle())
->addTag(
id(new PhabricatorTagView())
->setType(PhabricatorTagView::TYPE_STATE)
->setBackgroundColor(PhabricatorTagView::COLOR_BLUE)
- ->setName($this->renderAtomTypeName($atom->getType())));
+ ->setName(DivinerAtom::getAtomTypeNameString($atom->getType())));
$properties = id(new PhabricatorPropertyListView());
$group = $atom->getDocblockMetaValue('group');
if ($group) {
$group_name = $book->getGroupName($group);
} else {
$group_name = null;
}
$this->buildDefined($properties, $symbol);
$this->buildExtendsAndImplements($properties, $symbol);
$warnings = $atom->getWarnings();
if ($warnings) {
$warnings = id(new AphrontErrorView())
->setErrors($warnings)
->setTitle(pht('Documentation Warnings'))
->setSeverity(AphrontErrorView::SEVERITY_WARNING);
}
$field = 'default';
$engine = id(new PhabricatorMarkupEngine())
->setViewer($viewer)
->addObject($symbol, $field)
->process();
$content = $engine->getOutput($symbol, $field);
if (strlen(trim($symbol->getMarkupText($field)))) {
$content = phutil_tag(
'div',
array(
'class' => 'phabricator-remarkup',
),
array(
$content,
));
} else {
$undoc = DivinerAtom::getThisAtomIsNotDocumentedString($atom->getType());
$content = id(new AphrontErrorView())
->appendChild($undoc)
->setSeverity(AphrontErrorView::SEVERITY_NODATA);
}
$toc = $engine->getEngineMetadata(
$symbol,
$field,
PhutilRemarkupEngineRemarkupHeaderBlockRule::KEY_HEADER_TOC,
array());
$document = id(new PHUIDocumentView())
->setBook($book->getTitle(), $group_name)
->setHeader($header)
->appendChild($properties)
->appendChild($warnings)
->appendChild($content);
$parameters = $atom->getProperty('parameters');
if ($parameters !== null) {
$document->appendChild(
id(new PhabricatorHeaderView())
->setHeader(pht('Parameters')));
$document->appendChild(
id(new DivinerParameterTableView())
->setParameters($parameters));
}
$return = $atom->getProperty('return');
if ($return !== null) {
$document->appendChild(
id(new PhabricatorHeaderView())
->setHeader(pht('Return')));
$document->appendChild(
id(new DivinerReturnTableView())
->setReturn($return));
}
if ($children) {
$document->appendChild(
id(new PhabricatorHeaderView())
->setHeader(pht('Methods')));
foreach ($children as $child) {
$document->appendChild(
id(new PhabricatorHeaderView())
->setHeader($child->getName()));
}
}
if ($toc) {
$side = new PHUIListView();
$side->addMenuItem(
id(new PHUIListItemView())
->setName(pht('Contents'))
->setType(PHUIListItemView::TYPE_LABEL));
foreach ($toc as $key => $entry) {
$side->addMenuItem(
id(new PHUIListItemView())
->setName($entry[1])
->setHref('#'.$key));
}
$document->setSideNav($side, PHUIDocumentView::NAV_TOP);
}
return $this->buildApplicationPage(
array(
$crumbs,
$document,
),
array(
'title' => $symbol->getTitle(),
'device' => true,
));
}
- private function renderAtomTypeName($name) {
- return phutil_utf8_ucwords($name);
- }
-
private function buildExtendsAndImplements(
PhabricatorPropertyListView $view,
DivinerLiveSymbol $symbol) {
$lineage = $this->getExtendsLineage($symbol);
if ($lineage) {
$lineage = mpull($lineage, 'getName');
$lineage = implode(' > ', $lineage);
$view->addProperty(pht('Extends'), $lineage);
}
$implements = $this->getImplementsLineage($symbol);
if ($implements) {
$items = array();
foreach ($implements as $spec) {
$via = $spec['via'];
$iface = $spec['interface'];
if ($via == $symbol) {
$items[] = $iface->getName();
} else {
$items[] = $iface->getName().' (via '.$via->getName().')';
}
}
$view->addProperty(
pht('Implements'),
phutil_implode_html(phutil_tag('br'), $items));
}
}
private function getExtendsLineage(DivinerLiveSymbol $symbol) {
foreach ($symbol->getExtends() as $extends) {
if ($extends->getType() == 'class') {
$lineage = $this->getExtendsLineage($extends);
$lineage[] = $extends;
return $lineage;
}
}
return array();
}
private function getImplementsLineage(DivinerLiveSymbol $symbol) {
$implements = array();
// Do these first so we get interfaces ordered from most to least specific.
foreach ($symbol->getExtends() as $extends) {
if ($extends->getType() == 'interface') {
$implements[$extends->getName()] = array(
'interface' => $extends,
'via' => $symbol,
);
}
}
// Now do parent interfaces.
foreach ($symbol->getExtends() as $extends) {
if ($extends->getType() == 'class') {
$implements += $this->getImplementsLineage($extends);
}
}
return $implements;
}
private function buildDefined(
PhabricatorPropertyListView $view,
DivinerLiveSymbol $symbol) {
$atom = $symbol->getAtom();
$defined = $atom->getFile().':'.$atom->getLine();
$link = $symbol->getBook()->getConfig('uri.source');
if ($link) {
$link = strtr(
$link,
array(
'%%' => '%',
'%f' => phutil_escape_uri($atom->getFile()),
'%l' => phutil_escape_uri($atom->getLine()),
));
$defined = phutil_tag(
'a',
array(
'href' => $link,
'target' => '_blank',
),
$defined);
}
$view->addProperty(pht('Defined'), $defined);
}
}
diff --git a/src/applications/diviner/controller/DivinerController.php b/src/applications/diviner/controller/DivinerController.php
index 2622e05368..8e116d110a 100644
--- a/src/applications/diviner/controller/DivinerController.php
+++ b/src/applications/diviner/controller/DivinerController.php
@@ -1,47 +1,49 @@
<?php
abstract class DivinerController extends PhabricatorController {
protected function buildSideNavView() {
$menu = $this->buildMenu();
return AphrontSideNavFilterView::newFromMenu($menu);
}
protected function buildApplicationMenu() {
return $this->buildMenu();
}
private function buildMenu() {
$menu = new PHUIListView();
id(new DivinerAtomSearchEngine())
->setViewer($this->getRequest()->getUser())
->addNavigationItems($menu);
return $menu;
}
protected function renderAtomList(array $symbols) {
assert_instances_of($symbols, 'DivinerLiveSymbol');
$request = $this->getRequest();
$user = $request->getUser();
$list = id(new PhabricatorObjectItemListView())
->setUser($user);
foreach ($symbols as $symbol) {
$item = id(new PhabricatorObjectItemView())
->setHeader($symbol->getTitle())
->setHref($symbol->getURI())
- ->addIcon('none', $symbol->getType());
+ ->addIcon('none',
+ DivinerAtom::getAtomTypeNameString(
+ $symbol->getType()));
$item->addAttribute(phutil_safe_html($symbol->getSummary()));
$list->addItem($item);
}
return $list;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Oct 31, 2:12 PM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
312265
Default Alt Text
(20 KB)

Event Timeline