--- /dev/null
+package com.intellij.execution.filters;
+
+import com.intellij.execution.ConsoleFolding;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.Trinity;
+
+import java.util.List;
+
+/**
+ * @author peter
+ */
+public class AuxiliaryCallsFolding extends ConsoleFolding {
+ @Override
+ public boolean shouldFoldLine(String line) {
+ final Trinity<String, String, TextRange> pair = ExceptionFilter.parseExceptionLine(line);
+ return pair != null && shouldFold(pair.first);
+ }
+
+ private static boolean shouldFold(String className) {
+ for (StackFrameFilter provider : StackFrameFilter.EP_NAME.getExtensions()) {
+ if (provider.isAuxiliaryFrame(className, "")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ @Override
+ public String getPlaceholderText(List<String> lines) {
+ return " <" + lines.size() + " internal calls>";
+ }
+}
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.awt.*;
mySearchScope = scope;
}
- public Result applyFilter(final String line, final int textEndOffset) {
+ @Nullable
+ static Trinity<String, String, TextRange> parseExceptionLine(final String line) {
int atIndex;
if (line.startsWith(AT_PREFIX)){
atIndex = 0;
final int lastDotIndex = line.lastIndexOf('.', lparenthIndex);
if (lastDotIndex < 0 || lastDotIndex < atIndex) return null;
String className = line.substring(atIndex + AT.length() + 1, lastDotIndex).trim();
- final boolean isInternal = shouldFold(className);
- final int dollarIndex = className.indexOf('$');
- if (dollarIndex >= 0){
- className = className.substring(0, dollarIndex);
- }
//String methodName = text.substring(lastDotIndex + 1, lparenthIndex).trim();
if (rparenthIndex < 0) return null;
final String fileAndLine = line.substring(lparenthIndex + 1, rparenthIndex).trim();
+ return Trinity.create(className, fileAndLine, new TextRange(lparenthIndex, rparenthIndex));
+ }
+
+ public Result applyFilter(final String line, final int textEndOffset) {
+ final Trinity<String, String, TextRange> info = parseExceptionLine(line);
+ if (info == null) {
+ return null;
+ }
+
+ String className = info.first;
+ final int dollarIndex = className.indexOf('$');
+ if (dollarIndex >= 0){
+ className = className.substring(0, dollarIndex);
+ }
+
+ final String fileAndLine = info.second;
final int colonIndex = fileAndLine.lastIndexOf(':');
if (colonIndex < 0) return null;
*/
final int textStartOffset = textEndOffset - line.length();
- final int highlightStartOffset = textStartOffset + lparenthIndex + 1;
- final int highlightEndOffset = textStartOffset + rparenthIndex;
+ final int highlightStartOffset = textStartOffset + info.third.getStartOffset() + 1;
+ final int highlightEndOffset = textStartOffset + info.third.getEndOffset();
VirtualFile virtualFile = file.getVirtualFile();
- final OpenFileHyperlinkInfo info = new OpenFileHyperlinkInfo(myProject, virtualFile, lineNumber - 1);
+ final OpenFileHyperlinkInfo linkInfo = new OpenFileHyperlinkInfo(myProject, virtualFile, lineNumber - 1);
TextAttributes attributes = HYPERLINK_ATTRIBUTES.clone();
if (!ProjectRootManager.getInstance(myProject).getFileIndex().isInContent(virtualFile)) {
Color color = UIUtil.getTextInactiveTextColor();
attributes.setForegroundColor(color);
attributes.setEffectColor(color);
}
- return new Result(highlightStartOffset, highlightEndOffset, info, attributes, isInternal);
+ return new Result(highlightStartOffset, highlightEndOffset, linkInfo, attributes);
}
catch(NumberFormatException e){
return null;
}
}
- private static boolean shouldFold(String className) {
- for (StackFrameFilter provider : StackFrameFilter.EP_NAME.getExtensions()) {
- if (provider.isInternalFrame(className, "")) {
- return true;
- }
- }
- return false;
- }
}
\ No newline at end of file
* @author peter
*/
public class ReflectionStackFrameFilter extends StackFrameFilter {
- public boolean isInternalFrame(String className, String methodName) {
+ public boolean isAuxiliaryFrame(String className, String methodName) {
return className.startsWith("sun.reflect.");
}
}
public abstract class StackFrameFilter {
public static final ExtensionPointName<StackFrameFilter> EP_NAME = ExtensionPointName.create("com.intellij.stackFrameFilter");
- public abstract boolean isInternalFrame(String className, String methodName);
+ public abstract boolean isAuxiliaryFrame(String className, String methodName);
}
public final int highlightEndOffset;
public final TextAttributes highlightAttributes;
public final HyperlinkInfo hyperlinkInfo;
- public final boolean isInternal;
public Result(final int highlightStartOffset, final int highlightEndOffset, final HyperlinkInfo hyperlinkInfo) {
this(highlightStartOffset, highlightEndOffset, hyperlinkInfo, null);
}
public Result(final int highlightStartOffset, final int highlightEndOffset, final HyperlinkInfo hyperlinkInfo, final TextAttributes highlightAttributes) {
- this(highlightStartOffset, highlightEndOffset, hyperlinkInfo, highlightAttributes, false);
- }
-
- public Result(final int highlightStartOffset, final int highlightEndOffset, final HyperlinkInfo hyperlinkInfo, final TextAttributes highlightAttributes, boolean isInternal) {
this.highlightStartOffset = highlightStartOffset;
this.highlightEndOffset = highlightEndOffset;
- this.highlightAttributes = highlightAttributes;
this.hyperlinkInfo = hyperlinkInfo;
- this.isInternal = isInternal;
+ this.highlightAttributes = highlightAttributes;
}
}
--- /dev/null
+package com.intellij.execution;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * @author peter
+ */
+public abstract class ConsoleFolding {
+ public static final ExtensionPointName<ConsoleFolding> EP_NAME = ExtensionPointName.create("com.intellij.console.folding");
+
+ public abstract boolean shouldFoldLine(String line);
+
+ @Nullable
+ public abstract String getPlaceholderText(List<String> lines);
+}
package com.intellij.execution.impl;
import com.intellij.codeInsight.navigation.IncrementalSearchHandler;
+import com.intellij.execution.ConsoleFolding;
import com.intellij.execution.ExecutionBundle;
import com.intellij.execution.filters.*;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.util.LocalTimeCounter;
import com.intellij.util.containers.HashMap;
import com.intellij.util.text.CharArrayUtil;
-import gnu.trove.THashSet;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
private ArrayList<TokenInfo> myTokens = new ArrayList<TokenInfo>();
private final Hyperlinks myHyperlinks = new Hyperlinks();
- private final TIntObjectHashMap<Boolean> myFolding = new TIntObjectHashMap<Boolean>();
+ private final TIntObjectHashMap<ConsoleFolding> myFolding = new TIntObjectHashMap<ConsoleFolding>();
private String myHelpId;
final int startLine = Math.max(0, line1);
- final Set<FoldRegion> toRemove = clearOutdatedFolding(document, endLine, startLine);
final List<FoldRegion> toAdd = new ArrayList<FoldRegion>();
for(int line = startLine; line <= endLine; line++) {
- final int startOffset = document.getLineStartOffset(line);
int endOffset = document.getLineEndOffset(line);
if (endOffset < document.getTextLength()) {
endOffset++; // add '\n'
}
- final String text = chars.subSequence(startOffset, endOffset).toString();
+ final String text = getLineText(document, line, true);
Filter.Result result = myCustomFilter.applyFilter(text, endOffset);
if (result == null) {
result = myPredefinedMessageFilter.applyFilter(text, endOffset);
final int highlightEndOffset = result.highlightEndOffset;
final HyperlinkInfo hyperlinkInfo = result.hyperlinkInfo;
addHyperlink(highlightStartOffset, highlightEndOffset, result.highlightAttributes, hyperlinkInfo, hyperlinkAttributes);
- addFolding(document, chars, line, result.isInternal, toAdd);
}
+ addFolding(document, chars, line, toAdd);
}
- if (!toAdd.isEmpty() || !toRemove.isEmpty()) {
- doUpdateFolding(toRemove, toAdd);
+ if (!toAdd.isEmpty()) {
+ doUpdateFolding(toAdd);
}
}
- private void doUpdateFolding(final Set<FoldRegion> toRemove, final List<FoldRegion> toAdd) {
+ private void doUpdateFolding(final List<FoldRegion> toAdd) {
final FoldingModel model = myEditor.getFoldingModel();
model.runBatchFoldingOperationDoNotCollapseCaret(new Runnable() {
public void run() {
- for (FoldRegion region : toRemove) {
- model.removeFoldRegion(region);
- }
for (FoldRegion region : toAdd) {
region.setExpanded(false);
model.addFoldRegion(region);
});
}
- private Set<FoldRegion> clearOutdatedFolding(Document document, int endLine, int startLine) {
- final THashSet<FoldRegion> toRemove = new THashSet<FoldRegion>();
- final int dirtyRegionStart = document.getLineStartOffset(startLine);
- final int diretyRegionEnd = document.getLineEndOffset(endLine);
- for (FoldRegion region : myEditor.getFoldingModel().getAllFoldRegions()) {
- final int regStart = region.getStartOffset();
- final int regEnd = region.getEndOffset();
- if (regStart >= dirtyRegionStart && regStart <= dirtyRegionStart ||
- regEnd >= dirtyRegionStart && regEnd <= diretyRegionEnd) {
- toRemove.add(region);
- }
- }
- return toRemove;
- }
+ private void addFolding(Document document, CharSequence chars, int line, List<FoldRegion> toAdd) {
+ ConsoleFolding current = foldingForLine(getLineText(document, line, false));
+ myFolding.put(line, current);
- private void addFolding(Document document, CharSequence chars, int line, boolean isInternal, List<FoldRegion> toAdd) {
- myFolding.put(line, isInternal);
- final Boolean prevFolding = myFolding.get(line - 1);
- if (!isInternal && Boolean.TRUE.equals(prevFolding)) {
+ final ConsoleFolding prevFolding = myFolding.get(line - 1);
+ if (current == null && prevFolding != null) {
final int lEnd = line - 1;
int lStart = lEnd;
- while (Boolean.TRUE.equals(myFolding.get(lStart - 1))) lStart--;
+ while (prevFolding.equals(myFolding.get(lStart - 1))) lStart--;
if (lStart == lEnd) {
return;
}
+ List<String> toFold = new ArrayList<String>(lEnd - lStart + 1);
+ for (int i = lStart; i <= lEnd; i++) {
+ toFold.add(getLineText(document, i, false));
+ }
+
int oStart = document.getLineStartOffset(lStart);
- oStart = CharArrayUtil.shiftForward(chars, oStart, " \t");
-// if (oStart > 0) oStart--;
+// oStart = CharArrayUtil.shiftForward(chars, oStart, " \t");
+ if (oStart > 0) oStart--;
int oEnd = CharArrayUtil.shiftBackward(chars, document.getLineEndOffset(lEnd) - 1, " \t") + 1;
- toAdd.add(new FoldRegionImpl(myEditor, oStart, oEnd, " " + (lEnd - lStart + 1) + " internal calls", null));
+ toAdd.add(new FoldRegionImpl(myEditor, oStart, oEnd, prevFolding.getPlaceholderText(toFold), null));
+ }
+ }
+
+ private static String getLineText(Document document, int lineNumber, boolean includeEol) {
+ int endOffset = document.getLineEndOffset(lineNumber);
+ if (includeEol && endOffset < document.getTextLength()) {
+ endOffset++;
+ }
+ return document.getCharsSequence().subSequence(document.getLineStartOffset(lineNumber), endOffset).toString();
+ }
+
+ private static ConsoleFolding foldingForLine(String lineText) {
+ ConsoleFolding current = null;
+ for (ConsoleFolding folding : ConsoleFolding.EP_NAME.getExtensions()) {
+ if (folding.shouldFoldLine(lineText)) {
+ current = folding;
+ }
}
+ return current;
}
private void addHyperlink(final int highlightStartOffset,
<extensionPoint name="consoleFilterProvider" interface="com.intellij.execution.filters.ConsoleFilterProvider"/>
- <extensionPoint name="stackFrameFilter" interface="com.intellij.execution.filters.StackFrameFilter"/>
+ <extensionPoint name="console.folding" interface="com.intellij.execution.ConsoleFolding"/>
<extensionPoint name="configurationProducer"
interface="com.intellij.execution.junit.RuntimeConfigurationProducer"/>
return list;
}
- public boolean isInternalFrame(String className, String methodName) {
+ public boolean isAuxiliaryFrame(String className, String methodName) {
+ if (className.equals("org.codehaus.groovy.runtime.DefaultGroovyMethods") ||
+ className.equals("org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport")) {
+ return false;
+ }
+
for (ClassFilter filter : FILTERS) {
final String pattern = filter.getPattern();
if (className.startsWith(pattern.substring(0, pattern.length() - 1))) {
<extensionPoint name="clsStubBuilderFactory" interface="com.intellij.psi.impl.compiled.ClsStubBuilderFactory"/>
<extensionPoint name="javaMainMethodProvider" interface="com.intellij.codeInsight.runner.JavaMainMethodProvider"/>
- <!--debugger-->
<extensionPoint name="debuggerClassFilterProvider" interface="com.intellij.ui.classFilter.DebuggerClassFilterProvider"/>
+ <extensionPoint name="stackFrameFilter" interface="com.intellij.execution.filters.StackFrameFilter"/>
+
<extensionPoint name="paletteItemProvider" area="IDEA_PROJECT" interface="com.intellij.ide.palette.PaletteItemProvider"/>
<extensionPoint name="javadocTagInfo" area="IDEA_PROJECT" interface="com.intellij.psi.javadoc.JavadocTagInfo"/>
<gotoFileContributor implementation="com.intellij.ide.util.gotoByName.ProjectBaseDirNavigationContributor"/>
<consoleFilterProvider implementation="com.intellij.execution.filters.DefaultConsoleFiltersProvider"/>
+ <console.folding implementation="com.intellij.execution.filters.AuxiliaryCallsFolding"/>
<stackFrameFilter implementation="com.intellij.execution.filters.ReflectionStackFrameFilter"/>