@Override
 public void documentChanged(DocumentEvent e) {
   if (!myTaskFile.isTrackChanges()) {
     return;
   }
   if (myAnswerPlaceholders.isEmpty()) return;
   if (e instanceof DocumentEventImpl) {
     DocumentEventImpl event = (DocumentEventImpl) e;
     Document document = e.getDocument();
     int offset = e.getOffset();
     int change = event.getNewLength() - event.getOldLength();
     for (AnswerPlaceholderWrapper answerPlaceholderWrapper : myAnswerPlaceholders) {
       int twStart = answerPlaceholderWrapper.getTwStart();
       if (twStart > offset) {
         twStart += change;
       }
       int twEnd = answerPlaceholderWrapper.getTwEnd();
       if (twEnd >= offset) {
         twEnd += change;
       }
       AnswerPlaceholder answerPlaceholder = answerPlaceholderWrapper.getAnswerPlaceholder();
       int line = document.getLineNumber(twStart);
       int start = twStart - document.getLineStartOffset(line);
       int length = twEnd - twStart;
       answerPlaceholder.setLine(line);
       answerPlaceholder.setStart(start);
       if (usePossibleAnswerLength) {
         answerPlaceholder.setPossibleAnswer(
             document.getText(TextRange.create(twStart, twStart + length)));
       } else if (myTrackLength) {
         answerPlaceholder.setLength(length);
       }
     }
   }
 }
  @Override
  public void beforeDocumentChange(DocumentEvent event) {
    final Document document = event.getDocument();

    final FileViewProvider viewProvider = getCachedViewProvider(document);
    if (viewProvider == null) return;
    if (!isRelevant(viewProvider)) return;

    VirtualFile virtualFile = viewProvider.getVirtualFile();
    if (virtualFile.getFileType().isBinary()) return;

    final List<PsiFile> files = viewProvider.getAllFiles();
    PsiFile psiCause = null;
    for (PsiFile file : files) {
      mySmartPointerManager.fastenBelts(file, event.getOffset(), null);

      if (TextBlock.get(file).isLocked()) {
        psiCause = file;
      }
    }

    if (psiCause == null) {
      beforeDocumentChangeOnUnlockedDocument(viewProvider);
    }

    ((SingleRootFileViewProvider) viewProvider).beforeDocumentChanged(psiCause);
  }
    @Override
    public void documentChanged(final DocumentEvent e) {
      myApplication.assertIsDispatchThread();

      synchronized (myLock) {
        if (myReleased) return;
        if (myBulkUpdate || mySuppressUpdate || myAnathemaThrown || !myInitialized) return;
        assert myDocument == e.getDocument();

        int afterChangedLines;
        if (e.getNewLength() == 0) {
          afterChangedLines = 1;
        } else {
          int line1 = myLine1;
          int line2 = myDocument.getLineNumber(e.getOffset() + e.getNewLength());
          afterChangedLines = line2 - line1 + 1;
        }

        int linesShift = afterChangedLines - myBeforeChangedLines;

        int line1 = myLine1;
        int line2 = line1 + myBeforeChangedLines;

        int[] fixed = fixRanges(e, line1, line2);
        line1 = fixed[0];
        line2 = fixed[1];

        doUpdateRanges(line1, line2, linesShift, myBeforeTotalLines);
      }
    }
 @Override
 public void documentChanged(DocumentEvent e) {
   if (!myTaskFile.isTrackChanges()) {
     return;
   }
   if (e instanceof DocumentEventImpl) {
     final DocumentEventImpl event = (DocumentEventImpl) e;
     final Document document = e.getDocument();
     int offset = e.getOffset();
     int change = event.getNewLength() - event.getOldLength();
     for (TaskWindowWrapper taskWindowWrapper : myTaskWindows) {
       int twStart = taskWindowWrapper.getTwStart();
       if (twStart > offset) {
         twStart += change;
       }
       int twEnd = taskWindowWrapper.getTwEnd();
       if (twEnd >= offset) {
         twEnd += change;
       }
       final AnswerPlaceholder answerPlaceholder = taskWindowWrapper.getAnswerPlaceholder();
       int line = document.getLineNumber(twStart);
       int start = twStart - document.getLineStartOffset(line);
       int length = twEnd - twStart;
       answerPlaceholder.setLine(line);
       answerPlaceholder.setStart(start);
       answerPlaceholder.setLength(length);
     }
   }
 }
 @Override
 public void documentChanged(DocumentEvent e) {
   UndoManager undoManager = UndoManager.getInstance(myProject);
   boolean undoOrRedo = undoManager.isUndoInProgress() || undoManager.isRedoInProgress();
   if (undoOrRedo) {
     // allow undo/redo up until 'creation stamp' back in time
     // and check it after action is completed
     if (e.getDocument() == myOrigDocument) {
       //noinspection SSBasedInspection
       SwingUtilities.invokeLater(
           () -> {
             if (myOrigCreationStamp > myOrigDocument.getModificationStamp()) {
               closeEditor();
             }
           });
     }
   } else if (e.getDocument() == myNewDocument) {
     commitToOriginal(e);
     if (!isValid()) {
       ApplicationManager.getApplication()
           .invokeLater(() -> closeEditor(), myProject.getDisposed());
     }
   } else if (e.getDocument() == myOrigDocument) {
     if (myCommittingToOriginal || myAltFullRange != null && myAltFullRange.isValid()) return;
     ApplicationManager.getApplication().invokeLater(() -> closeEditor(), myProject.getDisposed());
   }
 }
