Page MenuHomePhabricator

D12460.diff
No OneTemporary

D12460.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2295,11 +2295,15 @@
'PhabricatorProjectIcon' => 'applications/project/icon/PhabricatorProjectIcon.php',
'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php',
'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php',
+ 'PhabricatorProjectLogicDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicDatasource.php',
+ 'PhabricatorProjectLogicalAndDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php',
+ 'PhabricatorProjectLogicalOrNotDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php',
'PhabricatorProjectMemberOfProjectEdgeType' => 'applications/project/edge/PhabricatorProjectMemberOfProjectEdgeType.php',
'PhabricatorProjectMembersDatasource' => 'applications/project/typeahead/PhabricatorProjectMembersDatasource.php',
'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php',
'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php',
'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php',
+ 'PhabricatorProjectNoProjectsDatasource' => 'applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php',
'PhabricatorProjectObjectHasProjectEdgeType' => 'applications/project/edge/PhabricatorProjectObjectHasProjectEdgeType.php',
'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php',
'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php',
@@ -5674,11 +5678,15 @@
'PhabricatorProjectFeedController' => 'PhabricatorProjectController',
'PhabricatorProjectIcon' => 'Phobject',
'PhabricatorProjectListController' => 'PhabricatorProjectController',
+ 'PhabricatorProjectLogicDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
+ 'PhabricatorProjectLogicalAndDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
+ 'PhabricatorProjectLogicalOrNotDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectMemberOfProjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorProjectMembersDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectMembersEditController' => 'PhabricatorProjectController',
'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController',
'PhabricatorProjectMoveController' => 'PhabricatorProjectController',
+ 'PhabricatorProjectNoProjectsDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorProjectObjectHasProjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicDatasource.php
@@ -0,0 +1,22 @@
+<?php
+
+final class PhabricatorProjectLogicDatasource
+ extends PhabricatorTypeaheadCompositeDatasource {
+
+ public function getPlaceholderText() {
+ return pht('Type a project name or selector...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorProjectApplication';
+ }
+
+ public function getComponentDatasources() {
+ return array(
+ new PhabricatorProjectNoProjectsDatasource(),
+ new PhabricatorProjectLogicalAndDatasource(),
+ new PhabricatorProjectLogicalOrNotDatasource(),
+ );
+ }
+
+}
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php
@@ -0,0 +1,32 @@
+<?php
+
+final class PhabricatorProjectLogicalAndDatasource
+ extends PhabricatorTypeaheadCompositeDatasource {
+
+ public function getPlaceholderText() {
+ return pht('Type a project name...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorProjectApplication';
+ }
+
+ public function getComponentDatasources() {
+ return array(
+ new PhabricatorProjectDatasource(),
+ );
+ }
+
+ public function evaluateTokens(array $tokens) {
+ $results = parent::evaluateTokens($tokens);
+
+ foreach ($results as $key => $result) {
+ $results[$key] = new PhabricatorQueryConstraint(
+ PhabricatorQueryConstraint::OPERATOR_AND,
+ $result);
+ }
+
+ return $results;
+ }
+
+}
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php
@@ -0,0 +1,115 @@
+<?php
+
+final class PhabricatorProjectLogicalOrNotDatasource
+ extends PhabricatorTypeaheadCompositeDatasource {
+
+ public function getPlaceholderText() {
+ return pht('Type any(<project>) or not(<project>)...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorProjectApplication';
+ }
+
+ public function getComponentDatasources() {
+ return array(
+ new PhabricatorProjectDatasource(),
+ );
+ }
+
+ public function getDatasourceFunctions() {
+ return array(
+ 'any' => array(
+ 'name' => pht('Find results in any of several projects.'),
+ ),
+ 'not' => array(
+ 'name' => pht('Find results not in specific projects.'),
+ ),
+ );
+ }
+
+ protected function didLoadResults(array $results) {
+ $function = $this->getCurrentFunction();
+ $return_any = ($function !== 'not');
+ $return_not = ($function !== 'any');
+
+ $return = array();
+ foreach ($results as $result) {
+ $result
+ ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION)
+ ->setIcon('fa-asterisk');
+
+ if ($return_any) {
+ $return[] = id(clone $result)
+ ->setPHID('any('.$result->getPHID().')')
+ ->setDisplayName(pht('In Any: %s', $result->getDisplayName()))
+ ->setName($result->getName().' any');
+ }
+
+ if ($return_not) {
+ $return[] = id(clone $result)
+ ->setPHID('not('.$result->getPHID().')')
+ ->setDisplayName(pht('Not In: %s', $result->getDisplayName()))
+ ->setName($result->getName().' not');
+ }
+ }
+
+ return $return;
+ }
+
+ protected function evaluateFunction($function, array $argv_list) {
+ $phids = array();
+ foreach ($argv_list as $argv) {
+ $phids[] = head($argv);
+ }
+
+ $operator = array(
+ 'any' => PhabricatorQueryConstraint::OPERATOR_OR,
+ 'not' => PhabricatorQueryConstraint::OPERATOR_NOT,
+ );
+
+ $results = array();
+ foreach ($phids as $phid) {
+ $results[] = new PhabricatorQueryConstraint(
+ $operator[$function],
+ $phid);
+ }
+
+ return $phids;
+ }
+
+ public function renderFunctionTokens($function, array $argv_list) {
+ $phids = array();
+ foreach ($argv_list as $argv) {
+ $phids[] = head($argv);
+ }
+
+ $tokens = $this->renderTokens($phids);
+ foreach ($tokens as $token) {
+ if ($token->isInvalid()) {
+ if ($function == 'any') {
+ $token->setValue(pht('In Any: Invalid Project'));
+ } else {
+ $token->setValue(pht('Not In: Invalid Project'));
+ }
+ } else {
+ $token
+ ->setIcon('fa-asterisk')
+ ->setTokenType(PhabricatorTypeaheadTokenView::TYPE_FUNCTION);
+
+ if ($function == 'any') {
+ $token
+ ->setKey('any('.$token->getKey().')')
+ ->setValue(pht('In Any: %s', $token->getValue()));
+ } else {
+ $token
+ ->setKey('not('.$token->getKey().')')
+ ->setValue(pht('Not In: %s', $token->getValue()));
+ }
+ }
+ }
+
+ return $tokens;
+ }
+
+}
diff --git a/src/applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php b/src/applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/typeahead/PhabricatorProjectNoProjectsDatasource.php
@@ -0,0 +1,62 @@
+<?php
+
+final class PhabricatorProjectNoProjectsDatasource
+ extends PhabricatorTypeaheadDatasource {
+
+ public function getPlaceholderText() {
+ return pht('Type "not in any projects"...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorProjectApplication';
+ }
+
+ public function getDatasourceFunctions() {
+ return array(
+ 'null' => array(
+ 'name' => pht('Find results which are not in any projects.'),
+ ),
+ );
+ }
+
+ public function loadResults() {
+ $results = array(
+ $this->buildNullResult(),
+ );
+
+ return $this->filterResultsAgainstTokens($results);
+ }
+
+ protected function evaluateFunction($function, array $argv_list) {
+ $results = array();
+
+ foreach ($argv_list as $argv) {
+ $results[] = new PhabricatorQueryConstraint(
+ PhabricatorQueryConstraint::OPERATOR_NULL,
+ 'empty');
+ }
+
+ return $results;
+ }
+
+ public function renderFunctionTokens($function, array $argv_list) {
+ $results = array();
+ foreach ($argv_list as $argv) {
+ $results[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
+ $this->buildNullResult());
+ }
+ return $results;
+ }
+
+ private function buildNullResult() {
+ $name = pht('Not In Any Projects');
+
+ return $this->newFunctionResult()
+ ->setUnique(true)
+ ->setPHID('null()')
+ ->setIcon('fa-ban')
+ ->setName('null '.$name)
+ ->setDisplayName($name);
+ }
+
+}
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
@@ -30,17 +30,39 @@
// query to child sources. This makes it easier to implement function
// sources in terms of real object sources.
$raw_query = $this->getRawQuery();
+
+ $is_function = false;
if (self::isFunctionToken($raw_query)) {
- $function = $this->parseFunction($raw_query, $allow_partial = true);
- if ($function) {
- $raw_query = head($function['argv']);
- }
+ $is_function = true;
}
+ $stack = $this->getFunctionStack();
+
$results = array();
foreach ($this->getUsableDatasources() as $source) {
+ $source_stack = $stack;
+
+ $source_query = $raw_query;
+ if ($is_function) {
+ // If this source can't handle the function, skip it.
+ $function = $source->parseFunction($raw_query, $allow_partial = true);
+ if (!$function) {
+ continue;
+ }
+
+ // If this source handles the function directly, strip the function.
+ // Otherwise, this is something like a composite source which has
+ // some internal source which can evaluate the function, but will
+ // perform stripping later.
+ if ($source->shouldStripFunction($function['name'])) {
+ $source_query = head($function['argv']);
+ $source_stack[] = $function['name'];
+ }
+ }
+
$source
- ->setRawQuery($raw_query)
+ ->setFunctionStack($source_stack)
+ ->setRawQuery($source_query)
->setQuery($this->getQuery())
->setViewer($this->getViewer());
@@ -106,7 +128,6 @@
return parent::canEvaluateFunction($function);
}
-
protected function evaluateFunction($function, array $argv) {
foreach ($this->getUsableDatasources() as $source) {
if ($source->canEvaluateFunction($function)) {
diff --git a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
--- a/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
+++ b/src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
@@ -11,6 +11,7 @@
private $offset;
private $limit;
private $parameters = array();
+ private $functionStack = array();
public function setLimit($limit) {
$this->limit = $limit;
@@ -274,6 +275,14 @@
* @task functions
*/
protected function canEvaluateFunction($function) {
+ return $this->shouldStripFunction($function);
+ }
+
+
+ /**
+ * @task functions
+ */
+ protected function shouldStripFunction($function) {
$functions = $this->getDatasourceFunctions();
return isset($functions[$function]);
}
@@ -337,7 +346,7 @@
$matches = null;
if ($allow_partial) {
- $ok = preg_match('/^([^(]+)\((.*)$/', $token, $matches);
+ $ok = preg_match('/^([^(]+)\((.*?)\)?$/', $token, $matches);
} else {
$ok = preg_match('/^([^(]+)\((.*)\)$/', $token, $matches);
}
@@ -367,4 +376,28 @@
}
+ /**
+ * @task functions
+ */
+ public function setFunctionStack(array $function_stack) {
+ $this->functionStack = $function_stack;
+ return $this;
+ }
+
+
+ /**
+ * @task functions
+ */
+ public function getFunctionStack() {
+ return $this->functionStack;
+ }
+
+
+ /**
+ * @task functions
+ */
+ protected function getCurrentFunction() {
+ return nonempty(last($this->functionStack), null);
+ }
+
}

File Metadata

Mime Type
text/plain
Expires
Wed, May 8, 11:55 PM (4 w, 1 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6273556
Default Alt Text
D12460.diff (13 KB)

Event Timeline