From 8741e287adb53447f449b5ca1487cc14dc0b335a Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Sun, 29 Oct 2017 17:17:58 -0700 Subject: [PATCH] feat: multi-root support (WIP) --- src/LanguageServer.php | 61 ++++++++++++++++++++------------ src/Protocol/WorkspaceFolder.php | 20 +++++++++++ 2 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 src/Protocol/WorkspaceFolder.php diff --git a/src/LanguageServer.php b/src/LanguageServer.php index 118dd937..62452d1e 100644 --- a/src/LanguageServer.php +++ b/src/LanguageServer.php @@ -9,7 +9,8 @@ TextDocumentSyncKind, Message, InitializeResult, - CompletionOptions + CompletionOptions, + WorkspaceFolder }; use LanguageServer\FilesFinder\{FilesFinder, ClientFilesFinder, FileSystemFilesFinder}; use LanguageServer\ContentRetriever\{ContentRetriever, ClientContentRetriever, FileSystemContentRetriever}; @@ -161,12 +162,26 @@ public function __construct(ProtocolReader $reader, ProtocolWriter $writer) * * @param ClientCapabilities $capabilities The capabilities provided by the client (editor) * @param string|null $rootPath The rootPath of the workspace. Is null if no folder is open. + * @param string|null $rootUri TThe rootUri of the workspace. Is null if no folder is open. If both `rootPath` and `rootUri` are set `rootUri` wins. + * @param WorkspaceFolder[]|null $workspaceFolders The actual configured workspace folders. * @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. * @return Promise */ - public function initialize(ClientCapabilities $capabilities, string $rootPath = null, int $processId = null): Promise + public function initialize(ClientCapabilities $capabilities, string $rootPath = null, string $rootUri = null, array $workspaceFolders = null, int $processId = null): Promise { - return coroutine(function () use ($capabilities, $rootPath, $processId) { + return coroutine(function () use ($capabilities, $rootPath, $rootUri, $workspaceFolders, $processId) { + + /** @var string[] */ + $rootPaths = []; + if ($workspaceFolders !== null) { + foreach ($workspaceFolders as $workspaceFolder) { + $rootPaths[] = uriToPath($workspaceFolder->uri); + } + } else if ($rootUri !== null) { + $rootPaths[] = uriToPath($rootUri); + } else if ($rootPath !== null) { + $rootPaths[] = $rootPath; + } if ($capabilities->xfilesProvider) { $this->filesFinder = new ClientFilesFinder($this->client); @@ -199,23 +214,23 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = yield $this->beforeIndex($rootPath); // Find composer.json - if ($this->composerJson === null) { - $composerJsonFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.json', $rootPath)); - sortUrisLevelOrder($composerJsonFiles); - - if (!empty($composerJsonFiles)) { - $this->composerJson = json_decode(yield $this->contentRetriever->retrieve($composerJsonFiles[0])); - } + if ($this->composerJsons === null) { + $this->composerJsons = yield array_map(function (string $rootPath) { + $composerJsonFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.json', $rootPath)); + foreach ($composerJsonFiles as $composerJsonFile) { + $this->composerJsons[$composerJsonFile] = json_decode(yield $this->contentRetriever->retrieve($composerJsonFile)); + } + }, $rootPaths); } // Find composer.lock - if ($this->composerLock === null) { - $composerLockFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.lock', $rootPath)); - sortUrisLevelOrder($composerLockFiles); - - if (!empty($composerLockFiles)) { - $this->composerLock = json_decode(yield $this->contentRetriever->retrieve($composerLockFiles[0])); - } + if ($this->composerLocks === null) { + $this->composerLocks = yield array_map(function (string $rootPath) { + $composerLockFiles = yield $this->filesFinder->find(Path::makeAbsolute('**/composer.lock', $rootPath)); + foreach ($composerLockFiles as $composerLockFile) { + $this->composerLocks[$composerLockFile] = json_decode(yield $this->contentRetriever->retrieve($composerLockFile)); + } + }, $rootPaths); } $cache = $capabilities->xcacheProvider ? new ClientCache($this->client) : new FileSystemCache; @@ -229,8 +244,8 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = $dependenciesIndex, $sourceIndex, $this->documentLoader, - $this->composerLock, - $this->composerJson + $this->composerLocks, + $this->composerJsons ); $indexer->index()->otherwise('\\LanguageServer\\crash'); } @@ -242,8 +257,8 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = $this->definitionResolver, $this->client, $this->globalIndex, - $this->composerJson, - $this->composerLock + $this->composerJsons, + $this->composerLocks ); } if ($this->workspace === null) { @@ -252,9 +267,9 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath = $this->projectIndex, $dependenciesIndex, $sourceIndex, - $this->composerLock, + $this->composerLocks, $this->documentLoader, - $this->composerJson + $this->composerJsons ); } diff --git a/src/Protocol/WorkspaceFolder.php b/src/Protocol/WorkspaceFolder.php new file mode 100644 index 00000000..535b8c07 --- /dev/null +++ b/src/Protocol/WorkspaceFolder.php @@ -0,0 +1,20 @@ +