Skip to content

Commit a40cf73

Browse files
phil-nelsonfelixfbecker
authored andcommitted
feat: Signature help (#547)
closes #18
1 parent 7831654 commit a40cf73

File tree

70 files changed

+1183
-161
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1183
-161
lines changed

fixtures/signature_help/calls.php

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace Foo;
4+
5+
class Test
6+
{
7+
/**
8+
* Constructor comment goes here
9+
*
10+
* @param string $first First param
11+
* @param int $second Second param
12+
* @param Test $third Third param with a longer description
13+
*/
14+
public function __construct(string $first, int $second, Test $third)
15+
{
16+
}
17+
18+
/**
19+
* Function doc
20+
*
21+
* @param SomethingElse $a A param with a different doc type
22+
* @param int|null $b Param with default value
23+
*/
24+
public function foo(\DateTime $a, int $b = null)
25+
{
26+
}
27+
28+
public static function bar($a)
29+
{
30+
}
31+
32+
/**
33+
* Method with no params
34+
*/
35+
public function baz()
36+
{
37+
}
38+
}
39+
40+
/**
41+
* @param int $i Global function param one
42+
* @param bool $b Default false param
43+
* @param Test|null ...$things Test things
44+
*/
45+
function foo(int $i, bool $b = false, Test ...$things = null)
46+
{
47+
}
48+
49+
$t = new Test();
50+
$t = new Test(1, );
51+
$t->foo();
52+
$t->foo(1,
53+
$t->foo(1,);
54+
$t->baz();
55+
56+
foo(
57+
1,
58+
foo(1, 2,
59+
);
60+
61+
Test::bar();
62+
63+
new $foo();
64+
new $foo(1, );
65+
66+
new NotExist();

src/Definition.php

+7
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ class Definition
9999
*/
100100
public $documentation;
101101

102+
/**
103+
* Signature information if this definition is for a FunctionLike, for use in textDocument/signatureHelp
104+
*
105+
* @var SignatureInformation
106+
*/
107+
public $signatureInformation;
108+
102109
/**
103110
* Yields the definitons of all ancestor classes (the Definition fqn is yielded as key)
104111
*

src/DefinitionResolver.php

+13
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use LanguageServer\Protocol\SymbolInformation;
88
use Microsoft\PhpParser;
99
use Microsoft\PhpParser\Node;
10+
use Microsoft\PhpParser\FunctionLike;
1011
use phpDocumentor\Reflection\{
1112
DocBlock, DocBlockFactory, Fqsen, Type, TypeResolver, Types
1213
};
@@ -34,6 +35,13 @@ class DefinitionResolver
3435
*/
3536
private $docBlockFactory;
3637

38+
/**
39+
* Creates SignatureInformation
40+
*
41+
* @var SignatureInformationFactory
42+
*/
43+
private $signatureInformationFactory;
44+
3745
/**
3846
* @param ReadableIndex $index
3947
*/
@@ -42,6 +50,7 @@ public function __construct(ReadableIndex $index)
4250
$this->index = $index;
4351
$this->typeResolver = new TypeResolver;
4452
$this->docBlockFactory = DocBlockFactory::createInstance();
53+
$this->signatureInformationFactory = new SignatureInformationFactory($this);
4554
}
4655

4756
/**
@@ -232,6 +241,10 @@ public function createDefinitionFromNode(Node $node, string $fqn = null): Defini
232241
$def->documentation = $this->getDocumentationFromNode($node);
233242
}
234243

244+
if ($node instanceof FunctionLike) {
245+
$def->signatureInformation = $this->signatureInformationFactory->create($node);
246+
}
247+
235248
return $def;
236249
}
237250

src/LanguageServer.php

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
TextDocumentSyncKind,
1010
Message,
1111
InitializeResult,
12-
CompletionOptions
12+
CompletionOptions,
13+
SignatureHelpOptions
1314
};
1415
use LanguageServer\FilesFinder\{FilesFinder, ClientFilesFinder, FileSystemFilesFinder};
1516
use LanguageServer\ContentRetriever\{ContentRetriever, ClientContentRetriever, FileSystemContentRetriever};
@@ -275,6 +276,10 @@ public function initialize(ClientCapabilities $capabilities, string $rootPath =
275276
$serverCapabilities->completionProvider = new CompletionOptions;
276277
$serverCapabilities->completionProvider->resolveProvider = false;
277278
$serverCapabilities->completionProvider->triggerCharacters = ['$', '>'];
279+
280+
$serverCapabilities->signatureHelpProvider = new SignatureHelpOptions();
281+
$serverCapabilities->signatureHelpProvider->triggerCharacters = ['(', ','];
282+
278283
// Support global references
279284
$serverCapabilities->xworkspaceReferencesProvider = true;
280285
$serverCapabilities->xdefinitionProvider = true;

src/Protocol/ParameterInformation.php

+13
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,17 @@ class ParameterInformation
2323
* @var string|null
2424
*/
2525
public $documentation;
26+
27+
/**
28+
* Create ParameterInformation
29+
*
30+
* @param string $label The label of this signature. Will be shown in the UI.
31+
* @param string $documentation The human-readable doc-comment of this signature. Will be shown in the UI but can
32+
* be omitted.
33+
*/
34+
public function __construct(string $label, string $documentation = null)
35+
{
36+
$this->label = $label;
37+
$this->documentation = $documentation;
38+
}
2639
}

src/Protocol/SignatureHelp.php

+14
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,18 @@ class SignatureHelp
2929
* @var int|null
3030
*/
3131
public $activeParameter;
32+
33+
/**
34+
* Create a SignatureHelp
35+
*
36+
* @param SignatureInformation[] $signatures List of signature information
37+
* @param int|null $activeSignature The active signature, zero based
38+
* @param int|null $activeParameter The active parameter, zero based
39+
*/
40+
public function __construct(array $signatures = [], $activeSignature = null, int $activeParameter = null)
41+
{
42+
$this->signatures = $signatures;
43+
$this->activeSignature = $activeSignature;
44+
$this->activeParameter = $activeParameter;
45+
}
3246
}

