From f43e0dc34aebb05e66cfc011d73d90d7321abb93 Mon Sep 17 00:00:00 2001 From: Trevor Bortins Date: Sun, 5 Feb 2017 17:55:59 -0800 Subject: [PATCH 01/13] Read vendor directory from project's composer.json, if set. If not set, default to "vendor". Also sort found vendor directories so we obtain the correct composer.json and composer.lock files --- src/Indexer.php | 17 +++++++++++++++-- src/LanguageServer.php | 17 ++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/Indexer.php b/src/Indexer.php index df9655a0..81b0f583 100644 --- a/src/Indexer.php +++ b/src/Indexer.php @@ -59,6 +59,11 @@ class Indexer */ private $composerLock; + /** + * @var \stdClasss + */ + private $composerJson; + /** * @param FilesFinder $filesFinder * @param string $rootPath @@ -77,7 +82,8 @@ public function __construct( DependenciesIndex $dependenciesIndex, Index $sourceIndex, PhpDocumentLoader $documentLoader, - \stdClass $composerLock = null + \stdClass $composerLock = null, + \stdClass $composerJson = null ) { $this->filesFinder = $filesFinder; $this->rootPath = $rootPath; @@ -87,6 +93,7 @@ public function __construct( $this->sourceIndex = $sourceIndex; $this->documentLoader = $documentLoader; $this->composerLock = $composerLock; + $this->composerJson = $composerJson; } /** @@ -109,8 +116,12 @@ public function index(): Promise $source = []; /** @var string[][] */ $deps = []; + + $vendorDir = str_replace('/', '\/', @$this->composerJson->config->{'vendor-dir'} ?: 'vendor'); + $this->client->window->logMessage(MessageType::INFO, "Vendor dir: $vendorDir"); + foreach ($uris as $uri) { - if ($this->composerLock !== null && preg_match('/\/vendor\/([^\/]+\/[^\/]+)\//', $uri, $matches)) { + if ($this->composerLock !== null && preg_match("/\/$vendorDir\/([^\/]+\/[^\/]+)\//", $uri, $matches)) { // Dependency file $packageName = $matches[1]; if (!isset($deps[$packageName])) { @@ -174,6 +185,8 @@ public function index(): Promise if ($cacheKey !== null) { $this->client->window->logMessage(MessageType::INFO, "Storing $packageKey in cache"); $this->cache->set($cacheKey, $index); + } else { + $this->client->window->logMessage(MessageType::INFO, "Cannot cache $packageName, cache key was null. Either you are using a 'dev-' version or your composer.lock is missing references."); } } } diff --git a/src/LanguageServer.php b/src/LanguageServer.php index 035e663a..ac392dce 100644 --- a/src/LanguageServer.php +++ b/src/LanguageServer.php @@ -206,6 +206,13 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = // Find composer.json if ($this->composerJson === null) { $composerJsonFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.json', $rootPath)); + + // If we sort our findings by string length (shortest to longest), + // the first entry will be the project's root composer.json. + usort($composerJsonFiles, function ($a, $b) { + return strlen($a) - strlen($b); + }); + if (!empty($composerJsonFiles)) { $this->composerJson = json_decode(yield $this->contentRetriever->retrieve($composerJsonFiles[0])); } @@ -214,6 +221,13 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = // Find composer.lock if ($this->composerLock === null) { $composerLockFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.lock', $rootPath)); + + // If we sort our findings by string length (shortest to longest), + // the first entry will be the project's root composer.lock. + usort($composerLockFiles, function ($a, $b) { + return strlen($a) - strlen($b); + }); + if (!empty($composerLockFiles)) { $this->composerLock = json_decode(yield $this->contentRetriever->retrieve($composerLockFiles[0])); } @@ -230,7 +244,8 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = $dependenciesIndex, $sourceIndex, $this->documentLoader, - $this->composerLock + $this->composerLock, + $this->composerJson ); $indexer->index()->otherwise('\\LanguageServer\\crash'); } From 81aed92ecfd32b2c6417e215d20bd4f3ed1fd088 Mon Sep 17 00:00:00 2001 From: Trevor Bortins Date: Mon, 6 Feb 2017 11:45:38 -0800 Subject: [PATCH 02/13] Sort by least number of slashes Change log message --- src/Indexer.php | 2 +- src/LanguageServer.php | 14 +++++--------- src/utils.php | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/Indexer.php b/src/Indexer.php index 81b0f583..3f7cf4b1 100644 --- a/src/Indexer.php +++ b/src/Indexer.php @@ -186,7 +186,7 @@ public function index(): Promise $this->client->window->logMessage(MessageType::INFO, "Storing $packageKey in cache"); $this->cache->set($cacheKey, $index); } else { - $this->client->window->logMessage(MessageType::INFO, "Cannot cache $packageName, cache key was null. Either you are using a 'dev-' version or your composer.lock is missing references."); + $this->client->window->logMessage(MessageType::WARNING, "Could not compute cache key for $packageName"); } } } diff --git a/src/LanguageServer.php b/src/LanguageServer.php index ac392dce..01f8d5c8 100644 --- a/src/LanguageServer.php +++ b/src/LanguageServer.php @@ -25,6 +25,7 @@ use Throwable; use Webmozart\PathUtil\Path; use Sabre\Uri; +use function LanguageServer\sortByLeastSlashes; class LanguageServer extends AdvancedJsonRpc\Dispatcher { @@ -206,12 +207,9 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = // Find composer.json if ($this->composerJson === null) { $composerJsonFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.json', $rootPath)); - - // If we sort our findings by string length (shortest to longest), + // If we sort our findings by number of slashes (least to greatest), // the first entry will be the project's root composer.json. - usort($composerJsonFiles, function ($a, $b) { - return strlen($a) - strlen($b); - }); + usort($composerJsonFiles, 'LanguageServer\sortByLeastSlashes'); if (!empty($composerJsonFiles)) { $this->composerJson = json_decode(yield $this->contentRetriever->retrieve($composerJsonFiles[0])); @@ -222,11 +220,9 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = if ($this->composerLock === null) { $composerLockFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.lock', $rootPath)); - // If we sort our findings by string length (shortest to longest), + // If we sort our findings by number of slashes (least to greatest), // the first entry will be the project's root composer.lock. - usort($composerLockFiles, function ($a, $b) { - return strlen($a) - strlen($b); - }); + usort($composerLockFiles, 'LanguageServer\sortByLeastSlashes'); if (!empty($composerLockFiles)) { $this->composerLock = json_decode(yield $this->contentRetriever->retrieve($composerLockFiles[0])); diff --git a/src/utils.php b/src/utils.php index 8ab7beb3..071be13e 100644 --- a/src/utils.php +++ b/src/utils.php @@ -7,6 +7,7 @@ use InvalidArgumentException; use PhpParser\Node; use Sabre\Event\{Loop, Promise, EmitterInterface}; +use function Sabre\Uri\parse; /** * Transforms an absolute file path into a URI as used by the language server protocol. @@ -131,3 +132,19 @@ function stripStringOverlap(string $a, string $b): string } return $b; } + +/** + * Use for sorting an array of URIs by number of segments + * in ascending order. + * + * Example: + * usort($uriList, 'LanguageServer\sortByLeastSlashes'); + * + * @param $a string + * @param $b string + * @return integer + */ +function sortByLeastSlashes($a, $b) +{ + return substr_count(parse($a)['path'], '/') - substr_count(parse($b)['path'], '/'); +} From 6146e6c87910fd70fce6d28e00e4e762d411df62 Mon Sep 17 00:00:00 2001 From: Trevor Bortins Date: Mon, 6 Feb 2017 13:15:30 -0800 Subject: [PATCH 03/13] use isset --- src/Indexer.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Indexer.php b/src/Indexer.php index 3f7cf4b1..a8c2bb1d 100644 --- a/src/Indexer.php +++ b/src/Indexer.php @@ -117,7 +117,10 @@ public function index(): Promise /** @var string[][] */ $deps = []; - $vendorDir = str_replace('/', '\/', @$this->composerJson->config->{'vendor-dir'} ?: 'vendor'); + $vendorDir = isset($this->composerJson->config->{'vendor-dir'}) ? + $this->composerJson->config->{'vendor-dir'} + : 'vendor'; + $vendorDir = str_replace('/', '\/', $vendorDir); $this->client->window->logMessage(MessageType::INFO, "Vendor dir: $vendorDir"); foreach ($uris as $uri) { From f84b22e05d3f8866bba26b5953edf7503c912c82 Mon Sep 17 00:00:00 2001 From: Trevor Bortins Date: Mon, 6 Feb 2017 13:28:57 -0800 Subject: [PATCH 04/13] Clean up style --- src/LanguageServer.php | 10 ++-------- src/utils.php | 16 +++++++--------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/LanguageServer.php b/src/LanguageServer.php index 01f8d5c8..7445e53b 100644 --- a/src/LanguageServer.php +++ b/src/LanguageServer.php @@ -25,7 +25,6 @@ use Throwable; use Webmozart\PathUtil\Path; use Sabre\Uri; -use function LanguageServer\sortByLeastSlashes; class LanguageServer extends AdvancedJsonRpc\Dispatcher { @@ -207,9 +206,7 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = // Find composer.json if ($this->composerJson === null) { $composerJsonFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.json', $rootPath)); - // If we sort our findings by number of slashes (least to greatest), - // the first entry will be the project's root composer.json. - usort($composerJsonFiles, 'LanguageServer\sortByLeastSlashes'); + sortUrisLevelOrder($composerJsonFiles); if (!empty($composerJsonFiles)) { $this->composerJson = json_decode(yield $this->contentRetriever->retrieve($composerJsonFiles[0])); @@ -219,10 +216,7 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = // Find composer.lock if ($this->composerLock === null) { $composerLockFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.lock', $rootPath)); - - // If we sort our findings by number of slashes (least to greatest), - // the first entry will be the project's root composer.lock. - usort($composerLockFiles, 'LanguageServer\sortByLeastSlashes'); + sortUrisLevelOrder($composerLockFiles); if (!empty($composerLockFiles)) { $this->composerLock = json_decode(yield $this->contentRetriever->retrieve($composerLockFiles[0])); diff --git a/src/utils.php b/src/utils.php index 071be13e..c13f1be6 100644 --- a/src/utils.php +++ b/src/utils.php @@ -7,7 +7,7 @@ use InvalidArgumentException; use PhpParser\Node; use Sabre\Event\{Loop, Promise, EmitterInterface}; -use function Sabre\Uri\parse; +use Sabre\Uri; /** * Transforms an absolute file path into a URI as used by the language server protocol. @@ -137,14 +137,12 @@ function stripStringOverlap(string $a, string $b): string * Use for sorting an array of URIs by number of segments * in ascending order. * - * Example: - * usort($uriList, 'LanguageServer\sortByLeastSlashes'); - * - * @param $a string - * @param $b string - * @return integer + * @param array + * @return array */ -function sortByLeastSlashes($a, $b) +function sortUrisLevelOrder(&$uriList) { - return substr_count(parse($a)['path'], '/') - substr_count(parse($b)['path'], '/'); + usort($uriList, function ($a, $b) { + return substr_count(Uri\parse($a)['path'], '/') - substr_count(Uri\parse($b)['path'], '/'); + }); } From 8d439f82f5a17dbd5b49da4db00dfbeb278cb8f8 Mon Sep 17 00:00:00 2001 From: Trevor Bortins Date: Mon, 6 Feb 2017 14:18:19 -0800 Subject: [PATCH 05/13] Minimize URI parsing in loop --- src/utils.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/utils.php b/src/utils.php index c13f1be6..2ed1c6ab 100644 --- a/src/utils.php +++ b/src/utils.php @@ -138,11 +138,22 @@ function stripStringOverlap(string $a, string $b): string * in ascending order. * * @param array - * @return array + * @return void */ function sortUrisLevelOrder(&$uriList) { - usort($uriList, function ($a, $b) { - return substr_count(Uri\parse($a)['path'], '/') - substr_count(Uri\parse($b)['path'], '/'); + // Parse URIs so we are not continually parsing them while sorting + $parsedUriList = array_map(function ($uri) { + return Uri\parse($uri); + }, $uriList); + + // Sort by number of slashes in parsed URI path, ascending + usort($parsedUriList, function ($a, $b) { + return substr_count($a['path'], '/') - substr_count($b['path'], '/'); }); + + // Reassemble the URIs + $uriList = array_map(function ($parsedUri) { + return Uri\build($parsedUri); + }, $parsedUriList); } From 0a69c7292a3765507f834a50bc0f7111faa365a6 Mon Sep 17 00:00:00 2001 From: Trevor Bortins Date: Mon, 6 Feb 2017 14:38:43 -0800 Subject: [PATCH 06/13] Revert "Minimize URI parsing in loop" This reverts commit 8d439f82f5a17dbd5b49da4db00dfbeb278cb8f8. --- src/utils.php | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/utils.php b/src/utils.php index 2ed1c6ab..c13f1be6 100644 --- a/src/utils.php +++ b/src/utils.php @@ -138,22 +138,11 @@ function stripStringOverlap(string $a, string $b): string * in ascending order. * * @param array - * @return void + * @return array */ function sortUrisLevelOrder(&$uriList) { - // Parse URIs so we are not continually parsing them while sorting - $parsedUriList = array_map(function ($uri) { - return Uri\parse($uri); - }, $uriList); - - // Sort by number of slashes in parsed URI path, ascending - usort($parsedUriList, function ($a, $b) { - return substr_count($a['path'], '/') - substr_count($b['path'], '/'); + usort($uriList, function ($a, $b) { + return substr_count(Uri\parse($a)['path'], '/') - substr_count(Uri\parse($b)['path'], '/'); }); - - // Reassemble the URIs - $uriList = array_map(function ($parsedUri) { - return Uri\build($parsedUri); - }, $parsedUriList); } From 16e27f90c12039e07aaa791d8050fa10d1cf9cd7 Mon Sep 17 00:00:00 2001 From: Trevor Bortins Date: Mon, 6 Feb 2017 14:39:03 -0800 Subject: [PATCH 07/13] returns a void --- src/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.php b/src/utils.php index c13f1be6..6cbb3171 100644 --- a/src/utils.php +++ b/src/utils.php @@ -138,7 +138,7 @@ function stripStringOverlap(string $a, string $b): string * in ascending order. * * @param array - * @return array + * @return void */ function sortUrisLevelOrder(&$uriList) { From 682cb2a072df07e692592f48ad43a76555771a20 Mon Sep 17 00:00:00 2001 From: Trevor Bortins Date: Mon, 6 Feb 2017 18:24:01 -0800 Subject: [PATCH 08/13] handle other vendor references --- src/Index/ProjectIndex.php | 5 ++-- src/Indexer.php | 10 ++------ src/LanguageServer.php | 5 ++-- src/PhpDocument.php | 11 --------- src/Server/TextDocument.php | 2 +- src/Server/Workspace.php | 5 ++-- src/utils.php | 46 ++++++++++++++++++++++++++++++++++++- tests/PhpDocumentTest.php | 10 ++++---- 8 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/Index/ProjectIndex.php b/src/Index/ProjectIndex.php index 8adc9380..8bc24677 100644 --- a/src/Index/ProjectIndex.php +++ b/src/Index/ProjectIndex.php @@ -22,10 +22,11 @@ class ProjectIndex extends AbstractAggregateIndex */ private $sourceIndex; - public function __construct(Index $sourceIndex, DependenciesIndex $dependenciesIndex) + public function __construct(Index $sourceIndex, DependenciesIndex $dependenciesIndex, \stdClass $composerJson = null) { $this->sourceIndex = $sourceIndex; $this->dependenciesIndex = $dependenciesIndex; + $this->composerJson = $composerJson; parent::__construct(); } @@ -43,7 +44,7 @@ protected function getIndexes(): array */ public function getIndexForUri(string $uri): Index { - if (preg_match('/\/vendor\/([^\/]+\/[^\/]+)\//', $uri, $matches)) { + if (\LanguageServer\uriInVendorDir($this->composerJson, $uri, $matches)) { $packageName = $matches[1]; return $this->dependenciesIndex->getDependencyIndex($packageName); } diff --git a/src/Indexer.php b/src/Indexer.php index a8c2bb1d..bf5ed90b 100644 --- a/src/Indexer.php +++ b/src/Indexer.php @@ -117,14 +117,8 @@ public function index(): Promise /** @var string[][] */ $deps = []; - $vendorDir = isset($this->composerJson->config->{'vendor-dir'}) ? - $this->composerJson->config->{'vendor-dir'} - : 'vendor'; - $vendorDir = str_replace('/', '\/', $vendorDir); - $this->client->window->logMessage(MessageType::INFO, "Vendor dir: $vendorDir"); - foreach ($uris as $uri) { - if ($this->composerLock !== null && preg_match("/\/$vendorDir\/([^\/]+\/[^\/]+)\//", $uri, $matches)) { + if ($this->composerLock !== null && uriInVendorDir($this->composerJson, $uri, $matches)) { // Dependency file $packageName = $matches[1]; if (!isset($deps[$packageName])) { @@ -221,7 +215,7 @@ private function indexFiles(array $files): Promise $this->client->window->logMessage(MessageType::LOG, "Parsing $uri"); try { $document = yield $this->documentLoader->load($uri); - if (!$document->isVendored()) { + if (!isVendored($document, $this->composerJson)) { $this->client->textDocument->publishDiagnostics($uri, $document->getDiagnostics()); } } catch (ContentTooLargeException $e) { diff --git a/src/LanguageServer.php b/src/LanguageServer.php index 7445e53b..3c999f22 100644 --- a/src/LanguageServer.php +++ b/src/LanguageServer.php @@ -187,7 +187,7 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = $dependenciesIndex = new DependenciesIndex; $sourceIndex = new Index; - $this->projectIndex = new ProjectIndex($sourceIndex, $dependenciesIndex); + $this->projectIndex = new ProjectIndex($sourceIndex, $dependenciesIndex, $this->composerJson); $stubsIndex = StubsIndex::read(); $this->globalIndex = new GlobalIndex($stubsIndex, $this->projectIndex); @@ -257,7 +257,8 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = $dependenciesIndex, $sourceIndex, $this->composerLock, - $this->documentLoader + $this->documentLoader, + $this->composerJson ); } diff --git a/src/PhpDocument.php b/src/PhpDocument.php index b838cd3a..3a25c236 100644 --- a/src/PhpDocument.php +++ b/src/PhpDocument.php @@ -220,17 +220,6 @@ public function updateContent(string $content) } } - /** - * Returns true if the document is a dependency - * - * @return bool - */ - public function isVendored(): bool - { - $path = Uri\parse($this->uri)['path']; - return strpos($path, '/vendor/') !== false; - } - /** * Returns array of TextEdit changes to format this document. * diff --git a/src/Server/TextDocument.php b/src/Server/TextDocument.php index 532d6425..b0878071 100644 --- a/src/Server/TextDocument.php +++ b/src/Server/TextDocument.php @@ -134,7 +134,7 @@ public function documentSymbol(TextDocumentIdentifier $textDocument): Promise public function didOpen(TextDocumentItem $textDocument) { $document = $this->documentLoader->open($textDocument->uri, $textDocument->text); - if (!$document->isVendored()) { + if (!\LanguageServer\isVendored($document, $this->composerJson)) { $this->client->textDocument->publishDiagnostics($textDocument->uri, $document->getDiagnostics()); } } diff --git a/src/Server/Workspace.php b/src/Server/Workspace.php index 5aae7cfa..46cab286 100644 --- a/src/Server/Workspace.php +++ b/src/Server/Workspace.php @@ -49,13 +49,14 @@ class Workspace * @param \stdClass $composerLock The parsed composer.lock of the project, if any * @param PhpDocumentLoader $documentLoader PhpDocumentLoader instance to load documents */ - public function __construct(ProjectIndex $index, DependenciesIndex $dependenciesIndex, Index $sourceIndex, \stdClass $composerLock = null, PhpDocumentLoader $documentLoader) + public function __construct(ProjectIndex $index, DependenciesIndex $dependenciesIndex, Index $sourceIndex, \stdClass $composerLock = null, PhpDocumentLoader $documentLoader, \stdClass $composerJson = null) { $this->sourceIndex = $sourceIndex; $this->index = $index; $this->dependenciesIndex = $dependenciesIndex; $this->composerLock = $composerLock; $this->documentLoader = $documentLoader; + $this->composerJson = $composerJson; } /** @@ -122,7 +123,7 @@ public function xreferences($query, array $files = null): Promise $symbol->$prop = $val; } // Find out package name - preg_match('/\/vendor\/([^\/]+\/[^\/]+)\//', $def->symbolInformation->location->uri, $matches); + uriInVendorDir($this->composerJson, $def->symbolInformation->location->uri, $matches); $packageName = $matches[1]; foreach ($this->composerLock->packages as $package) { if ($package->name === $packageName) { diff --git a/src/utils.php b/src/utils.php index 6cbb3171..3d844e4d 100644 --- a/src/utils.php +++ b/src/utils.php @@ -137,7 +137,7 @@ function stripStringOverlap(string $a, string $b): string * Use for sorting an array of URIs by number of segments * in ascending order. * - * @param array + * @param array $uriList * @return void */ function sortUrisLevelOrder(&$uriList) @@ -146,3 +146,47 @@ function sortUrisLevelOrder(&$uriList) return substr_count(Uri\parse($a)['path'], '/') - substr_count(Uri\parse($b)['path'], '/'); }); } + +/** + * Checks a document against the composer.json to see if it + * is a vendored document + * + * @param PhpDocument $document + * @param \stdClass|null $composerJson + * @return bool + */ +function isVendored(PhpDocument $document, \stdClass $composerJson = null): bool +{ + $path = Uri\parse($document->getUri())['path']; + $vendorDir = getVendorDir($composerJson); + return strpos($path, "/$vendorDir/") !== false; +} + +/** + * Check a given URI against the composer.json to see if it + * is a vendored URI + * + * @param \stdClass|null $composerJson + * @param string $uri + * @param array $matches + * @return int + */ +function uriInVendorDir(\stdClass $composerJson = null, string $uri, &$matches): int +{ + $vendorDir = str_replace('/', '\/', getVendorDir($composerJson)); + return preg_match("/\/$vendorDir\/([^\/]+\/[^\/]+)\//", $uri, $matches); +} + +/** + * Helper function to get the vendor directory from composer.json + * or default to 'vendor' + * + * @param \stdClass|null $composerJson + * @return string + */ +function getVendorDir(\stdClass $composerJson = null): string +{ + return isset($composerJson->config->{'vendor-dir'}) ? + $composerJson->config->{'vendor-dir'} + : 'vendor'; +} diff --git a/tests/PhpDocumentTest.php b/tests/PhpDocumentTest.php index b9b3704e..829a1762 100644 --- a/tests/PhpDocumentTest.php +++ b/tests/PhpDocumentTest.php @@ -42,18 +42,18 @@ public function testGetNodeAtPosition() public function testIsVendored() { $document = $this->createDocument('file:///dir/vendor/x.php', "assertEquals(true, $document->isVendored()); + $this->assertEquals(true, \LanguageServer\isVendored($document)); $document = $this->createDocument('file:///c:/dir/vendor/x.php', "assertEquals(true, $document->isVendored()); + $this->assertEquals(true, \LanguageServer\isVendored($document)); $document = $this->createDocument('file:///vendor/x.php', "assertEquals(true, $document->isVendored()); + $this->assertEquals(true, \LanguageServer\isVendored($document)); $document = $this->createDocument('file:///dir/vendor.php', "assertEquals(false, $document->isVendored()); + $this->assertEquals(false, \LanguageServer\isVendored($document)); $document = $this->createDocument('file:///dir/x.php', "assertEquals(false, $document->isVendored()); + $this->assertEquals(false, \LanguageServer\isVendored($document)); } } From d95874d4328c7e4714eaecfabe77a5b50303650e Mon Sep 17 00:00:00 2001 From: Trevor Bortins Date: Tue, 7 Feb 2017 08:21:34 -0800 Subject: [PATCH 09/13] refactor uriInVendorDir to getPackageName --- src/Index/ProjectIndex.php | 6 ++++-- src/Indexer.php | 4 ++-- src/Server/Workspace.php | 4 ++-- src/utils.php | 7 ++++--- tests/PhpDocumentTest.php | 11 ++++++----- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/Index/ProjectIndex.php b/src/Index/ProjectIndex.php index 8bc24677..538c5c45 100644 --- a/src/Index/ProjectIndex.php +++ b/src/Index/ProjectIndex.php @@ -3,6 +3,8 @@ namespace LanguageServer\Index; +use function LanguageServer\getPackageName; + /** * A project index manages the source and dependency indexes */ @@ -44,8 +46,8 @@ protected function getIndexes(): array */ public function getIndexForUri(string $uri): Index { - if (\LanguageServer\uriInVendorDir($this->composerJson, $uri, $matches)) { - $packageName = $matches[1]; + $packageName = getPackageName($this->composerJson, $uri); + if ($packageName) { return $this->dependenciesIndex->getDependencyIndex($packageName); } return $this->sourceIndex; diff --git a/src/Indexer.php b/src/Indexer.php index bf5ed90b..ddf5a578 100644 --- a/src/Indexer.php +++ b/src/Indexer.php @@ -118,9 +118,9 @@ public function index(): Promise $deps = []; foreach ($uris as $uri) { - if ($this->composerLock !== null && uriInVendorDir($this->composerJson, $uri, $matches)) { + $packageName = getPackageName($this->composerJson, $uri); + if ($this->composerLock !== null && $packageName) { // Dependency file - $packageName = $matches[1]; if (!isset($deps[$packageName])) { $deps[$packageName] = []; } diff --git a/src/Server/Workspace.php b/src/Server/Workspace.php index 46cab286..55821ac4 100644 --- a/src/Server/Workspace.php +++ b/src/Server/Workspace.php @@ -9,6 +9,7 @@ use Sabre\Event\Promise; use function Sabre\Event\coroutine; use function LanguageServer\waitForEvent; +use function LanguageServer\getPackageName; /** * Provides method handlers for all workspace/* methods @@ -123,8 +124,7 @@ public function xreferences($query, array $files = null): Promise $symbol->$prop = $val; } // Find out package name - uriInVendorDir($this->composerJson, $def->symbolInformation->location->uri, $matches); - $packageName = $matches[1]; + $packageName = getPackageName($this->composerJson, $def->symbolInformation->location->uri); foreach ($this->composerLock->packages as $package) { if ($package->name === $packageName) { $symbol->package = $package; diff --git a/src/utils.php b/src/utils.php index 3d844e4d..65db8633 100644 --- a/src/utils.php +++ b/src/utils.php @@ -169,12 +169,13 @@ function isVendored(PhpDocument $document, \stdClass $composerJson = null): bool * @param \stdClass|null $composerJson * @param string $uri * @param array $matches - * @return int + * @return string */ -function uriInVendorDir(\stdClass $composerJson = null, string $uri, &$matches): int +function getPackageName(\stdClass $composerJson = null, string $uri): ?string { $vendorDir = str_replace('/', '\/', getVendorDir($composerJson)); - return preg_match("/\/$vendorDir\/([^\/]+\/[^\/]+)\//", $uri, $matches); + preg_match("/\/$vendorDir\/([^\/]+\/[^\/]+)\//", $uri, $matches); + return isset($matches[1]) ? $matches[1] : null; } /** diff --git a/tests/PhpDocumentTest.php b/tests/PhpDocumentTest.php index 829a1762..011a2310 100644 --- a/tests/PhpDocumentTest.php +++ b/tests/PhpDocumentTest.php @@ -12,6 +12,7 @@ use LanguageServer\Protocol\{SymbolKind, Position, ClientCapabilities}; use LanguageServer\Index\{Index, ProjectIndex, DependenciesIndex}; use PhpParser\Node; +use function LanguageServer\isVendored; class PhpDocumentTest extends TestCase { @@ -42,18 +43,18 @@ public function testGetNodeAtPosition() public function testIsVendored() { $document = $this->createDocument('file:///dir/vendor/x.php', "assertEquals(true, \LanguageServer\isVendored($document)); + $this->assertEquals(true, isVendored($document)); $document = $this->createDocument('file:///c:/dir/vendor/x.php', "assertEquals(true, \LanguageServer\isVendored($document)); + $this->assertEquals(true, isVendored($document)); $document = $this->createDocument('file:///vendor/x.php', "assertEquals(true, \LanguageServer\isVendored($document)); + $this->assertEquals(true, isVendored($document)); $document = $this->createDocument('file:///dir/vendor.php', "assertEquals(false, \LanguageServer\isVendored($document)); + $this->assertEquals(false, isVendored($document)); $document = $this->createDocument('file:///dir/x.php', "assertEquals(false, \LanguageServer\isVendored($document)); + $this->assertEquals(false, isVendored($document)); } } From ed922e1d24e71c21d6522b0e1179de51cf28c9a7 Mon Sep 17 00:00:00 2001 From: Trevor Bortins Date: Tue, 7 Feb 2017 13:53:15 -0800 Subject: [PATCH 10/13] refactor for style, consistency missed a vendor reference! --- src/Index/ProjectIndex.php | 2 +- src/Indexer.php | 2 +- src/Server/TextDocument.php | 8 ++++---- src/Server/Workspace.php | 5 ++--- src/utils.php | 10 ++++------ 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/Index/ProjectIndex.php b/src/Index/ProjectIndex.php index 538c5c45..af980f8f 100644 --- a/src/Index/ProjectIndex.php +++ b/src/Index/ProjectIndex.php @@ -46,7 +46,7 @@ protected function getIndexes(): array */ public function getIndexForUri(string $uri): Index { - $packageName = getPackageName($this->composerJson, $uri); + $packageName = getPackageName($uri, $this->composerJson); if ($packageName) { return $this->dependenciesIndex->getDependencyIndex($packageName); } diff --git a/src/Indexer.php b/src/Indexer.php index ddf5a578..34ad618f 100644 --- a/src/Indexer.php +++ b/src/Indexer.php @@ -118,7 +118,7 @@ public function index(): Promise $deps = []; foreach ($uris as $uri) { - $packageName = getPackageName($this->composerJson, $uri); + $packageName = getPackageName($uri, $this->composerJson); if ($this->composerLock !== null && $packageName) { // Dependency file if (!isset($deps[$packageName])) { diff --git a/src/Server/TextDocument.php b/src/Server/TextDocument.php index a23358f3..3287b85c 100644 --- a/src/Server/TextDocument.php +++ b/src/Server/TextDocument.php @@ -30,7 +30,7 @@ use Sabre\Event\Promise; use Sabre\Uri; use function Sabre\Event\coroutine; -use function LanguageServer\waitForEvent; +use function LanguageServer\{waitForEvent,isVendored}; /** * Provides method handlers for all textDocument/* methods @@ -134,7 +134,7 @@ public function documentSymbol(TextDocumentIdentifier $textDocument): Promise public function didOpen(TextDocumentItem $textDocument) { $document = $this->documentLoader->open($textDocument->uri, $textDocument->text); - if (!\LanguageServer\isVendored($document, $this->composerJson)) { + if (!isVendored($document, $this->composerJson)) { $this->client->textDocument->publishDiagnostics($textDocument->uri, $document->getDiagnostics()); } } @@ -409,9 +409,9 @@ public function xdefinition(TextDocumentIdentifier $textDocument, Position $posi $symbol->$prop = $val; } $symbol->fqsen = $def->fqn; - if (preg_match('/\/vendor\/([^\/]+\/[^\/]+)\//', $def->symbolInformation->location->uri, $matches) && $this->composerLock !== null) { + $packageName = getPackageName($def->symbolInformation->location->uri, $this->composerJson); + if ($packageName && $this->composerLock !== null) { // Definition is inside a dependency - $packageName = $matches[1]; foreach (array_merge($this->composerLock->packages, $this->composerLock->{'packages-dev'}) as $package) { if ($package->name === $packageName) { $symbol->package = $package; diff --git a/src/Server/Workspace.php b/src/Server/Workspace.php index 2699de49..dba510ad 100644 --- a/src/Server/Workspace.php +++ b/src/Server/Workspace.php @@ -8,8 +8,7 @@ use LanguageServer\Protocol\{SymbolInformation, SymbolDescriptor, ReferenceInformation, DependencyReference, Location}; use Sabre\Event\Promise; use function Sabre\Event\coroutine; -use function LanguageServer\waitForEvent; -use function LanguageServer\getPackageName; +use function LanguageServer\{waitForEvent,getPackageName}; /** * Provides method handlers for all workspace/* methods @@ -124,7 +123,7 @@ public function xreferences($query, array $files = null): Promise $symbol->$prop = $val; } // Find out package name - $packageName = getPackageName($this->composerJson, $def->symbolInformation->location->uri); + $packageName = getPackageName($def->symbolInformation->location->uri, $this->composerJson); foreach (array_merge($this->composerLock->packages, $this->composerLock->{'packages-dev'}) as $package) { if ($package->name === $packageName) { $symbol->package = $package; diff --git a/src/utils.php b/src/utils.php index 65db8633..332602b6 100644 --- a/src/utils.php +++ b/src/utils.php @@ -169,13 +169,13 @@ function isVendored(PhpDocument $document, \stdClass $composerJson = null): bool * @param \stdClass|null $composerJson * @param string $uri * @param array $matches - * @return string + * @return string|null */ -function getPackageName(\stdClass $composerJson = null, string $uri): ?string +function getPackageName(string $uri, \stdClass $composerJson = null): ?string { $vendorDir = str_replace('/', '\/', getVendorDir($composerJson)); preg_match("/\/$vendorDir\/([^\/]+\/[^\/]+)\//", $uri, $matches); - return isset($matches[1]) ? $matches[1] : null; + return $matches[1] ?? null; } /** @@ -187,7 +187,5 @@ function getPackageName(\stdClass $composerJson = null, string $uri): ?string */ function getVendorDir(\stdClass $composerJson = null): string { - return isset($composerJson->config->{'vendor-dir'}) ? - $composerJson->config->{'vendor-dir'} - : 'vendor'; + return $composerJson->config->{'vendor-dir'} ?? 'vendor'; } From 963c5eb1d2847e731e435771920a0565c0ec5207 Mon Sep 17 00:00:00 2001 From: Trevor Bortins Date: Tue, 7 Feb 2017 13:59:30 -0800 Subject: [PATCH 11/13] forgot the php7.1 syntax thing, removed. --- src/utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.php b/src/utils.php index 332602b6..c0c5bf73 100644 --- a/src/utils.php +++ b/src/utils.php @@ -171,7 +171,7 @@ function isVendored(PhpDocument $document, \stdClass $composerJson = null): bool * @param array $matches * @return string|null */ -function getPackageName(string $uri, \stdClass $composerJson = null): ?string +function getPackageName(string $uri, \stdClass $composerJson = null) { $vendorDir = str_replace('/', '\/', getVendorDir($composerJson)); preg_match("/\/$vendorDir\/([^\/]+\/[^\/]+)\//", $uri, $matches); From af00745aeffc555476f40e3fbb24727b68d10ceb Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Tue, 7 Feb 2017 23:14:14 +0100 Subject: [PATCH 12/13] Add space --- src/Server/TextDocument.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Server/TextDocument.php b/src/Server/TextDocument.php index 3287b85c..aa76ec23 100644 --- a/src/Server/TextDocument.php +++ b/src/Server/TextDocument.php @@ -30,7 +30,7 @@ use Sabre\Event\Promise; use Sabre\Uri; use function Sabre\Event\coroutine; -use function LanguageServer\{waitForEvent,isVendored}; +use function LanguageServer\{waitForEvent, isVendored}; /** * Provides method handlers for all textDocument/* methods From 0ad8f345324f061a801d7cbf5536b4542546865b Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Tue, 7 Feb 2017 23:14:29 +0100 Subject: [PATCH 13/13] Add space --- src/Server/Workspace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Server/Workspace.php b/src/Server/Workspace.php index dba510ad..b94618cb 100644 --- a/src/Server/Workspace.php +++ b/src/Server/Workspace.php @@ -8,7 +8,7 @@ use LanguageServer\Protocol\{SymbolInformation, SymbolDescriptor, ReferenceInformation, DependencyReference, Location}; use Sabre\Event\Promise; use function Sabre\Event\coroutine; -use function LanguageServer\{waitForEvent,getPackageName}; +use function LanguageServer\{waitForEvent, getPackageName}; /** * Provides method handlers for all workspace/* methods