IDEA-60781 After formatting cursor jumps from indented position to beginning of the line.

Renaming ProcessingContext -> EditorPosition
This commit is contained in:
Denis Zhdanov
2010-11-18 14:35:47 +03:00
parent f6073e9e4c
commit dbaf8f3976
11 changed files with 267 additions and 266 deletions
@@ -74,7 +74,7 @@ abstract class AbstractMappingStrategy<T> implements MappingStrategy<T> {
@NotNull
@Override
public ProcessingContext buildInitialContext() {
public EditorPosition buildInitialPosition() {
return myCacheEntry.buildStartLineContext();
}
@@ -83,27 +83,27 @@ abstract class AbstractMappingStrategy<T> implements MappingStrategy<T> {
}
@Override
public T advance(ProcessingContext context, int offset) {
T result = buildIfExceeds(context, offset);
public T advance(EditorPosition position, int offset) {
T result = buildIfExceeds(position, offset);
if (result != null) {
return result;
}
// Update context state and continue processing.
context.logicalLine = myEditor.getDocument().getLineNumber(offset);
int diff = offset - context.offset;
context.visualColumn += diff;
context.logicalColumn += diff;
context.offset = offset;
position.logicalLine = myEditor.getDocument().getLineNumber(offset);
int diff = offset - position.offset;
position.visualColumn += diff;
position.logicalColumn += diff;
position.offset = offset;
return null;
}
@Nullable
protected abstract T buildIfExceeds(ProcessingContext context, int offset);
protected abstract T buildIfExceeds(EditorPosition context, int offset);
@Override
public T processFoldRegion(ProcessingContext context, FoldRegion foldRegion) {
T result = buildIfExceeds(context, foldRegion);
public T processFoldRegion(EditorPosition position, FoldRegion foldRegion) {
T result = buildIfExceeds(position, foldRegion);
if (result != null) {
return result;
}
@@ -111,12 +111,12 @@ abstract class AbstractMappingStrategy<T> implements MappingStrategy<T> {
Document document = myEditor.getDocument();
int endOffsetLogicalLine = document.getLineNumber(foldRegion.getEndOffset());
int collapsedSymbolsWidthInColumns;
if (context.logicalLine == endOffsetLogicalLine) {
if (position.logicalLine == endOffsetLogicalLine) {
// Single-line fold region.
FoldingData foldingData = getFoldRegionData(foldRegion);
if (foldingData == null) {
assert false;
collapsedSymbolsWidthInColumns = context.visualColumn * myRepresentationHelper.textWidth(" ", 0, 1, Font.PLAIN, 0);
collapsedSymbolsWidthInColumns = position.visualColumn * myRepresentationHelper.textWidth(" ", 0, 1, Font.PLAIN, 0);
}
else {
collapsedSymbolsWidthInColumns = foldingData.getCollapsedSymbolsWidthInColumns();
@@ -127,31 +127,31 @@ abstract class AbstractMappingStrategy<T> implements MappingStrategy<T> {
collapsedSymbolsWidthInColumns = myRepresentationHelper.toVisualColumnSymbolsNumber(
document.getCharsSequence(), foldRegion.getStartOffset(), foldRegion.getEndOffset(), 0
);
context.softWrapColumnDiff = 0;
context.softWrapLinesBefore += context.softWrapLinesCurrent;
context.softWrapLinesCurrent = 0;
position.softWrapColumnDiff = 0;
position.softWrapLinesBefore += position.softWrapLinesCurrent;
position.softWrapLinesCurrent = 0;
}
context.advance(foldRegion, collapsedSymbolsWidthInColumns);
position.advance(foldRegion, collapsedSymbolsWidthInColumns);
return null;
}
@Nullable
protected abstract T buildIfExceeds(@NotNull ProcessingContext context, @NotNull FoldRegion foldRegion);
protected abstract T buildIfExceeds(@NotNull EditorPosition context, @NotNull FoldRegion foldRegion);
@Override
public T processTabulation(ProcessingContext context, TabData tabData) {
T result = buildIfExceeds(context, tabData);
public T processTabulation(EditorPosition position, TabData tabData) {
T result = buildIfExceeds(position, tabData);
if (result != null) {
return result;
}
context.visualColumn += tabData.widthInColumns;
context.logicalColumn += tabData.widthInColumns;
context.offset++;
position.visualColumn += tabData.widthInColumns;
position.logicalColumn += tabData.widthInColumns;
position.offset++;
return null;
}
@Nullable
protected abstract T buildIfExceeds(ProcessingContext context, TabData tabData);
protected abstract T buildIfExceeds(EditorPosition context, TabData tabData);
}
@@ -74,7 +74,7 @@ class CacheEntry implements Comparable<CacheEntry>, Cloneable {
myCache = cache;
}
public void setLineStartPosition(@NotNull ProcessingContext context, int i) {
public void setLineStartPosition(@NotNull EditorPosition context, int i) {
assert context.visualColumn == 0;
startLogicalLine = context.logicalLine;
startLogicalColumn = context.logicalColumn;
@@ -91,7 +91,7 @@ class CacheEntry implements Comparable<CacheEntry>, Cloneable {
}
}
public void setLineEndPosition(@NotNull ProcessingContext context) {
public void setLineEndPosition(@NotNull EditorPosition context) {
endOffset = context.offset;
endLogicalLine = context.logicalLine;
endLogicalColumn = context.logicalColumn;
@@ -103,8 +103,8 @@ class CacheEntry implements Comparable<CacheEntry>, Cloneable {
endFoldingColumnDiff = context.foldingColumnDiff;
}
public ProcessingContext buildStartLineContext() {
ProcessingContext result = new ProcessingContext(myEditor, myRepresentationHelper);
public EditorPosition buildStartLineContext() {
EditorPosition result = new EditorPosition(myEditor, myRepresentationHelper);
result.logicalLine = startLogicalLine;
result.logicalColumn = startLogicalColumn;
result.offset = startOffset;
@@ -118,8 +118,8 @@ class CacheEntry implements Comparable<CacheEntry>, Cloneable {
return result;
}
public ProcessingContext buildEndLineContext() {
ProcessingContext result = new ProcessingContext(myEditor, myRepresentationHelper);
public EditorPosition buildEndLineContext() {
EditorPosition result = new EditorPosition(myEditor, myRepresentationHelper);
result.logicalLine = endLogicalLine;
result.logicalColumn = endLogicalColumn;
result.offset = endOffset;
@@ -152,7 +152,7 @@ class CacheEntry implements Comparable<CacheEntry>, Cloneable {
return myTabPositions;
}
public void storeTabData(ProcessingContext context) {
public void storeTabData(EditorPosition context) {
storeTabData(new TabData(context));
}
@@ -183,7 +183,7 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw
return eagerMatch;
}
ProcessingContext context = strategy.buildInitialContext();
EditorPosition position = strategy.buildInitialPosition();
// Folding model doesn't return information about fold regions if their 'enabled' state is set to 'false'. Unfortunately,
// such situation occurs not only on manual folding disabling but on internal processing as well. E.g. 'enabled' is set
@@ -196,13 +196,13 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw
try {
provider = new CompositeDataProvider(
new SoftWrapsDataProvider(myStorage), new FoldingDataProvider(myEditor.getFoldingModel().fetchTopLevel()),
getTabulationDataProvider(context.visualLine)
getTabulationDataProvider(position.visualLine)
);
}
finally {
foldingModel.setFoldingEnabled(foldingState);
}
provider.advance(context.offset);
provider.advance(position.offset);
while (provider.hasData()) {
Pair<SoftWrapDataProviderKeys, ?> data = provider.getData();
@@ -210,24 +210,24 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw
int sortingKey = provider.getSortingKey();
// There is a possible case that, say, fold region is soft wrapped. We don't want to perform unnecessary then.
if (context.offset <= sortingKey) {
result = strategy.advance(context, sortingKey);
if (position.offset <= sortingKey) {
result = strategy.advance(position, sortingKey);
if (result != null) {
return result;
}
}
switch (data.first) {
case SOFT_WRAP: result = strategy.processSoftWrap(context, (SoftWrap)data.second); break;
case COLLAPSED_FOLDING: result = strategy.processFoldRegion(context, (FoldRegion)data.second); break;
case TABULATION: result = strategy.processTabulation(context, (TabData)data.second); break;
case SOFT_WRAP: result = strategy.processSoftWrap(position, (SoftWrap)data.second); break;
case COLLAPSED_FOLDING: result = strategy.processFoldRegion(position, (FoldRegion)data.second); break;
case TABULATION: result = strategy.processTabulation(position, (TabData)data.second); break;
}
if (result != null) {
return result;
}
provider.next();
}
return strategy.build(context);
return strategy.build(position);
}
private TabulationDataProvider getTabulationDataProvider(int visualLine) throws IllegalStateException {
@@ -245,19 +245,19 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw
}
@Override
public void onProcessedSymbol(@NotNull ProcessingContext context) {
switch (context.symbol) {
case '\n': onLineFeed(context); break;
case '\t': onTabulation(context); break;
default: onNonLineFeedSymbol(context); break;
public void onProcessedSymbol(@NotNull EditorPosition position) {
switch (position.symbol) {
case '\n': onLineFeed(position); break;
case '\t': onTabulation(position); break;
default: onNonLineFeedSymbol(position); break;
}
int documentLength = myEditor.getDocument().getTextLength();
if (documentLength > 0 && context.offset >= documentLength - 1 && context.symbol != '\n') {
if (documentLength > 0 && position.offset >= documentLength - 1 && position.symbol != '\n') {
// Update information about end position of the last visual line.
CacheEntry cacheEntry = getCacheEntryForVisualLine(context.visualLine);
cacheEntry.endLogicalColumn += context.symbolWidthInColumns;
cacheEntry.endVisualColumn += context.symbolWidthInColumns;
CacheEntry cacheEntry = getCacheEntryForVisualLine(position.visualLine);
cacheEntry.endLogicalColumn += position.symbolWidthInColumns;
cacheEntry.endVisualColumn += position.symbolWidthInColumns;
cacheEntry.endOffset++;
}
}
@@ -269,15 +269,15 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw
}
@Override
public void beforeSoftWrap(@NotNull ProcessingContext context) {
CacheEntry cacheEntry = getCacheEntryForVisualLine(context.visualLine);
cacheEntry.setLineEndPosition(context);
public void beforeSoftWrap(@NotNull EditorPosition position) {
CacheEntry cacheEntry = getCacheEntryForVisualLine(position.visualLine);
cacheEntry.setLineEndPosition(position);
}
@Override
public void afterSoftWrapLineFeed(@NotNull ProcessingContext context) {
CacheEntry cacheEntry = getCacheEntryForVisualLine(context.visualLine);
cacheEntry.setLineStartPosition(context, context.visualLine);
public void afterSoftWrapLineFeed(@NotNull EditorPosition position) {
CacheEntry cacheEntry = getCacheEntryForVisualLine(position.visualLine);
cacheEntry.setLineStartPosition(position, position.visualLine);
}
@Override
@@ -305,49 +305,49 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw
}
/**
* Updates inner cache for the context that points to line feed symbol
* Updates inner cache for the position that points to line feed symbol
*
* @param context processing context that points to line feed symbol
* @param position position that points to line feed symbol
*/
private void onLineFeed(@NotNull ProcessingContext context) {
CacheEntry cacheEntry = getCacheEntryForVisualLine(context.visualLine);
cacheEntry.setLineEndPosition(context);
private void onLineFeed(@NotNull EditorPosition position) {
CacheEntry cacheEntry = getCacheEntryForVisualLine(position.visualLine);
cacheEntry.setLineEndPosition(position);
cacheEntry = getCacheEntryForVisualLine(context.visualLine + 1);
cacheEntry = getCacheEntryForVisualLine(position.visualLine + 1);
ProcessingContext newLineContext = context.clone();
newLineContext.onNewLine();
newLineContext.offset++;
cacheEntry.setLineStartPosition(newLineContext, context.visualLine + 1);
cacheEntry.setLineEndPosition(newLineContext);
EditorPosition newLinePosition = position.clone();
newLinePosition.onNewLine();
newLinePosition.offset++;
cacheEntry.setLineStartPosition(newLinePosition, position.visualLine + 1);
cacheEntry.setLineEndPosition(newLinePosition);
}
/**
* Updates inner cache for the context that points to tabulation symbol.
* Updates inner cache for the position that points to tabulation symbol.
*
* @param context processing context that points to tabulation symbol
* @param position position that points to tabulation symbol
*/
private void onTabulation(@NotNull ProcessingContext context) {
onNonLineFeedSymbol(context);
CacheEntry cacheEntry = getCacheEntryForVisualLine(context.visualLine);
cacheEntry.storeTabData(context);
private void onTabulation(@NotNull EditorPosition position) {
onNonLineFeedSymbol(position);
CacheEntry cacheEntry = getCacheEntryForVisualLine(position.visualLine);
cacheEntry.storeTabData(position);
}
/**
* Process given context in assumption that it points to non-line feed symbol.
* Process given position in assumption that it points to non-line feed symbol.
*
* @param context context that is assumed to point to non-line feed symbol
* @param position position that is assumed to point to non-line feed symbol
*/
private void onNonLineFeedSymbol(@NotNull ProcessingContext context) {
CacheEntry cacheEntry = getCacheEntryForVisualLine(context.visualLine);
private void onNonLineFeedSymbol(@NotNull EditorPosition position) {
CacheEntry cacheEntry = getCacheEntryForVisualLine(position.visualLine);
Document document = myEditor.getDocument();
if (context.offset >= document.getTextLength() - 1) {
cacheEntry.setLineEndPosition(context);
if (position.offset >= document.getTextLength() - 1) {
cacheEntry.setLineEndPosition(position);
return;
}
if (context.offset < 0 || (context.offset > 0 && context.offset < document.getTextLength()
&& document.getCharsSequence().charAt(context.offset - 1) != '\n'))
if (position.offset < 0 || (position.offset > 0 && position.offset < document.getTextLength()
&& document.getCharsSequence().charAt(position.offset - 1) != '\n'))
{
return;
}
@@ -355,7 +355,7 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw
// Process first symbol on a new line.
cacheEntry.getTabData().clear();
cacheEntry.getFoldingData().clear();
cacheEntry.setLineStartPosition(context.clone(), context.visualLine);
cacheEntry.setLineStartPosition(position.clone(), position.visualLine);
}
private CacheEntry getCacheEntryForVisualLine(int visualLine) {
@@ -22,12 +22,13 @@ import org.jetbrains.annotations.NotNull;
/**
* Utility class that is assumed to be used for internal purposes only.
* <p/>
* Allows to hold complete information about particular document position and provides utility methods for working with it.
* Allows to hold complete information about particular position of document exposed via IJ editor and provides utility
* methods for working with it.
*
* @author Denis Zhdanov
* @since Sep 1, 2010 12:16:38 PM
*/
class ProcessingContext implements Cloneable {
class EditorPosition implements Cloneable {
public int logicalLine;
public int logicalColumn;
@@ -47,22 +48,24 @@ class ProcessingContext implements Cloneable {
private final Editor myEditor;
private final EditorTextRepresentationHelper myRepresentationHelper;
ProcessingContext(@NotNull Editor editor, @NotNull EditorTextRepresentationHelper representationHelper) {
EditorPosition(@NotNull Editor editor, @NotNull EditorTextRepresentationHelper representationHelper) {
myEditor = editor;
myRepresentationHelper = representationHelper;
}
ProcessingContext(@NotNull LogicalPosition logical, int offset, @NotNull Editor editor,
@NotNull EditorTextRepresentationHelper representationHelper)
EditorPosition(@NotNull LogicalPosition logical,
int offset,
@NotNull Editor editor,
@NotNull EditorTextRepresentationHelper representationHelper)
{
this(logical, logical.toVisualPosition(), offset, editor, representationHelper);
}
ProcessingContext(@NotNull LogicalPosition logical,
@NotNull VisualPosition visual,
int offset,
@NotNull Editor editor,
@NotNull EditorTextRepresentationHelper representationHelper)
EditorPosition(@NotNull LogicalPosition logical,
@NotNull VisualPosition visual,
int offset,
@NotNull Editor editor,
@NotNull EditorTextRepresentationHelper representationHelper)
{
myEditor = editor;
myRepresentationHelper = representationHelper;
@@ -108,7 +111,7 @@ class ProcessingContext implements Cloneable {
* Calculates width in columns for the collapsed symbols of the given fold region and delegates further processing
* to {@link #advance(FoldRegion, int)}.
*
* @param foldRegion fold region which end offset should be pointed by the current context
* @param foldRegion fold region which end offset should be pointed by the current position
*/
public void advance(@NotNull FoldRegion foldRegion) {
Document document = myEditor.getDocument();
@@ -119,9 +122,9 @@ class ProcessingContext implements Cloneable {
}
/**
* Updates state of the current processing context in order to point it to the end offset of the given fold region.
* Updates state of the current processing position in order to point it to the end offset of the given fold region.
*
* @param foldRegion fold region which end offset should be pointed by the current context
* @param foldRegion fold region which end offset should be pointed by the current position
* @param collapsedSymbolsWidthInColumns identifies collapsed text width in columns, i.e. width of the last collapsed logical line
* in columns
*/
@@ -149,26 +152,26 @@ class ProcessingContext implements Cloneable {
}
}
public void from(@NotNull ProcessingContext context) {
logicalLine = context.logicalLine;
logicalColumn = context.logicalColumn;
visualLine = context.visualLine;
visualColumn = context.visualColumn;
offset = context.offset;
softWrapLinesBefore = context.softWrapLinesBefore;
softWrapLinesCurrent = context.softWrapLinesCurrent;
softWrapColumnDiff = context.softWrapColumnDiff;
foldedLines = context.foldedLines;
foldingColumnDiff = context.foldingColumnDiff;
x = context.x;
symbol = context.symbol;
symbolWidthInColumns = context.symbolWidthInColumns;
symbolWidthInPixels = context.symbolWidthInPixels;
public void from(@NotNull EditorPosition position) {
logicalLine = position.logicalLine;
logicalColumn = position.logicalColumn;
visualLine = position.visualLine;
visualColumn = position.visualColumn;
offset = position.offset;
softWrapLinesBefore = position.softWrapLinesBefore;
softWrapLinesCurrent = position.softWrapLinesCurrent;
softWrapColumnDiff = position.softWrapColumnDiff;
foldedLines = position.foldedLines;
foldingColumnDiff = position.foldingColumnDiff;
x = position.x;
symbol = position.symbol;
symbolWidthInColumns = position.symbolWidthInColumns;
symbolWidthInPixels = position.symbolWidthInPixels;
}
@Override
protected ProcessingContext clone() {
ProcessingContext result = new ProcessingContext(myEditor, myRepresentationHelper);
protected EditorPosition clone() {
EditorPosition result = new EditorPosition(myEditor, myRepresentationHelper);
result.logicalLine = logicalLine;
result.logicalColumn = logicalColumn;
result.visualLine = visualLine;
@@ -90,7 +90,7 @@ class LogicalToVisualMappingStrategy extends AbstractMappingStrategy<VisualPosit
}
@Override
protected VisualPosition buildIfExceeds(ProcessingContext context, int offset) {
protected VisualPosition buildIfExceeds(EditorPosition context, int offset) {
if (context.logicalLine < myTargetLogical.line) {
return null;
}
@@ -106,7 +106,7 @@ class LogicalToVisualMappingStrategy extends AbstractMappingStrategy<VisualPosit
}
@Override
protected VisualPosition buildIfExceeds(@NotNull ProcessingContext context, @NotNull FoldRegion foldRegion) {
protected VisualPosition buildIfExceeds(@NotNull EditorPosition context, @NotNull FoldRegion foldRegion) {
int foldEndLine = myEditor.getDocument().getLineNumber(foldRegion.getEndOffset());
if (myTargetLogical.line > foldEndLine) {
return null;
@@ -132,7 +132,7 @@ class LogicalToVisualMappingStrategy extends AbstractMappingStrategy<VisualPosit
}
@Override
protected VisualPosition buildIfExceeds(ProcessingContext context, TabData tabData) {
protected VisualPosition buildIfExceeds(EditorPosition context, TabData tabData) {
if (context.logicalLine < myTargetLogical.line) {
return null;
}
@@ -149,23 +149,23 @@ class LogicalToVisualMappingStrategy extends AbstractMappingStrategy<VisualPosit
}
@Override
public VisualPosition processSoftWrap(ProcessingContext context, SoftWrap softWrap) {
context.visualColumn = softWrap.getIndentInColumns();
context.softWrapColumnDiff += softWrap.getIndentInColumns();
public VisualPosition processSoftWrap(EditorPosition position, SoftWrap softWrap) {
position.visualColumn = softWrap.getIndentInColumns();
position.softWrapColumnDiff += softWrap.getIndentInColumns();
if (context.logicalLine < myTargetLogical.line || context.logicalColumn != myTargetLogical.column) {
if (position.logicalLine < myTargetLogical.line || position.logicalColumn != myTargetLogical.column) {
return null;
}
return context.buildVisualPosition();
return position.buildVisualPosition();
}
@NotNull
@Override
public VisualPosition build(ProcessingContext context) {
int diff = myTargetLogical.column - context.logicalColumn;
context.logicalColumn += diff;
context.visualColumn += diff;
context.offset += diff;
return context.buildVisualPosition();
public VisualPosition build(EditorPosition position) {
int diff = myTargetLogical.column - position.logicalColumn;
position.logicalColumn += diff;
position.visualColumn += diff;
position.offset += diff;
return position.buildVisualPosition();
}
}
@@ -36,29 +36,29 @@ interface MappingStrategy<T> {
T eagerMatch();
/**
* Builds initial context to start calculation from.
* Builds initial position to start calculation from.
* <p/>
* It's assumed that we store information about 'anchor' document positions like visual line starts and calculate
* target result starting from the nearest position.
*
* @return initial context to use for target result calculation
* @return initial position to use for target result calculation
*/
@NotNull
ProcessingContext buildInitialContext();
EditorPosition buildInitialPosition();
/**
* Notifies current strategy that there are no special symbols and regions between the document position identified
* by the current state of the given context and given offset. I.e. it's safe to assume that all symbols between the offset
* identified by the given context and given offset have occupy one visual and logical column.
* by the current state of the given position and given offset. I.e. it's safe to assume that all symbols between the offset
* identified by the given position and given offset have occupy one visual and logical column.
*
* @param context context that identifies currently processed position
* @param offset nearest offset to the one identified by the given context that conforms to requirement that every symbol
* @param position currently processed position
* @param offset nearest offset to the one identified by the given position that conforms to requirement that every symbol
* between them increments offset, visual and logical position by one
* @return resulting dimension if it's located between the document position identified by the given context
* @return resulting dimension if it's located between the given position
* and given offset if any; <code>null</code> otherwise
*/
@Nullable
T advance(ProcessingContext context, int offset);
T advance(EditorPosition position, int offset);
/**
* Notifies current strategy that soft wrap is encountered during the processing. There are two ways to continue the processing then:
@@ -69,12 +69,12 @@ interface MappingStrategy<T> {
* </ul>
* </pre>
*
* @param context current processing context
* @param position current processing position
* @param softWrap soft wrap encountered during the processing
* @return target document dimension if it's located within the bounds of the given soft wrap; <code>null</code> otherwise
*/
@Nullable
T processSoftWrap(ProcessingContext context, SoftWrap softWrap);
T processSoftWrap(EditorPosition position, SoftWrap softWrap);
/**
* Notifies current strategy that collapsed fold region is encountered during the processing. There are two ways to
@@ -86,13 +86,13 @@ interface MappingStrategy<T> {
* </ul>
* </pre>
*
* @param context current processing context
* @param position current processing position
* @param foldRegion collapsed fold region encountered during the processing
* @return target document dimension if it's located within the bounds of the given fold region;
* <code>null</code> otherwise
*/
@Nullable
T processFoldRegion(ProcessingContext context, FoldRegion foldRegion);
T processFoldRegion(EditorPosition position, FoldRegion foldRegion);
/**
* Notifies current strategy that tabulation symbols is encountered during the processing. Tabulation symbols
@@ -105,22 +105,22 @@ interface MappingStrategy<T> {
* </ul>
* </pre>
*
* @param context current processing context
* @param position current processing position
* @param tabData document position for the active tabulation symbol encountered during the processing
* @return target document dimension if it's located within the bounds of the given fold region;
* <code>null</code> otherwise
*/
@Nullable
T processTabulation(ProcessingContext context, TabData tabData);
T processTabulation(EditorPosition position, TabData tabData);
/**
* This method is assumed to be called when there are no special symbols between the document position identified by the
* given context and target dimension. E.g. this method may be called when we perform {@code visual -> logical} mapping
* given position and target dimension. E.g. this method may be called when we perform {@code visual -> logical} mapping
* and there are no soft wraps, collapsed fold regions and tabulation symbols on a current visual line.
*
* @param context current processing context that identifies active document position
* @return resulting dimension that is built on the basis of the given context and target anchor dimension
* @param position current processing position that identifies active document position
* @return resulting dimension that is built on the basis of the given position and target anchor dimension
*/
@NotNull
T build(ProcessingContext context);
T build(EditorPosition position);
}
@@ -76,7 +76,7 @@ class OffsetToLogicalCalculationStrategy extends AbstractMappingStrategy<Logical
}
@Override
protected LogicalPosition buildIfExceeds(ProcessingContext context, int offset) {
protected LogicalPosition buildIfExceeds(EditorPosition context, int offset) {
if (myTargetOffset > offset) {
return null;
}
@@ -97,7 +97,7 @@ class OffsetToLogicalCalculationStrategy extends AbstractMappingStrategy<Logical
}
@Override
protected LogicalPosition buildIfExceeds(@NotNull ProcessingContext context, @NotNull FoldRegion foldRegion) {
protected LogicalPosition buildIfExceeds(@NotNull EditorPosition context, @NotNull FoldRegion foldRegion) {
if (myTargetOffset >= foldRegion.getEndOffset()) {
return null;
}
@@ -131,7 +131,7 @@ class OffsetToLogicalCalculationStrategy extends AbstractMappingStrategy<Logical
@Nullable
@Override
protected LogicalPosition buildIfExceeds(ProcessingContext context, TabData tabData) {
protected LogicalPosition buildIfExceeds(EditorPosition context, TabData tabData) {
if (tabData.offset == myTargetOffset) {
return context.buildLogicalPosition();
}
@@ -140,26 +140,26 @@ class OffsetToLogicalCalculationStrategy extends AbstractMappingStrategy<Logical
@Nullable
@Override
public LogicalPosition processSoftWrap(ProcessingContext context, SoftWrap softWrap) {
context.visualColumn = softWrap.getIndentInColumns();
context.softWrapColumnDiff += softWrap.getIndentInColumns();
public LogicalPosition processSoftWrap(EditorPosition position, SoftWrap softWrap) {
position.visualColumn = softWrap.getIndentInColumns();
position.softWrapColumnDiff += softWrap.getIndentInColumns();
if (softWrap.getStart() == myTargetOffset) {
return context.buildLogicalPosition();
return position.buildLogicalPosition();
}
if (softWrap.getStart() == getCacheEntry().startOffset) {
return null;
}
assert false;
return context.buildLogicalPosition();
return position.buildLogicalPosition();
}
@NotNull
@Override
public LogicalPosition build(ProcessingContext context) {
int diff = myTargetOffset - context.offset;
context.logicalColumn += diff;
context.visualColumn += diff;
context.offset = myTargetOffset;
return context.buildLogicalPosition();
public LogicalPosition build(EditorPosition position) {
int diff = myTargetOffset - position.offset;
position.logicalColumn += diff;
position.visualColumn += diff;
position.offset = myTargetOffset;
return position.buildLogicalPosition();
}
}
@@ -37,7 +37,6 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@@ -191,20 +190,20 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen
TextAttributes attributes = iterationState.getMergedAttributes();
int fontType = attributes.getFontType();
ProcessingContext context = new ProcessingContext(logical, start, myEditor, myRepresentationHelper);
EditorPosition position = new EditorPosition(logical, start, myEditor, myRepresentationHelper);
Point point = myEditor.visualPositionToXY(visual);
context.x = point.x;
position.x = point.x;
int newX;
int spaceWidth = EditorUtil.getSpaceWidth(fontType, myEditor);
LogicalLineData logicalLineData = new LogicalLineData();
logicalLineData.update(logical.line, spaceWidth, myEditor);
ProcessingContext startLineContext = context.clone();
EditorPosition startLinePosition = position.clone();
JComponent contentComponent = myEditor.getContentComponent();
TIntIntHashMap fontType2spaceWidth = new TIntIntHashMap();
fontType2spaceWidth.put(fontType, spaceWidth);
int softWrapStartOffset = startLineContext.offset;
int softWrapStartOffset = startLinePosition.offset;
int reservedWidth = myPainter.getMinDrawingWidth(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
SoftWrap delayedSoftWrap = null;
@@ -216,19 +215,19 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen
if (currentFold != null) {
if (currentFold.getEndOffset() > document.getTextLength()) {
// There is a possible case that user just removed text that contained fold region and fold model is not updated yet
int startLineOffset = document.getLineStartOffset(context.logicalLine);
int startLineOffset = document.getLineStartOffset(position.logicalLine);
myDirtyRegions.add(new DirtyRegion(startLineOffset, document.getTextLength() - 1));
// We need to inform listeners about processing end.
context.offset = document.getTextLength() - 1;
context.symbol = document.getCharsSequence().charAt(context.offset);
notifyListenersOnProcessedSymbol(context);
position.offset = document.getTextLength() - 1;
position.symbol = document.getCharsSequence().charAt(position.offset);
notifyListenersOnProcessedSymbol(position);
return;
}
String placeholder = currentFold.getPlaceholderText();
FontInfo fontInfo = EditorUtil.fontForChar(placeholder.charAt(0), fontType, myEditor);
newX = context.x;
newX = position.x;
for (int i = 0; i < placeholder.length(); i++) {
newX += fontInfo.charWidth(placeholder.charAt(i), contentComponent);
}
@@ -238,50 +237,50 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen
assert softWrap != null; // We expect that it's always possible to wrap collapsed fold region placeholder text
softWrapStartOffset = softWrap.getStart();
if (softWrap.getStart() < start) {
revertListeners(softWrap.getStart(), context.visualLine);
revertListeners(softWrap.getStart(), position.visualLine);
for (int j = currentFold.getStartOffset() - 1; j >= softWrap.getStart(); j--) {
int pixelsDiff = myOffset2widthInPixels.data[j - myOffset2widthInPixels.anchor];
int tmpFontType = myOffset2fontType.data[j - myOffset2fontType.anchor];
int columnsDiff = calculateWidthInColumns(text.charAt(j), pixelsDiff, fontType2spaceWidth.get(tmpFontType));
context.offset--;
context.logicalColumn -= columnsDiff;
context.visualColumn -= columnsDiff;
position.offset--;
position.logicalColumn -= columnsDiff;
position.visualColumn -= columnsDiff;
}
notifyListenersOnBeforeSoftWrap(context);
notifyListenersOnBeforeSoftWrap(position);
}
context.visualColumn = 0;
context.softWrapColumnDiff = context.visualColumn - context.foldingColumnDiff - context.logicalColumn;
context.softWrapLinesCurrent++;
context.visualLine++;
notifyListenersOnAfterSoftWrapLineFeed(context);
position.visualColumn = 0;
position.softWrapColumnDiff = position.visualColumn - position.foldingColumnDiff - position.logicalColumn;
position.softWrapLinesCurrent++;
position.visualLine++;
notifyListenersOnAfterSoftWrapLineFeed(position);
context.x = softWrap.getIndentInPixels();
context.visualColumn = softWrap.getIndentInColumns();
context.softWrapColumnDiff += softWrap.getIndentInColumns();
startLineContext.from(context);
position.x = softWrap.getIndentInPixels();
position.visualColumn = softWrap.getIndentInColumns();
position.softWrapColumnDiff += softWrap.getIndentInColumns();
startLinePosition.from(position);
for (int j = softWrap.getStart(); j < start; j++) {
fontType = myOffset2fontType.data[j - myOffset2fontType.anchor];
newX = calculateNewX(context, fontType, contentComponent);
processSymbol(context, startLineContext, logicalLineData, fontType, newX, fontType2spaceWidth);
newX = calculateNewX(position, fontType, contentComponent);
processSymbol(position, startLinePosition, logicalLineData, fontType, newX, fontType2spaceWidth);
}
myOffset2fontType.clear();
myOffset2widthInPixels.clear();
continue;
}
else {
int visualLineBefore = context.visualLine;
int logicalColumnBefore = context.logicalColumn;
context.advance(currentFold);
context.x = newX;
int collapsedFoldingWidthInColumns = context.logicalColumn;
if (context.visualLine <= visualLineBefore) {
int visualLineBefore = position.visualLine;
int logicalColumnBefore = position.logicalColumn;
position.advance(currentFold);
position.x = newX;
int collapsedFoldingWidthInColumns = position.logicalColumn;
if (position.visualLine <= visualLineBefore) {
// Single-line fold region.
collapsedFoldingWidthInColumns = context.logicalColumn - logicalColumnBefore;
collapsedFoldingWidthInColumns = position.logicalColumn - logicalColumnBefore;
}
notifyListenersOnFoldRegion(currentFold, collapsedFoldingWidthInColumns, visualLineBefore);
start = context.offset;
start = position.offset;
softWrapStartOffset = currentFold.getEndOffset();
}
myOffset2fontType.clear();
@@ -301,28 +300,28 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen
if (myOffset2fontType.anchor + myOffset2fontType.end > i) {
fontType = myOffset2fontType.data[i - myOffset2fontType.anchor];
}
context.symbol = c;
position.symbol = c;
if (delayedSoftWrap != null && delayedSoftWrap.getStart() == i) {
processSoftWrap(delayedSoftWrap, context);
processSoftWrap(delayedSoftWrap, position);
softWrapStartOffset = delayedSoftWrap.getStart();
startLineContext.from(context);
startLinePosition.from(position);
delayedSoftWrap = null;
}
if (c == '\n') {
processSymbol(context, startLineContext, logicalLineData, fontType, 0, fontType2spaceWidth);
softWrapStartOffset = startLineContext.offset;
processSymbol(position, startLinePosition, logicalLineData, fontType, 0, fontType2spaceWidth);
softWrapStartOffset = startLinePosition.offset;
continue;
}
if (myOffset2widthInPixels.end > context.offset && (myOffset2widthInPixels.anchor + myOffset2widthInPixels.end > context.offset)
&& context.symbol != '\t'/*we need to recalculate tabulation width after soft wrap*/)
if (myOffset2widthInPixels.end > position.offset && (myOffset2widthInPixels.anchor + myOffset2widthInPixels.end > position.offset)
&& position.symbol != '\t'/*we need to recalculate tabulation width after soft wrap*/)
{
newX = context.x + myOffset2widthInPixels.data[context.offset - myOffset2widthInPixels.anchor];
newX = position.x + myOffset2widthInPixels.data[position.offset - myOffset2widthInPixels.anchor];
}
else {
newX = calculateNewX(context, fontType, contentComponent);
newX = calculateNewX(position, fontType, contentComponent);
}
if (newX + reservedWidth >= myVisibleAreaWidth && delayedSoftWrap == null) {
@@ -332,7 +331,7 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen
calculateSoftWrapEndOffset(softWrapStartOffset, logicalLineData.endLineOffset), spaceWidth, logicalLineData
);
if (softWrap == null) {
processSymbol(context, startLineContext, logicalLineData, fontType, newX, fontType2spaceWidth);
processSymbol(position, startLinePosition, logicalLineData, fontType, newX, fontType2spaceWidth);
continue;
}
int newI = softWrap.getStart();
@@ -345,38 +344,38 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen
// We should process that accordingly.
if (newI > end) {
delayedSoftWrap = softWrap;
processSymbol(context, startLineContext, logicalLineData, fontType, newX, fontType2spaceWidth);
processSymbol(position, startLinePosition, logicalLineData, fontType, newX, fontType2spaceWidth);
continue;
}
else if (newI < i) {
revertListeners(newI, context.visualLine);
revertListeners(newI, position.visualLine);
for (int j = i - 1; j >= newI; j--) {
int pixelsDiff = myOffset2widthInPixels.data[j - myOffset2widthInPixels.anchor];
int tmpFontType = myOffset2fontType.data[j - myOffset2fontType.anchor];
int columnsDiff = calculateWidthInColumns(text.charAt(j), pixelsDiff, fontType2spaceWidth.get(tmpFontType));
context.offset--;
context.logicalColumn -= columnsDiff;
context.visualColumn -= columnsDiff;
position.offset--;
position.logicalColumn -= columnsDiff;
position.visualColumn -= columnsDiff;
}
}
else if (newI > i) {
processSymbol(context, startLineContext, logicalLineData, fontType, newX, fontType2spaceWidth);
processSymbol(position, startLinePosition, logicalLineData, fontType, newX, fontType2spaceWidth);
for (int j = i + 1; j < newI; j++) {
context.symbol = text.charAt(j);
newX = calculateNewX(context, fontType, contentComponent);
processSymbol(context, startLineContext, logicalLineData, fontType, newX, fontType2spaceWidth);
position.symbol = text.charAt(j);
newX = calculateNewX(position, fontType, contentComponent);
processSymbol(position, startLinePosition, logicalLineData, fontType, newX, fontType2spaceWidth);
}
}
processSoftWrap(softWrap, context);
processSoftWrap(softWrap, position);
softWrapStartOffset = newI;
i = newI - 1/* because of loop increment */;
startLineContext.from(context);
startLinePosition.from(position);
myOffset2fontType.clear();
myOffset2widthInPixels.clear();
}
else {
processSymbol(context, startLineContext, logicalLineData, fontType, newX, fontType2spaceWidth);
processSymbol(position, startLinePosition, logicalLineData, fontType, newX, fontType2spaceWidth);
}
}
@@ -453,13 +452,13 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen
myOffset2fontType.end = end - myOffset2fontType.anchor;
}
private int calculateNewX(ProcessingContext context, int fontType, JComponent component) {
if (context.symbol == '\t') {
return EditorUtil.nextTabStop(context.x, myEditor);
private int calculateNewX(EditorPosition position, int fontType, JComponent component) {
if (position.symbol == '\t') {
return EditorUtil.nextTabStop(position.x, myEditor);
}
else {
FontInfo fontInfo = EditorUtil.fontForChar(context.symbol, fontType, myEditor);
return context.x + fontInfo.charWidth(context.symbol, component);
FontInfo fontInfo = EditorUtil.fontForChar(position.symbol, fontType, myEditor);
return position.x + fontInfo.charWidth(position.symbol, component);
}
}
@@ -474,7 +473,7 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen
return end;
}
private void processSymbol(ProcessingContext context, ProcessingContext startLineContext, LogicalLineData logicalLineData,
private void processSymbol(EditorPosition position, EditorPosition startLineContext, LogicalLineData logicalLineData,
int fontType, int newX, TIntIntHashMap fontType2spaceWidth)
{
int spaceWidth;
@@ -486,40 +485,40 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen
fontType2spaceWidth.put(fontType, spaceWidth);
}
if (context.symbol == '\n') {
context.symbolWidthInColumns = 0;
context.symbolWidthInPixels = 0;
notifyListenersOnProcessedSymbol(context);
context.offset++;
context.onNewLine();
if (position.symbol == '\n') {
position.symbolWidthInColumns = 0;
position.symbolWidthInPixels = 0;
notifyListenersOnProcessedSymbol(position);
position.offset++;
position.onNewLine();
myOffset2fontType.clear();
myOffset2widthInPixels.clear();
//clear(offset2fontType);
//clear(offset2widthInPixels);
startLineContext.from(context);
logicalLineData.update(context.logicalLine, spaceWidth, myEditor);
context.x = 0;
startLineContext.from(position);
logicalLineData.update(position.logicalLine, spaceWidth, myEditor);
position.x = 0;
return;
}
context.symbolWidthInPixels = newX - context.x;
context.symbolWidthInColumns = calculateWidthInColumns(context.symbol, context.symbolWidthInPixels, spaceWidth);
notifyListenersOnProcessedSymbol(context);
context.visualColumn += context.symbolWidthInColumns;
context.logicalColumn += context.symbolWidthInColumns;
context.x = newX;
position.symbolWidthInPixels = newX - position.x;
position.symbolWidthInColumns = calculateWidthInColumns(position.symbol, position.symbolWidthInPixels, spaceWidth);
notifyListenersOnProcessedSymbol(position);
position.visualColumn += position.symbolWidthInColumns;
position.logicalColumn += position.symbolWidthInColumns;
position.x = newX;
if (myOffset2widthInPixels.anchor <= 0) {
myOffset2widthInPixels.anchor = context.offset;
myOffset2widthInPixels.anchor = position.offset;
}
if (context.offset - myOffset2widthInPixels.anchor >= myOffset2widthInPixels.data.length) {
if (position.offset - myOffset2widthInPixels.anchor >= myOffset2widthInPixels.data.length) {
int[] newData = new int[myOffset2widthInPixels.data.length * 2];
System.arraycopy(myOffset2widthInPixels.data, 0, newData, 0, myOffset2widthInPixels.data.length);
myOffset2widthInPixels.data = newData;
}
myOffset2widthInPixels.data[context.offset - myOffset2widthInPixels.anchor] = context.symbolWidthInPixels;
myOffset2widthInPixels.data[position.offset - myOffset2widthInPixels.anchor] = position.symbolWidthInPixels;
myOffset2widthInPixels.end++;
context.offset++;
position.offset++;
}
private static int calculateWidthInColumns(char c, int widthInPixels, int spaceWithInPixels) {
@@ -578,18 +577,18 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen
return softWrap;
}
private void processSoftWrap(SoftWrap softWrap, ProcessingContext context) {
notifyListenersOnBeforeSoftWrap(context);
private void processSoftWrap(SoftWrap softWrap, EditorPosition position) {
notifyListenersOnBeforeSoftWrap(position);
context.visualColumn = 0;
context.softWrapColumnDiff = context.visualColumn - context.foldingColumnDiff - context.logicalColumn;
context.softWrapLinesCurrent++;
context.visualLine++;
notifyListenersOnAfterSoftWrapLineFeed(context);
position.visualColumn = 0;
position.softWrapColumnDiff = position.visualColumn - position.foldingColumnDiff - position.logicalColumn;
position.softWrapLinesCurrent++;
position.visualLine++;
notifyListenersOnAfterSoftWrapLineFeed(position);
context.x = softWrap.getIndentInPixels();
context.visualColumn = softWrap.getIndentInColumns();
context.softWrapColumnDiff += softWrap.getIndentInColumns();
position.x = softWrap.getIndentInPixels();
position.visualColumn = softWrap.getIndentInColumns();
position.softWrapColumnDiff += softWrap.getIndentInColumns();
}
public void recalculateIfNecessary() {
@@ -667,29 +666,29 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen
}
@SuppressWarnings({"ForLoopReplaceableByForEach"})
private void notifyListenersOnProcessedSymbol(@NotNull ProcessingContext context) {
private void notifyListenersOnProcessedSymbol(@NotNull EditorPosition position) {
for (int i = 0; i < myListeners.size(); i++) {
// Avoid unnecessary Iterator object construction as this method is expected to be called frequently.
SoftWrapAwareDocumentParsingListener listener = myListeners.get(i);
listener.onProcessedSymbol(context);
listener.onProcessedSymbol(position);
}
}
@SuppressWarnings({"ForLoopReplaceableByForEach"})
private void notifyListenersOnBeforeSoftWrap(@NotNull ProcessingContext context) {
private void notifyListenersOnBeforeSoftWrap(@NotNull EditorPosition position) {
for (int i = 0; i < myListeners.size(); i++) {
// Avoid unnecessary Iterator object construction as this method is expected to be called frequently.
SoftWrapAwareDocumentParsingListener listener = myListeners.get(i);
listener.beforeSoftWrap(context);
listener.beforeSoftWrap(position);
}
}
@SuppressWarnings({"ForLoopReplaceableByForEach"})
private void notifyListenersOnAfterSoftWrapLineFeed(@NotNull ProcessingContext context) {
private void notifyListenersOnAfterSoftWrapLineFeed(@NotNull EditorPosition position) {
for (int i = 0; i < myListeners.size(); i++) {
// Avoid unnecessary Iterator object construction as this method is expected to be called frequently.
SoftWrapAwareDocumentParsingListener listener = myListeners.get(i);
listener.afterSoftWrapLineFeed(context);
listener.afterSoftWrapLineFeed(position);
}
}
@@ -34,11 +34,11 @@ interface SoftWrapAwareDocumentParsingListener {
/**
* Notifies about processed symbol. Please note that given context points to the end of line (not to the start of the new line) if
* {@link ProcessingContext#symbol processed symbol} is line feed.
* {@link EditorPosition#symbol processed symbol} is line feed.
*
* @param context context that points to the {@link ProcessingContext#symbol processed symbol}
* @param context context that points to the {@link EditorPosition#symbol processed symbol}
*/
void onProcessedSymbol(@NotNull ProcessingContext context);
void onProcessedSymbol(@NotNull EditorPosition context);
/**
* Notifies about processed fold region.
@@ -54,14 +54,14 @@ interface SoftWrapAwareDocumentParsingListener {
*
* @param context context that points to document position just before soft wrap
*/
void beforeSoftWrap(@NotNull ProcessingContext context);
void beforeSoftWrap(@NotNull EditorPosition context);
/**
* Notifies about soft wrap-introduced line feed.
*
* @param context context that points to document position just after soft wrap-introduced line feed
*/
void afterSoftWrapLineFeed(@NotNull ProcessingContext context);
void afterSoftWrapLineFeed(@NotNull EditorPosition context);
/**
* There is a possible case that document parser steps back to particular offset, i.e. it may encounter a situation
@@ -83,7 +83,7 @@ interface SoftWrapAwareDocumentParsingListener {
* <pre>
* <ul>
* <li>{@link #onRecalculationStart(int, int)};</li>
* <li>number of calls like {@link #onProcessedSymbol(ProcessingContext)}, {@link #onCollapsedFoldRegion(FoldRegion, int, int)} etc;</li>
* <li>number of calls like {@link #onProcessedSymbol(EditorPosition)}, {@link #onCollapsedFoldRegion(FoldRegion, int, int)} etc;</li>
* <li>{@link #onRecalculationEnd(int, int)};</li>
* </ul>
* </pre>
@@ -15,7 +15,6 @@
*/
package com.intellij.openapi.editor.impl.softwrap.mapping;
import com.intellij.ui.TabbedPaneWrapper;
import org.jetbrains.annotations.NotNull;
/**
@@ -27,7 +26,7 @@ class TabData implements Cloneable {
public final int widthInColumns;
public int offset;
TabData(@NotNull ProcessingContext context) {
TabData(@NotNull EditorPosition context) {
widthInColumns = context.symbolWidthInColumns;
offset = context.offset;
}
@@ -523,7 +523,7 @@ public class CachingSoftWrapDataMapperTest {
@SuppressWarnings({"AssignmentToForLoopParameter"})
private void init(final String documentText) {
final TestProcessingContext context = new TestProcessingContext();
final TestEditorPosition context = new TestEditorPosition();
myMockery.checking(new Expectations() {{
allowing(myDocument).getCharsSequence(); will(new CustomAction("getCharsSequence()") {
@Override
@@ -627,7 +627,7 @@ public class CachingSoftWrapDataMapperTest {
}
}
private class TestProcessingContext extends ProcessingContext {
private class TestEditorPosition extends EditorPosition {
private final StringBuilder mySoftWrapBuffer = new StringBuilder();
final StringBuilder document = new StringBuilder();
@@ -643,7 +643,7 @@ public class CachingSoftWrapDataMapperTest {
int foldingStartVisualColumn;
int foldingStartX;
TestProcessingContext() {
TestEditorPosition() {
super(myEditor, myRepresentationHelper);
}