Пример #6
0
 @Override
 public final void documentChanged(@NotNull DocumentEvent e) {
   int oldStart = intervalStart();
   int oldEnd = intervalEnd();
   int docLength = myDocument.getTextLength();
   if (!isValid()) {
     LOG.error(
         "Invalid range marker "
             + (isGreedyToLeft() ? "[" : "(")
             + oldStart
             + ", "
             + oldEnd
             + (isGreedyToRight() ? "]" : ")")
             + ". Event = "
             + e
             + ". Doc length="
             + docLength
             + "; "
             + getClass());
     return;
   }
   if (intervalStart() > intervalEnd()
       || intervalStart() < 0
       || intervalEnd() > docLength - e.getNewLength() + e.getOldLength()) {
     LOG.error(
         "RangeMarker"
             + (isGreedyToLeft() ? "[" : "(")
             + oldStart
             + ", "
             + oldEnd
             + (isGreedyToRight() ? "]" : ")")
             + " is invalid before update. Event = "
             + e
             + ". Doc length="
             + docLength
             + "; "
             + getClass());
     invalidate(e);
     return;
   }
   changedUpdateImpl(e);
   if (isValid()
       && (intervalStart() > intervalEnd() || intervalStart() < 0 || intervalEnd() > docLength)) {
     LOG.error(
         "Update failed. Event = "
             + e
             + ". "
             + "old doc length="
             + docLength
             + "; real doc length = "
             + myDocument.getTextLength()
             + "; "
             + getClass()
             + "."
             + " After update: '"
             + this
             + "'");
     invalidate(e);
   }
 }
  public void testDocSynchronizerPrefersLineBoundaryChanges() throws Exception {
    String text =
        "import java.awt.List;\n"
            + "[import java.util.ArrayList;\n]"
            + "import java.util.HashMap;\n"
            + "import java.util.Map;";
    RangeMarker marker = createMarker(text);
    synchronizer.startTransaction(getProject(), document, psiFile);

    String newText = StringUtil.replaceSubstring(document.getText(), TextRange.create(marker), "");
    synchronizer.replaceString(document, 0, document.getTextLength(), newText);

    final List<DocumentEvent> events = new ArrayList<DocumentEvent>();
    document.addDocumentListener(
        new DocumentAdapter() {
          @Override
          public void documentChanged(DocumentEvent e) {
            events.add(e);
          }
        });
    synchronizer.commitTransaction(document);

    assertEquals(newText, document.getText());
    DocumentEvent event = assertOneElement(events);
    assertEquals(
        "DocumentEventImpl[myOffset=22, myOldLength=28, myNewLength=0, myOldString='import java.util.ArrayList;\n', myNewString=''].",
        event.toString());
  }
Пример #8
0
 protected void onCopyChanged(DocumentEvent event, Document original) {
   final int originalOffset = event.getOffset() + myRangeMarker.getStartOffset();
   LOG.assertTrue(originalOffset >= 0);
   if (!original.isWritable()) return;
   final String newText = subText(event.getDocument(), event.getOffset(), event.getNewLength());
   final int originalEnd = originalOffset + event.getOldLength();
   replaceString(original, originalOffset, originalEnd, newText);
 }
