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 requestpull/308/head
parent
a1c3845c9f
commit
a1e56543c3
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
$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');
|
||||
if (!$this->rootPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->textDocument === null) {
|
||||
$this->textDocument = new Server\TextDocument(
|
||||
$this->documentLoader,
|
||||
$this->definitionResolver,
|
||||
$this->client,
|
||||
$this->globalIndex,
|
||||
$this->composerJson,
|
||||
$this->composerLock
|
||||
);
|
||||
// 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 = $this->mapper->map($configuration[0], new Options());
|
||||
}
|
||||
|
||||
if ($this->workspace === null) {
|
||||
$this->workspace = new Server\Workspace(
|
||||
$this->client,
|
||||
$this->projectIndex,
|
||||
$dependenciesIndex,
|
||||
$sourceIndex,
|
||||
$options,
|
||||
$indexer,
|
||||
$this->composerLock,
|
||||
$this->documentLoader,
|
||||
$this->composerJson
|
||||
);
|
||||
// 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 ($options) {
|
||||
$this->indexer->setOptions($options);
|
||||
}
|
||||
|
||||
$this->indexer->index()->otherwise('\\LanguageServer\\crash');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -24,4 +24,9 @@ class ClientCapabilities
|
|||
* @var bool|null
|
||||
*/
|
||||
public $xcacheProvider;
|
||||
|
||||
/**
|
||||
* @var WorkspaceClientCapabilities
|
||||
*/
|
||||
public $workspace;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace LanguageServer\Protocol;
|
||||
|
||||
class WorkspaceClientCapabilities
|
||||
{
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
public $configuration;
|
||||
}
|
|
@ -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) {
|
||||
if (!property_exists($settings, 'php') || $settings->php === new \stdClass()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
xdebug_break();
|
||||
$mapper = new \JsonMapper();
|
||||
$settings = $mapper->map($settings->php, new Options);
|
||||
$options = $mapper->map($settings->php, new Options);
|
||||
|
||||
if ($this->options == $settings) {
|
||||
return;
|
||||
// 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()->otherwise('\\LanguageServer\\crash');
|
||||
}
|
||||
|
||||
// @TODO: get changed settings and apply them
|
||||
// @TODO: check settings that affect the indexer
|
||||
|
||||
if ($this->indexer->isIndexing()) {
|
||||
yield $this->indexer->cancel();
|
||||
}
|
||||
|
||||
$this->projectIndex->wipe();
|
||||
$this->indexer->index();
|
||||
|
||||
$this->client->window->showMessage(
|
||||
MessageType::INFO,
|
||||
'Reindexing with new settings.'
|
||||
);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue