Skip to content

Commit

Permalink
Library-fy coqdoc
Browse files Browse the repository at this point in the history
  • Loading branch information
SkySkimmer committed Dec 9, 2024
1 parent 086cc56 commit ade7dd6
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 158 deletions.
46 changes: 29 additions & 17 deletions tools/coqdoc/cmdArgs.ml
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,25 @@ let arg_string f = Arg.String (fun s -> prefs := f !prefs s)
let arg_file f = Arg.String (fun s -> FileUtil.check_if_file_exists s; prefs := f !prefs s)
let arg_int f = Arg.Int (fun d -> prefs := f !prefs d)

let current = ref 0

let argv = ref [||]

(* TODO: replace these hacks with Arg.Rest_all, when coq moves to a newer version of OCaml stdlib *)
let arg_path f = Arg.String (fun s ->
if Array.length Sys.argv < !Arg.current + 3 ||
CString.is_prefix "-" Sys.argv.(!Arg.current + 2) then
if Array.length !argv < !current + 3 ||
CString.is_prefix "-" !argv.(!current + 2) then
raise (Arg.Bad ("Two arguments expected: <dir> and <name>"))
else
Arg.current := !Arg.current + 1;
prefs := f !prefs (normalize_path s, Sys.argv.(!Arg.current + 1)))
Arg.current := !current + 1;
prefs := f !prefs (normalize_path s, !argv.(!current + 1)))
let arg_url_path f = Arg.String (fun s ->
if Array.length Sys.argv < !Arg.current + 3 ||
CString.is_prefix "-" Sys.argv.(!Arg.current + 2) then
if Array.length !argv < !current + 3 ||
CString.is_prefix "-" !argv.(!current + 2) then
raise (Arg.Bad ("Two arguments expected: <url> and <path>"))
else
Arg.current := !Arg.current + 1;
f s Sys.argv.(!Arg.current + 1))
current := !current + 1;
f s !argv.(!current + 1))

