Skip to content

Commit e317e8c

Browse files
committed
Start indexing after initialization
The indexer is moved to the method initialized, so we can request configurations from the client to init the indexer itself.
1 parent a5417cd commit e317e8c

File tree

5 files changed

+167
-70
lines changed

5 files changed

+167
-70
lines changed

src/Client/Workspace.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace LanguageServer\Client;
55

66
use LanguageServer\ClientHandler;
7+
use LanguageServer\Protocol\ConfigurationItem;
78
use LanguageServer\Protocol\TextDocumentIdentifier;
89
use Sabre\Event\Promise;
910
use JsonMapper;
@@ -44,4 +45,24 @@ public function xfiles(string $base = null): Promise
4445
return $this->mapper->mapArray($textDocuments, [], TextDocumentIdentifier::class);
4546
});
4647
}
48+
49+
/**
50+
* The workspace/configuration request is sent from the server to the
51+
* client to fetch configuration settings from the client.
52+
*
53+
* The request can fetch n configuration settings in one roundtrip.
54+
* The order of the returned configuration settings correspond to the order
55+
* of the passed ConfigurationItems (e.g. the first item in the response is
56+
* the result for the first configuration item in the params).
57+
*
58+
* @param ConfigurationItem[] $items
59+
* @return Promise
60+
*/
61+
public function configuration(array $items): Promise
62+
{
63+
return $this->handler->request(
64+
'workspace/configuration',
65+
['items' => $items]
66+
);
67+
}
4768
}

