1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | package Torello.Java; class SetCodeIndent { private static final String STR_FORMAT_EX_MESSAGE = "One of the lines of code for the method-body as-a-string that was passed contained " + "a tab '\\t' character. Source-Code String's that are passed to this method must have" + "been de-tabified."; private static int INDENTATION_COUNTER = 0; private static final boolean DEBUGGING_INDENTATION = false; static String run(String codeAsStr, int requestedIndent) { if (requestedIndent < 0) throw new IllegalArgumentException ("The requested indent passed to this method was a negative value: " + requestedIndent); else if (requestedIndent > 80) throw new IllegalArgumentException ("The requested indent passed to this method was greater than 80: " + requestedIndent); // Source-Code-String to char-array char[] cArr = codeAsStr.toCharArray(); // Code "Starts With New Line '\n'" boolean swNL = cArr[0] == '\n'; // Code "Ends With New Line" boolean ewNL = cArr[cArr.length - 1] == '\n'; // Location of each '\n' in the code int[] nlPosArr = StrIndexOf.all(codeAsStr, '\n'); // Unless the first character in the code is '\n', numLines - num '\n' + 1 int numLines = nlPosArr.length + (swNL ? 0 : 1); // Length of "Leading White Space" for each line of code int[] wsLenArr = new int[numLines]; // TRUE / FALSE for "only white-space" lines of code boolean[] isOnlyWSArr = new boolean[numLines]; // Amount of White-Space for the LEAST-INDENTED Line of Code int minIndent = Integer.MAX_VALUE; // These three variables are loop-control and temporary variables. int wsCount = 0; // "White Space Count" - amount of WS on each line int outArrPos = 0; // There are two parallel "Output Arrays", this the index int lastPos = 0; // Temp Var for the last-index in a line of code int i; // Simple Loop Control Variable int j; // Simple Loop Control Variable // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // Compute amount of "leading white space" (indentation) for the first LOC in input-String // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // // Count the leading white-space in the first line of text - unless the first character // in the code was a '\n' (newline) if (! swNL) { // The array-index in array cArr of the last character in the first line of text. // If the input code-String is just a single line of code without any newline '\n' // characters, then this value is the length of the code-string. Otherwise, this // value is assigned the cArr index/position of the first newline '\n' character. lastPos = (nlPosArr.length > 0) ? nlPosArr[0] : cArr.length; // The loop iterate until we reach the end of the first line of code/text, or // we reach a character that is not white-space. for (i=0; (i < lastPos) && Character.isWhitespace(cArr[i]); i++) if (cArr[i] == '\t') throw new StringFormatException(STR_FORMAT_EX_MESSAGE); else wsCount++; // Amount of "Leading" white-space (indentation) for first LOC wsLenArr[0] = wsCount; // Was the first line only white-space? isOnlyWSArr[0] = (i == lastPos); // 'minIndent' was initialized to Integer.MAX_VALUE minIndent = wsCount; outArrPos++; } // **************************************************************************************** // Compute the amount of "leading white space" (indentation) for each LOC in input-String // **************************************************************************************** // // This loop will iterate each line of code inside the input source-code character-array // The length (number of characters) for the "leading white-space" (Which may also be called // indentation) for each LOC is stored in an integer-array called "wsLenArr" // When this loop encounters a line that is blank (contains only white-space), it is noted // in a boolean array "isOnlyWSArr" // // NOTE: The previous loop did the *EXACT SAME THING*, but ONLY for the first line of code // in the input-string. This is because the loop-control variables are slightly // different for the first line of code. for (i=0; i < nlPosArr.length; i++) { wsCount = 0; lastPos = (i < (nlPosArr.length-1)) ? nlPosArr[i+1] : cArr.length; for (j = (nlPosArr[i]+1); (j < lastPos) && Character.isWhitespace(cArr[j]); j++) if (cArr[j] == '\t') throw new StringFormatException(STR_FORMAT_EX_MESSAGE); else wsCount++; // Amount of "Leading" white-space (indentation) for current LOC wsLenArr[outArrPos] = wsCount; // Is the current LOC only white-space? isOnlyWSArr[outArrPos] = (j == lastPos); // Check if this line is the "reigning champion" of minimum of white-space indentation // Blank lines (lines with 'only white-space') cannot be factored into the // "minimum indentation" computation if (wsCount < minIndent) if (! isOnlyWSArr[outArrPos]) minIndent = wsCount; outArrPos++; } // **************************************************************************************** // Now we will shorten or extend the amount of indentation for the input code snippet. // **************************************************************************************** // // *** Keep Here for Reference *** // int[] nlPosArr // Location of each '\n' in the code // int[] wsLenArr // Length of "Leading White Space" for each line of code // boolean[] isOnlyWSArr // TRUE / FALSE for "only white-space" lines of code int diff = requestedIndent - minIndent; int delta = 0; // Intended to store the change in "Source Code as a String" LENGTH // after performing the indentation changes int nextNLPos = 0; // Position of the next newline int srcPos = 0; // index/pointer to the input "Source Code as a String" char-array int destPos = 0; // index/pointer to (output) indentation-change output char-array int nlPosArrPos = 0; // index/pointer to the "New Line Position Array" int otherArrPos = 0; // index/pointer to the other 2 position arrays // a.k.a: "White-Space-Length Array" and the // "Is Only White-Space Array" if (diff == 0) return codeAsStr; for (i=0; i < wsLenArr.length; i++) if (! isOnlyWSArr[i]) delta += diff; char[] outArr = new char[cArr.length + delta]; if (diff > 0) return Indent.run(codeAsStr, diff, true, true); else { // We are removing white-space, start at end, work backwards srcPos = cArr.length - 1; // The "output array", therefore, also starts at end of char-array destPos = outArr.length - 1; // The "Where are the newlines array" index-pointer nlPosArrPos = nlPosArr.length - 1; otherArrPos = wsLenArr.length - 1; // The number of "lines of text" and "number of new-lines" // are *NOT NECESSARILY* identical. The former might be // longer by *PRECISELY ONE* array-element. for (; otherArrPos >= 0; otherArrPos--) { // Check if the first character in the Source-Code String is a newline. nextNLPos = (nlPosArrPos >= 0) ? nlPosArr[nlPosArrPos--] : -1; // Lines of Source Code that are only white-space shall simply be copied to // the destination/output char-array. if (isOnlyWSArr[otherArrPos]) while (srcPos >= nextNLPos) outArr[destPos--] = cArr[srcPos--]; else { // Copy the line of source code int numChars = srcPos - nextNLPos - wsLenArr[otherArrPos]; while (numChars-- > 0) outArr[destPos--] = cArr[srcPos--]; // Insert the exact amount of space-characters indentation numChars = wsLenArr[otherArrPos] + diff; while (numChars-- > 0) outArr[destPos--] = ' '; // Skip over the original indentation (white-space) from the input line // of source-code. srcPos -= (wsLenArr[otherArrPos] + 1); // Make sure to insert a new-line (since this character WASN'T copied) if (destPos >= 0) outArr[destPos--] = '\n'; } } } // **************************************************************************************** // Debug Println - This code isn't executed without the little debug-flag being set. // **************************************************************************************** // The returned code block is ready; convert to a String String ret = new String(outArr); // Do not delete. Writing the debugging information takes a lot of thought. // If there is ever an error, this code is quite important. if (! DEBUGGING_INDENTATION) return ret; try { StringBuilder sb = new StringBuilder(); sb.append( "swNL:\t\t\t\t" + swNL + '\n' + "ewNL:\t\t\t\t" + ewNL + '\n' + "numLines:\t\t\t" + numLines + '\n' + "minIndent:\t\t\t" + minIndent + '\n' + "requestedIndent:\t" + requestedIndent + '\n' + "diff:\t\t\t\t" + diff + '\n' + "delta:\t\t\t\t" + delta + '\n' + "nlPosArr:\n\t" ); for (i=0; i < nlPosArr.length; i++) sb.append(nlPosArr[i] + ", "); sb.append("\nwsLenArr:\n\t"); for (i=0; i < wsLenArr.length; i++) sb.append(wsLenArr[i] + ", "); sb.append("\nisOnlyWSArr:\n\t"); for (i=0; i < isOnlyWSArr.length; i++) sb.append(isOnlyWSArr[i] + ", "); sb.append("\n"); FileRW.writeFile( sb.toString() + "\n\n****************************************************\n\n" + codeAsStr + "\n\n****************************************************\n\n" + ret, "TEMP/method" + StringParse.zeroPad10e2(++INDENTATION_COUNTER) + ".txt" ); if (INDENTATION_COUNTER == 5) System.exit(0); } catch (Exception e) { e.printStackTrace(); System.out.println(e + "\n\nFatal Error. Exiting."); System.exit(0); } return ret; } } |