(***********************************************************************) (* OCamldoc *) (* *) (* Maxence Guesdon, projet Cristal, INRIA Rocquencourt *) (* *) (* Copyright 2001 Institut National de Recherche en Informatique et *) (* en Automatique. All rights reserved. This file is distributed *) (* under the terms of the Q Public License version 1.0. *) (* *) (***********************************************************************) (* $Id$ *) (** Generation of LaTeX documentation. *) let print_DEBUG s = print_string s ; print_newline () open Odoc_info open Parameter open Value open Type open Exception open Class open Module let separate_files = ref false let latex_titles = ref [ 1, "section" ; 2, "subsection" ; 3, "subsubsection" ; 4, "paragraph" ; 5, "subparagraph" ; ] let latex_value_prefix = ref Odoc_messages.default_latex_value_prefix let latex_type_prefix = ref Odoc_messages.default_latex_type_prefix let latex_exception_prefix = ref Odoc_messages.default_latex_exception_prefix let latex_module_prefix = ref Odoc_messages.default_latex_module_prefix let latex_module_type_prefix = ref Odoc_messages.default_latex_module_type_prefix let latex_class_prefix = ref Odoc_messages.default_latex_class_prefix let latex_class_type_prefix = ref Odoc_messages.default_latex_class_type_prefix let latex_attribute_prefix = ref Odoc_messages.default_latex_attribute_prefix let latex_method_prefix = ref Odoc_messages.default_latex_method_prefix let new_buf () = Buffer.create 1024 let new_fmt () = let b = new_buf () in let fmt = Format.formatter_of_buffer b in (fmt, fun () -> Format.pp_print_flush fmt (); let s = Buffer.contents b in Buffer.reset b; s ) let p = Format.fprintf let ps f s = Format.fprintf f "%s" s let bp = Printf.bprintf let bs = Buffer.add_string let print_concat fmt sep f = let rec iter = function [] -> () | [c] -> f c | c :: q -> f c; ps fmt sep; iter q in iter (** Generation of LaTeX code from text structures. *) class text = object (self) (** Return latex code to make a sectionning according to the given level, and with the given latex code. *) method section_style level s = try let sec = List.assoc level !latex_titles in "\\"^sec^"{"^s^"}\n" with Not_found -> s (** Associations of strings to subsitute in latex code. *) val mutable subst_strings = [ ("MAXENCE"^"ZZZ", "\\$"); ("MAXENCE"^"YYY", "\\&"); ("MAXENCE"^"XXX", "{\\textbackslash}") ; ("à", "\\`a") ; ("â", "\\^a") ; ("é", "\\'e") ; ("è", "\\`e") ; ("ê", "\\^e") ; ("ë", "\\\"e") ; ("ç", "\\c{c}") ; ("ô", "\\^o") ; ("ö", "\\\"o") ; ("î", "\\^i") ; ("ï", "\\\"i") ; ("ù", "\\`u") ; ("û", "\\^u") ; ("%", "\\%") ; ("_", "\\_"); ("\\.\\.\\.", "$\\ldots$"); ("~", "\\~{}"); ("#", "\\verb`#`"); ("}", "\\}"); ("{", "\\{"); ("&", "\\&"); (">", "$>$"); ("<", "$<$"); ("=", "$=$"); (">=", "$\\geq$"); ("<=", "$\\leq$"); ("->", "$\\rightarrow$") ; ("<-", "$\\leftarrow$"); ("|", "\\textbar "); ("\\^", "\\textasciicircum ") ; ("\\.\\.\\.", "$\\ldots$"); ("\\\\", "MAXENCE"^"XXX") ; ("&", "MAXENCE"^"YYY") ; ("\\$", "MAXENCE"^"ZZZ"); ] val mutable subst_strings_simple = [ ("MAXENCE"^"XXX", "{\\textbackslash}") ; "}", "\\}" ; "{", "\\{" ; ("\\\\", "MAXENCE"^"XXX") ; ] val mutable subst_strings_code = [ ("MAXENCE"^"ZZZ", "\\$"); ("MAXENCE"^"YYY", "\\&"); ("MAXENCE"^"XXX", "{\\textbackslash}") ; ("%", "\\%") ; ("_", "\\_"); ("~", "\\~{}"); ("#", "\\verb`#`"); ("}", "\\}"); ("{", "\\{"); ("&", "\\&"); ("\\^", "\\textasciicircum ") ; ("&", "MAXENCE"^"YYY") ; ("\\$", "MAXENCE"^"ZZZ") ; ("\\\\", "MAXENCE"^"XXX") ; ] method subst l s = List.fold_right (fun (s, s2) -> fun acc -> Str.global_replace (Str.regexp s) s2 acc) l s (** Escape the strings which would clash with LaTeX syntax. *) method escape s = self#subst subst_strings s (** Escape the ['\'], ['{'] and ['}'] characters. *) method escape_simple s = self#subst subst_strings_simple s (** Escape some characters for the code style. *) method escape_code s = self#subst subst_strings_code s (** Make a correct latex label from a name. *) (* The following characters are forbidden in LaTeX \index: \ { } $ & # ^ _ % ~ ! " @ | (" to close the double quote) The following characters are forbidden in LaTeX \label: \ { } $ & # ^ _ % ~ So we will use characters not forbidden in \index if no_ = true. *) method label ?(no_=true) name = let len = String.length name in let buf = Buffer.create len in for i = 0 to len - 1 do let (s_no_, s) = match name.[i] with '_' -> ("-underscore", "_") | '~' -> ("-tilde", "~") | '%' -> ("-percent", "%") | '@' -> ("-at", "\"@") | '!' -> ("-bang", "\"!") | '|' -> ("-pipe", "\\char124") | '<' -> ("-lt", "<") | '>' -> ("-gt", ">") | '^' -> ("-exp", "^") | '&' -> ("-ampersand", "&") | '+' -> ("-plus", "+") | '-' -> ("-minus", "-") | '*' -> ("-star", "*") | '/' -> ("-slash", "/") | '$' -> ("-dollar", "$") | '=' -> ("-equal", "=") | ':' -> ("-colon", ":") | c -> (String.make 1 c, String.make 1 c) in Buffer.add_string buf (if no_ then s_no_ else s) done; Buffer.contents buf (** Make a correct label from a value name. *) method value_label ?no_ name = !latex_value_prefix^(self#label ?no_ name) (** Make a correct label from an attribute name. *) method attribute_label ?no_ name = !latex_attribute_prefix^(self#label ?no_ name) (** Make a correct label from a method name. *) method method_label ?no_ name = !latex_method_prefix^(self#label ?no_ name) (** Make a correct label from a class name. *) method class_label ?no_ name = !latex_class_prefix^(self#label ?no_ name) (** Make a correct label from a class type name. *) method class_type_label ?no_ name = !latex_class_type_prefix^(self#label ?no_ name) (** Make a correct label from a module name. *) method module_label ?no_ name = !latex_module_prefix^(self#label ?no_ name) (** Make a correct label from a module type name. *) method module_type_label ?no_ name = !latex_module_type_prefix^(self#label ?no_ name) (** Make a correct label from an exception name. *) method exception_label ?no_ name = !latex_exception_prefix^(self#label ?no_ name) (** Make a correct label from a type name. *) method type_label ?no_ name = !latex_type_prefix^(self#label ?no_ name) (** Return latex code for the label of a given label. *) method make_label label = "\\label{"^label^"}" (** Return latex code for the ref to a given label. *) method make_ref label = "\\ref{"^label^"}" (** Print the LaTeX code corresponding to the [text] parameter.*) method latex_of_text fmt t = List.iter (self#latex_of_text_element fmt) t (** Print the LaTeX code for the [text_element] in parameter. *) method latex_of_text_element fmt te = match te with | Odoc_info.Raw s -> self#latex_of_Raw fmt s | Odoc_info.Code s -> self#latex_of_Code fmt s | Odoc_info.CodePre s -> self#latex_of_CodePre fmt s | Odoc_info.Verbatim s -> self#latex_of_Verbatim fmt s | Odoc_info.Bold t -> self#latex_of_Bold fmt t | Odoc_info.Italic t -> self#latex_of_Italic fmt t | Odoc_info.Emphasize t -> self#latex_of_Emphasize fmt t | Odoc_info.Center t -> self#latex_of_Center fmt t | Odoc_info.Left t -> self#latex_of_Left fmt t | Odoc_info.Right t -> self#latex_of_Right fmt t | Odoc_info.List tl -> self#latex_of_List fmt tl | Odoc_info.Enum tl -> self#latex_of_Enum fmt tl | Odoc_info.Newline -> self#latex_of_Newline fmt | Odoc_info.Block t -> self#latex_of_Block fmt t | Odoc_info.Title (n, l_opt, t) -> self#latex_of_Title fmt n l_opt t | Odoc_info.Latex s -> self#latex_of_Latex fmt s | Odoc_info.Link (s, t) -> self#latex_of_Link fmt s t | Odoc_info.Ref (name, ref_opt, text_opt) -> self#latex_of_Ref fmt name ref_opt text_opt | Odoc_info.Superscript t -> self#latex_of_Superscript fmt t | Odoc_info.Subscript t -> self#latex_of_Subscript fmt t | Odoc_info.Module_list _ -> () | Odoc_info.Index_list -> () | Odoc_info.Custom (s,t) -> self#latex_of_custom_text fmt s t | Odoc_info.Target (target, code) -> self#latex_of_Target fmt ~target ~code method latex_of_custom_text fmt s t = () method latex_of_Target fmt ~target ~code = if String.lowercase target = "latex" then self#latex_of_Latex fmt code else () method latex_of_Raw fmt s = ps fmt (self#escape s) method latex_of_Code fmt s = let s2 = self#escape_code s in let s3 = Str.global_replace (Str.regexp "\n") ("\\\\\n") s2 in p fmt "{\\tt{%s}}" s3 method latex_of_CodePre fmt s = ps fmt "\\begin{ocamldoccode}\n"; ps fmt (self#escape_simple s); ps fmt "\n\\end{ocamldoccode}\n" method latex_of_Verbatim fmt s = ps fmt "\\begin{verbatim}"; ps fmt s; ps fmt "\\end{verbatim}" method latex_of_Bold fmt t = ps fmt "{\\bf "; self#latex_of_text fmt t; ps fmt "}" method latex_of_Italic fmt t = ps fmt "{\\it "; self#latex_of_text fmt t; ps fmt "}" method latex_of_Emphasize fmt t = ps fmt "{\\em "; self#latex_of_text fmt t; ps fmt "}" method latex_of_Center fmt t = ps fmt "\\begin{center}\n"; self#latex_of_text fmt t; ps fmt "\\end{center}\n" method latex_of_Left fmt t = ps fmt "\\begin{flushleft}\n"; self#latex_of_text fmt t; ps fmt "\\end{flushleft}\n" method latex_of_Right fmt t = ps fmt "\\begin{flushright}\n"; self#latex_of_text fmt t; ps fmt "\\end{flushright}\n" method latex_of_List fmt tl = ps fmt "\\begin{itemize}\n"; List.iter (fun t -> ps fmt "\\item "; self#latex_of_text fmt t; ps fmt "\n" ) tl; ps fmt "\\end{itemize}\n" method latex_of_Enum fmt tl = ps fmt "\\begin{enumerate}\n"; List.iter (fun t -> ps fmt "\\item "; self#latex_of_text fmt t; ps fmt "\n" ) tl; ps fmt "\\end{enumerate}\n" method latex_of_Newline fmt = ps fmt "\n\n" method latex_of_Block fmt t = ps fmt "\\begin{ocamldocdescription}\n"; self#latex_of_text fmt t; ps fmt "\n\\end{ocamldocdescription}\n" method latex_of_Title fmt n label_opt t = let (fmt2, flush) = new_fmt () in self#latex_of_text fmt2 t; let s_title2 = self#section_style n (flush ()) in ps fmt s_title2; ( match label_opt with None -> () | Some l -> ps fmt (self#make_label (self#label ~no_: false l)) ) method latex_of_Latex fmt s = ps fmt s method latex_of_Link fmt s t = self#latex_of_text fmt t ; ps fmt "[\\url{"; ps fmt s ; ps fmt "}]" method latex_of_Ref fmt name ref_opt text_opt = match ref_opt with None -> self#latex_of_text fmt (match text_opt with None -> [Odoc_info.Code (Odoc_info.use_hidden_modules name)] | Some t -> t ) | Some (RK_section _) -> self#latex_of_text_element fmt (Latex ("["^(self#make_ref (self#label ~no_:false (Name.simple name)))^"]")) | Some kind -> let f_label = match kind with Odoc_info.RK_module -> self#module_label | Odoc_info.RK_module_type -> self#module_type_label | Odoc_info.RK_class -> self#class_label | Odoc_info.RK_class_type -> self#class_type_label | Odoc_info.RK_value -> self#value_label | Odoc_info.RK_type -> self#type_label | Odoc_info.RK_exception -> self#exception_label | Odoc_info.RK_attribute -> self#attribute_label | Odoc_info.RK_method -> self#method_label | Odoc_info.RK_section _ -> assert false in let text = match text_opt with None -> [Odoc_info.Code (Odoc_info.use_hidden_modules name)] | Some t -> t in self#latex_of_text fmt (text @ [Latex ("["^(self#make_ref (f_label name))^"]")]) method latex_of_Superscript fmt t = ps fmt "$^{"; self#latex_of_text fmt t; ps fmt "}$" method latex_of_Subscript fmt t = ps fmt "$_{"; self#latex_of_text fmt t; ps fmt "}$" end (** A class used to generate LaTeX code for info structures. *) class virtual info = object (self) (** The method used to get LaTeX code from a [text]. *) method virtual latex_of_text : Format.formatter -> Odoc_info.text -> unit (** The method used to get a [text] from an optionel info structure. *) method virtual text_of_info : ?block: bool -> Odoc_info.info option -> Odoc_info.text (** Print LaTeX code for a description, except for the [i_params] field. *) method latex_of_info fmt ?(block=false) info_opt = self#latex_of_text fmt (self#text_of_info ~block info_opt) end module Generator = struct (** This class is used to create objects which can generate a simple LaTeX documentation. *) class latex = object (self) inherit text inherit Odoc_to_text.to_text as to_text inherit info (** Get the first sentence and the rest of a description, from an optional [info] structure. The first sentence can be empty if it would not appear right in a title. In the first sentence, the titles and lists has been removed, since it is used in LaTeX titles and would make LaTeX complain if we has two nested \section commands. *) method first_and_rest_of_info i_opt = match i_opt with None -> ([], []) | Some i -> match i.Odoc_info.i_desc with None -> ([], self#text_of_info ~block: true i_opt) | Some t -> let (first,_) = Odoc_info.first_sentence_and_rest_of_text t in let (_, rest) = Odoc_info.first_sentence_and_rest_of_text (self#text_of_info ~block: false i_opt) in (Odoc_info.text_no_title_no_list first, rest) (** Print LaTeX code for a value. *) method latex_of_value fmt v = Odoc_info.reset_type_names () ; let label = self#value_label v.val_name in let latex = self#make_label label in self#latex_of_text fmt ((Latex latex) :: (to_text#text_of_value v)) (** Print LaTeX code for a class attribute. *) method latex_of_attribute fmt a = self#latex_of_text fmt ((Latex (self#make_label (self#attribute_label a.att_value.val_name))) :: (to_text#text_of_attribute a)) (** Print LaTeX code for a class method. *) method latex_of_method fmt m = self#latex_of_text fmt ((Latex (self#make_label (self#method_label m.met_value.val_name))) :: (to_text#text_of_method m)) (** Print LaTeX code for the parameters of a type. *) method latex_of_type_params fmt m_name t = let print_one (p, co, cn) = ps fmt (Odoc_info.string_of_variance t (co,cn)); ps fmt (self#normal_type m_name p) in match t.ty_parameters with [] -> () | [(p,co,cn)] -> print_one (p, co, cn) | l -> ps fmt "("; print_concat fmt ", " print_one t.ty_parameters; ps fmt ")" method latex_of_class_parameter_list fmt father c = self#latex_of_text fmt (self#text_of_class_params father c) (** Print LaTeX code for a type. *) method latex_of_type fmt t = let s_name = Name.simple t.ty_name in let text = let (fmt2, flush2) = new_fmt () in Odoc_info.reset_type_names () ; let mod_name = Name.father t.ty_name in Format.fprintf fmt2 "@[type "; self#latex_of_type_params fmt2 mod_name t; (match t.ty_parameters with [] -> () | _ -> ps fmt2 " "); ps fmt2 s_name; let priv = t.ty_private = Asttypes.Private in ( match t.ty_manifest with None -> () | Some typ -> p fmt2 " = %s%s" (if priv then "private " else "") (self#normal_type mod_name typ) ); let s_type3 = p fmt2 " %s" ( match t.ty_kind with Type_abstract -> "" | Type_variant _ -> "="^(if priv then " private" else "") | Type_record _ -> "= "^(if priv then "private " else "")^"{" ) ; flush2 () in let defs = match t.ty_kind with Type_abstract -> [] | Type_variant l -> (List.flatten (List.map (fun constr -> let s_cons = p fmt2 "@[ | %s" constr.vc_name; ( match constr.vc_args, constr.vc_ret with [], None -> () | l, None -> p fmt2 " %s@ %s" "of" (self#normal_type_list ~par: false mod_name " * " l) | [], Some r -> p fmt2 " %s@ %s" ":" (self#normal_type mod_name r) | l, Some r -> p fmt2 " %s@ %s@ %s@ %s" ":" (self#normal_type_list ~par: false mod_name " * " l) "->" (self#normal_type mod_name r) ); flush2 () in [ CodePre s_cons ] @ (match constr.vc_text with None -> [] | Some t -> let s = ps fmt2 "\\begin{ocamldoccomment}\n"; self#latex_of_text fmt2 t; ps fmt2 "\n\\end{ocamldoccomment}\n"; flush2 () in [ Latex s] ) ) l ) ) | Type_record l -> (List.flatten (List.map (fun r -> let s_field = p fmt2 "@[ %s%s :@ %s ;" (if r.rf_mutable then "mutable " else "") r.rf_name (self#normal_type mod_name r.rf_type); flush2 () in [ CodePre s_field ] @ (match r.rf_text with None -> [] | Some t -> let s = ps fmt2 "\\begin{ocamldoccomment}\n"; self#latex_of_text fmt2 t; ps fmt2 "\n\\end{ocamldoccomment}\n"; flush2 () in [ Latex s] ) ) l ) ) @ [ CodePre "}" ] in let defs2 = (CodePre s_type3) :: defs in let rec iter = function [] -> [] | [e] -> [e] | (CodePre s1) :: (CodePre s2) :: q -> iter ((CodePre (s1^"\n"^s2)) :: q) | e :: q -> e :: (iter q) in (iter defs2) @ [Latex ("\\index{"^(self#label s_name)^"@\\verb`"^(self#label ~no_:false s_name)^"`}\n")] @ (self#text_of_info t.ty_info) in self#latex_of_text fmt ((Latex (self#make_label (self#type_label t.ty_name))) :: text) (** Print LaTeX code for an exception. *) method latex_of_exception fmt e = Odoc_info.reset_type_names () ; self#latex_of_text fmt ((Latex (self#make_label (self#exception_label e.ex_name))) :: (to_text#text_of_exception e)) method latex_of_module_parameter fmt m_name p = self#latex_of_text fmt [ Code "functor ("; Code p.mp_name ; Code " : "; ] ; self#latex_of_module_type_kind fmt m_name p.mp_kind; self#latex_of_text fmt [ Code ") -> "] method latex_of_module_type_kind fmt father kind = match kind with Module_type_struct eles -> self#latex_of_text fmt [Latex "\\begin{ocamldocsigend}\n"]; List.iter (self#latex_of_module_element fmt father) eles; self#latex_of_text fmt [Latex "\\end{ocamldocsigend}\n"] | Module_type_functor (p, k) -> self#latex_of_module_parameter fmt father p; self#latex_of_module_type_kind fmt father k | Module_type_alias a -> self#latex_of_text fmt [Code (self#relative_module_idents father a.mta_name)] | Module_type_with (k, s) -> self#latex_of_module_type_kind fmt father k; self#latex_of_text fmt [ Code " "; Code (self#relative_idents father s); ] | Module_type_typeof s -> self#latex_of_text fmt [ Code "module type of "; Code (self#relative_idents father s); ] method latex_of_module_kind fmt father kind = match kind with Module_struct eles -> self#latex_of_text fmt [Latex "\\begin{ocamldocsigend}\n"]; List.iter (self#latex_of_module_element fmt father) eles; self#latex_of_text fmt [Latex "\\end{ocamldocsigend}\n"] | Module_alias a -> self#latex_of_text fmt [Code (self#relative_module_idents father a.ma_name)] | Module_functor (p, k) -> self#latex_of_module_parameter fmt father p; self#latex_of_module_kind fmt father k | Module_apply (k1, k2) -> (* TODO: l'application n'est pas correcte dans un .mli. Que faire ? -> afficher le module_type du typedtree *) self#latex_of_module_kind fmt father k1; self#latex_of_text fmt [Code "("]; self#latex_of_module_kind fmt father k2; self#latex_of_text fmt [Code ")"] | Module_with (k, s) -> (* TODO: à modifier quand Module_with sera plus détaillé *) self#latex_of_module_type_kind fmt father k; self#latex_of_text fmt [ Code " "; Code (self#relative_idents father s) ; ] | Module_constraint (k, tk) -> (* TODO: on affiche quoi ? *) self#latex_of_module_kind fmt father k | Module_typeof s -> self#latex_of_text fmt [ Code "module type of "; Code (self#relative_idents father s); ] | Module_unpack (s, _) -> self#latex_of_text fmt [ Code (self#relative_idents father s); ] method latex_of_class_kind fmt father kind = match kind with Class_structure (inh, eles) -> self#latex_of_text fmt [Latex "\\begin{ocamldocobjectend}\n"]; self#generate_inheritance_info fmt inh; List.iter (self#latex_of_class_element fmt father) eles; self#latex_of_text fmt [Latex "\\end{ocamldocobjectend}\n"] | Class_apply capp -> (* TODO: afficher le type final à partir du typedtree *) self#latex_of_text fmt [Raw "class application not handled yet"] | Class_constr cco -> ( match cco.cco_type_parameters with [] -> () | l -> self#latex_of_text fmt ( Code "[" :: (self#text_of_class_type_param_expr_list father l) @ [Code "] "] ) ); self#latex_of_text fmt [Code (self#relative_idents father cco.cco_name)] | Class_constraint (ck, ctk) -> self#latex_of_text fmt [Code "( "] ; self#latex_of_class_kind fmt father ck; self#latex_of_text fmt [Code " : "] ; self#latex_of_class_type_kind fmt father ctk; self#latex_of_text fmt [Code " )"] method latex_of_class_type_kind fmt father kind = match kind with Class_type cta -> ( match cta.cta_type_parameters with [] -> () | l -> self#latex_of_text fmt (Code "[" :: (self#text_of_class_type_param_expr_list father l) @ [Code "] "] ) ); self#latex_of_text fmt [Code (self#relative_idents father cta.cta_name)] | Class_signature (inh, eles) -> self#latex_of_text fmt [Latex "\\begin{ocamldocobjectend}\n"]; self#generate_inheritance_info fmt inh; List.iter (self#latex_of_class_element fmt father) eles; self#latex_of_text fmt [Latex "\\end{ocamldocobjectend}\n"] method latex_for_module_index fmt m = let s_name = Name.simple m.m_name in self#latex_of_text fmt [Latex ("\\index{"^(self#label s_name)^"@\\verb`"^ (self#label ~no_:false s_name)^"`}\n" ) ] method latex_for_module_type_index fmt mt = let s_name = Name.simple mt.mt_name in self#latex_of_text fmt [Latex ("\\index{"^(self#label s_name)^"@\\verb`"^ (self#label ~no_:false (Name.simple s_name))^"`}\n" ) ] method latex_for_module_label fmt m = ps fmt (self#make_label (self#module_label m.m_name)) method latex_for_module_type_label fmt mt = ps fmt (self#make_label (self#module_type_label mt.mt_name)) method latex_for_class_index fmt c = let s_name = Name.simple c.cl_name in self#latex_of_text fmt [Latex ("\\index{"^(self#label s_name)^"@\\verb`"^ (self#label ~no_:false s_name)^"`}\n" ) ] method latex_for_class_type_index fmt ct = let s_name = Name.simple ct.clt_name in self#latex_of_text fmt [Latex ("\\index{"^(self#label s_name)^"@\\verb`"^ (self#label ~no_:false s_name)^"`}\n" ) ] method latex_for_class_label fmt c = ps fmt (self#make_label (self#class_label c.cl_name)) method latex_for_class_type_label fmt ct = ps fmt (self#make_label (self#class_type_label ct.clt_name)) (** Print the LaTeX code for the given module. *) method latex_of_module fmt m = let father = Name.father m.m_name in let t = [ Latex "\\begin{ocamldoccode}\n" ; Code "module "; Code (Name.simple m.m_name); Code " : "; ] in self#latex_of_text fmt t; self#latex_of_text fmt [ Latex "\\end{ocamldoccode}\n" ]; self#latex_for_module_label fmt m; self#latex_for_module_index fmt m; p fmt "@["; self#latex_of_module_kind fmt father m.m_kind; ( match Module.module_is_functor m with false -> () | true -> self#latex_of_text fmt [Newline]; ( match List.filter (fun (_,d) -> d <> None) (module_parameters ~trans: false m) with [] -> () | l -> let t = [ Bold [Raw "Parameters: "]; List (List.map (fun (p,text_opt) -> let t = match text_opt with None -> [] | Some t -> t in ( Raw p.mp_name :: Raw ": " :: t) ) l ) ] in self#latex_of_text fmt t ); ); self#latex_of_text fmt [Newline]; self#latex_of_info fmt ~block: true m.m_info; p fmt "@]"; (** Print the LaTeX code for the given module type. *) method latex_of_module_type fmt mt = let father = Name.father mt.mt_name in let t = [ Latex "\\begin{ocamldoccode}\n" ; Code "module type " ; Code (Name.simple mt.mt_name); ] in self#latex_of_text fmt t; ( match mt.mt_type, mt.mt_kind with | Some mtyp, Some kind -> self#latex_of_text fmt [ Code " = " ]; self#latex_of_text fmt [ Latex "\\end{ocamldoccode}\n" ]; self#latex_for_module_type_label fmt mt; self#latex_for_module_type_index fmt mt; p fmt "@["; self#latex_of_module_type_kind fmt father kind | _ -> self#latex_of_text fmt [ Latex "\\end{ocamldoccode}\n" ]; self#latex_for_module_type_index fmt mt; p fmt "@["; ); ( match Module.module_type_is_functor mt with false -> () | true -> self#latex_of_text fmt [Newline]; ( match List.filter (fun (_,d) -> d <> None) (module_type_parameters ~trans: false mt) with [] -> () | l -> let t = [ Bold [Raw "Parameters: "]; List (List.map (fun (p,text_opt) -> let t = match text_opt with None -> [] | Some t -> t in ( Raw p.mp_name :: Raw ": " :: t) ) l ) ] in self#latex_of_text fmt t ); ); self#latex_of_text fmt [Newline]; self#latex_of_info fmt ~block: true mt.mt_info; p fmt "@]"; (** Print the LaTeX code for the given included module. *) method latex_of_included_module fmt im = self#latex_of_text fmt ((Code "include ") :: (Code (match im.im_module with None -> im.im_name | Some (Mod m) -> m.m_name | Some (Modtype mt) -> mt.mt_name) ) :: (self#text_of_info im.im_info) ) (** Print the LaTeX code for the given class. *) method latex_of_class fmt c = Odoc_info.reset_type_names () ; let father = Name.father c.cl_name in let type_params = match c.cl_type_parameters with [] -> "" | l -> (self#normal_class_type_param_list father l)^" " in let t = [ Latex "\\begin{ocamldoccode}\n" ; Code (Printf.sprintf "class %s%s%s : " (if c.cl_virtual then "virtual " else "") type_params (Name.simple c.cl_name) ) ] in self#latex_of_text fmt t; self#latex_of_class_parameter_list fmt father c; (* avoid a big gap if the kind is a consrt *) ( match c.cl_kind with Class.Class_constr _ -> self#latex_of_class_kind fmt father c.cl_kind | _ -> () ); self#latex_of_text fmt [ Latex "\\end{ocamldoccode}\n" ]; self#latex_for_class_label fmt c; self#latex_for_class_index fmt c; p fmt "@["; (match c.cl_kind with Class.Class_constr _ -> () | _ -> self#latex_of_class_kind fmt father c.cl_kind ); self#latex_of_text fmt [Newline]; self#latex_of_info fmt ~block: true c.cl_info; p fmt "@]" (** Print the LaTeX code for the given class type. *) method latex_of_class_type fmt ct = Odoc_info.reset_type_names () ; let father = Name.father ct.clt_name in let type_params = match ct.clt_type_parameters with [] -> "" | l -> (self#normal_class_type_param_list father l)^" " in let t = [ Latex "\\begin{ocamldoccode}\n" ; Code (Printf.sprintf "class type %s%s%s = " (if ct.clt_virtual then "virtual " else "") type_params (Name.simple ct.clt_name) ) ] in self#latex_of_text fmt t; self#latex_of_text fmt [ Latex "\\end{ocamldoccode}\n" ]; self#latex_for_class_type_label fmt ct; self#latex_for_class_type_index fmt ct; p fmt "@["; self#latex_of_class_type_kind fmt father ct.clt_kind; self#latex_of_text fmt [Newline]; self#latex_of_info fmt ~block: true ct.clt_info; p fmt "@]" (** Print the LaTeX code for the given class element. *) method latex_of_class_element fmt class_name class_ele = self#latex_of_text fmt [Newline]; match class_ele with Class_attribute att -> self#latex_of_attribute fmt att | Class_method met -> self#latex_of_method fmt met | Class_comment t -> match t with | [] -> () | (Title (_,_,_)) :: _ -> self#latex_of_text fmt t | _ -> self#latex_of_text fmt [ Title ((Name.depth class_name) + 2, None, t) ] (** Print the LaTeX code for the given module element. *) method latex_of_module_element fmt module_name module_ele = self#latex_of_text fmt [Newline]; match module_ele with Element_module m -> self#latex_of_module fmt m | Element_module_type mt -> self#latex_of_module_type fmt mt | Element_included_module im -> self#latex_of_included_module fmt im | Element_class c -> self#latex_of_class fmt c | Element_class_type ct -> self#latex_of_class_type fmt ct | Element_value v -> self#latex_of_value fmt v | Element_exception e -> self#latex_of_exception fmt e | Element_type t -> self#latex_of_type fmt t | Element_module_comment t -> self#latex_of_text fmt t (** Generate the LaTeX code for the given list of inherited classes.*) method generate_inheritance_info fmt inher_l = let f inh = match inh.ic_class with None -> (* we can't make the reference *) Newline :: Code ("inherit "^inh.ic_name) :: (match inh.ic_text with None -> [] | Some t -> Newline :: t ) | Some cct -> let label = match cct with Cl _ -> self#class_label inh.ic_name | Cltype _ -> self#class_type_label inh.ic_name in (* we can create the reference *) Newline :: Odoc_info.Code ("inherit "^inh.ic_name) :: (Odoc_info.Latex (" ["^(self#make_ref label)^"]")) :: (match inh.ic_text with None -> [] | Some t -> Newline :: t ) in List.iter (self#latex_of_text fmt) (List.map f inher_l) (** Generate the LaTeX code for the inherited classes of the given class. *) method generate_class_inheritance_info fmt cl = let rec iter_kind k = match k with Class_structure ([], _) -> () | Class_structure (l, _) -> self#generate_inheritance_info fmt l | Class_constraint (k, _) -> iter_kind k | Class_apply _ | Class_constr _ -> () in iter_kind cl.cl_kind (** Generate the LaTeX code for the inherited classes of the given class type. *) method generate_class_type_inheritance_info fmt clt = match clt.clt_kind with Class_signature ([], _) -> () | Class_signature (l, _) -> self#generate_inheritance_info fmt l | Class_type _ -> () (** Generate the LaTeX code for the given top module, in the given buffer. *) method generate_for_top_module fmt m = let (first_t, rest_t) = self#first_and_rest_of_info m.m_info in let text = if m.m_text_only then [ Title (1, None, [Raw m.m_name] @ (match first_t with [] -> [] | t -> (Raw " : ") :: t) ) ; ] else [ Title (1, None, [ Raw (Odoc_messages.modul^" ") ; Code m.m_name ] @ (match first_t with [] -> [] | t -> (Raw " : ") :: t)) ; ] in self#latex_of_text fmt text; self#latex_for_module_label fmt m; self#latex_for_module_index fmt m; self#latex_of_text fmt rest_t ; self#latex_of_text fmt [ Newline ] ; if not m.m_text_only then ps fmt "\\ocamldocvspace{0.5cm}\n\n"; List.iter (fun ele -> self#latex_of_module_element fmt m.m_name ele; ps fmt "\n\n" ) (Module.module_elements ~trans: false m) (** Print the header of the TeX document. *) method latex_header fmt module_list = ps fmt "\\documentclass[11pt]{article} \n"; ps fmt "\\usepackage[latin1]{inputenc} \n"; ps fmt "\\usepackage[T1]{fontenc} \n"; ps fmt "\\usepackage{fullpage} \n"; ps fmt "\\usepackage{url} \n"; ps fmt "\\usepackage{ocamldoc}\n"; ( match !Global.title with None -> () | Some s -> ps fmt "\\title{"; ps fmt (self#escape s); ps fmt "}\n" ); ps fmt "\\begin{document}\n"; (match !Global.title with None -> () | Some _ -> ps fmt "\\maketitle\n" ); if !Global.with_toc then ps fmt "\\tableofcontents\n"; ( let info = Odoc_info.apply_opt (Odoc_info.info_of_comment_file module_list) !Odoc_info.Global.intro_file in (match info with None -> () | Some _ -> ps fmt "\\vspace{0.2cm}"); self#latex_of_info fmt info; (match info with None -> () | Some _ -> ps fmt "\n\n") ) (** Generate the LaTeX style file, if it does not exists. *) method generate_style_file = try let dir = Filename.dirname !Global.out_file in let file = Filename.concat dir "ocamldoc.sty" in if Sys.file_exists file then Odoc_info.verbose (Odoc_messages.file_exists_dont_generate file) else ( let chanout = open_out file in output_string chanout Odoc_latex_style.content ; flush chanout ; close_out chanout; Odoc_info.verbose (Odoc_messages.file_generated file) ) with Sys_error s -> prerr_endline s ; incr Odoc_info.errors ; (** Generate the LaTeX file from a module list, in the {!Odoc_info.Global.out_file} file. *) method generate module_list = self#generate_style_file ; let main_file = !Global.out_file in let dir = Filename.dirname main_file in if !separate_files then ( let f m = try let chanout = open_out ((Filename.concat dir (Name.simple m.m_name))^".tex") in let fmt = Format.formatter_of_out_channel chanout in self#generate_for_top_module fmt m ; Format.pp_print_flush fmt (); close_out chanout with Failure s | Sys_error s -> prerr_endline s ; incr Odoc_info.errors in List.iter f module_list ); try let chanout = open_out main_file in let fmt = Format.formatter_of_out_channel chanout in if !Global.with_header then self#latex_header fmt module_list; List.iter (fun m -> if !separate_files then ps fmt ("\\input{"^((Name.simple m.m_name))^".tex}\n") else self#generate_for_top_module fmt m ) module_list ; if !Global.with_trailer then ps fmt "\\end{document}"; Format.pp_print_flush fmt (); close_out chanout with Failure s | Sys_error s -> prerr_endline s ; incr Odoc_info.errors end end module type Latex_generator = module type of Generator