1
0
Fork 0

WIP: Implement didChangeConfiguration with reindexing

* Handle the case where didChangeConfiguration is called before workspace/configuration request
is resolved.
* Implement basic cancellation signal request
* Use defaults options and only apply new on request
pull/308/head
Jürgen Steitz 2018-08-31 20:49:23 +02:00
parent a1c3845c9f
commit a1e56543c3
5 changed files with 142 additions and 77 deletions

View File

@ -85,7 +85,6 @@ class Indexer
* @param Cache $cache
* @param DependenciesIndex $dependenciesIndex
* @param Index $sourceIndex
* @param Options $options
* @param PhpDocumentLoader $documentLoader
* @param \stdClass|null $composerLock
*/
@ -97,7 +96,6 @@ class Indexer
DependenciesIndex $dependenciesIndex,
Index $sourceIndex,
PhpDocumentLoader $documentLoader,
Options $options,
\stdClass $composerLock = null,
\stdClass $composerJson = null
) {
@ -108,11 +106,24 @@ class Indexer
$this->dependenciesIndex = $dependenciesIndex;
$this->sourceIndex = $sourceIndex;
$this->documentLoader = $documentLoader;
$this->options = $options;
$this->composerLock = $composerLock;
$this->composerJson = $composerJson;
$this->hasCancellationSignal = false;
$this->isIndexing = false;
$this->options = new Options();
}
/**
* @param Options $options
*/
public function setOptions(Options $options)
{
$this->options = $options;
}
public function getOptions(): Options
{
return $this->options;
}
/**
@ -156,6 +167,7 @@ class Indexer
$this->client->window->logMessage(MessageType::INFO, 'Indexing project for definitions and static references');
yield $this->indexFiles($source);
$this->sourceIndex->setStaticComplete();
// Dynamic references
$this->client->window->logMessage(MessageType::INFO, 'Indexing project for dynamic references');
yield $this->indexFiles($source);
@ -243,6 +255,7 @@ class Indexer
}
$this->hasCancellationSignal = false;
$this->client->window->logMessage(MessageType::INFO, 'Indexing project canceled');
});
}
@ -254,6 +267,7 @@ class Indexer
{
return coroutine(function () use ($files) {
foreach ($files as $i => $uri) {
// abort current running indexing
if ($this->hasCancellationSignal) {
return;
}

View File

@ -117,6 +117,16 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
*/
protected $cache;
/**
* @var ClientCapabilities
*/
protected $clientCapabilities;
/**
* @var Indexer
*/
protected $indexer;
/**
* @param ProtocolReader $reader
* @param ProtocolWriter $writer
@ -203,6 +213,7 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
$stubsIndex = StubsIndex::read();
$this->globalIndex = new GlobalIndex($stubsIndex, $this->projectIndex);
$this->rootPath = $rootPath;
$this->clientCapabilities = $capabilities;
// The DefinitionResolver should look in stubs, the project source and dependencies
$this->definitionResolver = new DefinitionResolver($this->globalIndex);
@ -244,6 +255,43 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
}
$this->cache = $capabilities->xcacheProvider ? new ClientCache($this->client) : new FileSystemCache;
// Index in background
$this->indexer = new Indexer(
$this->filesFinder,
$this->rootPath,
$this->client,
$this->cache,
$dependenciesIndex,
$sourceIndex,
$this->documentLoader,
$this->composerLock,
$this->composerJson
);
}
if ($this->textDocument === null) {
$this->textDocument = new Server\TextDocument(
$this->documentLoader,
$this->definitionResolver,
$this->client,
$this->globalIndex,
$this->composerJson,
$this->composerLock
);
}
if ($this->workspace === null) {
$this->workspace = new Server\Workspace(
$this->client,
$this->projectIndex,
$dependenciesIndex,
$sourceIndex,
$this->indexer,
$this->composerLock,
$this->documentLoader,
$this->composerJson
);
}
$serverCapabilities = new ServerCapabilities();
@ -286,55 +334,31 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
public function initialized(): Promise
{
return coroutine(function () {
list($sourceIndex, $dependenciesIndex) = $this->projectIndex->getIndexes();
$mapper = new \JsonMapper();
if (!$this->rootPath) {
return;
}
// request configuration if it is supported
// support comes with protocol version 3.6.0
if ($this->clientCapabilities->workspace->configuration) {
$configurationitem = new ConfigurationItem();
$configurationitem->section = 'php';
$configuration = yield $this->client->workspace->configuration([$configurationitem]);
$options = $mapper->map($configuration[0], new Options());
if ($this->rootPath) {
// Index in background
$indexer = new Indexer(
$this->filesFinder,
$this->rootPath,
$this->client,
$this->cache,
$dependenciesIndex,
$sourceIndex,
$this->documentLoader,
$options,
$this->composerLock,
$this->composerJson
);
$indexer->index()->otherwise('\\LanguageServer\\crash');
$options = $this->mapper->map($configuration[0], new Options());
}
if ($this->textDocument === null) {
$this->textDocument = new Server\TextDocument(
$this->documentLoader,
$this->definitionResolver,
$this->client,
$this->globalIndex,
$this->composerJson,
$this->composerLock
);
// depending on the implementation of the client
// the workspace/didChangeConfiguration can be invoked before
// the response from the workspace/configuration request is resolved
if ($this->indexer->isIndexing()) {
return;
}
if ($this->workspace === null) {
$this->workspace = new Server\Workspace(
$this->client,
$this->projectIndex,
$dependenciesIndex,
$sourceIndex,
$options,
$indexer,
$this->composerLock,
$this->documentLoader,
$this->composerJson
);
if ($options) {
$this->indexer->setOptions($options);
}
$this->indexer->index()->otherwise('\\LanguageServer\\crash');
});
}

View File

@ -24,4 +24,9 @@ class ClientCapabilities
* @var bool|null
*/
public $xcacheProvider;
/**
* @var WorkspaceClientCapabilities
*/
public $workspace;
}

