diff --git a/sphinx/index.rst b/sphinx/index.rst index 972ac3045..c367b6ccd 100644 --- a/sphinx/index.rst +++ b/sphinx/index.rst @@ -21,6 +21,7 @@ Welcome to SuperBOL Studio OSS commands API doc license + remote-lsp Sources and Issues on Github diff --git a/sphinx/remote-lsp.rst b/sphinx/remote-lsp.rst new file mode 100644 index 000000000..41559db70 --- /dev/null +++ b/sphinx/remote-lsp.rst @@ -0,0 +1,25 @@ +.. remote-lsp + +You can simulate a remote LSP with the following scripts: + +Start a server on any port (here I chose 8000): +`$ nc -k -l localhost 8000 > test.nc` + +Then, use the following script to read on a file: +``` +touch $1 +inotifywait -m -e modify $1 | while read line +do + if [ ! -s $1 ]; then + echo 'Waiting for content' + else + cat $1 | superbol lsp > superbol.log + > $1 + fi +done +``` + +and call it with `test.nc`. + +TODO: this script only receives information, but does not send it back to +VSCODE; it only writes it in superbol.log. It should answer to the client. diff --git a/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient.ml b/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient.ml index 8b1a96104..9bdb91e22 100644 --- a/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient.ml +++ b/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient.ml @@ -190,6 +190,38 @@ module StaticFeature = struct [@@js.builder]] end +module StreamInfo = struct + include Interface.Make () + + type njs_stream + + let njs_stream_of_string str : njs_stream = + Format.ksprintf + Js_of_ocaml.Js.Unsafe.eval_string + "new joo_global_object.webSocket (`%s`);" + str + + let njs_stream_of_js = Obj.magic + + let njs_stream_to_js = Obj.magic + + include + [%js: + val writer : t -> njs_stream [@@js.get] + + val reader : t -> njs_stream [@@js.get] + + val detached : t -> bool option [@@js.get] + + val create : + writer:njs_stream + -> reader:njs_stream + -> ?detached:bool + -> unit + -> t + [@@js.builder]] +end + module DidChangeConfiguration = struct include Interface.Make () @@ -211,6 +243,13 @@ module LanguageClient = struct -> t [@@js.new "vscode_languageclient.LanguageClient"] + val make_stream : + id:string + -> name:string + -> (unit -> StreamInfo.t Promise.t) + -> t + [@@js.new "vscode_languageclient.LanguageClient"] + val start : t -> unit Promise.t [@@js.call] val isRunning : t -> bool [@@js.call] diff --git a/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient.mli b/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient.mli index 504e5ba88..1e6943673 100644 --- a/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient.mli +++ b/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient.mli @@ -167,6 +167,28 @@ module DidChangeConfiguration : sig val create : settings:Ojs.t -> unit -> t end +module StreamInfo : sig + include Js.T + + type njs_stream + + val njs_stream_of_string : string -> njs_stream + + val writer : t -> njs_stream [@@js.get] + + val reader : t -> njs_stream [@@js.get] + + val detached : t -> bool option [@@js.get] + + val create : + writer:njs_stream + -> reader:njs_stream + -> ?detached:bool + -> unit + -> t + [@@js.builder] +end + module LanguageClient : sig include Js.T @@ -179,6 +201,12 @@ module LanguageClient : sig -> unit -> t + val make_stream : + id:string + -> name:string + -> (unit -> StreamInfo.t Promise.t) + -> t + val start : t -> unit Promise.t val isRunning : t -> bool diff --git a/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient_stub.js b/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient_stub.js index 875f885b0..c8af13b07 100644 --- a/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient_stub.js +++ b/src/vendor/vscode-ocaml-platform/src-bindings/vscode_languageclient/vscode_languageclient_stub.js @@ -1 +1,2 @@ joo_global_object.vscode_languageclient = require("vscode-languageclient"); +joo_global_object.webSocket = require("ws"); diff --git a/src/vscode/superbol-vscode-platform/superbol_instance.ml b/src/vscode/superbol-vscode-platform/superbol_instance.ml index 7eddfe993..661500d00 100644 --- a/src/vscode/superbol-vscode-platform/superbol_instance.ml +++ b/src/vscode/superbol-vscode-platform/superbol_instance.ml @@ -20,6 +20,11 @@ type t = { } type client = LanguageClient.t + +let id = "superbol-free-lsp" + +let name = "SuperBOL Language Server" + let make ~context = { context; language_client = None } let client { language_client; _ } = language_client @@ -38,12 +43,33 @@ let stop_language_server t = let start_language_server ({ context; _ } as t) = let open Promise.Syntax in let* () = stop_language_server t in + let serverOptions = + Superbol_languageclient.server_options ~context + in let client = - LanguageClient.make () - ~id: "superbol-free-lsp" - ~name: "SuperBOL Language Server" - ~serverOptions:(Superbol_languageclient.server_options ~context) - ~clientOptions:(Superbol_languageclient.client_options ()) + let cmd = Executable.command serverOptions in + if String.starts_with ~prefix:"ws://" cmd then + LanguageClient.make_stream + ~id + ~name + (fun () -> + let njs_stream = + Vscode_languageclient.StreamInfo.njs_stream_of_string cmd + in + Promise.return ( + Vscode_languageclient.StreamInfo.create + ~writer:njs_stream + ~reader:njs_stream + () + ) + ) + else + let clientOptions = Superbol_languageclient.client_options () in + LanguageClient.make () + ~id + ~name + ~serverOptions + ~clientOptions in let+ () = LanguageClient.start client in t.language_client <- Some client