Skip to content

Commit 6e3b3d9

Browse files
authored
Merge pull request #4 from darvil82/dev
Add true color and `NO_COLOR=1` support.
2 parents af3331f + 174fe0d commit 6e3b3d9

File tree

8 files changed

+226
-60
lines changed

8 files changed

+226
-60
lines changed

README.md

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
# Terminal Text Formatter
22

3-
Text formatting utilities to easily format text on the terminal for Java.
3+
Text formatting utilities to easily format text in the terminal for Java.
4+
5+
6+
## Usage Example
7+
8+
```java
9+
var text = TextFormatter.of("blue text here, ", TrueColor.of(50, 50, 255))
10+
.addFormat(FormatOption.BOLD, FormatOption.ITALIC)
11+
.concat(TextFormatter.of("now yellow", SimpleColor.BRIGHT_YELLOW))
12+
.concat(" and back to blue");
13+
14+
System.out.println(text);
15+
```
16+
17+
Javadocs for the latest stable version are provided online [here](https://darvil82.github.io/java-terminal-text-formatter/).
18+
419

520
## Installation
621

@@ -17,4 +32,4 @@ The package is currently available on Repsy and GitHub Packages.
1732
```
1833
> [!NOTE]
1934
> The `+` symbol is a wildcard that will automatically use the latest version of the package.
20-
> You can also specify a specific version (e.g. `0.0.1`).
35+
> You can also specify a specific version (e.g. `0.0.1`).

build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
}
55

66
group = "com.darvil"
7-
version = "2.0.0b"
7+
version = "2.1.0"
88
description = "Text formatting utilities to easily format text on the terminal for Java."
99

1010
dependencies {

src/main/java/module-info.java

+1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
requires org.jetbrains.annotations;
44

55
exports textFormatter;
6+
exports textFormatter.color;
67
}

src/main/java/textFormatter/TextFormatter.java

+38-12
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
import org.jetbrains.annotations.NotNull;
44
import org.jetbrains.annotations.Nullable;
5+
import textFormatter.color.Color;
6+
import textFormatter.color.SimpleColor;
57

68
import java.util.ArrayList;
79
import java.util.Arrays;
810
import java.util.List;
911

1012
/**
11-
* Allows to easily format text for display in a terminal.
13+
* Allows easily formatting of text for it to be displayed in a terminal.
1214
* <p>
1315
* Multiple formatters can be concatenated together. This is useful for when you want to
1416
* format a string that has multiple parts that need to be formatted differently.
@@ -18,14 +20,17 @@ public class TextFormatter {
1820
/**
1921
* When set to {@code false}, no formatting will be applied to text. Raw text will be generated without any
2022
* color or formatting.
23+
* <p>
24+
* This will be set to {@code false} if the environment variable {@code NO_COLOR} is set.
25+
* @see #isColorDisabledEnv()
2126
*/
22-
public static boolean enableSequences = true;
27+
public static boolean enableSequences = !TextFormatter.isColorDisabledEnv();
2328

2429
/**
2530
* The default color that should be used when no foreground color is specified (if {@link #startWithDefaultColorIfNotDefined}
2631
* is set to {@code true}), or when the foreground color is reset.
2732
*/
28-
public static @NotNull Color defaultColor = Color.BRIGHT_WHITE;
33+
public static @NotNull Color defaultColor = SimpleColor.BRIGHT_WHITE;
2934

3035
/**
3136
* When set to {@code true}, the default color will be used when no foreground color is specified.
@@ -103,7 +108,7 @@ public static TextFormatter create() {
103108
* @return a new {@link TextFormatter} with the specified contents and the error formatting
104109
* */
105110
public static @NotNull TextFormatter error(@NotNull String msg) {
106-
return TextFormatter.of(msg, Color.BLACK, Color.BRIGHT_RED).addFormat(FormatOption.BOLD);
111+
return TextFormatter.of(msg, SimpleColor.BLACK, SimpleColor.BRIGHT_RED).addFormat(FormatOption.BOLD);
107112
}
108113

109114

@@ -287,7 +292,7 @@ else if (TextFormatter.startWithDefaultColorIfNotDefined && this.parent == null)
287292

288293
/**
289294
* Returns the {@link Color} that should properly reset the foreground color. This is determined by looking at the
290-
* parent formatters. If no parent formatter has a foreground color, then {@link Color#BRIGHT_WHITE} is returned.
295+
* parent formatters. If no parent formatter has a foreground color, then {@link SimpleColor#BRIGHT_WHITE} is returned.
291296
* @return the {@link Color} that should properly reset the foreground color
292297
*/
293298
private @Nullable Color getResetFgColor() {
@@ -359,19 +364,40 @@ else if (TextFormatter.startWithDefaultColorIfNotDefined && this.parent == null)
359364
}
360365

361366
/**
362-
* Returns a string with a terminal sequence with the specified code.
363-
* (e.g. {@code "ESC[<code here>m"})
367+
* Returns a string with a terminal sequence with the specified values, separated by a semicolon.
368+
* (e.g. {@code "ESC[<values here>m"})
364369
* <p>
365370
* If {@link #debug} is set to {@code true}, then the text "ESC" will be used instead of the actual escape
366371
* character.
367372
* </p>
368-
* @param code The code of the sequence.
369-
* @return a string with a terminal sequence with the specified code
373+
* If {@link #enableSequences} is set to {@code false}, then an empty string will be returned.
374+
* @param values The values to add to the terminal sequence.
375+
* @return a string with a terminal sequence with the specified values
370376
*/
371-
static @NotNull String getSequence(int code) {
377+
public static @NotNull String getSequence(@NotNull Object... values) {
378+
if (!TextFormatter.enableSequences)
379+
return "";
380+
381+
var joined = String.join(
382+
";",
383+
Arrays.stream(values)
384+
.map(Object::toString)
385+
.toArray(String[]::new)
386+
);
387+
372388
if (TextFormatter.debug)
373-
return "ESC[" + code + "]";
374-
return "" + ESC + '[' + code + 'm';
389+
return "ESC[" + joined + "]";
390+
return "" + ESC + '[' + joined + 'm';
391+
}
392+
393+
/**
394+
* Returns whether there is an environment variable that specifies that
395+
* the terminal does not support color.
396+
* <a href="https://no-color.org/">NO_COLOR.org</a>
397+
* @return {@code true} if the terminal supports color
398+
*/
399+
public static boolean isColorDisabledEnv() {
400+
return System.getenv("NO_COLOR") != null;
375401
}
376402

377403
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package textFormatter.color;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
5+
public interface Color {
6+
/**
7+
* Returns the ANSI escape sequence for this color for the text foreground.
8+
* @return The ANSI escape sequence for this color.
9+
*/
10+
@NotNull String fg();
11+
12+
/**
13+
* Returns the ANSI escape sequence for this color for the text background.
14+
* @return The ANSI escape sequence for this color.
15+
*/
16+
@NotNull String bg();
17+
18+
/**
19+
* Returns the ANSI escape sequence for this color for the text foreground.
20+
* @return The ANSI escape sequence for this color.
21+
* @see SimpleColor#fg()
22+
*/
23+
@NotNull String toString();
24+
}

src/main/java/textFormatter/Color.java renamed to src/main/java/textFormatter/color/SimpleColor.java

+11-25
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
package textFormatter;
1+
package textFormatter.color;
22

33
import org.jetbrains.annotations.NotNull;
4+
import textFormatter.TextFormatter;
45

56
/**
67
* Enumerates the ANSI color codes that a terminal can normally display.
78
*/
8-
public enum Color {
9+
public enum SimpleColor implements Color {
910
BLACK(30),
1011
RED(31),
1112
GREEN(32),
@@ -25,40 +26,27 @@ public enum Color {
2526

2627
private final byte value;
2728

28-
Color(int value) {
29+
SimpleColor(int value) {
2930
this.value = (byte)value;
3031
}
3132

32-
/**
33-
* Returns the ANSI escape sequence for this color for the text foreground.
34-
* @return The ANSI escape sequence for this color.
35-
*/
33+
@Override
3634
public @NotNull String fg() {
3735
return TextFormatter.getSequence(this.value);
3836
}
3937

40-
/**
41-
* Returns the ANSI escape sequence for this color for the text background.
42-
* @return The ANSI escape sequence for this color.
43-
*/
38+
@Override
4439
public @NotNull String bg() {
4540
return TextFormatter.getSequence(this.value + 10);
4641
}
4742

48-
/**
49-
* Returns the ANSI escape sequence for this color for the text foreground.
50-
* @return The ANSI escape sequence for this color.
51-
* @see Color#fg()
52-
*/
5343
@Override
54-
public String toString() {
44+
public @NotNull String toString() {
5545
return this.fg();
5646
}
5747

58-
/**
59-
* Immutable list of all the dark colors.
60-
*/
61-
public static final @NotNull Color[] BRIGHT_COLORS = {
48+
/** Array of all the bright colors. */
49+
public static final @NotNull SimpleColor[] BRIGHT_COLORS = {
6250
BRIGHT_RED,
6351
BRIGHT_GREEN,
6452
BRIGHT_YELLOW,
@@ -68,10 +56,8 @@ public String toString() {
6856
BRIGHT_WHITE
6957
};
7058

71-
/**
72-
* Immutable list of all the bright colors.
73-
*/
74-
public static final @NotNull Color[] DARK_COLORS = {
59+
/** Array of all the dark colors. */
60+
public static final @NotNull SimpleColor[] DARK_COLORS = {
7561
RED,
7662
GREEN,
7763
YELLOW,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package textFormatter.color;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
import textFormatter.TextFormatter;
5+
6+
/**
7+
* Represents a true color in the RGB color space.
8+
* <p>
9+
* <strong>Note:</strong> Support for true color is not universal. Expect this implementation to work in
10+
* most modern terminals, but not all.
11+
*/
12+
public class TrueColor implements Color {
13+
/** The color black. */
14+
public static final TrueColor BLACK = TrueColor.of(0, 0, 0);
15+
/** The color red. */
16+
public static final TrueColor RED = TrueColor.of(255, 0, 0);
17+
/** The color green. */
18+
public static final TrueColor GREEN = TrueColor.of(0, 255, 0);
19+
/** The color yellow. */
20+
public static final TrueColor YELLOW = TrueColor.of(255, 255, 0);
21+
/** The color blue. */
22+
public static final TrueColor BLUE = TrueColor.of(0, 0, 255);
23+
/** The color magenta. */
24+
public static final TrueColor MAGENTA = TrueColor.of(255, 0, 255);
25+
/** The color cyan. */
26+
public static final TrueColor CYAN = TrueColor.of(0, 255, 255);
27+
/** The color white. */
28+
public static final TrueColor WHITE = TrueColor.of(255, 255, 255);
29+
30+
31+
private final byte r, g, b;
32+
33+
private TrueColor(byte r, byte g, byte b) {
34+
this.r = r;
35+
this.g = g;
36+
this.b = b;
37+
}
38+
39+
/**
40+
* Creates a new TrueColor object with the given RGB components.
41+
* @param r The red component, in the range 0-255.
42+
* @param g The green component, in the range 0-255.
43+
* @param b The blue component, in the range 0-255.
44+
* @return A new TrueColor object with the given RGB components.
45+
* @throws IllegalArgumentException If any of the color components are not in the range 0-255.
46+
*/
47+
public static @NotNull TrueColor of(int r, int g, int b) {
48+
if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) {
49+
throw new IllegalArgumentException("Color components must be in the range 0-255");
50+
}
51+
return new TrueColor((byte)r, (byte)g, (byte)b);
52+
}
53+
54+
/**
55+
* Creates a new TrueColor object with the given RGB components packed into a single integer.
56+
* @param rgb The RGB components packed into a single integer.
57+
* @return A new TrueColor object with the given RGB components.
58+
*/
59+
public static @NotNull TrueColor of(int rgb) {
60+
return of((rgb >> 16) & 0xff, (rgb >> 8) & 0xff, rgb & 0xff);
61+
}
62+
63+
/**
64+
* Returns the red component of this color.
65+
* @return The red component of this color.
66+
*/
67+
public byte r() {
68+
return this.r;
69+
}
70+
71+
/**
72+
* Returns the green component of this color.
73+
* @return The green component of this color.
74+
*/
75+
public byte g() {
76+
return this.g;
77+
}
78+
79+
/**
80+
* Returns the blue component of this color.
81+
* @return The blue component of this color.
82+
*/
83+
public byte b() {
84+
return this.b;
85+
}
86+
87+
@Override
88+
public @NotNull String fg() {
89+
return this.getSequence(true);
90+
}
91+
92+
@Override
93+
public @NotNull String bg() {
94+
return this.getSequence(false);
95+
}
96+
97+
private @NotNull String getSequence(boolean fg) {
98+
return TextFormatter.getSequence(fg ? 38 : 48, 2, (this.r & 0xff), (this.g & 0xff), (this.b & 0xff));
99+
}
100+
101+
@Override
102+
public @NotNull String toString() {
103+
return this.fg();
104+
}
105+
}

0 commit comments

Comments
 (0)