protected boolean isTemplateLine(Line line) {
   ProcessedRichString string = line.getRichString();
   if (string.getLines().size() == 1) {
     return false;
   }
   boolean firstOrLast = string.getLines().get(0) == line;
   if (!firstOrLast) {
     if (string.getLines().get(string.getLines().size() - 1) == line) {
       if (!(line.getParts().get(line.getParts().size() - 1) instanceof LineBreak))
         firstOrLast = true;
     }
   }
   boolean onlyLiterals = true;
   for (LinePart part : line.getParts()) {
     if (part instanceof PrintedExpression) return false;
     if (part instanceof Literal) {
       Literal literal = (Literal) part;
       if (literal instanceof LineBreak) {
         if (firstOrLast) return onlyLiterals;
         return !onlyLiterals;
       }
       if (!(new TextLine(
               literal.getLiteral().getValue(), literal.getOffset(), literal.getLength(), 0)
           .containsOnlyWhitespace())) return false;
     } else if (firstOrLast) {
       return false;
     } else {
       onlyLiterals = false;
     }
   }
   if (firstOrLast) return onlyLiterals;
   return !onlyLiterals;
 }
 @Override
 public Boolean caseLiteral(Literal object) {
   if (announced == null || announced != object.getLiteral()) {
     acceptor.announceNextLiteral(object.getLiteral());
     announced = object.getLiteral();
   }
   Line line = object.getLine();
   TextLine textLine =
       new TextLine(
           Strings.emptyIfNull(object.getLiteral().getValue()),
           object.getOffset(),
           object.getLength(),
           0);
   CharSequence ws = textLine.getLeadingWhiteSpace();
   ProcessedRichString string = line.getRichString();
   boolean firstOrLast =
       string.getLines().get(0) == line
           || string.getLines().get(string.getLines().size() - 1) == line;
   if (isTemplateLine(line)) {
     if (line.getParts().get(0) == object) {
       if (!firstOrLast) {
         boolean followedByOpening = false;
         if (line.getParts().size() >= 2) {
           LinePart next = line.getParts().get(1);
           if (next instanceof ForLoopStart || next instanceof IfConditionStart) {
             followedByOpening = true;
           }
         }
         if (!followedByOpening) {
           pushSemanticIndentation(indentationHandler.getTotalIndentation());
         } else {
           pushSemanticIndentation(ws);
         }
       }
     }
     announceTemplateText(textLine, object.getLiteral());
   } else {
     if (skipCount <= 1) {
       firstOrLast = false;
       if (skipCount == 0 && line.getParts().get(0) == object) {
         if (textLine.length() == ws.length()) {
           for (int i = 1; i < line.getParts().size(); i++) {
             if (line.getParts().get(i) instanceof Literal
                 && !(line.getParts().get(i) instanceof LineBreak)) {
               Literal nextLiteralInSameLine = (Literal) line.getParts().get(i);
               TextLine nextLiteralLine =
                   new TextLine(
                       nextLiteralInSameLine.getLiteral().getValue(),
                       nextLiteralInSameLine.getOffset(),
                       nextLiteralInSameLine.getLength(),
                       0);
               CharSequence nextLeading = nextLiteralLine.getLeadingWhiteSpace();
               if (nextLeading.length() > 0) {
                 ws = ws.toString() + nextLeading;
               }
               skipCount++;
               if (nextLeading.length() != nextLiteralLine.length()) {
                 break;
               }
             } else {
               break;
             }
           }
           if (skipCount != 0) {
             pushSemanticIndentation(ws);
           } else {
             pushSemanticIndentation(ws);
             announceIndentation();
             announceSemanticText(
                 textLine.subSequence(ws.length(), textLine.length()), object.getLiteral());
           }
         } else {
           pushSemanticIndentation(ws);
           announceIndentation();
           announceSemanticText(
               textLine.subSequence(ws.length(), textLine.length()), object.getLiteral());
         }
       } else {
         if (skipCount == 1) {
           skipCount--;
           announceIndentation();
           announceSemanticText(
               textLine.subSequence(ws.length(), textLine.length()), object.getLiteral());
         } else {
           announceSemanticText(textLine, object.getLiteral());
         }
       }
     } else {
       skipCount--;
     }
   }
   if (!firstOrLast && line.getParts().get(line.getParts().size() - 1) == object) {
     popIndentation();
   }
   computeNextPart(object);
   return Boolean.TRUE;
 }