diff --git a/.classpath b/.classpath index e034f20..cc36a5e 100644 --- a/.classpath +++ b/.classpath @@ -2,6 +2,6 @@ - + diff --git a/.gitignore b/.gitignore index c0f3701..d84582c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ bin release +.settings diff --git a/README.markdown b/README.markdown index 086a1e8..2dfc6f6 100644 --- a/README.markdown +++ b/README.markdown @@ -3,9 +3,21 @@ TexDoclet This is a javadoc doclet - a plugin for the [javadoc tool](http://java.sun.com/j2se/javadoc/). This doclet produces output suitable to be included into LaTeX documents. -This version is based on [TexDoclet](https://texdoclet.dev.java.net/) from Gregg Wonderly. -A lot of the code was rewritten and changed to support a separation from content -and layout. The sourcecode is also cleaner than the original. +This version is based on [TexDoclet](https://texdoclet.dev.java.net/) from Gregg Wonderly with the changes made and +applied to by [Matthias Braun](https://github.com/MatzeB). See his github project for details. + +My fork adapts the doclet to meet the requirements of our project [lambda-alligatoren](https://github.com/vincent23/lambda-alligatoren). +In detail, those are: +* @texignore tag support +* modify the original "preamble.tex" to become an "\\input"-able "docletcommands.tex" (thanks to [@vincent23](https://github.com/vincent23)) +* fix a surplus "}" in HTMLtoTex which broke ordered lists + +Build instructions +------------------ +* The ant Build.xml file provided does NOT run on its own. +* You will need to open the project in Eclipse +* You will probably have to update the path to "tools.jar" in the project's build path properties if you aren't on linux and/or using an SDK different to openjdk 7 +* You can build a self-contained doclet jar file by exporting the project as jar from eclipse Features -------- @@ -14,6 +26,18 @@ Features * Layout is defined by a set of macros outside the tool. This allows you to easily adapt to your own style/document without the need to touch the tools output. +* Classes not intended to be part of the generated tex document can be excluded with a dedicated "texignore" tag. +* Shows generalization and realizations ("extends" and "implements") +* Shows dimensions of types, like in "String[][]". +* Has doclet specific tex commands outsourced to allow easy integration into existing documents. + +Commandline Options +------------------- +* -output: Defines the output file path. Default is "docs.tex" +* -silent: If this option is specified, all usually unnecessary messages are muted. Error messages will be printed still. +* -see: Specifies the text to use for references created from inline tags. The default text is "see " +* -See: Specifies the text to use for references created from block tags. The default text is "See also ". +* -help: Prints a help text similar to this Usage ----- @@ -23,17 +47,17 @@ Usage javadoc -docletpath texdoclet.jar -doclet org.wonderly.doclets.TexDoclet my.cool.package - This should produce a file docs.tex + This should produce a file docs.tex. See "man javadoc" and the section above for additional command line arguments. -2. You may test the generated output by copying preamble.tex into the current - directory and compiling it with pdflatex (preamble.tex includes docs.tex) +2. You will need to also input "docletcommands.tex" to the preamble of your main document, otherwise + you will get a lot of errors due to missing commands. -3. Copy the definitions inside preamble.tex into the preamble of your own latex - document. Adapt the macros to your style and language needs. - Use \input{docs.tex} inside your document to include the generated - documentation. +3. \\Input the generated "docs.tex" (or the file with the name you specified via -output) at any place within + your document environment. +4. If you like headers, put \\pagestyle{myheadings} in front of the \\input command you just entered. + You can turn off the headers again by re-executing \\pagestyle{plain} or whichever pagestyle you were using before. -Author/Contact +Original Author/Contact -------------- Matthias Braun diff --git a/preamble.tex b/docletcommands.tex similarity index 66% rename from preamble.tex rename to docletcommands.tex index 01cda32..5e4e843 100644 --- a/preamble.tex +++ b/docletcommands.tex @@ -1,24 +1,6 @@ -% This is an example preamble for texdoclet generated output. -% Used like this it produces a standalone document. However it should be easy -% to copy these definitions into your own document and use \input{docs.tex} -% where you want your texdoc documentation. - -% The following is an example to put packagename and class into the page -% headings. -\documentclass[a4paper,11pt,parskip=half]{scrbook} - -% Make sure you use at least the following packages -\usepackage{color} -% The texdoclet output is in UTF-8. I strongly recommend writing the latex -% source in UTF-8 encoding anyway... -\usepackage[utf8]{inputenc} -\usepackage[T1]{fontenc} -\usepackage{lmodern} - -% The following packages are not striclty necessary to get texdoclet working -\usepackage{hyperref} - -\pagestyle{myheadings} +\usepackage{xparse}% for passing multiple arguments +\usepackage{needspace}% for preventing classe to begin within the lower 7cm of a page + % Initially we're not in a package or class \def\packagename{} \def\classname{} @@ -26,8 +8,8 @@ \markboth{\protect\packagename{} -- \protect\classname{}}{\protect\packagename{} -- \protect\classname{}} % --------------------------------------------------------------------------- -% TexDoc macros start - everything below this point should be copied to your -% own document and adapted to your style/language if needed +% TexDoc macros start - everything below this point can be +% adapted to your style/language if needed % --------------------------------------------------------------------------- % Environment used to simulate html

@@ -36,64 +18,79 @@ } % Environment for packages \newenvironment{texdocpackage}[1]{% - \newpage{}\gdef\packagename{#1}\chapter{Package \texttt{#1}} - \rule{\hsize}{.7mm} -}{} + \gdef\packagename{#1}\section{Package \texttt{#1}} + \rule{\hsize}{.7mm} +}{\newpage{}} % Environment for classes, interfaces % Argument 1: "class" or "interface" % Argument 2: the name of the class/interface -\newenvironment{texdocclass}[2]{% - \gdef\classname{#2} - \section{\texttt{#1 \textbf{#2}}} -}{\newpage{}} +% Argument 3 [opt.]: the name of the superclass +% Argument 4 [opt.]: the name of the realized interfaces +\NewDocumentEnvironment{texdocclass}{ m m o o }{% + \gdef\classname{#2} + \subsection[#2]{\texttt{#1 \textbf{#2} + \IfNoValueTF{#3} + {} + {% "extends" argument was given + % test, if the argument was empty or not + \ifx&% + \else + extends #3 + \fi + } + \IfNoValueTF{#4} + {} + {implements #4} + }} +}{\needspace{7cm}} % Environment for class description \newenvironment{texdocclassintro}{ - \subsection*{Description} + \subsubsection*{Description} }{ } % Environment around class fields \newenvironment{texdocclassfields}{% - \subsection*{Attributes} - \begin{itemize} + \subsubsection*{Attributes} + \begin{itemize} }{% - \end{itemize} + \end{itemize} } % Environment around class methods \newenvironment{texdocclassmethods}{% - \subsection*{Methods} - \begin{itemize} + \subsubsection*{Methods} + \begin{itemize} }{% - \end{itemize} + \end{itemize} } % Environment around class Constructors \newenvironment{texdocclassconstructors}{% - \subsection*{Constructors} - \begin{itemize} + \subsubsection*{Constructors} + \begin{itemize} }{% - \end{itemize} + \end{itemize} } % Environment around enum constants \newenvironment{texdocenums}{% - \subsection*{Enum Constants} - \begin{itemize} + \subsubsection*{Enum Constants} + \begin{itemize} }{% - \end{itemize} + \end{itemize} } % Environment around "See also"-Blocks (\texdocsee invocations) % Argument 1: Text preceding the references \newenvironment{texdocsees}[1]{ - - \textbf{#1:} - \begin{itemize} + + \textbf{#1:} + \begin{itemize} }{% - \end{itemize} + \end{itemize} } % Formats a single field % Argument 1: modifiers @@ -127,7 +124,7 @@ % Inserted when @inheritdoc is used % Argument 1: Class where the documentation was inherited from % Argument 2: Documentation -\newcommand{\texdocinheritdoc}[2]{#2 (\textit{documentation inherited from \texttt{#1})}} +\newcommand{\texdocinheritdoc}[2]{#2 \\(\textit{documentation inherited from \texttt{#1})}} % Formats a single see-BlockTag % Argument 1: text @@ -136,10 +133,10 @@ % Environment around \texdocparameter invocations \newenvironment{texdocparameters}{% - \minisec{Parameters} - \begin{tabular}{ll} + \minisec{Parameters} + \begin{tabular}{ll} }{% - \end{tabular} + \end{tabular} } % Environment around \texdocthrow invocations @@ -176,14 +173,3 @@ \relax\else {$($ in \ref{#1}, page \pageref{#1}$)$} \fi} - -% --------------------------------------------------------------------------- -% TexDoc macros end -% --------------------------------------------------------------------------- - -\begin{document} - - \tableofcontents - \input{docs.tex} - -\end{document} diff --git a/src/org/wonderly/doclets/HTMLToTex.java b/src/org/wonderly/doclets/HTMLToTex.java index de20257..1bc1754 100644 --- a/src/org/wonderly/doclets/HTMLToTex.java +++ b/src/org/wonderly/doclets/HTMLToTex.java @@ -6,7 +6,6 @@ import java.util.Properties; import java.util.Stack; -import com.sun.javadoc.ClassDoc; import com.sun.javadoc.MethodDoc; /** @@ -58,12 +57,9 @@ private HTMLToTex() { private String str; private int pos; private StringBuffer ret; - private String block = ""; private String refurl = ""; private String refimg = ""; - private boolean collectBlock; private int chapt = 0; - private int textdepth = 0; private int verbat = 0; private Stack tblstk = new Stack(); private Hashtable colors = new Hashtable(10); @@ -166,7 +162,6 @@ private String convertToTex(String input, MethodDoc md) { this.str = input; ret = new StringBuffer(); - ++textdepth; for (pos = 0; pos < str.length(); ++pos) { char c = str.charAt(pos); switch (c) { @@ -177,6 +172,9 @@ private String convertToTex(String input, MethodDoc md) { ret.append(' '); } break; + case '"': + ret.append("\"'"); + break; case '_': case '%': case '$': @@ -232,7 +230,7 @@ private String convertToTex(String input, MethodDoc md) { leave(""); } else if (startsWith("")) { ret.append("\\chapter{"); @@ -240,19 +238,19 @@ private String convertToTex(String input, MethodDoc md) { ret.append("}"); } else if (startsWith("")) { /* nothing */ } else if (startsWith("")) { /* nothing */ } else if (startsWith("")) { /* nothing */ @@ -330,7 +328,7 @@ private String convertToTex(String input, MethodDoc md) { } } else if (startsWith("")) { ret.append("\n\\end{itemize}\n"); } else if (match("")) { - ret.append("}\n\\end{enumerate}"); + ret.append("\n\\end{enumerate}"); } else if (startsWith(" + * Note: This version is even heavier modified by Lukas Böhm * * This class provides a Java 2, javadoc Doclet which generates a * LaTeX2e document out of the java classes that it is used on. @@ -40,6 +42,7 @@ * * @author Gregg Wonderly * @author Matthias Braun + * @author Lukas Böhm */ public class TexDoclet extends Doclet { /** Writer for writing to output file */ @@ -47,6 +50,8 @@ public class TexDoclet extends Doclet { private static String outfile = "docs.tex"; private static String refInlineName = "see "; private static String refBlockName = "See also"; + private static boolean silent = false; + private static String excludeTag = "@texignore"; /** * Returns how many arguments would be consumed if option is a @@ -56,33 +61,35 @@ public class TexDoclet extends Doclet { * the option to check */ public static int optionLength(String option) { - if (option.equals("-output")) + if (option.equals("-output") + || option.equals("-classfilter") + || option.equals("-see")) { return 2; - else if (option.equals("-classfilter")) - return 2; - else if (option.equals("-see")) - return 2; - else if (option.equals("-help")) { - System.err.println("TexDoclet Usage:"); - System.err.println("-output Specifies the output file to write to. If none"); - System.err.println(" specified, the default is docs.tex in the current"); - System.err.println(" directory."); - System.err.println("-see Specifies the text to use for references created from inline tags."); - System.err.println(" For german javadocs use \"siehe \" for example."); - System.err.println(" The default is \"see \"."); - System.err.println("-See Specifies the text to use for references created from block tags."); - System.err.println(" For german javadocs use \"Siehe auch\" for example."); - System.err.println(" The default is \"See also\"."); - + } + if (option.equals("-help")) { + System.out.println("TexDoclet Usage:"); + System.out.println("-output Specifies the output file to write to. If none"); + System.out.println(" specified, the default is docs.tex in the current"); + System.out.println(" directory."); + System.out.println("-see Specifies the text to use for references created from inline tags."); + System.out.println(" For german javadocs use \"siehe \" for example."); + System.out.println(" The default is \"see \"."); + System.out.println("-See Specifies the text to use for references created from block tags."); + System.out.println(" For german javadocs use \"Siehe auch\" for example."); + System.out.println(" The default is \"See also\"."); + System.out.println("-silent Have the doclet run in silent mode, i.e. all output will be suppressed, except warnings"); return 1; } - - System.out.println("unknown option " + option); + if (option.equals("-silent")) { + return 1; + } + System.err.println("unknown option: " + option); return Doclet.optionLength(option); } /** * Checks the passed options and their arguments for validity. + * Used to already configure the doclet according to the options passed. * * @param args * the arguments to check @@ -93,16 +100,27 @@ static public boolean validOptions(String[][] args, DocErrorReporter err) { for (int i = 0; i < args.length; ++i) { if (args[i][0].equals("-output")) { outfile = args[i][1]; - } else if (args[i][0].equals("-see")) { + continue; + } + if (args[i][0].equals("-see")) { refInlineName = args[i][1]; - } else if (args[i][0].equals("-See")) { + continue; + } + if (args[i][0].equals("-See")) { refBlockName = args[i][1]; + continue; + } + if (args[i][0].equals("-silent")) { + silent = true; + continue; } } return true; } - /** indicate that we can handle (most) 1.5 language features */ + /** + * indicate that we can handle (most) Java 1.5 language features + */ static public LanguageVersion languageVersion() { return LanguageVersion.JAVA_1_5; } @@ -114,9 +132,9 @@ static public LanguageVersion languageVersion() { * the root of the starting document */ public static boolean start(RootDoc root) { - System.out.println("TexDoclet 4.0, Copyright 2009 - Matthias Braun"); - System.out.println("based on TexDoclet v3.0, Copyright 2003 - Gregg Wonderly."); - System.out.println("http://texdoclet.dev.java.net - on the World Wide Web."); + println("TexDoclet 4.0, Copyright 2009 - Matthias Braun"); + println("based on TexDoclet v3.0, Copyright 2003 - Gregg Wonderly."); + println("http://texdoclet.dev.java.net - on the World Wide Web."); try { /* Open output file and force an UTF-8 encoding */ @@ -129,10 +147,15 @@ public static boolean start(RootDoc root) { ClassDoc[] classes = root.specifiedClasses(); PackageDoc[] packages = root.specifiedPackages(); + Arrays.sort(packages, new Comparator() { + public int compare(PackageDoc o1, PackageDoc o2) { + return o1.name().compareToIgnoreCase(o2.name()); + } + }); for (PackageDoc pkg : packages) { - System.out.println("* Package: " + pkg.name()); + println("* Package: " + pkg.name()); os.println("\\begin{texdocpackage}{" + HTMLToTex.convert(pkg.name()) + "}"); os.println("\\label{texdoclet:" + pkg.name() + "}"); @@ -166,10 +189,6 @@ private static void printComment(Tag t) { printComment(t.inlineTags(), null); } - private static void printComment(Tag t, MethodDoc md) { - printComment(t.inlineTags(), md); - } - private static void printComment(Tag[] tags, MethodDoc md) { for (Tag t : tags) { if (t instanceof SeeTag) { @@ -188,7 +207,7 @@ private static void printComment(Tag[] tags, MethodDoc md) { os.print(HTMLToTex.convert(t.text(), md)); } else { os.print("\\texdocinheritdoc{"); - os.print(overridden.containingClass().qualifiedName()); + os.print(overridden.containingClass().qualifiedName().replace(".", "\\-.")); os.print("}{"); printComment(overridden.inlineTags(), overridden); os.print("}"); @@ -231,6 +250,11 @@ public int compare(ClassDoc o1, ClassDoc o2) { } private static void printClass(ClassDoc cd) { + if (cd.tags(excludeTag).length > 0) { + return; + } + + // Determine type: class or interface String type; if (cd.isInterface()) { type = "interface"; @@ -239,10 +263,43 @@ private static void printClass(ClassDoc cd) { } else { type = "class"; } + + String modifiers = cd.modifiers(); + + String name = formatClassDoc(cd); + + // this string will hold the class' section heading + String classLine = "\\begin{texdocclass}" + // TODO hacky, uses same tex macro argument as type + + "{" + modifiers + " " + type + "}" + + "{" + texEscape(name) + "}"; + + // print "extends" fields + Type s = cd.superclassType(); + if (s != null + && !s.toString().equals("java.lang.Object") + && !cd.isEnum() + ) { + String generalization = s.toString(); + classLine += "[" + HTMLToTex.convert(generalization) + "]"; + } else if (!cd.isInterface()) { + // HACKY: if cd is an interface, omit the empty brackets for the "extends" field, for it is used for extended interfaces + classLine += "[]"; + } + + // print "implements" fields + Type[] itypes = cd.interfaceTypes(); + if (itypes.length > 0) { + String realizations = itypes[0].asClassDoc().toString(); + for (int i = 1; i < itypes.length; i++) { + ClassDoc ic = itypes[i].asClassDoc(); + realizations += ", " + ic.toString(); + } + classLine += "[" + HTMLToTex.convert(realizations) + "]"; + } - os.println("\\begin{texdocclass}{" + type + "}{" - + HTMLToTex.convert(cd.name()) + "}"); - + os.println(classLine); + os.println("\\label{texdoclet:" + cd.containingPackage().name() + "." + cd.name() + "}"); os.println("\\begin{texdocclassintro}"); printComment(cd); @@ -322,9 +379,9 @@ public int compare(FieldDoc o1, FieldDoc o2) { for (FieldDoc f : fields) { os.print("\\texdocfield"); - os.print("{" + HTMLToTex.convert(f.modifiers()) + "}"); - os.print("{" + HTMLToTex.convert(typeToString(f.type())) + "}"); - os.print("{" + HTMLToTex.convert(f.name()) + "}"); + os.print("{" + texEscape(f.modifiers()) + "}"); + os.print("{" + texEscape(typeToString(f.type())) + "}"); + os.print("{" + texEscape(f.name()) + "}"); os.print("{"); printComment(f); os.print("}"); @@ -382,7 +439,7 @@ public int compare(ExecutableMemberDoc o1, ExecutableMemberDoc o2) { os.print("{" + HTMLToTex.convert(member.modifiers()) + "}"); if (member instanceof MethodDoc) { MethodDoc methodDoc = (MethodDoc) member; - os.print("{" + HTMLToTex.convert(typeToString(methodDoc.returnType())) + "}"); + os.print("{" + texEscape(typeToString(methodDoc.returnType())) + "}"); } os.print("{" + HTMLToTex.convert(member.name()) + "}"); os.print("{" + HTMLToTex.convert(formatParameters(member)) + "}"); @@ -458,6 +515,48 @@ private static String formatParameters(ExecutableMemberDoc member) { return res.toString(); } + + /** + * Builds a string with the name and the parameter types of a given ClassDoc. + * + * @param cd the ClassDoc whoes name is to be formatted + * @return a String like "List" in case of a string list + */ + private static String formatClassDoc(ClassDoc cd) { + String name = cd.name(); + TypeVariable[] parameters = cd.typeParameters(); + if (parameters.length > 0) { + name += "<" + formatTypeVariable(parameters[0]); + for (int i = 1; i < parameters.length; i++) { + TypeVariable t = parameters[i]; + name += ", " + formatTypeVariable(t); + } + name +=">"; + } + + return name; + } + + /** + * Formats a given type variable an returns its string representation. + * E.g. "? extends String" for an anonymous TypeVariable that is derived from String + * + * @param t the type variable to be formatted + * @return the formatted string representation + */ + private static String formatTypeVariable(TypeVariable t) { + String result = t.typeName(); + + Type[] bounds = t.bounds(); + if (bounds.length > 0) { + result += " extends " + bounds[0].toString(); + for(int i = 1; i < bounds.length; i++) { + result += ", " + bounds[i].toString(); + } + } + + return result; + } /** * Converts a DocLet type back to java syntax @@ -475,6 +574,52 @@ private static String typeToString(Type type) { } else { tstring = type.typeName(); } + tstring += type.dimension(); + return tstring; } + + private static String texEscape(String s) { + StringBuilder ret = new StringBuilder(); + for(int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + switch (c) { + case '"': + ret.append("\"'"); + break; + case '_': + case '%': + case '$': + case '#': + ret.append('\\'); + ret.append((char) c); + break; + case '^': /* { */ + ret.append("$\\wedge$"); + break; + case '}': + ret.append("$\\}$"); + break; + case '{': + ret.append("$\\{$"); + break; + case '<': + ret.append("\\textless{}"); + break; + case '>': + ret.append("\\textgreater{}"); + break; + default: + ret.append((char) c); + break; + } + } + return ret.toString(); + } + + private static void println(String s) { + if (!silent) { + System.out.println(s); + } + } }