1
0
Fork 0

Correct code style

pull/31/head
Felix Becker 2016-09-29 18:14:50 +02:00
parent 5f8e37be9e
commit b99fb94840
9 changed files with 353 additions and 360 deletions

View File

@ -1,60 +1,60 @@
<?php <?php
declare(strict_types = 1); declare(strict_types = 1);
namespace LanguageServer\Client; namespace LanguageServer\Client;
use AdvancedJsonRpc\Notification as NotificationBody; use AdvancedJsonRpc\Notification as NotificationBody;
use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer}; use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer};
use PhpParser\NodeVisitor\NameResolver; use PhpParser\NodeVisitor\NameResolver;
use LanguageServer\ProtocolWriter; use LanguageServer\ProtocolWriter;
use LanguageServer\Protocol\{TextDocumentItem, TextDocumentIdentifier, VersionedTextDocumentIdentifier, Message}; use LanguageServer\Protocol\{TextDocumentItem, TextDocumentIdentifier, VersionedTextDocumentIdentifier, Message};
/** /**
* Provides method handlers for all window/* methods * Provides method handlers for all window/* methods
*/ */
class Window class Window
{ {
/** /**
* @var ProtocolWriter * @var ProtocolWriter
*/ */
private $protocolWriter; private $protocolWriter;
public function __construct(ProtocolWriter $protocolWriter) public function __construct(ProtocolWriter $protocolWriter)
{ {
$this->protocolWriter = $protocolWriter; $this->protocolWriter = $protocolWriter;
} }
/** /**
* The show message notification is sent from a server to a client to ask the client to display a particular message in the user interface. * The show message notification is sent from a server to a client to ask the client to display a particular message in the user interface.
* *
* @param int $type * @param int $type
* @param string $message * @param string $message
*/ */
public function showMessage(int $type, string $message) public function showMessage(int $type, string $message)
{ {
$this->protocolWriter->write(new Message(new NotificationBody( $this->protocolWriter->write(new Message(new NotificationBody(
'window/showMessage', 'window/showMessage',
(object)[ (object)[
'type' => $type, 'type' => $type,
'message' => $message 'message' => $message
] ]
))); )));
} }
/** /**
* The log message notification is sent from the server to the client to ask the client to log a particular message. * The log message notification is sent from the server to the client to ask the client to log a particular message.
* *
* @param int $type * @param int $type
* @param string $message * @param string $message
*/ */
public function logMessage(int $type, string $message) public function logMessage(int $type, string $message)
{ {
$this->protocolWriter->write(new Message(new NotificationBody( $this->protocolWriter->write(new Message(new NotificationBody(
'window/logMessage', 'window/logMessage',
(object)[ (object)[
'type' => $type, 'type' => $type,
'message' => $message 'message' => $message
] ]
))); )));
} }
} }

View File

@ -133,22 +133,22 @@ class LanguageServer extends \AdvancedJsonRpc\Dispatcher
$numTotalFiles = count($fileList); $numTotalFiles = count($fileList);
$startTime = microtime(true); $startTime = microtime(true);
$processFile = function() use (&$fileList, &$processFile, $rootPath, $numTotalFiles, $startTime) { $processFile = function() use (&$fileList, &$processFile, $rootPath, $numTotalFiles, $startTime) {
if ($file = array_pop($fileList)) { if ($file = array_pop($fileList)) {
$uri = pathToUri($file); $uri = pathToUri($file);
$fileNum = $numTotalFiles - count($fileList); $fileNum = $numTotalFiles - count($fileList);
$shortName = substr($file, strlen($rootPath)+1); $shortName = substr($file, strlen($rootPath)+1);
$this->client->window->logMessage(3, "Parsing file $fileNum/$numTotalFiles: $shortName."); $this->client->window->logMessage(3, "Parsing file $fileNum/$numTotalFiles: $shortName.");
$this->project->getDocument($uri)->updateContent(file_get_contents($file)); $this->project->getDocument($uri)->updateContent(file_get_contents($file));
Loop\setTimeout($processFile, 0); Loop\setTimeout($processFile, 0);
} }
else { else {
$duration = (int)(microtime(true) - $startTime); $duration = (int)(microtime(true) - $startTime);
$mem = (int)(memory_get_usage(true)/(1024*1024)); $mem = (int)(memory_get_usage(true) / (1024 * 1024));
$this->client->window->logMessage(3, "All PHP files parsed in $duration seconds. $mem MiB allocated."); $this->client->window->logMessage(3, "All PHP files parsed in $duration seconds. $mem MiB allocated.");
} }
}; };

