Service Providers

Service providers are background services which can should be started on on the initialized notification from the client.

A good example of a service is a code indexing service which watches the file system and indexes code when files change.

Example

A full example of a service provider:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php

namespace Phpactor\LanguageServer\Example\Service;

use Amp\CancellationToken;
use Amp\CancelledException;
use Amp\Delayed;
use Amp\Promise;
use Phpactor\LanguageServer\Core\Server\ClientApi;
use Phpactor\LanguageServer\Core\Service\ServiceProvider;

/**
 * Example service which shows a "ping" message every second.
 */
class PingProvider implements ServiceProvider
{
    /**
     * @var ClientApi
     */
    private $client;

    public function __construct(ClientApi $client)
    {
        $this->client = $client;
    }

    /**
     * {@inheritDoc}
     */
    public function services(): array
    {
        return [
            'ping'
        ];
    }

    /**
     * @return Promise<null>
     */
    public function ping(CancellationToken $cancel): Promise
    {
        return \Amp\call(function () use ($cancel) {
            while (true) {
                try {
                    $cancel->throwIfRequested();
                } catch (CancelledException $cancelled) {
                    break;
                }
                yield new Delayed(1000);
                $this->client->window()->showMessage()->info('ping');
            }
        });
    }
}

This is similar to method handlers with the exception that:

  • The services method provides only an array of method names. The name doubles as both the method and service name.
  • The method is called when the Language Server is initialized (or when it is started via. the service manager).
  • Services are passed only a CancellationToken.

Usage

<?php

$serviceProviders = new ServiceProviders(
    new PingProvider($clientApi)
);

$serviceManager = new ServiceManager($serviceProviders, $logger);
$eventDispatcher = new EventDispatcher(
    new ServiceListener($serviceManager)
);

$handlers = new Handlers(
    // ...
    new ServiceHandler($serviceManager, $clientApi),
    // ...
);

return new MiddlewareDispatcher(
    // ...
    new InitializeMiddleware($handlers, $eventDispatcher)
    // ...
);

In the above code the ServiceManager is responsible for starting and stopping services, the ServiceHandler handles RPC methods to start/stop services, and we use the ServiceListener to start the services when the server is initialized (based on the Initialized event issued by the InitializeMiddleware.