Prettier latex output. diff -r dd7e1f8d25ff ocaml/idl/OMakefile --- a/ocaml/idl/OMakefile +++ b/ocaml/idl/OMakefile @@ -6,7 +6,7 @@ PSTOPDF = $(shell bash -c "which pstopdf || which ps2pdf || which ps2pdf14 || echo false") OCAMLINCLUDES = ocaml_backend ../database -OCAMLPACKS = xml-light2 sexpr log +OCAMLPACKS = xml-light2 sexpr log prettier CAMLP4_FILES = datamodel_types @@ -29,7 +29,7 @@ SHARED_EPS = vm_lifecycle.eps OPEN_TEX = xenapi.tex xenapi-coversheet.tex xenapi-datamodel.tex OPEN_EPS = xenapi-datamodel-graph.eps xen.eps -CLOSED_TEX = xenenterpriseapi.tex xenenterpriseapi-coversheet.tex xenenterpriseapi-datamodel.tex +CLOSED_TEX = xenenterpriseapi.tex xenenterpriseapi-coversheet.tex xenenterpriseapi-datamodel.tex xenclass.sty CLOSED_EPS = xenenterpriseapi-datamodel-graph.eps citrix_logo_black.eps DOCDIR = $(ROOT)/ocaml/autogen/doc diff -r dd7e1f8d25ff ocaml/idl/latex_backend.ml --- a/ocaml/idl/latex_backend.ml +++ b/ocaml/idl/latex_backend.ml @@ -19,6 +19,7 @@ open Dm_api open Stringext +open Prettier let rec formatted_wrap formatter s = let split_in_2 c s = @@ -111,6 +112,20 @@ | Ref obj -> (escape obj)^" ref" | Record obj -> escape obj ^ " record" +let rec ty_2_doc = function + | String -> text "string" + | Int -> text "int" + | Float -> text "float" + | Bool -> text "bool" + | DateTime -> text "datetime" + | Enum (n, _) -> text (escape n) + | Set i -> if (is_prim_type i) + then (ty_2_doc i) <|> text " Set" + else text "(" <|> (ty_2_doc i) <|> text ") Set" + | Map (a, b) -> text "(" <|> (ty_2_doc a) <|> text " $\\rightarrow$ " <|> (ty_2_doc b) <|> text ") Map" + | Ref o -> text (escape o) <|> text " ref" + | Record o -> text (escape o) <|> text " record" + let of_ty_opt = function None -> "void" | Some(ty, _) -> of_ty ty @@ -189,87 +204,6 @@ escape p.param_name; "&"; escape p.param_doc; "\\\\ \\hline"; "\n"] -let mk_latex_error err = - sprintf "{\\tt %s}" (escape err.err_name) - -let space = "\\vspace{0.3cm}" - -(* Make a latex section for an API-specified message *) -let latex_section_of_message closed section_prefix x = - String.concat "\n" - ([ - String.concat "" ["\\"^section_prefix^"subsection{RPC name:~"; escape x.msg_name; "}\n"]; - "{\\bf Overview:} "; - if x.msg_release.internal_deprecated_since <> None - then "{\\bf This message is deprecated}" - else ""; - wrap (full_stop (escape x.msg_doc)); - " \\noindent {\\bf Signature:} "; - - let section_contents = - (String.concat " " - [if is_prim_opt_type x.msg_result then of_ty_opt_verbatim x.msg_result - else "("^(of_ty_opt_verbatim x.msg_result)^")"; - x.msg_name; - String.concat "" - [ - "("; - String.concat ", " - ((if x.msg_session then ["session_id s"] else []) @ - (List.map (fun p -> of_ty_verbatim p.param_type ^ " " ^ p.param_name) x.msg_params)); - ")" - ] - ]) in - String.concat "" - (if closed then - ["\n\n{\\parbox{ \\columnwidth }{\\tt ~~~~~~~"; - escape section_contents; - "}}\n\n"] - else - ["\\begin{verbatim} "; - section_contents; - "\\end{verbatim}\n\n"]) - ] @ - - (if x.msg_params=[] then [] - else - [ - "\\noindent{\\bf Arguments:}\n\n "; - space; - - "\\begin{tabular}{|c|c|p{7cm}|}\n \\hline"; - "{\\bf type} & {\\bf name} & {\\bf description} \\\\ \\hline"; - String.concat "\n" ((List.map mk_latex_param) x.msg_params); - "\\end{tabular}\n"; - ]) @ - - [ - space; - "\n \\noindent {\\bf Return Type:} "; - "{\\tt "; - of_ty_opt x.msg_result; "}\n\n"; - escape (desc_of_ty_opt x.msg_result); - space - ] @ - - (if x.msg_errors=[] then [space; space] - else - [ - ""; - wrap (sprintf "\\noindent{\\bf Possible Error Codes:} %s" - (String.concat ", " ((List.map mk_latex_error) - x.msg_errors))); - "\\vspace{0.6cm}" - ])) - -(* Make a load of sections for a list of functions, fb. - if section_prefix="" then we make subsections for each function. - if section_prefix="sub" then we make subsubsections for each function. *) - -let latex_of_funblock closed section_prefix fb = - String.concat "\n" (List.map (latex_section_of_message closed section_prefix) fb) - - (** * The header for the table containing the fields of the given class. This * table has an additional column if closed is true. @@ -315,24 +249,6 @@ else (class_header x closed) @ field_tex @ class_footer) -let of_obj x closed = - [ - "\\newpage"; - "\\section{Class: "^(escape x.name)^"}" ] - @ (field_table_of_obj false x closed) - @ - [ - "\\subsection{RPCs associated with class: "^(escape x.name)^"}" - ] - @ - (if x.messages=[] then - ["\n\n"; - "{\\bf Class "^(escape x.name)^" has no additional RPCs associated with it.}"] - else - [ - latex_of_funblock closed "sub" x.messages - ]) - let error_signature name params = if params = [] then " @@ -440,6 +356,81 @@ let first_sentence s = List.hd (String.split '.' s) + +let build_class_section system = + let build_fields c = + match c.contents with + | [] -> line <|> text "\\noxapifields" + | _ -> + let build_one i = match i with + | Namespace _ -> nil (* ignore namespaces *) + | Field f -> + let field_qual = match f.qualifier with + | RW -> "\\RW" + | DynamicRO -> "\\ROrun" + | StaticRO -> "\\ROins" + in + text (sprintf "\\xapifield{%s}{%s}{" field_qual (escape f.field_name)) <|> + ty_2_doc f.ty <|> + text (sprintf "}{%s}" (escape f.field_description)) + in + let all_fields = List.fold_right + (fun d r -> line <|> d <|> r) + (List.map build_one c.contents) + nil + in + line <|> text "\\begin{xapiclassfields}" <|> + nest 4 all_fields <|> + line <|> text "\\end{xapiclassfields}" + in + let build_methods c = + let build_one m = + text (sprintf "%% method: %s" (escape m.msg_name)); + let b = text (sprintf "\\begin{xapimethod}{%s}{%s}" (escape m.msg_name) (escape m.msg_doc)) in + let e = text "\\end{xapimethod}" in + let r = + let ret_ty, ret_doc = match m.msg_result with + | None -> text "void", "" + | Some (t, d) -> ty_2_doc t, d + in + text "\\xapimethret{" <|> ret_ty <|> text (sprintf "}{%s}" (escape ret_doc)) + in + let s = if m.msg_session + then line <|> text "\\xapimethargig{session\\_id}{s}" + else nil + in + let arg p = text "\\xapimetharg{" <|> ty_2_doc p.param_type <|> text (sprintf "}{%s}{%s}" (escape p.param_name) (escape p.param_doc)) in + let all_args = List.fold_right + (fun d r -> line <|> d <|> r) + (List.map arg m.msg_params) + nil + in + let all_errs = match m.msg_errors with + | [] -> nil + | _ -> List.fold_right + (fun e r -> line <|> text (sprintf "\\xapimetherr{%s}" (escape e.err_name)) <|> r) + m.msg_errors + nil + in + b <|> nest 4 (line <|> r <|> s <|> all_args <|> all_errs) <|> line <|> e + in + let all_methods = List.fold_right + (fun d r -> line <|> d <|> r) + (List.map build_one c.messages) + nil + in + line <|> text "\\begin{xapiclassmethods}" <|> + nest 4 all_methods <|> + line <|> text "\\end{xapiclassmethods}" + in + let build_class c = + line <|> text (sprintf "\\begin{xapiclass}{%s}{%s}" (escape c.name) (escape c.description)) <|> + nest 4 (build_fields c) <|> + nest 4 (build_methods c) <|> + line <|> text "\\end{xapiclass}" + in + let all_parts = List.map build_class system in + List.fold_right (fun d r -> line <|> d <|> r) all_parts nil let all api closed = (* Remove private messages that are only used internally (e.g. get_record_internal) *) @@ -554,8 +545,8 @@ print_string vgap) system; error_section() end; - List.iter (fun x -> List.iter print_endline (of_obj x closed); - print_string vgap) system; + (* List.iter (fun x -> List.iter print_endline (of_obj x closed); print_string vgap) system; *) + print_endline (layout (build_class_section system)); if not closed then begin error_section() diff -r dd7e1f8d25ff ocaml/idl/xenclass.sty --- /dev/null +++ b/ocaml/idl/xenclass.sty @@ -0,0 +1,127 @@ +%NAME: xenclass.sty + +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{xenclass}[2010/02/19] +\RequirePackage{ifthen} + +%%%%%%%%%%%%%%%%%%%%%%%%% Xapi Class Environment %%%%%%%%%%%%%%%%%%%%%%%%% + +\newcommand{\xapiclass@name}{} +\newcommand{\xapiclass@description}{} +\newenvironment{xapiclass}[2]{% + \renewcommand{\xapiclass@name}{#1}% + \renewcommand{\xapiclass@description}{#2}% + \newpage \section{Class: \xapiclass@name}% + } {} + +%%%%%%%%%%%%%%%%%%%%%%%%% Xapi Class Field Environment %%%%%%%%%%%%%%%%%%%%%%%%% + +\newcommand{\ROrun}{\ensuremath{\mathit{RO}_\mathit{run}}} +\newcommand{\ROins}{\ensuremath{\mathit{RO}_\mathit{ins}}} +\newcommand{\RW}{\ensuremath{\mathit{RW}}} + +\newcommand{\xapifield}[4]{ #1 & { \tt #2 } & #3 & #4 \\ } +\newcommand{\noxapifields}{% + \subsection{Fields for class: \xapiclass@name }% + \begin{longtable}{|lllp{0.38\textwidth}|}% + \hline% + \multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf \xapiclass@name } \\% + \multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em \xapiclass@description }} \\% + \hline % + \multicolumn{4}{|c|}{ \bf Class \xapiclass@name~has no fields. } \\% + \hline \end{longtable}% + } + +\newenvironment{xapiclassfields}{% + \subsection{Fields for class: \xapiclass@name }% + \begin{longtable}{|lllp{0.38\textwidth}|}% + \hline% + \multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf \xapiclass@name } \\% + \multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em \xapiclass@description }} \\% + \hline% + Quals & Field & Type & Description \\% + \hline% + }{ \hline \end{longtable} } + +\newenvironment{xapiclassmethods}{% + \subsection{RPCs associated with class: \xapiclass@name}% + }{} + +%%%%%%%%%%%%%%%%%%%%%%%%% Xapi Class Method Environment %%%%%%%%%%%%%%%%%%%%%%%%% + +\newcommand{\xapimethod@name}{} +\newcommand{\xapimethod@returntype}{} +\newcommand{\xapimethod@returndesc}{} +\newcommand{\xapimethret}[2]{% + \renewcommand{\xapimethod@returntype}{#1} \renewcommand{\xapimethod@returndesc}{#2}% + } +\newtoks{\xapimethod@argtoks} +\newboolean{xapimethod@args} +\newcommand{\xapimethod@comma}{} +\newcommand{\xapimetharg}[3]{% + \setboolean{xapimethod@args}{true}% + \xapimethod@argtoks=\expandafter{\the\xapimethod@argtoks \xapimethod@argshow{#1}{#2}{#3}}% + } +\newcommand{\xapimethargig}[2]{% + \xapimethod@argtoks=\expandafter{\the\xapimethod@argtoks \xapimethod@argshowig{#1}{#2}{}}% + } +\newtoks{\xapimethod@errortoks} +\newboolean{xapimethod@errors} +\newcommand{\xapimetherr}[1]{% + \setboolean{xapimethod@errors}{true}% + \xapimethod@errortoks=\expandafter{\the\xapimethod@errortoks \xapimethod@errorshow{#1}}% + } +\newenvironment{xapimethod}[2]{% + \renewcommand{\xapimethod@name}{#1}% + \xapimethod@argtoks={}% + \setboolean{xapimethod@args}{false}% + \xapimethod@errortoks={}% + \setboolean{xapimethod@errors}{false}% + \subsubsection{RPC name: #1}% + {\bf Overview:} \linebreak #2% + }{% + \let\xapimethod@comma=\empty% + \let\xapimethod@argshow=\xapimethod@argshowcommaseparated% + \let\xapimethod@argshowig=\xapimethod@argshowcommaseparated% + % + \par\vspace{3mm}\noindent \textbf{Signature:} \linebreak% + \texttt{(\xapimethod@returntype) \xapimethod@name~(}% + \the\xapimethod@argtoks% + \texttt{)}% + % + \ifthenelse{\boolean{xapimethod@args}}{% + \par\vspace{3mm}\noindent \textbf{Arguments:} \linebreak% + \let\xapimethod@argshow=\xapimethod@argshowtabular% + \let\xapimethod@argshowig=\xapimethod@argshowtabularig% + \begin{tabular}{|c|c|p{7cm}|}% + \hline% + {\bf type} & {\bf name} & {\bf description} \\ \hline% + \the\xapimethod@argtoks% + \end{tabular}% + }{} + % + \par\vspace{3mm}\noindent\textbf{Return Type:} \texttt{\xapimethod@returntype}\par\xapimethod@returndesc% + % + \ifthenelse{\boolean{xapimethod@errors}}{% + \let\xapimethod@comma=\empty% + \let\xapimethod@errorshow=\xapimethod@errorshowcommaseparated% + \par\noindent\textbf{Possible Error Codes:} % + \the\xapimethod@errortoks% + }{}% + } + +\newcommand{\xapimethod@argshowcommaseparated}[3]{% + \xapimethod@comma% + \texttt{#1 #2}% + \def\xapimethod@comma{, }% + } + +\newcommand{\xapimethod@argshowtabular}[3]{% + \texttt{#1} & #2 & #3 \\ \hline% + } +\newcommand{\xapimethod@argshowtabularig}[3]{} + +\newcommand{\xapimethod@errorshowcommaseparated}[1]{% + \texttt{\xapimethod@comma #1}% + \def\xapimethod@comma{, }% + } diff -r dd7e1f8d25ff ocaml/idl/xenenterpriseapi.tex --- a/ocaml/idl/xenenterpriseapi.tex +++ b/ocaml/idl/xenenterpriseapi.tex @@ -12,6 +12,7 @@ \usepackage{graphics} \usepackage{longtable} \usepackage{fancyhdr} +\usepackage{xenclass} \pagestyle{fancy} \setlength\topskip{0cm}