diff --git a/.idea/discord.xml b/.idea/discord.xml index 30bab2a..d8e9561 100644 --- a/.idea/discord.xml +++ b/.idea/discord.xml @@ -1,7 +1,7 @@ - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 21885aa..82dbec8 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,7 +8,7 @@ - + \ No newline at end of file diff --git a/README.md b/README.md index 6e3e31e..db17962 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,12 @@ ### Features: - Support text color. - Support background color. + - Support 256 colors (RGB). + - Support ANSI colors. + - Support indexed colors. - Support text style. + - Lightweight and fast. + - Easy to use. ### How to add this library into your project **Step 1**. Add the dependency @@ -17,7 +22,6 @@ 0.1.5 ``` -**Step 2**. run this command `mvn install` #### Gradle: **Step 1**. Add the JitPack repository to your build file
@@ -37,43 +41,30 @@ allprojects { } ``` -### Usage: -```java -ConsoleManager manager = new DefaultConsoleManager(); // Create a new console manager -manager.setTextColor(TextColor.LIGHT_RED); // Set text color -manager.setBackgroundColor(BackgroundColor.DARK_BLUE); // Set background color - -manager.println("Hello World!"); // Print text -``` - +## Usage: -```java -ConsoleManager manager = new DefaultConsoleManager(); // Create a new console manager -manager.setTextColor(TextColor.LIGHT_RED); // Set text color -manager.setBackgroundColor(BackgroundColor.DARK_BLUE); // Set background color -manager.setTextStyle(TextStyle.ITALIC); // Set text style +## Requirements for development: +- Maven +- jdk 17 +- IntelliJ IDEA (not required but recommended) -manager.println("Hello World!"); // Print text -``` - +## TODO +- [ ] Add Tests +- [ ] Add Formatter +- [ ] Add Documentation +- [ ] Add more examples -```java -public class Example1 { - public static void main(String[] args) { - ConsoleManager manager = new DefaultConsoleManager(); +### Available in - manager.print("Hello", BackgroundColor.DARK_YELLOW, TextColor.DARK_WHITE, TextStyle.BOLD, TextStyle.ITALIC); - manager.print(", ", TextColor.LIGHT_GREEN); - manager.print("I'm ", TextColor.DARK_YELLOW); - manager.print("Anas", TextColor.LIGHT_BLUE, TextStyle.DOUBLE_UNDERLINE); - manager.println(" :D", TextColor.LIGHT_CYAN); - manager.println("\tFrom", TextColor.LIGHT_RED, TextStyle.ITALIC); - manager.print("Eg", BackgroundColor.LIGHT_RED); - manager.print("y", BackgroundColor.DARK_WHITE); - manager.print("pt", BackgroundColor.DARK_BLACK); - } -} -``` - +[![GitHub](https://img.shields.io/badge/GitHub-Main%20repo-brightgreen?style=for-the-badge&logo=GitHub)](https://github.com/Anas-Elgarhy/jpwd) +[![GitLab](https://img.shields.io/badge/GitLab-Mirror%20repo-brightgreen?style=for-the-badge&logo=GitLab)](https://gitlab.com/java-utils1/jpwd) +[![BitBucket](https://img.shields.io/badge/BitBucket-Mirror%20repo-brightgreen?style=for-the-badge&logo=BitBucket)](https://bitbucket.org/anas_elgarhy/jpwd) +[![Codeberg](https://img.shields.io/badge/Codeberg-Mirror%20repo-brightgreen?style=for-the-badge&logo=Codeberg)](https://codeberg.org/java-utils/jpwd) -#### License: MIT \ No newline at end of file + +[![Quality gate](https://sonarcloud.io/api/project_badges/quality_gate?project=Anas-Elgarhy_jpwd)](https://sonarcloud.io/summary/new_code?id=Anas-Elgarhy_jpwd) + + +[![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-black.svg)](https://sonarcloud.io/summary/new_code?id=Anas-Elgarhy_jpwd) + +![License: GPL-3.0](https://img.shields.io/badge/License-GPL%203.0-blue.svg) diff --git a/pom.xml b/pom.xml index c9e500a..5b79ed8 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.anas.jcolorfulconsole jcolorfulconsole - 0.1.5 + 1.0.0 jar JColorfulConsole @@ -16,7 +16,7 @@ github - GitHub OWNER Apache Maven Packages + GitHub Anas Elgarhy Apache Maven Packages https://maven.pkg.github.com/Anas-Elgarhy/JColorfulConsole @@ -28,16 +28,16 @@ maven-compiler-plugin 3.2 - 1.8 - 1.8 + 8 + 8 - 18 - 18 + 17 + 17 \ No newline at end of file diff --git a/src/main/java/com/anas/jcolorfulconsole/ColoredString.java b/src/main/java/com/anas/jcolorfulconsole/ColoredString.java new file mode 100644 index 0000000..35bf080 --- /dev/null +++ b/src/main/java/com/anas/jcolorfulconsole/ColoredString.java @@ -0,0 +1,237 @@ +package com.anas.jcolorfulconsole; + +import com.anas.jcolorfulconsole.lanterna.TextColor; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; + +public class ColoredString { + private byte[] strBytes; + private TextColor foregroundColor; + private TextColor backgroundColor; + private ArrayList styles; + + /** + * Create a new empty ColoredString object + */ + public ColoredString() { + this(null); + } + + /** + * Create a new ColoredString object with the given string + * @param str The string to be colored + * @param styles The styles to be applied to the string (optional) + */ + public ColoredString(String str, TextStyle... styles) { + this(str, (TextColor) null, styles); + } + + /** + * Create a new ColoredString object with the given string and foreground color + * @param str The string to be colored + * @param foregroundColor The foreground color to be applied to the string + * @param styles The styles to be applied to the string (optional) + */ + public ColoredString(String str, TextColor foregroundColor, TextStyle... styles) { + this(str, foregroundColor, null, styles); + } + + /** + * Create a new ColoredString object with the given string and foreground and background colors + * @param str The string to be colored + * @param foregroundColor The foreground color to be applied to the string + * @param backgroundColor The background color to be applied to the string + * @param styles The styles to be applied to the string (optional) + */ + public ColoredString(String str, TextColor foregroundColor, TextColor backgroundColor, TextStyle... styles) { + strBytes = str != null ? + str.getBytes(StandardCharsets.UTF_8) : null; + this.foregroundColor = foregroundColor; + this.backgroundColor = backgroundColor; + this.styles = null; + if (styles != null) { + this.styles = new ArrayList<>(); + this.styles.addAll(Arrays.asList(styles)); + } + } + + /** + * Create a new ColoredString object with the given string and foreground color as string of name of the color or hexadecimal color code + * @param str The string to be colored + * @param foregroundColor The foreground color to be applied to the string as string of name of the color or hexadecimal color code + * @param styles The styles to be applied to the string (optional) + */ + public ColoredString(String str, String foregroundColor, TextStyle... styles) { + this(str, foregroundColor, null, styles); + } + + /** + * Create a new ColoredString object with the given string and foreground and background colors as string of name of the color or hexadecimal color code + * @param str The string to be colored + * @param foregroundColor The foreground color to be applied to the string as string of name of the color or hexadecimal color code + * @param backgroundColor The background color to be applied to the string as string of name of the color or hexadecimal color code + * @param styles The styles to be applied to the string (optional) + */ + public ColoredString(String str, String foregroundColor, String backgroundColor, TextStyle... styles) { + this(str, + TextColor.Factory.fromString(foregroundColor), + TextColor.Factory.fromString(backgroundColor), + styles); + } + + /** + * Set the foreground color (text color) + * @param textColor The foreground color to be applied to the string + */ + public void setForegroundColor(TextColor textColor) { + this.foregroundColor = textColor; + } + + /** + * Set the foreground color (text color) as string of name of the color or hexadecimal color code + * @param textColor The foreground color to be applied to the string as string of name of the color or hexadecimal color code + */ + public void setForegroundColor(String textColor) { + this.setForegroundColor(TextColor.Factory.fromString(textColor)); + } + + /** + * Set the background color + * @param backgroundColor The background color to be applied to the string + */ + public void setBackgroundColor(TextColor backgroundColor) { + this.backgroundColor = backgroundColor; + } + + + /** + * Set the background color as string of name of the color or hexadecimal color code + * @param backgroundColor The background color to be applied to the string as string of name of the color or hexadecimal color code + */ + public void setBackgroundColor(String backgroundColor) { + this.setBackgroundColor(TextColor.Factory.fromString(backgroundColor)); + } + + /**' + * Get the foreground color (text color) + * @return The foreground color, null if not set + */ + public TextColor getForegroundColor() { + return foregroundColor; + } + + /** + * Get the background color + * @return The background color, null if not set + */ + public TextColor getBackgroundColor() { + return backgroundColor; + } + + /** + * Get the string as byte array + * @return The string as byte array + */ + public byte[] getBytes() { + return strBytes; + } + + /** + * Get the string with the applied styles and colors as byte array + * @return The string with the applied styles and colors as byte array + */ + public byte[] getColoredBytes() { + if (strBytes == null) { + return null; + } + return toString().getBytes(StandardCharsets.UTF_8); + } + + /** + * Set the string + * @param str The string to be colored + */ + public void setStr(String str) { + strBytes = str.getBytes(StandardCharsets.UTF_8); + } + + /** + * Add style to the string + * @param style The style to be applied to the string + */ + public void addStyle(TextStyle style) { + if (styles == null) { + styles = new ArrayList<>(); + } + styles.add(style); + } + + /** + * Remove style from the string + * @param style The style to be removed from the string + */ + public void removeStyle(TextStyle style) { + if (styles == null) { + return; + } + styles.remove(style); + } + + + /** + * Get the string with the applied styles and colors + * @return The string with the applied styles and colors + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + final String escapeSequenceOpen = "\u001b["; + final String escapeSequenceClose = "\u001b[0m"; + if (styles != null) { + for (TextStyle style : styles) { + sb.append(escapeSequenceOpen) + .append(style.getValue()) + .append("m"); + } + } + + if (foregroundColor != null) { + sb.append(escapeSequenceOpen); + sb.append(new String(foregroundColor.getForegroundSGRSequence(), StandardCharsets.UTF_8)); + sb.append("m"); + } + if (backgroundColor != null) { + sb.append(escapeSequenceOpen); + sb.append(new String(backgroundColor.getBackgroundSGRSequence(), StandardCharsets.UTF_8)); + sb.append("m"); + } + sb.append(this.toNormalStringString()); + + if (foregroundColor != null) { + sb.append(escapeSequenceClose); + } + + if (backgroundColor != null) { + sb.append(escapeSequenceClose); + } + + if (styles != null) { + for (int i = 0; i < styles.size(); i++) { + sb.append(escapeSequenceClose); + } + } + + return sb.toString(); + } + + /** + * Get the string without the applied styles and colors + * @return The string without the applied styles and colors + */ + public String toNormalStringString() { + return strBytes == null || strBytes.length < 1 ? + null : new String(strBytes, StandardCharsets.UTF_8); + } +} diff --git a/src/main/java/com/anas/jcolorfulconsole/ConsoleManager.java b/src/main/java/com/anas/jcolorfulconsole/ConsoleManager.java deleted file mode 100644 index 82ebb18..0000000 --- a/src/main/java/com/anas/jcolorfulconsole/ConsoleManager.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.anas.jcolorfulconsole; - -import com.anas.jcolorfulconsole.color.BackgroundColor; -import com.anas.jcolorfulconsole.color.TextColor; -import com.anas.jcolorfulconsole.style.TextStyle; - -public interface ConsoleManager { - void setTextColor(TextColor textColor); - void setBackgroundColor(BackgroundColor backgroundColor); - void setTextStyle(TextStyle textStyle); - void addProperty(ConsoleProperty property); - void removeProperty(ConsoleProperty property); - - void print(String text); - void print(String text, ConsoleProperty... properties); - void println(String text); - void println(String text, ConsoleProperty... properties); - void println(); - - void print(char c); - void print(char c, ConsoleProperty... properties); - void println(char c); - void println(char c, ConsoleProperty... properties); - - void print(int i); - void print(int i, ConsoleProperty... properties); - void println(int i); - void println(int i, ConsoleProperty... properties); - - void print(double d); - void print(double d, ConsoleProperty... properties); - void println(double d); - void println(double d, ConsoleProperty... properties); - - void print(boolean b); - void print(boolean b, ConsoleProperty... properties); - void println(boolean b); - void println(boolean b, ConsoleProperty... properties); - - void print(Object o); - void print(Object o, ConsoleProperty... properties); - void println(Object o); - void println(Object o, ConsoleProperty... properties); - - void printf(String format, Object... args); -} diff --git a/src/main/java/com/anas/jcolorfulconsole/ConsoleProperty.java b/src/main/java/com/anas/jcolorfulconsole/ConsoleProperty.java deleted file mode 100644 index 94a0478..0000000 --- a/src/main/java/com/anas/jcolorfulconsole/ConsoleProperty.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.anas.jcolorfulconsole; - -public interface ConsoleProperty { - public short getCode(); -} diff --git a/src/main/java/com/anas/jcolorfulconsole/TextStyle.java b/src/main/java/com/anas/jcolorfulconsole/TextStyle.java new file mode 100644 index 0000000..20c8316 --- /dev/null +++ b/src/main/java/com/anas/jcolorfulconsole/TextStyle.java @@ -0,0 +1,34 @@ +package com.anas.jcolorfulconsole; + +public enum TextStyle { + DEFAULT(10), + BOLD(1), + ITALIC(3), + UNDERLINE(4), + BLINK(5), + STRIKETHROUGH(9), + DOUBLE_UNDERLINE(21), + NORMAL_INTENSITY(22), + FRAKTUR(20), + ITALIC_INTENSITY(23), + UNDERLINE_INTENSITY(24), + BLINK_SLOW(25), + BLINK_FAST(26), + NEGATIVE_INTENSITY(27), + CONCEALED(28), + CROSSED_OUT(29), + FRAMED(54), + ENCIRCLED(51), + OVERLINED(53), + ; + + private final byte value; + + TextStyle(int value) { + this.value = (byte) value; + } + + public byte getValue() { + return value; + } +} diff --git a/src/main/java/com/anas/jcolorfulconsole/color/ASCIIColor.java b/src/main/java/com/anas/jcolorfulconsole/color/ASCIIColor.java deleted file mode 100644 index 459415a..0000000 --- a/src/main/java/com/anas/jcolorfulconsole/color/ASCIIColor.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.anas.jcolorfulconsole.color; - -import com.anas.jcolorfulconsole.ConsoleProperty; - -public class ASCIIColor implements ConsoleProperty { - private final short code; - - protected ASCIIColor(short code) { - this.code = code; - } - - public static final ASCIIColor DEFAULT = new ASCIIColor((short)0); - - @Override - public short getCode() { - return code; - } -} diff --git a/src/main/java/com/anas/jcolorfulconsole/color/BackgroundColor.java b/src/main/java/com/anas/jcolorfulconsole/color/BackgroundColor.java deleted file mode 100644 index d3cfdbc..0000000 --- a/src/main/java/com/anas/jcolorfulconsole/color/BackgroundColor.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.anas.jcolorfulconsole.color; - -public class BackgroundColor extends ASCIIColor { - - public static final BackgroundColor DARK_BLACK = new BackgroundColor((short)40); - public static final BackgroundColor DARK_RED = new BackgroundColor((short)41); - public static final BackgroundColor DARK_GREEN = new BackgroundColor((short)42); - public static final BackgroundColor DARK_YELLOW = new BackgroundColor((short)43); - public static final BackgroundColor DARK_BLUE = new BackgroundColor((short)44); - public static final BackgroundColor DARK_MAGENTA = new BackgroundColor((short)45); - public static final BackgroundColor DARK_CYAN = new BackgroundColor((short)46); - public static final BackgroundColor DARK_WHITE = new BackgroundColor((short)7); - public static final BackgroundColor DARK_GRAY = new BackgroundColor((short)47); - - - public static final BackgroundColor LIGHT_BLACK = new BackgroundColor((short)100); - public static final BackgroundColor LIGHT_RED = new BackgroundColor((short)101); - public static final BackgroundColor LIGHT_GREEN = new BackgroundColor((short)102); - public static final BackgroundColor LIGHT_YELLOW = new BackgroundColor((short)103); - public static final BackgroundColor LIGHT_BLUE = new BackgroundColor((short)104); - public static final BackgroundColor LIGHT_MAGENTA = new BackgroundColor((short)105); - public static final BackgroundColor LIGHT_CYAN = new BackgroundColor((short)106); - public static final BackgroundColor LIGHT_WHITE = new BackgroundColor((short)7); - public static final BackgroundColor LIGHT_GRAY = new BackgroundColor((short)107); - - public static final BackgroundColor DEFAULT = new BackgroundColor(ASCIIColor.DEFAULT.getCode()); - - protected BackgroundColor(short code) { - super(code); - } -} diff --git a/src/main/java/com/anas/jcolorfulconsole/color/TextColor.java b/src/main/java/com/anas/jcolorfulconsole/color/TextColor.java deleted file mode 100644 index e27fa3c..0000000 --- a/src/main/java/com/anas/jcolorfulconsole/color/TextColor.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.anas.jcolorfulconsole.color; - -public class TextColor extends ASCIIColor { - - public static final TextColor DARK_BLACK = new TextColor((short)30); - public static final TextColor DARK_RED = new TextColor((short)31); - public static final TextColor DARK_GREEN = new TextColor((short)32); - public static final TextColor DARK_YELLOW = new TextColor((short)33); - public static final TextColor DARK_BLUE = new TextColor((short)34); - public static final TextColor DARK_MAGENTA = new TextColor((short)35); - public static final TextColor DARK_CYAN = new TextColor((short)36); - public static final TextColor DARK_WHITE = new TextColor((short)0); - public static final TextColor DARK_GRY = new TextColor((short)47); - - public static final TextColor TRANSPARENT = new TextColor((short)2); - - public static final TextColor LIGHT_BLACK = new TextColor((short)90); - public static final TextColor LIGHT_RED = new TextColor((short)91); - public static final TextColor LIGHT_GREEN = new TextColor((short)92); - public static final TextColor LIGHT_YELLOW = new TextColor((short)93); - public static final TextColor LIGHT_BLUE = new TextColor((short)94); - public static final TextColor LIGHT_MAGENTA = new TextColor((short)95); - public static final TextColor LIGHT_CYAN = new TextColor((short)96); - public static final TextColor LIGHT_GRAY = new TextColor((short)97); - - public static final TextColor DEFAULT = new TextColor(ASCIIColor.DEFAULT.getCode()); - - - protected TextColor(short code) { - super(code); - } -} diff --git a/src/main/java/com/anas/jcolorfulconsole/lanterna/TextColor.java b/src/main/java/com/anas/jcolorfulconsole/lanterna/TextColor.java new file mode 100644 index 0000000..158663d --- /dev/null +++ b/src/main/java/com/anas/jcolorfulconsole/lanterna/TextColor.java @@ -0,0 +1,697 @@ +/* + * This file is part of lanterna (https://github.com/mabe02/lanterna). + * + * lanterna is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Copyright (C) 2010-2020 Martin Berglund + */ +package com.anas.jcolorfulconsole.lanterna; +import java.awt.Color; +import java.util.regex.Pattern; + +/** + * This is an abstract base class for terminal color definitions. Since there are different ways of specifying terminal + * colors, all with a different range of adoptions, this makes it possible to program an API against an implementation- + * agnostic color definition. Please remember when using colors that not all terminals and terminal emulators supports + * them. The 24-bit color mode is very unsupported, for example, and even the default Linux terminal doesn't support + * the 256-color indexed mode. + * + * @author Martin + */ +public interface TextColor { + /** + * Returns the byte sequence in between CSI and character 'm' that is used to enable this color as the foreground + * color on an ANSI-compatible terminal. + * @return Byte array out data to output in between of CSI and 'm' + */ + byte[] getForegroundSGRSequence(); + + /** + * Returns the byte sequence in between CSI and character 'm' that is used to enable this color as the background + * color on an ANSI-compatible terminal. + * @return Byte array out data to output in between of CSI and 'm' + */ + byte[] getBackgroundSGRSequence(); + + /** + * @return Red intensity of this color, from 0 to 255 + */ + int getRed() ; + + /** + * @return Green intensity of this color, from 0 to 255 + */ + int getGreen(); + + /** + * @return Blue intensity of this color, from 0 to 255 + */ + int getBlue(); + + /** + * Converts this color to an AWT color object, assuming a standard VGA palette. + * @return TextColor as an AWT Color + * @deprecated This adds a runtime dependency to the java.desktop module which isn't declared in the module + * descriptor of lanterna. If you want to call this method, make sure to add it to your module. + */ + @Deprecated + Color toColor(); + + /** + * This class represent classic ANSI colors that are likely to be very compatible with most terminal + * implementations. It is limited to 8 colors (plus the 'default' color) but as a norm, using bold mode (SGR code) + * will slightly alter the color, giving it a bit brighter tone, so in total this will give you 16 (+1) colors. + *

