public void testSuccessiveBulkModeOperations() throws Exception {
    initText("some text");
    DocumentEx document = (DocumentEx) myEditor.getDocument();

    document.setInBulkUpdate(true);
    document.replaceString(4, 5, "-");
    document.setInBulkUpdate(false);

    myEditor.getCaretModel().moveToOffset(9);

    document.setInBulkUpdate(true);
    document.replaceString(4, 5, "+");
    document.setInBulkUpdate(false);

    checkResultByText("some+text<caret>");
  }
  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();
    }
  }
  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 void testSoftWrapModeUpdateDuringBulkModeChange() throws Exception {
   initText("long long line<caret>");
   configureSoftWraps(12);
   DocumentEx document = (DocumentEx) myEditor.getDocument();
   document.setInBulkUpdate(true);
   document.replaceString(4, 5, "-");
   document.setInBulkUpdate(false);
   assertEquals(new VisualPosition(1, 5), myEditor.getCaretModel().getVisualPosition());
 }
  private void doReplaceString(int startOffset, int endOffset, CharSequence s) {
    assert intersectWithEditable(new TextRange(startOffset, startOffset)) != null;
    assert intersectWithEditable(new TextRange(endOffset, endOffset)) != null;

    List<Pair<TextRange, CharSequence>> hostRangesToModify;
    synchronized (myLock) {
      hostRangesToModify = new ArrayList<Pair<TextRange, CharSequence>>(myShreds.size());

      int offset = startOffset;
      int curRangeStart = 0;
      for (int i = 0; i < myShreds.size(); i++) {
        PsiLanguageInjectionHost.Shred shred = myShreds.get(i);
        curRangeStart += shred.getPrefix().length();
        if (offset < curRangeStart) offset = curRangeStart;
        Segment hostRange = shred.getHostRangeMarker();
        if (hostRange == null) continue;
        int hostRangeLength = hostRange.getEndOffset() - hostRange.getStartOffset();
        TextRange range = TextRange.from(curRangeStart, hostRangeLength);
        if (range.contains(offset)
            || range.getEndOffset() == offset /* in case of inserting at the end*/) {
          TextRange rangeToModify =
              new TextRange(offset, Math.min(range.getEndOffset(), endOffset));
          TextRange hostRangeToModify =
              rangeToModify.shiftRight(hostRange.getStartOffset() - curRangeStart);
          CharSequence toReplace =
              i == myShreds.size() - 1
                      || range.getEndOffset() + shred.getSuffix().length() >= endOffset
                  ? s
                  : s.subSequence(0, Math.min(hostRangeToModify.getLength(), s.length()));
          s = toReplace == s ? "" : s.subSequence(toReplace.length(), s.length());
          hostRangesToModify.add(Pair.create(hostRangeToModify, toReplace));
          offset = rangeToModify.getEndOffset();
        }
        curRangeStart += hostRangeLength;
        curRangeStart += shred.getSuffix().length();
        if (curRangeStart > endOffset) break;
      }
    }

    int delta = 0;
    for (Pair<TextRange, CharSequence> pair : hostRangesToModify) {
      TextRange hostRange = pair.getFirst();
      CharSequence replace = pair.getSecond();

      myDelegate.replaceString(
          hostRange.getStartOffset() + delta, hostRange.getEndOffset() + delta, replace);
      delta -= hostRange.getLength() - replace.length();
    }
  }
  private static void doCommitTransaction(
      @NotNull Document document, @NotNull DocumentChangeTransaction documentChangeTransaction) {
    DocumentEx ex = (DocumentEx) document;
    ex.suppressGuardedExceptions();
    try {
      boolean isReadOnly = !document.isWritable();
      ex.setReadOnly(false);

      for (Map.Entry<TextRange, CharSequence> entry :
          documentChangeTransaction.myAffectedFragments.descendingMap().entrySet()) {
        ex.replaceString(
            entry.getKey().getStartOffset(), entry.getKey().getEndOffset(), entry.getValue());
      }

      ex.setReadOnly(isReadOnly);
    } finally {
      ex.unSuppressGuardedExceptions();
    }
  }
 @Override
 public void setText(@NotNull CharSequence text) {
   synchronized (myLock) {
     LOG.assertTrue(text.toString().startsWith(myShreds.get(0).getPrefix()));
     LOG.assertTrue(text.toString().endsWith(myShreds.get(myShreds.size() - 1).getSuffix()));
     if (isOneLine()) {
       text = StringUtil.replace(text.toString(), "\n", "");
     }
     String[] changes = calculateMinEditSequence(text.toString());
     assert changes.length == myShreds.size();
     for (int i = 0; i < changes.length; i++) {
       String change = changes[i];
       if (change != null) {
         Segment hostRange = myShreds.get(i).getHostRangeMarker();
         if (hostRange == null) continue;
         myDelegate.replaceString(hostRange.getStartOffset(), hostRange.getEndOffset(), change);
       }
     }
   }
 }