Пример #9
0
 private boolean needToShiftWhiteSpaces(final DocumentEvent e) {
   if (!CharArrayUtil.containsOnlyWhiteSpaces(e.getNewFragment())
       || CharArrayUtil.containLineBreaks(e.getNewFragment())) return e.getOldLength() > 0;
   if (e.getOffset() == 0) return false;
   final char charBefore = myEditor.getDocument().getCharsSequence().charAt(e.getOffset() - 1);
   // final char charAfter = myEditor.getDocument().getCharsSequence().charAt(e.getOffset() +
   // e.getNewLength());
   return Character.isWhitespace(charBefore) /* || !Character.isWhitespace(charAfter)*/;
 }
Пример #10
0
  public void documentChanged(DocumentEvent e) {
    finishUpdate();

    DocumentEventImpl event = (DocumentEventImpl) e;
    final Document document = myEditor.getDocument();
    boolean performSoftWrapAdjustment =
        e.getNewLength() > 0 // We want to put caret just after the last added symbol
            // There is a possible case that the user removes text just before the soft wrap. We
            // want to keep caret
            // on a visual line with soft wrap start then.
            || myEditor.getSoftWrapModel().getSoftWrap(e.getOffset()) != null;

    if (event.isWholeTextReplaced()) {
      int newLength = document.getTextLength();
      if (myOffset == newLength - e.getNewLength() + e.getOldLength() || newLength == 0) {
        moveToOffset(newLength, performSoftWrapAdjustment);
      } else {
        final int line;
        try {
          line = event.translateLineViaDiff(myLogicalCaret.line);
          moveToLogicalPosition(
              new LogicalPosition(line, myLogicalCaret.column), performSoftWrapAdjustment);
        } catch (FilesTooBigForDiffException e1) {
          LOG.info(e1);
          moveToOffset(0);
        }
      }
    } else {
      if (document instanceof DocumentEx && ((DocumentEx) document).isInBulkUpdate()) return;
      int startOffset = e.getOffset();
      int oldEndOffset = startOffset + e.getOldLength();

      int newOffset = myOffset;

      if (myOffset > oldEndOffset || myOffset == oldEndOffset && needToShiftWhiteSpaces(e)) {
        newOffset += e.getNewLength() - e.getOldLength();
      } else if (myOffset >= startOffset && myOffset <= oldEndOffset) {
        newOffset = Math.min(newOffset, startOffset + e.getNewLength());
      }

      newOffset = Math.min(newOffset, document.getTextLength());

      // if (newOffset != myOffset) {
      moveToOffset(newOffset, performSoftWrapAdjustment);
      // }
      // else {
      //  moveToVisualPosition(oldPosition);
      // }
    }

    myVisualLineStart =
        myEditor.logicalPositionToOffset(
            myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line, 0)));
    myVisualLineEnd =
        myEditor.logicalPositionToOffset(
            myEditor.visualToLogicalPosition(new VisualPosition(myVisibleCaret.line + 1, 0)));
  }
  @Override
  public void documentChanged(DocumentEvent event) {
    final Document document = event.getDocument();
    final FileViewProvider viewProvider = getCachedViewProvider(document);
    if (viewProvider == null) return;
    if (!isRelevant(viewProvider)) return;

    ApplicationManager.getApplication().assertWriteAccessAllowed();
    final List<PsiFile> files = viewProvider.getAllFiles();
    boolean commitNecessary = true;
    for (PsiFile file : files) {
      mySmartPointerManager.unfastenBelts(file, event.getOffset());

      final TextBlock textBlock = TextBlock.get(file);
      if (textBlock.isLocked()) {
        commitNecessary = false;
        continue;
      }

      textBlock.documentChanged(event);
      assert file instanceof PsiFileImpl
              || "mock.file".equals(file.getName())
                  && ApplicationManager.getApplication().isUnitTestMode()
          : event + "; file=" + file + "; allFiles=" + files + "; viewProvider=" + viewProvider;
    }

    boolean forceCommit =
        ApplicationManager.getApplication().hasWriteAction(ExternalChangeAction.class)
            && (SystemProperties.getBooleanProperty("idea.force.commit.on.external.change", false)
                || ApplicationManager.getApplication().isHeadlessEnvironment());

    // Consider that it's worth to perform complete re-parse instead of merge if the whole document
    // text is replaced and
    // current document lines number is roughly above 5000. This makes sense in situations when
    // external change is performed
    // for the huge file (that causes the whole document to be reloaded and 'merge' way takes a
    // while to complete).
    if (event.isWholeTextReplaced() && document.getTextLength() > 100000) {
      document.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE);
    }

    if (commitNecessary) {
      myUncommittedDocuments.add(document);
      if (forceCommit) {
        commitDocument(document);
      } else if (!((DocumentEx) document).isInBulkUpdate()) {
        myDocumentCommitProcessor.commitAsynchronously(myProject, document, event);
      }
    }
  }
