@Contract("null, _, _ -> null") private static String toCanonicalPath( @Nullable String path, char separatorChar, boolean removeLastSlash) { if (path == null || path.isEmpty()) { return path; } else if (".".equals(path)) { return ""; } path = path.replace(separatorChar, '/'); if (path.indexOf('/') == -1) { return path; } int start = pathRootEnd(path) + 1, dots = 0; boolean separator = true; StringBuilder result = new StringBuilder(path.length()); result.append(path, 0, start); for (int i = start; i < path.length(); ++i) { char c = path.charAt(i); if (c == '/') { if (!separator) { processDots(result, dots, start); dots = 0; } separator = true; } else if (c == '.') { if (separator || dots > 0) { ++dots; } else { result.append('.'); } separator = false; } else { if (dots > 0) { StringUtil.repeatSymbol(result, '.', dots); dots = 0; } result.append(c); separator = false; } } if (dots > 0) { processDots(result, dots, start); } int lastChar = result.length() - 1; if (removeLastSlash && lastChar >= 0 && result.charAt(lastChar) == '/' && lastChar > start) { result.deleteCharAt(lastChar); } return result.toString(); }
protected String doCalculateSignature(PsiMethod method) { final StringBuilder buffer = new StringBuilder(); final PsiModifierList modifierList = method.getModifierList(); String modifiers = modifierList.getText(); final String oldModifier = VisibilityUtil.getVisibilityModifier(modifierList); final String newModifier = getVisibility(); String newModifierStr = VisibilityUtil.getVisibilityString(newModifier); if (!newModifier.equals(oldModifier)) { int index = modifiers.indexOf(oldModifier); if (index >= 0) { final StringBuilder buf = new StringBuilder(modifiers); buf.replace( index, index + oldModifier.length() + ("".equals(newModifierStr) ? 1 : 0), newModifierStr); modifiers = buf.toString(); } else { if (!StringUtil.isEmpty(newModifierStr)) { newModifierStr += " "; } modifiers = newModifierStr + modifiers; } } buffer.append(modifiers); if (modifiers.length() > 0 && !StringUtil.endsWithChar(modifiers, '\n') && !StringUtil.endsWithChar(modifiers, '\r') && !StringUtil.endsWithChar(modifiers, ' ')) { buffer.append(" "); } if (!method.isConstructor()) { final CanonicalTypes.Type type = getReturnType(); if (type != null) { buffer.append(type.getTypeText()); } buffer.append(" "); } buffer.append(getMethodName()); buffer.append("("); final int lineBreakIdx = buffer.lastIndexOf("\n"); String indent = StringUtil.repeatSymbol( ' ', lineBreakIdx >= 0 ? buffer.length() - lineBreakIdx - 1 : buffer.length()); List<ParameterTableModelItemBase<ParameterInfoImpl>> items = myParametersTableModel.getItems(); int curIndent = indent.length(); for (int i = 0; i < items.size(); i++) { final ParameterTableModelItemBase<ParameterInfoImpl> item = items.get(i); if (i > 0) { buffer.append(","); buffer.append("\n"); buffer.append(indent); } final String text = item.typeCodeFragment.getText(); buffer.append(text).append(" "); final String name = item.parameter.getName(); buffer.append(name); curIndent = indent.length() + text.length() + 1 + name.length(); } // if (!items.isEmpty()) { // buffer.append("\n"); // } buffer.append(")"); PsiTypeCodeFragment[] thrownExceptionsFragments = myExceptionsModel.getTypeCodeFragments(); if (thrownExceptionsFragments.length > 0) { // buffer.append("\n"); buffer.append(" throws "); curIndent += 9; // ") throws ".length() indent = StringUtil.repeatSymbol(' ', curIndent); for (int i = 0; i < thrownExceptionsFragments.length; i++) { String text = thrownExceptionsFragments[i].getText(); if (i != 0) buffer.append(indent); buffer.append(text); if (i < thrownExceptionsFragments.length - 1) { buffer.append(","); } buffer.append("\n"); } } return buffer.toString(); }
@NotNull private static String getMultilineDocCommentText(final @NotNull DartDocComment docComment) { final StringBuilder buf = new StringBuilder(); boolean afterAsterisk = false; for (PsiElement child = docComment.getFirstChild(); child != null; child = child.getNextSibling()) { final IElementType elementType = child.getNode().getElementType(); final String text = child.getText(); if (elementType != DartTokenTypesSets.MULTI_LINE_DOC_COMMENT_START && elementType != DartTokenTypesSets.DOC_COMMENT_LEADING_ASTERISK && elementType != DartTokenTypesSets.MULTI_LINE_COMMENT_END) { int newLinesCount; if (child instanceof PsiWhiteSpace && (newLinesCount = StringUtil.countNewLines(text)) > 0) { buf.append(StringUtil.repeatSymbol('\n', newLinesCount)); } else { if (afterAsterisk && text.startsWith(" ")) { buf.append(text.substring(1)); } else { buf.append(text); } } } afterAsterisk = elementType == DartTokenTypesSets.DOC_COMMENT_LEADING_ASTERISK; } return buf.toString(); }
@NotNull public static String shiftIndentInside( @NotNull String initial, final int i, boolean shiftEmptyLines) { StringBuilder result = new StringBuilder(initial.length()); List<byte[]> lines; try { LineReader reader = new LineReader(new ByteArrayInputStream(initial.getBytes(CharsetToolkit.UTF8_CHARSET))); lines = reader.readLines(); } catch (IOException e) { throw new RuntimeException(e); } boolean first = true; for (byte[] line : lines) { try { if (!first) result.append('\n'); if (line.length > 0 || shiftEmptyLines) { StringUtil.repeatSymbol(result, ' ', i); } result.append(new String(line)); } finally { first = false; } } return result.toString(); }
public void testE5() { DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', 10)); List<RangeMarker> mm = add(document, 9, 9, 4, 4, 1, 7, 7, 7, 4, 7); edit(document, 1, 5, 0); delete(mm, 3); }
public void testE13() { DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', 10)); List<RangeMarker> mm = add(document, 5, 9, 9, 9, 7, 7, 6, 8); edit(document, 2, 1, 0); delete(mm, 0, 2); }
public void testRangeHighlighterLinesInRangeForLongLinePerformance() throws Exception { final int N = 50000; Document document = EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol('x', 2 * N)); final MarkupModelEx markupModel = (MarkupModelEx) DocumentMarkupModel.forDocument(document, ourProject, true); for (int i = 0; i < N - 1; i++) { markupModel.addRangeHighlighter(2 * i, 2 * i + 1, 0, null, HighlighterTargetArea.EXACT_RANGE); } markupModel.addRangeHighlighter( N / 2, N / 2 + 1, 0, null, HighlighterTargetArea.LINES_IN_RANGE); PlatformTestUtil.startPerformanceTest( "slow highlighters lookup", (int) (N * Math.log(N) / 1000), new ThrowableRunnable() { @Override public void run() { List<RangeHighlighterEx> list = new ArrayList<RangeHighlighterEx>(); CommonProcessors.CollectProcessor<RangeHighlighterEx> coll = new CommonProcessors.CollectProcessor<RangeHighlighterEx>(list); for (int i = 0; i < N - 1; i++) { list.clear(); markupModel.processRangeHighlightersOverlappingWith(2 * i, 2 * i + 1, coll); assertEquals(2, list.size()); // 1 line plus one exact range marker } } }) .assertTiming(); }
static void log( ProgressIndicator progressIndicator, TextEditorHighlightingPass pass, @NonNls @NotNull Object... info) { if (LOG.isDebugEnabled()) { CharSequence docText = pass == null || pass.getDocument() == null ? "" : ": '" + StringUtil.first(pass.getDocument().getCharsSequence(), 10, true) + "'"; synchronized (PassExecutorService.class) { String infos = StringUtil.join(info, Functions.TO_STRING(), " "); String message = StringUtil.repeatSymbol(' ', getThreadNum() * 4) + " " + pass + " " + infos + "; progress=" + (progressIndicator == null ? null : progressIndicator.hashCode()) + " " + (progressIndicator == null ? "?" : progressIndicator.isCanceled() ? "X" : "V") + docText; LOG.debug(message); // System.out.println(message); } } }
@SuppressWarnings("ForLoopThatDoesntUseLoopVariable") private static void indentPlainTextBlock( final Document document, final int startOffset, final int endOffset, final int indentLevel) { CharSequence chars = document.getCharsSequence(); int spaceEnd = CharArrayUtil.shiftForward(chars, startOffset, " \t"); int line = document.getLineNumber(startOffset); if (spaceEnd > endOffset || indentLevel <= 0 || line >= document.getLineCount() - 1 || chars.charAt(spaceEnd) == '\n') { return; } int linesToAdjustIndent = 0; for (int i = line + 1; i < document.getLineCount(); i++) { if (document.getLineStartOffset(i) >= endOffset) { break; } linesToAdjustIndent++; } String indentString = StringUtil.repeatSymbol(' ', indentLevel); for (; linesToAdjustIndent > 0; linesToAdjustIndent--) { int lineStartOffset = document.getLineStartOffset(++line); document.insertString(lineStartOffset, indentString); } }
public void testE11() { DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', 10)); List<RangeMarker> mm = add(document, 9, 9, 7, 7, 1, 6, 3, 7); // edit(document, 0,0,0); delete(mm, 1); }
public void testE4() { DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', 10)); List<RangeMarker> mm = add(document, 3, 5, 5, 6, 4, 8, 6, 9, 8, 9); edit(document, 6, 0, 0, 3, 0, 2); delete(mm, 1, 0); }
private static void edit(DocumentEx document, int... offsets) { for (int i = 0; i < offsets.length; i += 3) { int offset = offsets[i]; int oldlength = offsets[i + 1]; int newlength = offsets[i + 2]; document.replaceString(offset, offset + oldlength, StringUtil.repeatSymbol(' ', newlength)); } }
public static void log(@NonNls @NotNull Object... info) { if (IN_TESTS) { if (log.length() > 10000) { log.replace(0, log.length() - 5000, ""); } String s = StringUtil.repeatSymbol(' ', getThreadNum() * 4) + Arrays.asList(info) + "\n"; log.append(s); } }
public void testE14() { DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', 100)); List<RangeMarker> mm = add( document, 6, 11, 2, 13, 17, 17, 13, 19, 2, 3, 9, 10, 10, 11, 14, 14, 1, 3, 4, 12, 14, 15, 3, 10, 14, 14, 4, 4, 4, 8, 6, 14, 8, 16, 2, 12, 11, 19, 10, 13); edit(document, 19, 0, 0, 7, 3, 0, 16, 0, 3); }
public void testE15() { DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', 100)); List<RangeMarker> mm = add( document, 90, 93, 0, 9, 44, 79, 4, 48, 44, 99, 53, 64, 59, 82, 12, 99, 81, 86, 8, 40, 24, 55, 32, 50, 74, 79, 14, 94, 7, 14); edit(document, 34, 0, 4, 99, 0, 3); }
public void testE16() { DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', 100)); List<RangeMarker> mm = add( document, 29, 63, 47, 52, 72, 86, 19, 86, 13, 55, 18, 57, 92, 95, 83, 99, 41, 80, 53, 85, 10, 30, 28, 44, 23, 32, 70, 95, 14, 28); edit(document, 67, 5, 0, 1, 0, 4); delete(mm, 11); }
public void testX() { RangeMarkerEx marker1 = createMarker(StringUtil.repeatSymbol(' ', 10), 3, 6); DocumentEx document = (DocumentEx) marker1.getDocument(); document.createRangeMarker(2, 3); document.createRangeMarker(3, 8); document.createRangeMarker(7, 9); RangeMarkerEx r1 = (RangeMarkerEx) document.createRangeMarker(6, 8); r1.dispose(); marker1.dispose(); }
public void testE17() { DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', 100)); List<RangeMarker> mm = add( document, 15, 85, 79, 88, 90, 94, 43, 67, 54, 89, 81, 98, 1, 34, 58, 93, 22, 23, 44, 45, 63, 84, 45, 76, 58, 87, 40, 59, 5, 81, 95, 95, 12, 61, 52, 65, 80, 95, 6, 16, 7, 67, 59, 63, 91, 96, 99, 99, 50, 96, 72, 78, 78, 78, 85, 85, 5, 51, 90, 91); edit(document, 20, 26, 0, 15, 0, 4, 64, 4, 0); }
private static void printImpl( JTree tree, Object root, Collection<String> strings, int level, boolean withSelection, @Nullable Condition<String> nodePrintCondition) { DefaultMutableTreeNode defaultMutableTreeNode = (DefaultMutableTreeNode) root; final Object userObject = defaultMutableTreeNode.getUserObject(); String nodeText; if (userObject != null) { nodeText = toString(userObject, null); } else { nodeText = "null"; } if (nodePrintCondition != null && !nodePrintCondition.value(nodeText)) return; final StringBuilder buff = new StringBuilder(); StringUtil.repeatSymbol(buff, ' ', level); final boolean expanded = tree.isExpanded(new TreePath(defaultMutableTreeNode.getPath())); if (!defaultMutableTreeNode.isLeaf()) { buff.append(expanded ? "-" : "+"); } final boolean selected = tree.getSelectionModel().isPathSelected(new TreePath(defaultMutableTreeNode.getPath())); if (withSelection && selected) { buff.append("["); } buff.append(nodeText); if (withSelection && selected) { buff.append("]"); } strings.add(buff.toString()); int childCount = tree.getModel().getChildCount(root); if (expanded) { for (int i = 0; i < childCount; i++) { printImpl( tree, tree.getModel().getChild(root, i), strings, level + 1, withSelection, nodePrintCondition); } } }
public void _testRandomAddRemove() { int N = 100; for (int ti = 0; ; ti++) { if (ti % 10000 == 0) System.out.println(ti); DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', N)); Random gen = new Random(); List<Pair<RangeMarker, TextRange>> adds = new ArrayList<Pair<RangeMarker, TextRange>>(); List<Pair<RangeMarker, TextRange>> dels = new ArrayList<Pair<RangeMarker, TextRange>>(); try { for (int i = 0; i < 30; i++) { int x = gen.nextInt(N); int y = x + gen.nextInt(N - x); if (gen.nextBoolean()) { x = 0; y = document.getTextLength(); } RangeMarkerEx r = (RangeMarkerEx) document.createRangeMarker(x, y); adds.add(Pair.create((RangeMarker) r, TextRange.create(r))); } List<Pair<RangeMarker, TextRange>> candidates = new ArrayList<Pair<RangeMarker, TextRange>>(adds); while (!candidates.isEmpty()) { int size = candidates.size(); int x = gen.nextInt(size); Pair<RangeMarker, TextRange> c = candidates.remove(x); RangeMarkerEx r = (RangeMarkerEx) c.first; assertEquals(size - 1, candidates.size()); dels.add(c); r.dispose(); } } catch (AssertionError e) { String s = "adds: "; for (Pair<RangeMarker, TextRange> c : adds) { TextRange t = c.second; s += t.getStartOffset() + "," + t.getEndOffset() + ", "; } s += "\ndels: "; for (Pair<RangeMarker, TextRange> c : dels) { int index = adds.indexOf(c); assertSame(c, adds.get(index)); s += index + ", "; } System.err.println(s); throw e; } } }
@Override protected JComponent getRowPresentation( ParameterTableModelItemBase<ParameterInfoImpl> item, boolean selected, final boolean focused) { final JPanel panel = new JPanel(new BorderLayout()); final String typeText = item.typeCodeFragment.getText(); final String separator = StringUtil.repeatSymbol(' ', getTypesMaxLength() - typeText.length() + 1); String text = typeText + separator + item.parameter.getName(); final String defaultValue = item.defaultValueCodeFragment.getText(); String tail = ""; if (StringUtil.isNotEmpty(defaultValue)) { tail += " default value = " + defaultValue; } if (item.parameter.isUseAnySingleVariable()) { if (StringUtil.isNotEmpty(defaultValue)) { tail += ";"; } tail += " Use any var."; } if (!StringUtil.isEmpty(tail)) { text += " //" + tail; } final EditorTextField field = new EditorTextField(" " + text, getProject(), getFileType()) { @Override protected boolean shouldHaveBorder() { return false; } }; Font font = EditorColorsManager.getInstance().getGlobalScheme().getFont(EditorFontType.PLAIN); font = new Font(font.getFontName(), font.getStyle(), 12); field.setFont(font); if (selected && focused) { panel.setBackground(UIUtil.getTableSelectionBackground()); field.setAsRendererWithSelection( UIUtil.getTableSelectionBackground(), UIUtil.getTableSelectionForeground()); } else { panel.setBackground(UIUtil.getTableBackground()); if (selected && !focused) { panel.setBorder(new DottedBorder(UIUtil.getTableForeground())); } } panel.add(field, BorderLayout.WEST); return panel; }
public static void deleteToTargetPosition(@NotNull Editor editor, @NotNull LogicalPosition pos) { LogicalPosition logicalPosition = editor.getCaretModel().getLogicalPosition(); if (logicalPosition.line != pos.line) { LOGGER.error( "Unexpected caret position: " + logicalPosition + ", target indent position: " + pos); return; } if (pos.column < logicalPosition.column) { int targetOffset = editor.logicalPositionToOffset(pos); int offset = editor.getCaretModel().getOffset(); editor.getSelectionModel().setSelection(targetOffset, offset); EditorModificationUtil.deleteSelectedText(editor); } else if (pos.column > logicalPosition.column) { EditorModificationUtil.insertStringAtCaret( editor, StringUtil.repeatSymbol(' ', pos.column - logicalPosition.column)); } }
private static int doPrint( StringBuilder buffer, int currentLevel, Object node, AbstractTreeStructure structure, @Nullable Comparator comparator, int maxRowCount, int currentLine, char paddingChar, @Nullable Queryable.PrintInfo printInfo) { if (currentLine >= maxRowCount && maxRowCount != -1) return currentLine; StringUtil.repeatSymbol(buffer, paddingChar, currentLevel); buffer.append(toString(node, printInfo)).append("\n"); currentLine++; Object[] children = structure.getChildElements(node); if (comparator != null) { ArrayList<?> list = new ArrayList<Object>(Arrays.asList(children)); @SuppressWarnings({"UnnecessaryLocalVariable", "unchecked"}) Comparator<Object> c = comparator; Collections.sort(list, c); children = ArrayUtil.toObjectArray(list); } for (Object child : children) { currentLine = doPrint( buffer, currentLevel + 1, child, structure, comparator, maxRowCount, currentLine, paddingChar, printInfo); } return currentLine; }
private static void addFormattedDocString( PsiElement element, @NotNull String docstring, ChainIterable<String> formattedOutput, ChainIterable<String> unformattedOutput) { final Project project = element.getProject(); List<String> formatted = PyStructuredDocstringFormatter.formatDocstring(element, docstring); if (formatted != null) { unformattedOutput.add(formatted); return; } boolean isFirstLine; final List<String> result = new ArrayList<String>(); String[] lines = removeCommonIndentation(docstring); // reconstruct back, dropping first empty fragment as needed isFirstLine = true; int tabSize = CodeStyleSettingsManager.getSettings(project).getTabSize(PythonFileType.INSTANCE); for (String line : lines) { if (isFirstLine && ourSpacesPattern.matcher(line).matches()) continue; // ignore all initial whitespace if (isFirstLine) { isFirstLine = false; } else { result.add(BR); } int leadingTabs = 0; while (leadingTabs < line.length() && line.charAt(leadingTabs) == '\t') { leadingTabs++; } if (leadingTabs > 0) { line = StringUtil.repeatSymbol(' ', tabSize * leadingTabs) + line.substring(leadingTabs); } result.add(combUp(line)); } formattedOutput.add(result); }
private static void processDots(StringBuilder result, int dots, int start) { if (dots == 2) { int pos = -1; if (!StringUtil.endsWith(result, "/../") && !StringUtil.equals(result, "../")) { pos = StringUtil.lastIndexOf(result, '/', start, result.length() - 1); if (pos >= 0) { ++pos; // separator found, trim to next char } else if (start > 0) { pos = start; // path is absolute, trim to root ('/..' -> '/') } else if (result.length() > 0) { pos = 0; // path is relative, trim to default ('a/..' -> '') } } if (pos >= 0) { result.delete(pos, result.length()); } else { result.append("../"); // impossible to traverse, keep as-is } } else if (dots != 1) { StringUtil.repeatSymbol(result, '.', dots); result.append('/'); } }
public void testE9() { DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', 10)); List<RangeMarker> mm = add(document, 4, 5, 9, 9, 1, 2, 0, 3); edit(document, 0, 3, 0); }
public void testE10() { DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', 10)); List<RangeMarker> mm = add(document, 9, 9, 6, 8, 8, 8, 5, 9); edit(document, 2, 6, 0, 2, 0, 4); }
void doPrintNotification(final Notification notification) { Editor editor = myLogEditor.getValue(); if (editor.isDisposed()) { return; } Document document = editor.getDocument(); boolean scroll = document.getTextLength() == editor.getCaretModel().getOffset() || !editor.getContentComponent().hasFocus(); Long notificationTime = myProjectModel.getNotificationTime(notification); if (notificationTime == null) { return; } String date = DateFormatUtil.formatTimeWithSeconds(notificationTime) + " "; append(document, date); int startLine = document.getLineCount() - 1; EventLog.LogEntry pair = EventLog.formatForLog(notification, StringUtil.repeatSymbol(' ', date.length())); final NotificationType type = notification.getType(); TextAttributesKey key = type == NotificationType.ERROR ? ConsoleViewContentType.LOG_ERROR_OUTPUT_KEY : type == NotificationType.INFORMATION ? ConsoleViewContentType.NORMAL_OUTPUT_KEY : ConsoleViewContentType.LOG_WARNING_OUTPUT_KEY; int msgStart = document.getTextLength(); String message = pair.message; append(document, message); TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(key); int layer = HighlighterLayer.CARET_ROW + 1; editor .getMarkupModel() .addRangeHighlighter( msgStart, document.getTextLength(), layer, attributes, HighlighterTargetArea.EXACT_RANGE); for (Pair<TextRange, HyperlinkInfo> link : pair.links) { myHyperlinkSupport .getValue() .addHyperlink( link.first.getStartOffset() + msgStart, link.first.getEndOffset() + msgStart, null, link.second); } append(document, "\n"); if (scroll) { editor.getCaretModel().moveToOffset(document.getTextLength()); editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); } if (notification.isImportant()) { highlightNotification(notification, pair.status, startLine, document.getLineCount() - 1); } }
private static String genSameLineFeed(String text) { final int count = StringUtil.countChars(text, '\n'); return StringUtil.repeatSymbol('\n', count); }
public void testRandomEdit_NoCommand() { final int N = 100; final Random gen = new Random(); int N_TRIES = Timings.adjustAccordingToMySpeed(7000, false); System.out.println("N_TRIES = " + N_TRIES); DocumentEx document = null; for (int tryn = 0; tryn < N_TRIES; tryn++) { ((UndoManagerImpl) UndoManager.getInstance(getProject())).flushCurrentCommandMerger(); ((UndoManagerImpl) UndoManager.getGlobalInstance()).flushCurrentCommandMerger(); if (document != null) { ((UndoManagerImpl) UndoManager.getInstance(getProject())) .clearUndoRedoQueueInTests(document); ((UndoManagerImpl) UndoManager.getGlobalInstance()).clearUndoRedoQueueInTests(document); } if (tryn % 10000 == 0) { System.out.println(tryn); } document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', N)); final DocumentEx finalDocument = document; new WriteCommandAction(getProject()) { @Override protected void run(@NotNull Result result) throws Exception { List<Pair<RangeMarker, TextRange>> adds = new ArrayList<Pair<RangeMarker, TextRange>>(); List<Pair<RangeMarker, TextRange>> dels = new ArrayList<Pair<RangeMarker, TextRange>>(); List<Trinity<Integer, Integer, Integer>> edits = new ArrayList<Trinity<Integer, Integer, Integer>>(); try { for (int i = 0; i < 30; i++) { int x = gen.nextInt(N); int y = x + gen.nextInt(N - x); RangeMarkerEx r = (RangeMarkerEx) finalDocument.createRangeMarker(x, y); adds.add(Pair.create((RangeMarker) r, TextRange.create(r))); } for (int i = 0; i < 10; i++) { int offset = gen.nextInt(finalDocument.getTextLength()); if (gen.nextBoolean()) { int length = gen.nextInt(5); edits.add(Trinity.create(offset, 0, length)); finalDocument.insertString(offset, StringUtil.repeatSymbol(' ', length)); } else { int length = gen.nextInt(finalDocument.getTextLength() - offset); edits.add(Trinity.create(offset, length, 0)); finalDocument.deleteString(offset, offset + length); } } List<Pair<RangeMarker, TextRange>> candidates = new ArrayList<Pair<RangeMarker, TextRange>>(adds); while (!candidates.isEmpty()) { int size = candidates.size(); int x = gen.nextInt(size); Pair<RangeMarker, TextRange> c = candidates.remove(x); RangeMarkerEx r = (RangeMarkerEx) c.first; assertEquals(size - 1, candidates.size()); dels.add(c); r.dispose(); } } catch (AssertionError e) { String s = "adds: "; for (Pair<RangeMarker, TextRange> c : adds) { TextRange t = c.second; s += t.getStartOffset() + "," + t.getEndOffset() + ", "; } s += "\nedits: "; for (Trinity<Integer, Integer, Integer> edit : edits) { s += edit.first + "," + edit.second + "," + edit.third + ", "; } s += "\ndels: "; for (Pair<RangeMarker, TextRange> c : dels) { int index = adds.indexOf(c); assertSame(c, adds.get(index)); s += index + ", "; } System.err.println(s); throw e; } } }.execute(); } }