Skip to content

Commit 2fd3b58

Browse files
committed
Add method to find out node at position
Keep AST in memory
1 parent 4786fe1 commit 2fd3b58

File tree

3 files changed

+81
-9
lines changed

3 files changed

+81
-9
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
declare(strict_types = 1);
3+
4+
namespace LanguageServer\NodeVisitors;
5+
6+
use PhpParser\{NodeVisitorAbstract, Node};
7+
use LanguageServer\Protocol\Position;
8+
9+
/**
10+
* Finds the Node at a specified position
11+
* Depends on ColumnCalculator
12+
*/
13+
class NodeAtPositionFinder extends NodeVisitorAbstract
14+
{
15+
/**
16+
* The node at the position, if found
17+
*
18+
* @var Node
19+
*/
20+
public $node;
21+
22+
/**
23+
* @var Position
24+
*/
25+
private $position;
26+
27+
/**
28+
* @param Position $position The position where the node is located
29+
*/
30+
public function __construct(Position $position)
31+
{
32+
$this->position = $position;
33+
}
34+
35+
public function leaveNode(Node $node)
36+
{
37+
if (
38+
!isset($this->node)
39+
&& $node->getAttribute('startLine') <= $this->position->line + 1
40+
&& $node->getAttribute('endLine') >= $this->position->line + 1
41+
&& $node->getAttribute('startColumn') <= $this->position->character + 1
42+
&& $node->getAttribute('endColumn') >= $this->position->character + 1
43+
) {
44+
$this->node = $node;
45+
}
46+
}
47+
}

src/PhpDocument.php

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace LanguageServer;
55

66
use LanguageServer\Protocol\{Diagnostic, DiagnosticSeverity, Range, Position, SymbolKind, TextEdit};
7-
use LanguageServer\NodeVisitors\{ReferencesAdder, SymbolFinder, ColumnCalculator};
7+
use LanguageServer\NodeVisitors\{NodeAtPositionFinder, ReferencesAdder, SymbolFinder, ColumnCalculator};
88
use PhpParser\{Error, Comment, Node, ParserFactory, NodeTraverser, Lexer, Parser};
99
use PhpParser\PrettyPrinter\Standard as PrettyPrinter;
1010
use PhpParser\NodeVisitor\NameResolver;
@@ -104,7 +104,7 @@ public function updateContent(string $content)
104104
* Re-parses a source file, updates symbols, reports parsing errors
105105
* that may have occured as diagnostics and returns parsed nodes.
106106
*
107-
* @return \PhpParser\Node[]
107+
* @return void
108108
*/
109109
public function parse()
110110
{
@@ -155,9 +155,9 @@ public function parse()
155155
$traverser->traverse($stmts);
156156

157157
$this->symbols = $symbolFinder->symbols;
158-
}
159158

160-
return $stmts;
159+
$this->stmts = $stmts;
160+
}
161161
}
162162

163163
/**
@@ -167,14 +167,13 @@ public function parse()
167167
*/
168168
public function getFormattedText()
169169
{
170-
$stmts = $this->parse();
171-
if (empty($stmts)) {
170+
if (empty($this->stmts)) {
172171
return [];
173172
}
174173
$prettyPrinter = new PrettyPrinter();
175174
$edit = new TextEdit();
176175
$edit->range = new Range(new Position(0, 0), new Position(PHP_INT_MAX, PHP_INT_MAX));
177-
$edit->newText = $prettyPrinter->prettyPrintFile($stmts);
176+
$edit->newText = $prettyPrinter->prettyPrintFile($this->stmts);
178177
return [$edit];
179178
}
180179

@@ -187,4 +186,19 @@ public function getContent()
187186
{
188187
return $this->content;
189188
}
189+
190+
/**
191+
* Returns the node at a specified position
192+
*
193+
* @param Position $position
194+
* @return Node|null
195+
*/
196+
public function getNodeAtPosition(Position $position)
197+
{
198+
$traverser = new NodeTraverser;
199+
$finder = new NodeAtPositionFinder($position);
200+
$traverser->addVisitor($finder);
201+
$traverser->traverse($this->stmts);
202+
return $finder->node;
203+
}
190204
}

tests/PhpDocumentTest.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
use PHPUnit\Framework\TestCase;
77
use LanguageServer\Tests\MockProtocolStream;
88
use LanguageServer\{LanguageClient, Project};
9-
use LanguageServer\Protocol\SymbolKind;
9+
use LanguageServer\NodeVisitors\NodeAtPositionFinder;
10+
use LanguageServer\Protocol\{SymbolKind, Position};
11+
use PhpParser\Node;
1012

1113
class PhpDocumentTest extends TestCase
1214
{
@@ -23,7 +25,7 @@ public function setUp()
2325
public function testParsesVariableVariables()
2426
{
2527
$document = $this->project->getDocument('whatever');
26-
28+
2729
$document->updateContent("<?php\n$\$a = 'foo';\n\$bar = 'baz';\n");
2830

2931
$symbols = $document->getSymbols();
@@ -67,4 +69,13 @@ public function testParsesVariableVariables()
6769
]
6870
], json_decode(json_encode($symbols), true));
6971
}
72+
73+
public function testGetNodeAtPosition()
74+
{
75+
$document = $this->project->getDocument('whatever');
76+
$document->updateContent("<?php\n$\$a = new SomeClass;");
77+
$node = $document->getNodeAtPosition(new Position(1, 13));
78+
$this->assertInstanceOf(Node\Name\FullyQualified::class, $node);
79+
$this->assertEquals('SomeClass', (string)$node);
80+
}
7081
}

0 commit comments

Comments
 (0)