Exemple #1
0
 int getVisualLineWidth(
     VisualLinesIterator visualLinesIterator, @Nullable Runnable quickEvaluationListener) {
   assert !visualLinesIterator.atEnd();
   int visualLine = visualLinesIterator.getVisualLine();
   FoldRegion[] topLevelRegions = myEditor.getFoldingModel().fetchTopLevel();
   if (quickEvaluationListener != null
       && (topLevelRegions == null || topLevelRegions.length == 0)
       && myEditor.getSoftWrapModel().getRegisteredSoftWraps().isEmpty()
       && !myView.getTextLayoutCache().hasCachedLayoutFor(visualLine)) {
     // fast path - speeds up editor opening
     quickEvaluationListener.run();
     return myView
             .getLogicalPositionCache()
             .offsetToLogicalColumn(
                 visualLine,
                 myDocument.getLineEndOffset(visualLine)
                     - myDocument.getLineStartOffset(visualLine))
         * myView.getMaxCharWidth();
   }
   float x = 0;
   int maxOffset = visualLinesIterator.getVisualLineStartOffset();
   for (VisualLineFragmentsIterator.Fragment fragment :
       VisualLineFragmentsIterator.create(myView, visualLinesIterator, quickEvaluationListener)) {
     x = fragment.getEndX();
     maxOffset = Math.max(maxOffset, fragment.getMaxOffset());
   }
   if (myEditor.getSoftWrapModel().getSoftWrap(maxOffset) != null) {
     x +=
         myEditor
             .getSoftWrapModel()
             .getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
   }
   return (int) x;
 }
  @Nullable("null means we were unable to calculate")
  LogicalPosition hostToInjectedInVirtualSpace(@NotNull LogicalPosition hPos) {
    // beware the virtual space
    int hLineStartOffset =
        hPos.line >= myDelegate.getLineCount()
            ? myDelegate.getTextLength()
            : myDelegate.getLineStartOffset(hPos.line);
    int iLineStartOffset = hostToInjected(hLineStartOffset);
    int iLine = getLineNumber(iLineStartOffset);

    synchronized (myLock) {
      for (int i = myShreds.size() - 1; i >= 0; i--) {
        PsiLanguageInjectionHost.Shred shred = myShreds.get(i);
        if (!shred.isValid()) continue;
        Segment hostRangeMarker = shred.getHostRangeMarker();
        if (hostRangeMarker == null) continue;
        int hShredEndOffset = hostRangeMarker.getEndOffset();
        int hShredStartOffset = hostRangeMarker.getStartOffset();

        int hShredStartLine = myDelegate.getLineNumber(hShredStartOffset);
        int hShredEndLine = myDelegate.getLineNumber(hShredEndOffset);

        if (hShredStartLine <= hPos.line && hPos.line <= hShredEndLine) {
          int hColumnOfShredEnd = hShredEndOffset - hLineStartOffset;
          int iColumnOfShredEnd = hostToInjected(hShredEndOffset) - iLineStartOffset;
          int iColumn = iColumnOfShredEnd + hPos.column - hColumnOfShredEnd;
          return new LogicalPosition(iLine, iColumn);
        }
      }
    }

    return null;
  }
  private void doSync(
      @NotNull final PsiTreeChangeEvent event,
      boolean force,
      @NotNull final DocSyncAction syncAction) {
    if (!toProcessPsiEvent()) return;
    final PsiFile psiFile = event.getFile();
    if (!(psiFile instanceof PsiFileEx) || !((PsiFileEx) psiFile).isContentsLoaded()) return;

    final DocumentEx document = getCachedDocument(psiFile, force);
    if (document == null) return;

    performAtomically(
        psiFile,
        new Runnable() {
          @Override
          public void run() {
            syncAction.syncDocument(document, (PsiTreeChangeEventImpl) event);
          }
        });

    final boolean insideTransaction = myTransactionsMap.containsKey(document);
    if (!insideTransaction) {
      document.setModificationStamp(psiFile.getViewProvider().getModificationStamp());
    }
  }
  private RangeMarkerImpl(
      @NotNull DocumentEx document,
      int start,
      int end,
      boolean register,
      boolean greedyToLeft,
      boolean greedyToRight) {
    if (start < 0) {
      throw new IllegalArgumentException("Wrong start: " + start + "; end=" + end);
    }
    if (end > document.getTextLength()) {
      throw new IllegalArgumentException(
          "Wrong end: "
              + end
              + "; document length="
              + document.getTextLength()
              + "; start="
              + start);
    }
    if (start > end) {
      throw new IllegalArgumentException("start > end: start=" + start + "; end=" + end);
    }

    myDocument = document;
    myId = counter.next();
    if (register) {
      registerInTree(start, end, greedyToLeft, greedyToRight, 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 testSwap() {
   RangeMarkerEx marker1 = createMarker("012345678901234567", 5, 6);
   DocumentEx document = (DocumentEx) marker1.getDocument();
   document.createRangeMarker(3, 5);
   document.createRangeMarker(6, 7);
   document.createRangeMarker(4, 4);
   marker1.dispose();
 }
  public void testNested3() {
    RangeMarker marker1 = createMarker("01[23]4567890123");
    DocumentEx document = (DocumentEx) marker1.getDocument();
    RangeMarker marker2 = document.createRangeMarker(9, 11);
    RangeMarker marker3 = document.createRangeMarker(1, 12);
    marker3.dispose();

    document.deleteString(marker1.getEndOffset(), marker2.getStartOffset());
  }
 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());
 }
 public void testUpdatingCaretPositionAfterBulkMode() throws Exception {
   initText("a<caret>bc");
   DocumentEx document = (DocumentEx) myEditor.getDocument();
   document.setInBulkUpdate(true);
   document.insertString(
       0, "\n "); // we're changing number of visual lines, and invalidating text layout for caret
   // line
   document.setInBulkUpdate(false);
   checkResultByText("\n a<caret>bc");
 }
  public void testMoveTextRetargetsMarkers() throws Exception {
    RangeMarkerEx marker1 = createMarker("01234567890", 1, 3);
    DocumentEx document = (DocumentEx) marker1.getDocument();
    RangeMarker marker2 = document.createRangeMarker(2, 4);

    document.moveText(0, 5, 8);
    assertEquals("56701234890", document.getText());

    assertValidMarker(marker1, 4, 6);
    assertValidMarker(marker2, 5, 7);
  }
  @Override
  @Nullable
  public Document getDocument(@NotNull final VirtualFile file) {
    DocumentEx document = (DocumentEx) getCachedDocument(file);
    if (document == null) {
      if (file.isDirectory()
          || isBinaryWithoutDecompiler(file)
          || SingleRootFileViewProvider.isTooLargeForContentLoading(file)) {
        return null;
      }
      final CharSequence text = LoadTextUtil.loadText(file);

      synchronized (lock) {
        document = (DocumentEx) getCachedDocument(file);
        if (document != null) return document; // Double checking

        document = (DocumentEx) createDocument(text);
        document.setModificationStamp(file.getModificationStamp());
        final FileType fileType = file.getFileType();
        document.setReadOnly(!file.isWritable() || fileType.isBinary());
        file.putUserData(DOCUMENT_KEY, new WeakReference<Document>(document));
        document.putUserData(FILE_KEY, file);

        if (!(file instanceof LightVirtualFile
            || file.getFileSystem() instanceof DummyFileSystem)) {
          document.addDocumentListener(
              new DocumentAdapter() {
                @Override
                public void documentChanged(DocumentEvent e) {
                  final Document document = e.getDocument();
                  myUnsavedDocuments.add(document);
                  final Runnable currentCommand =
                      CommandProcessor.getInstance().getCurrentCommand();
                  Project project =
                      currentCommand == null
                          ? null
                          : CommandProcessor.getInstance().getCurrentCommandProject();
                  String lineSeparator = CodeStyleFacade.getInstance(project).getLineSeparator();
                  document.putUserData(LINE_SEPARATOR_KEY, lineSeparator);

                  // avoid documents piling up during batch processing
                  if (areTooManyDocumentsInTheQueue(myUnsavedDocuments)) {
                    saveAllDocumentsLater();
                  }
                }
              });
        }
      }

      myMultiCaster.fileContentLoaded(file, document);
    }

    return document;
  }
  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 testNoExceptionDuringBulkModeDocumentUpdate() throws Exception {
   initText("something");
   DocumentEx document = (DocumentEx) myEditor.getDocument();
   document.setInBulkUpdate(true);
   try {
     document.setText("something\telse");
   } finally {
     document.setInBulkUpdate(false);
   }
   checkResultByText("something\telse");
 }
  public void testLL() {
    RangeMarker marker1 = createMarker("012345678901234567", 5, 6);
    DocumentEx document = (DocumentEx) marker1.getDocument();
    document.createRangeMarker(4, 5);
    document.createRangeMarker(6, 7);
    document.createRangeMarker(0, 4);
    document.deleteString(1, 2);

    document.createRangeMarker(0, 7);
    document.createRangeMarker(0, 7);
  }
  public void testMoveTextToTheBeginningRetargetsMarkers() throws Exception {
    RangeMarkerEx marker1 = createMarker("01234567890", 5, 5);
    DocumentEx document = (DocumentEx) marker1.getDocument();
    RangeMarker marker2 = document.createRangeMarker(5, 7);

    document.moveText(4, 7, 1);
    assertEquals("04561237890", document.getText());

    assertValidMarker(marker1, 2, 2);
    assertValidMarker(marker2, 2, 4);
  }
  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;
      }
    }
  }
  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();
    }
  }