src/Index/ProjectIndex.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function __construct(Index $sourceIndex, DependenciesIndex $dependenciesI
3535
/**
3636
* @return ReadableIndex[]
3737
*/
38-
protected function getIndexes(): array
38+
public function getIndexes(): array
3939
{
4040
return [$this->sourceIndex, $this->dependenciesIndex];
4141
}

src/LanguageServer.php

Lines changed: 97 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace LanguageServer;
55

66
use LanguageServer\Protocol\{
7+
ConfigurationItem,
78
ServerCapabilities,
89
ClientCapabilities,
910
TextDocumentSyncKind,
@@ -15,7 +16,7 @@
1516
use LanguageServer\FilesFinder\{FilesFinder, ClientFilesFinder, FileSystemFilesFinder};
1617
use LanguageServer\ContentRetriever\{ContentRetriever, ClientContentRetriever, FileSystemContentRetriever};
1718
use LanguageServer\Index\{DependenciesIndex, GlobalIndex, Index, ProjectIndex, StubsIndex};
18-
use LanguageServer\Cache\{FileSystemCache, ClientCache};
19+
use LanguageServer\Cache\{Cache, FileSystemCache, ClientCache};
1920
use AdvancedJsonRpc;
2021
use Sabre\Event\Promise;
2122
use function Sabre\Event\coroutine;
@@ -106,6 +107,16 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher
106107
*/
107108
protected $definitionResolver;
108109

110+
/**
111+
* @var string|null
112+
*/
113+
protected $rootPath;
114+
115+
/**
116+
* @var Cache
117+
*/
118+
protected $cache;
119+
109120
/**
110121
* @param ProtocolReader $reader
111122
* @param ProtocolWriter $writer
@@ -162,14 +173,18 @@ public function __construct(ProtocolReader $reader, ProtocolWriter $writer)
162173
*
163174
* @param ClientCapabilities $capabilities The capabilities provided by the client (editor)
164175
* @param string|null $rootPath The rootPath of the workspace. Is null if no folder is open.
165-
* @param int|null $processId The process Id of the parent process that started the server. Is null if the process has not been started by another process. If the parent process is not alive then the server should exit (see exit notification) its process.
166-
* @param Options $initializationOptions The options send from client to initialize the server
176+
* @param int|null $processId The process Id of the parent process that started the server.
177+
* Is null if the process has not been started by another process.
178+
* If the parent process is not alive then the server should exit
179+
* (see exit notification) its process.
167180
* @return Promise <InitializeResult>
168181
*/
169-
public function initialize(ClientCapabilities $capabilities, string $rootPath = null, int $processId = null, Options $initializationOptions = null): Promise
170-
{
171-
return coroutine(function () use ($capabilities, $rootPath, $processId, $initializationOptions) {
172-
182+
public function initialize(
183+
ClientCapabilities $capabilities,
184+
string $rootPath = null,
185+
int $processId = null
186+
): Promise {
187+
return coroutine(function () use ($capabilities, $rootPath, $processId) {
173188
if ($capabilities->xfilesProvider) {
174189
$this->filesFinder = new ClientFilesFinder($this->client);
175190
} else {
@@ -187,60 +202,115 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath =
187202
$this->projectIndex = new ProjectIndex($sourceIndex, $dependenciesIndex, $this->composerJson);
188203
$stubsIndex = StubsIndex::read();
189204
$this->globalIndex = new GlobalIndex($stubsIndex, $this->projectIndex);
190-
$initializationOptions = $initializationOptions ?? new Options;
205+
$this->rootPath = $rootPath;
191206

192207
// The DefinitionResolver should look in stubs, the project source and dependencies
193208
$this->definitionResolver = new DefinitionResolver($this->globalIndex);
194-
195209
$this->documentLoader = new PhpDocumentLoader(
196210
$this->contentRetriever,
197211
$this->projectIndex,
198212
$this->definitionResolver
199213
);
200214

201-
if ($rootPath !== null) {
202-
yield $this->beforeIndex($rootPath);
215+
if ($this->rootPath !== null) {
216+
yield $this->beforeIndex($this->rootPath);
203217

204218
// Find composer.json
205219
if ($this->composerJson === null) {
206-
$composerJsonFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.json', $rootPath));
220+
$composerJsonFiles = yield $this->filesFinder->find(
221+
Path::makeAbsolute('**/composer.json', $this->rootPath)
222+
);
207223
sortUrisLevelOrder($composerJsonFiles);
208224

209225
if (!empty($composerJsonFiles)) {
210-
$this->composerJson = json_decode(yield $this->contentRetriever->retrieve($composerJsonFiles[0]));
226+
$this->composerJson = json_decode(
227+
yield $this->contentRetriever->retrieve($composerJsonFiles[0])
228+
);
211229
}
212230
}
213231

214232
// Find composer.lock
215233
if ($this->composerLock === null) {
216-
$composerLockFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.lock', $rootPath));
234+
$composerLockFiles = yield $this->filesFinder->find(
235+
Path::makeAbsolute('**/composer.lock', $this->rootPath)
236+
);
217237
sortUrisLevelOrder($composerLockFiles);
218238

219239
if (!empty($composerLockFiles)) {
220-
$this->composerLock = json_decode(yield $this->contentRetriever->retrieve($composerLockFiles[0]));
240+
$this->composerLock = json_decode(
241+
yield $this->contentRetriever->retrieve($composerLockFiles[0])
242+
);
221243
}
222244
}
223245

224-
$cache = $capabilities->xcacheProvider ? new ClientCache($this->client) : new FileSystemCache;
246+
$this->cache = $capabilities->xcacheProvider ? new ClientCache($this->client) : new FileSystemCache;
247+
}
248+
249+
$serverCapabilities = new ServerCapabilities();
250+
// Ask the client to return always full documents (because we need to rebuild the AST from scratch)
251+
$serverCapabilities->textDocumentSync = TextDocumentSyncKind::FULL;
252+
// Support "Find all symbols"
253+
$serverCapabilities->documentSymbolProvider = true;
254+
// Support "Find all symbols in workspace"
255+
$serverCapabilities->workspaceSymbolProvider = true;
256+
// Support "Go to definition"
257+
$serverCapabilities->definitionProvider = true;
258+
// Support "Find all references"
259+
$serverCapabilities->referencesProvider = true;
260+
// Support "Hover"
261+
$serverCapabilities->hoverProvider = true;
262+
// Support "Completion"
263+
$serverCapabilities->completionProvider = new CompletionOptions;
264+
$serverCapabilities->completionProvider->resolveProvider = false;
265+
$serverCapabilities->completionProvider->triggerCharacters = ['$', '>'];
266+
267+
$serverCapabilities->signatureHelpProvider = new SignatureHelpOptions();
268+
$serverCapabilities->signatureHelpProvider->triggerCharacters = ['(', ','];
269+
270+
// Support global references
271+
$serverCapabilities->xworkspaceReferencesProvider = true;
272+
$serverCapabilities->xdefinitionProvider = true;
273+
$serverCapabilities->xdependenciesProvider = true;
225274

275+
return new InitializeResult($serverCapabilities);
276+
});
277+
}
278+
279+
/**
280+
* The initialized notification is sent from the client to the server after
281+
* the client received the result of the initialize request but before the
282+
* client is sending any other request or notification to the server.
283+
*
284+
* @return Promise
285+
*/
286+
public function initialized(): Promise
287+
{
288+
return coroutine(function () {
289+
list($sourceIndex, $dependenciesIndex) = $this->projectIndex->getIndexes();
290+
$mapper = new \JsonMapper();
291+
$configurationitem = new ConfigurationItem();
292+
$configurationitem->section = 'php';
293+
$configuration = yield $this->client->workspace->configuration([$configurationitem]);
294+
$options = $mapper->map($configuration[0], new Options());
295+
296+
if ($this->rootPath) {
226297
// Index in background
227298
$indexer = new Indexer(
228299
$this->filesFinder,
229-
$rootPath,
300+
$this->rootPath,
230301
$this->client,
231-
$cache,
302+
$this->cache,
232303
$dependenciesIndex,
233304
$sourceIndex,
234305
$this->documentLoader,
235-
$initializationOptions,
306+
$options,
236307
$this->composerLock,
237-
$this->composerJson,
238-
$initializationOptions
308+
$this->composerJson
239309
);
310+
240311
$indexer->index()->otherwise('\\LanguageServer\\crash');
241312
}
242313

243-
244314
if ($this->textDocument === null) {
245315
$this->textDocument = new Server\TextDocument(
246316
$this->documentLoader,
@@ -251,54 +321,26 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath =
251321
$this->composerLock
252322
);
253323
}
324+
254325
if ($this->workspace === null) {
255326
$this->workspace = new Server\Workspace(
256327
$this->client,
257328
$this->projectIndex,
258329
$dependenciesIndex,
259330
$sourceIndex,
331+
$options,
260332
$this->composerLock,
261333
$this->documentLoader,
262-
$this->composerJson,
263-
$indexer,
264-
$initializationOptions
334+
$this->composerJson
265335
);
266336
}
267-
268-
$serverCapabilities = new ServerCapabilities();
269-
// Ask the client to return always full documents (because we need to rebuild the AST from scratch)
270-
$serverCapabilities->textDocumentSync = TextDocumentSyncKind::FULL;
271-
// Support "Find all symbols"
272-
$serverCapabilities->documentSymbolProvider = true;
273-
// Support "Find all symbols in workspace"
274-
$serverCapabilities->workspaceSymbolProvider = true;
275-
// Support "Go to definition"
276-
$serverCapabilities->definitionProvider = true;
277-
// Support "Find all references"
278-
$serverCapabilities->referencesProvider = true;
279-
// Support "Hover"
280-
$serverCapabilities->hoverProvider = true;
281-
// Support "Completion"
282-
$serverCapabilities->completionProvider = new CompletionOptions;
283-
$serverCapabilities->completionProvider->resolveProvider = false;
284-
$serverCapabilities->completionProvider->triggerCharacters = ['$', '>'];
285-
286-
$serverCapabilities->signatureHelpProvider = new SignatureHelpOptions();
287-
$serverCapabilities->signatureHelpProvider->triggerCharacters = ['(', ','];
288-
289-
// Support global references
290-
$serverCapabilities->xworkspaceReferencesProvider = true;
291-
$serverCapabilities->xdefinitionProvider = true;
292-
$serverCapabilities->xdependenciesProvider = true;
293-
294-
return new InitializeResult($serverCapabilities);
295337
});
296338
}
297339

298340
/**
299341
* The shutdown request is sent from the client to the server. It asks the server to shut down, but to not exit
300-
* (otherwise the response might not be delivered correctly to the client). There is a separate exit notification that
301-
* asks the server to exit.
342+
* (otherwise the response might not be delivered correctly to the client). There is a separate exit notification
343+
* that asks the server to exit.
302344
*
303345
* @return void
304346
*/

src/Protocol/ConfigurationItem.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace LanguageServer\Protocol;
4+
5+
class ConfigurationItem
6+
{
7+
/**
8+
* The scope to get the configuration section for.
9+
*
10+
* @var string|null
11+
*/
12+
public $scopeUri;
13+
14+
/**
15+
* The configuration section asked for.
16+
*
17+
* @var string|null
18+
*/
19+
public $section;
20+
}

0 commit comments

Comments
 (0)