View File

@ -0,0 +1,11 @@
<?php
namespace LanguageServer\Protocol;
class WorkspaceClientCapabilities
{
/**
* @var bool|null
*/
public $configuration;
}

View File

@ -46,11 +46,6 @@ class Workspace
*/
private $sourceIndex;
/**
* @var Options
*/
private $options;
/**
* @var Indexer
*/
@ -71,7 +66,6 @@ class Workspace
* @param ProjectIndex $projectIndex Index that is used to wait for full index completeness
* @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 Options $options Initialization options that are used on a workspace/didChangeConfiguration
* @param Indexer $indexer
* @param \stdClass $composerLock The parsed composer.lock of the project, if any
* @param PhpDocumentLoader $documentLoader PhpDocumentLoader instance to load documents
@ -81,7 +75,6 @@ class Workspace
ProjectIndex $projectIndex,
DependenciesIndex $dependenciesIndex,
Index $sourceIndex,
Options $options,
Indexer $indexer,
\stdClass $composerLock = null,
PhpDocumentLoader $documentLoader,
@ -94,7 +87,6 @@ class Workspace
$this->composerLock = $composerLock;
$this->documentLoader = $documentLoader;
$this->composerJson = $composerJson;
$this->options = $options;
$this->indexer = $indexer;
}
@ -205,36 +197,32 @@ class Workspace
/**
* A notification sent from the client to the server to signal the change of configuration settings.
*
* @param \stdClass $settings Settings as JSON object structure with php as primary key
* @param mixed $settings Settings as JSON object structure with php as primary key
* @return Promise
*/
public function didChangeConfiguration(\stdClass $settings): Promise
public function didChangeConfiguration($settings): Promise
{
xdebug_break();
return coroutine(function () use ($settings) {
try {
xdebug_break();
$mapper = new \JsonMapper();
$settings = $mapper->map($settings->php, new Options);
if ($this->options == $settings) {
if (!property_exists($settings, 'php') || $settings->php === new \stdClass()) {
return;
}
// @TODO: get changed settings and apply them
// @TODO: check settings that affect the indexer
try {
$mapper = new \JsonMapper();
$options = $mapper->map($settings->php, new Options);
// handle options for indexer
$currentIndexerOptions = $this->indexer->getOptions();
$this->indexer->setOptions($options);
if ($this->hasIndexerOptionsChanged($currentIndexerOptions, $options)) {
if ($this->indexer->isIndexing()) {
yield $this->indexer->cancel();
}
$this->projectIndex->wipe();
$this->indexer->index();
$this->client->window->showMessage(
MessageType::INFO,
'Reindexing with new settings.'
);
$this->indexer->index()->otherwise('\\LanguageServer\\crash');
}
} catch (\JsonMapper_Exception $exception) {
$this->client->window->showMessage(
MessageType::ERROR,
@ -244,4 +232,27 @@ class Workspace
}
});
}
/**
* Compare current options with new
*
* When the new options differ from the current, then we need start
* to reindex the project folder.
*
* @param Options $current
* @param Options $new
* @return bool
*/
private function hasIndexerOptionsChanged(Options $current, Options $new): bool
{
$properties = ['fileTypes'];
foreach ($properties as $property) {
if ($current->{$property} !== $new->{$property}) {
return true;
}
}
return false;
}
}