Exemple #18
0
 void invalidateRange(int startOffset, int endOffset) {
   if (myDocument.isInBulkUpdate()) return;
   if (myDocument.isInEventsHandling()) {
     myDocumentChangeStartOffset = Math.min(myDocumentChangeStartOffset, startOffset);
     myDocumentChangeEndOffset = Math.max(myDocumentChangeEndOffset, endOffset);
   } else if (myFoldingChangeEndOffset != Integer.MIN_VALUE) {
     // during batch folding processing we delay invalidation requests, as we cannot perform
     // coordinate conversions immediately
     myFoldingChangeStartOffset = Math.min(myFoldingChangeStartOffset, startOffset);
     myFoldingChangeEndOffset = Math.max(myFoldingChangeEndOffset, endOffset);
   } else {
     doInvalidateRange(startOffset, endOffset);
   }
 }
 /**
  * @return position <code>x</code> for which <code>
  *     myDocument.getText().substring(x, startOffset)</code> contains <code>blankLinesNumber
  *     </code> line feeds and <code>myDocument.getText.charAt(x-1) == '\n'</code>
  */
 private int getBlankLineOffset(int blankLinesNumber, int startOffset) {
   int startLine = myDocument.getLineNumber(startOffset);
   if (startLine <= 0) {
     return 0;
   }
   CharSequence text = myDocument.getCharsSequence();
   for (int i = myDocument.getLineStartOffset(startLine - 1) - 1;
       i >= 0;
       i = CharArrayUtil.lastIndexOf(text, "\n", i - 1)) {
     if (--blankLinesNumber <= 0) {
       return i + 1;
     }
   }
   return 0;
 }
 void lineLayoutCreated(int logicalLine) {
   int startVisualLine =
       myView.offsetToVisualLine(myDocument.getLineStartOffset(logicalLine), false);
   int endVisualLine = myView.offsetToVisualLine(myDocument.getLineEndOffset(logicalLine), false);
   boolean sizeInvalidated = false;
   for (int i = startVisualLine; i <= endVisualLine; i++) {
     if (myLineWidths.get(i) < 0) {
       myLineWidths.set(i, UNKNOWN_WIDTH);
       sizeInvalidated = true;
     }
   }
   if (sizeInvalidated) {
     myWidthInPixels = -1;
     myEditor.getContentComponent().revalidate();
   }
 }
  @Override
  public int getLineStartOffset(int line) {
    LOG.assertTrue(line >= 0, line);
    if (line == 0) return 0;
    String hostText = myDelegate.getText();

    int[] pos = new int[2]; // pos[0] = curLine; pos[1] == offset;
    synchronized (myLock) {
      for (PsiLanguageInjectionHost.Shred shred : myShreds) {
        Segment hostRange = shred.getHostRangeMarker();
        if (hostRange == null) continue;

        int found = countNewLinesIn(shred.getPrefix(), pos, line);
        if (found != -1) return found;

        CharSequence text =
            hostText.subSequence(hostRange.getStartOffset(), hostRange.getEndOffset());
        found = countNewLinesIn(text, pos, line);
        if (found != -1) return found;

        found = countNewLinesIn(shred.getSuffix(), pos, line);
        if (found != -1) return found;
      }
    }

    return pos[1];
  }
