@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}; }
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 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); } }
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); }
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)*/; }
@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) { } } }
@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; }
@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); }
@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); }