blob: c83123453e60eaec715c95f167f58e552c5e7522 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.logging.log4j.core.pattern;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.logging.log4j.core.util.Patterns;
import org.apache.logging.log4j.util.EnglishEnums;
/**
* Converts text into ANSI escape sequences.
* <p>
* The names for colors and attributes are standard, but the exact shade/hue/value of colors are not, and depend on the
* device used to display them.
* </p>
*/
public enum AnsiEscape {
/**
* The Control Sequence Introducer (or Control Sequence Initiator).
* <p>
* Most sequences are more than two characters and start with the characters ESC and [ (the left bracket).
* </p>
*/
CSI("\u001b["),
/**
* Escape suffix.
*/
SUFFIX("m"),
/**
* Escape separator.
*/
SEPARATOR(";"),
/**
* Normal general attribute.
*/
NORMAL("0"),
/**
* Bright general attribute.
*/
BRIGHT("1"),
/**
* Dim general attribute.
*/
DIM("2"),
/**
* Underline general attribute.
*/
UNDERLINE("3"),
/**
* Blink general attribute.
*/
BLINK("5"),
/**
* Reverse general attribute.
*/
REVERSE("7"),
/**
* Normal general attribute.
*/
HIDDEN("8"),
/**
* Black foreground color.
*/
BLACK("30"),
/**
* Black foreground color.
*/
FG_BLACK("30"),
/**
* Red foreground color.
*/
RED("31"),
/**
* Red foreground color.
*/
FG_RED("31"),
/**
* Green foreground color.
*/
GREEN("32"),
/**
* Green foreground color.
*/
FG_GREEN("32"),
/**
* Yellow foreground color.
*/
YELLOW("33"),
/**
* Yellow foreground color.
*/
FG_YELLOW("33"),
/**
* Blue foreground color.
*/
BLUE("34"),
/**
* Blue foreground color.
*/
FG_BLUE("34"),
/**
* Magenta foreground color.
*/
MAGENTA("35"),
/**
* Magenta foreground color.
*/
FG_MAGENTA("35"),
/**
* Cyan foreground color.
*/
CYAN("36"),
/**
* Cyan foreground color.
*/
FG_CYAN("36"),
/**
* White foreground color.
*/
WHITE("37"),
/**
* White foreground color.
*/
FG_WHITE("37"),
/**
* Default foreground color.
*/
DEFAULT("39"),
/**
* Default foreground color.
*/
FG_DEFAULT("39"),
/**
* Black background color.
*/
BG_BLACK("40"),
/**
* Red background color.
*/
BG_RED("41"),
/**
* Green background color.
*/
BG_GREEN("42"),
/**
* Yellow background color.
*/
BG_YELLOW("43"),
/**
* Blue background color.
*/
BG_BLUE("44"),
/**
* Magenta background color.
*/
BG_MAGENTA("45"),
/**
* Cyan background color.
*/
BG_CYAN("46"),
/**
* White background color.
*/
BG_WHITE("47");
private static final String DEFAULT_STYLE = CSI.getCode() + SUFFIX.getCode();
private final String code;
AnsiEscape(final String code) {
this.code = code;
}
/**
* Gets the default style.
*
* @return the default style
*/
public static String getDefaultStyle() {
return DEFAULT_STYLE;
}
/**
* Gets the escape code.
*
* @return the escape code.
*/
public String getCode() {
return code;
}
/**
* Creates a Map from a source array where values are ANSI escape sequences. The format is:
*
* <pre>
* Key1=Value, Key2=Value, ...
* </pre>
*
* For example:
*
* <pre>
* ERROR=red bold, WARN=yellow bold, INFO=green, ...
* </pre>
*
* You can use whitespace around the comma and equal sign. The names in values MUST come from the
* {@linkplain AnsiEscape} enum, case is normalized to upper-case internally.
*
* @param values the source string to parse.
* @param dontEscapeKeys do not escape these keys, leave the values as is in the map
* @return a new map
*/
public static Map<String, String> createMap(final String values, final String[] dontEscapeKeys) {
return createMap(values.split(Patterns.COMMA_SEPARATOR), dontEscapeKeys);
}
/**
* Creates a Map from a source array where values are ANSI escape sequences. Each array entry must be in the format:
*
* <pre>
* Key1 = Value
* </pre>
*
* For example:
*
* <pre>
* ERROR=red bold
* </pre>
*
* You can use whitespace around the equal sign and between the value elements. The names in values MUST come from
* the {@linkplain AnsiEscape} enum, case is normalized to upper-case internally.
*
* @param values
* the source array to parse.
* @param dontEscapeKeys
* do not escape these keys, leave the values as is in the map
* @return a new map
*/
public static Map<String, String> createMap(final String[] values, final String[] dontEscapeKeys) {
final String[] sortedIgnoreKeys = dontEscapeKeys != null ? dontEscapeKeys.clone() : new String[0];
Arrays.sort(sortedIgnoreKeys);
final Map<String, String> map = new HashMap<>();
for (final String string : values) {
final String[] keyValue = string.split(Patterns.toWhitespaceSeparator("="));
if (keyValue.length > 1) {
final String key = keyValue[0].toUpperCase(Locale.ENGLISH);
final String value = keyValue[1];
final boolean escape = Arrays.binarySearch(sortedIgnoreKeys, key) < 0;
map.put(key, escape ? createSequence(value.split("\\s")) : value);
}
}
return map;
}
/**
* Creates an ANSI escape sequence from the given {@linkplain AnsiEscape} names.
*
* @param names
* {@linkplain AnsiEscape} names.
* @return An ANSI escape sequence.
*/
public static String createSequence(final String... names) {
if (names == null) {
return getDefaultStyle();
}
final StringBuilder sb = new StringBuilder(AnsiEscape.CSI.getCode());
boolean first = true;
for (final String name : names) {
try {
final AnsiEscape escape = EnglishEnums.valueOf(AnsiEscape.class, name.trim());
if (!first) {
sb.append(AnsiEscape.SEPARATOR.getCode());
}
first = false;
sb.append(escape.getCode());
} catch (final Exception ex) {
// Ignore the error.
}
}
sb.append(AnsiEscape.SUFFIX.getCode());
return sb.toString();
}
}