001package Torello.HTML.Tools.JavaDoc; 002 003import java.util.*; 004import java.io.*; 005import java.util.regex.*; 006 007import java.util.function.*; 008 009import Torello.HTML.*; 010import Torello.HTML.NodeSearch.*; 011import Torello.HTML.Tools.JavaDoc.*; 012import Torello.Java.*; 013 014import Torello.Java.Shell.C; 015 016/** 017 * <CODE>HiLiteConstructors - Documentation.</CODE><BR /><BR /> 018 * <EMBED CLASS="external-html" DATA-FILE-ID="HLCONST"> 019 */ 020@StaticFunctional 021public class HiLiteConstructors 022{ 023 private HiLiteConstructors() { } 024 025 private static final HTMLNode[] SURROUNDING_MESSAGE = HTMLPage 026 .getPageTokens( 027 "<DT><span class='" + Colorize.CSS_CLASS_FOR_CODE_METHOD_LABEL + "'>" + 028 "Code:</span></dt>\n" + 029 "<DD CLASS='" + Colorize.CSS_CLASS_FOR_CODE_METHOD_DEFINITION + "'>" + 030 "<B>Exact Constructor Body:</B><BR />\n", 031 false 032 ) 033 .stream() 034 .toArray(HTMLNode[]::new); 035 036 /** 037 * This method will hilite all {@code Constructor's} that are scraped from a Java Doc Generated 038 * HTML Documentation Page for a Class, Enumerated Type, or Interface. Hilited source-code for 039 * constructor-bodies (as {@code String's}) are inserted into the Java-Doc HTML Web-Page in the 040 * <B>{@code 'Constructor Details'}</B> section for any / all {@code Constructor's} found on 041 * the page.. 042 * 043 * @param pr This contains all of the needed parameters for this method, encapsulated into a 044 * single record-class. The list is somewhat lengthy, so this makes the code "look cleaner" 045 * 046 * @return This will return a count on exactly how many {@code Constructor's} have had their 047 * code-hilited {@code Constructor}-bodies inserted into the JavaDoc Documentation File for 048 * this class. 049 */ 050 public static int run(CommonParamRecord pr) 051 { 052 if (pr.sw != null) pr.sw.println 053 ("HiLiteConstructors.run(...) " + C.BRED + "[REQUESTED] " + C.RESET); 054 055 int countNumConstructorsHiLited = 0; 056 int numConstructorsSkipped = 0; 057 058 // ********** Check whether the fileVec has any Constructors in the first place ********** 059 if (Details.hasConstructorDetails(pr.fileVec) == null) 060 { 061 if (pr.sw != null) pr.sw.println( 062 "\tJavaDoc File: " + C.BYELLOW + pr.jdFileName + C.RESET + " does not have a " + 063 "Constructor-Details-Section, Skipping..." 064 ); 065 return 0; // no constructors to hilite, skip this file 066 } 067 // ********** Check whether the fileVec has any Constructors in the first place ********** 068 069 070 // ********** Iterate through every method found in the '.html' file ***************** 071 HNLIInclusive constructorsIter = Details.constructorDetailsIterator(pr.fileVec); 072 boolean firstIteration = true; 073 int cur = 0; 074 075 while (constructorsIter.hasNext()) 076 { 077 // Retrieves the next constructor-details section defined in the HTML file using the 078 // "Constructor Details Iterator" 079 DotPair constructorDP = constructorsIter.nextDotPair(); 080 081 // The instance of JavaDocHTMLFile (jdhf) was built using the same '.html' file, and 082 // the same iterator. Using the 'getConstructor(counter)' should retrieve the parsed 083 // version of this HTML-defined java constructor from the javadoc documentation HTML 084 // page. 085 Constructor fromHTMLFileConstructor = pr.jdhf.getConstructor(cur++); 086 087 // Now we need to search through all of the constructors in the JavaSourceCodeFile for 088 // a constructor with the EXACT SAME PARAMETER LIST. 089 Constructor fromSrcFileConstructor = (fromHTMLFileConstructor != null) 090 ? pr.jscf.findConstructor(fromHTMLFileConstructor) 091 : null; 092 093 // Since the instance of "Constructor" that is retrieved from the Source-Code '.java' 094 // file is guaranteed to have the "body text" filled out (as long as their was a body 095 // defined for that constructor, i.e. - it wasn't 'abstract') - we can get that string 096 // and save it and hilite it. 097 String constructorBodyStr = (fromSrcFileConstructor != null) 098 ? fromSrcFileConstructor.body 099 : null; 100 101 // Output a tab or else it will look "lopsided" 102 if (pr.sw != null) if (firstIteration) { firstIteration = false; pr.sw.print('\t'); } 103 104 // If there was no constructor body found ... skip to the next constructor. 105 if (constructorBodyStr == null) 106 { 107 if (pr.sw != null) 108 pr.sw.print 109 ("[NOT-FOUND]: " + C.BRED + fromHTMLFileConstructor.name + C.RESET + " "); 110 111 numConstructorsSkipped++; 112 continue; 113 } 114 115 // PRINT OUT THE CONSTRUCTOR 116 if (pr.sw != null) pr.sw.print(C.BGREEN + fromHTMLFileConstructor.name + C.RESET + " "); 117 118 119 // ********** Compute the Insertion Point ***************** 120 // The "<DL> <DT></DT><DD></DD> </DL>" lists are for the throws, see-also, returns, 121 // etc.... The Code HiLited Constructor-Body HTML needs to be inserted into its own: 122 // <DT>Code:</DT>\n 123 // <DD> Hi-Lited Constructor-Body DIV created by HiLite.ME Server</DD> 124 // 125 // The Insertion point shall be right before the closing </DL> HTML Element. This 126 // means HiLited Code will *always* be the last 'thing' (for lack of a technical 127 // term) that you can see in a Constructor-Details Section. 128 // 129 // ALSO: There are some Constructor for which no Javadoc Comments have been written, 130 // therefore, there is no HTML "Definition List" already present in that 131 // particular constructor's "Constructor Details" Section. In this case, an HTML 132 // <DL> ... </DL> surrounding element needs to be created. 133 // ********** Compute the Insertion Point ***************** 134 135 int insertionPoint = TagNodeFind.last 136 (pr.fileVec, constructorDP.start, constructorDP.end, TC.ClosingTags, "dl"); 137 138 boolean needToBuildDefList = insertionPoint == -1; 139 140 // ********** Compute the Insertion Point ***************** 141 // If we need to build the <DL> (Definition List), then we will also have to find a 142 // new insertion point. The constructor-details section ends with a closing '</LI>' 143 // element, and then a closing '</UL>' Element. Right before the '</LI>' is where 144 // the insertion should occur. 145 // ********** Compute the Insertion Point ***************** 146 147 if (needToBuildDefList) insertionPoint = TagNodeFind.last 148 (pr.fileVec, constructorDP.start, constructorDP.end, TC.ClosingTags, "li"); 149 150 if (insertionPoint == -1) 151 // This case should never happen, but keep it is here, just in case. 152 // (Kind of the point of exceptions). Guarantees no "Index Out of Bounds" 153 // Exceptions, and a friendly message. 154 { 155 if (pr.sw != null) pr.sw.println( 156 C.BRED + "Could not determine a place to put the hilited code in the JD Page. " + 157 "NOT INSERTING CODE." + C.RESET 158 ); 159 160 continue; 161 } 162 163 // ********** Call the Code Hilite Server ***************** 164 constructorBodyStr = StrIndent.chompCallableBraces(constructorBodyStr); 165 166 try 167 { 168 constructorsIter.insertAt( 169 hiLiteConstructorBody(constructorBodyStr, needToBuildDefList, pr.hiLiter), 170 insertionPoint 171 ); 172 } 173 catch (IOException | HiLiteException e) 174 { 175 throw new HiLiteError( 176 "Failed to HiLite Constructor-Body (first three lines): " + 177 "[\n" + StringParse.firstNLines(constructorBodyStr, 3) + "\n].\n" + 178 "Currently Processing Java Source Code File: [" + pr.srcCodeFileName + "].\n" + 179 "Currently Processing JavaDoc HTML Documentation Page: [" + pr.jdFileName + "].\n" + 180 "Please see getCause() throwable for details.\n" + EXCC.toString(e), 181 e 182 ); 183 } 184 // ********** Call the Code Hilite Server ***************** 185 186 // Loop to the next constructor. 187 countNumConstructorsHiLited++; 188 } 189 190 if ((countNumConstructorsHiLited > 0) || (numConstructorsSkipped > 0)) 191 if (pr.sw != null) pr.sw.println(); 192 193 if (numConstructorsSkipped > 0) 194 if (pr.sw != null) pr.sw.println( 195 "\t" + C.BRED + "Skipped " + C.RESET + 196 C.BBLUE + StringParse.zeroPad(numConstructorsSkipped, 5) + C.RESET + " Constructors." 197 ); 198 199 if (pr.sw != null) pr.sw.println( 200 "\tHilited " + C.BBLUE + StringParse.zeroPad(countNumConstructorsHiLited, 5) + C.RESET + 201 " Constructors." 202 ); 203 204 return countNumConstructorsHiLited; 205 } 206 207 /** 208 * This method is used to hilited the code of a Java <B>{@code Constructor Body}</B> 209 * 210 * @param constructorBody This is the Java Source Code <B>{@code Constructor Body}</B> 211 * Definition that was retrieved using the <B>{@code 'JavaParser Library'}</B> 212 * 213 * @param needToBuildDefList This happens when there is no {@code <DL> DD/DT ... </DL>} list 214 * already available on the page. In this case, and extra {@code '<DL>'} and {@code '</DL>'} 215 * must attached to the HTML-{@code Vector} that is produced here. 216 * 217 * @param hiLiter The {@code Functional Interface} module that performs <B>Code Hiliting</B>. 218 * 219 * @return This will return the HiLited Source Code. It is vectorized into a 220 * {@code Vector<HTMLNode>}. 221 * 222 * @throws IOException If there are I/O errors when calling the {@code HiLiter} 223 * @throws HiLiteException If there are other errors when invoking the {@code HiLiter} 224 * 225 * @see HiLiter#hiLite(String, String, boolean) * 226 * @see TagNodePeek 227 * @see TagNodeIndex 228 * @see HTMLTags#hasTag(String, TC) 229 */ 230 private static Vector<HTMLNode> hiLiteConstructorBody 231 (String constructorBody, boolean needToBuildDefList, HiLiter hiLiter) 232 throws IOException, HiLiteException 233 { 234 // Call the "Pretty Print HiLiter" 235 Vector<HTMLNode> newSubSection = hiLiter.hiLite(constructorBody, "java", true); 236 237 for (int j = (SURROUNDING_MESSAGE.length - 1); j >= 0; j--) 238 newSubSection.add(0, SURROUNDING_MESSAGE[j]); 239 240 // *** The SURROUNDING_MESSAGE array has the opening <DT><SPAN ...>Code:</SPAN><DD> 241 // nodes that are needed before the hilited code. HOWEVER, the "Closing </DD>" 242 // HTML Element needs to be added *AFTER* (at the end of) the hilited code. 243 244 newSubSection.add(HTMLTags.hasTag("dd", TC.ClosingTags)); 245 // adds </DD> to the end of this vector 246 247 // *** If we have to create the surrounding <DL>...</DL> list, because the actual 248 // constructor-details section did not have one in the first place, add an opening 249 // <DL> and also a closing </DL> element at the beginning, and the end, respectively. 250 251 if (needToBuildDefList) 252 { 253 newSubSection.add(0, HTMLTags.hasTag("dl", TC.OpeningTags)); 254 // adds <DL> the beginning of this vector 255 256 newSubSection.add(HTMLTags.hasTag("dl", TC.ClosingTags)); 257 // adds </DL> to the end of this vector. 258 } 259 260 // *** Make all of them scrollable 261 TagNodeIndex tni = TagNodePeek.first(newSubSection, TC.OpeningTags, "div"); 262 263 newSubSection.setElementAt( 264 tni.n.appendToAV 265 ("style", " max-height: 20em; overflow: auto; ", true, SD.SingleQuotes), 266 tni.index 267 ); 268 269 return newSubSection; 270 } 271}