Пример #12
0
 public void documentChanged(DocumentEvent event) {
   if (((DocumentEx) event.getDocument()).isInBulkUpdate()) {
     myFoldTree.clear();
   } else {
     updateCachedOffsets();
   }
 }
Пример #13
0
  @Nullable
  static ProperTextRange applyChange(
      @NotNull DocumentEvent e,
      int intervalStart,
      int intervalEnd,
      boolean isGreedyToLeft,
      boolean isGreedyToRight) {
    if (intervalStart == intervalEnd) {
      return processIfOnePoint(e, intervalStart, intervalEnd, isGreedyToRight);
    }

    final int offset = e.getOffset();
    final int oldLength = e.getOldLength();
    final int newLength = e.getNewLength();

    // changes after the end.
    if (intervalEnd < offset || !isGreedyToRight && intervalEnd == offset) {
      return new ProperTextRange(intervalStart, intervalEnd);
    }

    // changes before start
    if (intervalStart > offset + oldLength
        || !isGreedyToLeft && intervalStart == offset + oldLength) {
      return new ProperTextRange(
          intervalStart + newLength - oldLength, intervalEnd + newLength - oldLength);
    }

    // Changes inside marker's area. Expand/collapse.
    if (intervalStart <= offset && intervalEnd >= offset + oldLength) {
      return new ProperTextRange(intervalStart, intervalEnd + newLength - oldLength);
    }

    // At this point we either have (myStart xor myEnd inside changed area) or whole area changed.

    // Replacing prefix or suffix...
    if (intervalStart >= offset
        && intervalStart <= offset + oldLength
        && intervalEnd > offset + oldLength) {
      return new ProperTextRange(offset + newLength, intervalEnd + newLength - oldLength);
    }

    if (intervalEnd >= offset && intervalEnd <= offset + oldLength && intervalStart < offset) {
      return new ProperTextRange(intervalStart, offset);
    }

    return null;
  }
  private void altCommitToOriginal(@NotNull DocumentEvent e) {
    final PsiFile origPsiFile =
        PsiDocumentManager.getInstance(myProject).getPsiFile(myOrigDocument);
    String newText = myNewDocument.getText();
    // prepare guarded blocks
    LinkedHashMap<String, String> replacementMap = new LinkedHashMap<String, String>();
    int count = 0;
    for (RangeMarker o : ContainerUtil.reverse(((DocumentEx) myNewDocument).getGuardedBlocks())) {
      String replacement = o.getUserData(REPLACEMENT_KEY);
      String tempText = "REPLACE" + (count++) + Long.toHexString(StringHash.calc(replacement));
      newText =
          newText.substring(0, o.getStartOffset()) + tempText + newText.substring(o.getEndOffset());
      replacementMap.put(tempText, replacement);
    }
    // run preformat processors
    final int hostStartOffset = myAltFullRange.getStartOffset();
    myEditor.getCaretModel().moveToOffset(hostStartOffset);
    for (CopyPastePreProcessor preProcessor :
        Extensions.getExtensions(CopyPastePreProcessor.EP_NAME)) {
      newText = preProcessor.preprocessOnPaste(myProject, origPsiFile, myEditor, newText, null);
    }
    myOrigDocument.replaceString(hostStartOffset, myAltFullRange.getEndOffset(), newText);
    // replace temp strings for guarded blocks
    for (String tempText : replacementMap.keySet()) {
      int idx =
          CharArrayUtil.indexOf(
              myOrigDocument.getCharsSequence(),
              tempText,
              hostStartOffset,
              myAltFullRange.getEndOffset());
      myOrigDocument.replaceString(idx, idx + tempText.length(), replacementMap.get(tempText));
    }
    // JAVA: fix occasional char literal concatenation
    fixDocumentQuotes(myOrigDocument, hostStartOffset - 1);
    fixDocumentQuotes(myOrigDocument, myAltFullRange.getEndOffset());

    // reformat
    PsiDocumentManager.getInstance(myProject).commitDocument(myOrigDocument);
    Runnable task =
        () -> {
          try {
            CodeStyleManager.getInstance(myProject)
                .reformatRange(origPsiFile, hostStartOffset, myAltFullRange.getEndOffset(), true);
          } catch (IncorrectOperationException e1) {
            // LOG.error(e);
          }
        };
    DocumentUtil.executeInBulk(myOrigDocument, true, task);

    PsiElement newInjected =
        InjectedLanguageManager.getInstance(myProject)
            .findInjectedElementAt(origPsiFile, hostStartOffset);
    DocumentWindow documentWindow =
        newInjected == null ? null : InjectedLanguageUtil.getDocumentWindow(newInjected);
    if (documentWindow != null) {
      myEditor.getCaretModel().moveToOffset(documentWindow.injectedToHost(e.getOffset()));
      myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
    }
  }
 @Override
 public void documentChanged(DocumentEvent event) {
   try {
     if (!((DocumentEx) event.getDocument()).isInBulkUpdate()) {
       updateCachedOffsets();
     }
   } finally {
     myDocumentChangeProcessed = true;
   }
 }
