diff --git a/src/applications/search/compiler/PhutilSearchQueryCompiler.php b/src/applications/search/compiler/PhutilSearchQueryCompiler.php index 17a2483755..891cfcce28 100644 --- a/src/applications/search/compiler/PhutilSearchQueryCompiler.php +++ b/src/applications/search/compiler/PhutilSearchQueryCompiler.php @@ -358,7 +358,14 @@ final class PhutilSearchQueryCompiler $result['function'] = $function; - $is_sticky = !$result['quoted']; + // Note that the function remains sticky across quoted terms appearing + // after the function term. For example, all of these terms are title + // terms: + // + // title:a "b c" d + + $is_sticky = (!$result['quoted'] || ($token['function'] === null)); + switch ($operator) { case self::OPERATOR_ABSENT: case self::OPERATOR_PRESENT: diff --git a/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php b/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php index bae95a8647..dca1b16e94 100644 --- a/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php +++ b/src/applications/search/compiler/__tests__/PhutilSearchQueryCompilerTestCase.php @@ -185,6 +185,14 @@ final class PhutilSearchQueryCompilerTestCase array(null, $op_and, 'x'), ), + // Functions like "title:" continue to stick across quotes if the + // quotes aren't the initial argument. + 'title:a "b c" d' => array( + array('title', $op_and, 'a'), + array('title', $op_and, 'b c'), + array('title', $op_and, 'd'), + ), + // These queries require a field be both present and absent, which is // impossible. 'title:- title:x' => false,