1
0
Fork 0

Cleaned up code. Fixed tests

pull/31/head
Stephan Unverwerth 2016-09-18 21:51:23 +02:00
parent d597eeebf6
commit a34426fb4e
6 changed files with 85 additions and 64 deletions

View File

@ -75,12 +75,12 @@ class LanguageServer extends \AdvancedJsonRpc\Dispatcher
/** /**
* The initialize request is sent as the first request from the client to the server. * 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 int $processId The process Id of the parent process that started the server.
* @param ClientCapabilities $capabilities The capabilities provided by the client (editor) * @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 * @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 // start building project index
if ($rootPath) { if ($rootPath) {
@ -124,7 +124,7 @@ class LanguageServer extends \AdvancedJsonRpc\Dispatcher
/** /**
* Parses workspace files, one at a time. * 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 * @return void
*/ */
private function indexProject(string $rootPath) private function indexProject(string $rootPath)
@ -136,26 +136,29 @@ class LanguageServer extends \AdvancedJsonRpc\Dispatcher
foreach($files as $file) { foreach($files as $file) {
$fileList = array_merge($fileList, $file); $fileList = array_merge($fileList, $file);
} }
$numTotalFiles = count($fileList);
$startTime = microtime(true);
$processFile = function() use (&$fileList, &$processFile, &$rootPath){ $processFile = function() use (&$fileList, &$processFile, $rootPath, $numTotalFiles, $startTime) {
if ($file = array_pop($fileList)) { if ($file = array_pop($fileList)) {
$uri = 'file://'.($file[0] == '/' || $file[0] == '\\' ? '' : '/').str_replace('\\', '/', $file); $uri = 'file://'.($file[0] == '/' || $file[0] == '\\' ? '' : '/').str_replace('\\', '/', $file);
$numFiles = count($fileList); $fileNum = $numTotalFiles - count($fileList);
if (($numFiles % 100) == 0) { $shortName = substr($file, strlen($rootPath)+1);
$this->client->window->logMessage(3, $numFiles.' PHP files remaining.'); $this->client->window->logMessage(3, "Parsing file $fileNum/$numTotalFiles: $shortName.");
}
$this->project->getDocument($uri)->updateAst(file_get_contents($file)); $this->project->getDocument($uri)->updateAst(file_get_contents($file));
Loop\nextTick($processFile); Loop\setTimeout($processFile, 0);
} }
else { 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);
} }
} }

View File