Пример #16
0
 protected void onOriginalChanged(DocumentEvent event, Document copy) {
   if (!myRangeMarker.isValid()) {
     fireContentInvalid();
     return;
   }
   replaceString(
       copy,
       0,
       copy.getTextLength(),
       subText(event.getDocument(), myRangeMarker.getStartOffset(), getLength()));
 }
Пример #17
0
    public void documentChanged(@NotNull DocumentEvent event) {
      if (!VimPlugin.isEnabled()) {
        return;
      }

      Project[] projs = ProjectManager.getInstance().getOpenProjects();
      for (Project proj : projs) {
        Editor[] editors = EditorFactory.getInstance().getEditors(event.getDocument(), proj);
        for (Editor editor : editors) {
          Collection hls = EditorData.getLastHighlights(editor);
          if (hls == null) {
            continue;
          }

          int soff = event.getOffset();
          int eoff = soff + event.getNewLength();

          if (logger.isDebugEnabled()) {
            logger.debug("hls=" + hls);
            logger.debug("event=" + event);
          }
          Iterator iter = hls.iterator();
          while (iter.hasNext()) {
            RangeHighlighter rh = (RangeHighlighter) iter.next();
            if (!rh.isValid() || (eoff >= rh.getStartOffset() && soff <= rh.getEndOffset())) {
              iter.remove();
              editor.getMarkupModel().removeHighlighter(rh);
            }
          }

          int sl = editor.offsetToLogicalPosition(soff).line;
          int el = editor.offsetToLogicalPosition(eoff).line;
          VimPlugin.getSearch().highlightSearchLines(editor, false, sl, el);
          hls = EditorData.getLastHighlights(editor);
          if (logger.isDebugEnabled()) {
            logger.debug("sl=" + sl + ", el=" + el);
            logger.debug("hls=" + hls);
          }
        }
      }
    }
Пример #18
0
  @Nullable
  private static ProperTextRange processIfOnePoint(
      @NotNull DocumentEvent e, int intervalStart, int intervalEnd, boolean greedyRight) {
    int offset = e.getOffset();
    int oldLength = e.getOldLength();
    int oldEnd = offset + oldLength;
    if (offset < intervalStart && intervalStart < oldEnd) {
      return null;
    }

    if (offset == intervalStart && oldLength == 0 && greedyRight) {
      return new ProperTextRange(intervalStart, intervalEnd + e.getNewLength());
    }

    if (intervalStart > oldEnd || intervalStart == oldEnd && oldLength > 0) {
      return new ProperTextRange(
          intervalStart + e.getNewLength() - oldLength, intervalEnd + e.getNewLength() - oldLength);
    }

    return new ProperTextRange(intervalStart, intervalEnd);
  }
 // remembering old end before document change because of problems
 // with fragments containing "\n"
 @Override
 public void beforeDocumentChange(DocumentEvent e) {
   if (!myTaskFile.isTrackChanges()) {
     return;
   }
   myTaskFile.setHighlightErrors(true);
   final Document document = e.getDocument();
   myTaskWindows.clear();
   for (AnswerPlaceholder answerPlaceholder : myTaskFile.getAnswerPlaceholders()) {
     int twStart = answerPlaceholder.getRealStartOffset(document);
     int twEnd = twStart + answerPlaceholder.getLength();
     myTaskWindows.add(new TaskWindowWrapper(answerPlaceholder, twStart, twEnd));
   }
 }
 @Override
 public void documentChanged(final DocumentEvent e) {
   final Document document = e.getDocument();
   Collection<XLineBreakpointImpl> breakpoints = myBreakpoints.getKeysByValue(document);
   if (breakpoints != null && !breakpoints.isEmpty()) {
     myBreakpointsUpdateQueue.queue(
         new Update(document) {
           @Override
           public void run() {
             updateBreakpoints(document);
           }
         });
   }
 }
    @Override
    public void beforeDocumentChange(DocumentEvent e) {
      myApplication.assertIsDispatchThread();

      synchronized (myLock) {
        if (myReleased) return;
        if (myBulkUpdate || mySuppressUpdate || myAnathemaThrown || !myInitialized) return;
        assert myDocument == e.getDocument();

        try {
          myLine1 = myDocument.getLineNumber(e.getOffset());
          if (e.getOldLength() == 0) {
            myBeforeChangedLines = 1;
          } else {
            int line1 = myLine1;
            int line2 = myDocument.getLineNumber(e.getOffset() + e.getOldLength());
            myBeforeChangedLines = line2 - line1 + 1;
          }

          myBeforeTotalLines = getLineCount(myDocument);
        } catch (ProcessCanceledException ignore) {
        }
      }
    }