Exemple #22
0
 void textLayoutPerformed(int startOffset, int endOffset) {
   if (myDocument.isInBulkUpdate()) return;
   if (myEditor.getFoldingModel().isInBatchFoldingOperation()) {
     myDeferredRanges.add(new TextRange(startOffset, endOffset));
   } else {
     onTextLayoutPerformed(startOffset, endOffset);
   }
 }
Exemple #23
0
 private int getPreferredWidth() {
   if (myWidthInPixels < 0) {
     assert !myDocument.isInBulkUpdate();
     myWidthInPixels = calculatePreferredWidth();
   }
   validateMaxLineWithExtension();
   return Math.max(myWidthInPixels, myMaxLineWithExtensionWidth);
 }
 protected boolean unregisterInTree() {
   if (!isValid()) return false;
   IntervalTreeImpl tree = myNode.getTree();
   tree.checkMax(true);
   boolean b = myDocument.removeRangeMarker(this);
   tree.checkMax(true);
   return b;
 }
Exemple #25
0
 @Override
 public void onFoldRegionStateChange(@NotNull FoldRegion region) {
   if (myDocument.isInBulkUpdate()) return;
   if (region.isValid()) {
     myFoldingChangeStartOffset = Math.min(myFoldingChangeStartOffset, region.getStartOffset());
     myFoldingChangeEndOffset = Math.max(myFoldingChangeEndOffset, region.getEndOffset());
   }
 }
