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;
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\PrettyPrinter\Standard as PrettyPrinter;
use PhpParser\NodeVisitor\NameResolver;
@ -104,7 +104,7 @@ class PhpDocument
* Re-parses a source file, updates symbols, reports parsing errors
* that may have occured as diagnostics and returns parsed nodes.
*
* @return \PhpParser\Node[]
* @return void
*/
public function parse()
{
@ -155,9 +155,9 @@ class PhpDocument
$traverser->traverse($stmts);
$this->symbols = $symbolFinder->symbols;
}
return $stmts;
$this->stmts = $stmts;
}
}
/**
@ -167,14 +167,13 @@ class PhpDocument
*/
public function getFormattedText()
{
$stmts = $this->parse();
if (empty($stmts)) {
if (empty($this->stmts)) {
return [];
}
$prettyPrinter = new PrettyPrinter();
$edit = new TextEdit();
$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];
}
@ -187,4 +186,22 @@ class PhpDocument
{
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 LanguageServer\Tests\MockProtocolStream;
use LanguageServer\{LanguageClient, Project};
use LanguageServer\Protocol\SymbolKind;
use LanguageServer\NodeVisitors\NodeAtPositionFinder;
use LanguageServer\Protocol\{SymbolKind, Position};
use PhpParser\Node;
class PhpDocumentTest extends TestCase
{
@ -67,4 +69,13 @@ class PhpDocumentTest extends TestCase
]
], 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);
}
}