+ * For more information, see http://en.wikipedia.org/wiki/File:Ansi.png + */ + enum ANSI implements TextColor { + BLACK(0, 0, 0, 0), + RED(1, 170, 0, 0), + GREEN(2, 0, 170, 0), + YELLOW(3, 170, 85, 0), + BLUE(4, 0, 0, 170), + MAGENTA(5, 170, 0, 170), + CYAN(6, 0, 170, 170), + WHITE(7, 170, 170, 170), + DEFAULT(9, 0, 0, 0), + BLACK_BRIGHT(0, true, 85, 85, 85), + RED_BRIGHT(1, true, 255, 85, 85), + GREEN_BRIGHT(2, true, 85, 255, 85), + YELLOW_BRIGHT(3, true, 255, 255, 85), + BLUE_BRIGHT(4, true, 85, 85, 255), + MAGENTA_BRIGHT(5, true, 255, 85, 255), + CYAN_BRIGHT(6, true, 85, 255, 255), + WHITE_BRIGHT(7, true, 255, 255, 255); + + private final boolean bright; + private final int red; + private final int green; + private final int blue; + private final byte[] foregroundSGR; + private final byte[] backgroundSGR; + + ANSI(int index, int red, int green, int blue) { + this(index, false, red, green, blue); + } + + ANSI(int index, boolean bright, int red, int green, int blue) { + this.bright = bright; + this.red = red; + this.green = green; + this.blue = blue; + foregroundSGR = String.format("%d%d", bright ? 9 : 3, index).getBytes(); + backgroundSGR = String.format("%d%d", bright ? 10 : 4, index).getBytes(); + } + + @Override + public byte[] getForegroundSGRSequence() { + return foregroundSGR.clone(); + } + + @Override + public byte[] getBackgroundSGRSequence() { + return backgroundSGR.clone(); + } + + public boolean isBright() { + return bright; + } + + @Override + public int getRed() { + return red; + } + + @Override + public int getGreen() { + return green; + } + + @Override + public int getBlue() { + return blue; + } + + @Override + public Color toColor() { + return new Color(getRed(), getGreen(), getBlue()); + } + } + + /** + * This class represents a color expressed in the indexed XTerm 256 color extension, where each color is defined in a + * lookup-table. All in all, there are 256 codes, but in order to know which one to know you either need to have the + * table at hand, or you can use the two static helper methods which can help you convert from three 8-bit + * RGB values to the closest approximate indexed color number. If you are interested, the 256 index values are + * actually divided like this:
+ * 0 .. 15 - System colors, same as ANSI, but the actual rendered color depends on the terminal emulators color scheme
+ * 16 .. 231 - Forms a 6x6x6 RGB color cube
+ * 232 .. 255 - A gray scale ramp (without black and white endpoints)
+ *

