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 Cache $cache
|
||||||
* @param DependenciesIndex $dependenciesIndex
|
* @param DependenciesIndex $dependenciesIndex
|
||||||
* @param Index $sourceIndex
|
* @param Index $sourceIndex
|
||||||
* @param Options $options
|
|
||||||
* @param PhpDocumentLoader $documentLoader
|
* @param PhpDocumentLoader $documentLoader
|
||||||
* @param \stdClass|null $composerLock
|
* @param \stdClass|null $composerLock
|
||||||
*/
|
*/
|
||||||
|
@ -97,7 +96,6 @@ class Indexer
|
||||||
DependenciesIndex $dependenciesIndex,
|
DependenciesIndex $dependenciesIndex,
|
||||||
Index $sourceIndex,
|
Index $sourceIndex,
|
||||||
PhpDocumentLoader $documentLoader,
|
PhpDocumentLoader $documentLoader,
|
||||||
Options $options,
|
|
||||||
\stdClass $composerLock = null,
|
\stdClass $composerLock = null,
|
||||||
\stdClass $composerJson = null
|
\stdClass $composerJson = null
|
||||||
) {
|
) {
|
||||||
|
@ -108,11 +106,24 @@ class Indexer
|
||||||
$this->dependenciesIndex = $dependenciesIndex;
|
$this->dependenciesIndex = $dependenciesIndex;
|
||||||
$this->sourceIndex = $sourceIndex;
|
$this->sourceIndex = $sourceIndex;
|
||||||
$this->documentLoader = $documentLoader;
|
$this->documentLoader = $documentLoader;
|
||||||
$this->options = $options;
|
|
||||||
$this->composerLock = $composerLock;
|
$this->composerLock = $composerLock;
|
||||||
$this->composerJson = $composerJson;
|
$this->composerJson = $composerJson;
|
||||||
$this->hasCancellationSignal = false;
|
$this->hasCancellationSignal = false;
|
||||||
$this->isIndexing = 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');
|
$this->client->window->logMessage(MessageType::INFO, 'Indexing project for definitions and static references');
|
||||||
yield $this->indexFiles($source);
|
yield $this->indexFiles($source);
|
||||||
$this->sourceIndex->setStaticComplete();
|
$this->sourceIndex->setStaticComplete();
|
||||||
|
|
||||||
// Dynamic references
|
// Dynamic references
|
||||||
$this->client->window->logMessage(MessageType::INFO, 'Indexing project for dynamic references');
|
$this->client->window->logMessage(MessageType::INFO, 'Indexing project for dynamic references');
|
||||||
yield $this->indexFiles($source);
|
yield $this->indexFiles($source);
|
||||||
|
@ -243,6 +255,7 @@ class Indexer
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->hasCancellationSignal = false;
|
$this->hasCancellationSignal = false;
|
||||||
|
$this->client->window->logMessage(MessageType::INFO, 'Indexing project canceled');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +267,7 @@ class Indexer
|
||||||
{
|
{
|
||||||
return coroutine(function () use ($files) {
|
return coroutine(function () use ($files) {
|
||||||
foreach ($files as $i => $uri) {
|
foreach ($files as $i => $uri) {
|
||||||
|
// abort current running indexing
|
||||||
if ($this->hasCancellationSignal) {
|
if ($this->hasCancellationSignal) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,6 +117,16 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
|
||||||
*/
|
*/
|
||||||
protected $cache;
|
protected $cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ClientCapabilities
|
||||||
|
*/
|
||||||
|
protected $clientCapabilities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Indexer
|
||||||
|
*/
|
||||||
|
protected $indexer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ProtocolReader $reader
|
* @param ProtocolReader $reader
|
||||||
* @param ProtocolWriter $writer
|
* @param ProtocolWriter $writer
|
||||||
|
@ -203,6 +213,7 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
|
||||||
$stubsIndex = StubsIndex::read();
|
$stubsIndex = StubsIndex::read();
|
||||||
$this->globalIndex = new GlobalIndex($stubsIndex, $this->projectIndex);
|
$this->globalIndex = new GlobalIndex($stubsIndex, $this->projectIndex);
|
||||||
$this->rootPath = $rootPath;
|
$this->rootPath = $rootPath;
|
||||||
|
$this->clientCapabilities = $capabilities;
|
||||||
|
|
||||||
// The DefinitionResolver should look in stubs, the project source and dependencies
|
// The DefinitionResolver should look in stubs, the project source and dependencies
|
||||||
$this->definitionResolver = new DefinitionResolver($this->globalIndex);
|
$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;
|
$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();
|
$serverCapabilities = new ServerCapabilities();
|
||||||
|
@ -286,55 +334,31 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
|
||||||
public function initialized(): Promise
|
public function initialized(): Promise
|
||||||
{
|
{
|
||||||
return coroutine(function () {
|
return coroutine(function () {
|
||||||
list($sourceIndex, $dependenciesIndex) = $this->projectIndex->getIndexes();
|
if (!$this->rootPath) {
|
||||||
$mapper = new \JsonMapper();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// request configuration if it is supported
|
||||||
|
// support comes with protocol version 3.6.0
|
||||||
|
if ($this->clientCapabilities->workspace->configuration) {
|
||||||
$configurationitem = new ConfigurationItem();
|
$configurationitem = new ConfigurationItem();
|
||||||
$configurationitem->section = 'php';
|
$configurationitem->section = 'php';
|
||||||
$configuration = yield $this->client->workspace->configuration([$configurationitem]);
|
$configuration = yield $this->client->workspace->configuration([$configurationitem]);
|
||||||
$options = $mapper->map($configuration[0], new Options());
|
$options = $this->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->textDocument === null) {
|
// depending on the implementation of the client
|
||||||
$this->textDocument = new Server\TextDocument(
|
// the workspace/didChangeConfiguration can be invoked before
|
||||||
$this->documentLoader,
|
// the response from the workspace/configuration request is resolved
|
||||||
$this->definitionResolver,
|
if ($this->indexer->isIndexing()) {
|
||||||
$this->client,
|
return;
|
||||||
$this->globalIndex,
|
|
||||||
$this->composerJson,
|
|
||||||
$this->composerLock
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->workspace === null) {
|
if ($options) {
|
||||||
$this->workspace = new Server\Workspace(
|
$this->indexer->setOptions($options);
|
||||||
$this->client,
|
|
||||||
$this->projectIndex,
|
|
||||||
$dependenciesIndex,
|
|
||||||
$sourceIndex,
|
|
||||||
$options,
|
|
||||||
$indexer,
|
|
||||||
$this->composerLock,
|
|
||||||
$this->documentLoader,
|
|
||||||
$this->composerJson
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->indexer->index()->otherwise('\\LanguageServer\\crash');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,4 +24,9 @@ class ClientCapabilities
|
||||||
* @var bool|null
|
* @var bool|null
|
||||||
*/
|
*/
|
||||||
public $xcacheProvider;
|
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;
|
private $sourceIndex;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Options
|
|
||||||
*/
|
|
||||||
private $options;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Indexer
|
* @var Indexer
|
||||||
*/
|
*/
|
||||||
|
@ -71,7 +66,6 @@ class Workspace
|
||||||
* @param ProjectIndex $projectIndex Index that is used to wait for full index completeness
|
* @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 $dependenciesIndex Index that is used on a workspace/xreferences request
|
||||||
* @param DependenciesIndex $sourceIndex 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 Indexer $indexer
|
||||||
* @param \stdClass $composerLock The parsed composer.lock of the project, if any
|
* @param \stdClass $composerLock The parsed composer.lock of the project, if any
|
||||||
* @param PhpDocumentLoader $documentLoader PhpDocumentLoader instance to load documents
|
* @param PhpDocumentLoader $documentLoader PhpDocumentLoader instance to load documents
|
||||||
|
@ -81,7 +75,6 @@ class Workspace
|
||||||
ProjectIndex $projectIndex,
|
ProjectIndex $projectIndex,
|
||||||
DependenciesIndex $dependenciesIndex,
|
DependenciesIndex $dependenciesIndex,
|
||||||
Index $sourceIndex,
|
Index $sourceIndex,
|
||||||
Options $options,
|
|
||||||
Indexer $indexer,
|
Indexer $indexer,
|
||||||
\stdClass $composerLock = null,
|
\stdClass $composerLock = null,
|
||||||
PhpDocumentLoader $documentLoader,
|
PhpDocumentLoader $documentLoader,
|
||||||
|
@ -94,7 +87,6 @@ class Workspace
|
||||||
$this->composerLock = $composerLock;
|
$this->composerLock = $composerLock;
|
||||||
$this->documentLoader = $documentLoader;
|
$this->documentLoader = $documentLoader;
|
||||||
$this->composerJson = $composerJson;
|
$this->composerJson = $composerJson;
|
||||||
$this->options = $options;
|
|
||||||
$this->indexer = $indexer;
|
$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.
|
* 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
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
public function didChangeConfiguration(\stdClass $settings): Promise
|
public function didChangeConfiguration($settings): Promise
|
||||||
{
|
{
|
||||||
xdebug_break();
|
|
||||||
return coroutine(function () use ($settings) {
|
return coroutine(function () use ($settings) {
|
||||||
try {
|
if (!property_exists($settings, 'php') || $settings->php === new \stdClass()) {
|
||||||
xdebug_break();
|
|
||||||
$mapper = new \JsonMapper();
|
|
||||||
$settings = $mapper->map($settings->php, new Options);
|
|
||||||
|
|
||||||
if ($this->options == $settings) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: get changed settings and apply them
|
try {
|
||||||
// @TODO: check settings that affect the indexer
|
$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()) {
|
if ($this->indexer->isIndexing()) {
|
||||||
yield $this->indexer->cancel();
|
yield $this->indexer->cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->projectIndex->wipe();
|
$this->projectIndex->wipe();
|
||||||
$this->indexer->index();
|
$this->indexer->index()->otherwise('\\LanguageServer\\crash');
|
||||||
|
}
|
||||||
$this->client->window->showMessage(
|
|
||||||
MessageType::INFO,
|
|
||||||
'Reindexing with new settings.'
|
|
||||||
);
|
|
||||||
} catch (\JsonMapper_Exception $exception) {
|
} catch (\JsonMapper_Exception $exception) {
|
||||||
$this->client->window->showMessage(
|
$this->client->window->showMessage(
|
||||||
MessageType::ERROR,
|
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