Skip to content

Commit c88be05

Browse files
committed
Report progress for dune builds
When a dune build is running, the server will display this as a running task. Signed-off-by: Rudi Grinberg <[email protected]>
1 parent 27b5c9e commit c88be05

File tree

6 files changed

+164
-13
lines changed

6 files changed

+164
-13
lines changed

ocaml-lsp-server/src/dune.ml

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,13 @@ type run =
111111
| Out_of_date
112112

113113
type state =
114-
| Waiting_for_init of { diagnostics : Diagnostics.t }
114+
| Waiting_for_init of
115+
{ diagnostics : Diagnostics.t
116+
; progress : Progress.t
117+
}
115118
| Active of
116119
{ diagnostics : Diagnostics.t
120+
; progress : Progress.t
117121
; finish : unit Fiber.Ivar.t
118122
; chan : Chan.t
119123
}
@@ -127,13 +131,14 @@ let stop (t : t) =
127131
| Waiting_for_init _ ->
128132
t := Closed;
129133
Fiber.return ()
130-
| Active { finish; chan; diagnostics = _ } ->
134+
| Active { finish; chan; progress = _; diagnostics = _ } ->
131135
t := Closed;
132136
let pid = Chan.pid chan in
133137
Unix.kill (Pid.to_int pid) Sys.sigstop;
134138
Fiber.Ivar.fill finish ()
135139

136-
let create diagnostics = ref (Waiting_for_init { diagnostics })
140+
let create diagnostics progress =
141+
ref (Waiting_for_init { diagnostics; progress })
137142

