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(); |
LanguageServerBuilder
abstracts the creation of streams and builds the Language Server. It accepts an instance ofDispatcherFactory
-ClosureDispatcherFactory
is aDispatcherFactory
. This class has the responsibility initializing the session. It is invoked when the Language Server client sendsinitialize
method, providing its capabilities.MessageTransmitter
is how your session can communicate with the client - you wouldn’t normally use this directly, but more on this later. TheInitializeParams
is a class containing the initialization information from the client, including theClientCapabilities
.MiddlewareDispatcher
Is aDispatcher
which uses the Middleware concept - this is the pipeline for incoming requests. Requests go in, andResponseMessage
classes come out (ornull
if no response is necessary).ClosureMiddleware
is aMiddleware
which allows you to specific a\Closure
instead of implementing a new class (which is what you’d normally do). TheMessage
is the incoming message (Request
,Notification
orResponse
) from the client, theRequestHandler
is used to delegate to the nextMiddleware
.- We return a
ResponseMessage
wrapped in aPromise
. We only return aResponse
forRequest
messages, and theResponse
must reference the request’s ID. - The
Success
class is aPromise
which resolves immediately. Returning aPromise
allows 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.