3838import java .util .Collection ;
3939import java .util .HashSet ;
4040import java .util .List ;
41+ import java .util .Map ;
4142import java .util .Set ;
43+ import java .util .concurrent .atomic .AtomicReference ;
4244import java .util .regex .Matcher ;
4345import java .util .regex .Pattern ;
4446import lombok .Data ;
@@ -344,9 +346,10 @@ private String extractHashPrefixedDirective(final String line,
344346 }
345347
346348
347- private String extractDoubleDollarPrefixedDirective (final String line ,
348- final boolean block ,
349- final PreprocessorContext context ) {
349+ private String extractDoubleDollarPrefixedDirective (
350+ final String line ,
351+ final boolean block ,
352+ final PreprocessorContext context ) {
350353 String tail ;
351354 if (context .isAllowWhitespaces ()) {
352355 final Matcher matcher = block ? DIRECTIVE_TWO_DOLLARS_BLOCK_PREFIXED .matcher (line ) :
@@ -401,11 +404,17 @@ private String extractSingleDollarPrefixedDirective(final String line,
401404 return tail ;
402405 }
403406
404- private void flushTextBufferForRemovedComments (final StringBuilder textBuffer ,
405- final ResetablePrinter resetablePrinter ,
406- final PreprocessingState state ,
407- final PreprocessorContext context )
407+ private void flushTextBufferForRemovedComments (
408+ final AtomicReference <Map .Entry <String , String >> firstDetectedUncommentLinePtr ,
409+ final StringBuilder textBuffer ,
410+ final ResetablePrinter resetablePrinter ,
411+ final PreprocessingState state ,
412+ final PreprocessorContext context )
408413 throws IOException {
414+
415+ final Map .Entry <String , String > firstUncommentLine =
416+ firstDetectedUncommentLinePtr .getAndSet (null );
417+
409418 if (textBuffer .length () > 0 ) {
410419 final List <CommentTextProcessor > processors = context .getCommentTextProcessors ();
411420 final String origText = textBuffer .toString ();
@@ -415,7 +424,9 @@ private void flushTextBufferForRemovedComments(final StringBuilder textBuffer,
415424 if (!processors .isEmpty ()) {
416425 processors .forEach (x -> {
417426 try {
418- final String result = x .onUncommentText (origText , this , context , state );
427+ final String result = x .onUncommentText (
428+ firstUncommentLine == null ? 0 : firstUncommentLine .getKey ().length (), origText ,
429+ this , context , state );
419430 textBuffer .append (result );
420431 } catch (Exception ex ) {
421432 throw new PreprocessorException (
@@ -486,6 +497,9 @@ public PreprocessingState preprocessFileWithNotification(final PreprocessingStat
486497 final StringBuilder textBlockBuffer = new StringBuilder ();
487498
488499 try {
500+ final AtomicReference <Map .Entry <String , String >> firstUncommentLine =
501+ new AtomicReference <>();
502+
489503 while (!Thread .currentThread ().isInterrupted ()) {
490504 final ResetablePrinter thePrinter =
491505 requireNonNull (preprocessingState .getPrinter (), "Printer must be defined" );
@@ -510,7 +524,8 @@ public PreprocessingState preprocessFileWithNotification(final PreprocessingStat
510524 }
511525
512526 if (rawString == null ) {
513- this .flushTextBufferForRemovedComments (textBlockBuffer , thePrinter , preprocessingState ,
527+ this .flushTextBufferForRemovedComments (firstUncommentLine , textBlockBuffer , thePrinter ,
528+ preprocessingState ,
514529 context );
515530 lastTextFileDataContainer = preprocessingState .popTextContainer ();
516531 if (preprocessingState .isIncludeStackEmpty ()) {
@@ -539,7 +554,8 @@ public PreprocessingState preprocessFileWithNotification(final PreprocessingStat
539554 final boolean doPrintLn = presentedNextLine || !context .isCareForLastEol ();
540555
541556 if (isHashPrefixed (stringToBeProcessed , context )) {
542- this .flushTextBufferForRemovedComments (textBlockBuffer , thePrinter , preprocessingState ,
557+ this .flushTextBufferForRemovedComments (firstUncommentLine , textBlockBuffer , thePrinter ,
558+ preprocessingState ,
543559 context );
544560 final String extractedDirective =
545561 extractHashPrefixedDirective (stringToBeProcessed , context );
@@ -585,51 +601,77 @@ public PreprocessingState preprocessFileWithNotification(final PreprocessingStat
585601 }
586602
587603 if (startsWithTwoDollars ) {
588- // Output the tail of the string to the output stream without comments and macroses
589- final String text =
590- extractDoubleDollarPrefixedDirective (leftTrimmedString , false , context );
604+ // Output the tail of the string to the output stream without comments and macros
605+ String text = extractDoubleDollarPrefixedDirective (leftTrimmedString , false , context );
606+ Map .Entry <String , String > indentText =
607+ Map .entry (context .isPreserveIndents () ? stringPrefix : "" , text );
608+ final boolean firstLineSet = firstUncommentLine .compareAndSet (null , indentText );
609+
591610 if (context .isAllowsBlocks () &&
592611 isDoubleDollarBlockPrefixed (leftTrimmedString , context .isAllowWhitespaces ())) {
593- textBlockBuffer .append (
594- extractDoubleDollarPrefixedDirective (leftTrimmedString , true , context ));
612+ text =
613+ extractDoubleDollarPrefixedDirective (leftTrimmedString , true , context );
614+ indentText = Map .entry (context .isPreserveIndents () ? stringPrefix : "" , text );
615+
616+ if (firstLineSet ) {
617+ firstUncommentLine .set (indentText );
618+ }
619+ textBlockBuffer .append (indentText .getValue ());
595620 if (doPrintLn ) {
596621 textBlockBuffer .append (context .getEol ());
597622 }
598623 } else {
599- this .flushTextBufferForRemovedComments (textBlockBuffer , thePrinter ,
624+ this .flushTextBufferForRemovedComments (firstUncommentLine , textBlockBuffer ,
625+ thePrinter ,
600626 preprocessingState , context );
601- textBlockBuffer .append (stringPrefix ).append (text );
627+ textBlockBuffer .append (stringPrefix ).append (indentText .getKey ())
628+ .append (indentText .getValue ());
602629 if (doPrintLn ) {
603630 textBlockBuffer .append (context .getEol ());
604631 }
605- this .flushTextBufferForRemovedComments (textBlockBuffer , thePrinter ,
632+ this .flushTextBufferForRemovedComments (firstUncommentLine , textBlockBuffer ,
633+ thePrinter ,
606634 preprocessingState , context );
607635 }
608636 } else if (isSingleDollarPrefixed (stringToBeProcessed , context .isAllowWhitespaces ())) {
609637 // Output the tail of the string to the output stream without comments
610- final String text =
638+ String text =
611639 extractSingleDollarPrefixedDirective (stringToBeProcessed , false , context );
640+ Map .Entry <String , String > indentText =
641+ Map .entry (context .isPreserveIndents () ? stringPrefix : "" , text );
642+ final boolean firstLineSet = firstUncommentLine .compareAndSet (null , indentText );
612643
613644 if (context .isAllowsBlocks () &&
614645 isDollarBlockPrefixed (stringToBeProcessed , context .isAllowWhitespaces ())) {
615- textBlockBuffer .append (
616- extractSingleDollarPrefixedDirective (stringToBeProcessed , true , context ));
646+ text =
647+ extractSingleDollarPrefixedDirective (stringToBeProcessed , true , context );
648+ indentText = Map .entry (context .isPreserveIndents () ? stringPrefix : "" , text );
649+
650+ if (firstLineSet ) {
651+ firstUncommentLine .set (indentText );
652+ }
653+
654+ textBlockBuffer .append (indentText .getValue ());
617655 if (doPrintLn ) {
618656 textBlockBuffer .append (context .getEol ());
619657 }
620658 } else {
621- this .flushTextBufferForRemovedComments (textBlockBuffer , thePrinter ,
659+ this .flushTextBufferForRemovedComments (firstUncommentLine , textBlockBuffer ,
660+ thePrinter ,
622661 preprocessingState , context );
623- textBlockBuffer .append (stringPrefix ).append (text );
662+ textBlockBuffer .append (stringPrefix ).append (indentText .getKey ())
663+ .append (indentText .getValue ());
624664 if (doPrintLn ) {
625665 textBlockBuffer .append (context .getEol ());
626666 }
627- this .flushTextBufferForRemovedComments (textBlockBuffer , thePrinter ,
667+ this .flushTextBufferForRemovedComments (firstUncommentLine , textBlockBuffer ,
668+ thePrinter ,
628669 preprocessingState , context );
629670 }
630671 } else {
631672 // Just string
632- this .flushTextBufferForRemovedComments (textBlockBuffer , thePrinter ,
673+ this .flushTextBufferForRemovedComments (firstUncommentLine , textBlockBuffer ,
674+ thePrinter ,
633675 preprocessingState , context );
634676
635677 final String strToOut = findTailRemover (stringToBeProcessed , context );
@@ -649,7 +691,8 @@ public PreprocessingState preprocessFileWithNotification(final PreprocessingStat
649691 }
650692 }
651693 } else if (context .isKeepLines ()) {
652- flushTextBufferForRemovedComments (textBlockBuffer , thePrinter , preprocessingState ,
694+ flushTextBufferForRemovedComments (firstUncommentLine , textBlockBuffer , thePrinter ,
695+ preprocessingState ,
653696 context );
654697 final String text = AbstractDirectiveHandler .PREFIX_FOR_KEEPING_LINES + rawString ;
655698 if (doPrintLn ) {
0 commit comments