Пример #22
0
        @Override
        public void beforeDocumentChange(DocumentEvent event) {

          if (project.isDisposed()) {
            return;
          }

          if (!isListening) {
            System.out.println("Ignoring change.");
            return;
          }

          VirtualFile file = FileDocumentManager.getInstance().getFile(event.getDocument());

          // Make sure file exists
          if (file == null) {
            return;
          }

          // Make sure file is in the project
          if (!ProjectFileIndex.SERVICE.getInstance(project).isInSource(file)) {
            return;
          }

          String dummyIdentifier = "IntellijIdeaRulezzz";

          if (!event.getNewFragment().toString().contains(dummyIdentifier)) {
            if (!event.isWholeTextReplaced()) {

              // Get path relative to project root (e.g. src/Sample.java)
              Path basePath = Paths.get(project.getBasePath());
              Path absoluteFilePath = Paths.get(file.getPath());
              String relativeFilePath = basePath.relativize(absoluteFilePath).toString();

              String documentText = event.getDocument().getText();
              String oldFragment = event.getOldFragment().toString();
              String newFragment = event.getNewFragment().toString();
              int offset = event.getOffset();

              IOPatcher patcher = new IOPatcher();
              LinkedList<Patch> patches =
                  patcher.makePatchAsList(documentText, oldFragment, newFragment, offset);

              UserEdit edit = new UserEdit(0, relativeFilePath, patches);

              for (EditorEvent editorEvent : events) {
                editorEvent.sendChange(edit);
              }
            }
          }
        }
  @Override
  public void beforeDocumentChange(@NotNull DocumentEvent event) {
    if (myStopTrackingDocuments) return;

    final Document document = event.getDocument();
    if (!(document instanceof DocumentWindow) && !myLastCommittedTexts.containsKey(document)) {
      myLastCommittedTexts.put(
          document,
          Pair.create(document.getImmutableCharSequence(), document.getModificationStamp()));
    }

    VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
    boolean isRelevant = virtualFile != null && isRelevant(virtualFile);

    final FileViewProvider viewProvider = getCachedViewProvider(document);
    boolean inMyProject = viewProvider != null && viewProvider.getManager() == myPsiManager;
    if (!isRelevant || !inMyProject) {
      return;
    }

    final List<PsiFile> files = viewProvider.getAllFiles();
    PsiFile psiCause = null;
    for (PsiFile file : files) {
      if (file == null) {
        throw new AssertionError(
            "View provider "
                + viewProvider
                + " ("
                + viewProvider.getClass()
                + ") returned null in its files array: "
                + files
                + " for file "
                + viewProvider.getVirtualFile());
      }

      if (mySynchronizer.isInsideAtomicChange(file)) {
        psiCause = file;
      }
    }

    if (psiCause == null) {
      beforeDocumentChangeOnUnlockedDocument(viewProvider);
    }

    ((SingleRootFileViewProvider) viewProvider).beforeDocumentChanged(psiCause);
  }
 // remembering old end before document change because of problems
 // with fragments containing "\n"
 @Override
 public void beforeDocumentChange(DocumentEvent e) {
   if (!myTaskFile.isTrackChanges()) {
     return;
   }
   myTaskFile.setHighlightErrors(true);
   Document document = e.getDocument();
   myAnswerPlaceholders.clear();
   for (AnswerPlaceholder answerPlaceholder : myTaskFile.getAnswerPlaceholders()) {
     int twStart = answerPlaceholder.getRealStartOffset(document);
     int length =
         usePossibleAnswerLength
             ? answerPlaceholder.getPossibleAnswerLength()
             : answerPlaceholder.getLength();
     int twEnd = twStart + length;
     myAnswerPlaceholders.add(new AnswerPlaceholderWrapper(answerPlaceholder, twStart, twEnd));
   }
 }
  @NotNull
  private int[] fixRanges(@NotNull DocumentEvent e, int line1, int line2) {
    CharSequence document = myDocument.getCharsSequence();
    int offset = e.getOffset();

    if (e.getOldLength() == 0 && e.getNewLength() != 0) {
      if (StringUtil.endsWithChar(e.getNewFragment(), '\n') && isNewline(offset - 1, document)) {
        return new int[] {line1, line2 - 1};
      }
      if (StringUtil.startsWithChar(e.getNewFragment(), '\n')
          && isNewline(offset + e.getNewLength(), document)) {
        return new int[] {line1 + 1, line2};
      }
    }
    if (e.getOldLength() != 0 && e.getNewLength() == 0) {
      if (StringUtil.endsWithChar(e.getOldFragment(), '\n') && isNewline(offset - 1, document)) {
        return new int[] {line1, line2 - 1};
      }
      if (StringUtil.startsWithChar(e.getOldFragment(), '\n')
          && isNewline(offset + e.getNewLength(), document)) {
        return new int[] {line1 + 1, line2};
      }
    }

    return new int[] {line1, line2};
  }