+ * Support for indexed colors is somewhat widely adopted, not as much as the ANSI colors (TextColor.ANSI) but more + * than the RGB (TextColor.RGB). + *

+ * For more details on this, please see + * this commit message to Konsole. + */ + class Indexed implements TextColor { + private static final byte[][] COLOR_TABLE = new byte[][] { + //These are the standard 16-color VGA palette entries + {(byte)0,(byte)0,(byte)0 }, + {(byte)170,(byte)0,(byte)0 }, + {(byte)0,(byte)170,(byte)0 }, + {(byte)170,(byte)85,(byte)0 }, + {(byte)0,(byte)0,(byte)170 }, + {(byte)170,(byte)0,(byte)170 }, + {(byte)0,(byte)170,(byte)170 }, + {(byte)170,(byte)170,(byte)170 }, + {(byte)85,(byte)85,(byte)85 }, + {(byte)255,(byte)85,(byte)85 }, + {(byte)85,(byte)255,(byte)85 }, + {(byte)255,(byte)255,(byte)85 }, + {(byte)85,(byte)85,(byte)255 }, + {(byte)255,(byte)85,(byte)255 }, + {(byte)85,(byte)255,(byte)255 }, + {(byte)255,(byte)255,(byte)255 }, + + //Starting 6x6x6 RGB color cube from 16 + {(byte)0x00,(byte)0x00,(byte)0x00 }, + {(byte)0x00,(byte)0x00,(byte)0x5f }, + {(byte)0x00,(byte)0x00,(byte)0x87 }, + {(byte)0x00,(byte)0x00,(byte)0xaf }, + {(byte)0x00,(byte)0x00,(byte)0xd7 }, + {(byte)0x00,(byte)0x00,(byte)0xff }, + {(byte)0x00,(byte)0x5f,(byte)0x00 }, + {(byte)0x00,(byte)0x5f,(byte)0x5f }, + {(byte)0x00,(byte)0x5f,(byte)0x87 }, + {(byte)0x00,(byte)0x5f,(byte)0xaf }, + {(byte)0x00,(byte)0x5f,(byte)0xd7 }, + {(byte)0x00,(byte)0x5f,(byte)0xff }, + {(byte)0x00,(byte)0x87,(byte)0x00 }, + {(byte)0x00,(byte)0x87,(byte)0x5f }, + {(byte)0x00,(byte)0x87,(byte)0x87 }, + {(byte)0x00,(byte)0x87,(byte)0xaf }, + {(byte)0x00,(byte)0x87,(byte)0xd7 }, + {(byte)0x00,(byte)0x87,(byte)0xff }, + {(byte)0x00,(byte)0xaf,(byte)0x00 }, + {(byte)0x00,(byte)0xaf,(byte)0x5f }, + {(byte)0x00,(byte)0xaf,(byte)0x87 }, + {(byte)0x00,(byte)0xaf,(byte)0xaf }, + {(byte)0x00,(byte)0xaf,(byte)0xd7 }, + {(byte)0x00,(byte)0xaf,(byte)0xff }, + {(byte)0x00,(byte)0xd7,(byte)0x00 }, + {(byte)0x00,(byte)0xd7,(byte)0x5f }, + {(byte)0x00,(byte)0xd7,(byte)0x87 }, + {(byte)0x00,(byte)0xd7,(byte)0xaf }, + {(byte)0x00,(byte)0xd7,(byte)0xd7 }, + {(byte)0x00,(byte)0xd7,(byte)0xff }, + {(byte)0x00,(byte)0xff,(byte)0x00 }, + {(byte)0x00,(byte)0xff,(byte)0x5f }, + {(byte)0x00,(byte)0xff,(byte)0x87 }, + {(byte)0x00,(byte)0xff,(byte)0xaf }, + {(byte)0x00,(byte)0xff,(byte)0xd7 }, + {(byte)0x00,(byte)0xff,(byte)0xff }, + {(byte)0x5f,(byte)0x00,(byte)0x00 }, + {(byte)0x5f,(byte)0x00,(byte)0x5f }, + {(byte)0x5f,(byte)0x00,(byte)0x87 }, + {(byte)0x5f,(byte)0x00,(byte)0xaf }, + {(byte)0x5f,(byte)0x00,(byte)0xd7 }, + {(byte)0x5f,(byte)0x00,(byte)0xff }, + {(byte)0x5f,(byte)0x5f,(byte)0x00 }, + {(byte)0x5f,(byte)0x5f,(byte)0x5f }, + {(byte)0x5f,(byte)0x5f,(byte)0x87 }, + {(byte)0x5f,(byte)0x5f,(byte)0xaf }, + {(byte)0x5f,(byte)0x5f,(byte)0xd7 }, + {(byte)0x5f,(byte)0x5f,(byte)0xff }, + {(byte)0x5f,(byte)0x87,(byte)0x00 }, + {(byte)0x5f,(byte)0x87,(byte)0x5f }, + {(byte)0x5f,(byte)0x87,(byte)0x87 }, + {(byte)0x5f,(byte)0x87,(byte)0xaf }, + {(byte)0x5f,(byte)0x87,(byte)0xd7 }, + {(byte)0x5f,(byte)0x87,(byte)0xff }, + {(byte)0x5f,(byte)0xaf,(byte)0x00 }, + {(byte)0x5f,(byte)0xaf,(byte)0x5f }, + {(byte)0x5f,(byte)0xaf,(byte)0x87 }, + {(byte)0x5f,(byte)0xaf,(byte)0xaf }, + {(byte)0x5f,(byte)0xaf,(byte)0xd7 }, + {(byte)0x5f,(byte)0xaf,(byte)0xff }, + {(byte)0x5f,(byte)0xd7,(byte)0x00 }, + {(byte)0x5f,(byte)0xd7,(byte)0x5f }, + {(byte)0x5f,(byte)0xd7,(byte)0x87 }, + {(byte)0x5f,(byte)0xd7,(byte)0xaf }, + {(byte)0x5f,(byte)0xd7,(byte)0xd7 }, + {(byte)0x5f,(byte)0xd7,(byte)0xff }, + {(byte)0x5f,(byte)0xff,(byte)0x00 }, + {(byte)0x5f,(byte)0xff,(byte)0x5f }, + {(byte)0x5f,(byte)0xff,(byte)0x87 }, + {(byte)0x5f,(byte)0xff,(byte)0xaf }, + {(byte)0x5f,(byte)0xff,(byte)0xd7 }, + {(byte)0x5f,(byte)0xff,(byte)0xff }, + {(byte)0x87,(byte)0x00,(byte)0x00 }, + {(byte)0x87,(byte)0x00,(byte)0x5f }, + {(byte)0x87,(byte)0x00,(byte)0x87 }, + {(byte)0x87,(byte)0x00,(byte)0xaf }, + {(byte)0x87,(byte)0x00,(byte)0xd7 }, + {(byte)0x87,(byte)0x00,(byte)0xff }, + {(byte)0x87,(byte)0x5f,(byte)0x00 }, + {(byte)0x87,(byte)0x5f,(byte)0x5f }, + {(byte)0x87,(byte)0x5f,(byte)0x87 }, + {(byte)0x87,(byte)0x5f,(byte)0xaf }, + {(byte)0x87,(byte)0x5f,(byte)0xd7 }, + {(byte)0x87,(byte)0x5f,(byte)0xff }, + {(byte)0x87,(byte)0x87,(byte)0x00 }, + {(byte)0x87,(byte)0x87,(byte)0x5f }, + {(byte)0x87,(byte)0x87,(byte)0x87 }, + {(byte)0x87,(byte)0x87,(byte)0xaf }, + {(byte)0x87,(byte)0x87,(byte)0xd7 }, + {(byte)0x87,(byte)0x87,(byte)0xff }, + {(byte)0x87,(byte)0xaf,(byte)0x00 }, + {(byte)0x87,(byte)0xaf,(byte)0x5f }, + {(byte)0x87,(byte)0xaf,(byte)0x87 }, + {(byte)0x87,(byte)0xaf,(byte)0xaf }, + {(byte)0x87,(byte)0xaf,(byte)0xd7 }, + {(byte)0x87,(byte)0xaf,(byte)0xff }, + {(byte)0x87,(byte)0xd7,(byte)0x00 }, + {(byte)0x87,(byte)0xd7,(byte)0x5f }, + {(byte)0x87,(byte)0xd7,(byte)0x87 }, + {(byte)0x87,(byte)0xd7,(byte)0xaf }, + {(byte)0x87,(byte)0xd7,(byte)0xd7 }, + {(byte)0x87,(byte)0xd7,(byte)0xff }, + {(byte)0x87,(byte)0xff,(byte)0x00 }, + {(byte)0x87,(byte)0xff,(byte)0x5f }, + {(byte)0x87,(byte)0xff,(byte)0x87 }, + {(byte)0x87,(byte)0xff,(byte)0xaf }, + {(byte)0x87,(byte)0xff,(byte)0xd7 }, + {(byte)0x87,(byte)0xff,(byte)0xff }, + {(byte)0xaf,(byte)0x00,(byte)0x00 }, + {(byte)0xaf,(byte)0x00,(byte)0x5f }, + {(byte)0xaf,(byte)0x00,(byte)0x87 }, + {(byte)0xaf,(byte)0x00,(byte)0xaf }, + {(byte)0xaf,(byte)0x00,(byte)0xd7 }, + {(byte)0xaf,(byte)0x00,(byte)0xff }, + {(byte)0xaf,(byte)0x5f,(byte)0x00 }, + {(byte)0xaf,(byte)0x5f,(byte)0x5f }, + {(byte)0xaf,(byte)0x5f,(byte)0x87 }, + {(byte)0xaf,(byte)0x5f,(byte)0xaf }, + {(byte)0xaf,(byte)0x5f,(byte)0xd7 }, + {(byte)0xaf,(byte)0x5f,(byte)0xff }, + {(byte)0xaf,(byte)0x87,(byte)0x00 }, + {(byte)0xaf,(byte)0x87,(byte)0x5f }, + {(byte)0xaf,(byte)0x87,(byte)0x87 }, + {(byte)0xaf,(byte)0x87,(byte)0xaf }, + {(byte)0xaf,(byte)0x87,(byte)0xd7 }, + {(byte)0xaf,(byte)0x87,(byte)0xff }, + {(byte)0xaf,(byte)0xaf,(byte)0x00 }, + {(byte)0xaf,(byte)0xaf,(byte)0x5f }, + {(byte)0xaf,(byte)0xaf,(byte)0x87 }, + {(byte)0xaf,(byte)0xaf,(byte)0xaf }, + {(byte)0xaf,(byte)0xaf,(byte)0xd7 }, + {(byte)0xaf,(byte)0xaf,(byte)0xff }, + {(byte)0xaf,(byte)0xd7,(byte)0x00 }, + {(byte)0xaf,(byte)0xd7,(byte)0x5f }, + {(byte)0xaf,(byte)0xd7,(byte)0x87 }, + {(byte)0xaf,(byte)0xd7,(byte)0xaf }, + {(byte)0xaf,(byte)0xd7,(byte)0xd7 }, + {(byte)0xaf,(byte)0xd7,(byte)0xff }, + {(byte)0xaf,(byte)0xff,(byte)0x00 }, + {(byte)0xaf,(byte)0xff,(byte)0x5f }, + {(byte)0xaf,(byte)0xff,(byte)0x87 }, + {(byte)0xaf,(byte)0xff,(byte)0xaf }, + {(byte)0xaf,(byte)0xff,(byte)0xd7 }, + {(byte)0xaf,(byte)0xff,(byte)0xff }, + {(byte)0xd7,(byte)0x00,(byte)0x00 }, + {(byte)0xd7,(byte)0x00,(byte)0x5f }, + {(byte)0xd7,(byte)0x00,(byte)0x87 }, + {(byte)0xd7,(byte)0x00,(byte)0xaf }, + {(byte)0xd7,(byte)0x00,(byte)0xd7 }, + {(byte)0xd7,(byte)0x00,(byte)0xff }, + {(byte)0xd7,(byte)0x5f,(byte)0x00 }, + {(byte)0xd7,(byte)0x5f,(byte)0x5f }, + {(byte)0xd7,(byte)0x5f,(byte)0x87 }, + {(byte)0xd7,(byte)0x5f,(byte)0xaf }, + {(byte)0xd7,(byte)0x5f,(byte)0xd7 }, + {(byte)0xd7,(byte)0x5f,(byte)0xff }, + {(byte)0xd7,(byte)0x87,(byte)0x00 }, + {(byte)0xd7,(byte)0x87,(byte)0x5f }, + {(byte)0xd7,(byte)0x87,(byte)0x87 }, + {(byte)0xd7,(byte)0x87,(byte)0xaf }, + {(byte)0xd7,(byte)0x87,(byte)0xd7 }, + {(byte)0xd7,(byte)0x87,(byte)0xff }, + {(byte)0xd7,(byte)0xaf,(byte)0x00 }, + {(byte)0xd7,(byte)0xaf,(byte)0x5f }, + {(byte)0xd7,(byte)0xaf,(byte)0x87 }, + {(byte)0xd7,(byte)0xaf,(byte)0xaf }, + {(byte)0xd7,(byte)0xaf,(byte)0xd7 }, + {(byte)0xd7,(byte)0xaf,(byte)0xff }, + {(byte)0xd7,(byte)0xd7,(byte)0x00 }, + {(byte)0xd7,(byte)0xd7,(byte)0x5f }, + {(byte)0xd7,(byte)0xd7,(byte)0x87 }, + {(byte)0xd7,(byte)0xd7,(byte)0xaf }, + {(byte)0xd7,(byte)0xd7,(byte)0xd7 }, + {(byte)0xd7,(byte)0xd7,(byte)0xff }, + {(byte)0xd7,(byte)0xff,(byte)0x00 }, + {(byte)0xd7,(byte)0xff,(byte)0x5f }, + {(byte)0xd7,(byte)0xff,(byte)0x87 }, + {(byte)0xd7,(byte)0xff,(byte)0xaf }, + {(byte)0xd7,(byte)0xff,(byte)0xd7 }, + {(byte)0xd7,(byte)0xff,(byte)0xff }, + {(byte)0xff,(byte)0x00,(byte)0x00 }, + {(byte)0xff,(byte)0x00,(byte)0x5f }, + {(byte)0xff,(byte)0x00,(byte)0x87 }, + {(byte)0xff,(byte)0x00,(byte)0xaf }, + {(byte)0xff,(byte)0x00,(byte)0xd7 }, + {(byte)0xff,(byte)0x00,(byte)0xff }, + {(byte)0xff,(byte)0x5f,(byte)0x00 }, + {(byte)0xff,(byte)0x5f,(byte)0x5f }, + {(byte)0xff,(byte)0x5f,(byte)0x87 }, + {(byte)0xff,(byte)0x5f,(byte)0xaf }, + {(byte)0xff,(byte)0x5f,(byte)0xd7 }, + {(byte)0xff,(byte)0x5f,(byte)0xff }, + {(byte)0xff,(byte)0x87,(byte)0x00 }, + {(byte)0xff,(byte)0x87,(byte)0x5f }, + {(byte)0xff,(byte)0x87,(byte)0x87 }, + {(byte)0xff,(byte)0x87,(byte)0xaf }, + {(byte)0xff,(byte)0x87,(byte)0xd7 }, + {(byte)0xff,(byte)0x87,(byte)0xff }, + {(byte)0xff,(byte)0xaf,(byte)0x00 }, + {(byte)0xff,(byte)0xaf,(byte)0x5f }, + {(byte)0xff,(byte)0xaf,(byte)0x87 }, + {(byte)0xff,(byte)0xaf,(byte)0xaf }, + {(byte)0xff,(byte)0xaf,(byte)0xd7 }, + {(byte)0xff,(byte)0xaf,(byte)0xff }, + {(byte)0xff,(byte)0xd7,(byte)0x00 }, + {(byte)0xff,(byte)0xd7,(byte)0x5f }, + {(byte)0xff,(byte)0xd7,(byte)0x87 }, + {(byte)0xff,(byte)0xd7,(byte)0xaf }, + {(byte)0xff,(byte)0xd7,(byte)0xd7 }, + {(byte)0xff,(byte)0xd7,(byte)0xff }, + {(byte)0xff,(byte)0xff,(byte)0x00 }, + {(byte)0xff,(byte)0xff,(byte)0x5f }, + {(byte)0xff,(byte)0xff,(byte)0x87 }, + {(byte)0xff,(byte)0xff,(byte)0xaf }, + {(byte)0xff,(byte)0xff,(byte)0xd7 }, + {(byte)0xff,(byte)0xff,(byte)0xff }, + + //Grey-scale ramp from 232 + {(byte)0x08,(byte)0x08,(byte)0x08 }, + {(byte)0x12,(byte)0x12,(byte)0x12 }, + {(byte)0x1c,(byte)0x1c,(byte)0x1c }, + {(byte)0x26,(byte)0x26,(byte)0x26 }, + {(byte)0x30,(byte)0x30,(byte)0x30 }, + {(byte)0x3a,(byte)0x3a,(byte)0x3a }, + {(byte)0x44,(byte)0x44,(byte)0x44 }, + {(byte)0x4e,(byte)0x4e,(byte)0x4e }, + {(byte)0x58,(byte)0x58,(byte)0x58 }, + {(byte)0x62,(byte)0x62,(byte)0x62 }, + {(byte)0x6c,(byte)0x6c,(byte)0x6c }, + {(byte)0x76,(byte)0x76,(byte)0x76 }, + {(byte)0x80,(byte)0x80,(byte)0x80 }, + {(byte)0x8a,(byte)0x8a,(byte)0x8a }, + {(byte)0x94,(byte)0x94,(byte)0x94 }, + {(byte)0x9e,(byte)0x9e,(byte)0x9e }, + {(byte)0xa8,(byte)0xa8,(byte)0xa8 }, + {(byte)0xb2,(byte)0xb2,(byte)0xb2 }, + {(byte)0xbc,(byte)0xbc,(byte)0xbc }, + {(byte)0xc6,(byte)0xc6,(byte)0xc6 }, + {(byte)0xd0,(byte)0xd0,(byte)0xd0 }, + {(byte)0xda,(byte)0xda,(byte)0xda }, + {(byte)0xe4,(byte)0xe4,(byte)0xe4 }, + {(byte)0xee,(byte)0xee,(byte)0xee } + }; + + private final int colorIndex; + + /** + * Creates a new TextColor using the XTerm 256 color indexed mode, with the specified index value. You must + * choose a value between 0 and 255. + * @param colorIndex Index value to use for this color. + */ + public Indexed(int colorIndex) { + if(colorIndex > 255 || colorIndex < 0) { + throw new IllegalArgumentException("Cannot create a Color.Indexed with a color index of " + colorIndex + + ", must be in the range of 0-255"); + } + this.colorIndex = colorIndex; + } + + @Override + public byte[] getForegroundSGRSequence() { + return ("38;5;" + colorIndex).getBytes(); + } + + @Override + public byte[] getBackgroundSGRSequence() { + return ("48;5;" + colorIndex).getBytes(); + } + + @Override + public int getRed() { + return COLOR_TABLE[colorIndex][0] & 0x000000ff; + } + + @Override + public int getGreen() { + return COLOR_TABLE[colorIndex][1] & 0x000000ff; + } + + @Override + public int getBlue() { + return COLOR_TABLE[colorIndex][2] & 0x000000ff; + } + + @Override + public Color toColor() { + return new Color(getRed(), getGreen(), getBlue()); + } + + @Override + public String toString() { + return "{IndexedColor:" + colorIndex + "}"; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 43 * hash + this.colorIndex; + return hash; + } + + @Override + public boolean equals(Object obj) { + if(obj == null) { + return false; + } + if(getClass() != obj.getClass()) { + return false; + } + final Indexed other = (Indexed) obj; + return this.colorIndex == other.colorIndex; + } + + /** + * Picks out a color approximated from the supplied RGB components + * @param red Red intensity, from 0 to 255 + * @param green Red intensity, from 0 to 255 + * @param blue Red intensity, from 0 to 255 + * @return Nearest color from the 6x6x6 RGB color cube or from the 24 entries grey-scale ramp (whichever is closest) + */ + public static Indexed fromRGB(int red, int green, int blue) { + if(red < 0 || red > 255) { + throw new IllegalArgumentException("fromRGB: red is outside of valid range (0-255)"); + } + if(green < 0 || green > 255) { + throw new IllegalArgumentException("fromRGB: green is outside of valid range (0-255)"); + } + if(blue < 0 || blue > 255) { + throw new IllegalArgumentException("fromRGB: blue is outside of valid range (0-255)"); + } + + int rescaledRed = (int)(((double)red / 255.0) * 5.0); + int rescaledGreen = (int)(((double)green / 255.0) * 5.0); + int rescaledBlue = (int)(((double)blue / 255.0) * 5.0); + + int index = rescaledBlue + (6 * rescaledGreen) + (36 * rescaledRed) + 16; + Indexed fromColorCube = new Indexed(index); + Indexed fromGreyRamp = fromGreyRamp((red + green + blue) / 3); + + //Now figure out which one is closest + int coloredDistance = ((red - fromColorCube.getRed()) * (red - fromColorCube.getRed())) + + ((green - fromColorCube.getGreen()) * (green - fromColorCube.getGreen())) + + ((blue - fromColorCube.getBlue()) * (blue - fromColorCube.getBlue())); + int greyDistance = ((red - fromGreyRamp.getRed()) * (red - fromGreyRamp.getRed())) + + ((green - fromGreyRamp.getGreen()) * (green - fromGreyRamp.getGreen())) + + ((blue - fromGreyRamp.getBlue()) * (blue - fromGreyRamp.getBlue())); + if(coloredDistance < greyDistance) { + return fromColorCube; + } + else { + return fromGreyRamp; + } + } + + /** + * Picks out a color from the grey-scale ramp area of the color index. + * @param intensity Intensity, 0 - 255 + * @return Indexed color from the grey-scale ramp which is the best match for the supplied intensity + */ + private static Indexed fromGreyRamp(int intensity) { + int rescaled = (int)(((double)intensity / 255.0) * 23.0) + 232; + return new Indexed(rescaled); + } + } + + /** + * This class can be used to specify a color in 24-bit color space (RGB with 8-bit resolution per color). Please be + * aware that only a few terminal support 24-bit color control codes, please avoid using this class unless you know + * all users will have compatible terminals. For details, please see + * + * this commit log. Behavior on terminals that don't support these codes is undefined. + */ + class RGB implements TextColor { + private final int red; + private final int green; + private final int blue; + + /** + * This class can be used to specify a color in 24-bit color space (RGB with 8-bit resolution per color). Please be + * aware that only a few terminal support 24-bit color control codes, please avoid using this class unless you know + * all users will have compatible terminals. For details, please see + * + * this commit log. Behavior on terminals that don't support these codes is undefined. + * + * @param r Red intensity, from 0 to 255 + * @param g Green intensity, from 0 to 255 + * @param b Blue intensity, from 0 to 255 + */ + public RGB(int r, int g, int b) { + if(r < 0 || r > 255) { + throw new IllegalArgumentException("RGB: r is outside of valid range (0-255)"); + } + if(g < 0 || g > 255) { + throw new IllegalArgumentException("RGB: g is outside of valid range (0-255)"); + } + if(b < 0 || b > 255) { + throw new IllegalArgumentException("RGB: b is outside of valid range (0-255)"); + } + this.red = r; + this.green = g; + this.blue = b; + } + + @Override + public byte[] getForegroundSGRSequence() { + return ("38;2;" + getRed() + ";" + getGreen() + ";" + getBlue()).getBytes(); + } + + @Override + public byte[] getBackgroundSGRSequence() { + return ("48;2;" + getRed() + ";" + getGreen() + ";" + getBlue()).getBytes(); + } + + @Override + public int getRed() { + return red; + } + + @Override + public int getGreen() { + return green; + } + + @Override + public int getBlue() { + return blue; + } + + @Override + public Color toColor() { + return new Color(getRed(), getGreen(), getBlue()); + } + + @Override + public String toString() { + return "{RGB:" + getRed() + "," + getGreen() + "," + getBlue() + "}"; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 29 * hash + red; + hash = 29 * hash + green; + hash = 29 * hash + blue; + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final RGB other = (RGB) obj; + return this.red == other.red + && this.green == other.green + && this.blue == other.blue; + } + } + + /** + * Utility class to instantiate colors from other types and definitions + */ + class Factory { + private static final Pattern INDEXED_COLOR = Pattern.compile("#[0-9]{1,3}"); + private static final Pattern RGB_COLOR = Pattern.compile("#[0-9a-fA-F]{6}"); + + private Factory() {} + + /** + * Parses a string into a color. The string can have one of three formats: + *

    + *
  • blue - Constant value from the {@link ANSI} enum
  • + *
  • #17 - Hash character followed by one to three numbers; picks the color with that index from + * the 256 color palette
  • + *
  • #1a1a1a - Hash character followed by three hex-decimal tuples; creates an RGB color entry by + * parsing the tuples as Red, Green and Blue
  • + *
+ * @param value The string value to parse + * @return A {@link TextColor} that is either an {@link ANSI}, an {@link Indexed} or an {@link RGB} depending on + * the format of the string, or {@code null} if {@code value} is {@code null}. + */ + public static TextColor fromString(String value) { + if(value == null) { + return null; + } + value = value.trim(); + if(RGB_COLOR.matcher(value).matches()) { + int r = Integer.parseInt(value.substring(1, 3), 16); + int g = Integer.parseInt(value.substring(3, 5), 16); + int b = Integer.parseInt(value.substring(5, 7), 16); + return new TextColor.RGB(r, g, b); + } + else if(INDEXED_COLOR.matcher(value).matches()) { + int index = Integer.parseInt(value.substring(1)); + return new TextColor.Indexed(index); + } + try { + return TextColor.ANSI.valueOf(value.toUpperCase()); + } + catch(IllegalArgumentException e) { + throw new IllegalArgumentException("Unknown color definition \"" + value + "\"", e); + } + } + } +} diff --git a/src/main/java/com/anas/jcolorfulconsole/managers/DefaultConsoleManager.java b/src/main/java/com/anas/jcolorfulconsole/managers/DefaultConsoleManager.java deleted file mode 100644 index ae1d058..0000000 --- a/src/main/java/com/anas/jcolorfulconsole/managers/DefaultConsoleManager.java +++ /dev/null @@ -1,180 +0,0 @@ -package com.anas.jcolorfulconsole.managers; - -import com.anas.jcolorfulconsole.ConsoleManager; -import com.anas.jcolorfulconsole.ConsoleProperty; -import com.anas.jcolorfulconsole.color.BackgroundColor; -import com.anas.jcolorfulconsole.color.TextColor; -import com.anas.jcolorfulconsole.stringmake.StringProcessor; -import com.anas.jcolorfulconsole.style.TextStyle; - -import java.util.ArrayList; - -public class DefaultConsoleManager implements ConsoleManager { - private final ArrayList properties; - private final StringProcessor stringProcessor; - - public DefaultConsoleManager() { - this.properties = new ArrayList<>(); - this.stringProcessor = new StringProcessor(); - - properties.add(TextColor.DEFAULT); - properties.add(BackgroundColor.DEFAULT); - properties.add(TextStyle.DEFAULT); - } - - @Override - public void setTextColor(TextColor textColor) { - properties.set(0, textColor); - } - - @Override - public void setBackgroundColor(BackgroundColor backgroundColor) { - properties.set(1, backgroundColor); - } - - @Override - public void setTextStyle(TextStyle textStyle) { - properties.set(2, textStyle); - } - - @Override - public void addProperty(ConsoleProperty property) { - properties.add(property); - } - - @Override - public void removeProperty(ConsoleProperty property) { - properties.remove(property); - } - - @Override - public void print(String str) { - System.out.print(stringProcessor.addPropertiesEscape(str, - properties.toArray(new ConsoleProperty[0]))); - } - - @Override - public void print(String str, ConsoleProperty... properties) { - System.out.print(stringProcessor.addPropertiesEscape(str, properties)); - } - - @Override - public void println(String str) { - this.print(str + "\n"); - } - - @Override - public void println(String str, ConsoleProperty... properties) { - this.print(str + "\n", properties); - } - - @Override - public void println() { - this.println(""); - } - - @Override - public void print(char c) { - this.print(String.valueOf(c)); - } - - @Override - public void print(char c, ConsoleProperty... properties) { - this.print(String.valueOf(c), properties); - } - - @Override - public void println(char c) { - this.print(c + "\n"); - } - - @Override - public void println(char c, ConsoleProperty... properties) { - this.print(c, properties); - } - - @Override - public void print(int i) { - this.print(String.valueOf(i)); - } - - @Override - public void print(int i, ConsoleProperty... properties) { - this.print(String.valueOf(i), properties); - } - - @Override - public void println(int i) { - this.print(i + "\n"); - } - - @Override - public void println(int i, ConsoleProperty... properties) { - this.print(i, properties); - } - - @Override - public void print(double d) { - this.print(String.valueOf(d)); - } - - @Override - public void print(double d, ConsoleProperty... properties) { - this.print(String.valueOf(d), properties); - } - - @Override - public void println(double d) { - this.println(String.valueOf(d)); - } - - @Override - public void println(double d, ConsoleProperty... properties) { - this.print(d, properties); - } - - @Override - public void print(boolean b) { - this.print(String.valueOf(b)); - } - - @Override - public void print(boolean b, ConsoleProperty... properties) { - this.print(String.valueOf(b), properties); - } - - @Override - public void println(boolean b) { - this.println(String.valueOf(b)); - } - - @Override - public void println(boolean b, ConsoleProperty... properties) { - this.print(b, properties); - } - - @Override - public void print(Object o) { - this.print(o.toString()); - } - - @Override - public void print(Object o, ConsoleProperty... properties) { - this.print(o.toString(), properties); - } - - @Override - public void println(Object o) { - this.println(o.toString()); - } - - @Override - public void println(Object o, ConsoleProperty... properties) { - this.print(o.toString(), properties); - } - - @Override - public void printf(String format, Object... args) { - this.print(String.format(format, args)); - } -} diff --git a/src/main/java/com/anas/jcolorfulconsole/stringmake/StringProcessor.java b/src/main/java/com/anas/jcolorfulconsole/stringmake/StringProcessor.java deleted file mode 100644 index 86a2981..0000000 --- a/src/main/java/com/anas/jcolorfulconsole/stringmake/StringProcessor.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.anas.jcolorfulconsole.stringmake; - -import com.anas.jcolorfulconsole.ConsoleProperty; - -public class StringProcessor { - public String addPropertiesEscape(String str, ConsoleProperty... properties) { - StringBuilder sb = new StringBuilder(); - for (int i = properties.length; i > 0; i--) { - sb.append(getEscapedText(properties[i - 1])); - } - sb.append(str); - for (int i = properties.length; i > 0; i--) { - sb.append(closeEscapedText()); - } - return sb.toString(); - } - - public String getEscapedText(ConsoleProperty property) { - return "\033[" + property.getCode() + "m"; - } - - public String closeEscapedText() { - return "\033[m"; - } - - private String getTerminalType() { - return System.getenv("TERM"); - } -} diff --git a/src/main/java/com/anas/jcolorfulconsole/style/Style.java b/src/main/java/com/anas/jcolorfulconsole/style/Style.java deleted file mode 100644 index 4c1c8a5..0000000 --- a/src/main/java/com/anas/jcolorfulconsole/style/Style.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.anas.jcolorfulconsole.style; - -import com.anas.jcolorfulconsole.ConsoleProperty; - -public abstract class Style implements ConsoleProperty { - private final short code; - - protected Style(short code) { - this.code = code; - } - - public short getCode() { - return code; - } -} diff --git a/src/main/java/com/anas/jcolorfulconsole/style/TextStyle.java b/src/main/java/com/anas/jcolorfulconsole/style/TextStyle.java deleted file mode 100644 index 5be4162..0000000 --- a/src/main/java/com/anas/jcolorfulconsole/style/TextStyle.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.anas.jcolorfulconsole.style; - -public class TextStyle extends Style { - - public static final TextStyle DEFAULT = new TextStyle((short) 10); - public static final TextStyle BOLD = new TextStyle((short) 1); - public static final TextStyle ITALIC = new TextStyle((short) 3); - public static final TextStyle UNDERLINE = new TextStyle((short) 4); - public static final TextStyle STRIKETHROUGH = new TextStyle((short) 9); - public static final TextStyle DOUBLE_UNDERLINE = new TextStyle((short) 21); - public static final TextStyle NORMAL_INTENSITY = new TextStyle((short) 22); - public static final TextStyle FRAKTUR = new TextStyle((short) 20); - public static final TextStyle ITALIC_INTENSITY = new TextStyle((short) 23); - public static final TextStyle UNDERLINE_INTENSITY = new TextStyle((short) 24); - public static final TextStyle BLINK_SLOW = new TextStyle((short) 25); - public static final TextStyle BLINK_FAST = new TextStyle((short) 26); - public static final TextStyle NEGATIVE_INTENSITY = new TextStyle((short) 27); - public static final TextStyle CONCEALED = new TextStyle((short) 28); - public static final TextStyle CROSSED_OUT = new TextStyle((short) 29); - public static final TextStyle FRAMED = new TextStyle((short) 54); - public static final TextStyle ENCIRCLED = new TextStyle((short) 51); - public static final TextStyle OVERLINED = new TextStyle((short) 53); - - protected TextStyle(short code) { - super(code); - } -} diff --git a/src/main/java/test/Main.java b/src/main/java/test/Main.java new file mode 100644 index 0000000..692fdc9 --- /dev/null +++ b/src/main/java/test/Main.java @@ -0,0 +1,26 @@ +package test; + +import com.anas.jcolorfulconsole.ColoredString; +import com.anas.jcolorfulconsole.TextStyle; +import com.anas.jcolorfulconsole.lanterna.TextColor; + +public class Main { + public static void main(String[] args) { + ColoredString coloredString = new ColoredString("Hello World", null, "blue", TextStyle.BOLD, TextStyle.ITALIC); + System.out.println(coloredString); + + new Thread(() -> { + while (true) { + System.out.println(new ColoredString("Hi", + new TextColor.RGB((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255)), + new TextColor.RGB((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255)), + TextStyle.values()[(int) (Math.random() * TextStyle.values().length)])); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }).start(); + } +}