let args_options = Arg.align [
"--html", arg_set (fun p -> { p with targetlang = HTML }),
Expand Down Expand Up @@ -228,17 +232,25 @@ let args_options = Arg.align [
let add_input_files f = prefs := { !prefs with files = what_file f :: !prefs.files }
let usage_msg = "coqdoc [options] <input file>...\nAvailable options are:"

let parse_args () =
(* Deprecated options *)
let single_hyphen_opts =
["-html"; "-latex"; "-texmacs"; "-raw"; "-dvi"; "-ps"; "-pdf"; "-stdout"; "-output"; "-directory"; "-gallina"; "-short"; "-light"; "-title"; "-body-only"; "-no-preamble"; "-with-header"; "-with-footer"; "-no-index"; "-multi-index"; "-index"; "-toc"; "-table-of-contents"; "-vernac-file"; "-tex-file"; "-preamble"; "-files-from"; "-files"; "-glob-from"; "-no-glob"; "-quiet"; "-verbose"; "-no-externals"; "-external"; "-coqlib_url"; "-coqlib"; "-latin1"; "-utf8"; "-charset"; "-inputenc"; "-interpolate"; "-raw-comments"; "-parse-comments"; "-plain-comments"; "-toc-depth"; "-no-lib-name"; "-lib-name"; "-lib-subtitles"; "-inline-notmono"; "-version"] in
["-html"; "-latex"; "-texmacs"; "-raw"; "-dvi"; "-ps"; "-pdf"; "-stdout"; "-output"; "-directory"; "-gallina"; "-short"; "-light"; "-title"; "-body-only"; "-no-preamble"; "-with-header"; "-with-footer"; "-no-index"; "-multi-index"; "-index"; "-toc"; "-table-of-contents"; "-vernac-file"; "-tex-file"; "-preamble"; "-files-from"; "-files"; "-glob-from"; "-no-glob"; "-quiet"; "-verbose"; "-no-externals"; "-external"; "-coqlib_url"; "-coqlib"; "-latin1"; "-utf8"; "-charset"; "-inputenc"; "-interpolate"; "-raw-comments"; "-parse-comments"; "-plain-comments"; "-toc-depth"; "-no-lib-name"; "-lib-name"; "-lib-subtitles"; "-inline-notmono"; "-version"]

let deprecated_mapper_opts =
[("-noindex", "--no-index"); ("-nopreamble", "--no-preamble"); ("-noexternals", "--no-externals"); ("-V", "--version")] in
let new_argv = Array.map (fun s -> match List.find_opt (fun m -> m = s) single_hyphen_opts with
| Some _ -> Printf.sprintf "-%s" s
| None -> (match List.assoc_opt s deprecated_mapper_opts with
| Some b -> b
| None -> s)) Sys.argv in
[("-noindex", "--no-index"); ("-nopreamble", "--no-preamble"); ("-noexternals", "--no-externals"); ("-V", "--version")]

let translate_arg s =
match List.find_opt (fun m -> m = s) single_hyphen_opts with
| Some _ -> Printf.sprintf "-%s" s
| None -> (match List.assoc_opt s deprecated_mapper_opts with
| Some b -> b
| None -> s)

let parse_args ~prog args =
(* Deprecated options *)
let new_argv = List.map translate_arg args in
let new_argv = Array.of_list (prog::new_argv) in
argv := new_argv;
current := 0;
try
Arg.parse_argv new_argv args_options add_input_files usage_msg
with
Expand Down
2 changes: 1 addition & 1 deletion tools/coqdoc/cmdArgs.mli
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
(************************************************************************)

(* Command-line parser with side-effects *)
val parse_args : unit -> unit
val parse_args : prog:string -> string list -> unit
140 changes: 1 addition & 139 deletions tools/coqdoc/coqdoc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -8,142 +8,4 @@
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)

open Printf
open Common

(*s \textbf{Banner.} Always printed. Notice that it is printed on error
output, so that when the output of [coqdoc] is redirected this header
is not (unless both standard and error outputs are redirected, of
course). *)

let banner () =
eprintf "This is coqdoc version %s\n" Coq_config.version;
flush stderr

let target_full_name f =
match !prefs.targetlang with
| HTML -> f ^ ".html"
| Raw -> f ^ ".txt"
| _ -> f ^ ".tex"

(*s The following function produces the output. The default output is
the \LaTeX\ document: in that case, we just call [Web.produce_document].
If option \verb!-dvi!, \verb!-ps! or \verb!-html! is invoked, then
we make calls to \verb!latex! or \verb!dvips! or \verb!pdflatex! accordingly. *)

(*s Functions for generating output files *)

let gen_one_file l =
let file = function
| Vernac_file (f,m) ->
let sub = if !prefs.lib_subtitles then Cpretty.detect_subtitle f m else None in
Output.set_module m sub;
Cpretty.coq_file f m
| Latex_file _ -> ()
in
if (!prefs.header_trailer) then Output.header ();
if !prefs.toc then Output.make_toc ();
List.iter file l;
if !prefs.index then Output.make_index();
if (!prefs.header_trailer) then Output.trailer ()

let gen_mult_files l =
let file = function
| Vernac_file (f,m) ->
let sub = if !prefs.lib_subtitles then Cpretty.detect_subtitle f m else None in
let hf = target_full_name m in
Output.set_module m sub;
open_out_file hf;
if (!prefs.header_trailer) then Output.header ();
Cpretty.coq_file f m;
if (!prefs.header_trailer) then Output.trailer ();
close_out_file()
| Latex_file _ -> ()
in
List.iter file l;
if (!prefs.index && !prefs.targetlang=HTML) then begin
if (!prefs.multi_index) then Output.make_multi_index ();
open_out_file (!prefs.index_name^".html");
page_title := (if !prefs.title <> "" then !prefs.title else "Index");
if (!prefs.header_trailer) then Output.header ();
Output.make_index ();
if (!prefs.header_trailer) then Output.trailer ();
close_out_file()
end;
if (!prefs.toc && !prefs.targetlang=HTML) then begin
open_out_file "toc.html";
page_title := (if !prefs.title <> "" then !prefs.title else "Table of contents");
if (!prefs.header_trailer) then Output.header ();
if !prefs.title <> "" then printf "<h1>%s</h1>\n" !prefs.title;
Output.make_toc ();
if (!prefs.header_trailer) then Output.trailer ();
close_out_file()
end
(* NB: for latex and texmacs, a separated toc or index is meaningless... *)

let read_glob_file vfile f =
try Glob_file.read_glob vfile f
with Sys_error s -> eprintf "Warning: %s (links will not be available)\n" s

let read_glob_file_of = function
| Vernac_file (f,_) ->
read_glob_file (Some f) (Filename.chop_extension f ^ ".glob")
| Latex_file _ -> ()

let index_module = function
| Vernac_file (f,m) ->
Index.add_module m
| Latex_file _ -> ()

module E = Boot.Env

let copy_style_file file =
(* We give preference to coqlib in case it is overriden *)
let env = E.init () in
let coqdoc = E.tool env "coqdoc" in
let sty_file = E.Path.relative coqdoc file in
if not (E.Path.exists sty_file) then
begin
let sty_file = E.Path.to_string sty_file in
eprintf "coqdoc: cannot find coqdoc style file: %s\n" sty_file;
exit 1
end;
let sty_file_s = E.Path.to_string sty_file in
let dst = coqdoc_out file in
FileUtil.copy sty_file_s dst

let produce_document l =
if !prefs.targetlang=HTML then copy_style_file "coqdoc.css";
if !prefs.targetlang=LaTeX then copy_style_file "coqdoc.sty";
(match !prefs.glob_source with
| NoGlob -> ()
| DotGlob -> List.iter read_glob_file_of l
| GlobFile f -> read_glob_file None f);
List.iter index_module l;
match !prefs.out_to with
| StdOut ->
Common.out_channel := stdout;
gen_one_file l
| File f ->
open_out_file f;
gen_one_file l;
close_out_file()
| MultFiles ->
gen_mult_files l

let produce_output fl =
if List.length !prefs.compile_targets = 0 then
produce_document fl
else
let otypes = !prefs.compile_targets in
LatexCompiler.compile ~otypes ~produce_document fl

(*s \textbf{Main program.} Print the banner, parse the command line,
read the files and then call [produce_document] from module [Web]. *)

let _ =
CmdArgs.parse_args (); (* Sets prefs *)
let files = List.rev !prefs.files in
Index.init_coqlib_library ();
if not !prefs.quiet then banner ();
if files <> [] then produce_output files
let () = Coqdoclib.Rocqdoc_main.main ~prog:(Sys.argv.(0)) (List.tl (Array.to_list Sys.argv))
8 changes: 7 additions & 1 deletion tools/coqdoc/dune
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@
(files
(coqdoc.sty as texmf/tex/latex/misc/coqdoc.sty)))

