1 package org.apache.maven.plugin.checkstyle;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6
7 import org.apache.maven.plugin.AbstractMojo;
8 import org.apache.maven.plugin.MojoExecutionException;
9
10
11
12
13
14
15
16
17
18
19 public class HelpMojo
20 extends AbstractMojo
21 {
22
23
24
25
26
27 private boolean detail;
28
29
30
31
32
33
34 private java.lang.String goal;
35
36
37
38
39
40
41 private int lineLength;
42
43
44
45
46
47
48 private int indentSize;
49
50
51
52 public void execute()
53 throws MojoExecutionException
54 {
55 if ( lineLength <= 0 )
56 {
57 getLog().warn( "The parameter 'lineLength' should be positive, using '80' as default." );
58 lineLength = 80;
59 }
60 if ( indentSize <= 0 )
61 {
62 getLog().warn( "The parameter 'indentSize' should be positive, using '2' as default." );
63 indentSize = 2;
64 }
65
66 StringBuffer sb = new StringBuffer();
67
68 append( sb, "org.apache.maven.plugins:maven-checkstyle-plugin:2.7", 0 );
69 append( sb, "", 0 );
70
71 append( sb, "Maven Checkstyle Plugin", 0 );
72 append( sb, "Generates a report on violations of code style and optionally fails the build if violations are detected.", 1 );
73 append( sb, "", 0 );
74
75 if ( goal == null || goal.length() <= 0 )
76 {
77 append( sb, "This plugin has 3 goals:", 0 );
78 append( sb, "", 0 );
79 }
80
81 if ( goal == null || goal.length() <= 0 || "check".equals( goal ) )
82 {
83 append( sb, "checkstyle:check", 0 );
84 append( sb, "Perform a violation check against the last Checkstyle run to see if there are any violations. It reads the Checkstyle output file, counts the number of violations found and displays it on the console.", 1 );
85 append( sb, "", 0 );
86 if ( detail )
87 {
88 append( sb, "Available parameters:", 1 );
89 append( sb, "", 0 );
90
91 append( sb, "cacheFile (Default: ${project.build.directory}/checkstyle-cachefile)", 2 );
92 append( sb, "Specifies the cache file used to speed up Checkstyle on successive runs.", 3 );
93 append( sb, "", 0 );
94
95 append( sb, "configLocation (Default: config/sun_checks.xml)", 2 );
96 append( sb, "Specifies the location of the XML configuration to use.\n\nPotential values are a filesystem path, a URL, or a classpath resource. This parameter expects that the contents of the location conform to the xml format (Checkstyle Checker module) configuration of rulesets.\n\nThis parameter is resolved as resource, URL, then file. If successfully resolved, the contents of the configuration is copied into the ${project.build.directory}/checkstyle-configuration.xml file before being passed to Checkstyle as a configuration.\n\nThere are 4 predefined rulesets.\n\n-\tconfig/sun_checks.xml: Sun Checks.\n-\tconfig/turbine_checks.xml: Turbine Checks.\n-\tconfig/avalon_checks.xml: Avalon Checks.\n-\tconfig/maven_checks.xml: Maven Source Checks.\n", 3 );
97 append( sb, "Expression: ${checkstyle.config.location}", 3 );
98 append( sb, "", 0 );
99
100 append( sb, "consoleOutput (Default: false)", 2 );
101 append( sb, "Output errors to console.", 3 );
102 append( sb, "", 0 );
103
104 append( sb, "encoding (Default: ${project.build.sourceEncoding})", 2 );
105 append( sb, "The file encoding to use when reading the source files. If the property project.build.sourceEncoding is not set, the platform default encoding is used. Note: This parameter always overrides the property charset from Checkstyle\'s TreeWalker module.", 3 );
106 append( sb, "Expression: ${encoding}", 3 );
107 append( sb, "", 0 );
108
109 append( sb, "excludes", 2 );
110 append( sb, "Specifies the names filter of the source files to be excluded for Checkstyle.", 3 );
111 append( sb, "Expression: ${checkstyle.excludes}", 3 );
112 append( sb, "", 0 );
113
114 append( sb, "failOnViolation (Default: true)", 2 );
115 append( sb, "Do we fail the build on a violation?", 3 );
116 append( sb, "Expression: ${checkstyle.failOnViolation}", 3 );
117 append( sb, "", 0 );
118
119 append( sb, "failsOnError (Default: false)", 2 );
120 append( sb, "Specifies if the build should fail upon a violation.", 3 );
121 append( sb, "", 0 );
122
123 append( sb, "headerLocation (Default: LICENSE.txt)", 2 );
124 append( sb, "Specifies the location of the License file (a.k.a. the header file) that can be used by Checkstyle to verify that source code has the correct license header.\n\nYou need to use ${checkstyle.header.file} in your Checkstyle xml configuration to reference the name of this header file.\n\nFor instance:\n\n<module name=\'RegexpHeader\'> <property name=\'headerFile\' value=\'${checkstyle.header.file}\'/> </module>\n", 3 );
125 append( sb, "Expression: ${checkstyle.header.file}", 3 );
126 append( sb, "", 0 );
127
128 append( sb, "includes (Default: **/*.java)", 2 );
129 append( sb, "Specifies the names filter of the source files to be used for Checkstyle.", 3 );
130 append( sb, "Required: Yes", 3 );
131 append( sb, "Expression: ${checkstyle.includes}", 3 );
132 append( sb, "", 0 );
133
134 append( sb, "includeTestSourceDirectory (Default: ${false})", 2 );
135 append( sb, "Include or not the test source directory to be used for Checkstyle.", 3 );
136 append( sb, "", 0 );
137
138 append( sb, "logViolationsToConsole (Default: false)", 2 );
139 append( sb, "Output the detected violations to the console.", 3 );
140 append( sb, "Expression: ${checkstyle.console}", 3 );
141 append( sb, "", 0 );
142
143 append( sb, "maxAllowedViolations (Default: 0)", 2 );
144 append( sb, "The maximum number of allowed violations. The execution fails only if the number of violations is above this limit.", 3 );
145 append( sb, "Expression: ${checkstyle.maxAllowedViolations}", 3 );
146 append( sb, "", 0 );
147
148 append( sb, "outputFile (Default: ${project.build.directory}/checkstyle-result.xml)", 2 );
149 append( sb, "Specifies the path and filename to save the Checkstyle output. The format of the output file is determined by the outputFileFormat parameter.", 3 );
150 append( sb, "Expression: ${checkstyle.output.file}", 3 );
151 append( sb, "", 0 );
152
153 append( sb, "outputFileFormat (Default: xml)", 2 );
154 append( sb, "Specifies the format of the output to be used when writing to the output file. Valid values are \'plain\' and \'xml\'.", 3 );
155 append( sb, "Expression: ${checkstyle.output.format}", 3 );
156 append( sb, "", 0 );
157
158 append( sb, "propertiesLocation", 2 );
159 append( sb, "Specifies the location of the properties file.\n\nThis parameter is resolved as URL, File then resource. If successfully resolved, the contents of the properties location is copied into the ${project.build.directory}/checkstyle-checker.properties file before being passed to Checkstyle for loading.\n\nThe contents of the propertiesLocation will be made available to Checkstyle for specifying values for parameters within the xml configuration (specified in the configLocation parameter).\n", 3 );
160 append( sb, "Expression: ${checkstyle.properties.location}", 3 );
161 append( sb, "", 0 );
162
163 append( sb, "propertyExpansion", 2 );
164 append( sb, "Allows for specifying raw property expansion information.", 3 );
165 append( sb, "", 0 );
166
167 append( sb, "skip (Default: false)", 2 );
168 append( sb, "Skip entire check.", 3 );
169 append( sb, "Expression: ${checkstyle.skip}", 3 );
170 append( sb, "", 0 );
171
172 append( sb, "skipExec (Default: false)", 2 );
173 append( sb, "Skip checktyle execution will only scan the outputFile.", 3 );
174 append( sb, "Expression: ${checkstyle.skipExec}", 3 );
175 append( sb, "", 0 );
176
177 append( sb, "sourceDirectory (Default: ${project.build.sourceDirectory})", 2 );
178 append( sb, "Specifies the location of the source directory to be used for Checkstyle.", 3 );
179 append( sb, "Required: Yes", 3 );
180 append( sb, "", 0 );
181
182 append( sb, "suppressionsFileExpression (Default: checkstyle.suppressions.file)", 2 );
183 append( sb, "The key to be used in the properties for the suppressions file.", 3 );
184 append( sb, "Expression: ${checkstyle.suppression.expression}", 3 );
185 append( sb, "", 0 );
186
187 append( sb, "suppressionsLocation", 2 );
188 append( sb, "Specifies the location of the suppressions XML file to use.\n\nThis parameter is resolved as resource, URL, then file. If successfully resolved, the contents of the suppressions XML is copied into the ${project.build.directory}/checkstyle-supressions.xml file before being passed to Checkstyle for loading.\n\nSee suppressionsFileExpression for the property that will be made available to your checkstyle configuration.\n", 3 );
189 append( sb, "Expression: ${checkstyle.suppressions.location}", 3 );
190 append( sb, "", 0 );
191
192 append( sb, "testSourceDirectory (Default: ${project.build.testSourceDirectory})", 2 );
193 append( sb, "Specifies the location of the test source directory to be used for Checkstyle.", 3 );
194 append( sb, "", 0 );
195
196 append( sb, "useFile", 2 );
197 append( sb, "If null, the Checkstyle plugin will display violations on stdout. Otherwise, a text file will be created with the violations.", 3 );
198 append( sb, "", 0 );
199
200 append( sb, "violationSeverity (Default: error)", 2 );
201 append( sb, "The lowest severity level that is considered a violation. Valid values are \'error\', \'warning\' and \'info\'.", 3 );
202 append( sb, "Expression: ${checkstyle.violationSeverity}", 3 );
203 append( sb, "", 0 );
204 }
205 }
206
207 if ( goal == null || goal.length() <= 0 || "checkstyle".equals( goal ) )
208 {
209 append( sb, "checkstyle:checkstyle", 0 );
210 append( sb, "Perform a Checkstyle analysis, and generate a report on violations.", 1 );
211 append( sb, "", 0 );
212 if ( detail )
213 {
214 append( sb, "Available parameters:", 1 );
215 append( sb, "", 0 );
216
217 append( sb, "cacheFile (Default: ${project.build.directory}/checkstyle-cachefile)", 2 );
218 append( sb, "Specifies the cache file used to speed up Checkstyle on successive runs.", 3 );
219 append( sb, "", 0 );
220
221 append( sb, "configLocation (Default: config/sun_checks.xml)", 2 );
222 append( sb, "Specifies the location of the XML configuration to use.\n\nPotential values are a filesystem path, a URL, or a classpath resource. This parameter expects that the contents of the location conform to the xml format (Checkstyle Checker module) configuration of rulesets.\n\nThis parameter is resolved as resource, URL, then file. If successfully resolved, the contents of the configuration is copied into the ${project.build.directory}/checkstyle-configuration.xml file before being passed to Checkstyle as a configuration.\n\nThere are 4 predefined rulesets.\n\n-\tconfig/sun_checks.xml: Sun Checks.\n-\tconfig/turbine_checks.xml: Turbine Checks.\n-\tconfig/avalon_checks.xml: Avalon Checks.\n-\tconfig/maven_checks.xml: Maven Source Checks.\n", 3 );
223 append( sb, "Expression: ${checkstyle.config.location}", 3 );
224 append( sb, "", 0 );
225
226 append( sb, "consoleOutput (Default: false)", 2 );
227 append( sb, "Output errors to console.", 3 );
228 append( sb, "", 0 );
229
230 append( sb, "enableFilesSummary (Default: true)", 2 );
231 append( sb, "Specifies if the Files summary should be enabled or not.", 3 );
232 append( sb, "Expression: ${checkstyle.enable.files.summary}", 3 );
233 append( sb, "", 0 );
234
235 append( sb, "enableRSS (Default: true)", 2 );
236 append( sb, "Specifies if the RSS should be enabled or not.", 3 );
237 append( sb, "Expression: ${checkstyle.enable.rss}", 3 );
238 append( sb, "", 0 );
239
240 append( sb, "enableRulesSummary (Default: true)", 2 );
241 append( sb, "Specifies if the Rules summary should be enabled or not.", 3 );
242 append( sb, "Expression: ${checkstyle.enable.rules.summary}", 3 );
243 append( sb, "", 0 );
244
245 append( sb, "enableSeveritySummary (Default: true)", 2 );
246 append( sb, "Specifies if the Severity summary should be enabled or not.", 3 );
247 append( sb, "Expression: ${checkstyle.enable.severity.summary}", 3 );
248 append( sb, "", 0 );
249
250 append( sb, "encoding (Default: ${project.build.sourceEncoding})", 2 );
251 append( sb, "The file encoding to use when reading the source files. If the property project.build.sourceEncoding is not set, the platform default encoding is used. Note: This parameter always overrides the property charset from Checkstyle\'s TreeWalker module.", 3 );
252 append( sb, "Expression: ${encoding}", 3 );
253 append( sb, "", 0 );
254
255 append( sb, "excludes", 2 );
256 append( sb, "Specifies the names filter of the source files to be excluded for Checkstyle.", 3 );
257 append( sb, "Expression: ${checkstyle.excludes}", 3 );
258 append( sb, "", 0 );
259
260 append( sb, "failsOnError (Default: false)", 2 );
261 append( sb, "Specifies if the build should fail upon a violation.", 3 );
262 append( sb, "", 0 );
263
264 append( sb, "format (Default: sun)", 2 );
265 append( sb, "Deprecated. Use configLocation instead.", 3 );
266 append( sb, "", 0 );
267 append( sb, "Specifies what predefined check set to use. Available sets are \'sun\' (for the Sun coding conventions), \'turbine\', and \'avalon\'.", 3 );
268 append( sb, "", 0 );
269
270 append( sb, "headerFile", 2 );
271 append( sb, "Deprecated. Use headerLocation instead.", 3 );
272 append( sb, "", 0 );
273 append( sb, "Specifies the location of the License file (a.k.a. the header file) that is used by Checkstyle to verify that source code has the correct license header.", 3 );
274 append( sb, "Expression: ${basedir}/LICENSE.txt", 3 );
275 append( sb, "", 0 );
276
277 append( sb, "headerLocation (Default: LICENSE.txt)", 2 );
278 append( sb, "Specifies the location of the License file (a.k.a. the header file) that can be used by Checkstyle to verify that source code has the correct license header.\n\nYou need to use ${checkstyle.header.file} in your Checkstyle xml configuration to reference the name of this header file.\n\nFor instance:\n\n<module name=\'RegexpHeader\'> <property name=\'headerFile\' value=\'${checkstyle.header.file}\'/> </module>\n", 3 );
279 append( sb, "Expression: ${checkstyle.header.file}", 3 );
280 append( sb, "", 0 );
281
282 append( sb, "includes (Default: **/*.java)", 2 );
283 append( sb, "Specifies the names filter of the source files to be used for Checkstyle.", 3 );
284 append( sb, "Required: Yes", 3 );
285 append( sb, "Expression: ${checkstyle.includes}", 3 );
286 append( sb, "", 0 );
287
288 append( sb, "includeTestSourceDirectory (Default: ${false})", 2 );
289 append( sb, "Include or not the test source directory to be used for Checkstyle.", 3 );
290 append( sb, "", 0 );
291
292 append( sb, "linkXRef (Default: true)", 2 );
293 append( sb, "Link the violation line numbers to the source xref. Will link automatically if Maven JXR plugin is being used.", 3 );
294 append( sb, "Expression: ${linkXRef}", 3 );
295 append( sb, "", 0 );
296
297 append( sb, "outputDirectory (Default: ${project.reporting.outputDirectory})", 2 );
298 append( sb, "The output directory for the report. Note that this parameter is only evaluated if the goal is run directly from the command line. If the goal is run indirectly as part of a site generation, the output directory configured in Maven Site Plugin is used instead.", 3 );
299 append( sb, "Required: Yes", 3 );
300 append( sb, "", 0 );
301
302 append( sb, "outputFile (Default: ${project.build.directory}/checkstyle-result.xml)", 2 );
303 append( sb, "Specifies the path and filename to save the checkstyle output. The format of the output file is determined by the outputFileFormat parameter.", 3 );
304 append( sb, "Expression: ${checkstyle.output.file}", 3 );
305 append( sb, "", 0 );
306
307 append( sb, "outputFileFormat (Default: xml)", 2 );
308 append( sb, "Specifies the format of the output to be used when writing to the output file. Valid values are \'plain\' and \'xml\'.", 3 );
309 append( sb, "Expression: ${checkstyle.output.format}", 3 );
310 append( sb, "", 0 );
311
312 append( sb, "packageNamesFile", 2 );
313 append( sb, "Deprecated. Use packageNamesLocation instead.", 3 );
314 append( sb, "", 0 );
315 append( sb, "Specifies the location of the package names XML to be used to configure Checkstyle.", 3 );
316 append( sb, "", 0 );
317
318 append( sb, "packageNamesLocation", 2 );
319 append( sb, "Specifies the location of the package names XML to be used to configure the Checkstyle Packages.\n\nThis parameter is resolved as resource, URL, then file. If resolved to a resource, or a URL, the contents of the package names XML is copied into the ${project.build.directory}/checkstyle-packagenames.xml file before being passed to Checkstyle for loading.\n", 3 );
320 append( sb, "", 0 );
321
322 append( sb, "propertiesFile", 2 );
323 append( sb, "Deprecated. Use propertiesLocation instead.", 3 );
324 append( sb, "", 0 );
325 append( sb, "Specifies the location of the Checkstyle properties file that will be used to check the source.", 3 );
326 append( sb, "", 0 );
327
328 append( sb, "propertiesLocation", 2 );
329 append( sb, "Specifies the location of the properties file.\n\nThis parameter is resolved as URL, File then resource. If successfully resolved, the contents of the properties location is copied into the ${project.build.directory}/checkstyle-checker.properties file before being passed to Checkstyle for loading.\n\nThe contents of the propertiesLocation will be made available to Checkstyle for specifying values for parameters within the xml configuration (specified in the configLocation parameter).\n", 3 );
330 append( sb, "Expression: ${checkstyle.properties.location}", 3 );
331 append( sb, "", 0 );
332
333 append( sb, "propertiesURL", 2 );
334 append( sb, "Deprecated. Use propertiesLocation instead.", 3 );
335 append( sb, "", 0 );
336 append( sb, "Specifies the URL of the Checkstyle properties that will be used to check the source.", 3 );
337 append( sb, "", 0 );
338
339 append( sb, "propertyExpansion", 2 );
340 append( sb, "Allows for specifying raw property expansion information.", 3 );
341 append( sb, "", 0 );
342
343 append( sb, "skip (Default: false)", 2 );
344 append( sb, "Skip entire check.", 3 );
345 append( sb, "Expression: ${checkstyle.skip}", 3 );
346 append( sb, "", 0 );
347
348 append( sb, "sourceDirectory (Default: ${project.build.sourceDirectory})", 2 );
349 append( sb, "Specifies the location of the source directory to be used for Checkstyle.", 3 );
350 append( sb, "Required: Yes", 3 );
351 append( sb, "", 0 );
352
353 append( sb, "suppressionsFile", 2 );
354 append( sb, "Deprecated. Use suppressionsLocation instead.", 3 );
355 append( sb, "", 0 );
356 append( sb, "Specifies the location of the suppressions XML file to use. The plugin defines a Checkstyle property named checkstyle.suppressions.file with the value of this property. This allows using the Checkstyle property in your own custom checkstyle configuration file when specifying a suppressions file.", 3 );
357 append( sb, "", 0 );
358
359 append( sb, "suppressionsFileExpression (Default: checkstyle.suppressions.file)", 2 );
360 append( sb, "The key to be used in the properties for the suppressions file.", 3 );
361 append( sb, "Expression: ${checkstyle.suppression.expression}", 3 );
362 append( sb, "", 0 );
363
364 append( sb, "suppressionsLocation", 2 );
365 append( sb, "Specifies the location of the suppressions XML file to use.\n\nThis parameter is resolved as resource, URL, then file. If successfully resolved, the contents of the suppressions XML is copied into the ${project.build.directory}/checkstyle-supressions.xml file before being passed to Checkstyle for loading.\n\nSee suppressionsFileExpression for the property that will be made available to your checkstyle configuration.\n", 3 );
366 append( sb, "Expression: ${checkstyle.suppressions.location}", 3 );
367 append( sb, "", 0 );
368
369 append( sb, "testSourceDirectory (Default: ${project.build.testSourceDirectory})", 2 );
370 append( sb, "Specifies the location of the test source directory to be used for Checkstyle.", 3 );
371 append( sb, "", 0 );
372
373 append( sb, "useFile", 2 );
374 append( sb, "If null, the Checkstyle plugin will display violations on stdout. Otherwise, a text file will be created with the violations.", 3 );
375 append( sb, "", 0 );
376
377 append( sb, "xrefLocation (Default: ${project.reporting.outputDirectory}/xref)", 2 );
378 append( sb, "Location of the Xrefs to link to.", 3 );
379 append( sb, "", 0 );
380 }
381 }
382
383 if ( goal == null || goal.length() <= 0 || "help".equals( goal ) )
384 {
385 append( sb, "checkstyle:help", 0 );
386 append( sb, "Display help information on maven-checkstyle-plugin.\nCall\n\u00a0\u00a0mvn\u00a0checkstyle:help\u00a0-Ddetail=true\u00a0-Dgoal=<goal-name>\nto display parameter details.", 1 );
387 append( sb, "", 0 );
388 if ( detail )
389 {
390 append( sb, "Available parameters:", 1 );
391 append( sb, "", 0 );
392
393 append( sb, "detail (Default: false)", 2 );
394 append( sb, "If true, display all settable properties for each goal.", 3 );
395 append( sb, "Expression: ${detail}", 3 );
396 append( sb, "", 0 );
397
398 append( sb, "goal", 2 );
399 append( sb, "The name of the goal for which to show help. If unspecified, all goals will be displayed.", 3 );
400 append( sb, "Expression: ${goal}", 3 );
401 append( sb, "", 0 );
402
403 append( sb, "indentSize (Default: 2)", 2 );
404 append( sb, "The number of spaces per indentation level, should be positive.", 3 );
405 append( sb, "Expression: ${indentSize}", 3 );
406 append( sb, "", 0 );
407
408 append( sb, "lineLength (Default: 80)", 2 );
409 append( sb, "The maximum length of a display line, should be positive.", 3 );
410 append( sb, "Expression: ${lineLength}", 3 );
411 append( sb, "", 0 );
412 }
413 }
414
415 if ( getLog().isInfoEnabled() )
416 {
417 getLog().info( sb.toString() );
418 }
419 }
420
421
422
423
424
425
426
427
428
429
430 private static String repeat( String str, int repeat )
431 {
432 StringBuffer buffer = new StringBuffer( repeat * str.length() );
433
434 for ( int i = 0; i < repeat; i++ )
435 {
436 buffer.append( str );
437 }
438
439 return buffer.toString();
440 }
441
442
443
444
445
446
447
448
449
450 private void append( StringBuffer sb, String description, int indent )
451 {
452 for ( Iterator it = toLines( description, indent, indentSize, lineLength ).iterator(); it.hasNext(); )
453 {
454 sb.append( it.next().toString() ).append( '\n' );
455 }
456 }
457
458
459
460
461
462
463
464
465
466
467
468 private static List toLines( String text, int indent, int indentSize, int lineLength )
469 {
470 List lines = new ArrayList();
471
472 String ind = repeat( "\t", indent );
473 String[] plainLines = text.split( "(\r\n)|(\r)|(\n)" );
474 for ( int i = 0; i < plainLines.length; i++ )
475 {
476 toLines( lines, ind + plainLines[i], indentSize, lineLength );
477 }
478
479 return lines;
480 }
481
482
483
484
485
486
487
488
489
490 private static void toLines( List lines, String line, int indentSize, int lineLength )
491 {
492 int lineIndent = getIndentLevel( line );
493 StringBuffer buf = new StringBuffer( 256 );
494 String[] tokens = line.split( " +" );
495 for ( int i = 0; i < tokens.length; i++ )
496 {
497 String token = tokens[i];
498 if ( i > 0 )
499 {
500 if ( buf.length() + token.length() >= lineLength )
501 {
502 lines.add( buf.toString() );
503 buf.setLength( 0 );
504 buf.append( repeat( " ", lineIndent * indentSize ) );
505 }
506 else
507 {
508 buf.append( ' ' );
509 }
510 }
511 for ( int j = 0; j < token.length(); j++ )
512 {
513 char c = token.charAt( j );
514 if ( c == '\t' )
515 {
516 buf.append( repeat( " ", indentSize - buf.length() % indentSize ) );
517 }
518 else if ( c == '\u00A0' )
519 {
520 buf.append( ' ' );
521 }
522 else
523 {
524 buf.append( c );
525 }
526 }
527 }
528 lines.add( buf.toString() );
529 }
530
531
532
533
534
535
536
537 private static int getIndentLevel( String line )
538 {
539 int level = 0;
540 for ( int i = 0; i < line.length() && line.charAt( i ) == '\t'; i++ )
541 {
542 level++;
543 }
544 for ( int i = level + 1; i <= level + 4 && i < line.length(); i++ )
545 {
546 if ( line.charAt( i ) == '\t' )
547 {
548 level++;
549 break;
550 }
551 }
552 return level;
553 }
554 }