Index: src/__phutil_library_map__.php =================================================================== --- src/__phutil_library_map__.php +++ src/__phutil_library_map__.php @@ -507,6 +507,8 @@ 'DiffusionEmptyResultView' => 'applications/diffusion/view/DiffusionEmptyResultView.php', 'DiffusionExistsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php', 'DiffusionExternalController' => 'applications/diffusion/controller/DiffusionExternalController.php', + 'DiffusionExternalSymbolQuery' => 'applications/diffusion/symbol/DiffusionExternalSymbolQuery.php', + 'DiffusionExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionExternalSymbolsSource.php', 'DiffusionFileContent' => 'applications/diffusion/data/DiffusionFileContent.php', 'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionFileContentQuery.php', 'DiffusionFileContentQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionFileContentQueryConduitAPIMethod.php', @@ -2955,6 +2957,7 @@ 'PhortuneSubscriptionWorker' => 'applications/phortune/worker/PhortuneSubscriptionWorker.php', 'PhortuneTestPaymentProvider' => 'applications/phortune/provider/PhortuneTestPaymentProvider.php', 'PhortuneWePayPaymentProvider' => 'applications/phortune/provider/PhortuneWePayPaymentProvider.php', + 'PhpExternalSymbolsSource' => 'applications/diffusion/symbol/PhpExternalSymbolsSource.php', 'PhragmentBrowseController' => 'applications/phragment/controller/PhragmentBrowseController.php', 'PhragmentCanCreateCapability' => 'applications/phragment/capability/PhragmentCanCreateCapability.php', 'PhragmentConduitAPIMethod' => 'applications/phragment/conduit/PhragmentConduitAPIMethod.php', @@ -3097,6 +3100,7 @@ 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', 'ProjectRemarkupRuleTestCase' => 'applications/project/remarkup/__tests__/ProjectRemarkupRuleTestCase.php', 'ProjectReplyHandler' => 'applications/project/mail/ProjectReplyHandler.php', + 'PythonExternalSymbolsSource' => 'applications/diffusion/symbol/PythonExternalSymbolsSource.php', 'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php', 'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php', 'ReleephBranch' => 'applications/releeph/storage/ReleephBranch.php', @@ -6479,6 +6483,7 @@ 'PhortuneSubscriptionWorker' => 'PhabricatorWorker', 'PhortuneTestPaymentProvider' => 'PhortunePaymentProvider', 'PhortuneWePayPaymentProvider' => 'PhortunePaymentProvider', + 'PhpExternalSymbolsSource' => 'DiffusionExternalSymbolsSource', 'PhragmentBrowseController' => 'PhragmentController', 'PhragmentCanCreateCapability' => 'PhabricatorPolicyCapability', 'PhragmentConduitAPIMethod' => 'ConduitAPIMethod', @@ -6663,6 +6668,7 @@ 'ProjectRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'ProjectRemarkupRuleTestCase' => 'PhabricatorTestCase', 'ProjectReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', + 'PythonExternalSymbolsSource' => 'DiffusionExternalSymbolsSource', 'QueryFormattingTestCase' => 'PhabricatorTestCase', 'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification', 'ReleephBranch' => array( Index: src/applications/diffusion/controller/DiffusionSymbolController.php =================================================================== --- src/applications/diffusion/controller/DiffusionSymbolController.php +++ src/applications/diffusion/controller/DiffusionSymbolController.php @@ -12,7 +12,7 @@ ->setViewer($user) ->setName($this->name); - if ($request->getStr('context') !== null) { + if ($request->getStr('context')) { $query->setContext($request->getStr('context')); } @@ -47,63 +47,67 @@ $symbols = $query->execute(); - // For PHP builtins, jump to php.net documentation. - if ($request->getBool('jump') && count($symbols) == 0) { - if ($request->getStr('lang', 'php') == 'php') { - if ($request->getStr('type', 'function') == 'function') { - $functions = get_defined_functions(); - if (in_array($this->name, $functions['internal'])) { - return id(new AphrontRedirectResponse()) - ->setIsExternal(true) - ->setURI('http://www.php.net/function.'.$this->name); - } - } - if ($request->getStr('type', 'class') == 'class') { - if (class_exists($this->name, false) || - interface_exists($this->name, false)) { - if (id(new ReflectionClass($this->name))->isInternal()) { - return id(new AphrontRedirectResponse()) - ->setIsExternal(true) - ->setURI('http://www.php.net/class.'.$this->name); - } - } - } - } + + + $external_query = id(new DiffusionExternalSymbolQuery()) + ->withNames(array($this->name)); + + if ($request->getStr('context')) { + $external_query->withContexts(array($request->getStr('context'))); + } + + if ($request->getStr('type')) { + $external_query->withTypes(array($request->getStr('type'))); + } + + if ($request->getStr('lang')) { + $external_query->withLanguages(array($request->getStr('lang'))); + } + + $external_sources = id(new PhutilSymbolLoader()) + ->setAncestorClass('DiffusionExternalSymbolsSource') + ->loadObjects(); + $results = array($symbols); + foreach ($external_sources as $source) { + $results[] = $source->lookupSymbol($external_query); + } + $symbols = array_mergev($results); + + if ($request->getBool('jump') && count($symbols) == 1) { + // If this is a clickthrough from Differential, just jump them + // straight to the target if we got a single hit. + $href = head($symbols)->getURI(); + return id(new AphrontRedirectResponse())->setURI($href); } $rows = array(); foreach ($symbols as $symbol) { - $file = $symbol->getPath(); - $line = $symbol->getLineNumber(); - - $repo = $symbol->getRepository(); - if ($repo) { - $href = $symbol->getURI(); + $href = $symbol->getURI(); - if ($request->getBool('jump') && count($symbols) == 1) { - // If this is a clickthrough from Differential, just jump them - // straight to the target if we got a single hit. - return id(new AphrontRedirectResponse())->setURI($href); - } + if ($symbol->isExternal()) { + $source = $symbol->getSource(); + $location = $symbol->getLocation(); + } else { + $repo = $symbol->getRepository(); + $file = $symbol->getPath(); + $line = $symbol->getLineNumber(); - $location = phutil_tag( - 'a', - array( - 'href' => $href, - ), - $file.':'.$line); - } else if ($file) { + $source = $repo->getMonogram(); $location = $file.':'.$line; - } else { - $location = '?'; } + $location = phutil_tag( + 'a', + array( + 'href' => $href, + ), + $location); $rows[] = array( $symbol->getSymbolType(), $symbol->getSymbolContext(), $symbol->getSymbolName(), $symbol->getSymbolLanguage(), - $repo->getMonogram(), + $source, $location, ); } @@ -115,8 +119,8 @@ pht('Context'), pht('Name'), pht('Language'), - pht('Repository'), - pht('File'), + pht('Source'), + pht('Location'), )); $table->setColumnClasses( array( Index: src/applications/diffusion/symbol/DiffusionExternalSymbolQuery.php =================================================================== --- /dev/null +++ src/applications/diffusion/symbol/DiffusionExternalSymbolQuery.php @@ -0,0 +1,40 @@ +languages = $languages; + return $this; + } + public function withTypes(array $types) { + $this->types = $types; + return $this; + } + public function withNames(array $names) { + $this->names = $names; + return $this; + } + public function withContexts(array $contexts) { + $this->contexts = $contexts; + return $this; + } + + + public function getLanguages() { + return $this->languages; + } + public function getTypes() { + return $this->types; + } + public function getNames() { + return $this->names; + } + public function getContexts() { + return $this->contexts; + } + +} Index: src/applications/diffusion/symbol/DiffusionExternalSymbolsSource.php =================================================================== --- /dev/null +++ src/applications/diffusion/symbol/DiffusionExternalSymbolsSource.php @@ -0,0 +1,28 @@ +setIsExternal(true) + ->makeEphemeral() + ->setSymbolName($name) + ->setSymbolType($type) + ->setSource($source) + ->setLocation($location) + ->setSymbolLanguage($language) + ->setExternalURI($uri); + } +} Index: src/applications/diffusion/symbol/PhpExternalSymbolsSource.php =================================================================== --- /dev/null +++ src/applications/diffusion/symbol/PhpExternalSymbolsSource.php @@ -0,0 +1,48 @@ +getLanguages(); + if ($langs && !in_array('php', $langs)) { + return array(); + } + + $names = $query->getNames(); + $symbols = array(); + + $types = $query->getTypes(); + if (!$types || in_array('function', $types)) { + $functions = get_defined_functions(); + $functions = $functions['internal']; + + foreach ($names as $name) { + if (in_array($name, $functions)) { + $symbols[] = $this->buildExternalSymbol( + $name, + 'function', + 'PHP', + 'Manual at php.net', + 'PHP', + 'http://www.php.net/function.'.$name); + } + } + } + if (!$types || in_array('class', $types)) { + foreach ($names as $name) { + if (class_exists($name, false) || interface_exists($name, false)) { + if (id(new ReflectionClass($name))->isInternal()) { + $symbols[] = $this->buildExternalSymbol( + $name, + 'class', + 'PHP', + 'Manual at php.net', + 'http://www.php.net/class.'.$name); + } + } + } + } + + return $symbols; + } +} Index: src/applications/diffusion/symbol/PythonExternalSymbolsSource.php =================================================================== --- /dev/null +++ src/applications/diffusion/symbol/PythonExternalSymbolsSource.php @@ -0,0 +1,133 @@ +getLanguages(); + if ($langs && !array_intersect(array('py', 'python'), $langs)) { + return array(); + } + + $names = $query->getNames(); + $symbols = array(); + + $types = $query->getTypes(); + if ($types && !in_array('builtin', $types)) { + return $symbols; + } + + foreach ($names as $name) { + if (idx(self::$python2Builtins, $name)) { + $symbols[] = $this->buildExternalSymbol( + $name, + 'builtin', + 'Standard Library', + 'The Python 2 Standard Library', + 'Python', + 'https://docs.python.org/2/library/functions.html#'.$name); + } + if (idx(self::$python3Builtins, $name)) { + $symbols[] = $this->buildExternalSymbol( + $name, + 'builtin', + 'Standard Library', + 'The Python 3 Standard Library', + 'Python', + 'https://docs.python.org/3/library/functions.html#'.$name); + } + } + return $symbols; + } + + private static $python2Builtins = array( + '__import__' => true, + 'abs' => true, + 'all' => true, + 'any' => true, + 'basestring' => true, + 'bin' => true, + 'bool' => true, + 'bytearray' => true, + 'callable' => true, + 'chr' => true, + 'classmethod' => true, + 'cmp' => true, + 'compile' => true, + 'complex' => true, + 'delattr' => true, + 'dict' => true, + 'dir' => true, + 'divmod' => true, + 'enumerate' => true, + 'eval' => true, + 'execfile' => true, + 'file' => true, + 'filter' => true, + 'float' => true, + 'format' => true, + 'frozenset' => true, + 'getattr' => true, + 'globals' => true, + 'hasattr' => true, + 'hash' => true, + 'help' => true, + 'hex' => true, + 'id' => true, + 'input' => true, + 'int' => true, + 'isinstance' => true, + 'issubclass' => true, + 'iter' => true, + 'len' => true, + 'list' => true, + 'locals' => true, + 'long' => true, + 'map' => true, + 'max' => true, + 'memoryview' => true, + 'min' => true, + 'next' => true, + 'object' => true, + 'oct' => true, + 'open' => true, + 'ord' => true, + 'pow' => true, + 'print' => true, + 'property' => true, + 'range' => true, + 'raw_input' => true, + 'reduce' => true, + 'reload' => true, + 'repr' => true, + 'reversed' => true, + 'round' => true, + 'set' => true, + 'setattr' => true, + 'slice' => true, + 'sorted' => true, + 'staticmethod' => true, + 'str' => true, + 'sum' => true, + 'super' => true, + 'tuple' => true, + 'type' => true, + 'unichr' => true, + 'unicode' => true, + 'vars' => true, + 'xrange' => true, + 'zip' => true, + ); + + // This list only contains functions that are new or changed between the + // Python versions. + private static $python3Builtins = array( + 'ascii' => true, + 'bytes' => true, + 'filter' => true, + 'map' => true, + 'next' => true, + 'range' => true, + 'super' => true, + 'zip' => true, + ); +} Index: src/applications/repository/storage/PhabricatorRepositorySymbol.php =================================================================== --- src/applications/repository/storage/PhabricatorRepositorySymbol.php +++ src/applications/repository/storage/PhabricatorRepositorySymbol.php @@ -15,6 +15,10 @@ protected $symbolLanguage; protected $pathID; protected $lineNumber; + private $isExternal; + private $source; + private $location; + private $externalURI; private $path = self::ATTACHABLE; private $repository = self::ATTACHABLE; @@ -40,6 +44,10 @@ } public function getURI() { + if ($this->isExternal) { + return $this->externalURI; + } + $request = DiffusionRequest::newFromDictionary( array( 'user' => PhabricatorUser::getOmnipotentUser(), @@ -71,4 +79,32 @@ return $this; } + public function isExternal() { + return $this->isExternal; + } + public function setIsExternal($is_external) { + $this->isExternal = $is_external; + return $this; + } + + public function getSource() { + return $this->source; + } + public function setSource($source) { + $this->source = $source; + return $this; + } + + public function getLocation() { + return $this->location; + } + public function setLocation($location) { + $this->location = $location; + return $this; + } + + public function setExternalURI($external_uri) { + $this->externalURI = $external_uri; + return $this; + } }