View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.pattern;
18  
19  import java.util.Arrays;
20  import java.util.HashMap;
21  import java.util.Locale;
22  import java.util.Map;
23  
24  /**
25   * Converts text into ANSI escape sequences.
26   * <p>
27   * The names for colors and attributes are standard, but the exact shade/hue/value of colors are not, and depend on the
28   * device used to display them.
29   * </p>
30   */
31  public enum AnsiEscape {
32  
33      /**
34       * Escape prefix.
35       */
36      PREFIX("\u001b["),
37      /**
38       * Escape suffix.
39       */
40      SUFFIX("m"),
41  
42      /**
43       * Escape separator.
44       */
45      SEPARATOR(";"),
46  
47      /**
48       * Normal general attribute.
49       */
50      NORMAL("0"),
51  
52      /**
53       * Bright general attribute.
54       */
55      BRIGHT("1"),
56  
57      /**
58       * Dim general attribute.
59       */
60      DIM("2"),
61  
62      /**
63       * Underline general attribute.
64       */
65      UNDERLINE("3"),
66  
67      /**
68       * Blink general attribute.
69       */
70      BLINK("5"),
71  
72      /**
73       * Reverse general attribute.
74       */
75      REVERSE("7"),
76  
77      /**
78       * Normal general attribute.
79       */
80      HIDDEN("8"),
81  
82      /**
83       * Black foreground color.
84       */
85      BLACK("30"),
86  
87      /**
88       * Black foreground color.
89       */
90      FG_BLACK("30"),
91  
92      /**
93       * Red foreground color.
94       */
95      RED("31"),
96  
97      /**
98       * Red foreground color.
99       */
100     FG_RED("31"),
101 
102     /**
103      * Green foreground color.
104      */
105     GREEN("32"),
106 
107     /**
108      * Green foreground color.
109      */
110     FG_GREEN("32"),
111 
112     /**
113      * Yellow foreground color.
114      */
115     YELLOW("33"),
116 
117     /**
118      * Yellow foreground color.
119      */
120     FG_YELLOW("33"),
121 
122     /**
123      * Blue foreground color.
124      */
125     BLUE("34"),
126 
127     /**
128      * Blue foreground color.
129      */
130     FG_BLUE("34"),
131 
132     /**
133      * Magenta foreground color.
134      */
135     MAGENTA("35"),
136 
137     /**
138      * Magenta foreground color.
139      */
140     FG_MAGENTA("35"),
141 
142     /**
143      * Cyan foreground color.
144      */
145     CYAN("36"),
146 
147     /**
148      * Cyan foreground color.
149      */
150     FG_CYAN("36"),
151 
152     /**
153      * White foreground color.
154      */
155     WHITE("37"),
156 
157     /**
158      * White foreground color.
159      */
160     FG_WHITE("37"),
161 
162     /**
163      * Default foreground color.
164      */
165     DEFAULT("39"),
166 
167     /**
168      * Default foreground color.
169      */
170     FG_DEFAULT("39"),
171 
172     /**
173      * Black background color.
174      */
175     BG_BLACK("40"),
176 
177     /**
178      * Red background color.
179      */
180     BG_RED("41"),
181 
182     /**
183      * Green background color.
184      */
185     BG_GREEN("42"),
186 
187     /**
188      * Yellow background color.
189      */
190     BG_YELLOW("43"),
191 
192     /**
193      * Blue background color.
194      */
195     BG_BLUE("44"),
196 
197     /**
198      * Magenta background color.
199      */
200     BG_MAGENTA("45"),
201 
202     /**
203      * Cyan background color.
204      */
205     BG_CYAN("46"),
206 
207     /**
208      * White background color.
209      */
210     BG_WHITE("47");
211 
212     private static final String WHITESPACE_REGEX = "\\s*";
213 
214     private final String code;
215 
216     private AnsiEscape(final String code) {
217         this.code = code;
218     }
219 
220     /**
221      * Gets the default style.
222      *
223      * @return the default style
224      */
225     public static String getDefaultStyle() {
226         return PREFIX.getCode() + SUFFIX.getCode();
227     }
228 
229     private static String toRegexSeparator(final String separator) {
230         return WHITESPACE_REGEX + separator + WHITESPACE_REGEX;
231     }
232 
233     /**
234      * Gets the escape code.
235      *
236      * @return the escape code.
237      */
238     public String getCode() {
239         return code;
240     }
241 
242     /**
243      * Creates a Map from a source array where values are ANSI escape sequences. The format is:
244      *
245      * <pre>
246      * Key1=Value, Key2=Value, ...
247      * </pre>
248      *
249      * For example:
250      *
251      * <pre>
252      * ERROR=red bold, WARN=yellow bold, INFO=green, ...
253      * </pre>
254      *
255      * You can use whitespace around the comma and equal sign. The names in values MUST come from the
256      * {@linkplain AnsiEscape} enum, case is normalized to upper-case internally.
257      *
258      * @param values the source string to parse.
259      * @param dontEscapeKeys do not escape these keys, leave the values as is in the map
260      * @return a new map
261      */
262     public static Map<String, String> createMap(final String values, final String[] dontEscapeKeys) {
263         return createMap(values.split(toRegexSeparator(",")), dontEscapeKeys);
264     }
265 
266     /**
267      * Creates a Map from a source array where values are ANSI escape sequences. Each array entry must be in the format:
268      *
269      * <pre>
270      * Key1 = Value
271      * </pre>
272      *
273      * For example:
274      *
275      * <pre>
276      * ERROR=red bold
277      * </pre>
278      *
279      * You can use whitespace around the equal sign and between the value elements. The names in values MUST come from
280      * the {@linkplain AnsiEscape} enum, case is normalized to upper-case internally.
281      *
282      * @param values
283      *            the source array to parse.
284      * @param dontEscapeKeys
285      *            do not escape these keys, leave the values as is in the map
286      * @return a new map
287      */
288     public static Map<String, String> createMap(final String[] values, final String[] dontEscapeKeys) {
289         final String[] sortedIgnoreKeys = dontEscapeKeys != null ? dontEscapeKeys.clone() : new String[0];
290         Arrays.sort(sortedIgnoreKeys);
291         final Map<String, String> map = new HashMap<String, String>();
292         for (final String string : values) {
293             final String[] keyValue = string.split(toRegexSeparator("="));
294             if (keyValue.length > 1) {
295                 final String key = keyValue[0].toUpperCase(Locale.ENGLISH);
296                 final String value = keyValue[1];
297                 final boolean escape = Arrays.binarySearch(sortedIgnoreKeys, key) < 0;
298                 map.put(key, escape ? createSequence(value.split("\\s")) : value);
299             }
300         }
301         return map;
302     }
303 
304     /**
305      * Creates an ANSI escape sequence from the given {@linkplain AnsiEscape} names.
306      *
307      * @param names
308      *            {@linkplain AnsiEscape} names.
309      * @return An ANSI escape sequence.
310      */
311     public static String createSequence(final String... names) {
312         if (names == null) {
313             return getDefaultStyle();
314         }
315         final StringBuilder sb = new StringBuilder(AnsiEscape.PREFIX.getCode());
316         boolean first = true;
317         for (final String name : names) {
318             try {
319                 final AnsiEscape escape = AnsiEscape.valueOf(name.trim().toUpperCase(Locale.ENGLISH));
320                 if (!first) {
321                     sb.append(AnsiEscape.SEPARATOR.getCode());
322                 }
323                 first = false;
324                 sb.append(escape.getCode());
325             } catch (final Exception ex) {
326                 // Ignore the error.
327             }
328         }
329         sb.append(AnsiEscape.SUFFIX.getCode());
330         return sb.toString();
331     }
332 
333 }