diff --git a/src/applications/diviner/atom/DivinerAtom.php b/src/applications/diviner/atom/DivinerAtom.php index b224dde4d7..b130dbf2a4 100644 --- a/src/applications/diviner/atom/DivinerAtom.php +++ b/src/applications/diviner/atom/DivinerAtom.php @@ -403,6 +403,17 @@ final class DivinerAtom { } } + public static function getAllTypes() { + return array( + self::TYPE_FILE, + self::TYPE_FUNCTION, + self::TYPE_CLASS, + self::TYPE_ARTICLE, + self::TYPE_METHOD, + self::TYPE_INTERFACE, + ); + } + public static function getAtomTypeNameString($type) { switch ($type) { case self::TYPE_FILE: diff --git a/src/applications/diviner/atom/DivinerAtomRef.php b/src/applications/diviner/atom/DivinerAtomRef.php index b536ed6223..87e2ce940a 100644 --- a/src/applications/diviner/atom/DivinerAtomRef.php +++ b/src/applications/diviner/atom/DivinerAtomRef.php @@ -199,6 +199,10 @@ final class DivinerAtomRef { } public static function normalizeTitleString($str) { + // Remove colons from titles. This is mostly to accommodate legacy rules + // from the old Diviner, which generated a significant number of article + // URIs without colons present in the titles. + $str = str_replace(':', '', $str); $str = self::normalizeString($str); return phutil_utf8_strtolower($str); } diff --git a/src/applications/diviner/controller/DivinerAtomListController.php b/src/applications/diviner/controller/DivinerAtomListController.php index 0da8842e56..1bddea8658 100644 --- a/src/applications/diviner/controller/DivinerAtomListController.php +++ b/src/applications/diviner/controller/DivinerAtomListController.php @@ -26,7 +26,29 @@ final class DivinerAtomListController extends DivinerController public function renderResultsList( array $symbols, PhabricatorSavedQuery $query) { - return $this->renderAtomList($symbols); + + assert_instances_of($symbols, 'DivinerLiveSymbol'); + + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $list = id(new PHUIObjectItemListView()) + ->setUser($viewer); + + foreach ($symbols as $symbol) { + $type = $symbol->getType(); + $type_name = DivinerAtom::getAtomTypeNameString($type); + + $item = id(new PHUIObjectItemView()) + ->setHeader($symbol->getTitle()) + ->setHref($symbol->getURI()) + ->addAttribute($symbol->getSummary()) + ->addIcon('none', $type_name); + + $list->addItem($item); + } + + return $list; } } diff --git a/src/applications/diviner/query/DivinerAtomQuery.php b/src/applications/diviner/query/DivinerAtomQuery.php index df6124293f..6dc3ff0763 100644 --- a/src/applications/diviner/query/DivinerAtomQuery.php +++ b/src/applications/diviner/query/DivinerAtomQuery.php @@ -14,6 +14,7 @@ final class DivinerAtomQuery private $includeGhosts; private $nodeHashes; private $titles; + private $nameContains; private $needAtoms; private $needExtends; @@ -64,6 +65,11 @@ final class DivinerAtomQuery return $this; } + public function withNameContains($text) { + $this->nameContains = $text; + return $this; + } + public function needAtoms($need) { $this->needAtoms = $need; return $this; @@ -361,6 +367,17 @@ final class DivinerAtomQuery $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); + } + $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); diff --git a/src/applications/diviner/query/DivinerAtomSearchEngine.php b/src/applications/diviner/query/DivinerAtomSearchEngine.php index 2701e26435..6c8382be3b 100644 --- a/src/applications/diviner/query/DivinerAtomSearchEngine.php +++ b/src/applications/diviner/query/DivinerAtomSearchEngine.php @@ -6,18 +6,60 @@ final class DivinerAtomSearchEngine public function buildSavedQueryFromRequest(AphrontRequest $request) { $saved = new PhabricatorSavedQuery(); + $saved->setParameter( + 'types', + $this->readListFromRequest($request, 'types')); + + $saved->setParameter('name', $request->getStr('name')); + return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new DivinerAtomQuery()); + $types = $saved->getParameter('types'); + if ($types) { + $query->withTypes($types); + } + + $name = $saved->getParameter('name'); + if ($name) { + $query->withNameContains($name); + } + return $query; } public function buildSearchForm( AphrontFormView $form, - PhabricatorSavedQuery $saved_query) { + PhabricatorSavedQuery $saved) { + + $all_types = array(); + foreach (DivinerAtom::getAllTypes() as $type) { + $all_types[$type] = DivinerAtom::getAtomTypeNameString($type); + } + asort($all_types); + + $types = $saved->getParameter('types', array()); + $types = array_fuse($types); + $type_control = id(new AphrontFormCheckboxControl()) + ->setLabel(pht('Types')); + foreach ($all_types as $type => $name) { + $type_control->addCheckbox( + 'types[]', + $type, + $name, + isset($types[$type])); + } + + $form + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel(pht('Name Contains')) + ->setName('name') + ->setValue($saved->getParameter('name'))) + ->appendChild($type_control); }