Getting Started¶
Below is an example which will run a language server which will respond to any request with a response “Hello world!”:
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 | #!/usr/bin/env php <?php use Amp\Success; use Phpactor\LanguageServer\Core\Middleware\RequestHandler; use Phpactor\LanguageServer\Core\Rpc\Message; use Phpactor\LanguageServer\Core\Rpc\RequestMessage; use Phpactor\LanguageServer\Core\Rpc\ResponseMessage; use Phpactor\LanguageServer\Middleware\ClosureMiddleware; use Phpactor\LanguageServer\Core\Dispatcher\Dispatcher\MiddlewareDispatcher; use Phpactor\LanguageServerProtocol\InitializeParams; use Phpactor\LanguageServer\Core\Server\Transmitter\MessageTransmitter; use Phpactor\LanguageServer\Core\Dispatcher\Factory\ClosureDispatcherFactory; use Phpactor\LanguageServer\LanguageServerBuilder; require __DIR__ . '/../../vendor/autoload.php'; $builder = LanguageServerBuilder::create(new ClosureDispatcherFactory( function (MessageTransmitter $transmitter, InitializeParams $params) { return new MiddlewareDispatcher( new ClosureMiddleware(function (Message $message, RequestHandler $handler) { if (!$message instanceof RequestMessage) { return $handler->handle($message); } return new Success(new ResponseMessage($message->id, 'Hello World!')); }) ); } )); $builder ->build() ->run(); |
LanguageServerBuilderabstracts the creation of streams and builds the Language Server. It accepts an instance ofDispatcherFactory-ClosureDispatcherFactoryis aDispatcherFactory. This class has the responsibility initializing the session. It is invoked when the Language Server client sendsinitializemethod, providing its capabilities.MessageTransmitteris how your session can communicate with the client - you wouldn’t normally use this directly, but more on this later. TheInitializeParamsis a class containing the initialization information from the client, including theClientCapabilities.MiddlewareDispatcherIs aDispatcherwhich uses the Middleware concept - this is the pipeline for incoming requests. Requests go in, andResponseMessageclasses come out (ornullif no response is necessary).ClosureMiddlewareis aMiddlewarewhich allows you to specific a\Closureinstead of implementing a new class (which is what you’d normally do). TheMessageis the incoming message (Request,NotificationorResponse) from the client, theRequestHandleris used to delegate to the nextMiddleware.- We return a
ResponseMessagewrapped in aPromise. We only return aResponseforRequestmessages, and theResponsemust reference the request’s ID. - The
Successclass is aPromisewhich resolves immediately. Returning aPromiseallows us to run non-blocking co-routines. - Then finally build and run the server. It will listen on STDIO by default.
If you run this example, you should be able to connect to the language server and it should respond (incorrectly) to all requests with “Hello World!”.
Let’s try it out.
$ echo '{"id":1,"method":"foobar","params":[]}' | ./bin/proxy request | php example/server/minimal.php
The proxy binary file is used only for this demonstration, it adds the
necessary formatting to the message before passing it to our new language
server (running on STDIO by default).
It should show something like:
At this point you could connect an IDE to your new Language Server, but it wouldn’t do very much.
In the next chapter we’ll try and introduce some more concepts and add some language server functionality.