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 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | package Torello.Java; import java.util.regex.*; import java.util.stream.IntStream; import Torello.Browser.Debugger.scriptParsed; import Torello.Java.Function.IntCharFunction; import Torello.JavaDoc.StaticFunctional; import Torello.JavaDoc.Excuse; import Torello.JavaDoc.LinkJavaSource; /** * A class for indenting, unindenting and trimming textual-strings. * * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=STRINDENT> */ @StaticFunctional public class StrIndent { private StrIndent() { } // This matches lines of text that contain only blank / white-space characters private static final Pattern EMPTY_LINE = Pattern.compile("^[ \t]+\n", Pattern.MULTILINE); /** * Replaces sub-strings that contain a newline character followed by only white-space with * only the new-line character itself. * * @param s Any Java {@code String}, but preferrably one which contains newline characters * ({@code '\n'}), and white-space characters immediately followng the newline, but not other * ASCII nor UNICODE. * * @return The same String with each instance of {@code ^[ \t]+\n} replaced by {@code '\n'}. */ public static String trimWhiteSpaceOnlyLines(String s) { Matcher m = EMPTY_LINE.matcher(s); return m.replaceAll("\n"); } /** * Will iterate through <I>each line of text</I> within the input {@code String}-parameter * {@code 's'}, and right-trim the lines. "Right Trim" means to remove all white-space * characters that occur <I><B>after</I></B> the last non-white-space character on the line. * (Does not remove the new-line character ({@code '\n'}) itself). * * <BR /><BR /><B>NOTE:</B> Any line of text which contains only white-space characters is * reduced to a single new-line character. * * @param s Any Java {@code String}, preferrably one with several new-line characters. * * @return The same text, but only after having any 'trailing white-space' characters removed * from each line of text. */ @LinkJavaSource(handle="RightTrimAll") public static String rightTrimAll(String s) { return RightTrimAll.run(s); } /** * Will iterate through <I>each line of text</I> within the input {@code String}-parameter * {@code 's'}, and left-trim the lines. "Left Trim" means to remove all white-space * characters that occur <I><B>before</I></B> the last non-white-space character on the line. * (Does not remove the new-line character ({@code '\n'}) itself). * * <BR /><BR /><B>NOTE:</B> Any line of text which contains only white-space characters is * reduced to a single new-line character. * * @param s Any Java {@code String}, preferrably one with several new-line characters. * * @return The same text, but only after having any 'leading white-space' characters removed * from each line of text. */ @LinkJavaSource(handle="LeftTrimAll") public static String leftTrimAll(String s) { return LeftTrimAll.run(s); } /** * This method expects to receive a method body, constructor body, or other callable body as a * {@code String}; it will remove the beginning and ending braces <CODE>('{'</CODE> & * <CODE>'}')</CODE>, and beginning & ending empty lines. This is to prepare the * method for code hiliting, used internally by the package {@code Torello.JavaDoc}. * * @param callableAsStr This should be a method body. Make sure <B>**NOT TO INCLUDE**</B> the * method signature at the beginning of the method. The first non-white-space character should * be the open braces character <CODE>('{')</CODE>, and the last non-white-space should be * the closing braces character <CODE>('&#125')</CODE>. * * @return A method body {@code String} that can be hilited using the code-hiliting mechanism * of the "JavaDoc Package." * * @throws CallableBodyException If the input parameter {@code String} does not begin and end * with the curly-braces. */ @LinkJavaSource(handle="ChompCallableBraces") public static String chompCallableBraces(String callableAsStr) { return ChompCallableBraces.run(callableAsStr); } /** * Accepts a method body as a {@code String} and left-shifts or right-shifts each line * of text (each {@code 'Line of Code' - LOC}) so that the indentation is consistent with * the requested-indentation input-parameter. * * <BR /><BR /><B>NOTE:</B> The lines of code contained by input-parameter {@code 'codeAsStr'} * must contain leading white-space <I><B STYLE='color: red;'>without any tab ({@code '\t'}) * characters.</B></I> The reasoning here is that tabs can be interpreted in many different * ways, and therefore it is required to replace them before invoking this method. This method * merely adds or removes leading {@code ASCII 0x20} (space-bar characters) from the beginning * of each line of text. A leading tab-character {@code ASCII 0x09} will generate an exception * throw. * * @param codeAsStr A method body. It is expected to be the internal part of a chunk of * source code. * * @param requestedIndent The requested amount of indentation for the method-body. The * line of code that contains the shortest amount of indentation (white-space) will be * calculated, and then all LOC's shall be left-shifted (or right-shifted) according to that * LOC which contained the least amount of leading white-space. * * @return An updated method-body as a {@code String}. * * @throws StringFormatException This exception shall throw whenever a line of text contained * by the input {@code String} has a {@code '\t'} (tab-character) before the first * non-white-space character on that line of text. Code that contains tab-characters is * invariably "auto-indented" by the Code-Editor when loaded into the GUI, and the amount of * indentation applied for each tab-character is usually configurable. Because there are many * variants of how tab's {@code '\t'} gets interpreted by the editor, it is required to replace * these characters first before invoking this method. */ @LinkJavaSource(handle="SetCodeIndent") public static String setCodeIndent(String codeAsStr, int requestedIndent) { return SetCodeIndent.run(codeAsStr, requestedIndent); } /** * Convenience Method. * <BR />See Documentation: {@link #setCodeIndent(String, int)} * <BR />Converts: All {@code '\t'} to the specified number of spaces in parameter * {@code SPACES}. * <BR /><B STYLE='color: red'>NOTE:</B> Exception-Checking is <B STYLE='color: red'>NOT</B> * done on input */ @LinkJavaSource(handle="SetCodeIndent") public static String setCodeIndent_WithTabsPolicyAbsolute (String codeAsStr, int requestedIndent, String SPACES) { return SetCodeIndent.run(codeAsStr.replace("\t", SPACES), requestedIndent); } /** * Adjusts code-indentation using a relative-sized tab-policy. This method performs the * equivalent of shifting the entire text-block, proportionately, to the left or right. * * <BR /><BR />To do this, first, the number of spaces that preceed the * <B STYLE='color: red;'>least-indented</B> line is computed, and afterwards, every line in * the text is shifted by an identical number of space-characters. The number of spaces that * are either added or removed from each line is dependent on whether the requested * indentation (parameter {@code 'requestedIndent'}) is greater-than or less-than the computed * least-indented line. * * <EMBED CLASS='external-html' DATA-FILE-ID=SI_REL_TABS> * * @param codeAsStr Any Java source-code block, as a {@code java.lang.String} * * @param requestedIndent The number of spaces that the code should have as indentation. * Note, that in the JavaDoc Upgrader code, this number is always {@code '1'}. * * @param spacesPerTab If tabs are found inside this {@code String}, then they are replaced * with an appropriate number of space characters, according to a relative tab-policy, as * described above. * * @return A properly shifted-indented Java source-code block. */ @LinkJavaSource(handle="SetCodeIndentTabsPolicy") public static String setCodeIndent_WithTabsPolicyRelative (String codeAsStr, int requestedIndent, int spacesPerTab) { return SetCodeIndentTabsPolicy.run(codeAsStr, requestedIndent, spacesPerTab); } /** * Helper Method for calculating the number of space characters to be used at the beginning * of a line of code, all the while obeying a particular tabs-policy. * * <BR /><BR /><B STYLE='color: red;'>IMPORTANT:</B> None of the parameters to this method * will be checked for errors. This method is often used inside of a loop, and improper * input should be presumed to cause indeterminate results. * * @param code A Java source-code {@code String}, that has been converted into a Java * {@code char[]}-Array. The line of code whose leading white-space is being computed may be * located anywhere in the array. * * <BR /><BR /><B>NOTE:</B> These types of arrays are easily creaated by invoking the * {@code java.lang.String} method {@code 'toCharArray()'} * * @param lineFirstCharacterPos The array-index to be considered as the first character of * non-new-line character data. * * @param spacesPerTab The number of spaces that a tab-character ({@code '\t'}) intends to * represent. * * <BR /><BR />When {@code FALSE} is passed to this parameter, a tab-character will represent * a {@code String} of space-characters whose length is equal to the number of space-characters * that remain until the next modulo-{@code spacesPerTab} boundary. * * @return The number of space-characters ({@code ' '}) that should preceede the line of source * code. * * <BR /><BR /><B STYLE='color: red'>NOTE:</B> If this line of source-code is a white-space * <B STYLE='color: red;'>ONLY</B> line, then {@code -1} will be returned. */ public static int computeEffectiveLeadingWhiteSpace (char[] code, int lineFirstCharacterPos, int spacesPerTab) { int ret = 0; int relativeCount = 0; for (int i=lineFirstCharacterPos; i < code.length; i++) if (! Character.isWhitespace(code[i])) return ret; else switch (code[i]) { case ' ' : ret++; relativeCount = (relativeCount + 1) % spacesPerTab; break; case '\t' : ret += (spacesPerTab - relativeCount); relativeCount = 0; break; case '\r' : case '\f' : break; case '\n' : return -1; default: throw new UnreachableError(); } return -1; } /** * Replaces tab-characters ({@code '\t'}) in a single-line of source-code with a * relative-number of space-characters ({@code ' '}). * * <EMBED CLASS='external-html' DATA-FILE-ID=SI_REL_TABS> * * <BR /><BR /><B STYLE='color: red;'>IMPORTANT:</B> None of the parameters to this method * will be checked for errors. This method is often used inside of a loop, and improper * input should be presumed to cause indeterminate results. * * @param code This should be the source-code, converted to a character-array. The specific * line in the source-code being properly space-adjusted may be located anywhere in this * array. * * <BR /><BR /><B>NOTE:</B> These types of arrays are easily creaated by invoking the * {@code java.lang.String} method {@code 'toCharArray()'} * * @param numLeadingSpaces The number of spaces that have been placed before the start of this * line of code. This is needed because <B STYLE='color: red;'>relative</B>-tabs are computed * based on integral-multiples of the tab-width ({@code 'spacesPerTab'}). * * <BR /><BR />This method is a helper & example method that may be used in conjunction * with properly indenting source-code. Note that the number of leading-spaces may not be * identicaly to the actual number of white-space characters in the array. <I>After converting * tab-characters ({@code '\t'}) to spaces ({@code ' '}), this number will often change.</I> * * @param fcPos This parameter should contain the location of the first source-code character * in the line of code. This parameter should be an array-index that * <B STYLE='color: red;'>does not</B> contain white-space. * * @param spacesPerTab The number of spaces that are used to replaces tab-characters. Since * this method performs relative tab-replacement, this constitutes the * <B STYLE='color: red;'>maximum</B> number of space characters that will be used to replace * a tab. * * @return A line of code, as a {@code String}, without any leading white-space, and one in * which all tab-characters have been replaced by spaces. */ @LinkJavaSource(handle="LOCAsStr") public static String lineOfCodeAsStr (char[] code, int numLeadingSpaces, int fcPos, int spacesPerTab) { return LOCAsStr.run(code, numLeadingSpaces, fcPos, spacesPerTab); } /** * This performs a variation of "indentation" on a Java {@code String} - simply put - it * replaces each new-line character ({@code '\n'}) with a {@code String} that begins with a * new-line, and is followed by {@code 'n'} blank white-space characters {@code ' '}. * * If the input {@code String} parameter {@code 's'} is of zero-length, then the zero-length * {@code String} is returned. If the final character in the input {@code String} is a * new-line, that new-line is not padded. * * @param s Any {@code java.lang.String} - preferably one that contains new-line characters. * * @param n The number of white-space characters to use when pre-pending white-space to each * line of text in input-parameter {@code 's'} * * @return A new {@code java.lang.String} where each line of text has been indented by * {@code 'n'} blank white-space characters. If the text ends with a new-line, that line of * text is not indented. * * @throws NException If parameter {@code 'n'} is less than one. */ public static String indent(String s, int n) { if (n < 1) throw new NException( "The value passed to parameter 'n' was [" + n + "], but this is expected to be an " + "integer greater than or equal to 1." ); if (s.length() == 0) return ""; String padding = String.format("%1$" + n + "s", " "); boolean lastIsNewLine = s.charAt(s.length() - 1) == '\n'; s = padding + s.replace("\n", "\n" + padding); return lastIsNewLine ? s.substring(0, s.length() - padding.length()) : s; } /** * Identical to {@link #indent(String, int)}, but pre-pends a {@code TAB} character {@code 'n'} * times, rather than a space-character {@code ' '}. * * @param s Any {@code java.lang.String} - preferably one that contains new-line characters. * * @param n The number of tab ({@code '\t'}) characters to use when pre-pending to each line of * text within input-parameter {@code 's'} * * @return A new {@code java.lang.String} where each line of text has been indented by * {@code 'n'} tab characters. If the text ends with a new-line, that line of text is not * indented. * * @throws NException If parameter {@code 'n'} is less than one. */ public static String indentTabs(String s, int n) { if (n < 1) throw new NException( "The value passed to parameter 'n' was [" + n + "], but this is expected to be an " + "integer greater than or equal to 1." ); if (s.length() == 0) return ""; String padding = String.format("%1$"+ n + "s", "\t"); boolean lastIsNewLine = s.charAt(s.length() - 1) == '\n'; s = padding + s.replace("\n", "\n" + padding); return lastIsNewLine ? s.substring(0, s.length() - padding.length()) : s; } /** * <EMBED CLASS='external-html' DATA-FILE-ID=SI_INDENT_DESC> * * @param s Any {@code java.lang.String} - preferably one that contains new-line characters. * * @param n The number of tab ({@code '\t'}) characters to use when pre-pending to each line of * text in input-parameter {@code 's'} * * @param spaceOrTab When this parameter is passed <B>{@code TRUE}</B>, the space character * {@code ' '} is used for indentation. When <B>{@code FALSE}</B>, the tab-character * {@code '\t'} is used. * * @return <EMBED CLASS='external-html' DATA-FILE-ID=SI_INDENT_RET> * @throws NException If parameter {@code 'n'} is less than one. */ @LinkJavaSource(handle="Indent") public static String indent (final String s, int n, boolean spaceOrTab, boolean trimBlankLines) { return Indent.run(s, n, spaceOrTab, trimBlankLines); } /** * Throws a new {@code ToDoException} * * @return Will (one day) return an unindented String. */ public static String unIndent( String s, int n, boolean trimBlankLines, boolean rightTrimLines, boolean throwOnTab, boolean throwOnNotEnough, boolean dontThrowOnWhiteSpaceOnlyLines ) { if (n < 1) throw new NException( "The value that was passed to parameter 'n' was [" + n + "], but unfortunately this " + "expected to be a positive integer, greater than zero." ); char[] cArr = s.toCharArray(); throw new ToDoException(); } /** * Performs an indenting of {@code String} of text, but does not indent the first line. This * is used quit frequently by code-generators that need to assign or invoke something, and want * to make sure that subsequent lines of piece of code are indented (after the first line of * text). * * @param s Any instance of {@code java.lang.String}. * @param n The number of space-characters to insert after each newline {@code '\n'} character. * @param spaceOrTab When {@code TRUE}, then there shall be {@code 'n'}-number of space * characters ({@code ' '}) inserted at the beginning of each line of text. When * {@code FALSE}, then this function will insert {@code 'n'} tab characters. * @param trimBlankLines When {@code TRUE}, requests that blank lines be trimmed to only * a single newline ({@code '\n'}) character. * @return The indented {@code String} */ public static String indentAfter2ndLine (String s, int n, boolean spaceOrTab, boolean trimBlankLines) { int pos = s.indexOf('\n'); // If there are no newlines, then return the original string. if (pos == -1) return s; pos++; return // return the first string, as is, and then indent subsequent lines. s.substring(0, pos) + indent(s.substring(pos), n, spaceOrTab, trimBlankLines); } /** * This will replaced leading tabs for each line of text in a source code file with a specified * number of spaces. If tabs are supposed to represent {@code 4} spaces, then if a line in a * source-code file had three leading tab-characters, then those three leading * {@code char '\t'} would be replaced with {@code 12} leading space characters {@code ' '}. * * @param javaSrcFileAsStr A Java Source-Code File, loaded as a {@code String}. * * @param numSpacesPerTab This identifies the number of spaces a {@code char '\t'} is supposed * to represent in any source-code editor's settings. In Google Cloud Server, the default * value is '4' spaces. */ public static String tabsToSpace(String javaSrcFileAsStr, int numSpacesPerTab) { String spaces = StringParse.nChars(' ', numSpacesPerTab); String[] lines = javaSrcFileAsStr.split("\n"); for (String line:lines) System.out.println("LINE: " + line); for (int i=0; i < lines.length; i++) { int numTabs = 0; while ((numTabs < lines[i].length()) && (lines[i].charAt(numTabs) == '\t')) numTabs++; if (numTabs == 0) lines[i] = lines[i] + '\n'; else lines[i] = StringParse.nStrings(spaces, numTabs) + lines[i].substring(numTabs) + '\n'; } StringBuilder sb = new StringBuilder(); for (String line : lines) sb.append(line); return sb.toString(); } } |