View File

@ -1,141 +1,140 @@
<?php <?php
namespace LanguageServer; namespace LanguageServer;
use \LanguageServer\Protocol\{Diagnostic, DiagnosticSeverity, Range, Position, SymbolKind, TextEdit}; use \LanguageServer\Protocol\{Diagnostic, DiagnosticSeverity, Range, Position, SymbolKind, TextEdit};
use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer, Parser}; use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer, Parser};
use PhpParser\PrettyPrinter\Standard as PrettyPrinter; use PhpParser\PrettyPrinter\Standard as PrettyPrinter;
use PhpParser\NodeVisitor\NameResolver; use PhpParser\NodeVisitor\NameResolver;
class PhpDocument class PhpDocument
{ {
private $client; private $client;
private $project; private $project;
private $parser; private $parser;
private $uri; private $uri;
private $content; private $content;
private $symbols = []; private $symbols = [];
public function __construct(string $uri, Project $project, LanguageClient $client, Parser $parser) public function __construct(string $uri, Project $project, LanguageClient $client, Parser $parser)
{ {
$this->uri = $uri; $this->uri = $uri;
$this->project = $project; $this->project = $project;
$this->client = $client; $this->client = $client;
$this->parser = $parser; $this->parser = $parser;
} }
/** /**
* Returns all symbols in this document. * Returns all symbols in this document.
* *
* @return SymbolInformation[] * @return SymbolInformation[]
*/ */
public function getSymbols() public function getSymbols()
{ {
return $this->symbols; return $this->symbols;
} }
/** /**
* Returns symbols in this document filtered by query string. * Returns symbols in this document filtered by query string.
* *
* @param string $query The search query * @param string $query The search query
* @return SymbolInformation[] * @return SymbolInformation[]
*/ */
public function findSymbols(string $query) public function findSymbols(string $query)
{ {
return array_filter($this->symbols, function($symbol) use(&$query) { return array_filter($this->symbols, function($symbol) use(&$query) {
return stripos($symbol->name, $query) !== false; return stripos($symbol->name, $query) !== false;
}); });
} }
/** /**
* Updates the content on this document. * Updates the content on this document.
* *
* @param string $content * @param string $content
*/ */
public function updateContent(string $content) public function updateContent(string $content)
{ {
$this->content = $content; $this->content = $content;
$this->parse(); $this->parse();
} }
/** /**
* Re-parses a source file, updates symbols, reports parsing errors * Re-parses a source file, updates symbols, reports parsing errors
* that may have occured as diagnostics and returns parsed nodes. * that may have occured as diagnostics and returns parsed nodes.
* *
* @return \PhpParser\Node[] * @return \PhpParser\Node[]
*/ */
public function parse() public function parse()
{ {
$stmts = null; $stmts = null;
$errors = []; $errors = [];
try { try {
$stmts = $this->parser->parse($this->content); $stmts = $this->parser->parse($this->content);
} } catch(\PhpParser\Error $e) {
catch(\PhpParser\Error $e) { // Lexer can throw errors. e.g for unterminated comments
// Lexer can throw errors. e.g for unterminated comments // unfortunately we don't get a location back
// unfortunately we don't get a location back $errors[] = $e;
$errors[] = $e; }
}
$errors = array_merge($this->parser->getErrors(), $errors);
$errors = array_merge($this->parser->getErrors(), $errors);
$diagnostics = [];
$diagnostics = []; foreach ($errors as $error) {
foreach ($errors as $error) { $diagnostic = new Diagnostic();
$diagnostic = new Diagnostic(); $diagnostic->range = new Range(
$diagnostic->range = new Range( new Position($error->getStartLine() - 1, $error->hasColumnInfo() ? $error->getStartColumn($this->content) - 1 : 0),
new Position($error->getStartLine() - 1, $error->hasColumnInfo() ? $error->getStartColumn($this->content) - 1 : 0), new Position($error->getEndLine() - 1, $error->hasColumnInfo() ? $error->getEndColumn($this->content) : 0)
new Position($error->getEndLine() - 1, $error->hasColumnInfo() ? $error->getEndColumn($this->content) : 0) );
); $diagnostic->severity = DiagnosticSeverity::ERROR;
$diagnostic->severity = DiagnosticSeverity::ERROR; $diagnostic->source = 'php';
$diagnostic->source = 'php'; // Do not include "on line ..." in the error message
// Do not include "on line ..." in the error message $diagnostic->message = $error->getRawMessage();
$diagnostic->message = $error->getRawMessage(); $diagnostics[] = $diagnostic;
$diagnostics[] = $diagnostic; }
} $this->client->textDocument->publishDiagnostics($this->uri, $diagnostics);
$this->client->textDocument->publishDiagnostics($this->uri, $diagnostics);
// $stmts can be null in case of a fatal parsing error
// $stmts can be null in case of a fatal parsing error if ($stmts) {
if ($stmts) { $traverser = new NodeTraverser;
$traverser = new NodeTraverser; $finder = new SymbolFinder($this->uri);
$finder = new SymbolFinder($this->uri); $traverser->addVisitor(new NameResolver);
$traverser->addVisitor(new NameResolver); $traverser->addVisitor(new ColumnCalculator($this->content));
$traverser->addVisitor(new ColumnCalculator($this->content)); $traverser->addVisitor($finder);
$traverser->addVisitor($finder); $traverser->traverse($stmts);
$traverser->traverse($stmts);
$this->symbols = $finder->symbols;
$this->symbols = $finder->symbols; }
}
return $stmts;
return $stmts; }
}
/**
/** * Returns this document as formatted text.
* Returns this document as formatted text. *
* * @return string
* @return string */
*/ public function getFormattedText()
public function getFormattedText() {
{ $stmts = $this->parse();
$stmts = $this->parse(); if (empty($stmts)) {
if (empty($stmts)) { return [];
return []; }
} $prettyPrinter = new PrettyPrinter();
$prettyPrinter = new PrettyPrinter(); $edit = new TextEdit();
$edit = new TextEdit(); $edit->range = new Range(new Position(0, 0), new Position(PHP_INT_MAX, PHP_INT_MAX));
$edit->range = new Range(new Position(0, 0), new Position(PHP_INT_MAX, PHP_INT_MAX)); $edit->newText = $prettyPrinter->prettyPrintFile($stmts);
$edit->newText = $prettyPrinter->prettyPrintFile($stmts); return [$edit];
return [$edit]; }
}
/**
/** * Returns this document's text content.
* Returns this document's text content. *
* * @return string
* @return string */
*/ public function getContent()
public function getContent() {
{ return $this->content;
return $this->content; }
} }
}

