diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/SoftWrapModelEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/SoftWrapModelEx.java
index 3f309e1987d9..ac7a6aef1359 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/SoftWrapModelEx.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/SoftWrapModelEx.java
@@ -116,4 +116,19 @@ public interface SoftWrapModelEx extends SoftWrapModel {
* @return true if given listener was not registered before; false otherwise
*/
boolean addSoftWrapChangeListener(@NotNull SoftWrapChangeListener listener);
+
+ /**
+ * Asks current model to define approximate soft wraps for the lines range defined by the given lines if necessary.
+ *
+ * The main idea is to calculate exact soft wraps positions during editor repainting because we have complete
+ * information about font types used for text representation there. However, there is a possible case that we need to
+ * perform intermediate soft wraps calculations. E.g. we may open big document and than may want to scroll to the middle
+ * of it, hence, need to define vertical offset to apply to viewport position. However, vertical offset value depends on
+ * soft wraps between current visible area and target logical line and that soft wraps are not applied yet. We may call this
+ * method in order to define approximate soft wraps number and positions then in order to make scrolling more precise.
+ *
+ * @param line1 one of the target lines boundaries (not imposed to be greater or less than the other boundary)
+ * @param line2 another boundary line (not imposed to be greater or less than the other boundary)
+ */
+ void defineApproximateSoftWraps(int line1, int line2);
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ScrollingModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ScrollingModelImpl.java
index 2995e30be3a6..8bb8addc586e 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/ScrollingModelImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/ScrollingModelImpl.java
@@ -142,6 +142,13 @@ public class ScrollingModelImpl implements ScrollingModel {
}
private Point calcOffsetsToScroll(LogicalPosition pos, ScrollType scrollType, Rectangle viewRect) {
+ // There is a possible case that the user opens huge document with many number of soft-wrapped line.
+ // Suppose that he or she wants to move viewport to such a logical position that many document lines between current
+ // viewport position and the target one are not displayed before. That means that we can't be sure about vertical offset
+ // to be applied to the viewport. Hence, we ask soft wrap model to roughly define soft wraps on a trail.
+ LogicalPosition firstVisibleLineStart = myEditor.xyToLogicalPosition(viewRect.getLocation());
+ myEditor.getSoftWrapModel().defineApproximateSoftWraps(firstVisibleLineStart.line, pos.line);
+
Point targetLocation = myEditor.logicalPositionToXY(pos);
if (myEditor.getSettings().isRefrainFromScrolling() && viewRect.contains(targetLocation)) {
@@ -424,9 +431,10 @@ public class ScrollingModelImpl implements ScrollingModel {
return new Rectangle(myEndHOffset, myEndVOffset, viewRect.width, viewRect.height);
}
- public Runnable getStartCommand() {
- return myStartCommand;
- }
+ // Commented as the method is not used
+ //public Runnable getStartCommand() {
+ // return myStartCommand;
+ //}
private void tick() {
double time = (myTicksCount + 1) / (double)myStepCount;
@@ -496,9 +504,8 @@ public class ScrollingModelImpl implements ScrollingModel {
double lineDist = myTotalDist / lineHeight;
double part = (lineDist - 1) / 10;
if (part > 1) part = 1;
- int duration = (int)(part * SCROLL_DURATION);
//System.out.println("duration = " + duration);
- return duration;
+ return (int)(part * SCROLL_DURATION);
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java
index 11e1c6c9a711..d25baa66f843 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SoftWrapModelImpl.java
@@ -172,6 +172,28 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, DocumentListener {
return result;
}
+ @Override
+ public void defineApproximateSoftWraps(int line1, int line2) {
+ if (!isSoftWrappingEnabled()) {
+ return;
+ }
+ int startLine = line1;
+ int endLine = line2;
+ if (line1 > line2) {
+ startLine = line2;
+ endLine = line1;
+ }
+
+ // Normalization.
+ Document document = myEditor.getDocument();
+ startLine = Math.max(0, startLine);
+ endLine = Math.min(endLine, document.getLineCount() - 1);
+
+ myApplianceManager.registerSoftWrapIfNecessary(
+ document.getCharsSequence(), document.getLineStartOffset(startLine), document.getLineEndOffset(endLine), 0, Font.PLAIN, true
+ );
+ }
+
public void registerSoftWrapIfNecessary(@NotNull CharSequence text, int start, int end, int x, int fontType) {
if (!isSoftWrappingEnabled()) {
return;
@@ -180,7 +202,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx, DocumentListener {
myActive++;
try {
- myApplianceManager.registerSoftWrapIfNecessary(text, start, end, x, fontType);
+ myApplianceManager.registerSoftWrapIfNecessary(text, start, end, x, fontType, false);
}
finally {
myActive--;
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/DefaultSoftWrapApplianceManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/DefaultSoftWrapApplianceManager.java
index c54eff21b8e1..148c3e8f7de8 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/DefaultSoftWrapApplianceManager.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/DefaultSoftWrapApplianceManager.java
@@ -16,8 +16,6 @@
package com.intellij.openapi.editor.impl.softwrap;
import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.VisualPosition;
-import com.intellij.openapi.editor.actions.EditorActionUtil;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.util.EditorUtil;
@@ -29,6 +27,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import gnu.trove.TIntArrayList;
import gnu.trove.TIntHashSet;
+import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
@@ -103,7 +102,12 @@ public class DefaultSoftWrapApplianceManager implements SoftWrapApplianceManager
SPECIAL_SYMBOLS_TO_WRAP_BEFORE.add('.');
}
- private final TIntHashSet myProcessedLogicalLines = new TIntHashSet();
+ /**
+ * Holds information about logical lines for which soft wrap is calculated as a set of
+ * (logical line number; temporary) pairs.
+ */
+ private final TIntObjectHashMap myProcessedLogicalLines = new TIntObjectHashMap();
+
private final DocumentListener myDocumentListener = new LineOrientedDocumentChangeAdapter() {
@Override
public void beforeDocumentChange(int startLine, int endLine, int symbolsDifference) {
@@ -124,7 +128,7 @@ public class DefaultSoftWrapApplianceManager implements SoftWrapApplianceManager
// Note: we don't update 'myProcessedLogicalLines' collection here, i.e. soft wraps will be recalculated precisely
// during standard editor repainting iteration.
if (i < document.getLineCount()) {
- processLogicalLine(document.getCharsSequence(), i, Font.PLAIN, IndentType.NONE);
+ processLogicalLine(document.getCharsSequence(), i, Font.PLAIN, IndentType.NONE, true);
}
}
}
@@ -150,7 +154,7 @@ public class DefaultSoftWrapApplianceManager implements SoftWrapApplianceManager
@SuppressWarnings({"AssignmentToForLoopParameter"})
@Override
- public void registerSoftWrapIfNecessary(@NotNull CharSequence text, int start, int end, int x, int fontType) {
+ public void registerSoftWrapIfNecessary(@NotNull CharSequence text, int start, int end, int x, int fontType, boolean temporary) {
dropDataIfNecessary();
if (myVisibleAreaWidth <= 0 || start >= end) {
@@ -161,13 +165,13 @@ public class DefaultSoftWrapApplianceManager implements SoftWrapApplianceManager
int startLine = document.getLineNumber(start);
int endLine = document.getLineNumber(end);
for (int i = startLine; i <= endLine; i++) {
- if (!myProcessedLogicalLines.contains(i)) {
+ if (!myProcessedLogicalLines.contains(i) || (!temporary && myProcessedLogicalLines.get(i))) {
IndentType indent = IndentType.NONE;
if (!myEditor.isViewer() && !document.isWritable()) {
indent = IndentType.TO_PREV_LINE_NON_WS_START;
}
- processLogicalLine(text, i, fontType, indent);
- myProcessedLogicalLines.add(i);
+ processLogicalLine(text, i, fontType, indent, temporary);
+ myProcessedLogicalLines.put(i, temporary);
}
}
}
@@ -188,7 +192,7 @@ public class DefaultSoftWrapApplianceManager implements SoftWrapApplianceManager
myVisibleAreaWidth = currentVisibleAreaWidth;
}
- private void processLogicalLine(CharSequence text, int line, int fontType, IndentType indentType) {
+ private void processLogicalLine(CharSequence text, int line, int fontType, IndentType indentType, boolean temporary) {
Document document = myEditor.getDocument();
int startOffset = document.getLineStartOffset(line);
int endOffset = document.getLineEndOffset(line);
@@ -202,15 +206,26 @@ public class DefaultSoftWrapApplianceManager implements SoftWrapApplianceManager
if (indentType == IndentType.NONE) {
TIntArrayList offsets = calculateSoftWrapOffsets(text, startOffset, endOffset, fontType, 0);
- registerSoftWraps(offsets, 0);
+ registerSoftWraps(offsets, 0, temporary);
return;
}
// Understand if it's worth to define indent for soft wrap(s) to create and perform their actual construction and registration.
+ int prevLineIndentInColumns = 0;
+
+ int firstNonSpaceSymbolIndex = startOffset;
+ for (; firstNonSpaceSymbolIndex < endOffset; firstNonSpaceSymbolIndex++) {
+ char c = text.charAt(firstNonSpaceSymbolIndex);
+ if (c != ' ' && c != '\t') {
+ break;
+ }
+ }
+ if (firstNonSpaceSymbolIndex > startOffset) {
+ prevLineIndentInColumns = myTextRepresentationHelper.toVisualColumnSymbolsNumber(text, startOffset, firstNonSpaceSymbolIndex, 0);
+ }
+
int spaceWidth = EditorUtil.getSpaceWidth(fontType, myEditor);
int indentInColumns = getIndentSize();
- VisualPosition visual = myEditor.offsetToVisualPosition(startOffset);
- int prevLineIndentInColumns = EditorActionUtil.findFirstNonSpaceColumnOnTheLine(myEditor, visual.line);
int indentInColumnsToUse = 0;
TIntArrayList softWrapOffsetsToUse = null;
for (; indentInColumns >= 0; indentInColumns--) {
@@ -229,10 +244,10 @@ public class DefaultSoftWrapApplianceManager implements SoftWrapApplianceManager
}
if (indentInColumnsToUse <= 0) {
- processLogicalLine(text, line, fontType, IndentType.NONE);
+ processLogicalLine(text, line, fontType, IndentType.NONE, temporary);
}
else {
- registerSoftWraps(softWrapOffsetsToUse, indentInColumnsToUse + prevLineIndentInColumns);
+ registerSoftWraps(softWrapOffsetsToUse, indentInColumnsToUse + prevLineIndentInColumns, temporary);
}
}
@@ -275,10 +290,10 @@ public class DefaultSoftWrapApplianceManager implements SoftWrapApplianceManager
return settings.getIndentSize(file.getFileType());
}
- private void registerSoftWraps(TIntArrayList offsets, int indentInColumns) {
+ private void registerSoftWraps(TIntArrayList offsets, int indentInColumns, boolean temporary) {
for (int i = 0; i < offsets.size(); i++) {
int offset = offsets.getQuick(i);
- myStorage.storeOrReplace(new TextChangeImpl("\n" + StringUtil.repeatSymbol(' ', indentInColumns), offset));
+ myStorage.storeOrReplace(new TextChangeImpl("\n" + StringUtil.repeatSymbol(' ', indentInColumns), offset), !temporary);
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapApplianceManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapApplianceManager.java
index ccbef464f82c..c334cbb5b6d5 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapApplianceManager.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapApplianceManager.java
@@ -44,6 +44,8 @@ public interface SoftWrapApplianceManager {
* @param end end offset of the token to process within the given char array (exclusive)
* @param x 'x' coordinate within the given graphics buffer that will be used to start drawing the text
* @param fontType font type used for the target text fragment representation
+ * @param temporary defines type of the current call. 'Temporary' means that soft wraps registered during
+ * the processing should be recalculated on further invocations; they may be reused otherwise
*/
- void registerSoftWrapIfNecessary(@NotNull CharSequence text, int start, int end, int x, int fontType);
+ void registerSoftWrapIfNecessary(@NotNull CharSequence text, int start, int end, int x, int fontType, boolean temporary);
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapsStorage.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapsStorage.java
index fe8f785fc8bb..ad24ee00ab42 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapsStorage.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/SoftWrapsStorage.java
@@ -92,19 +92,23 @@ public class SoftWrapsStorage {
/**
* Inserts given soft wrap to {@link #myWraps} collection at the given index.
*
- * @param softWrap soft wrap to store
- * @return previous soft wrap object stored for the same offset if any; null otherwise
+ * @param softWrap soft wrap to store
+ * @param notifyListeners flag that indicates if registered listeners should be notified about soft wrap registration
+ * @return previous soft wrap object stored for the same offset if any; null otherwise
*/
@Nullable
- public TextChangeImpl storeOrReplace(TextChangeImpl softWrap) { int i = getSoftWrapIndex(softWrap.getStart());
+ public TextChangeImpl storeOrReplace(TextChangeImpl softWrap, boolean notifyListeners) {
+ int i = getSoftWrapIndex(softWrap.getStart());
if (i >= 0) {
return myWraps.set(i, softWrap);
}
i = -i - 1;
myWraps.add(i, softWrap);
- for (SoftWrapChangeListener listener : myListeners) {
- listener.softWrapAdded(softWrap);
+ if (notifyListeners) {
+ for (SoftWrapChangeListener listener : myListeners) {
+ listener.softWrapAdded(softWrap);
+ }
}
return null;
}
diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/DefaultSoftWrapApplianceManagerTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/DefaultSoftWrapApplianceManagerTest.java
index 5a74d03f650b..e2cff945fd24 100644
--- a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/DefaultSoftWrapApplianceManagerTest.java
+++ b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/DefaultSoftWrapApplianceManagerTest.java
@@ -111,7 +111,7 @@ public class DefaultSoftWrapApplianceManagerTest {
allowing(myScrollingModel).getVisibleArea(); will(returnValue(new Rectangle(0, 0, context.visualWidth, Integer.MAX_VALUE)));
allowing(myDocument).getLineEndOffset(0); will(returnValue(context.document.length()));
}});
- myManager.registerSoftWrapIfNecessary(context.document, 0, context.document.length(), 0, Font.PLAIN);
+ myManager.registerSoftWrapIfNecessary(context.document, 0, context.document.length(), 0, Font.PLAIN, true);
}
private static TextChangeImpl createSoftWrap(int offset, int indent) {
@@ -177,7 +177,7 @@ public class DefaultSoftWrapApplianceManagerTest {
private void processWrap() {
buffer.append(rawDocument.substring(index, wrapIndex));
myMockery.checking(new Expectations() {{
- one(myStorage).storeOrReplace(createSoftWrap(buffer.length(), 0));
+ one(myStorage).storeOrReplace(createSoftWrap(buffer.length(), 0), false);
}});
index = wrapIndex + WRAP_MARKER.length();
wrapIndex = rawDocument.indexOf(WRAP_MARKER, index);
diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java
index 16dc3764f6ef..be4b1dd30734 100644
--- a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java
+++ b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/SoftWrapDataMapperTest.java
@@ -654,7 +654,7 @@ public class SoftWrapDataMapperTest {
}
public void onSoftWrapEnd() {
- myStorage.storeOrReplace(new TextChangeImpl(mySoftWrapBuffer.toString(), softWrapStartOffset));
+ myStorage.storeOrReplace(new TextChangeImpl(mySoftWrapBuffer.toString(), softWrapStartOffset), false);
mySoftWrapBuffer.setLength(0);
insideSoftWrap = false;
x += SOFT_WRAP_DRAWING_WIDTH;