diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CachingSoftWrapDataMapper.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CachingSoftWrapDataMapper.java index db4a4efd72c3..ea0d171231b7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CachingSoftWrapDataMapper.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CachingSoftWrapDataMapper.java @@ -256,9 +256,9 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw if (documentLength > 0 && context.offset >= documentLength - 1 && context.symbol != '\n') { // Update information about end position of the last visual line. CacheEntry cacheEntry = getCacheEntryForVisualLine(context.visualLine); - cacheEntry.endLogicalColumn = context.logicalColumn + context.symbolWidthInColumns - 1; // -1 because the first context's - // column already points to the symbol - cacheEntry.endVisualColumn = context.visualColumn + context.symbolWidthInColumns - 1; + cacheEntry.endLogicalColumn += context.symbolWidthInColumns; + cacheEntry.endVisualColumn += context.symbolWidthInColumns; + cacheEntry.endOffset++; } } @@ -424,6 +424,20 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw myNotAffectedByUpdateTailCacheEntries.clear(); myNotAffectedByUpdateTailCacheEntries.addAll(myCache.subList(myBeforeChangeState.endCacheEntryIndex + 1, myCache.size())); + + // There is a possible case that the change is non-line feed symbol insertion to the document's end and its previous symbol + // is line feed. E.g.: + // line1 + // line2 + // + // We stored cache entry that corresponds to offset just before the previous last symbol (line feed). However, last symbol is + // not line feed now, hence, we need to remove corresponding virtual cache entry. + int textLength = myEditor.getDocument().getTextLength(); + if (endOffset >= textLength && !myNotAffectedByUpdateTailCacheEntries.isEmpty() + && myNotAffectedByUpdateTailCacheEntries.get(myNotAffectedByUpdateTailCacheEntries.size() - 1).startOffset >= textLength) + { + myNotAffectedByUpdateTailCacheEntries.remove(myNotAffectedByUpdateTailCacheEntries.size() - 1); + } myCache.subList(myBeforeChangeState.startCacheEntryIndex + 1, myCache.size()).clear(); for (CacheEntry entry : myNotAffectedByUpdateTailCacheEntries) { entry.locked = true; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/MappingUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/MappingUtil.java index af9e65b042a8..2b38aeddfdbe 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/MappingUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/MappingUtil.java @@ -41,7 +41,7 @@ public class MappingUtil { * -1 if it's not possible to perform such mapping */ public static int getCacheEntryIndexForOffset(int offset, Document document, List cache) { - if (offset >= document.getTextLength()) { + if (offset >= document.getTextLength() && (cache.isEmpty() || cache.get(cache.size() - 1).endOffset < offset)) { if (cache.isEmpty()) { return -1; } diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java index 3027e2fc8f57..3347c2bc15e4 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java @@ -158,6 +158,22 @@ public class SoftWrapApplianceOnDocumentModificationTest extends LightPlatformCo // Don't expect any exceptions here. } + public void testTypeNewLastLineAndSymbolOnIt() throws IOException { + // Inspired by IDEA-59439 + String text = + "This is a test document\n" + + "line1\n" + + "line2\n" + + "line3\n" + + "line4\n" + + "line5\n" + + "line6"; + + init(700, text); + type("\nq"); + assertEquals(new VisualPosition(7, 1), myEditor.offsetToVisualPosition(myEditor.getDocument().getTextLength())); + } + //private void init(final int visibleWidth) throws Exception { // configureByFile(PATH + getFileName()); // initCommon(visibleWidth);