From f9240cd2beb3aa8b74dc71ab29ee54df077ff589 Mon Sep 17 00:00:00 2001 From: Ivan Bozhanov Date: Thu, 19 Jan 2017 20:33:31 +0200 Subject: [PATCH] added signature help --- fixtures/global_symbols.php | 6 ++- src/Definition.php | 7 +++ src/DefinitionResolver.php | 6 +++ src/LanguageServer.php | 3 ++ src/Server/TextDocument.php | 16 +++++- src/SignatureHelpProvider.php | 91 +++++++++++++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/SignatureHelpProvider.php diff --git a/fixtures/global_symbols.php b/fixtures/global_symbols.php index 6494848..787b1c7 100644 --- a/fixtures/global_symbols.php +++ b/fixtures/global_symbols.php @@ -55,9 +55,13 @@ class TestClass implements TestInterface * @param TestClass $testParameter Lorem sunt velit incididunt mollit * @return TestClass */ - public function testMethod($testParameter): TestInterface + public function testMethod( + string $testParameter = '()', + string $asdf = "," + ) : TestInterface { $this->testProperty = $testParameter; + $this->testMethod(); } } diff --git a/src/Definition.php b/src/Definition.php index d4b59cb..dab8295 100644 --- a/src/Definition.php +++ b/src/Definition.php @@ -89,4 +89,11 @@ class Definition * @var string */ public $documentation; + + /** + * Parameters array (for methods and functions), for use in textDocument/signatureHelp + * + * @var string[] + */ + public $parameters; } diff --git a/src/DefinitionResolver.php b/src/DefinitionResolver.php index 8cbddf7..58bc9e9 100644 --- a/src/DefinitionResolver.php +++ b/src/DefinitionResolver.php @@ -131,6 +131,12 @@ class DefinitionResolver $def->type = $this->getTypeFromNode($node); $def->declarationLine = $this->getDeclarationLineFromNode($node); $def->documentation = $this->getDocumentationFromNode($node); + $def->parameters = []; + if ($node instanceof Node\FunctionLike) { + foreach ($node->getParams() as $param) { + $def->parameters[] = $this->prettyPrinter->prettyPrint([$param]); + } + } return $def; } diff --git a/src/LanguageServer.php b/src/LanguageServer.php index b0af2f0..b4ba22b 100644 --- a/src/LanguageServer.php +++ b/src/LanguageServer.php @@ -247,6 +247,9 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher $serverCapabilities->completionProvider = new CompletionOptions; $serverCapabilities->completionProvider->resolveProvider = false; $serverCapabilities->completionProvider->triggerCharacters = ['$', '>']; + // Support "Signature Help" + $serverCapabilities->signatureHelpProvider = new SignatureHelpOptions; + $serverCapabilities->signatureHelpProvider->triggerCharacters = ['(']; // Support global references $serverCapabilities->xworkspaceReferencesProvider = true; $serverCapabilities->xdefinitionProvider = true; diff --git a/src/Server/TextDocument.php b/src/Server/TextDocument.php index a3183dc..b956698 100644 --- a/src/Server/TextDocument.php +++ b/src/Server/TextDocument.php @@ -5,7 +5,7 @@ namespace LanguageServer\Server; use PhpParser\PrettyPrinter\Standard as PrettyPrinter; use PhpParser\{Node, NodeTraverser}; -use LanguageServer\{LanguageClient, PhpDocumentLoader, PhpDocument, DefinitionResolver, CompletionProvider}; +use LanguageServer\{LanguageClient, PhpDocumentLoader, PhpDocument, DefinitionResolver, CompletionProvider, SignatureHelpProvider}; use LanguageServer\NodeVisitor\VariableReferencesCollector; use LanguageServer\Protocol\{ SymbolLocationInformation, @@ -63,6 +63,11 @@ class TextDocument */ protected $completionProvider; + /** + * @var SignatureHelpProvider + */ + protected $signatureHelpProvider; + /** * @var ReadableIndex */ @@ -99,6 +104,7 @@ class TextDocument $this->prettyPrinter = new PrettyPrinter(); $this->definitionResolver = $definitionResolver; $this->completionProvider = new CompletionProvider($this->definitionResolver, $index); + $this->signatureHelpProvider = new SignatureHelpProvider($this->definitionResolver, $index); $this->index = $index; $this->composerJson = $composerJson; $this->composerLock = $composerLock; @@ -343,6 +349,14 @@ class TextDocument }); } + public function signatureHelp(TextDocumentIdentifier $textDocument, Position $position): Promise + { + return coroutine(function () use ($textDocument, $position) { + $document = yield $this->documentLoader->getOrLoad($textDocument->uri); + return $this->signatureHelpProvider->provideSignature($document, $position); + }); + } + /** * This method is the same as textDocument/definition, except that * diff --git a/src/SignatureHelpProvider.php b/src/SignatureHelpProvider.php new file mode 100644 index 0000000..553e0bf --- /dev/null +++ b/src/SignatureHelpProvider.php @@ -0,0 +1,91 @@ +definitionResolver = $definitionResolver; + $this->index = $index; + } + + /** + * Returns signature help for a specific cursor position in a document + * + * @param PhpDocument $doc The opened document + * @param Position $pos The cursor position + * @return SignatureHelp + */ + public function provideSignature(PhpDocument $doc, Position $pos): SignatureHelp + { + $node = $doc->getNodeAtPosition($pos); + $help = new SignatureHelp; + $help->signatures = []; + + if ($node instanceof Node\Expr\FuncCall) { + if ($def = $this->definitionResolver->resolveReferenceNodeToDefinition($node)) { + $signature = new SignatureInformation; + $signature->label = str_replace('()', '', $def->fqn); + $signature->documentation = $def->documentation; + $signature->parameters = []; + foreach ($def->parameters as $param) { + $p = new ParameterInformation; + $p->label = $param; + $signature->parameters[] = $p; + } + $help->signatures[] = $signature; + } + } else if ($node instanceof Node\Expr\MethodCall) { + if ($def = $this->definitionResolver->resolveReferenceNodeToDefinition($node)) { + $signature = new SignatureInformation; + $signature->label = str_replace('()', '', explode('->', $def->fqn)[1]); + $signature->documentation = $def->documentation; + $signature->parameters = []; + foreach ($def->parameters as $param) { + $p = new ParameterInformation; + $p->label = $param; + $signature->parameters[] = $p; + } + $help->signatures[] = $signature; + } + } else if ($node instanceof Node\Expr\StaticCall) { + $signature = new SignatureInformation; + $signature->label = str_replace('()', '', explode('::', $def->fqn)[1]); + $signature->documentation = $def->documentation; + $signature->parameters = []; + foreach ($def->parameters as $param) { + $p = new ParameterInformation; + $p->label = $param; + $signature->parameters[] = $p; + } + $help->signatures[] = $signature; + } + + return $help; + } +}