View File

@ -1,70 +1,70 @@
<?php <?php
namespace LanguageServer; namespace LanguageServer;
use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer}; use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer};
use PhpParser\PrettyPrinter\Standard as PrettyPrinter; use PhpParser\PrettyPrinter\Standard as PrettyPrinter;
use PhpParser\NodeVisitor\NameResolver; use PhpParser\NodeVisitor\NameResolver;
class Project class Project
{ {
/** /**
* An associative array [string => PhpDocument] * An associative array [string => PhpDocument]
* that maps URIs to loaded PhpDocuments * that maps URIs to loaded PhpDocuments
* *
* @var array * @var array
*/ */
private $documents; private $documents;
/** /**
* Instance of the PHP parser * Instance of the PHP parser
* *
* @var ParserAbstract * @var ParserAbstract
*/ */
private $parser; private $parser;
/** /**
* Reference to the language server client interface * Reference to the language server client interface
* *
* @var LanguageClient * @var LanguageClient
*/ */
private $client; private $client;
public function __construct(LanguageClient $client) public function __construct(LanguageClient $client)
{ {
$this->client = $client; $this->client = $client;
$lexer = new Lexer(['usedAttributes' => ['comments', 'startLine', 'endLine', 'startFilePos', 'endFilePos']]); $lexer = new Lexer(['usedAttributes' => ['comments', 'startLine', 'endLine', 'startFilePos', 'endFilePos']]);
$this->parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7, $lexer, ['throwOnError' => false]); $this->parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7, $lexer, ['throwOnError' => false]);
} }
/** /**
* Returns the document indicated by uri. Instantiates a new document if none exists. * Returns the document indicated by uri. Instantiates a new document if none exists.
* *
* @param string $uri * @param string $uri
* @return LanguageServer\PhpDocument * @return LanguageServer\PhpDocument
*/ */
public function getDocument(string $uri) public function getDocument(string $uri)
{ {
$uri = urldecode($uri); $uri = urldecode($uri);
if (!isset($this->documents[$uri])){ if (!isset($this->documents[$uri])) {
$this->documents[$uri] = new PhpDocument($uri, $this, $this->client, $this->parser); $this->documents[$uri] = new PhpDocument($uri, $this, $this->client, $this->parser);
} }
return $this->documents[$uri]; return $this->documents[$uri];
} }
/** /**
* Finds symbols in all documents, filtered by query parameter. * Finds symbols in all documents, filtered by query parameter.
* *
* @param string $query * @param string $query
* @return SymbolInformation[] * @return SymbolInformation[]
*/ */
public function findSymbols(string $query) public function findSymbols(string $query)
{ {
$queryResult = []; $queryResult = [];
foreach($this->documents as $uri => $document) { foreach($this->documents as $uri => $document) {
$queryResult = array_merge($queryResult, $document->findSymbols($query)); $queryResult = array_merge($queryResult, $document->findSymbols($query));
} }
return $queryResult; return $queryResult;
} }
} }

View File

@ -71,7 +71,7 @@ class TextDocument
{ {
$this->project->getDocument($textDocument->uri)->updateContent($contentChanges[0]->text); $this->project->getDocument($textDocument->uri)->updateContent($contentChanges[0]->text);
} }
/** /**
* The document formatting request is sent from the server to the client to format a whole document. * The document formatting request is sent from the server to the client to format a whole document.
@ -84,5 +84,4 @@ class TextDocument
{ {
return $this->project->getDocument($textDocument->uri)->getFormattedText(); return $this->project->getDocument($textDocument->uri)->getFormattedText();
} }
} }

View File

@ -1,58 +1,58 @@
<?php <?php
namespace LanguageServer\Server; namespace LanguageServer\Server;
use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer}; use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer};
use PhpParser\PrettyPrinter\Standard as PrettyPrinter; use PhpParser\PrettyPrinter\Standard as PrettyPrinter;
use PhpParser\NodeVisitor\NameResolver; use PhpParser\NodeVisitor\NameResolver;
use LanguageServer\{LanguageClient, ColumnCalculator, SymbolFinder, Project}; use LanguageServer\{LanguageClient, ColumnCalculator, SymbolFinder, Project};
use LanguageServer\Protocol\{ use LanguageServer\Protocol\{
TextDocumentItem, TextDocumentItem,
TextDocumentIdentifier, TextDocumentIdentifier,
VersionedTextDocumentIdentifier, VersionedTextDocumentIdentifier,
Diagnostic, Diagnostic,
DiagnosticSeverity, DiagnosticSeverity,
Range, Range,
Position, Position,
FormattingOptions, FormattingOptions,
TextEdit, TextEdit,
SymbolInformation SymbolInformation
}; };
/** /**
* Provides method handlers for all workspace/* methods * Provides method handlers for all workspace/* methods
*/ */
class Workspace class Workspace
{ {
/** /**
* The lanugage client object to call methods on the client * The lanugage client object to call methods on the client
* *
* @var \LanguageServer\LanguageClient * @var \LanguageServer\LanguageClient
*/ */
private $client; private $client;
/** /**
* The current project database * The current project database
* *
* @var Project * @var Project
*/ */
private $project; private $project;
public function __construct(Project $project, LanguageClient $client) public function __construct(Project $project, LanguageClient $client)
{ {
$this->project = $project; $this->project = $project;
$this->client = $client; $this->client = $client;
} }
/** /**
* The workspace symbol request is sent from the client to the server to list project-wide symbols matching the query string. * The workspace symbol request is sent from the client to the server to list project-wide symbols matching the query string.
* document. * document.
* *
* @param string $query * @param string $query
* @return SymbolInformation[] * @return SymbolInformation[]
*/ */
public function symbol(string $query): array public function symbol(string $query): array
{ {
return $this->project->findSymbols($query); return $this->project->findSymbols($query);
} }
} }

View File

