Cleaned up code. Fixed tests
parent
d597eeebf6
commit
a34426fb4e
|
@ -75,12 +75,12 @@ class LanguageServer extends \AdvancedJsonRpc\Dispatcher
|
|||
/**
|
||||
* The initialize request is sent as the first request from the client to the server.
|
||||
*
|
||||
* @param string $rootPath The rootPath of the workspace. Is null if no folder is open.
|
||||
* @param int $processId The process Id of the parent process that started the server.
|
||||
* @param ClientCapabilities $capabilities The capabilities provided by the client (editor)
|
||||
* @param string $rootPath The rootPath of the workspace. Is null if no folder is open.
|
||||
* @return InitializeResult
|
||||
*/
|
||||
public function initialize(string $rootPath, int $processId, ClientCapabilities $capabilities): InitializeResult
|
||||
public function initialize(int $processId, ClientCapabilities $capabilities, string $rootPath = null): InitializeResult
|
||||
{
|
||||
// start building project index
|
||||
if ($rootPath) {
|
||||
|
@ -124,7 +124,7 @@ class LanguageServer extends \AdvancedJsonRpc\Dispatcher
|
|||
/**
|
||||
* Parses workspace files, one at a time.
|
||||
*
|
||||
* @param string $rootPath The rootPath of the workspace. Is null if no folder is open.
|
||||
* @param string $rootPath The rootPath of the workspace.
|
||||
* @return void
|
||||
*/
|
||||
private function indexProject(string $rootPath)
|
||||
|
@ -136,26 +136,29 @@ class LanguageServer extends \AdvancedJsonRpc\Dispatcher
|
|||
foreach($files as $file) {
|
||||
$fileList = array_merge($fileList, $file);
|
||||
}
|
||||
$numTotalFiles = count($fileList);
|
||||
|
||||
$processFile = function() use (&$fileList, &$processFile, &$rootPath){
|
||||
$startTime = microtime(true);
|
||||
|
||||
$processFile = function() use (&$fileList, &$processFile, $rootPath, $numTotalFiles, $startTime) {
|
||||
if ($file = array_pop($fileList)) {
|
||||
|
||||
$uri = 'file://'.($file[0] == '/' || $file[0] == '\\' ? '' : '/').str_replace('\\', '/', $file);
|
||||
|
||||
$numFiles = count($fileList);
|
||||
if (($numFiles % 100) == 0) {
|
||||
$this->client->window->logMessage(3, $numFiles.' PHP files remaining.');
|
||||
}
|
||||
$fileNum = $numTotalFiles - count($fileList);
|
||||
$shortName = substr($file, strlen($rootPath)+1);
|
||||
$this->client->window->logMessage(3, "Parsing file $fileNum/$numTotalFiles: $shortName.");
|
||||
|
||||
$this->project->getDocument($uri)->updateAst(file_get_contents($file));
|
||||
|
||||
Loop\nextTick($processFile);
|
||||
Loop\setTimeout($processFile, 0);
|
||||
}
|
||||
else {
|
||||
$this->client->window->logMessage(3, 'All PHP files parsed.');
|
||||
$duration = (int)(microtime(true) - $startTime);
|
||||
$this->client->window->logMessage(3, "All PHP files parsed in $duration seconds.");
|
||||
}
|
||||
};
|
||||
|
||||
Loop\nextTick($processFile);
|
||||
Loop\setTimeout($processFile, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,26 @@ use PhpParser\NodeVisitor\NameResolver;
|
|||
|
||||
class Project
|
||||
{
|
||||
/**
|
||||
* An associative array [string => PhpDocument]
|
||||
* that maps URIs to loaded PhpDocuments
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $documents;
|
||||
|
||||
/**
|
||||
* Instance of the PHP parser
|
||||
*
|
||||
* @var ParserAbstract
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
/**
|
||||
* Reference to the language server client interface
|
||||
*
|
||||
* @var LanguageClient
|
||||
*/
|
||||
private $client;
|
||||
|
||||
public function __construct(LanguageClient $client)
|
||||
|
|
|
@ -30,32 +30,36 @@ class ProtocolStreamReader implements ProtocolReader
|
|||
{
|
||||
$this->input = $input;
|
||||
Loop\addReadStream($this->input, function() {
|
||||
$c = fgetc($this->input);
|
||||
$this->buffer .= $c;
|
||||
switch ($this->parsingMode) {
|
||||
case ParsingMode::HEADERS:
|
||||
if ($this->buffer === "\r\n") {
|
||||
$this->parsingMode = ParsingMode::BODY;
|
||||
$this->contentLength = (int)$this->headers['Content-Length'];
|
||||
$this->buffer = '';
|
||||
} else if (substr($this->buffer, -2) === "\r\n") {
|
||||
$parts = explode(':', $this->buffer);
|
||||
$this->headers[$parts[0]] = trim($parts[1]);
|
||||
$this->buffer = '';
|
||||
}
|
||||
break;
|
||||
case ParsingMode::BODY:
|
||||
if (strlen($this->buffer) === $this->contentLength) {
|
||||
if (isset($this->listener)) {
|
||||
$msg = new Message(MessageBody::parse($this->buffer), $this->headers);
|
||||
$listener = $this->listener;
|
||||
$listener($msg);
|
||||
while(($c = fgetc($this->input)) !== false) {
|
||||
$this->buffer .= $c;
|
||||
switch ($this->parsingMode) {
|
||||
case ParsingMode::HEADERS:
|
||||
if ($this->buffer === "\r\n") {
|
||||
$this->parsingMode = ParsingMode::BODY;
|
||||
$this->contentLength = (int)$this->headers['Content-Length'];
|
||||
$this->buffer = '';
|
||||
} else if (substr($this->buffer, -2) === "\r\n") {
|
||||
$parts = explode(':', $this->buffer);
|
||||
$this->headers[$parts[0]] = trim($parts[1]);
|
||||
$this->buffer = '';
|
||||
}
|
||||
$this->parsingMode = ParsingMode::HEADERS;
|
||||
$this->headers = [];
|
||||
$this->buffer = '';
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case ParsingMode::BODY:
|
||||
if (strlen($this->buffer) === $this->contentLength) {
|
||||
if (isset($this->listener)) {
|
||||
$msg = new Message(MessageBody::parse($this->buffer), $this->headers);
|
||||
$listener = $this->listener;
|
||||
$listener($msg);
|
||||
}
|
||||
$this->parsingMode = ParsingMode::HEADERS;
|
||||
$this->headers = [];
|
||||
$this->buffer = '';
|
||||
|
||||
// after reading a full message, leave to allow different tasks to run
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -31,6 +31,11 @@ class Workspace
|
|||
*/
|
||||
private $client;
|
||||
|
||||
/**
|
||||
* The current project database
|
||||
*
|
||||
* @var Project
|
||||
*/
|
||||
private $project;
|
||||
|
||||
public function __construct(Project $project, LanguageClient $client)
|
||||
|
@ -50,24 +55,4 @@ class Workspace
|
|||
{
|
||||
return $this->project->findSymbols($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* A notification sent from the client to the server to signal the change of configuration settings.
|
||||
*
|
||||
* @param The actual changed settings
|
||||
* @return void
|
||||
*/
|
||||
public function didChangeConfiguration($settings)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The document change notification is sent from the client to the server to signal changes to a text document.
|
||||
*
|
||||
* @param \LanguageServer\Protocol\FileEvent[] $textDocument
|
||||
* @return void
|
||||
*/
|
||||
public function didChangeWatchedFiles(array $changes)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@ declare(strict_types = 1);
|
|||
namespace LanguageServer;
|
||||
|
||||
use PhpParser\{NodeVisitorAbstract, Node};
|
||||
use PhpParser\Builder\Function_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
|
||||
use LanguageServer\Protocol\{SymbolInformation, SymbolKind, Range, Position, Location};
|
||||
|
||||
class SymbolFinder extends NodeVisitorAbstract
|
||||
|
@ -75,7 +78,7 @@ class SymbolFinder extends NodeVisitorAbstract
|
|||
}
|
||||
|
||||
// if we enter a method or function, increase the function counter
|
||||
if ($class === Node\Stmt\Function_::class || $class === Node\Stmt\ClassMethod::class) {
|
||||
if ($node instanceof Function_ || $node instanceof ClassMethod) {
|
||||
$this->functionCount++;
|
||||
}
|
||||
|
||||
|
@ -107,8 +110,7 @@ class SymbolFinder extends NodeVisitorAbstract
|
|||
array_pop($this->nameStack);
|
||||
|
||||
// if we leave a method or function, decrease the function counter
|
||||
$class = get_class($node);
|
||||
if ($class === Node\Stmt\Function_::class || $class === Node\Stmt\ClassMethod::class) {
|
||||
if ($node instanceof Function_ || $node instanceof ClassMethod) {
|
||||
$this->functionCount--;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace LanguageServer\Tests\Server;
|
|||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use LanguageServer\Tests\MockProtocolStream;
|
||||
use LanguageServer\{Server, Client, LanguageClient};
|
||||
use LanguageServer\{Server, Client, LanguageClient, Project, PhpDocument};
|
||||
use LanguageServer\Protocol\{TextDocumentItem, TextDocumentIdentifier, SymbolKind, DiagnosticSeverity, FormattingOptions};
|
||||
use AdvancedJsonRpc\{Request as RequestBody, Response as ResponseBody};
|
||||
|
||||
|
@ -13,7 +13,9 @@ class TextDocumentTest extends TestCase
|
|||
{
|
||||
public function testDocumentSymbol()
|
||||
{
|
||||
$textDocument = new Server\TextDocument(new LanguageClient(new MockProtocolStream()));
|
||||
$client = new LanguageClient(new MockProtocolStream());
|
||||
$project = new Project($client);
|
||||
$textDocument = new Server\TextDocument($project, $client);
|
||||
// Trigger parsing of source
|
||||
$textDocumentItem = new TextDocumentItem();
|
||||
$textDocumentItem->uri = 'whatever';
|
||||
|
@ -94,7 +96,7 @@ class TextDocumentTest extends TestCase
|
|||
]
|
||||
]
|
||||
],
|
||||
'containerName' => null
|
||||
'containerName' => 'TestClass'
|
||||
],
|
||||
[
|
||||
'name' => 'TestTrait',
|
||||
|
@ -151,7 +153,11 @@ class TextDocumentTest extends TestCase
|
|||
$this->args = func_get_args();
|
||||
}
|
||||
};
|
||||
$textDocument = new Server\TextDocument($client);
|
||||
|
||||
$project = new Project($client);
|
||||
|
||||
$textDocument = new Server\TextDocument($project, $client);
|
||||
|
||||
// Trigger parsing of source
|
||||
$textDocumentItem = new TextDocumentItem();
|
||||
$textDocumentItem->uri = 'whatever';
|
||||
|
@ -182,7 +188,10 @@ class TextDocumentTest extends TestCase
|
|||
|
||||
public function testFormatting()
|
||||
{
|
||||
$textDocument = new Server\TextDocument(new LanguageClient(new MockProtocolStream()));
|
||||
$client = new LanguageClient(new MockProtocolStream());
|
||||
$project = new Project($client);
|
||||
$textDocument = new Server\TextDocument($project, $client);
|
||||
|
||||
// Trigger parsing of source
|
||||
$textDocumentItem = new TextDocumentItem();
|
||||
$textDocumentItem->uri = 'whatever';
|
||||
|
|
Loading…
Reference in New Issue