reduce visibility to prevent subclassing of RangeMarkerImpl which can break tree invariants

This commit is contained in:
Alexey Kudravtsev
2014-12-19 14:45:22 +03:00
parent 16d2f8e458
commit c57b73d20c
8 changed files with 226 additions and 170 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,11 +23,7 @@ import org.jetbrains.annotations.NotNull;
* @author Denis Zhdanov
* @since 12/27/10 4:26 PM
*/
public class PersistentRangeMarkerUtil {
private PersistentRangeMarkerUtil() {
}
class PersistentRangeMarkerUtil {
/**
* Answers if document region identified by the given range marker should be translated via diff algorithm on document change
* identified by the given event.
@@ -37,7 +33,7 @@ public class PersistentRangeMarkerUtil {
* @return <code>true</code> if target document range referenced by the given range marker should be translated via
* diff algorithm; <code>false</code> otherwise
*/
public static boolean shouldTranslateViaDiff(@NotNull DocumentEventImpl e, @NotNull RangeMarker rangeMarker) {
static boolean shouldTranslateViaDiff(@NotNull DocumentEventImpl e, @NotNull RangeMarker rangeMarker) {
if (e.isWholeTextReplaced()) {
// Perform translation if the whole text is replaced.
return true;
@@ -21,7 +21,6 @@ import com.intellij.openapi.editor.FoldRegion;
import com.intellij.openapi.editor.FoldingGroup;
import com.intellij.openapi.editor.ex.FoldingListener;
import com.intellij.openapi.editor.ex.FoldingModelEx;
import com.intellij.openapi.editor.impl.FoldRegionImpl;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
@@ -35,12 +34,12 @@ import java.util.List;
/**
* @author cdr
*/
public class FoldingModelWindow implements FoldingModelEx{
class FoldingModelWindow implements FoldingModelEx{
private final FoldingModelEx myDelegate;
private final DocumentWindow myDocumentWindow;
private final EditorWindow myEditorWindow;
public FoldingModelWindow(@NotNull FoldingModelEx delegate, @NotNull DocumentWindow documentWindow, @NotNull EditorWindow editorWindow) {
FoldingModelWindow(@NotNull FoldingModelEx delegate, @NotNull DocumentWindow documentWindow, @NotNull EditorWindow editorWindow) {
myDelegate = delegate;
myDocumentWindow = documentWindow;
myEditorWindow = editorWindow;
@@ -82,12 +81,12 @@ public class FoldingModelWindow implements FoldingModelEx{
@Override
public boolean addFoldRegion(@NotNull final FoldRegion region) {
return myDelegate.addFoldRegion(((FoldingRegionWindow)region).getDelegate());
return myDelegate.addFoldRegion((FoldRegion)((FoldingRegionWindow)region).getDelegate());
}
@Override
public void removeFoldRegion(@NotNull FoldRegion region) {
myDelegate.removeFoldRegion(((FoldingRegionWindow)region).getDelegate());
myDelegate.removeFoldRegion((FoldRegion)((FoldingRegionWindow)region).getDelegate());
}
@Override
@@ -172,7 +171,7 @@ public class FoldingModelWindow implements FoldingModelEx{
FoldRegion hostRegion = myDelegate.createFoldRegion(hostRange.getStartOffset(), hostRange.getEndOffset(), placeholder, group, neverExpands);
int startShift = Math.max(0, myDocumentWindow.hostToInjected(hostRange.getStartOffset()) - startOffset);
int endShift = Math.max(0, endOffset - myDocumentWindow.hostToInjected(hostRange.getEndOffset()) - startShift);
FoldingRegionWindow window = new FoldingRegionWindow(myDocumentWindow, myEditorWindow, (FoldRegionImpl)hostRegion, startShift, endShift);
FoldingRegionWindow window = new FoldingRegionWindow(myDocumentWindow, myEditorWindow, hostRegion, startShift, endShift);
hostRegion.putUserData(FOLD_REGION_WINDOW, window);
return window;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,24 +18,24 @@ package com.intellij.injected.editor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.FoldRegion;
import com.intellij.openapi.editor.FoldingGroup;
import com.intellij.openapi.editor.impl.FoldRegionImpl;
import com.intellij.openapi.editor.ex.RangeMarkerEx;
import org.jetbrains.annotations.NotNull;
/**
* User: cdr
*/
public class FoldingRegionWindow extends RangeMarkerWindow implements FoldRegion {
class FoldingRegionWindow extends RangeMarkerWindow implements FoldRegion {
private final EditorWindow myEditorWindow;
private final FoldRegionImpl myHostRegion;
private final FoldRegion myHostRegion;
public FoldingRegionWindow(@NotNull DocumentWindow documentWindow,
@NotNull EditorWindow editorWindow,
@NotNull FoldRegionImpl hostRegion,
int startShift,
int endShift)
FoldingRegionWindow(@NotNull DocumentWindow documentWindow,
@NotNull EditorWindow editorWindow,
@NotNull FoldRegion hostRegion,
int startShift,
int endShift)
{
super(documentWindow, hostRegion, startShift, endShift);
super(documentWindow, (RangeMarkerEx)hostRegion, startShift, endShift);
myEditorWindow = editorWindow;
myHostRegion = hostRegion;
}
@@ -72,7 +72,7 @@ public class FoldingRegionWindow extends RangeMarkerWindow implements FoldRegion
}
@Override
public FoldRegionImpl getDelegate() {
return myHostRegion;
public RangeMarkerEx getDelegate() {
return (RangeMarkerEx)myHostRegion;
}
}
@@ -29,12 +29,11 @@ import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiLanguageInjectionHost;
import org.jetbrains.annotations.NotNull;
public class RangeMarkerWindow implements RangeMarkerEx {
class RangeMarkerWindow implements RangeMarkerEx {
private final DocumentWindow myDocumentWindow;
private final RangeMarkerEx myHostMarker;
private final int myStartShift;
private final int myEndShift;
private final RangeMarkerEx myHostMarker;
private final int myStartShift;
private final int myEndShift;
/**
* Creates new <code>RangeMarkerWindow</code> object with the given data.
@@ -51,7 +50,7 @@ public class RangeMarkerWindow implements RangeMarkerEx {
* @param endShift similar to the 'startShift' argument but specifies difference between the target injected host end offset
* and end offset of the given host range marker at the injected text
*/
public RangeMarkerWindow(@NotNull DocumentWindow documentWindow, RangeMarkerEx hostMarker, int startShift, int endShift) {
RangeMarkerWindow(@NotNull DocumentWindow documentWindow, RangeMarkerEx hostMarker, int startShift, int endShift) {
myDocumentWindow = documentWindow;
myHostMarker = hostMarker;
myStartShift = startShift;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,30 +17,40 @@ package com.intellij.openapi.diff.impl.incrementalMerge;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.impl.RangeMarkerImpl;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
class DiffRangeMarker extends RangeMarkerImpl {
class DiffRangeMarker implements RangeMarker {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.incrementalMerge.DiffRangeMarker");
private final RangeMarker myRangeMarker;
private RangeInvalidListener myListener;
DiffRangeMarker(@NotNull DocumentEx document, @NotNull TextRange range, RangeInvalidListener listener) {
super(document, range.getStartOffset(), range.getEndOffset(),true);
DiffRangeMarker(@NotNull Document document, @NotNull TextRange range, RangeInvalidListener listener) {
myRangeMarker = document.createRangeMarker(range.getStartOffset(), range.getEndOffset());
myListener = listener;
if (myListener != null) InvalidRangeDispatcher.addClient(document);
}
@Override
protected void changedUpdateImpl(DocumentEvent e) {
super.changedUpdateImpl(e);
if (!isValid() && myListener != null) InvalidRangeDispatcher.notify(e.getDocument(), myListener);
if (listener != null) {
final InvalidRangeDispatcher notifier = InvalidRangeDispatcher.addClient(document);
document.addDocumentListener(new DocumentAdapter() {
@Override
public void beforeDocumentChange(DocumentEvent e) {
if (myListener != null) {
notifier.notify(new RangeInvalidListener() {
@Override
public void onRangeInvalidated() {
if (!isValid() && myListener != null) myListener.onRangeInvalidated();
}
});
}
}
});
}
}
public void removeListener(RangeInvalidListener listener) {
@@ -49,7 +59,7 @@ class DiffRangeMarker extends RangeMarkerImpl {
InvalidRangeDispatcher.removeClient(getDocument());
}
public interface RangeInvalidListener {
interface RangeInvalidListener {
void onRangeInvalidated();
}
@@ -58,6 +68,7 @@ class DiffRangeMarker extends RangeMarkerImpl {
private final ArrayList<RangeInvalidListener> myDeferedNotifications = new ArrayList<RangeInvalidListener>();
private int myClientCount = 0;
@Override
public void documentChanged(DocumentEvent e) {
if (myDeferedNotifications.isEmpty()) return;
RangeInvalidListener[] notifications = myDeferedNotifications.toArray(new RangeInvalidListener[myDeferedNotifications.size()]);
@@ -67,12 +78,11 @@ class DiffRangeMarker extends RangeMarkerImpl {
}
}
public static void notify(Document document, RangeInvalidListener listener) {
InvalidRangeDispatcher notifier = document.getUserData(KEY);
notifier.myDeferedNotifications.add(listener);
public void notify(@NotNull RangeInvalidListener listener) {
myDeferedNotifications.add(listener);
}
public static void addClient(@NotNull Document document) {
private static InvalidRangeDispatcher addClient(@NotNull Document document) {
InvalidRangeDispatcher notifier = document.getUserData(KEY);
if (notifier == null) {
notifier = new InvalidRangeDispatcher();
@@ -80,6 +90,7 @@ class DiffRangeMarker extends RangeMarkerImpl {
document.addDocumentListener(notifier);
}
notifier.myClientCount++;
return notifier;
}
private static void removeClient(Document document) {
@@ -96,4 +107,63 @@ class DiffRangeMarker extends RangeMarkerImpl {
}
}
}
/// delegates
@Override
@NotNull
public Document getDocument() {
return myRangeMarker.getDocument();
}
@Override
public int getStartOffset() {
return myRangeMarker.getStartOffset();
}
@Override
public int getEndOffset() {
return myRangeMarker.getEndOffset();
}
@Override
public boolean isValid() {
return myRangeMarker.isValid();
}
@Override
public void setGreedyToLeft(boolean greedy) {
myRangeMarker.setGreedyToLeft(greedy);
}
@Override
public void setGreedyToRight(boolean greedy) {
myRangeMarker.setGreedyToRight(greedy);
}
@Override
public boolean isGreedyToRight() {
return myRangeMarker.isGreedyToRight();
}
@Override
public boolean isGreedyToLeft() {
return myRangeMarker.isGreedyToLeft();
}
@Override
public void dispose() {
myRangeMarker.dispose();
}
@Override
@Nullable
public <T> T getUserData(@NotNull Key<T> key) {
return myRangeMarker.getUserData(key);
}
@Override
public <T> void putUserData(@NotNull Key<T> key, @Nullable T value) {
myRangeMarker.putUserData(key, value);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package com.intellij.openapi.diff.impl.incrementalMerge;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.impl.highlighting.FragmentSide;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.util.TextRange;
import org.jetbrains.annotations.NotNull;
@@ -28,15 +27,16 @@ class SimpleChange extends Change implements DiffRangeMarker.RangeInvalidListene
private final SimpleChangeSide[] mySides;
private final ChangeList myChangeList;
public SimpleChange(@NotNull ChangeType type, @NotNull TextRange range1, @NotNull TextRange range2, @NotNull ChangeList changeList) {
SimpleChange(@NotNull ChangeType type, @NotNull TextRange range1, @NotNull TextRange range2, @NotNull ChangeList changeList) {
mySides = new SimpleChangeSide[]{ createSide(changeList, range1, FragmentSide.SIDE1),
createSide(changeList, range2, FragmentSide.SIDE2)};
myType = type;
myChangeList = changeList;
}
@NotNull
private SimpleChangeSide createSide(@NotNull ChangeList changeList, @NotNull TextRange range1, @NotNull FragmentSide side) {
return new SimpleChangeSide(side, new DiffRangeMarker((DocumentEx)changeList.getDocument(side), range1, this));
return new SimpleChangeSide(side, new DiffRangeMarker(changeList.getDocument(side), range1, this));
}
/**
@@ -55,19 +55,23 @@ class SimpleChange extends Change implements DiffRangeMarker.RangeInvalidListene
}
}
@Override
protected void removeFromList() {
myChangeList.remove(this);
}
@Override
@NotNull
public ChangeSide getChangeSide(@NotNull FragmentSide side) {
return mySides[side.getIndex()];
}
@Override
public ChangeType getType() {
return myType;
}
@Override
public ChangeList getChangeList() {
return myChangeList;
}
@@ -83,6 +87,7 @@ class SimpleChange extends Change implements DiffRangeMarker.RangeInvalidListene
myChangeList.apply(this);
}
@Override
public void onRemovedFromList() {
for (int i = 0; i < mySides.length; i++) {
SimpleChangeSide side = mySides[i];
@@ -92,16 +97,18 @@ class SimpleChange extends Change implements DiffRangeMarker.RangeInvalidListene
}
}
@Override
public boolean isValid() {
LOG.assertTrue((mySides[0] == null) == (mySides[1] == null));
return mySides[0] != null;
}
@Override
public void onRangeInvalidated() {
myChangeList.remove(this);
}
public static Change fromRanges(@NotNull TextRange baseRange, @NotNull TextRange versionRange, @NotNull ChangeList changeList) {
static Change fromRanges(@NotNull TextRange baseRange, @NotNull TextRange versionRange, @NotNull ChangeList changeList) {
ChangeType type = ChangeType.fromRanges(baseRange, versionRange);
return new SimpleChange(type, baseRange, versionRange, changeList);
}
@@ -95,7 +95,11 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
*/
private int myDesiredX = -1;
private volatile MyRangeMarker mySelectionMarker;
private volatile RangeMarker mySelectionMarker;
private volatile VisualPosition myRangeMarkerStartPosition;
private volatile VisualPosition myRangeMarkerEndPosition;
private volatile boolean myRangeMarkerEndPositionIsLead;
private int startBefore;
private int endBefore;
boolean myUnknownDirection;
@@ -140,7 +144,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
}
public void beforeDocumentChange() {
MyRangeMarker marker = mySelectionMarker;
RangeMarker marker = mySelectionMarker;
if (marker != null && marker.isValid()) {
startBefore = marker.getStartOffset();
endBefore = marker.getEndOffset();
@@ -148,7 +152,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
}
public void documentChanged() {
MyRangeMarker marker = mySelectionMarker;
RangeMarker marker = mySelectionMarker;
if (marker != null) {
int endAfter;
int startAfter;
@@ -164,7 +168,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
}
else {
startAfter = endAfter = getOffset();
marker.release();
marker.dispose();
myStartVirtualOffset = 0;
myEndVirtualOffset = 0;
mySelectionMarker = null;
@@ -189,6 +193,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
return;
}
myEditor.getCaretModel().doWithCaretMerging(new Runnable() {
@Override
public void run() {
final LogicalPosition logicalPosition = myEditor.offsetToLogicalPosition(offset);
CaretEvent event = moveToLogicalPosition(logicalPosition, locateBeforeSoftWrap, null, false);
@@ -203,12 +208,10 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
int inverseOffset = myEditor.logicalPositionToOffset(logicalPosition);
LogMessageEx.error(
LOG, "caret moved to wrong offset. Please submit a dedicated ticket and attach current editor's text to it.",
String.format(
"Requested: offset=%d, logical position='%s' but actual: offset=%d, logical position='%s' (%s). %s%n"
+ "interested text [%d;%d): '%s'%n debug trace: %s%nLogical position -> offset ('%s'->'%d')",
offset, logicalPosition, myOffset, myLogicalCaret, positionByOffsetAfterMove, myEditor.dumpState(),
textStart, textEnd, text, debugBuffer, logicalPosition, inverseOffset
)
"Requested: offset=" + offset + ", logical position='" + logicalPosition + "' but actual: offset=" +
myOffset + ", logical position='" + myLogicalCaret + "' (" + positionByOffsetAfterMove + "). " + myEditor.dumpState() +
"\ninterested text [" + textStart + ";" + textEnd + "): '" + text + "'\n debug trace: " + debugBuffer +
"\nLogical position -> offset ('" + logicalPosition + "'->'" + inverseOffset + "')"
);
}
if (event != null) {
@@ -251,6 +254,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
CopyPasteManager.getInstance().stopKillRings();
}
myEditor.getCaretModel().doWithCaretMerging(new Runnable() {
@Override
public void run() {
SelectionModelImpl selectionModel = myEditor.getSelectionModel();
final int leadSelectionOffset = getLeadSelectionOffset();
@@ -431,6 +435,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
@Override
public void moveToLogicalPosition(@NotNull final LogicalPosition pos) {
myEditor.getCaretModel().doWithCaretMerging(new Runnable() {
@Override
public void run() {
moveToLogicalPosition(pos, false, null, true);
}
@@ -593,10 +598,9 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
}
}
else {
LogMessageEx.error(LOG, "Invalid editor dimension mapping", String.format(
"Expected to map visual position '%s' to offset %d but got the following: -> logical position '%s'; -> offset %d. "
+ "State: %s", visualPosition, myOffset, logicalPosition, tmpOffset, myEditor.dumpState()
));
LogMessageEx.error(LOG, "Invalid editor dimension mapping", "Expected to map visual position '" +
visualPosition + "' to offset " + myOffset + " but got the following: -> logical position '" +
logicalPosition + "'; -> offset " + tmpOffset + ". State: " + myEditor.dumpState());
}
}
}
@@ -651,6 +655,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
@Override
public void moveToVisualPosition(@NotNull final VisualPosition pos) {
myEditor.getCaretModel().doWithCaretMerging(new Runnable() {
@Override
public void run() {
moveToVisualPosition(pos, true);
}
@@ -767,7 +772,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
@Override
public void dispose() {
if (mySelectionMarker != null) {
mySelectionMarker.release();
mySelectionMarker.dispose();
mySelectionMarker = null;
}
releaseBulkCaretMarker();
@@ -837,7 +842,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
/**
* Recalculates caret visual position without changing its logical position (called when soft wraps are changing)
*/
public void updateVisualPosition() {
void updateVisualPosition() {
VerticalInfo oldInfo = myCaretInfo;
LogicalPosition visUnawarePos = new LogicalPosition(myLogicalCaret.line, myLogicalCaret.column);
setCurrentLogicalCaret(visUnawarePos);
@@ -956,20 +961,20 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
return newOffset;
}
CaretImpl cloneWithoutSelection() {
private CaretImpl cloneWithoutSelection() {
CaretImpl clone = new CaretImpl(myEditor);
clone.myLogicalCaret = this.myLogicalCaret;
clone.myCaretInfo = this.myCaretInfo;
clone.myVisibleCaret = this.myVisibleCaret;
clone.myOffset = this.myOffset;
clone.myVirtualSpaceOffset = this.myVirtualSpaceOffset;
clone.myVisualLineStart = this.myVisualLineStart;
clone.myVisualLineEnd = this.myVisualLineEnd;
clone.savedBeforeBulkCaretMarker = this.savedBeforeBulkCaretMarker;
clone.mySkipChangeRequests = this.mySkipChangeRequests;
clone.myLastColumnNumber = this.myLastColumnNumber;
clone.myReportCaretMoves = this.myReportCaretMoves;
clone.myDesiredX = this.myDesiredX;
clone.myLogicalCaret = myLogicalCaret;
clone.myCaretInfo = myCaretInfo;
clone.myVisibleCaret = myVisibleCaret;
clone.myOffset = myOffset;
clone.myVirtualSpaceOffset = myVirtualSpaceOffset;
clone.myVisualLineStart = myVisualLineStart;
clone.myVisualLineEnd = myVisualLineEnd;
clone.savedBeforeBulkCaretMarker = savedBeforeBulkCaretMarker;
clone.mySkipChangeRequests = mySkipChangeRequests;
clone.myLastColumnNumber = myLastColumnNumber;
clone.myReportCaretMoves = myReportCaretMoves;
clone.myDesiredX = myDesiredX;
clone.myDesiredSelectionStartColumn = -1;
clone.myDesiredSelectionEndColumn = -1;
return clone;
@@ -981,8 +986,12 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
assertIsDispatchThread();
int lineShift = above ? -1 : 1;
final CaretImpl clone = cloneWithoutSelection();
final int newSelectionStartOffset, newSelectionEndOffset, newSelectionStartColumn, newSelectionEndColumn;
final VisualPosition newSelectionStartPosition, newSelectionEndPosition;
final int newSelectionStartOffset;
final int newSelectionEndOffset;
final int newSelectionStartColumn;
final int newSelectionEndColumn;
final VisualPosition newSelectionStartPosition;
final VisualPosition newSelectionEndPosition;
final boolean hasNewSelection;
if (hasSelection() || myDesiredSelectionStartColumn >=0 || myDesiredSelectionEndColumn >= 0) {
VisualPosition startPosition = getSelectionStartPosition();
@@ -1060,7 +1069,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
* @return information on whether current selection's direction in known
* @see #setUnknownDirection(boolean)
*/
public boolean isUnknownDirection() {
boolean isUnknownDirection() {
return myUnknownDirection;
}
@@ -1076,9 +1085,8 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
* <b>Note:</b> when this method is called with <code>'true'</code>, subsequent calls are guaranteed to return <code>'true'</code>
* until selection is changed. 'Unknown direction' flag is automatically reset then.
*
* @param unknownDirection
*/
public void setUnknownDirection(boolean unknownDirection) {
void setUnknownDirection(boolean unknownDirection) {
myUnknownDirection = unknownDirection;
}
@@ -1086,7 +1094,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
public int getSelectionStart() {
validateContext(false);
if (hasSelection()) {
MyRangeMarker marker = mySelectionMarker;
RangeMarker marker = mySelectionMarker;
if (marker != null) {
return marker.getStartOffset();
}
@@ -1100,7 +1108,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
validateContext(false);
VisualPosition position;
if (hasSelection() && mySelectionMarker != null) {
position = mySelectionMarker.getStartPosition();
position = getRangeMarkerStartPosition();
if (position == null) {
position = myEditor.offsetToVisualPosition(mySelectionMarker.getStartOffset());
}
@@ -1118,7 +1126,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
public int getSelectionEnd() {
validateContext(false);
if (hasSelection()) {
MyRangeMarker marker = mySelectionMarker;
RangeMarker marker = mySelectionMarker;
if (marker != null) {
return marker.getEndOffset();
}
@@ -1132,7 +1140,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
validateContext(false);
VisualPosition position;
if (hasSelection() && mySelectionMarker != null) {
position = mySelectionMarker.getEndPosition();
position = getRangeMarkerEndPosition();
if (position == null) {
position = myEditor.offsetToVisualPosition(mySelectionMarker.getEndOffset());
}
@@ -1149,7 +1157,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
@Override
public boolean hasSelection() {
validateContext(false);
MyRangeMarker marker = mySelectionMarker;
RangeMarker marker = mySelectionMarker;
return marker != null && marker.isValid() && (marker.getEndOffset() > marker.getStartOffset()
|| isVirtualSelectionEnabled() && myEndVirtualOffset > myStartVirtualOffset);
}
@@ -1197,6 +1205,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
final boolean updateSystemSelection)
{
myEditor.getCaretModel().doWithCaretMerging(new Runnable() {
@Override
public void run() {
int startOffset = _startOffset;
int endOffset = _endOffset;
@@ -1255,24 +1264,24 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
oldSelectionStart = oldSelectionEnd = getOffset();
}
MyRangeMarker marker = mySelectionMarker;
RangeMarker marker = mySelectionMarker;
if (marker != null) {
marker.release();
marker.dispose();
}
marker = new MyRangeMarker((DocumentEx)doc, startOffset, endOffset);
marker = doc.createRangeMarker(startOffset, endOffset);
myStartVirtualOffset = 0;
myEndVirtualOffset = 0;
if (visualPositionAware) {
if (endPosition.after(startPosition)) {
marker.setStartPosition(startPosition);
marker.setEndPosition(endPosition);
marker.setEndPositionIsLead(false);
setRangeMarkerStartPosition(startPosition);
setRangeMarkerEndPosition(endPosition);
setRangeMarkerEndPositionIsLead(false);
}
else {
marker.setStartPosition(endPosition);
marker.setEndPosition(startPosition);
marker.setEndPositionIsLead(true);
setRangeMarkerStartPosition(endPosition);
setRangeMarkerEndPosition(startPosition);
setRangeMarkerEndPositionIsLead(true);
}
if (isVirtualSelectionEnabled() &&
@@ -1314,15 +1323,16 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
return;
}
myEditor.getCaretModel().doWithCaretMerging(new Runnable() {
@Override
public void run() {
validateContext(true);
myEditor.getSelectionModel().removeBlockSelection();
int caretOffset = getOffset();
MyRangeMarker marker = mySelectionMarker;
RangeMarker marker = mySelectionMarker;
if (marker != null) {
int startOffset = marker.getStartOffset();
int endOffset = marker.getEndOffset();
marker.release();
marker.dispose();
mySelectionMarker = null;
myStartVirtualOffset = 0;
myEndVirtualOffset = 0;
@@ -1337,7 +1347,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
validateContext(false);
int caretOffset = getOffset();
if (hasSelection()) {
MyRangeMarker marker = mySelectionMarker;
RangeMarker marker = mySelectionMarker;
if (marker != null) {
int startOffset = marker.getStartOffset();
int endOffset = marker.getEndOffset();
@@ -1369,7 +1379,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
@NotNull
@Override
public VisualPosition getLeadSelectionPosition() {
MyRangeMarker marker = mySelectionMarker;
RangeMarker marker = mySelectionMarker;
VisualPosition caretPosition = getVisualPosition();
if (isVirtualSelectionEnabled() && !hasSelection()) {
return caretPosition;
@@ -1378,8 +1388,8 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
return caretPosition;
}
if (marker.isEndPositionIsLead()) {
VisualPosition result = marker.getEndPosition();
if (isRangeMarkerEndPositionIsLead()) {
VisualPosition result = getRangeMarkerEndPosition();
if (result == null) {
return getSelectionEndPosition();
}
@@ -1391,7 +1401,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
}
}
else {
VisualPosition result = marker.getStartPosition();
VisualPosition result = getRangeMarkerStartPosition();
if (result == null) {
return getSelectionStartPosition();
}
@@ -1408,6 +1418,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
public void selectLineAtCaret() {
validateContext(true);
myEditor.getCaretModel().doWithCaretMerging(new Runnable() {
@Override
public void run() {
SelectionModelImpl.doSelectLineAtCaret(myEditor);
}
@@ -1418,6 +1429,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
public void selectWordAtCaret(final boolean honorCamelWordsSettings) {
validateContext(true);
myEditor.getCaretModel().doWithCaretMerging(new Runnable() {
@Override
public void run() {
removeSelection();
final EditorSettings settings = myEditor.getSettings();
@@ -1481,7 +1493,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
boolean hasVirtualSelection() {
validateContext(false);
MyRangeMarker marker = mySelectionMarker;
RangeMarker marker = mySelectionMarker;
return marker != null && marker.isValid() && isVirtualSelectionEnabled() && myEndVirtualOffset > myStartVirtualOffset;
}
@@ -1503,7 +1515,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
/**
* Encapsulates information about target vertical range info - its <code>'y'</code> coordinate and height in pixels.
*/
public static class VerticalInfo {
private static class VerticalInfo {
public final int y;
public final int height;
@@ -1513,68 +1525,40 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
}
}
private class MyRangeMarker extends RangeMarkerImpl {
private VisualPosition myStartPosition;
private VisualPosition myEndPosition;
private boolean myEndPositionIsLead;
private boolean myIsReleased;
@Nullable
private VisualPosition getRangeMarkerStartPosition() {
invalidateRangeMarkerVisualPositions(mySelectionMarker);
return myRangeMarkerStartPosition;
}
MyRangeMarker(DocumentEx document, int start, int end) {
super(document, start, end, true);
myIsReleased = false;
}
private void setRangeMarkerStartPosition(@NotNull VisualPosition startPosition) {
myRangeMarkerStartPosition = startPosition;
}
public void release() {
myIsReleased = true;
dispose();
}
@Nullable
private VisualPosition getRangeMarkerEndPosition() {
invalidateRangeMarkerVisualPositions(mySelectionMarker);
return myRangeMarkerEndPosition;
}
@Nullable
public VisualPosition getStartPosition() {
invalidateVisualPositions();
return myStartPosition;
}
void setRangeMarkerEndPosition(@NotNull VisualPosition endPosition) {
myRangeMarkerEndPosition = endPosition;
}
public void setStartPosition(@NotNull VisualPosition startPosition) {
myStartPosition = startPosition;
}
private boolean isRangeMarkerEndPositionIsLead() {
return myRangeMarkerEndPositionIsLead;
}
@Nullable
public VisualPosition getEndPosition() {
invalidateVisualPositions();
return myEndPosition;
}
void setRangeMarkerEndPositionIsLead(boolean endPositionIsLead) {
myRangeMarkerEndPositionIsLead = endPositionIsLead;
}
public void setEndPosition(@NotNull VisualPosition endPosition) {
myEndPosition = endPosition;
}
public boolean isEndPositionIsLead() {
return myEndPositionIsLead;
}
public void setEndPositionIsLead(boolean endPositionIsLead) {
myEndPositionIsLead = endPositionIsLead;
}
int startBefore;
int endBefore;
@Override
protected void changedUpdateImpl(DocumentEvent e) {
if (myIsReleased) return;
startBefore = getStartOffset();
endBefore = getEndOffset();
super.changedUpdateImpl(e);
}
private void invalidateVisualPositions() {
SoftWrapModelImpl model = myEditor.getSoftWrapModel();
if (!myEditor.offsetToVisualPosition(getStartOffset()).equals(myStartPosition) && model.getSoftWrap(getStartOffset()) == null
|| !myEditor.offsetToVisualPosition(getEndOffset()).equals(myEndPosition) && model.getSoftWrap(getEndOffset()) == null) {
myStartPosition = null;
myEndPosition = null;
}
private void invalidateRangeMarkerVisualPositions(RangeMarker marker) {
SoftWrapModelImpl model = myEditor.getSoftWrapModel();
if (!myEditor.offsetToVisualPosition(marker.getStartOffset()).equals(myRangeMarkerStartPosition) && model.getSoftWrap(marker.getStartOffset()) == null
|| !myEditor.offsetToVisualPosition(marker.getEndOffset()).equals(myRangeMarkerEndPosition) && model.getSoftWrap(marker.getEndOffset()) == null) {
myRangeMarkerStartPosition = null;
myRangeMarkerEndPosition = null;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@ import com.intellij.openapi.editor.ex.DocumentEx;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class FoldRegionImpl extends RangeMarkerImpl implements FoldRegion {
class FoldRegionImpl extends RangeMarkerImpl implements FoldRegion {
private boolean myIsExpanded;
private final Editor myEditor;
private final String myPlaceholderText;
@@ -94,7 +94,7 @@ public class FoldRegionImpl extends RangeMarkerImpl implements FoldRegion {
return super.isValid() && intervalStart() < intervalEnd();
}
public void setExpandedInternal(boolean toExpand) {
void setExpandedInternal(boolean toExpand) {
myIsExpanded = toExpand;
}
@@ -120,6 +120,7 @@ public class FoldRegionImpl extends RangeMarkerImpl implements FoldRegion {
return myShouldNeverExpand;
}
@Override
public String toString() {
return "FoldRegion " + (myIsExpanded ? "-" : "+") + "(" + getStartOffset() + ":" + getEndOffset() + ")"
+ (isValid() ? "" : "(invalid)") + ", placeholder='" + myPlaceholderText + "'";