comprehensive completion generation: native, manpage, --help
Three-strategy pipeline with priority: native completion generators (e.g. CMD completions nushell) > manpage parsing > --help fallback. Single `generate` command produces one module-wrapped .nu file per command. Parallel execution scaled to cores, 200ms timeouts, ELF string scanning to skip binaries without -h support, native gzip decompression via camlzip, SYNOPSIS-based subcommand detection, nix3 manpage strategy, deduplication, nushell builtin exclusion.
This commit is contained in:
parent
01ccf64efc
commit
7f0ec8ab4d
9 changed files with 937 additions and 265 deletions
|
|
@ -177,15 +177,15 @@ with \fB\-l\fR, scale sizes by SIZE
|
|||
.SH AUTHOR
|
||||
Written by someone.
|
||||
|} in
|
||||
let entries = parse_manpage_string groff in
|
||||
check "three entries" (List.length entries = 3);
|
||||
if List.length entries >= 1 then begin
|
||||
let e = List.hd entries in
|
||||
let result = parse_manpage_string groff in
|
||||
check "three entries" (List.length result.entries = 3);
|
||||
if List.length result.entries >= 1 then begin
|
||||
let e = List.hd result.entries in
|
||||
check "first is -a/--all" (e.switch = Both ('a', "all"));
|
||||
check "first desc" (String.length e.desc > 0)
|
||||
end;
|
||||
if List.length entries >= 3 then begin
|
||||
let e = List.nth entries 2 in
|
||||
if List.length result.entries >= 3 then begin
|
||||
let e = List.nth result.entries 2 in
|
||||
check "block-size switch" (e.switch = Long "block-size");
|
||||
check "block-size param" (e.param = Some (Mandatory "SIZE"))
|
||||
end
|
||||
|
|
@ -199,10 +199,10 @@ Allow insecure connections.
|
|||
Write output to file.
|
||||
.SH SEE ALSO
|
||||
|} in
|
||||
let entries = parse_manpage_string groff in
|
||||
check "two entries" (List.length entries = 2);
|
||||
if List.length entries >= 1 then begin
|
||||
let e = List.hd entries in
|
||||
let result = parse_manpage_string groff in
|
||||
check "two entries" (List.length result.entries = 2);
|
||||
if List.length result.entries >= 1 then begin
|
||||
let e = List.hd result.entries in
|
||||
check "first is -k/--insecure" (e.switch = Both ('k', "insecure"))
|
||||
end
|
||||
|
||||
|
|
@ -221,8 +221,115 @@ foo \- does stuff
|
|||
.SH DESCRIPTION
|
||||
Does stuff.
|
||||
|} in
|
||||
let entries = parse_manpage_string groff in
|
||||
check "no entries" (List.length entries = 0)
|
||||
let result = parse_manpage_string groff in
|
||||
check "no entries" (List.length result.entries = 0)
|
||||
|
||||
let test_slash_switch_separator () =
|
||||
Printf.printf "\n== Slash switch separator (--long / -s) ==\n";
|
||||
let r = parse " --verbose / -v Increase verbosity\n" in
|
||||
check "one entry" (List.length r.entries = 1);
|
||||
let e = List.hd r.entries in
|
||||
check "both switch" (e.switch = Both ('v', "verbose"));
|
||||
check "no param" (e.param = None);
|
||||
check "desc" (e.desc = "Increase verbosity")
|
||||
|
||||
let test_manpage_nix3_style () =
|
||||
Printf.printf "\n== Manpage nix3 style ==\n";
|
||||
let groff = {|.SH Options
|
||||
.SS Logging-related options
|
||||
.IP "\(bu" 3
|
||||
.UR #opt-verbose
|
||||
\f(CR--verbose\fR
|
||||
.UE
|
||||
/ \f(CR-v\fR
|
||||
.IP
|
||||
Increase the logging verbosity level.
|
||||
.IP "\(bu" 3
|
||||
.UR #opt-quiet
|
||||
\f(CR--quiet\fR
|
||||
.UE
|
||||
.IP
|
||||
Decrease the logging verbosity level.
|
||||
.SH SEE ALSO
|
||||
|} in
|
||||
let result = parse_manpage_string groff in
|
||||
check "two entries" (List.length result.entries = 2);
|
||||
if List.length result.entries >= 1 then begin
|
||||
let e = List.hd result.entries in
|
||||
check "verbose is Both" (e.switch = Both ('v', "verbose"));
|
||||
check "verbose desc" (String.length e.desc > 0)
|
||||
end;
|
||||
if List.length result.entries >= 2 then begin
|
||||
let e = List.nth result.entries 1 in
|
||||
check "quiet is Long" (e.switch = Long "quiet");
|
||||
check "quiet desc" (String.length e.desc > 0)
|
||||
end
|
||||
|
||||
let test_manpage_nix3_with_params () =
|
||||
Printf.printf "\n== Manpage nix3 with params ==\n";
|
||||
let groff = {|.SH Options
|
||||
.IP "\(bu" 3
|
||||
.UR #opt-arg
|
||||
\f(CR--arg\fR
|
||||
.UE
|
||||
\fIname\fR \fIexpr\fR
|
||||
.IP
|
||||
Pass the value as the argument name to Nix functions.
|
||||
.IP "\(bu" 3
|
||||
.UR #opt-include
|
||||
\f(CR--include\fR
|
||||
.UE
|
||||
/ \f(CR-I\fR \fIpath\fR
|
||||
.IP
|
||||
Add path to search path entries.
|
||||
.IP
|
||||
This option may be given multiple times.
|
||||
.SH SEE ALSO
|
||||
|} in
|
||||
let result = parse_manpage_string groff in
|
||||
check "two entries" (List.length result.entries = 2);
|
||||
if List.length result.entries >= 1 then begin
|
||||
let e = List.hd result.entries in
|
||||
check "arg is Long" (e.switch = Long "arg");
|
||||
check "arg has param" (e.param <> None)
|
||||
end;
|
||||
if List.length result.entries >= 2 then begin
|
||||
let e = List.nth result.entries 1 in
|
||||
check "include is Both" (e.switch = Both ('I', "include"));
|
||||
check "include has path param" (e.param = Some (Mandatory "path"))
|
||||
end
|
||||
|
||||
let test_synopsis_subcommand () =
|
||||
Printf.printf "\n== SYNOPSIS subcommand detection ==\n";
|
||||
let groff = {|.SH "SYNOPSIS"
|
||||
.sp
|
||||
.nf
|
||||
\fBgit\fR \fBcommit\fR [\fB\-a\fR | \fB\-\-interactive\fR]
|
||||
.fi
|
||||
.SH "DESCRIPTION"
|
||||
|} in
|
||||
let cmd = extract_synopsis_command groff in
|
||||
check "detected git commit" (cmd = Some "git commit")
|
||||
|
||||
let test_synopsis_standalone () =
|
||||
Printf.printf "\n== SYNOPSIS standalone command ==\n";
|
||||
let groff = {|.SH Synopsis
|
||||
.LP
|
||||
\f(CRnix-build\fR [\fIpaths\fR]
|
||||
.SH Description
|
||||
|} in
|
||||
let cmd = extract_synopsis_command groff in
|
||||
check "detected nix-build" (cmd = Some "nix-build")
|
||||
|
||||
let test_synopsis_nix3 () =
|
||||
Printf.printf "\n== SYNOPSIS nix3 subcommand ==\n";
|
||||
let groff = {|.SH Synopsis
|
||||
.LP
|
||||
\f(CRnix run\fR [\fIoption\fR] \fIinstallable\fR
|
||||
.SH Description
|
||||
|} in
|
||||
let cmd = extract_synopsis_command groff in
|
||||
check "detected nix run" (cmd = Some "nix run")
|
||||
|
||||
(* --- Nushell generation tests --- *)
|
||||
|
||||
|
|
@ -276,8 +383,8 @@ do not ignore entries starting with .
|
|||
scale sizes by SIZE
|
||||
.SH AUTHOR
|
||||
|} in
|
||||
let entries = parse_manpage_string groff in
|
||||
let nu = generate_extern_from_entries "ls" entries in
|
||||
let result = parse_manpage_string groff in
|
||||
let nu = generate_extern "ls" result in
|
||||
check "has extern" (contains nu "export extern \"ls\"");
|
||||
check "has --all(-a)" (contains nu "--all(-a)");
|
||||
check "has --block-size" (contains nu "--block-size: string")
|
||||
|
|
@ -290,6 +397,54 @@ let test_nushell_module () =
|
|||
check "has extern inside" (contains nu "export extern \"myapp\"");
|
||||
check "has flag" (contains nu "--verbose(-v)")
|
||||
|
||||
let test_dedup_entries () =
|
||||
Printf.printf "\n== Deduplication ==\n";
|
||||
let r = parse {| -v, --verbose verbose output
|
||||
--verbose verbose mode
|
||||
-v be verbose
|
||||
|} in
|
||||
let nu = generate_extern "test" r in
|
||||
(* Count occurrences of --verbose *)
|
||||
let count =
|
||||
let re = Str.regexp_string "--verbose" in
|
||||
let n = ref 0 in
|
||||
let i = ref 0 in
|
||||
(try while true do
|
||||
let _ = Str.search_forward re nu !i in
|
||||
incr n; i := Str.match_end ()
|
||||
done with Not_found -> ());
|
||||
!n
|
||||
in
|
||||
check "verbose appears once" (count = 1);
|
||||
check "best version kept (Both)" (contains nu "--verbose(-v)")
|
||||
|
||||
let test_dedup_manpage () =
|
||||
Printf.printf "\n== Dedup from manpage ==\n";
|
||||
let groff = {|.SH OPTIONS
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Be verbose.
|
||||
.SH DESCRIPTION
|
||||
Use \fB\-v\fR for verbose output.
|
||||
Use \fB\-\-verbose\fR to see more.
|
||||
|} in
|
||||
let result = parse_manpage_string groff in
|
||||
let nu = generate_extern "test" result in
|
||||
check "has --verbose(-v)" (contains nu "--verbose(-v)");
|
||||
(* Should not have standalone -v or duplicate --verbose *)
|
||||
let lines = String.split_on_char '\n' nu in
|
||||
let verbose_lines = List.filter (fun l -> contains l "verbose") lines in
|
||||
check "only one verbose line" (List.length verbose_lines = 1)
|
||||
|
||||
let test_font_boundary_spacing () =
|
||||
Printf.printf "\n== Font boundary spacing ==\n";
|
||||
(* \fB--max-results\fR\fIcount\fR should become "--max-results count" *)
|
||||
let s = strip_groff_escapes {|\fB\-\-max\-results\fR\fIcount\fR|} in
|
||||
check "has space before param" (contains s "--max-results count");
|
||||
(* \fB--color\fR[=\fIWHEN\fR] should NOT insert space before = *)
|
||||
let s2 = strip_groff_escapes {|\fB\-\-color\fR[=\fIWHEN\fR]|} in
|
||||
check "no space before =" (contains s2 "--color[=WHEN]")
|
||||
|
||||
let () =
|
||||
Printf.printf "Running help parser tests...\n";
|
||||
test_gnu_basic ();
|
||||
|
|
@ -314,6 +469,12 @@ let () =
|
|||
test_manpage_ip_style ();
|
||||
test_manpage_groff_stripping ();
|
||||
test_manpage_empty_options ();
|
||||
test_slash_switch_separator ();
|
||||
test_manpage_nix3_style ();
|
||||
test_manpage_nix3_with_params ();
|
||||
test_synopsis_subcommand ();
|
||||
test_synopsis_standalone ();
|
||||
test_synopsis_nix3 ();
|
||||
|
||||
Printf.printf "\nRunning nushell generation tests...\n";
|
||||
test_nushell_basic ();
|
||||
|
|
@ -322,5 +483,10 @@ let () =
|
|||
test_nushell_from_manpage ();
|
||||
test_nushell_module ();
|
||||
|
||||
Printf.printf "\nRunning dedup and font tests...\n";
|
||||
test_dedup_entries ();
|
||||
test_dedup_manpage ();
|
||||
test_font_boundary_spacing ();
|
||||
|
||||
Printf.printf "\n=== Results: %d passed, %d failed ===\n" !passes !failures;
|
||||
if !failures > 0 then exit 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue