void (int startLine, int endLine) { ThreadingAssertions.assertEventDispatchThread(); Editor editor = getEditor(); editor.getFoldingModel().runBatchFoldingOperation(() -> { Document document = editor.getDocument(); FoldRegion existingRegion = null; if (startLine > 0) { int prevLineStart = document.getLineStartOffset(startLine - 1); FoldRegion[] regions = FoldingUtil.getFoldRegionsAtOffset(editor, prevLineStart); if (regions.length == 1) { existingRegion = regions[0]; } } ConsoleFolding lastFolding = existingRegion == null ? null : findFoldingByRegion(existingRegion); int lastStartLine = Integer.MAX_VALUE; if (lastFolding != null) { int offset = existingRegion.getStartOffset(); if (offset == 0) { lastStartLine = 0; } else { lastStartLine = document.getLineNumber(offset); if (document.getLineStartOffset(lastStartLine) != offset) lastStartLine++; } } List<ConsoleFolding> extensions = ContainerUtil.filter(ConsoleFolding.EP_NAME.getExtensionList(), cf -> cf.isEnabledForConsole(this)); if (extensions.isEmpty()) return; for (int line = startLine; line <= endLine; line++) { /* Grep Console plugin allows to fold empty lines. We need to handle this case in a special way. Multiple lines are grouped into one folding, but to know when you can create the folding, you need a line which does not belong to that folding. When a new line, or a chunk of lines is printed, #addFolding is called for that lines + for an empty string (which basically does only one thing, gets a folding displayed). We do not want to process that empty string, but also we do not want to wait for another line which will create and display the folding - we'd see an unfolded stacktrace until another text came and flushed it. Thus, the condition: the last line(empty string) should still flush, but not be processed by com.intellij.execution.ConsoleFolding. */ ConsoleFolding next = line < endLine ? foldingForLine(extensions, line, document) : null; if (next != lastFolding) { if (lastFolding != null) { boolean isExpanded = false; if (line > startLine && existingRegion != null && lastStartLine < startLine) { isExpanded = existingRegion.isExpanded(); editor.getFoldingModel().removeFoldRegion(existingRegion); } addFoldRegion(document, lastFolding, lastStartLine, line - 1, isExpanded); } lastFolding = next; lastStartLine = line; existingRegion = null; } } }); }