1
0
Fork 0

Add method to find out node at position

Keep AST in memory
pull/49/head
Felix Becker 2016-10-08 13:34:49 +02:00
parent 4786fe173c
commit 48c71e5bc1
3 changed files with 84 additions and 9 deletions

View File

@ -0,0 +1,47 @@
<?php
declare(strict_types = 1);
namespace LanguageServer\NodeVisitors;
use PhpParser\{NodeVisitorAbstract, Node};
use LanguageServer\Protocol\Position;
/**
* Finds the Node at a specified position
* Depends on ColumnCalculator
*/
class NodeAtPositionFinder extends NodeVisitorAbstract
{
/**
* The node at the position, if found
*
* @var Node
*/
public $node;
/**
* @var Position
*/
private $position;
/**
* @param Position $position The position where the node is located
*/
public function __construct(Position $position)
{
$this->position = $position;
}
public function leaveNode(Node $node)
{
if (
!isset($this->node)
&& $node->getAttribute('startLine') <= $this->position->line + 1
&& $node->getAttribute('endLine') >= $this->position->line + 1
&& $node->getAttribute('startColumn') <= $this->position->character + 1
&& $node->getAttribute('endColumn') >= $this->position->character + 1
) {
$this->node = $node;
}
}
}

View File

@ -4,7 +4,7 @@ declare(strict_types = 1);
namespace LanguageServer; namespace LanguageServer;
use LanguageServer\Protocol\{Diagnostic, DiagnosticSeverity, Range, Position, SymbolKind, TextEdit}; use LanguageServer\Protocol\{Diagnostic, DiagnosticSeverity, Range, Position, SymbolKind, TextEdit};
use LanguageServer\NodeVisitors\{ReferencesAdder, SymbolFinder, ColumnCalculator}; use LanguageServer\NodeVisitors\{NodeAtPositionFinder, ReferencesAdder, SymbolFinder, ColumnCalculator};
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;
@ -104,7 +104,7 @@ class PhpDocument
* 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 void
*/ */
public function parse() public function parse()
{ {
@ -155,9 +155,9 @@ class PhpDocument
$traverser->traverse($stmts); $traverser->traverse($stmts);
$this->symbols = $symbolFinder->symbols; $this->symbols = $symbolFinder->symbols;
}
return $stmts; $this->stmts = $stmts;
}
} }
/** /**
@ -167,14 +167,13 @@ class PhpDocument
*/ */
public function getFormattedText() public function getFormattedText()
{ {
$stmts = $this->parse(); if (empty($this->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($this->stmts);
return [$edit]; return [$edit];
} }
@ -187,4 +186,22 @@ class PhpDocument
{ {
return $this->content; return $this->content;
} }
/**
* Returns the node at a specified position
*
* @param Position $position
* @return Node|null
*/
public function getNodeAtPosition(Position $position)
{
if ($this->stmts === null) {
return null;
}
$traverser = new NodeTraverser;
$finder = new NodeAtPositionFinder($position);
$traverser->addVisitor($finder);
$traverser->traverse($this->stmts);
return $finder->node;
}
} }

View File

@ -6,7 +6,9 @@ namespace LanguageServer\Tests\Server;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use LanguageServer\Tests\MockProtocolStream; use LanguageServer\Tests\MockProtocolStream;
use LanguageServer\{LanguageClient, Project}; use LanguageServer\{LanguageClient, Project};
use LanguageServer\Protocol\SymbolKind; use LanguageServer\NodeVisitors\NodeAtPositionFinder;
use LanguageServer\Protocol\{SymbolKind, Position};
use PhpParser\Node;
class PhpDocumentTest extends TestCase class PhpDocumentTest extends TestCase
{ {
@ -67,4 +69,13 @@ class PhpDocumentTest extends TestCase
] ]
], json_decode(json_encode($symbols), true)); ], json_decode(json_encode($symbols), true));
} }
public function testGetNodeAtPosition()
{
$document = $this->project->getDocument('whatever');
$document->updateContent("<?php\n$\$a = new SomeClass;");
$node = $document->getNodeAtPosition(new Position(1, 13));
$this->assertInstanceOf(Node\Name\FullyQualified::class, $node);
$this->assertEquals('SomeClass', (string)$node);
}
} }