@ -39,12 +39,12 @@ class SymbolFinder extends NodeVisitorAbstract
/** /**
* @var array * @var array
*/ */
private $nameStack = array(); private $nameStack = [];
/** /**
* @var array * @var array
*/ */
private $nodeStack = array(); private $nodeStack = [];
/** /**
* @var int * @var int
@ -58,26 +58,21 @@ class SymbolFinder extends NodeVisitorAbstract
public function enterNode(Node $node) public function enterNode(Node $node)
{ {
array_push($this->nodeStack, $node); $this->nodeStack[] = $node;
$containerName = end($this->nameStack); $containerName = end($this->nameStack);
// If we enter a named node, push its name onto name stack. // If we enter a named node, push its name onto name stack.
// Else push the current name onto stack. // Else push the current name onto stack.
if (!empty($node->name) && (is_string($node->name) || method_exists($node->name, '__toString')) && !empty((string)$node->name)) { if (!empty($node->name) && !empty((string)$node->name)) {
if (empty($containerName)) { if (empty($containerName)) {
array_push($this->nameStack, (string)$node->name); $this->nameStack[] = (string)$node->name;
} else if ($node instanceof Node\Stmt\ClassMethod) {
$this->nameStack[] = $containerName . '::' . (string)$node->name;
} else {
$this->nameStack[] = $containerName . '\\' . (string)$node->name;
} }
else { } else {
if ($node instanceof Node\Stmt\ClassMethod) { $this->nameStack[] = $containerName;
array_push($this->nameStack, $containerName . '::' . (string)$node->name);
}
else {
array_push($this->nameStack, $containerName . '\\' . (string)$node->name);
}
}
}
else {
array_push($this->nameStack, $containerName);
} }
$class = get_class($node); $class = get_class($node);

View File

@ -3,7 +3,7 @@
namespace LanguageServer; namespace LanguageServer;
/** /**
* Recursively Searches files with matching filename, starting at $path. * Recursively Searches files with matching filename, starting at $path.
* *
* @param string $path * @param string $path
* @param string $pattern * @param string $pattern
@ -13,15 +13,15 @@ function findFilesRecursive(string $path, string $pattern): array {
$dir = new \RecursiveDirectoryIterator($path); $dir = new \RecursiveDirectoryIterator($path);
$ite = new \RecursiveIteratorIterator($dir); $ite = new \RecursiveIteratorIterator($dir);
$files = new \RegexIterator($ite, $pattern, \RegexIterator::GET_MATCH); $files = new \RegexIterator($ite, $pattern, \RegexIterator::GET_MATCH);
$fileList = array(); $fileList = [];
foreach($files as $file) { foreach ($files as $file) {
$fileList = array_merge($fileList, $file); $fileList = array_merge($fileList, $file);
} }
return $fileList; return $fileList;
} }
/** /**
* Transforms an absolute file path into a URI as used by the language server protocol. * Transforms an absolute file path into a URI as used by the language server protocol.
* *
* @param string $filepath * @param string $filepath
* @return string * @return string
@ -29,5 +29,5 @@ function findFilesRecursive(string $path, string $pattern): array {
function pathToUri(string $filepath): string { function pathToUri(string $filepath): string {
$filepath = trim(str_replace('\\', '/', $filepath), '/'); $filepath = trim(str_replace('\\', '/', $filepath), '/');
$filepath = implode('/', array_map('urlencode', explode('/', $filepath))); $filepath = implode('/', array_map('urlencode', explode('/', $filepath)));
return 'file:///'.$filepath; return 'file:///' . $filepath;
} }

View File

@ -21,8 +21,8 @@ class FileUriTest extends TestCase
$uri = \LanguageServer\pathToUri('/usr/local/bin'); $uri = \LanguageServer\pathToUri('/usr/local/bin');
$this->assertEquals('file:///usr/local/bin', $uri); $this->assertEquals('file:///usr/local/bin', $uri);
$uri = \LanguageServer\pathToUri('a/b/c/'); $uri = \LanguageServer\pathToUri('a/b/c/test.txt');
$this->assertEquals('file:///a/b/c', $uri); $this->assertEquals('file:///a/b/c/test.txt', $uri);
$uri = \LanguageServer\pathToUri('/d/e/f'); $uri = \LanguageServer\pathToUri('/d/e/f');
$this->assertEquals('file:///d/e/f', $uri); $this->assertEquals('file:///d/e/f', $uri);