Пример #26
0
 @Override
 public void beforeDocumentChange(DocumentEvent event) {
   if (myDocument.isInBulkUpdate()) return;
   myDocumentChangeStartOffset = event.getOffset();
   myDocumentChangeEndOffset = event.getOffset() + event.getNewLength();
 }
 @Override
 public void documentChanged(DocumentEvent event) {
   invalidateRange(event.getOffset(), event.getOffset() + event.getNewLength());
 }
  @Override
  public synchronized void documentChanged(DocumentEvent e) {
    final Document document = e.getDocument();

    if (document instanceof DocumentEx && ((DocumentEx) document).isInBulkUpdate()) {
      mySegments.removeAll();
      return;
    }

    if (mySegments.getSegmentCount() == 0) {
      setText(document.getCharsSequence());
      return;
    }

    CharSequence text = document.getCharsSequence();
    int oldStartOffset = e.getOffset();

    final int segmentIndex;
    try {
      segmentIndex = mySegments.findSegmentIndex(oldStartOffset) - 2;
    } catch (IndexOutOfBoundsException ex) {
      throw new IndexOutOfBoundsException(ex.getMessage() + " Lexer: " + myLexer);
    }
    final int oldStartIndex = Math.max(0, segmentIndex);
    int startIndex = oldStartIndex;

    int data;
    do {
      data = mySegments.getSegmentData(startIndex);
      if (isInitialState(data) || startIndex == 0) break;
      startIndex--;
    } while (true);

    int startOffset = mySegments.getSegmentStart(startIndex);
    int newEndOffset = e.getOffset() + e.getNewLength();

    myLexer.start(text, startOffset, text.length(), myInitialState);

    int lastTokenStart = -1;
    int lastLexerState = -1;

    while (myLexer.getTokenType() != null) {
      if (startIndex >= oldStartIndex) break;

      int tokenStart = myLexer.getTokenStart();
      int lexerState = myLexer.getState();

      if (tokenStart == lastTokenStart && lexerState == lastLexerState) {
        throw new IllegalStateException(
            "Error while updating lexer: " + e + " document text: " + document.getText());
      }

      int tokenEnd = myLexer.getTokenEnd();
      data = packData(myLexer.getTokenType(), lexerState);
      if (mySegments.getSegmentStart(startIndex) != tokenStart
          || mySegments.getSegmentEnd(startIndex) != tokenEnd
          || mySegments.getSegmentData(startIndex) != data) {
        break;
      }
      startIndex++;
      myLexer.advance();
      lastTokenStart = tokenStart;
      lastLexerState = lexerState;
    }

    startOffset = mySegments.getSegmentStart(startIndex);
    int repaintEnd = -1;
    int insertSegmentCount = 0;
    int oldEndIndex = -1;
    SegmentArrayWithData insertSegments = new SegmentArrayWithData();

    while (myLexer.getTokenType() != null) {
      int tokenStart = myLexer.getTokenStart();
      int lexerState = myLexer.getState();

      if (tokenStart == lastTokenStart && lexerState == lastLexerState) {
        throw new IllegalStateException(
            "Error while updating lexer: " + e + " document text: " + document.getText());
      }

      lastTokenStart = tokenStart;
      lastLexerState = lexerState;

      int tokenEnd = myLexer.getTokenEnd();
      data = packData(myLexer.getTokenType(), lexerState);
      if (tokenStart >= newEndOffset && lexerState == myInitialState) {
        int shiftedTokenStart = tokenStart - e.getNewLength() + e.getOldLength();
        int index = mySegments.findSegmentIndex(shiftedTokenStart);
        if (mySegments.getSegmentStart(index) == shiftedTokenStart
            && mySegments.getSegmentData(index) == data) {
          repaintEnd = tokenStart;
          oldEndIndex = index;
          break;
        }
      }
      insertSegments.setElementAt(insertSegmentCount, tokenStart, tokenEnd, data);
      insertSegmentCount++;
      myLexer.advance();
    }

    final int shift = e.getNewLength() - e.getOldLength();
    if (repaintEnd > 0) {
      while (insertSegmentCount > 0 && oldEndIndex > startIndex) {
        if (!segmentsEqual(
            mySegments, oldEndIndex - 1, insertSegments, insertSegmentCount - 1, shift)) {
          break;
        }
        insertSegmentCount--;
        oldEndIndex--;
        repaintEnd = insertSegments.getSegmentStart(insertSegmentCount);
        insertSegments.remove(insertSegmentCount, insertSegmentCount + 1);
      }
    }

    if (repaintEnd == -1) {
      repaintEnd = text.length();
    }

    if (oldEndIndex < 0) {
      oldEndIndex = mySegments.getSegmentCount();
    }
    mySegments.shiftSegments(oldEndIndex, shift);
    mySegments.replace(startIndex, oldEndIndex, insertSegments);

    if (insertSegmentCount == 0
        || oldEndIndex == startIndex + 1
            && insertSegmentCount == 1
            && data == mySegments.getSegmentData(startIndex)) {
      return;
    }

    myEditor.repaint(startOffset, repaintEnd);
  }
  @Override
  public void documentChanged(DocumentEvent event) {
    if (myStopTrackingDocuments) return;

    final Document document = event.getDocument();
    VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
    boolean isRelevant = virtualFile != null && isRelevant(virtualFile);

    final FileViewProvider viewProvider = getCachedViewProvider(document);
    if (viewProvider == null) {
      handleCommitWithoutPsi(document);
      return;
    }
    boolean inMyProject = viewProvider.getManager() == myPsiManager;
    if (!isRelevant || !inMyProject) {
      myLastCommittedTexts.remove(document);
      return;
    }

    ApplicationManager.getApplication().assertWriteAccessAllowed();
    final List<PsiFile> files = viewProvider.getAllFiles();
    boolean commitNecessary = true;
    for (PsiFile file : files) {

      if (mySynchronizer.isInsideAtomicChange(file)) {
        commitNecessary = false;
        continue;
      }

      assert file instanceof PsiFileImpl
              || "mock.file".equals(file.getName())
                  && ApplicationManager.getApplication().isUnitTestMode()
          : event + "; file=" + file + "; allFiles=" + files + "; viewProvider=" + viewProvider;
    }

    boolean forceCommit =
        ApplicationManager.getApplication().hasWriteAction(ExternalChangeAction.class)
            && (SystemProperties.getBooleanProperty("idea.force.commit.on.external.change", false)
                || ApplicationManager.getApplication().isHeadlessEnvironment()
                    && !ApplicationManager.getApplication().isUnitTestMode());

    // Consider that it's worth to perform complete re-parse instead of merge if the whole document
    // text is replaced and
    // current document lines number is roughly above 5000. This makes sense in situations when
    // external change is performed
    // for the huge file (that causes the whole document to be reloaded and 'merge' way takes a
    // while to complete).
    if (event.isWholeTextReplaced() && document.getTextLength() > 100000) {
      document.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE);
    }

    if (commitNecessary) {
      assert !(document instanceof DocumentWindow);
      myUncommittedDocuments.add(document);
      myDocumentCommitProcessor.log(
          "added uncommitted doc",
          null,
          false,
          myProject,
          document,
          ((DocumentEx) document).isInBulkUpdate());
      if (forceCommit) {
        commitDocument(document);
      } else if (!((DocumentEx) document).isInBulkUpdate() && myPerformBackgroundCommit) {
        myDocumentCommitProcessor.commitAsynchronously(myProject, document, event);
      }
    } else {
      myLastCommittedTexts.remove(document);
    }
  }