Cache hover
parent
3c00a349a4
commit
279e2fb996
|
@ -45,4 +45,18 @@ class Definition
|
|||
* @var \phpDocumentor\Type|null
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* The first line of the declaration, for use in textDocument/hover
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $declarationLine;
|
||||
|
||||
/**
|
||||
* A documentation string, for use in textDocument/hover
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $documentation;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types = 1);
|
|||
namespace LanguageServer;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\PrettyPrinter\Standard as PrettyPrinter;
|
||||
use phpDocumentor\Reflection\{Types, Type, Fqsen, TypeResolver};
|
||||
use LanguageServer\Protocol\SymbolInformation;
|
||||
use Sabre\Event\Promise;
|
||||
|
@ -18,6 +19,61 @@ class DefinitionResolver
|
|||
{
|
||||
$this->project = $project;
|
||||
$this->typeResolver = new TypeResolver;
|
||||
$this->prettyPrinter = new PrettyPrinter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the declaration line for a given node
|
||||
*
|
||||
* @param Node $node
|
||||
* @return string
|
||||
*/
|
||||
public function getDeclarationLineFromNode(Node $node): string
|
||||
{
|
||||
if ($node instanceof Node\Stmt\PropertyProperty || $node instanceof Node\Const_) {
|
||||
// Properties and constants can have multiple declarations
|
||||
// Use the parent node (that includes the modifiers), but only render the requested declaration
|
||||
$child = $node;
|
||||
$node = $node->getAttribute('parentNode');
|
||||
$defLine = clone $node;
|
||||
$defLine->props = [$child];
|
||||
} else {
|
||||
$defLine = clone $node;
|
||||
}
|
||||
// Don't include the docblock in the declaration string
|
||||
$defLine->setAttribute('comments', []);
|
||||
if (isset($defLine->stmts)) {
|
||||
$defLine->stmts = [];
|
||||
}
|
||||
$defText = $this->prettyPrinter->prettyPrint([$defLine]);
|
||||
return strstr($defText, "\n", true) ?: $defText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the documentation string for a node, if it has one
|
||||
*
|
||||
* @param Node $node
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDocumentationFromNode(Node $node)
|
||||
{
|
||||
if ($node instanceof Node\Param) {
|
||||
$fn = $node->getAttribute('parentNode');
|
||||
$docBlock = $fn->getAttribute('docBlock');
|
||||
if ($docBlock !== null) {
|
||||
$tags = $docBlock->getTagsByName('param');
|
||||
foreach ($tags as $tag) {
|
||||
if ($tag->getVariableName() === $node->name) {
|
||||
return $tag->getDescription()->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$docBlock = $node->getAttribute('docBlock');
|
||||
if ($docBlock !== null) {
|
||||
return $docBlock->getSummary();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,6 +91,10 @@ class DefinitionResolver
|
|||
$def = new Definition;
|
||||
// Get symbol information from node (range, symbol kind)
|
||||
$def->symbolInformation = SymbolInformation::fromNode($defNode);
|
||||
// Declaration line
|
||||
$def->declarationLine = $this->getDeclarationLineFromNode($node);
|
||||
// Documentation
|
||||
$def->documentation = $this->getDocumentationFromNode($node);
|
||||
if ($defNode instanceof Node\Param) {
|
||||
// Get parameter type
|
||||
$def->type = $this->getTypeFromNode($defNode);
|
||||
|
|
|
@ -27,7 +27,7 @@ class DefinitionCollector extends NodeVisitorAbstract
|
|||
*/
|
||||
public $nodes = [];
|
||||
|
||||
public $definitionResolver;
|
||||
private $definitionResolver;
|
||||
|
||||
public function __construct(DefinitionResolver $definitionResolver)
|
||||
{
|
||||
|
@ -46,6 +46,9 @@ class DefinitionCollector extends NodeVisitorAbstract
|
|||
$def->fqn = $fqn;
|
||||
$def->symbolInformation = SymbolInformation::fromNode($node, $fqn);
|
||||
$def->type = $this->definitionResolver->getTypeFromNode($node);
|
||||
$def->declarationLine = $this->definitionResolver->getDeclarationLineFromNode($node);
|
||||
$def->documentation = $this->definitionResolver->getDocumentationFromNode($node);
|
||||
|
||||
$this->definitions[$fqn] = $def;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,66 +196,17 @@ class TextDocument
|
|||
return new Hover([]);
|
||||
}
|
||||
$range = Range::fromNode($node);
|
||||
if ($node instanceof Node\Expr\Variable) {
|
||||
$defNode = DefinitionResolver::resolveVariableToNode($node);
|
||||
} else {
|
||||
// Get the definition for whatever node is under the cursor
|
||||
$def = $this->definitionResolver->resolveReferenceNodeToDefinition($node);
|
||||
if ($def === null) {
|
||||
return new Hover([], $range);
|
||||
}
|
||||
// TODO inefficient. Add documentation and declaration line to Definition class
|
||||
// so document doesnt have to be loaded
|
||||
$document = yield $this->project->getOrLoadDocument($def->symbolInformation->location->uri);
|
||||
if ($document === null) {
|
||||
return new Hover([], $range);
|
||||
}
|
||||
$defNode = $document->getDefinitionNodeByFqn($def->fqn);
|
||||
// Get the definition for whatever node is under the cursor
|
||||
$def = $this->definitionResolver->resolveReferenceNodeToDefinition($node);
|
||||
if ($def === null) {
|
||||
return new Hover([], $range);
|
||||
}
|
||||
$contents = [];
|
||||
|
||||
// Build a declaration string
|
||||
if ($defNode instanceof Node\Stmt\PropertyProperty || $defNode instanceof Node\Const_) {
|
||||
// Properties and constants can have multiple declarations
|
||||
// Use the parent node (that includes the modifiers), but only render the requested declaration
|
||||
$child = $defNode;
|
||||
$defNode = $defNode->getAttribute('parentNode');
|
||||
$defLine = clone $defNode;
|
||||
$defLine->props = [$child];
|
||||
} else {
|
||||
$defLine = clone $defNode;
|
||||
if ($def->declarationLine) {
|
||||
$contents[] = new MarkedString('php', "<?php\n" . $def->declarationLine);
|
||||
}
|
||||
// Don't include the docblock in the declaration string
|
||||
$defLine->setAttribute('comments', []);
|
||||
if (isset($defLine->stmts)) {
|
||||
$defLine->stmts = [];
|
||||
if ($def->documentation) {
|
||||
$contents[] = $def->documentation;
|
||||
}
|
||||
$defText = $this->prettyPrinter->prettyPrint([$defLine]);
|
||||
$lines = explode("\n", $defText);
|
||||
if (isset($lines[0])) {
|
||||
$contents[] = new MarkedString('php', "<?php\n" . $lines[0]);
|
||||
}
|
||||
|
||||
// Get the documentation string
|
||||
if ($defNode instanceof Node\Param) {
|
||||
$fn = $defNode->getAttribute('parentNode');
|
||||
$docBlock = $fn->getAttribute('docBlock');
|
||||
if ($docBlock !== null) {
|
||||
$tags = $docBlock->getTagsByName('param');
|
||||
foreach ($tags as $tag) {
|
||||
if ($tag->getVariableName() === $defNode->name) {
|
||||
$contents[] = $tag->getDescription()->render();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$docBlock = $defNode->getAttribute('docBlock');
|
||||
if ($docBlock !== null) {
|
||||
$contents[] = $docBlock->getSummary();
|
||||
}
|
||||
}
|
||||
|
||||
return new Hover($contents, $range);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue