Namefie
Namefie

Reputation: 137

How to apply indentation to all lines when injecting multi-line strings in formatted text blocks

I started using Java 15 text blocks which are nice for readability. Now I want to format text blocks and inject strings in them, and from what I understand the idiomatic way to do this right now is to use String::formatted. But it seems that source-code indentation in text blocks is a bit limited when injecting multi-line strings.

For example, the following program:

class Scratch {

    public static void main(String[] args) {

        String text = """
            Hello!
            This is a text block!
            """;

        System.out.println(text);

    }

}

prints the two lines without any indentation, as expected:

Hello!
This is a text block!

However, this one:

class Scratch {

    public static void main(String[] args) {

        String text = """
            Hello!
            This is a text block!
            """;

        String wrapperText = """
            Hello again, now I'd like the entire text below to be indented with a single tab:
                %s
            """.formatted(text);

        System.out.println(wrapperText);

    }

}

prints the following:

Hello again, now I'd like the entire text below to be indented with a single tab:
    Hello!
This is a text block!

whereas I was kind of hoping to get the following:

Hello again, now I'd like the entire text below to be indented with a single tab:
    Hello!
    This is a text block!

I do realize that the problem has nothing to do with the fact that text is a text block in my second program, it might as well have been a traditional string literal with a new line character \n, and the outcome would have been the same. The wrapper text block clearly only applies the indentation to the first line of the injected multi-line string, which is understandable as it is probably just appending the injected string as it is after the indentation.

So I guess my question is: is there a clean way to apply the indentation specified in the wrapper text block to all lines of the injected string?

I know I could do something like .formatted(text.replaceAll("\n", "\n\t")) to format the text block, but that is clumsy, makes assumptions about the line termination sequence, and defeats the purpose of having the indentation specified in one place, cause then if I want to update the indentation, I would need to do it both in the text block and in the replacement string.

Upvotes: 3

Views: 1970

Answers (1)

Gilbert Le Blanc
Gilbert Le Blanc

Reputation: 51445

I use Java 8. Here's one method to indent a multi-line String.

Here are the test results from one of my tests.

Hello!
This is a text block!

Hello again, now I'd like the entire text below to be indented with 4 spaces:
    Hello!
    This is a text block!

You may have to adjust the indent method to work with Java 15.

Here's the complete runnable code.

public class TextIndentationTesting {

    public static void main(String[] args) {
        TextIndentationTesting tit = new TextIndentationTesting();

        String text = "Hello!\nThis is a text block!";
        System.out.println(text);
        System.out.println();

        String wrapperText = "Hello again, now I'd like the entire text below "
                + "to be indented with 4 spaces:";
        System.out.println(wrapperText + "\n" + tit.indent(text, 4));
    }

    public String indent(String text, int indentation) {
        // Create the indent space
        StringBuilder indentBuilder = new StringBuilder();
        for (int index = 0; index < indentation; index++) {
            indentBuilder.append(' ');
        }
        String indentSpace = indentBuilder.toString();

        // Indent the text
        String lineSeparator = Character.toString((char) 10);
        String replacement = lineSeparator + indentSpace;
        text = text.replaceAll(lineSeparator, replacement);

        return indentSpace + text;
    }

}

Upvotes: 0

Related Questions