diff --git a/src/NodeVisitors/NodeAtPositionFinder.php b/src/NodeVisitors/NodeAtPositionFinder.php new file mode 100644 index 0000000..35de06f --- /dev/null +++ b/src/NodeVisitors/NodeAtPositionFinder.php @@ -0,0 +1,47 @@ +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; + } + } +} diff --git a/src/PhpDocument.php b/src/PhpDocument.php index ac46a85..8a264c6 100644 --- a/src/PhpDocument.php +++ b/src/PhpDocument.php @@ -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; + } } diff --git a/tests/PhpDocumentTest.php b/tests/PhpDocumentTest.php index 465748a..40a5dea 100644 --- a/tests/PhpDocumentTest.php +++ b/tests/PhpDocumentTest.php @@ -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 { @@ -23,7 +25,7 @@ class PhpDocumentTest extends TestCase public function testParsesVariableVariables() { $document = $this->project->getDocument('whatever'); - + $document->updateContent("getSymbols(); @@ -67,4 +69,13 @@ class PhpDocumentTest extends TestCase ] ], json_decode(json_encode($symbols), true)); } + + public function testGetNodeAtPosition() + { + $document = $this->project->getDocument('whatever'); + $document->updateContent("getNodeAtPosition(new Position(1, 13)); + $this->assertInstanceOf(Node\Name\FullyQualified::class, $node); + $this->assertEquals('SomeClass', (string)$node); + } }