dorkbox.console.output.AnsiRenderer Maven / Gradle / Ivy
/*
* Copyright 2016 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
* Copyright (C) 2009 the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.console.output;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* Renders ANSI color escape-codes in strings by parsing out some special syntax to pick up the correct fluff to use.
*
*
* The syntax for embedded ANSI codes is:
*
*
* @|code(,code)* text|@
*
*
* Examples:
*
*
* @|bold Hello|@
*
*
*
* @|bold,red Warning!|@
*
* For Colors, FG_x and BG_x are supported, as are BRIGHT_x (and consequently, FG_BRIGHT_x)
*
* @author dorkbox, llc
* @author Jason Dillon
* @author Hiram Chirino
*/
@SuppressWarnings("WeakerAccess")
public
class AnsiRenderer {
public static final String BEGIN_TOKEN = "@|";
public static final String CODE_LIST_SEPARATOR = ",";
public static final String CODE_TEXT_SEPARATOR = " ";
public static final String END_TOKEN = "|@";
private static final int BEGIN_TOKEN_LEN = 2;
private static final int END_TOKEN_LEN = 2;
private static Map codeMap = new HashMap(32);
static {
// have to make sure that all the different categories are added to our map.
Color red = Color.RED;
Attribute bold = Attribute.BOLD;
}
static
void reg(Enum anEnum, String codeName) {
reg(anEnum, codeName, false);
}
static
void reg(Enum anEnum, String codeName, boolean isBackgroundColor) {
codeMap.put(codeName, new AnsiCodeMap(anEnum, isBackgroundColor));
}
/**
* Renders {@link AnsiCodeMap} names on the given Ansi.
*
* @param ansi The Ansi to render upon
* @param codeNames The code names to render
*/
public static
Ansi render(Ansi ansi, final String... codeNames) {
for (String codeName : codeNames) {
render(ansi, codeName);
}
return ansi;
}
/**
* Renders a {@link AnsiCodeMap} name on the given Ansi.
*
* @param ansi The Ansi to render upon
* @param codeName The code name to render
*/
public static
Ansi render(Ansi ansi, String codeName) {
AnsiCodeMap ansiCodeMap = codeMap.get(codeName.toUpperCase(Locale.ENGLISH));
assert ansiCodeMap != null : "Invalid ANSI code name: '" + codeName + "'";
if (ansiCodeMap.isColor()) {
if (ansiCodeMap.isBackgroundColor()) {
ansi = ansi.bg(ansiCodeMap.getColor());
}
else {
ansi = ansi.fg(ansiCodeMap.getColor());
}
}
else if (ansiCodeMap.isAttribute()) {
ansi = ansi.a(ansiCodeMap.getAttribute());
} else {
assert false : "Undetermined ANSI code name: '" + codeName + "'";
}
return ansi;
}
/**
* Renders text using the {@link AnsiCodeMap} names.
*
* @param text The text to render
* @param codeNames The code names to render
*/
public static
String render(final String text, final String... codeNames) {
Ansi ansi = render(Ansi.ansi(), codeNames);
return ansi.a(text)
.reset()
.toString();
}
public static
String render(final String input) throws IllegalArgumentException {
StringBuilder buff = new StringBuilder();
int i = 0;
int j, k;
while (true) {
j = input.indexOf(BEGIN_TOKEN, i);
if (j == -1) {
if (i == 0) {
return input;
}
else {
buff.append(input.substring(i, input.length()));
return buff.toString();
}
}
else {
buff.append(input.substring(i, j));
k = input.indexOf(END_TOKEN, j);
if (k == -1) {
return input;
}
else {
j += BEGIN_TOKEN_LEN;
String spec = input.substring(j, k);
String[] items = spec.split(CODE_TEXT_SEPARATOR, 2);
if (items.length == 1) {
return input;
}
String replacement = render(items[1], items[0].split(CODE_LIST_SEPARATOR));
buff.append(replacement);
i = k + END_TOKEN_LEN;
}
}
}
}
/**
* Renders {@link AnsiCodeMap} names as an ANSI escape string.
*
* @param codeNames The code names to render
*
* @return an ANSI escape string.
*/
public static
String renderCodeNames(final String codeNames) {
return render(new Ansi(), codeNames.split("\\s")).toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy