Method Handlers¶
Method handlers handle the RPC calls from the client.
They look like this:
<?php
use Phpactor\LanguageServer\Core\Handler\Handler;
use Amp\Promise;
class MyHandler implements Handler
{
public function methods(): array
{
return [
'method/name' => 'doSomething',
];
}
public function doSomething($args, CancellationToken $canellation): Promise
{
return new Success('hello!');
}
}
Once registered this command will respond to an RPC request to method/name
with hello!
.
Argument Resolvers¶
The first arguments passed to the parameter will depend on the argument resolvers
used by the HandlerRunner
, the last argument is always a cancellation
token more on this later.
<?php
$runner = new HandlerMethodRunner(
new Handlers(new MyHandler()),
new ChainArgumentResolver(
new LanguageSeverProtocolParamsResolver(),
new PassThroughArgumentResolver()
),
);
Here we use the ChainArgumentResolver
to try two different stragies.
LanguageServerProtocolParamsResolver¶
This strategy will see if your method implements an LSP *Params
class and
automatically instantaite it for you:
<?php
class MyHandler implements Handler
{
public function methods(): array
{
return [
'textDocument/completion' => 'complete',
];
}
public function doSomething(CompletionParams $completionParams, CancellationToken $canellation): Promise
{
$uriToTextDocument = $completionParams->textDocument->uri;
// ...
}
}
You should be able to do this with any method documented in the language server specification.
DTLArgumentResolver¶
This argument resolver will try and match the parameters from the request to the parameters of your method.
PassThroughArgumentResolver¶
This is a fallback resolver which will simply pass the raw array of arguments.
Co-routines¶
Your method MUST return an Amp\Promise
. If you return immediately you can
use the new Success($value)
promise, if you do any interruptable* work
which takes a significant amount of time you should use a co-routing. For
example:
<?php
class MyHandler implements Handler
{
//...
public function doSomething(CompletionParams $params, CancellationToken $canellation): Promise
{
return \Amp\call(function () {
// ...
$completionItems = [];
foreach($this->magicCompletionProvider->provideCompletions($params) as $completion) {
$completionItems[] = $completion;
yield Amp\delay(1);
}
return $completionItems;
});
}
}
The above will process a single completion item but then yield control back to the server for 1 millisecond before continuing. This allows the server to do other things (like for example cancel this request).
Cancellation¶
The CancellationToken
passed to the method handler can throw an exception
if the request is cancelled as follows:
<?php
class MyHandler implements Handler
{
//...
public function doSomething(CompletionParams $params, CancellationToken $canellation): Promise
{
return \Amp\call(function () {
// ...
$completionItems = [];
foreach($this->magicCompletionProvider->provideCompletions($params) as $completion) {
$completionItems[] = $completion;
yield Amp\delay(1);
try {
$cancellation->throwIfRequested();
} catch (Amp\CancelledException $cancelled) {
break;
}
}
return $completionItems;
});
}
}
In the above example, when the server cancels this request, the exception will be thrown and we will return early.