From 0de7ba833534d87e925be211386ea348446c5235 Mon Sep 17 00:00:00 2001 From: Sara Itani Date: Wed, 1 Mar 2017 02:18:37 -0800 Subject: [PATCH 1/6] Ensure diagnostics are cleared on file deletion (#319) * Ensure diagnostics are cleared on file deletion Previously, error diagnostics would not be cleared when a file was deleted while it was closed. This would result in lingering errors in the problems view that could only be cleared by reloading the language server. This fix addresses the issue by adding support for workspace/didChangeWatchedFiles and automatically clearing diagnostics for deleted files. * add FileEvent constructor --- src/LanguageServer.php | 1 + src/Protocol/FileEvent.php | 10 +++++ src/Server/Workspace.php | 34 ++++++++++++++- tests/Server/ServerTestCase.php | 2 +- .../Workspace/DidChangeWatchedFilesTest.php | 41 +++++++++++++++++++ 5 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 tests/Server/Workspace/DidChangeWatchedFilesTest.php diff --git a/src/LanguageServer.php b/src/LanguageServer.php index 3c999f2..8fe9ec1 100644 --- a/src/LanguageServer.php +++ b/src/LanguageServer.php @@ -253,6 +253,7 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher } if ($this->workspace === null) { $this->workspace = new Server\Workspace( + $this->client, $this->projectIndex, $dependenciesIndex, $sourceIndex, diff --git a/src/Protocol/FileEvent.php b/src/Protocol/FileEvent.php index b4ed833..015044d 100644 --- a/src/Protocol/FileEvent.php +++ b/src/Protocol/FileEvent.php @@ -20,4 +20,14 @@ class FileEvent * @var int */ public $type; + + /** + * @param string $uri + * @param int $type + */ + public function __construct(string $uri, int $type) + { + $this->uri = $uri; + $this->type = $type; + } } diff --git a/src/Server/Workspace.php b/src/Server/Workspace.php index b94618c..d2f8cec 100644 --- a/src/Server/Workspace.php +++ b/src/Server/Workspace.php @@ -5,7 +5,15 @@ namespace LanguageServer\Server; use LanguageServer\{LanguageClient, Project, PhpDocumentLoader}; use LanguageServer\Index\{ProjectIndex, DependenciesIndex, Index}; -use LanguageServer\Protocol\{SymbolInformation, SymbolDescriptor, ReferenceInformation, DependencyReference, Location}; +use LanguageServer\Protocol\{ + FileChangeType, + FileEvent, + SymbolInformation, + SymbolDescriptor, + ReferenceInformation, + DependencyReference, + Location +}; use Sabre\Event\Promise; use function Sabre\Event\coroutine; use function LanguageServer\{waitForEvent, getPackageName}; @@ -15,6 +23,11 @@ use function LanguageServer\{waitForEvent, getPackageName}; */ class Workspace { + /** + * @var LanguageClient + */ + public $client; + /** * The symbol index for the workspace * @@ -43,14 +56,16 @@ class Workspace public $documentLoader; /** + * @param LanguageClient $client LanguageClient instance used to signal updated results * @param ProjectIndex $index Index that is searched on a workspace/symbol request * @param DependenciesIndex $dependenciesIndex Index that is used on a workspace/xreferences request * @param DependenciesIndex $sourceIndex Index that is used on a workspace/xreferences request * @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, \stdClass $composerJson = null) + public function __construct(LanguageClient $client, ProjectIndex $index, DependenciesIndex $dependenciesIndex, Index $sourceIndex, \stdClass $composerLock = null, PhpDocumentLoader $documentLoader, \stdClass $composerJson = null) { + $this->client = $client; $this->sourceIndex = $sourceIndex; $this->index = $index; $this->dependenciesIndex = $dependenciesIndex; @@ -82,6 +97,21 @@ class Workspace }); } + /** + * The watched files notification is sent from the client to the server when the client detects changes to files watched by the language client. + * + * @param FileEvent[] $changes + * @return void + */ + public function didChangeWatchedFiles(array $changes) + { + foreach ($changes as $change) { + if ($change->type === FileChangeType::DELETED) { + $this->client->textDocument->publishDiagnostics($change->uri, []); + } + } + } + /** * The workspace references request is sent from the client to the server to locate project-wide references to a symbol given its description / metadata. * diff --git a/tests/Server/ServerTestCase.php b/tests/Server/ServerTestCase.php index 679191f..94ba933 100644 --- a/tests/Server/ServerTestCase.php +++ b/tests/Server/ServerTestCase.php @@ -54,7 +54,7 @@ abstract class ServerTestCase extends TestCase $client = new LanguageClient(new MockProtocolStream, new MockProtocolStream); $this->documentLoader = new PhpDocumentLoader(new FileSystemContentRetriever, $projectIndex, $definitionResolver); $this->textDocument = new Server\TextDocument($this->documentLoader, $definitionResolver, $client, $projectIndex); - $this->workspace = new Server\Workspace($projectIndex, $dependenciesIndex, $sourceIndex, null, $this->documentLoader); + $this->workspace = new Server\Workspace($client, $projectIndex, $dependenciesIndex, $sourceIndex, null, $this->documentLoader); $globalSymbolsUri = pathToUri(realpath(__DIR__ . '/../../fixtures/global_symbols.php')); $globalReferencesUri = pathToUri(realpath(__DIR__ . '/../../fixtures/global_references.php')); diff --git a/tests/Server/Workspace/DidChangeWatchedFilesTest.php b/tests/Server/Workspace/DidChangeWatchedFilesTest.php new file mode 100644 index 0000000..1074c58 --- /dev/null +++ b/tests/Server/Workspace/DidChangeWatchedFilesTest.php @@ -0,0 +1,41 @@ +on('message', function (Message $message) use ($fileEvent, &$isDiagnosticsCleared) { + if ($message->body->method === "textDocument/publishDiagnostics") { + $this->assertEquals($message->body->params->uri, $fileEvent->uri); + $this->assertEquals($message->body->params->diagnostics, []); + $isDiagnosticsCleared = true; + } + }); + + $workspace->didChangeWatchedFiles([$fileEvent]); + Loop\tick(true); + + $this->assertTrue($isDiagnosticsCleared, "Deleting file should clear all diagnostics."); + } +} From 7f8eccb5aec8d312e68fd7dde9f5aebafacddc3b Mon Sep 17 00:00:00 2001 From: Sara Itani Date: Thu, 2 Mar 2017 01:07:47 -0800 Subject: [PATCH 2/6] Fix formatting breakage (option 2) (#324) PHP_CodeSniffer 3.0 RC4 introduces a breaking change that removes PHPCS from the composer autoloader. This fix addresses the issue by locking to v3.0 RC3. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 268a989..b29c1ee 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "phpdocumentor/reflection-docblock": "^3.0", "sabre/event": "^5.0", "felixfbecker/advanced-json-rpc": "^2.0", - "squizlabs/php_codesniffer" : "^3.0", + "squizlabs/php_codesniffer" : "3.0.0RC3", "netresearch/jsonmapper": "^1.0", "webmozart/path-util": "^2.3", "webmozart/glob": "^4.1", From 546660f957623b2cdc179fe107b28581d60ba190 Mon Sep 17 00:00:00 2001 From: Harings Rob Date: Wed, 8 Mar 2017 16:19:56 +0100 Subject: [PATCH 3/6] Update README.md (#329) Updating the used by to no longer link to the deprecated repository. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fecd6c7..37800e0 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ Example: - [VS Code PHP IntelliSense](https://github.com/felixfbecker/vscode-php-intellisense) - [Eclipse Che](https://eclipse.org/che/) - [Eclipse IDE (LSP4E-PHP)](https://github.com/eclipselabs/lsp4e-php) - - [Neovim (nvim-cm-php-language-server)](https://github.com/roxma/nvim-cm-php-language-server) + - NeoVim: [LanguageServer-php-neovim](https://github.com/roxma/LanguageServer-php-neovim) with [LanguageClient neovim](https://github.com/autozimu/LanguageClient-neovim) ## Contributing From 4d0a0a2a1053111acb7d3d03d36b927ad9b56b76 Mon Sep 17 00:00:00 2001 From: Jens Hausdorf Date: Sun, 19 Mar 2017 12:15:39 +0100 Subject: [PATCH 4/6] show anything from a doc comment block (#315) --- src/DefinitionResolver.php | 9 ++++++- tests/Server/TextDocument/CompletionTest.php | 28 +++++++++++++++++--- tests/Server/TextDocument/HoverTest.php | 21 ++++++++++++--- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index ec295a5..6bfceb0 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -89,7 +89,14 @@ class DefinitionResolver } else { $docBlock = $node->getAttribute('docBlock'); if ($docBlock !== null) { - return $docBlock->getSummary(); + // check wether we have a description, when true, add a new paragraph + // with the description + $description = $docBlock->getDescription()->render(); + + if (empty($description)) { + return $docBlock->getSummary(); + } + return $docBlock->getSummary() . "\n\n" . $description; } } } diff --git a/tests/Server/TextDocument/CompletionTest.php b/tests/Server/TextDocument/CompletionTest.php index dd9e680..786fb55 100644 --- a/tests/Server/TextDocument/CompletionTest.php +++ b/tests/Server/TextDocument/CompletionTest.php @@ -160,7 +160,12 @@ class CompletionTest extends TestCase 'TestClass', CompletionItemKind::CLASS_, null, - 'Pariatur ut laborum tempor voluptate consequat ea deserunt.', + 'Pariatur ut laborum tempor voluptate consequat ea deserunt.' . "\n\n" . + 'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' . "\n" . + 'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' . "\n" . + 'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' . "\n" . + 'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' . "\n" . + 'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.', null, null, '\TestClass' @@ -179,7 +184,12 @@ class CompletionTest extends TestCase 'TestClass', CompletionItemKind::CLASS_, 'TestNamespace', - 'Pariatur ut laborum tempor voluptate consequat ea deserunt.', + 'Pariatur ut laborum tempor voluptate consequat ea deserunt.' . "\n\n" . + 'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' . "\n" . + 'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' . "\n" . + 'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' . "\n" . + 'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' . "\n" . + 'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.', null, null, 'TestClass' @@ -209,7 +219,12 @@ class CompletionTest extends TestCase 'TestClass', CompletionItemKind::CLASS_, 'TestNamespace', - 'Pariatur ut laborum tempor voluptate consequat ea deserunt.' + 'Pariatur ut laborum tempor voluptate consequat ea deserunt.' . "\n\n" . + 'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' . "\n" . + 'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' . "\n" . + 'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' . "\n" . + 'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' . "\n" . + 'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.' ) ], true), $items); } @@ -347,7 +362,12 @@ class CompletionTest extends TestCase 'TestClass', CompletionItemKind::CLASS_, null, - 'Pariatur ut laborum tempor voluptate consequat ea deserunt.', + 'Pariatur ut laborum tempor voluptate consequat ea deserunt.' . "\n\n" . + 'Deserunt enim minim sunt sint ea nisi. Deserunt excepteur tempor id nostrud' . "\n" . + 'laboris commodo ad commodo velit mollit qui non officia id. Nulla duis veniam' . "\n" . + 'veniam officia deserunt et non dolore mollit ea quis eiusmod sit non. Occaecat' . "\n" . + 'consequat sunt culpa exercitation pariatur id reprehenderit nisi incididunt Lorem' . "\n" . + 'sint. Officia culpa pariatur laborum nostrud cupidatat consequat mollit.', null, null, 'TestClass' diff --git a/tests/Server/TextDocument/HoverTest.php b/tests/Server/TextDocument/HoverTest.php index 7d61354..cdc1718 100644 --- a/tests/Server/TextDocument/HoverTest.php +++ b/tests/Server/TextDocument/HoverTest.php @@ -22,7 +22,12 @@ class HoverTest extends ServerTestCase )->wait(); $this->assertEquals(new Hover([ new MarkedString('php', "range), $result); } @@ -37,7 +42,12 @@ class HoverTest extends ServerTestCase )->wait(); $this->assertEquals(new Hover([ new MarkedString('php', "range), $result); } @@ -181,7 +191,12 @@ class HoverTest extends ServerTestCase $result = $this->textDocument->hover(new TextDocumentIdentifier($uri), new Position(59, 11))->wait(); $this->assertEquals(new Hover([ new MarkedString('php', " Date: Sun, 2 Apr 2017 00:30:10 +0200 Subject: [PATCH 5/6] Fix missing '()' for function definition (#340) --- src/DefinitionResolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index 6bfceb0..7307de9 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -446,7 +446,7 @@ class DefinitionResolver // Cannot get type for dynamic function call return new Types\Mixed; } - $fqn = (string)($expr->getAttribute('namespacedName') ?? $expr->name); + $fqn = (string)($expr->getAttribute('namespacedName') ?? $expr->name) . '()'; $def = $this->index->getDefinition($fqn, true); if ($def !== null) { return $def->type; From f50df5cdaf47496f36fdff942008753665aca1c6 Mon Sep 17 00:00:00 2001 From: Sara Itani Date: Sun, 2 Apr 2017 05:08:45 -0700 Subject: [PATCH 6/6] Enforce memory limit in phpunit.xml (#320) This will help highlight memory regressions, make it easier for newcomers to get started with the codebase w/o editing php.ini defaults (128M), and also keep things consistent between local and travis runs. --- phpunit.xml.dist | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4e3f6be..6cd8787 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -11,4 +11,7 @@ ./src + + +