@ -8,8 +8,26 @@ use PhpParser\NodeVisitor\NameResolver;
class Project class Project
{ {
/**
* An associative array [string => PhpDocument]
* that maps URIs to loaded PhpDocuments
*
* @var array
*/
private $documents; private $documents;
/**
* Instance of the PHP parser
*
* @var ParserAbstract
*/
private $parser; private $parser;
/**
* Reference to the language server client interface
*
* @var LanguageClient
*/
private $client; private $client;
public function __construct(LanguageClient $client) public function __construct(LanguageClient $client)

View File

@ -30,32 +30,36 @@ class ProtocolStreamReader implements ProtocolReader
{ {
$this->input = $input; $this->input = $input;
Loop\addReadStream($this->input, function() { Loop\addReadStream($this->input, function() {
$c = fgetc($this->input); while(($c = fgetc($this->input)) !== false) {
$this->buffer .= $c; $this->buffer .= $c;
switch ($this->parsingMode) { switch ($this->parsingMode) {
case ParsingMode::HEADERS: case ParsingMode::HEADERS:
if ($this->buffer === "\r\n") { if ($this->buffer === "\r\n") {
$this->parsingMode = ParsingMode::BODY; $this->parsingMode = ParsingMode::BODY;
$this->contentLength = (int)$this->headers['Content-Length']; $this->contentLength = (int)$this->headers['Content-Length'];
$this->buffer = ''; $this->buffer = '';
} else if (substr($this->buffer, -2) === "\r\n") { } else if (substr($this->buffer, -2) === "\r\n") {
$parts = explode(':', $this->buffer); $parts = explode(':', $this->buffer);
$this->headers[$parts[0]] = trim($parts[1]); $this->headers[$parts[0]] = trim($parts[1]);
$this->buffer = ''; $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);
} }
$this->parsingMode = ParsingMode::HEADERS; break;
$this->headers = []; case ParsingMode::BODY:
$this->buffer = ''; if (strlen($this->buffer) === $this->contentLength) {
} if (isset($this->listener)) {
break; $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;
}
} }
}); });
} }

View File

@ -31,6 +31,11 @@ class Workspace
*/ */
private $client; private $client;
/**
* The current project database
*
* @var Project
*/
private $project; private $project;
public function __construct(Project $project, LanguageClient $client) public function __construct(Project $project, LanguageClient $client)
@ -50,24 +55,4 @@ class Workspace
{ {
return $this->project->findSymbols($query); 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)
{
}
} }

View File

@ -4,6 +4,9 @@ declare(strict_types = 1);
namespace LanguageServer; namespace LanguageServer;
use PhpParser\{NodeVisitorAbstract, Node}; use PhpParser\{NodeVisitorAbstract, Node};
use PhpParser\Builder\Function_;
use PhpParser\Node\Stmt\ClassMethod;
use LanguageServer\Protocol\{SymbolInformation, SymbolKind, Range, Position, Location}; use LanguageServer\Protocol\{SymbolInformation, SymbolKind, Range, Position, Location};
class SymbolFinder extends NodeVisitorAbstract class SymbolFinder extends NodeVisitorAbstract
@ -75,7 +78,7 @@ class SymbolFinder extends NodeVisitorAbstract
} }
// if we enter a method or function, increase the function counter // 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++; $this->functionCount++;
} }
@ -107,8 +110,7 @@ class SymbolFinder extends NodeVisitorAbstract
array_pop($this->nameStack); array_pop($this->nameStack);
// if we leave a method or function, decrease the function counter // if we leave a method or function, decrease the function counter
$class = get_class($node); if ($node instanceof Function_ || $node instanceof ClassMethod) {
if ($class === Node\Stmt\Function_::class || $class === Node\Stmt\ClassMethod::class) {
$this->functionCount--; $this->functionCount--;
} }
} }

View File

@ -5,7 +5,7 @@ namespace LanguageServer\Tests\Server;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use LanguageServer\Tests\MockProtocolStream; 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 LanguageServer\Protocol\{TextDocumentItem, TextDocumentIdentifier, SymbolKind, DiagnosticSeverity, FormattingOptions};
use AdvancedJsonRpc\{Request as RequestBody, Response as ResponseBody}; use AdvancedJsonRpc\{Request as RequestBody, Response as ResponseBody};
@ -13,7 +13,9 @@ class TextDocumentTest extends TestCase
{ {
public function testDocumentSymbol() 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 // Trigger parsing of source
$textDocumentItem = new TextDocumentItem(); $textDocumentItem = new TextDocumentItem();
$textDocumentItem->uri = 'whatever'; $textDocumentItem->uri = 'whatever';
@ -94,7 +96,7 @@ class TextDocumentTest extends TestCase
] ]
] ]
], ],
'containerName' => null 'containerName' => 'TestClass'
], ],
[ [
'name' => 'TestTrait', 'name' => 'TestTrait',
@ -151,7 +153,11 @@ class TextDocumentTest extends TestCase
$this->args = func_get_args(); $this->args = func_get_args();
} }
}; };
$textDocument = new Server\TextDocument($client);
$project = new Project($client);
$textDocument = new Server\TextDocument($project, $client);
// Trigger parsing of source // Trigger parsing of source
$textDocumentItem = new TextDocumentItem(); $textDocumentItem = new TextDocumentItem();
$textDocumentItem->uri = 'whatever'; $textDocumentItem->uri = 'whatever';
@ -182,7 +188,10 @@ class TextDocumentTest extends TestCase
public function testFormatting() 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 // Trigger parsing of source
$textDocumentItem = new TextDocumentItem(); $textDocumentItem = new TextDocumentItem();
$textDocumentItem->uri = 'whatever'; $textDocumentItem->uri = 'whatever';