Exemple #26
0
 private void onSoftWrapRecalculationEnd(IncrementalCacheUpdateEvent event) {
   if (myDocument.isInBulkUpdate()) return;
   boolean invalidate = true;
   if (myEditor.getFoldingModel().isInBatchFoldingOperation()) {
     myFoldingChangeStartOffset = Math.min(myFoldingChangeStartOffset, event.getStartOffset());
     myFoldingChangeEndOffset = Math.max(myFoldingChangeEndOffset, event.getActualEndOffset());
     invalidate = false;
   }
   if (myDocument.isInEventsHandling()) {
     myDocumentChangeStartOffset = Math.min(myDocumentChangeStartOffset, event.getStartOffset());
     myDocumentChangeEndOffset = Math.max(myDocumentChangeEndOffset, event.getActualEndOffset());
     invalidate = false;
   }
   if (invalidate) {
     doInvalidateRange(event.getStartOffset(), event.getActualEndOffset());
   }
 }
 EditorSizeManager(EditorView view) {
   myView = view;
   myEditor = view.getEditor();
   myDocument = myEditor.getDocument();
   myDocument.addDocumentListener(this, this);
   myEditor.getFoldingModel().addListener(this, this);
   myEditor.getSoftWrapModel().getApplianceManager().addListener(mySoftWrapChangeListener);
 }
Exemple #28
0
 private void assertValidState() {
   if (myDocument.isInBulkUpdate() || myDirty) return;
   if (myLineWidths.size() != myEditor.getVisibleLineCount()) {
     LOG.error("Inconsistent state", new Attachment("editor.txt", myEditor.dumpState()));
     reset();
   }
   assert myLineWidths.size() == myEditor.getVisibleLineCount();
 }
 @Override
 @NotNull
 public RangeMarker createRangeMarker(final int startOffset, final int endOffset) {
   ProperTextRange hostRange = injectedToHost(new ProperTextRange(startOffset, endOffset));
   RangeMarker hostMarker = myDelegate.createRangeMarker(hostRange);
   int startShift = Math.max(0, hostToInjected(hostRange.getStartOffset()) - startOffset);
   int endShift = Math.max(0, endOffset - hostToInjected(hostRange.getEndOffset()) - startShift);
   return new RangeMarkerWindow(this, (RangeMarkerEx) hostMarker, startShift, endShift);
 }
  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));
    }
  }