138143
let lsp_of_dune uri dune =
139144
let module D = Drpc.Diagnostic in
@@ -178,13 +183,13 @@ let run_rpc (t : t) bin =
178183
match !t with
179184
| Closed -> Code_error.raise "dune already closed" []
180185
| Active _ -> Code_error.raise "dune alrady running" []
181-
| Waiting_for_init { diagnostics } ->
186+
| Waiting_for_init { diagnostics; progress } ->
182187
Diagnostics.update_dune_status diagnostics Disconnected;
183188
let open Fiber.O in
184189
let finish = Fiber.Ivar.create () in
185190
let* chan = Chan.create bin in
186-
t := Active { diagnostics; finish; chan };
187-
let+ () =
191+
t := Active { diagnostics; finish; chan; progress };
192+
let* () =
188193
Fiber.parallel_iter
189194
~f:(fun f -> f ())
190195
[ (fun () -> Diagnostics.send diagnostics)
@@ -198,6 +203,13 @@ let run_rpc (t : t) bin =
198203
Drpc.Initialize.create ~id:(Drpc.Id.make (Atom "ocamllsp"))
199204
in
200205
let handler =
206+
let build_event, build_progress =
207+
if Progress.should_report_build_progress progress then
208+
Progress.
209+
(Some (build_event progress), Some (build_progress progress))
210+
else
211+
(None, None)
212+
in
201213
let diagnostic evs =
202214
List.iter evs ~f:(fun (ev : Drpc.Diagnostic.Event.t) ->
203215
let id =
@@ -220,19 +232,26 @@ let run_rpc (t : t) bin =
220232
(`Dune (id, uri, lsp_of_dune uri d)));
221233
Diagnostics.send diagnostics
222234
in
223-
Client.Handler.create ~diagnostic ()
235+
Client.Handler.create ?build_event ?build_progress ~diagnostic ()
224236
in
225237
Client.connect ~handler chan init ~f:(fun client ->
226238
Diagnostics.update_dune_status diagnostics Connected;
227-
let* () = Diagnostics.send diagnostics in
228-
let sub = Drpc.Subscribe.Diagnostics in
229239
let* () =
230-
Client.notification client Drpc.Notification.subscribe sub
240+
let sub what =
241+
Client.notification client Drpc.Notification.subscribe what
242+
in
243+
if Progress.should_report_build_progress progress then
244+
Fiber.fork_and_join_unit
245+
(fun () -> sub Diagnostics)
246+
(fun () -> sub Build_progress)
247+
else
248+
sub Diagnostics
231249
in
232250
Fiber.Ivar.read finish))
233251
]
234252
in
235-
t := Waiting_for_init { diagnostics }
253+
t := Waiting_for_init { diagnostics; progress };
254+
Progress.end_build_if_running progress
236255

237256
let run t : (unit, run) result Fiber.t =
238257
match !t with

ocaml-lsp-server/src/dune.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ type t
88

99
val run : t -> (unit, run) result Fiber.t
1010

11-
val create : Diagnostics.t -> t
11+
val create : Diagnostics.t -> Progress.t -> t
1212

1313
val stop : t -> unit Fiber.t

ocaml-lsp-server/src/import.ml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module Loc = Location
1919
module Scheduler = Fiber_unix.Scheduler
2020
module Server = Lsp_fiber.Server
2121
module Client_request = Lsp.Client_request
22+
module Server_request = Lsp.Server_request
2223
module Client_notification = Lsp.Client_notification
2324
module Text_document = Lsp.Text_document
2425
open Lsp.Types
@@ -38,6 +39,13 @@ module DiagnosticRelatedInformation = DiagnosticRelatedInformation
3839
module PublishDiagnosticsParams = PublishDiagnosticsParams
3940
module MessageType = MessageType
4041
module WorkspaceEdit = WorkspaceEdit
42+
module ProgressToken = ProgressToken
43+
module WorkDoneProgressCreateParams = WorkDoneProgressCreateParams
44+
module WorkDoneProgressBegin = WorkDoneProgressBegin
45+
module WorkDoneProgressReport = WorkDoneProgressReport
46+
module WorkDoneProgressEnd = WorkDoneProgressEnd
47+
module ProgressParams = ProgressParams
48+
module ExecuteCommandOptions = ExecuteCommandOptions
4149
module TextEdit = TextEdit
4250
module CodeActionKind = CodeActionKind
4351
module ShowMessageParams = ShowMessageParams

ocaml-lsp-server/src/ocaml_lsp_server.ml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,18 @@ let start () =
974974
Fiber.fork_and_join_unit
975975
(fun () -> Server.start server)
976976
(fun () ->
977-
let* (_ : InitializeParams.t) = Server.initialized server in
977+
let* (init_params : InitializeParams.t) =
978+
Server.initialized server
979+
in
980+
let progress =
981+
Progress.create init_params.capabilities
982+
~report_progress:(fun progress ->
983+
Server.notification server
984+
(Server_notification.WorkDoneProgress progress))
985+
~create_task:(fun task ->
986+
Server.request server
987+
(Server_request.WorkDoneProgressCreate task))
988+
in
978989
let dune =
979990
let dune' = Dune.create diagnostics progress in
980991
dune := Some dune';

ocaml-lsp-server/src/progress.ml

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
open Import
2+
3+
type enabled =
4+
(* TODO this needs to be mutexed *)
5+
{ mutable token : ProgressToken.t option
6+
; mutable build_counter : int
7+
; report_progress :
8+
Server_notification.Progress.t ProgressParams.t -> unit Fiber.t
9+
; create_task : WorkDoneProgressCreateParams.t -> unit Fiber.t
10+
}
11+
12+
type t =
13+
| Disabled
14+
| Enabled of enabled
15+
16+
let create (client_capabilities : ClientCapabilities.t) ~report_progress
17+
~create_task =
18+
match client_capabilities.window with
19+
| Some { workDoneProgress = Some true; _ } ->
20+
Enabled { token = None; build_counter = 0; create_task; report_progress }
21+
| _ -> Disabled
22+
23+
let end_build (t : enabled) ~message =
24+
match t.token with
25+
| None -> Fiber.return ()
26+
| Some token ->
27+
t.token <- None;
28+
t.report_progress
29+
(ProgressParams.create ~token
30+
~value:
31+
(Server_notification.Progress.End
32+
(WorkDoneProgressEnd.create ~message ())))
33+
34+
let end_build_if_running = function
35+
| Disabled -> Fiber.return ()
36+
| Enabled e -> end_build e ~message:"Build interrupted"
37+
38+
let start_build (t : enabled) =
39+
let open Fiber.O in
40+
let* () = end_build t ~message:"Starting new build" in
41+
let token = `String ("dune-build-" ^ Int.to_string t.build_counter) in
42+
t.token <- Some token;
43+
t.build_counter <- t.build_counter + 1;
44+
let* () = t.create_task (WorkDoneProgressCreateParams.create ~token) in
45+
t.token <- Some token;
46+
let+ () =
47+
t.report_progress
48+
(ProgressParams.create ~token
49+
~value:
50+
(Server_notification.Progress.Begin
51+
(WorkDoneProgressBegin.create ~title:"Build" ~message:"started" ())))
52+
in
53+
token
54+
55+
let build_event t (event : Drpc.Build.Event.t) =
56+
match t with
57+
| Disabled -> Code_error.raise "progress reporting is not supported" []
58+
| Enabled t -> (
59+
match event with
60+
| Finish -> end_build t ~message:"Build finished"
61+
| Fail -> end_build t ~message:"Build failed"
62+
| Interrupt -> end_build t ~message:"Build interrupted"
63+
| Start ->
64+
let open Fiber.O in
65+
let+ (_ : ProgressToken.t) = start_build t in
66+
())
67+
68+
let build_progress t (progress : Drpc.Progress.t) =
69+
match t with
70+
| Disabled -> Code_error.raise "progress reporting is not supported" []
71+
| Enabled ({ token; report_progress; _ } as t) ->
72+
let open Fiber.O in
73+
let* token =
74+
match token with
75+
| Some token -> Fiber.return token
76+
| None ->
77+
(* This can happen when we connect to dune in the middle of a build. *)
78+
start_build t
79+
in
80+
let percentage =
81+
let fraction =
82+
float_of_int progress.complete
83+
/. float_of_int (progress.complete + progress.remaining)
84+
in
85+
int_of_float (fraction *. 100.)
86+
in
87+
report_progress
88+
(ProgressParams.create ~token
89+
~value:
90+
(Server_notification.Progress.Report
91+
(WorkDoneProgressReport.create ~percentage ~message:"Building" ())))
92+
93+
let should_report_build_progress = function
94+
| Disabled -> false
95+
| Enabled _ -> true

ocaml-lsp-server/src/progress.mli

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
open Import
2+
3+
type t
4+
5+
val create :
6+
ClientCapabilities.t
7+
-> report_progress:
8+
(Server_notification.Progress.t ProgressParams.t -> unit Fiber.t)
9+
-> create_task:(WorkDoneProgressCreateParams.t -> unit Fiber.t)
10+
-> t
11+
12+
val end_build_if_running : t -> unit Fiber.t
13+
14+
val build_event : t -> Drpc.Build.Event.t -> unit Fiber.t
15+
16+
val build_progress : t -> Drpc.Progress.t -> unit Fiber.t
17+
18+
val should_report_build_progress : t -> bool

0 commit comments

Comments
 (0)