(library
(name coqdoclib)
(modules :standard \ coqdoc)
(libraries str rocq-runtime.boot rocq-runtime.config rocq-runtime.clib))

(executable
(name coqdoc)
(public_name coqdoc)
(package rocq-runtime)
(libraries str rocq-runtime.boot rocq-runtime.config rocq-runtime.clib))
(modules coqdoc)
(libraries coqdoclib))

(ocamllex cpretty)
149 changes: 149 additions & 0 deletions tools/coqdoc/rocqdoc_main.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
(************************************************************************)
(* * The Rocq Prover / The Rocq Development Team *)
(* v * Copyright INRIA, CNRS and contributors *)
(* <O___,, * (see version control and CREDITS file for authors & dates) *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)

open Printf
open Common

(*s \textbf{Banner.} Always printed. Notice that it is printed on error
output, so that when the output of [coqdoc] is redirected this header
is not (unless both standard and error outputs are redirected, of
course). *)

let banner () =
eprintf "This is coqdoc version %s\n" Coq_config.version;
flush stderr

let target_full_name f =
match !prefs.targetlang with
| HTML -> f ^ ".html"
| Raw -> f ^ ".txt"
| _ -> f ^ ".tex"

(*s The following function produces the output. The default output is
the \LaTeX\ document: in that case, we just call [Web.produce_document].
If option \verb!-dvi!, \verb!-ps! or \verb!-html! is invoked, then
we make calls to \verb!latex! or \verb!dvips! or \verb!pdflatex! accordingly. *)

(*s Functions for generating output files *)

