feat: prepare for Ipc server testing

This commit is contained in:
Wojciech Nawrocki 2020-12-22 22:00:25 -05:00 committed by Sebastian Ullrich
parent ed81967338
commit 7dabff382f
5 changed files with 114 additions and 1 deletions

View file

@ -14,3 +14,4 @@ import Lean.Data.Lsp.InitShutdown
import Lean.Data.Lsp.TextSync
import Lean.Data.Lsp.Utf16
import Lean.Data.Lsp.Workspace
import Lean.Data.Lsp.Ipc

View file

@ -31,6 +31,12 @@ structure ServerCapabilities where
textDocumentSync? : Option TextDocumentSyncOptions := none
hoverProvider : Bool := false
instance : FromJson ServerCapabilities :=
⟨fun j => do
let textDocumentSync? := j.getObjValAs? TextDocumentSyncOptions "textDocumentSync"
let hoverProvider ← j.getObjValAs? Bool "hoverProvider"
pure ⟨textDocumentSync?, hoverProvider⟩⟩
instance : ToJson ServerCapabilities := ⟨fun o => mkObj $
opt "textDocumentSync" o.textDocumentSync? ++
[⟨"hoverProvider", o.hoverProvider⟩]⟩

View file

@ -89,12 +89,21 @@ inductive InitializedParams where
| mk
instance : FromJson InitializedParams :=
⟨fun j => InitializedParams.mk⟩
⟨fun _ => InitializedParams.mk⟩
instance : ToJson InitializedParams :=
⟨fun _ => Json.null⟩
structure ServerInfo where
name : String
version? : Option String := none
instance : FromJson ServerInfo :=
⟨fun j => do
let name ← j.getObjValAs? String "name"
let version? := j.getObjValAs? String "version"
pure ⟨name, version?⟩⟩
instance : ToJson ServerInfo := ⟨fun o => mkObj $
⟨"name", o.name⟩ ::
opt "version" o.version?⟩
@ -103,6 +112,12 @@ structure InitializeResult where
capabilities : ServerCapabilities
serverInfo? : Option ServerInfo := none
instance : FromJson InitializeResult :=
⟨fun j => do
let capabilities ← j.getObjValAs? ServerCapabilities "capabilities"
let serverInfo? := j.getObjValAs? ServerInfo "serverInfo"
pure ⟨capabilities, serverInfo?⟩⟩
instance : ToJson InitializeResult := ⟨fun o =>
mkObj $
⟨"capabilities", toJson o.capabilities⟩ ::

View file

@ -0,0 +1,77 @@
/-
Copyright (c) 2020 Marc Huisinga. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Marc Huisinga, Wojciech Nawrocki
-/
import Init.System.IO
import Lean.Data.Json
import Lean.Data.Lsp.Communication
import Lean.Data.Lsp.Diagnostics
import Lean.Data.Lsp.Extra
/-! Provides an IpcM monad for interacting with an external LSP process.
Used for testing the Lean server. -/
namespace Lean.Lsp.Ipc
open IO
open JsonRpc
def ipcStdioConfig : Process.StdioConfig where
stdin := Process.Stdio.piped
stdout := Process.Stdio.piped
stderr := Process.Stdio.piped
abbrev IpcM := ReaderT (Process.Child ipcStdioConfig) IO
variable [ToJson α]
def stdin : IpcM FS.Stream := do
FS.Stream.ofHandle (←read).stdin
def stdout : IpcM FS.Stream := do
FS.Stream.ofHandle (←read).stdout
def stderr : IpcM FS.Stream := do
FS.Stream.ofHandle (←read).stderr
def writeRequest (r : Request α) : IpcM Unit := do
(←stdin).writeLspRequest r
def writeNotification (n : Notification α) : IpcM Unit := do
(←stdin).writeLspNotification n
def readMessage : IpcM JsonRpc.Message := do
(←stdout).readLspMessage
def readResponseAs (expectedID : RequestID) (α) [FromJson α] : IpcM (Response α) := do
(←stdout).readLspResponseAs expectedID α
/-- Waits for the worker to emit all diagnostics for the current document version
and returns them as a list. -/
partial def collectDiagnostics (waitForDiagnosticsId : RequestID := 0) (target : DocumentUri)
: IpcM (List (Notification PublishDiagnosticsParams)) := do
writeRequest ⟨waitForDiagnosticsId, "textDocument/waitForDiagnostics", WaitForDiagnosticsParam.mk target⟩
let rec loop : IpcM (List (Notification PublishDiagnosticsParams)) := do
match ←readMessage with
| Message.response id _ =>
if id = waitForDiagnosticsId then
[]
else
loop
| Message.notification "textDocument/publishDiagnostics" (some param) =>
match fromJson? (toJson param) with
| some diagnosticParam => ⟨"textDocument/publishDiagnostics", diagnosticParam⟩ :: (←loop)
| none => throw $ userError "Cannot decode publishDiagnostics parameters"
| _ => loop
loop
def runWith (cmd : String) (args : Array String := #[]) (test : IpcM α) : IO α := do
let proc ← Process.spawn {
toStdioConfig := ipcStdioConfig
cmd := cmd
args := args }
ReaderT.run test proc
end Lean.Lsp.Ipc

View file

@ -85,6 +85,11 @@ instance DidChangeTextDocumentParams.hasToJson : ToJson DidChangeTextDocumentPar
structure SaveOptions where
includeText : Bool
instance : FromJson SaveOptions :=
⟨fun j => do
let includeText ← j.getObjValAs? Bool "includeText"
pure ⟨includeText⟩⟩
instance : ToJson SaveOptions := ⟨fun o =>
mkObj $ [⟨"includeText", o.includeText⟩]⟩
@ -107,6 +112,15 @@ structure TextDocumentSyncOptions where
willSaveWaitUntil : Bool
save? : Option SaveOptions := none
instance : FromJson TextDocumentSyncOptions :=
⟨fun j => do
let openClose ← j.getObjValAs? Bool "openClose"
let change ← j.getObjValAs? TextDocumentSyncKind "change"
let willSave ← j.getObjValAs? Bool "willSave"
let willSaveUntil ← j.getObjValAs? Bool "willSaveWaitUntil"
let save? := j.getObjValAs? SaveOptions "save"
pure ⟨openClose, change, willSave, willSaveUntil, save?⟩⟩
instance : ToJson TextDocumentSyncOptions := ⟨fun o =>
mkObj $
opt "save" o.save? ++ [