112 lines
3.9 KiB
OCaml
112 lines
3.9 KiB
OCaml
open Inshellah.Parser
|
|
open Inshellah.Manpage
|
|
open Inshellah.Nushell
|
|
|
|
let usage () =
|
|
Printf.eprintf {|inshellah — generate nushell completions from manpages and --help output
|
|
|
|
Usage:
|
|
inshellah manpage FILE Parse a manpage (.1, .1.gz) and emit nushell extern
|
|
inshellah manpage-dir DIR Batch-process all manpages under DIR/man1/
|
|
inshellah help CMD [ARGS...] Run CMD ARGS --help, parse output, emit nushell extern
|
|
inshellah parse-help CMD Read --help text from stdin, emit nushell extern for CMD
|
|
inshellah demo Run built-in demo
|
|
|
|
|};
|
|
exit 1
|
|
|
|
(* Extract command name from a manpage filename *)
|
|
let cmd_name_of_manpage path =
|
|
let base = Filename.basename path in
|
|
(* strip .gz if present *)
|
|
let base =
|
|
if Filename.check_suffix base ".gz" then Filename.chop_suffix base ".gz"
|
|
else base
|
|
in
|
|
(* strip .N section suffix *)
|
|
try Filename.chop_extension base
|
|
with Invalid_argument _ -> base
|
|
|
|
let cmd_manpage file =
|
|
let cmd = cmd_name_of_manpage file in
|
|
let entries = parse_manpage_file file in
|
|
if entries <> [] then
|
|
print_string (generate_extern_from_entries cmd entries)
|
|
|
|
let cmd_manpage_dir dir =
|
|
(* Walk man1/ through man9/ looking for manpages *)
|
|
for section = 1 to 9 do
|
|
let subdir = Filename.concat dir (Printf.sprintf "man%d" section) in
|
|
if Sys.file_exists subdir && Sys.is_directory subdir then begin
|
|
let files = Sys.readdir subdir in
|
|
Array.sort String.compare files;
|
|
Array.iter (fun file ->
|
|
let path = Filename.concat subdir file in
|
|
try cmd_manpage path
|
|
with _ -> () (* skip unparseable manpages *)
|
|
) files
|
|
end
|
|
done
|
|
|
|
let cmd_help args =
|
|
match args with
|
|
| [] -> Printf.eprintf "error: help mode requires a command name\n"; exit 1
|
|
| cmd :: rest ->
|
|
let full_cmd =
|
|
String.concat " " (List.map Filename.quote (cmd :: rest @ ["--help"]))
|
|
in
|
|
let ic = Unix.open_process_in (full_cmd ^ " 2>&1") in
|
|
let buf = Buffer.create 4096 in
|
|
(try while true do
|
|
let line = input_line ic in
|
|
Buffer.add_string buf line;
|
|
Buffer.add_char buf '\n'
|
|
done with End_of_file -> ());
|
|
let _ = Unix.close_process_in ic in
|
|
let text = Buffer.contents buf in
|
|
let cmd_name = Filename.basename cmd in
|
|
(match parse_help text with
|
|
| Ok r -> print_string (generate_extern cmd_name r)
|
|
| Error msg -> Printf.eprintf "parse error for %s: %s\n" cmd_name msg; exit 1)
|
|
|
|
let cmd_parse_help cmd =
|
|
let buf = Buffer.create 4096 in
|
|
(try while true do
|
|
let line = input_line stdin in
|
|
Buffer.add_string buf line;
|
|
Buffer.add_char buf '\n'
|
|
done with End_of_file -> ());
|
|
let text = Buffer.contents buf in
|
|
(match parse_help text with
|
|
| Ok r -> print_string (generate_extern cmd r)
|
|
| Error msg -> Printf.eprintf "parse error for %s: %s\n" cmd msg; exit 1)
|
|
|
|
let cmd_demo () =
|
|
let ls_help =
|
|
{|Usage: ls [OPTION]... [FILE]...
|
|
List information about the FILEs (the current directory by default).
|
|
|
|
-a, --all do not ignore entries starting with .
|
|
-A, --almost-all do not list implied . and ..
|
|
--block-size=SIZE with -l, scale sizes by SIZE when printing them;
|
|
e.g., '--block-size=M'; see SIZE format below
|
|
--color[=WHEN] color the output WHEN
|
|
-h, --human-readable with -l and -s, print sizes like 1K 234M 2G etc.
|
|
--help display this help and exit
|
|
--version output version information and exit
|
|
|}
|
|
in
|
|
Printf.printf "# Generated by: inshellah demo\n\n";
|
|
(match parse_help ls_help with
|
|
| Ok r -> print_string (generate_extern "ls" r)
|
|
| Error msg -> Printf.eprintf "parse error: %s\n" msg)
|
|
|
|
let () =
|
|
let args = Array.to_list Sys.argv |> List.tl in
|
|
match args with
|
|
| ["manpage"; file] -> cmd_manpage file
|
|
| ["manpage-dir"; dir] -> cmd_manpage_dir dir
|
|
| "help" :: rest -> cmd_help rest
|
|
| ["parse-help"; cmd] -> cmd_parse_help cmd
|
|
| ["demo"] -> cmd_demo ()
|
|
| _ -> usage ()
|