IDEA-149450 ANSI escapes not interpreted as expected
[idea/community.git] / platform / platform-api / src / com / intellij / execution / process / ColoredOutputTypeRegistry.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.execution.process;
17
18 import com.intellij.execution.ui.ConsoleViewContentType;
19 import com.intellij.openapi.components.ServiceManager;
20 import com.intellij.openapi.editor.colors.EditorColorsManager;
21 import com.intellij.openapi.editor.colors.EditorColorsScheme;
22 import com.intellij.openapi.editor.colors.TextAttributesKey;
23 import com.intellij.openapi.editor.markup.EffectType;
24 import com.intellij.openapi.editor.markup.TextAttributes;
25 import com.intellij.openapi.util.Key;
26 import com.intellij.openapi.util.text.StringUtil;
27 import com.intellij.util.ObjectUtils;
28 import org.jetbrains.annotations.NonNls;
29 import org.jetbrains.annotations.NotNull;
30
31 import java.awt.*;
32
33 /**
34  * @author yole
35  */
36 public class ColoredOutputTypeRegistry {
37   public static ColoredOutputTypeRegistry getInstance() {
38     return ServiceManager.getService(ColoredOutputTypeRegistry.class);
39   }
40
41   private static final TextAttributesKey[] myAnsiColorKeys = new TextAttributesKey[]{
42     ConsoleHighlighter.BLACK,
43     ConsoleHighlighter.RED,
44     ConsoleHighlighter.GREEN,
45     ConsoleHighlighter.YELLOW,
46     ConsoleHighlighter.BLUE,
47     ConsoleHighlighter.MAGENTA,
48     ConsoleHighlighter.CYAN,
49     ConsoleHighlighter.GRAY,
50
51     ConsoleHighlighter.DARKGRAY,
52     ConsoleHighlighter.RED_BRIGHT,
53     ConsoleHighlighter.GREEN_BRIGHT,
54     ConsoleHighlighter.YELLOW_BRIGHT,
55     ConsoleHighlighter.BLUE_BRIGHT,
56     ConsoleHighlighter.MAGENTA_BRIGHT,
57     ConsoleHighlighter.CYAN_BRIGHT,
58     ConsoleHighlighter.WHITE,
59   };
60
61   /*
62     Description
63      0  Cancel all attributes except foreground/background color
64      1  Bright (bold)
65      2  Normal (not bold)
66      4  Underline
67      5  Blink
68      7  Reverse video
69      8  Concealed (don't display characters)
70      30 Make foreground (the characters) black
71      31 Make foreground red
72      32 Make foreground green
73      33 Make foreground yellow
74      34 Make foreground blue
75      35 Make foreground magenta
76      36 Make foreground cyan
77      37 Make foreground white
78
79      40 Make background (around the characters) black
80      41 Make background red
81      42 Make background green
82      43 Make background yellow
83      44 Make background blue
84      45 Make background magenta
85      46 Make background cyan
86      47 Make background white (you may need 0 instead, or in addition)
87
88      see full doc at http://en.wikipedia.org/wiki/ANSI_escape_code
89   */
90
91   @NotNull
92   public Key getOutputKey(@NonNls String attribute) {
93     final String completeAttribute = attribute;
94     if (attribute.startsWith("\u001B[")) {
95       attribute = attribute.substring(2);
96     }
97     else {
98       attribute = StringUtil.trimStart(attribute, "[");
99     }
100     attribute = StringUtil.trimEnd(attribute, "m");
101     if (attribute.equals("0")) {
102       return ProcessOutputTypes.STDOUT;
103     }
104     TextAttributes attrs = new TextAttributes();
105     final String[] strings = attribute.split(";");
106     for (String string : strings) {
107       int value;
108       try {
109         value = Integer.parseInt(string);
110       }
111       catch (NumberFormatException e) {
112         continue;
113       }
114       if (value == 1) {
115         attrs.setFontType(Font.BOLD);
116       }
117       else if (value == 4) {
118         attrs.setEffectType(EffectType.LINE_UNDERSCORE);
119       }
120       else if (value == 22) {
121         attrs.setFontType(Font.PLAIN);
122       }
123       else if (value == 24) {  //not underlined
124         attrs.setEffectType(null);
125       }
126       else if (value >= 30 && value <= 37) {
127         attrs.setForegroundColor(getAnsiColor(value - 30));
128       }
129       else if (value == 38) {
130         //TODO: 256 colors foreground
131       }
132       else if (value == 39) {
133         attrs.setForegroundColor(getColorByKey(ConsoleViewContentType.NORMAL_OUTPUT_KEY));
134       }
135       else if (value >= 40 && value <= 47) {
136         attrs.setBackgroundColor(getAnsiColor(value - 40));
137       }
138       else if (value == 48) {
139         //TODO: 256 colors background
140       }
141       else if (value == 49) {
142         attrs.setBackgroundColor(getDefaultBackgroundColor());
143       }
144       else if (value >= 90 && value <= 97) {
145         attrs.setForegroundColor(
146           getAnsiColor(value - 82));
147       }
148       else if (value >= 100 && value <= 107) {
149         attrs.setBackgroundColor(
150           getAnsiColor(value - 92));
151       }
152     }
153     if (attrs.getEffectType() == EffectType.LINE_UNDERSCORE) {
154       attrs.setEffectColor(attrs.getForegroundColor());
155     }
156     Key newKey = new Key(completeAttribute);
157     ConsoleViewContentType contentType = new ConsoleViewContentType(completeAttribute, attrs);
158     ConsoleViewContentType.registerNewConsoleViewType(newKey, contentType);
159     return newKey;
160   }
161
162   private static Color getAnsiColor(final int value) {
163     return getColorByKey(getAnsiColorKey(value));
164   }
165
166   private static Color getColorByKey(TextAttributesKey colorKey) {
167     return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(colorKey).getForegroundColor();
168   }
169
170   @NotNull
171   private static Color getDefaultBackgroundColor() {
172     EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
173     Color color = scheme.getColor(ConsoleViewContentType.CONSOLE_BACKGROUND_KEY);
174     return ObjectUtils.notNull(color, scheme.getDefaultBackground());
175   }
176
177   public static TextAttributesKey getAnsiColorKey(int value) {
178     if (value >= 16) {
179       return ConsoleViewContentType.NORMAL_OUTPUT_KEY;
180     }
181     return myAnsiColorKeys[value];
182   }
183 }