src/Protocol/SignatureInformation.php

+15
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,19 @@ class SignatureInformation
3131
* @var ParameterInformation[]|null
3232
*/
3333
public $parameters;
34+
35+
/**
36+
* Create a SignatureInformation
37+
*
38+
* @param string $label The label of this signature. Will be shown in the UI.
39+
* @param ParameterInformation[]|null The parameters of this signature
40+
* @param string|null The human-readable doc-comment of this signature. Will be shown in the UI
41+
* but can be omitted.
42+
*/
43+
public function __construct(string $label, array $parameters = null, string $documentation = null)
44+
{
45+
$this->label = $label;
46+
$this->parameters = $parameters;
47+
$this->documentation = $documentation;
48+
}
3449
}

src/Server/TextDocument.php

+24-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace LanguageServer\Server;
55

66
use LanguageServer\{
7-
CompletionProvider, LanguageClient, PhpDocument, PhpDocumentLoader, DefinitionResolver
7+
CompletionProvider, SignatureHelpProvider, LanguageClient, PhpDocument, PhpDocumentLoader, DefinitionResolver
88
};
99
use LanguageServer\Index\ReadableIndex;
1010
use LanguageServer\Protocol\{
@@ -59,6 +59,11 @@ class TextDocument
5959
*/
6060
protected $completionProvider;
6161

62+
/**
63+
* @var SignatureHelpProvider
64+
*/
65+
protected $signatureHelpProvider;
66+
6267
/**
6368
* @var ReadableIndex
6469
*/
@@ -94,6 +99,7 @@ public function __construct(
9499
$this->client = $client;
95100
$this->definitionResolver = $definitionResolver;
96101
$this->completionProvider = new CompletionProvider($this->definitionResolver, $index);
102+
$this->signatureHelpProvider = new SignatureHelpProvider($this->definitionResolver, $index, $documentLoader);
97103
$this->index = $index;
98104
$this->composerJson = $composerJson;
99105
$this->composerLock = $composerLock;
@@ -237,6 +243,23 @@ public function references(
237243
});
238244
}
239245

246+
/**
247+
* The signature help request is sent from the client to the server to request signature information at a given
248+
* cursor position.
249+
*
250+
* @param TextDocumentIdentifier $textDocument The text document
251+
* @param Position $position The position inside the text document
252+
*
253+
* @return Promise <SignatureHelp>
254+
*/
255+
public function signatureHelp(TextDocumentIdentifier $textDocument, Position $position): Promise
256+
{
257+
return coroutine(function () use ($textDocument, $position) {
258+
$document = yield $this->documentLoader->getOrLoad($textDocument->uri);
259+
return $this->signatureHelpProvider->getSignatureHelp($document, $position);
260+
});
261+
}
262+
240263
/**
241264
* The goto definition request is sent from the client to the server to resolve the definition location of a symbol
242265
* at a given text document position.

0 commit comments

Comments
 (0)