private Pair<MutableTextRange, StringBuffer> getFragmentByRange(int start, final int length) { final StringBuffer fragmentBuffer = new StringBuffer(); int end = start + length; // restoring buffer and remove all subfragments from the list int documentOffset = 0; int effectiveOffset = 0; Iterator<Pair<MutableTextRange, StringBuffer>> iterator = myAffectedFragments.iterator(); while (iterator.hasNext() && effectiveOffset <= end) { final Pair<MutableTextRange, StringBuffer> pair = iterator.next(); final MutableTextRange range = pair.getFirst(); final StringBuffer buffer = pair.getSecond(); int effectiveFragmentEnd = range.getStartOffset() + buffer.length(); if (range.getStartOffset() <= start && effectiveFragmentEnd >= end) return pair; if (effectiveFragmentEnd >= start) { final int effectiveStart = Math.max(effectiveOffset, start); if (range.getStartOffset() > start) { fragmentBuffer.append( myDocument.getCharsSequence(), effectiveStart - effectiveOffset + documentOffset, Math.min(range.getStartOffset(), end) - effectiveOffset + documentOffset); } if (end >= range.getStartOffset()) { fragmentBuffer.append(buffer); end = end > effectiveFragmentEnd ? end - (buffer.length() - range.getLength()) : range.getEndOffset(); effectiveFragmentEnd = range.getEndOffset(); start = Math.min(start, range.getStartOffset()); iterator.remove(); } } documentOffset += range.getEndOffset() - effectiveOffset; effectiveOffset = effectiveFragmentEnd; } if (effectiveOffset < end) { final int effectiveStart = Math.max(effectiveOffset, start); fragmentBuffer.append( myDocument.getCharsSequence(), effectiveStart - effectiveOffset + documentOffset, end - effectiveOffset + documentOffset); } MutableTextRange newRange = new MutableTextRange(start, end); final Pair<MutableTextRange, StringBuffer> pair = new Pair<MutableTextRange, StringBuffer>(newRange, fragmentBuffer); for (Pair<MutableTextRange, StringBuffer> affectedFragment : myAffectedFragments) { MutableTextRange range = affectedFragment.getFirst(); assert end <= range.getStartOffset() || range.getEndOffset() <= start : "Range :" + range + "; Added: " + newRange; } myAffectedFragments.add(pair); return pair; }
private static void doCommitTransaction( @NotNull Document document, @NotNull DocumentChangeTransaction documentChangeTransaction) { DocumentEx ex = (DocumentEx) document; ex.suppressGuardedExceptions(); try { boolean isReadOnly = !document.isWritable(); ex.setReadOnly(false); final Set<Pair<MutableTextRange, StringBuffer>> affectedFragments = documentChangeTransaction.getAffectedFragments(); for (final Pair<MutableTextRange, StringBuffer> pair : affectedFragments) { final StringBuffer replaceBuffer = pair.getSecond(); final MutableTextRange range = pair.getFirst(); if (replaceBuffer.length() == 0) { ex.deleteString(range.getStartOffset(), range.getEndOffset()); } else if (range.getLength() == 0) { ex.insertString(range.getStartOffset(), replaceBuffer); } else { ex.replaceString(range.getStartOffset(), range.getEndOffset(), replaceBuffer); } } ex.setReadOnly(isReadOnly); // if(documentChangeTransaction.getChangeScope() != null) { // // LOG.assertTrue(document.getText().equals(documentChangeTransaction.getChangeScope().getText()), // "Psi to document synchronization failed (send to IK)"); // } } finally { ex.unSuppressGuardedExceptions(); } }