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
open B0_std
open Result.Syntax
let driver =
let libs = [B00_ocaml.Lib.Name.v "b0.b0"] in
B0_driver.create ~name:"b0" ~version:"v0.0.5" ~libs
module Def = struct
let list (module Def : B0_def.S) c format ds =
let pp, sep = match format with
| `Short -> Def.pp_name, Fmt.cut
| `Normal -> Def.pp_synopsis, Fmt.cut
| `Long -> Def.pp, Fmt.(cut ++ cut)
in
Log.if_error ~use:B00_cli.Exit.no_such_name @@
let* ds = Def.get_list_or_hint ~empty_means_all:true ds in
Log.if_error' ~use:B00_cli.Exit.some_error @@
let don't = B0_driver.Conf.no_pager c in
let* = B00_pager.find ~don't () in
let* () = B00_pager.page_stdout pager in
if ds <> [] then Log.app (fun m -> m "@[<v>%a@]" Fmt.(list ~sep pp) ds);
Ok B00_cli.Exit.ok
let edit (module Def : B0_def.S) c ds =
let rec find_files not_found fs = function
| [] -> not_found, Fpath.distinct fs
| d :: ds ->
match B0_def.file (Def.def d) with
| None -> find_files (Def.Set.add d not_found) fs ds
| Some f -> find_files not_found (f :: fs) ds
in
let edit_all = ds = [] in
Log.if_error ~use:B00_cli.Exit.no_such_name @@
let* ds = Def.get_list_or_hint ~empty_means_all:true ds in
let not_found, files = find_files Def.Set.empty [] ds in
Log.if_error' ~use:B00_cli.Exit.some_error @@
match not edit_all && not (Def.Set.is_empty not_found) with
| true ->
let plural = if (Def.Set.cardinal not_found > 1) then "s" else "" in
let none = Def.Set.elements not_found in
Fmt.error "Could not find B0 file for %s%s: @[%a@]"
Def.def_kind plural Fmt.(list ~sep:sp Def.pp_name) none
| false ->
let* editor = B00_editor.find () in
Result.bind (B00_editor.edit_files editor files) @@ function
| `Exited 0 -> Ok B00_cli.Exit.ok
| _ -> Ok B00_cli.Exit.some_error
let get_meta_key (module Def : B0_def.S) c format key ds =
Log.if_error ~use:B00_cli.Exit.no_such_name @@
let* B0_meta.Key.V key = B0_meta.Key.get_or_hint key in
let* ds = Def.get_list_or_hint ~empty_means_all:true ds in
let add_meta acc d = match B0_meta.find_binding key (Def.meta d) with
| None -> acc | Some v -> (d, v) :: acc
in
let bs = List.rev @@ List.fold_left add_meta [] ds in
begin match ds with
| [d] ->
begin match bs with
| [] -> ()
| [_, B0_meta.B (k, v)] ->
Log.app (fun m -> m "@[<h>%a@]" (B0_meta.Key.pp_value k) v)
| _ -> assert false
end
| _ ->
let pp_bindings ppf (d, B0_meta.B (k, v)) =
Fmt.pf ppf "@[<h>%a %a@]" Def.pp_name d (B0_meta.Key.pp_value k) v
in
Log.app (fun m -> m "@[<v>%a@]" Fmt.(list pp_bindings) bs)
end;
Ok B00_cli.Exit.ok
end
module Cli = struct
open Cmdliner
let man_see_manual = `Blocks
[ `S Manpage.s_see_also;
`P "Consult $(b,odig doc b0) for manuals and more details."]
let man_with_descr ?synopsis descr =
let man = [`S Manpage.s_description;
descr;
`S Manpage.s_commands;
`S Manpage.s_arguments;
`S Manpage.s_options;
`S B00_cli.s_output_format_options;
`S Manpage.s_common_options;
man_see_manual]
in
match synopsis with
| None -> man
| Some syn -> `S Manpage.s_synopsis :: syn :: man
let editor_envs = B00_editor.envs ()
let = B00_pager.envs ()
let format = B00_cli.Arg.output_format ()
let pos_key =
let doc = "The metadata key $(docv) to get." and docv = "KEY" in
Arg.(required & pos 0 (some string) None & info [] ~doc ~docv)
let subcmd_with_b0_file
?(exits = B0_driver.Exit.infos) ?(envs = []) ?synopsis name ~doc ~descr
term
=
let man = man_with_descr ?synopsis descr in
let term = B0_driver.with_b0_file ~driver term in
Cmd.v (Cmd.info name ~doc ~exits ~envs ~man) term
let cmd_group_with_b0_file
?(exits = B0_driver.Exit.infos) ?(envs = []) ?synopsis name ~doc ~descr
~default subs
=
let man = man_with_descr ?synopsis descr in
let default = B0_driver.with_b0_file ~driver default in
Cmd.group (Cmd.info name ~doc ~exits ~envs ~man) ~default subs
let subcmd_with_driver_conf
?(exits = B0_driver.Exit.infos) ?(envs = []) ?synopsis name ~doc ~descr
term
=
let man = man_with_descr ?synopsis descr in
let term = Term.(term $ B0_driver.Cli.conf) in
Cmd.v (Cmd.info name ~doc ~exits ~envs ~man) term
let cmd_group_with_driver_conf
?(exits = B0_driver.Exit.infos) ?(envs = []) ?synopsis name ~doc ~descr
~default subs
=
let man = man_with_descr ?synopsis descr in
let default = Term.(default $ B0_driver.Cli.conf) in
Cmd.group (Cmd.info name ~doc ~exits ~envs ~man) ~default subs
end