Source file vcaml_cinaps.ml
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
open Core
type scope =
| Global
| Buffer
| Window
| Window_per_buffer
| Tabpage
let window_local_options_with_ignored_global_setting =
[ "previewwindow"; "scroll"; "winfixheight"; "winfixwidth" ] |> String.Set.of_list
;;
let buffer_local_options_with_ignored_global_setting =
[ "bufhidden"; "buftype"; "channel"; "filetype"; "modified"; "readonly"; "syntax" ]
|> String.Set.of_list
;;
let global_or_local_to_tabpage = [ "cmdheight" ] |> String.Set.of_list
let options_for_scope =
let global_or_local_to_tabpage_options, global_options =
Nvim_internal.Options.Global.options
|> List.partition_tf ~f:(fun { name; _ } -> Set.mem global_or_local_to_tabpage name)
in
let window_options, window_per_buffer_options =
Nvim_internal.Options.Window.options
|> List.partition_tf ~f:(fun { name; _ } ->
Set.mem window_local_options_with_ignored_global_setting name)
in
function
| Global -> global_options
| Buffer -> Nvim_internal.Options.Buffer.options
| Window -> window_options
| Window_per_buffer -> window_per_buffer_options
| Tabpage -> global_or_local_to_tabpage_options
;;
let generate_options_type ~scope =
let options = options_for_scope scope in
let gadt_params =
match scope with
| Global | Window | Tabpage -> "'a"
| Buffer | Window_per_buffer -> "('a, 'global)"
in
let gadt =
options
|> List.map ~f:(fun { name; global_local; type_ } ->
let type_phantom =
match type_ with
| String -> "string"
| Int -> "int"
| Bool -> "bool"
| Char_list _ -> "char list"
| String_list -> "string list"
in
let scope_phantoms =
match scope, global_local with
| Global, true ->
raise_s [%message "Globally scoped option is marked global-local" name]
| Global, false -> []
| Buffer, true -> [ "[`global]" ]
| Buffer, false ->
(match Set.mem buffer_local_options_with_ignored_global_setting name with
| true -> [ "[`none]" ]
| false -> [ "[`copied]" ])
| Window, true ->
raise_s [%message "Special window-local option was marked global-local" name]
| Window, false -> []
| Window_per_buffer, true -> [ "[`global]" ]
| Window_per_buffer, false -> [ "[`copied]" ]
| Tabpage, _ -> []
in
let phantom = String.concat (type_phantom :: scope_phantoms) ~sep:"," in
[%string "| %{String.capitalize name} : (%{phantom}) t"])
|> String.concat ~sep:"\n"
in
[%string {| type %{gadt_params} t = %{gadt} [@@deriving sexp_of] |}] |> print_endline
;;
let generate_options_to_string ~scope =
let options = options_for_scope scope in
let cases =
options
|> List.map ~f:(fun { name; _ } ->
[%string {| | %{String.capitalize name} -> "%{name}" |}])
|> String.concat ~sep:"\n"
in
(match scope with
| Global | Window | Tabpage ->
[%string {| let to_string (type a) : a t -> string = function %{cases} |}]
| Buffer | Window_per_buffer ->
[%string {| let to_string (type a g) : (a, g) t -> string = function %{cases} |}])
|> print_endline
;;
let generate_options_of_msgpack ~scope =
let options = options_for_scope scope in
let cases =
options
|> List.map ~f:(fun { name; type_; _ } ->
let phantom =
match type_ with
| String -> "String"
| Int -> "Int"
| Bool -> "Bool"
| Char_list { commalist = false } -> "Custom (module Char_list)"
| Char_list { commalist = true } -> "Custom (module Char_list.Comma_separated)"
| String_list -> "Custom (module String_list)"
in
[%string {| | %{String.capitalize name} -> Type.of_msgpack (%{phantom}) msgpack |}])
|> String.concat ~sep:"\n"
in
(match scope with
| Global | Window | Tabpage ->
[%string
{|
let[@warning "-33"] of_msgpack (type a) (t : a t) msgpack : a Or_error.t =
let open Option_helpers in
match t with %{cases} |}]
| Buffer | Window_per_buffer ->
[%string
{|
let of_msgpack (type a g) (t : (a, g) t) msgpack : a Or_error.t =
let open Option_helpers in
match t with %{cases} |}])
|> print_endline
;;
let generate_options_to_msgpack ~scope =
let options = options_for_scope scope in
let cases =
options
|> List.map ~f:(fun { name; type_; _ } ->
let phantom =
match type_ with
| String -> "String"
| Int -> "Int"
| Bool -> "Bool"
| Char_list { commalist = false } -> "Custom (module Char_list)"
| Char_list { commalist = true } -> "Custom (module Char_list.Comma_separated)"
| String_list -> "Custom (module String_list)"
in
[%string {| | %{String.capitalize name} -> Type.to_msgpack (%{phantom}) value |}])
|> String.concat ~sep:"\n"
in
(match scope with
| Global | Window | Tabpage ->
[%string
{|
let[@warning "-33"] to_msgpack (type a) (t : a t) (value : a) =
let open Option_helpers in
match t with %{cases} |}]
| Buffer | Window_per_buffer ->
[%string
{|
let to_msgpack (type a g) (t : (a, g) t) (value : a) =
let open Option_helpers in
match t with %{cases} |}])
|> print_endline
;;
let generate_buffer_options_kind () =
let options = Nvim_internal.Options.Buffer.options in
let cases =
options
|> List.map ~f:(fun { name; global_local; _ } ->
let kind =
match global_local with
| true -> "Global"
| false ->
(match Set.mem buffer_local_options_with_ignored_global_setting name with
| true -> "None"
| false -> "Copied")
in
[%string {| | %{String.capitalize name} -> %{kind} |}])
|> String.concat ~sep:"\n"
in
[%string
{|
module Global = struct
type 'a t =
| Copied : [ `copied ] t
| Global : [ `global ] t
| None : [ `none ] t
end
let kind (type a g) : (a, g) t -> g Global.t = function
%{cases} |}]
|> print_endline
;;
let generate_options_impl ~scope =
generate_options_type ~scope;
generate_options_to_string ~scope;
generate_options_of_msgpack ~scope;
generate_options_to_msgpack ~scope;
match scope with
| Global | Window | Window_per_buffer | Tabpage -> ()
| Buffer -> generate_buffer_options_kind ()
;;
let generate_options_intf ~scope =
let () =
match scope with
| Global | Window | Tabpage -> ()
| Buffer ->
print_endline
{|
(** Buffer-specific Neovim options. The ['global] phantom type represents the notion of
a "global" value for the option. [`none] means setting the global value has no
effect. [`global] means there is a global value that can be locally overridden.
[`copied] means the global value is copied to the local value on buffer creation,
so setting it will only affect new buffers. *) |}
| Window_per_buffer ->
print_endline
{|
(** Buffer-specific Neovim window options. These operate like buffer options, but the
"global scope" is per-window. The ['global] phantom type represents the notion of
a "global" value for the option. [`global] means there is a global value for each
window that can be locally overridden for any given buffer in the window.
[`copied] means the (per-window) global value is copied to the (per-buffer,window)
local value when a new buffer is opened in the window. The details of when and how
these settings are copied are somewhat arcane, so it's best not to rely on this
behavior. *) |}
in
generate_options_type ~scope
;;