I've attached a patch that modifies how the latex version of the api docs is
generated. I've uploaded the api document as it's generated with this patch
applied to [1]. A short description of the changes:
- use a latex style for the class descriptions
- use a proper pretty printer for the output
diffstat says:
b/ocaml/idl/xenclass.sty | 127 ++++++++++++++++++++++++++
ocaml/idl/OMakefile | 4
ocaml/idl/latex_backend.ml | 193 +++++++++++++++++++----------------------
ocaml/idl/xenenterpriseapi.tex | 1
4 files changed, 222 insertions(+), 103 deletions(-)
The changes make use of prettier[2].
There are further improvements possible, but first I'd like to get some
feedback on whether this is considered an improvement or not. :-)
Cheers,
M
[1] http://dl.dropbox.com/u/187401/xenenterpriseapi-prettier.pdf
[2] https://github.com/magthe/prettier
--
Magnus Therning [email protected]
XenServer Security Lead
There does not now, nor will there ever, exist a programming language
in which it is the least bit hard to write bad programs.
-- Flon's Axiom
Most software today is very much like an Egyptian pyramid with
millions of bricks piled on top of each other, with no structural
integrity, but just done by brute force and thousands of slaves.
-- Alan Kay
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{\xapicl...@name}{}
+\newcommand{\xapicl...@description}{}
+\newenvironment{xapiclass}[2]{%
+ \renewcommand{\xapicl...@name}{#1}%
+ \renewcommand{\xapicl...@description}{#2}%
+ \newpage \section{Class: \xapicl...@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: \xapicl...@name }%
+ \begin{longtable}{|lllp{0.38\textwidth}|}%
+ \hline%
+ \multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf \xapicl...@name } \\%
+ \multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em
\xapicl...@description }} \\%
+ \hline %
+ \multicolumn{4}{|c|}{ \bf Class \xapicl...@name~has no fields. } \\%
+ \hline \end{longtable}%
+ }
+
+\newenvironment{xapiclassfields}{%
+ \subsection{Fields for class: \xapicl...@name }%
+ \begin{longtable}{|lllp{0.38\textwidth}|}%
+ \hline%
+ \multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf \xapicl...@name } \\%
+ \multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em
\xapicl...@description }} \\%
+ \hline%
+ Quals & Field & Type & Description \\%
+ \hline%
+ }{ \hline \end{longtable} }
+
+\newenvironment{xapiclassmethods}{%
+ \subsection{RPCs associated with class: \xapicl...@name}%
+ }{}
+
+%%%%%%%%%%%%%%%%%%%%%%%%% Xapi Class Method Environment
%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\newcommand{\xapimet...@name}{}
+\newcommand{\xapimet...@returntype}{}
+\newcommand{\xapimet...@returndesc}{}
+\newcommand{\xapimethret}[2]{%
+ \renewcommand{\xapimet...@returntype}{#1}
\renewcommand{\xapimet...@returndesc}{#2}%
+ }
+\newtoks{\xapimet...@argtoks}
+\newboolean{xapimet...@args}
+\newcommand{\xapimet...@comma}{}
+\newcommand{\xapimetharg}[3]{%
+ \setboolean{xapimet...@args}{true}%
+ \xapimet...@argtoks=\expandafter{\the\xapimethod@argtoks
\xapimet...@argshow{#1}{#2}{#3}}%
+ }
+\newcommand{\xapimethargig}[2]{%
+ \xapimet...@argtoks=\expandafter{\the\xapimethod@argtoks
\xapimet...@argshowig{#1}{#2}{}}%
+ }
+\newtoks{\xapimet...@errortoks}
+\newboolean{xapimet...@errors}
+\newcommand{\xapimetherr}[1]{%
+ \setboolean{xapimet...@errors}{true}%
+ \xapimet...@errortoks=\expandafter{\the\xapimethod@errortoks
\xapimet...@errorshow{#1}}%
+ }
+\newenvironment{xapimethod}[2]{%
+ \renewcommand{\xapimet...@name}{#1}%
+ \xapimet...@argtoks={}%
+ \setboolean{xapimet...@args}{false}%
+ \xapimet...@errortoks={}%
+ \setboolean{xapimet...@errors}{false}%
+ \subsubsection{RPC name: #1}%
+ {\bf Overview:} \linebreak #2%
+ }{%
+ \let\xapimet...@comma=\empty%
+ \let\xapimet...@argshow=\xapimethod@argshowcommaseparated%
+ \let\xapimet...@argshowig=\xapimethod@argshowcommaseparated%
+ %
+ \par\vspace{3mm}\noindent \textbf{Signature:} \linebreak%
+ \texttt{(\xapimet...@returntype) \xapimet...@name~(}%
+ \the\xapimet...@argtoks%
+ \texttt{)}%
+ %
+ \ifthenelse{\boolean{xapimet...@args}}{%
+ \par\vspace{3mm}\noindent \textbf{Arguments:} \linebreak%
+ \let\xapimet...@argshow=\xapimethod@argshowtabular%
+ \let\xapimet...@argshowig=\xapimethod@argshowtabularig%
+ \begin{tabular}{|c|c|p{7cm}|}%
+ \hline%
+ {\bf type} & {\bf name} & {\bf description} \\ \hline%
+ \the\xapimet...@argtoks%
+ \end{tabular}%
+ }{}
+ %
+ \par\vspace{3mm}\noindent\textbf{Return Type:}
\texttt{\xapimet...@returntype}\par\xapimethod@returndesc%
+ %
+ \ifthenelse{\boolean{xapimet...@errors}}{%
+ \let\xapimet...@comma=\empty%
+ \let\xapimet...@errorshow=\xapimethod@errorshowcommaseparated%
+ \par\noindent\textbf{Possible Error Codes:} %
+ \the\xapimet...@errortoks%
+ }{}%
+ }
+
+\newcommand{\xapimet...@argshowcommaseparated}[3]{%
+ \xapimet...@comma%
+ \texttt{#1 #2}%
+ \def\xapimet...@comma{, }%
+ }
+
+\newcommand{\xapimet...@argshowtabular}[3]{%
+ \texttt{#1} & #2 & #3 \\ \hline%
+ }
+\newcommand{\xapimet...@argshowtabularig}[3]{}
+
+\newcommand{\xapimet...@errorshowcommaseparated}[1]{%
+ \texttt{\xapimet...@comma #1}%
+ \def\xapimet...@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}
_______________________________________________
xen-api mailing list
[email protected]
http://lists.xensource.com/mailman/listinfo/xen-api