Skip to content

feat: Add LSP skeleton architecture #906

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/stdlib/lsp/json-rpc.mc
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
include "common.mc"
include "json.mc"
include "./utils.mc"

type RPCRequest = {
method: String,
params: Map String JsonValue,
id: Option Int
}

type RPCError = {
code: Int,
message: String,
data: JsonValue
}

type RPCResult
con RPCSuccess : JsonValue -> RPCResult
con RPCFailure : RPCError -> RPCResult

type RPCResponse = {
result: RPCResult,
id: Int
}

let getContentLength: String -> Int = lam header.
match header with "Content-Length: " ++ len ++ "\n" then
string2int len
else
error "The JSON-RPC header could not be read, this shouldn't happen!"

let getRPCRequest: JsonValue -> Option RPCRequest = lam request.
match request with JsonObject request in
let lookup = (flip mapLookup) request in
let id = match lookup "id" with Some JsonInt id then Some id else None () in
match (lookup "method", lookup "params") with (Some JsonString method, Some JsonObject params) then
Some { method = method, params = params, id = id }
else
None ()
8 changes: 8 additions & 0 deletions src/stdlib/lsp/methods.mc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include "./methods/unknown.mc"
include "./methods/initialize.mc"

-- To be extended with more methods
lang LSP =
LSPInitialize
+ LSPUnknownMethod
end
37 changes: 37 additions & 0 deletions src/stdlib/lsp/methods/initialize.mc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
include "../utils.mc"
include "./root.mc"

lang LSPInitialize = LSPRoot
syn Message =
| Initialized {}
| Initialize {
processId: Option Int,
locale: Option String,
rootPath: Option String,
rootUri: Option String,
initializationOptions: Option JsonValue,
trace: Option String -- 'off' | 'messages' | 'verbose'
}

sem getMessage request =
| "initialized" ->
Initialized {}
| "initialize" ->
let getParam = (flip mapLookup) request.params in

let processId = match getParam "processId" with JsonInt processId then Some processId else None () in
let locale = match getParam "locale" with JsonString locale then Some locale else None () in
let rootPath = match getParam "rootPath" with JsonString rootPath then Some rootPath else None () in
let rootUri = match getParam "rootUri" with JsonString rootUri then Some rootUri else None () in
let initializationOptions = getParam "initializationOptions" in
let trace = match getParam "trace" with JsonString trace then Some trace else None () in

Initialize {
processId = processId,
locale = locale,
rootPath = optionMap stripUriProtocol rootPath,
rootUri = optionMap stripUriProtocol rootUri,
initializationOptions = initializationOptions,
trace = trace
}
end
7 changes: 7 additions & 0 deletions src/stdlib/lsp/methods/root.mc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
include "../json-rpc.mc"

lang LSPRoot
syn Message =

sem getMessage: RPCRequest -> String -> Message
end
14 changes: 14 additions & 0 deletions src/stdlib/lsp/methods/unknown.mc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
include "./root.mc"

lang LSPUnknownMethod = LSPRoot
syn Message =
| UnknownMethod {
method: String
}

sem getMessage request =
| method ->
UnknownMethod {
method = method
}
end
20 changes: 20 additions & 0 deletions src/stdlib/lsp/utils.mc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
include "ext/file-ext.mc"

-- returns Option content if the requested number of bytes could be read
-- otherwise, None is returned
let readBytesBuffered : ReadChannel -> Int -> Option [Int] =
lam rc. lam len.
recursive let work = lam remainLen. lam acc.
if leqi remainLen 0 then Some acc
else switch fileReadBytes rc remainLen
case Some s then
let acc = concat acc s in
let readLen = length s in
work (subi remainLen readLen) acc
case None () then None ()
end
in work len []

let stripUriProtocol = lam uri. match uri
with "file://" ++ rest then rest
else uri
Loading