let gen_one_file l =
let file = function
| Vernac_file (f,m) ->
let sub = if !prefs.lib_subtitles then Cpretty.detect_subtitle f m else None in
Output.set_module m sub;
Cpretty.coq_file f m
| Latex_file _ -> ()
in
if (!prefs.header_trailer) then Output.header ();
if !prefs.toc then Output.make_toc ();
List.iter file l;
if !prefs.index then Output.make_index();
if (!prefs.header_trailer) then Output.trailer ()

let gen_mult_files l =
let file = function
| Vernac_file (f,m) ->
let sub = if !prefs.lib_subtitles then Cpretty.detect_subtitle f m else None in
let hf = target_full_name m in
Output.set_module m sub;
open_out_file hf;
if (!prefs.header_trailer) then Output.header ();
Cpretty.coq_file f m;
if (!prefs.header_trailer) then Output.trailer ();
close_out_file()
| Latex_file _ -> ()
in
List.iter file l;
if (!prefs.index && !prefs.targetlang=HTML) then begin
if (!prefs.multi_index) then Output.make_multi_index ();
open_out_file (!prefs.index_name^".html");
page_title := (if !prefs.title <> "" then !prefs.title else "Index");
if (!prefs.header_trailer) then Output.header ();
Output.make_index ();
if (!prefs.header_trailer) then Output.trailer ();
close_out_file()
end;
if (!prefs.toc && !prefs.targetlang=HTML) then begin
open_out_file "toc.html";
page_title := (if !prefs.title <> "" then !prefs.title else "Table of contents");
if (!prefs.header_trailer) then Output.header ();
if !prefs.title <> "" then printf "<h1>%s</h1>\n" !prefs.title;
Output.make_toc ();
if (!prefs.header_trailer) then Output.trailer ();
close_out_file()
end
(* NB: for latex and texmacs, a separated toc or index is meaningless... *)

let read_glob_file vfile f =
try Glob_file.read_glob vfile f
with Sys_error s -> eprintf "Warning: %s (links will not be available)\n" s

let read_glob_file_of = function
| Vernac_file (f,_) ->
read_glob_file (Some f) (Filename.chop_extension f ^ ".glob")
| Latex_file _ -> ()

let index_module = function
| Vernac_file (f,m) ->
Index.add_module m
| Latex_file _ -> ()

module E = Boot.Env

let copy_style_file file =
(* We give preference to coqlib in case it is overriden *)
let env = E.init () in
let coqdoc = E.tool env "coqdoc" in
let sty_file = E.Path.relative coqdoc file in
if not (E.Path.exists sty_file) then
begin
let sty_file = E.Path.to_string sty_file in
eprintf "coqdoc: cannot find coqdoc style file: %s\n" sty_file;
exit 1
end;
let sty_file_s = E.Path.to_string sty_file in
let dst = coqdoc_out file in
FileUtil.copy sty_file_s dst

let produce_document l =
if !prefs.targetlang=HTML then copy_style_file "coqdoc.css";
if !prefs.targetlang=LaTeX then copy_style_file "coqdoc.sty";
(match !prefs.glob_source with
| NoGlob -> ()
| DotGlob -> List.iter read_glob_file_of l
| GlobFile f -> read_glob_file None f);
List.iter index_module l;
match !prefs.out_to with
| StdOut ->
Common.out_channel := stdout;
gen_one_file l
| File f ->
open_out_file f;
gen_one_file l;
close_out_file()
| MultFiles ->
gen_mult_files l

let produce_output fl =
if List.length !prefs.compile_targets = 0 then
produce_document fl
else
let otypes = !prefs.compile_targets in
LatexCompiler.compile ~otypes ~produce_document fl

(*s \textbf{Main program.} Print the banner, parse the command line,
read the files and then call [produce_document] from module [Web]. *)

let main ~prog args =
CmdArgs.parse_args ~prog args; (* Sets prefs *)
let files = List.rev !prefs.files in
Index.init_coqlib_library ();
if not !prefs.quiet then banner ();
if files <> [] then produce_output files
11 changes: 11 additions & 0 deletions tools/coqdoc/rocqdoc_main.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(************************************************************************)
(* * The Rocq Prover / The Rocq Development Team *)
(* v * Copyright INRIA, CNRS and contributors *)
(* <O___,, * (see version control and CREDITS file for authors & dates) *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)

val main : prog:string -> string list -> unit

0 comments on commit ade7dd6

Please sign in to comment.