File: rpc_test.ml

package info (click to toggle)
ocamlformat 0.28.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 14,436 kB
  • sloc: ml: 63,321; pascal: 4,769; lisp: 229; sh: 217; makefile: 121
file content (194 lines) | stat: -rw-r--r-- 5,488 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
module Result = struct
  module Infix = struct
    let ( >>= ) r f = match r with Ok x -> f x | Error _ as e -> e

    let ( >>| ) r f = match r with Ok x -> Ok (f x) | Error _ as e -> e
  end

  let map_error ~f = function Ok x -> Ok x | Error x -> Error (f x)
end

module IO = struct
  type 'a t = 'a

  type ic = in_channel

  type oc = out_channel

  let ( >>= ) x f = f x

  let return x = x

  let read ic =
    match Csexp.input ic with
    | Ok x -> return (Some x)
    | Error _ -> return None

  let write oc lx =
    List.iter (Csexp.to_channel oc) lx ;
    Stdlib.flush oc ;
    return ()
end

open Result.Infix
open Ocamlformat_rpc_lib
module Ocf = Make (IO)

let log = Format.printf

type close = unit -> unit

type state = Uninitialized | Running of Ocf.client * close | Errored

let state : state ref = ref Uninitialized

let start ?versions () =
  let prog = Sys.argv.(1) in
  let argv = [|"ocamlformat-rpc"|] in
  ( match
      let input, output = Unix.open_process_args prog argv in
      let pid = Unix.process_pid (input, output) in
      let versions =
        match versions with
        | Some v -> List.map Version.to_string v
        | None -> List.map Version.to_string [V2; V1]
      in
      Ocf.pick_client ~pid input output versions
      >>| fun client ->
      let close =
        match client with
        | `V1 _ ->
            log "[ocf] client V1 selected\n%!" ;
            fun () -> close_out output ; close_in input
        | `V2 _ ->
            log "[ocf] client V2 selected\n%!" ;
            fun () -> close_out output ; close_in input
      in
      state := Running (client, close) ;
      client
    with
    | exception _ ->
        Error
          (`Msg
             "OCamlFormat-RPC did not respond. Check that a compatible \
              version of the OCamlFormat RPC server (ocamlformat-rpc >= \
              0.18.0) is installed." )
    | x -> x )
  |> Result.map_error ~f:(fun (`Msg msg) ->
      state := Errored ;
      log
        "An error occured while initializing and configuring ocamlformat:\n\
         %s\n\
         %!"
        msg ;
      `No_process )

let get_client ?versions () =
  match !state with
  | Uninitialized -> start ?versions ()
  | Running (cl, _) ->
      let i, _ = Unix.waitpid [WNOHANG] (Ocf.pid cl) in
      if i = 0 then Ok cl else start ?versions ()
  | Errored -> Error `No_process

let close_client () =
  match !state with
  | Uninitialized -> ()
  | Running (cl, close) ->
      let i, _ = Unix.waitpid [WNOHANG] (Ocf.pid cl) in
      if i = 0 then close () else ()
  | Errored -> ()

let config c =
  get_client () >>= fun cl -> log "[ocf] Config\n%!" ; Ocf.config c cl

let format ?(format_args = empty_args) ?versions x =
  get_client ?versions ()
  >>= fun cl ->
  log "[ocf] Format '%s'\n%!" x ;
  Ocf.format ~format_args x cl

let halt () =
  get_client ()
  >>= fun cl ->
  log "[ocf] Halt\n%!" ;
  Ocf.halt cl
  >>| fun () ->
  close_client () ;
  state := Uninitialized

let protect_unit x =
  match x with
  | Ok () -> ()
  | Error (`Msg e) -> log "Error: %s\n%!" e
  | Error `No_process -> log "No process\n%!"

let protect_string x =
  match x with
  | Ok s -> log "@[<hv>Output:@;%s@]\n%!" s
  | Error (`Msg e) -> log "Error: %s\n%!" e
  | Error `No_process -> log "No process\n%!"

let () =
  log "Starting then doing nothing\n%!" ;
  protect_unit @@ halt ()

let () =
  log "Testing v1\n%!" ;
  protect_string @@ format ~versions:[V1] "char -> string" ;
  protect_string @@ format "int -> int" ;
  protect_string @@ format " int    (* foo *) \n\n ->     int  (* bar *)" ;
  protect_unit @@ config [("foo", "bar")] ;
  protect_unit @@ config [("margin", "10")] ;
  protect_string @@ format "aaa -> bbb -> ccc -> ddd -> eee -> fff -> ggg" ;
  protect_unit @@ config [("margin", "80")] ;
  protect_string @@ format "aaa -> bbb -> ccc -> ddd -> eee -> fff -> ggg" ;
  protect_string @@ format "val x :\n \nint" ;
  protect_string @@ format "val write : 'a    t/1 -> 'a ->unit M/2.t" ;
  protect_string @@ format "x + y * z" ;
  protect_string @@ format "let x = 4 in x" ;
  protect_string @@ format "sig end" ;
  protect_string
  @@ format
       "sig\n\n\
       \ val x : foo -> bar\n\
       \  (** this does something *)\n\n\
       \ val f : a -> b -> c ->\n\n\
       \ d     end" ;
  let some_function =
    {|
let ssmap
    :  (module MapT
          with type key = string
           and type data = string
           and type map = SSMap.map )
    -> unit
  =
  ()
|}
  in
  protect_string @@ format some_function ;
  protect_unit @@ config [("profile", "janestreet")] ;
  protect_string @@ format some_function ;
  protect_unit @@ halt ()

let () =
  log "Testing v2\n%!" ;
  (* testing format args *)
  protect_string
  @@ format ~versions:[V2]
       ~format_args:{empty_args with path= Some "small_margin/foo.ml"}
       "aaa -> bbb -> ccc -> ddd -> eee -> fff -> ggg" ;
  protect_string @@ format "aaa -> bbb -> ccc -> ddd -> eee -> fff -> ggg" ;
  protect_string
  @@ format
       ~format_args:{empty_args with config= Some [("margin", "10")]}
       "aaa -> bbb -> ccc -> ddd -> eee -> fff -> ggg" ;
  protect_string @@ format "aaa -> bbb -> ccc -> ddd -> eee -> fff -> ggg" ;
  protect_string
  @@ format
       ~format_args:
         {config= Some [("margin", "80")]; path= Some "small_margin/foo.ml"}
       "aaa -> bbb -> ccc -> ddd -> eee -> fff -> ggg" ;
  protect_string @@ format "aaa -> bbb -> ccc -> ddd -> eee -> fff -> ggg" ;
  protect_unit @@ halt ()