From 748d6a4c023cc6f6f5b62692815114d098d8a097 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 4 Mar 2010 17:50:44 +0000 Subject: [PATCH] generic API for console folding --- .../filters/AuxiliaryCallsFolding.java | 33 +++++++++ .../execution/filters/ExceptionFilter.java | 43 ++++++----- .../filters/ReflectionStackFrameFilter.java | 2 +- .../execution/filters/StackFrameFilter.java | 2 +- .../intellij/execution/filters/Filter.java | 8 +- .../intellij/execution/ConsoleFolding.java | 18 +++++ .../execution/impl/ConsoleViewImpl.java | 73 ++++++++++--------- .../src/META-INF/LangExtensionPoints.xml | 2 +- .../GroovyDebuggerClassFilterProvider.java | 7 +- resources/src/META-INF/IdeaPlugin.xml | 4 +- 10 files changed, 128 insertions(+), 64 deletions(-) create mode 100644 java/execution/openapi/src/com/intellij/execution/filters/AuxiliaryCallsFolding.java create mode 100644 platform/lang-impl/src/com/intellij/execution/ConsoleFolding.java diff --git a/java/execution/openapi/src/com/intellij/execution/filters/AuxiliaryCallsFolding.java b/java/execution/openapi/src/com/intellij/execution/filters/AuxiliaryCallsFolding.java new file mode 100644 index 000000000000..5240ad7b7add --- /dev/null +++ b/java/execution/openapi/src/com/intellij/execution/filters/AuxiliaryCallsFolding.java @@ -0,0 +1,33 @@ +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 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 lines) { + return " <" + lines.size() + " internal calls>"; + } +} diff --git a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java index 701cb8de59f2..6b05b21f3fa6 100644 --- a/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java +++ b/java/execution/openapi/src/com/intellij/execution/filters/ExceptionFilter.java @@ -21,6 +21,8 @@ import com.intellij.openapi.editor.markup.TextAttributes; 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; @@ -30,6 +32,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.awt.*; @@ -51,7 +54,8 @@ public class ExceptionFilter implements Filter, DumbAware { mySearchScope = scope; } - public Result applyFilter(final String line, final int textEndOffset) { + @Nullable + static Trinity parseExceptionLine(final String line) { int atIndex; if (line.startsWith(AT_PREFIX)){ atIndex = 0; @@ -69,11 +73,6 @@ public class ExceptionFilter implements Filter, DumbAware { 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(); @@ -81,6 +80,22 @@ public class ExceptionFilter implements Filter, DumbAware { 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 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; @@ -103,29 +118,21 @@ public class ExceptionFilter implements Filter, DumbAware { */ 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 diff --git a/java/execution/openapi/src/com/intellij/execution/filters/ReflectionStackFrameFilter.java b/java/execution/openapi/src/com/intellij/execution/filters/ReflectionStackFrameFilter.java index 14714a25b380..ed60d87c0b4d 100644 --- a/java/execution/openapi/src/com/intellij/execution/filters/ReflectionStackFrameFilter.java +++ b/java/execution/openapi/src/com/intellij/execution/filters/ReflectionStackFrameFilter.java @@ -4,7 +4,7 @@ package com.intellij.execution.filters; * @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."); } } diff --git a/java/execution/openapi/src/com/intellij/execution/filters/StackFrameFilter.java b/java/execution/openapi/src/com/intellij/execution/filters/StackFrameFilter.java index a07d058f673f..25f6cdb1b07c 100644 --- a/java/execution/openapi/src/com/intellij/execution/filters/StackFrameFilter.java +++ b/java/execution/openapi/src/com/intellij/execution/filters/StackFrameFilter.java @@ -8,6 +8,6 @@ import com.intellij.openapi.extensions.ExtensionPointName; public abstract class StackFrameFilter { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.stackFrameFilter"); - public abstract boolean isInternalFrame(String className, String methodName); + public abstract boolean isAuxiliaryFrame(String className, String methodName); } diff --git a/platform/lang-api/src/com/intellij/execution/filters/Filter.java b/platform/lang-api/src/com/intellij/execution/filters/Filter.java index 2346497b07d2..264792ec8723 100644 --- a/platform/lang-api/src/com/intellij/execution/filters/Filter.java +++ b/platform/lang-api/src/com/intellij/execution/filters/Filter.java @@ -28,22 +28,16 @@ public interface Filter { 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; } } diff --git a/platform/lang-impl/src/com/intellij/execution/ConsoleFolding.java b/platform/lang-impl/src/com/intellij/execution/ConsoleFolding.java new file mode 100644 index 000000000000..32f781410e6c --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/ConsoleFolding.java @@ -0,0 +1,18 @@ +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 EP_NAME = ExtensionPointName.create("com.intellij.console.folding"); + + public abstract boolean shouldFoldLine(String line); + + @Nullable + public abstract String getPlaceholderText(List lines); +} diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index af7bbefa5b70..d5e20a06b5dd 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -17,6 +17,7 @@ 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; @@ -73,7 +74,6 @@ import com.intellij.util.EditorPopupHandler; 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; @@ -172,7 +172,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo private ArrayList myTokens = new ArrayList(); private final Hyperlinks myHyperlinks = new Hyperlinks(); - private final TIntObjectHashMap myFolding = new TIntObjectHashMap(); + private final TIntObjectHashMap myFolding = new TIntObjectHashMap(); private String myHelpId; @@ -807,16 +807,14 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo final int startLine = Math.max(0, line1); - final Set toRemove = clearOutdatedFolding(document, endLine, startLine); final List toAdd = new ArrayList(); 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); @@ -826,21 +824,18 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo 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 toRemove, final List toAdd) { + private void doUpdateFolding(final List 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); @@ -849,41 +844,51 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo }); } - private Set clearOutdatedFolding(Document document, int endLine, int startLine) { - final THashSet toRemove = new THashSet(); - 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 toAdd) { + ConsoleFolding current = foldingForLine(getLineText(document, line, false)); + myFolding.put(line, current); - private void addFolding(Document document, CharSequence chars, int line, boolean isInternal, List 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 toFold = new ArrayList(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, final int highlightEndOffset, final TextAttributes highlightAttributes, diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index bbe0d6f0b4fd..51dc6c039dbf 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -239,7 +239,7 @@ - + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/filters/GroovyDebuggerClassFilterProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/filters/GroovyDebuggerClassFilterProvider.java index 6e992b1f5e0c..3e0a45dd38de 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/filters/GroovyDebuggerClassFilterProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/filters/GroovyDebuggerClassFilterProvider.java @@ -41,7 +41,12 @@ public class GroovyDebuggerClassFilterProvider extends StackFrameFilter implemen 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))) { diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index f14242a4f49d..9d64b8b58933 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -141,9 +141,10 @@ - + + @@ -711,6 +712,7 @@ +