You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
lsp4clj reads and writes from io streams, parsing JSON-RPC according to the LSP spec. It provides tools to allow server implementors to receive, process, and respond to any of the methods defined in the LSP spec, and to send their own requests and notifications to clients.
8
-
9
-
## Usage
10
-
11
-
### Create a server
12
-
13
-
To initialize a server that will read from stdin and write to stdout:
14
-
15
-
```clojure
16
-
(lsp4clj.io-server/stdio-server)
17
-
```
18
-
19
-
The returned server will have a core.async `:log-ch`, from which you can read server logs (vectors beginning with a log level).
To receive messages from a client, lsp4clj defines a pair of multimethods, `lsp4clj.server/receive-notification` and `lsp4clj.server/receive-request` that dispatch on the method name (as defined by the LSP spec) of an incoming JSON-RPC message.
31
-
32
-
Server implementors should create `defmethod`s for the messages they want to process. (Other methods will be logged and responded to with a generic "Method not found" response.)
33
-
34
-
These `defmethod`s receive 3 arguments, the method name, a "context", and the `params` of the [JSON-RPC request or notification object](https://www.jsonrpc.org/specification#request_object). The keys of the params will have been converted (recursively) to kebab-case keywords. Read on for an explanation of what a "context" is and how to set it.
However, it'spossibletocalculaterequestsinparallel (though not notifications).Ifthelanguageserverwantsarequesttobecalculatedinparallelwithothers, itshouldreturna `java.util.concurrent.CompletableFuture`, possiblycreatedwith `promesa.core/future`, from `lsp4clj.server/receive-request`.lsp4cljwillarrangefortheresultofthisfuturetobereturnedtotheclientwhenitresolves.Inthemeantime, lsp4cljwillcontinuepassingtheclient'smessagestothelanguageserver.ThelanguageservercancontrolthenumberofsimultaneousmessagesbysettingtheparallelismoftheCompletableFutures' executor.
Butclientscancancelrequeststhatareprocessedinparallel.Inthesecaseslsp4cljwillcancelthefutureandreturnamessagetotheclientacknowledgingthecancellation.BecauseofthedesignofCompletableFuture, cancellationcanmeanoneoftwothings.Iftheexecutorhasn'tstartedthethreadthatiscalculatingthevalueofthefuture (perhaps because the executor's thread pool is full), itwon'tbestarted.Butifthereisalreadyathreadcalculatingthevalue, thethreadwon'tbeinterupted.SeethedocumentationforCompletableFutureforanexplanationofwhythisisso.
`lsp4clj.io-server/server` acceptsapairofoptions `:in` and `:out`.Thesewillbecoercedtoa `java.io.InputStream` and `java.io.OutputStream` via `clojure.java.io/input-stream` and `clojure.java.io/output-stream`, respectively.Theexampleaboveworksbecausea `java.net.Socket` canbecoercedtobothaninputandoutputstreamviathismechanism.
160
-
161
-
Asimilarapproachcanbeusedtoconnectoverpipes.
162
-
163
-
## Developmentdetails
164
-
165
-
### Tracing
166
-
167
-
Asyouareimplementing, youmaywanttotraceincomingandoutgoingmessages.Initializetheserverwith `:trace-level"verbose"` andthenreadtraces (two element vectors, beginning with the log level `:debug` and ending with a string, the trace itself) offits `:trace-ch`.
`:trace-level` canbesetto `"off"` (no tracing), `"messages"` (to show just the message time, method, id and direction), or `"verbose"` (to also show details of the message body).
179
-
180
-
Thetracelevelcanbechangedduringthelifeofaserverbycalling, forexample, `(ls4clj.server/set-trace-level server "messages")`.Thiscanbeusedtorespectatracelevelreceivedatruntime, eitherinan [initialize](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initializeParams) requestora [$/setTrace](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#setTrace) notification.
181
-
182
-
### Testing
183
-
184
-
Aclientisinmanywayslikeaserver—italsosendsandreceivesrequestsandnotificationsandreceivesresponses.Thatis, LSPusesJSON-RPCasabi-directionalprotocol.Assuch, youmaybeabletousesomeoflsp4clj'stoolstobuildamockclientfortesting.See `integration.client` in `clojure-lsp` foronesuchexample.
Fromexperience, it'sdismayinglyeasytoleaveinanerrant `prn` or `time` andendupwithanon-responsiveclient.Forthisreason, wehighlyrecommendsupportingcommunicationoversockets (see [other types of servers](#other-types-of-servers)) whichareimmunetothisproblem.However, sincethechoiceofwhethertousesocketsorstdioisultimatelyuptotheclient, youmayhavenochoicebuttosupportboth.
193
-
194
-
lsp4cljprovidesonetooltoavoidaccidentalwritestostdout (or rather to `*out*`, which is usually the same as `System.out`).Toprotectablockofcodefromwritingto `*out*`, wrapitwith `lsp4clj.server/discarding-stdout`.The `receive-notification` and `receive-request` multimethodsarealreadyprotectedthisway, buttasksstartedoutsideofthesemultimethodsorthatruninseparatethreadsneedthisprotectionadded.
7
+
Currently lsp4clj is just a wrapper for [jsonrpc4clj](https://github.com/clojure-lsp/jsonrpc4clj) adding some LSP schemas, for more details how to use it check that lib.
0 commit comments