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 constructorpull/328/head
parent
56bd465bf8
commit
0de7ba8335
|
@ -253,6 +253,7 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
|
|||
}
|
||||
if ($this->workspace === null) {
|
||||
$this->workspace = new Server\Workspace(
|
||||
$this->client,
|
||||
$this->projectIndex,
|
||||
$dependenciesIndex,
|
||||
$sourceIndex,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace LanguageServer\Tests\Server\Workspace;
|
||||
|
||||
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
||||
use LanguageServer\{DefinitionResolver, LanguageClient, PhpDocumentLoader, Server};
|
||||
use LanguageServer\Index\{DependenciesIndex, Index, ProjectIndex};
|
||||
use LanguageServer\Protocol\{FileChangeType, FileEvent, Message};
|
||||
use LanguageServer\Tests\MockProtocolStream;
|
||||
use LanguageServer\Tests\Server\ServerTestCase;
|
||||
use LanguageServer\Server\Workspace;
|
||||
use Sabre\Event\Loop;
|
||||
|
||||
class DidChangeWatchedFilesTest extends ServerTestCase
|
||||
{
|
||||
public function testDeletingFileClearsAllDiagnostics()
|
||||
{
|
||||
$client = new LanguageClient(new MockProtocolStream(), $writer = new MockProtocolStream());
|
||||
$projectIndex = new ProjectIndex($sourceIndex = new Index(), $dependenciesIndex = new DependenciesIndex());
|
||||
$definitionResolver = new DefinitionResolver($projectIndex);
|
||||
$loader = new PhpDocumentLoader(new FileSystemContentRetriever(), $projectIndex, $definitionResolver);
|
||||
$workspace = new Server\Workspace($client, $projectIndex, $dependenciesIndex, $sourceIndex, null, $loader, null);
|
||||
|
||||
$fileEvent = new FileEvent('my uri', FileChangeType::DELETED);
|
||||
|
||||
$isDiagnosticsCleared = false;
|
||||
$writer->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.");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue