Skip to content

Commit 0bb18d8

Browse files
committed
Arg.align: optionally use '\t' as alignment separator
Arg.align now optionally uses the tab character '\t' to separate the "unaligned" and "aligned" parts of the documentation string. If tab is not present, then space is used as a fallback. Allows to have spaces in the unaligned part, which is useful for Tuple options.
1 parent 2691c40 commit 0bb18d8

File tree

5 files changed

+62
-20
lines changed

5 files changed

+62
-20
lines changed

Changes

+5
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ Working version
6161

6262
- Resurrect tabulation boxes in module Format. Rewrite/extend documentation
6363
of tabulation boxes.
64+
- PR#7515, GPR#1147: Arg.align now optionally uses the tab character '\t' to
65+
separate the "unaligned" and "aligned" parts of the documentation string. If
66+
tab is not present, then space is used as a fallback. Allows to have spaces in the
67+
unaligned part, which is useful for Tuple options.
68+
(Nicolas Ojeda Bar, review by ...)
6469

6570
### Compiler user-interface and warnings:
6671

stdlib/arg.ml

+24-12
Original file line numberDiff line numberDiff line change
@@ -304,20 +304,32 @@ let parse_expand l f msg =
304304

305305
let second_word s =
306306
let len = String.length s in
307-
let rec loop n =
308-
if n >= len then len
309-
else if s.[n] = ' ' then loop (n+1)
310-
else n
307+
let rec loop sep n =
308+
if n >= len then sep, len
309+
else if s.[n] = sep then loop sep (n+1)
310+
else sep, n
311311
in
312-
try loop (String.index s ' ')
313-
with Not_found -> len
312+
match String.index s '\t' with
313+
| n -> loop '\t' n
314+
| exception Not_found ->
315+
begin match String.index s ' ' with
316+
| n -> loop ' ' n
317+
| exception Not_found -> ' ', len
318+
end
314319

315320

316321
let max_arg_len cur (kwd, spec, doc) =
317322
match spec with
318323
| Symbol _ -> max cur (String.length kwd)
319-
| _ -> max cur (String.length kwd + second_word doc)
324+
| _ -> max cur (String.length kwd + snd (second_word doc))
325+
320326

327+
let sub_subst s n sep =
328+
let last_sep = ref (-1) in
329+
let f i =
330+
if s.[i] = sep && (!last_sep < 0 || !last_sep = i-1) then (last_sep := i; ' ') else s.[i]
331+
in
332+
String.init n f
321333

322334
let add_padding len ksd =
323335
match ksd with
@@ -326,18 +338,18 @@ let add_padding len ksd =
326338
* run through [usage] or [parse]. *)
327339
ksd
328340
| (kwd, (Symbol _ as spec), msg) ->
329-
let cutcol = second_word msg in
341+
let sep, cutcol = second_word msg in
330342
let spaces = String.make ((max 0 (len - cutcol)) + 3) ' ' in
331-
(kwd, spec, "\n" ^ spaces ^ msg)
343+
(kwd, spec, "\n" ^ spaces ^ sub_subst msg (String.length msg) sep)
332344
| (kwd, spec, msg) ->
333-
let cutcol = second_word msg in
345+
let sep, cutcol = second_word msg in
334346
let kwd_len = String.length kwd in
335347
let diff = len - kwd_len - cutcol in
336348
if diff <= 0 then
337-
(kwd, spec, msg)
349+
(kwd, spec, sub_subst msg (String.length msg) sep)
338350
else
339351
let spaces = String.make diff ' ' in
340-
let prefix = String.sub msg 0 cutcol in
352+
let prefix = sub_subst msg cutcol sep in
341353
let suffix = String.sub msg cutcol (String.length msg - cutcol) in
342354
(kwd, spec, prefix ^ spaces ^ suffix)
343355

stdlib/arg.mli

+7-8
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,13 @@ val usage_string : (key * spec * doc) list -> usage_msg -> string
168168
if provided with the same parameters. *)
169169

170170
val align: ?limit: int -> (key * spec * doc) list -> (key * spec * doc) list
171-
(** Align the documentation strings by inserting spaces at the first
172-
space, according to the length of the keyword. Use a
173-
space as the first character in a doc string if you want to
174-
align the whole string. The doc strings corresponding to
175-
[Symbol] arguments are aligned on the next line.
176-
@param limit options with keyword and message longer than
177-
[limit] will not be used to compute the alignment.
178-
*)
171+
(** Align the documentation strings by inserting spaces at the first alignment
172+
separator (tab or, if tab is not found, space), according to the length of
173+
the keyword. Use a alignment separator as the first character in a doc
174+
string if you want to align the whole string. The doc strings corresponding
175+
to [Symbol] arguments are aligned on the next line.
176+
@param limit options with keyword and message longer than [limit] will not
177+
be used to compute the alignment. *)
179178

180179
val current : int ref
181180
(** Position (in {!Sys.argv}) of the argument being processed. You can

testsuite/tests/lib-arg/testarg.ml

+15
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,18 @@ let test_expand spec argv reference =
187187

188188
test_expand (expand1@spec) args1 expected1;;
189189
test_expand (expand2@spec) args2 expected2;;
190+
191+
let test_align () =
192+
let spec =
193+
[
194+
"-foo", Arg.String ignore, "FOO Do foo with FOO";
195+
"-bar", Arg.Tuple [Arg.String ignore; Arg.String ignore], "FOO BAR\tDo bar with FOO and BAR";
196+
"-cha", Arg.Unit ignore, " Another option";
197+
"-sym", Arg.Symbol (["a"; "b"], ignore), "\ty\tfoo";
198+
"-sym2", Arg.Symbol (["a"; "b"], ignore), "x bar";
199+
]
200+
in
201+
print_endline (Arg.usage_string (Arg.align spec) "")
202+
;;
203+
204+
test_align ();;
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
-foo FOO Do foo with FOO
3+
-bar FOO BAR Do bar with FOO and BAR
4+
-cha Another option
5+
-sym {a|b}
6+
y foo
7+
-sym2 {a|b}
8+
x bar
9+
-help Display this list of options
10+
--help Display this list of options
11+

0 commit comments

Comments
 (0)