enable in-place replace action for Analyze Stacktrace (IDEA-CR-9987)
[idea/community.git] / platform / platform-impl / src / com / intellij / execution / impl / ConsoleViewUtil.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.impl;
17
18 import com.intellij.execution.ui.ConsoleView;
19 import com.intellij.execution.ui.ConsoleViewContentType;
20 import com.intellij.ide.ui.LafManager;
21 import com.intellij.ide.ui.LafManagerListener;
22 import com.intellij.ide.ui.UISettings;
23 import com.intellij.lexer.Lexer;
24 import com.intellij.openapi.application.ApplicationManager;
25 import com.intellij.openapi.command.undo.UndoUtil;
26 import com.intellij.openapi.editor.*;
27 import com.intellij.openapi.editor.colors.*;
28 import com.intellij.openapi.editor.colors.impl.DelegateColorScheme;
29 import com.intellij.openapi.editor.ex.EditorEx;
30 import com.intellij.openapi.editor.impl.EditorFactoryImpl;
31 import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces;
32 import com.intellij.openapi.editor.markup.TextAttributes;
33 import com.intellij.openapi.fileTypes.FileType;
34 import com.intellij.openapi.fileTypes.SyntaxHighlighter;
35 import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
36 import com.intellij.openapi.project.Project;
37 import com.intellij.openapi.util.Key;
38 import com.intellij.psi.tree.IElementType;
39 import com.intellij.util.containers.ConcurrentFactoryMap;
40 import com.intellij.util.containers.ContainerUtil;
41 import org.jetbrains.annotations.NotNull;
42 import org.jetbrains.annotations.Nullable;
43
44 import java.awt.*;
45 import java.util.Arrays;
46 import java.util.List;
47 import java.util.Map;
48
49 import static com.intellij.execution.ui.ConsoleViewContentType.registerNewConsoleViewType;
50
51 /**
52  * @author peter
53  */
54 public class ConsoleViewUtil {
55
56   public static final Key<Boolean> EDITOR_IS_CONSOLE_VIEW = Key.create("EDITOR_IS_CONSOLE_VIEW");
57   private static final Key<Boolean> REPLACE_ACTION_ENABLED = Key.create("REPLACE_ACTION_ENABLED");
58
59   public static EditorEx setupConsoleEditor(Project project, final boolean foldingOutlineShown, final boolean lineMarkerAreaShown) {
60     EditorFactory editorFactory = EditorFactory.getInstance();
61     Document document = ((EditorFactoryImpl)editorFactory).createDocument(true);
62     UndoUtil.disableUndoFor(document);
63     EditorEx editor = (EditorEx) editorFactory.createViewer(document, project);
64     setupConsoleEditor(editor, foldingOutlineShown, lineMarkerAreaShown);
65     return editor;
66   }
67
68   public static void setupConsoleEditor(@NotNull final EditorEx editor, final boolean foldingOutlineShown, final boolean lineMarkerAreaShown) {
69     ApplicationManager.getApplication().runReadAction(new Runnable() {
70       @Override
71       public void run() {
72         editor.setSoftWrapAppliancePlace(SoftWrapAppliancePlaces.CONSOLE);
73
74         final EditorSettings editorSettings = editor.getSettings();
75         editorSettings.setLineMarkerAreaShown(lineMarkerAreaShown);
76         editorSettings.setIndentGuidesShown(false);
77         editorSettings.setLineNumbersShown(false);
78         editorSettings.setFoldingOutlineShown(foldingOutlineShown);
79         editorSettings.setAdditionalPageAtBottom(false);
80         editorSettings.setAdditionalColumnsCount(0);
81         editorSettings.setAdditionalLinesCount(0);
82         editorSettings.setRightMarginShown(false);
83         editorSettings.setCaretRowShown(false);
84         editor.getGutterComponentEx().setPaintBackground(false);
85
86         editor.putUserData(EDITOR_IS_CONSOLE_VIEW, true);
87
88         final DelegateColorScheme scheme = updateConsoleColorScheme(editor.getColorsScheme());
89         if (UISettings.getInstance().PRESENTATION_MODE) {
90           scheme.setEditorFontSize(UISettings.getInstance().PRESENTATION_MODE_FONT_SIZE);
91         }
92         editor.setColorsScheme(scheme);
93       }
94     });
95   }
96
97   @NotNull
98   public static DelegateColorScheme updateConsoleColorScheme(@NotNull EditorColorsScheme scheme) {
99     return new DelegateColorScheme(scheme) {
100       @NotNull
101       @Override
102       public Color getDefaultBackground() {
103         final Color color = getColor(ConsoleViewContentType.CONSOLE_BACKGROUND_KEY);
104         return color == null ? super.getDefaultBackground() : color;
105       }
106
107       @NotNull
108       @Override
109       public FontPreferences getFontPreferences() {
110         return getConsoleFontPreferences();
111       }
112
113       @Override
114       public int getEditorFontSize() {
115         return getConsoleFontSize();
116       }
117
118       @Override
119       public String getEditorFontName() {
120         return getConsoleFontName();
121       }
122
123       @Override
124       public float getLineSpacing() {
125         return getConsoleLineSpacing();
126       }
127
128       @Override
129       public Font getFont(EditorFontType key) {
130         return super.getFont(EditorFontType.getConsoleType(key));
131       }
132
133       @Override
134       public void setEditorFontSize(int fontSize) {
135         setConsoleFontSize(fontSize);
136       }
137     };
138   }
139
140   public static boolean isConsoleViewEditor(@NotNull Editor editor) {
141     return editor.getUserData(EDITOR_IS_CONSOLE_VIEW) == Boolean.TRUE;
142   }
143
144   public static boolean isReplaceActionEnabledForConsoleViewEditor(@NotNull Editor editor) {
145     return editor.getUserData(REPLACE_ACTION_ENABLED) == Boolean.TRUE;
146   }
147
148   public static void enableReplaceActionForConsoleViewEditor(@NotNull Editor editor) {
149     editor.putUserData(REPLACE_ACTION_ENABLED, true);
150   }
151
152   @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
153   private static class ColorCache {
154     static {
155       LafManager.getInstance().addLafManagerListener(new LafManagerListener() {
156         @Override
157         public void lookAndFeelChanged(LafManager source) {
158           mergedTextAttributes.clear();
159         }
160       });
161     }
162     static final Map<Key, List<TextAttributesKey>> textAttributeKeys = ContainerUtil.newConcurrentMap();
163     static final Map<Key, TextAttributes> mergedTextAttributes = new ConcurrentFactoryMap<Key, TextAttributes>() {
164       @Nullable
165       @Override
166       protected TextAttributes create(Key contentKey) {
167         EditorColorsScheme scheme = EditorColorsManager.getInstance().getGlobalScheme();
168         TextAttributes result = scheme.getAttributes(HighlighterColors.TEXT);
169         for (TextAttributesKey key : textAttributeKeys.get(contentKey)) {
170           TextAttributes attributes = scheme.getAttributes(key);
171           if (attributes != null) {
172             result = TextAttributes.merge(result, attributes);
173           }
174         }
175         return result;
176       }
177     };
178
179     static final Map<List<TextAttributesKey>, Key> keys = new ConcurrentFactoryMap<List<TextAttributesKey>, Key>() {
180       @Override
181       protected Key create(List<TextAttributesKey> keys) {
182         StringBuilder keyName = new StringBuilder("ConsoleViewUtil_");
183         for (TextAttributesKey key : keys) {
184           keyName.append("_").append(key.getExternalName());
185         }
186         final Key newKey = new Key(keyName.toString());
187         textAttributeKeys.put(newKey, keys);
188         ConsoleViewContentType contentType = new ConsoleViewContentType(keyName.toString(), HighlighterColors.TEXT) {
189           @Override
190           public TextAttributes getAttributes() {
191             return mergedTextAttributes.get(newKey);
192           }
193         };
194
195         registerNewConsoleViewType(newKey, contentType);
196         return newKey;
197       }
198     };
199   }
200
201   public static void printWithHighlighting(@NotNull ConsoleView console, @NotNull String text, @NotNull SyntaxHighlighter highlighter) {
202     Lexer lexer = highlighter.getHighlightingLexer();
203     lexer.start(text, 0, text.length(), 0);
204
205     IElementType tokenType;
206     while ((tokenType = lexer.getTokenType()) != null) {
207       console.print(lexer.getTokenText(), getContentTypeForToken(tokenType, highlighter));
208       lexer.advance();
209     }
210   }
211
212   @NotNull
213   public static ConsoleViewContentType getContentTypeForToken(@NotNull IElementType tokenType, @NotNull SyntaxHighlighter highlighter) {
214     TextAttributesKey[] keys = highlighter.getTokenHighlights(tokenType);
215     return keys.length == 0 ? ConsoleViewContentType.NORMAL_OUTPUT :
216            ConsoleViewContentType.getConsoleViewType(ColorCache.keys.get(Arrays.asList(keys)));
217   }
218
219   public static void printAsFileType(@NotNull ConsoleView console, @NotNull String text, @NotNull FileType fileType) {
220     SyntaxHighlighter highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(fileType, null, null);
221     if (highlighter != null) {
222       printWithHighlighting(console, text, highlighter);
223     }
224     else {
225       console.print(text, ConsoleViewContentType.NORMAL_OUTPUT);
226     }
227   }
228 }