From 2a792bfeabe0c6f3c71d15c1f90308caeca8042d Mon Sep 17 00:00:00 2001 From: Denis Zhdanov Date: Fri, 3 Jun 2011 18:09:47 +0400 Subject: [PATCH] IDEA-70602 Soft wrap in xml files: lines after long line are wrapped though they are not too long --- ...iAwareDefaultLineWrapPositionStrategy.java | 11 ++++---- .../PsiAwareLineWrapPositionStrategy.java | 28 +++++++++++++------ .../editorActions/AutoHardWrapHandler.java | 2 +- .../source/codeStyle/CodeFormatterFacade.java | 2 +- .../openapi/editor/EditorSettings.java | 2 ++ .../GenericLineWrapPositionStrategy.java | 3 +- .../editor/LineWrapPositionStrategy.java | 3 +- .../DefaultLineWrapPositionStrategyTest.java | 3 +- .../openapi/editor/impl/SettingsImpl.java | 19 ++++++++++--- .../mapping/SoftWrapApplianceManager.java | 17 ++++++----- ...apApplianceOnDocumentModificationTest.java | 16 +++++++++++ .../MarkupLineWrapPositionStrategy.java | 2 +- 12 files changed, 78 insertions(+), 30 deletions(-) diff --git a/platform/lang-api/src/com/intellij/openapi/editor/PsiAwareDefaultLineWrapPositionStrategy.java b/platform/lang-api/src/com/intellij/openapi/editor/PsiAwareDefaultLineWrapPositionStrategy.java index f10ddc670f76..47462ad878c7 100644 --- a/platform/lang-api/src/com/intellij/openapi/editor/PsiAwareDefaultLineWrapPositionStrategy.java +++ b/platform/lang-api/src/com/intellij/openapi/editor/PsiAwareDefaultLineWrapPositionStrategy.java @@ -23,15 +23,15 @@ import org.jetbrains.annotations.Nullable; /** * {@link LineWrapPositionStrategy} implementation that uses * {@link LanguageLineWrapPositionStrategy#getDefaultImplementation() default line wrap strategy} but restricts its scope - * by {@link #PsiAwareDefaultLineWrapPositionStrategy(IElementType...) target tokens/elements}. + * by {@link #PsiAwareDefaultLineWrapPositionStrategy(boolean, IElementType...) target tokens/elements}. * * @author Denis Zhdanov * @since 5/12/11 12:50 PM */ public class PsiAwareDefaultLineWrapPositionStrategy extends PsiAwareLineWrapPositionStrategy { - public PsiAwareDefaultLineWrapPositionStrategy(@NotNull IElementType ... enabledTypes) { - super(enabledTypes); + public PsiAwareDefaultLineWrapPositionStrategy(boolean nonVirtualOnly, @NotNull IElementType ... enabledTypes) { + super(nonVirtualOnly, enabledTypes); } @Override @@ -40,10 +40,11 @@ public class PsiAwareDefaultLineWrapPositionStrategy extends PsiAwareLineWrapPos int startOffset, int endOffset, int maxPreferredOffset, - boolean allowToBeyondMaxPreferredOffset) + boolean allowToBeyondMaxPreferredOffset, + boolean virtual) { LineWrapPositionStrategy implementation = LanguageLineWrapPositionStrategy.INSTANCE.getDefaultImplementation(); return implementation.calculateWrapPosition(document, project, startOffset, endOffset, maxPreferredOffset, - allowToBeyondMaxPreferredOffset); + allowToBeyondMaxPreferredOffset, virtual); } } diff --git a/platform/lang-api/src/com/intellij/openapi/editor/PsiAwareLineWrapPositionStrategy.java b/platform/lang-api/src/com/intellij/openapi/editor/PsiAwareLineWrapPositionStrategy.java index 3daa6e646cd8..a59da3c70e69 100644 --- a/platform/lang-api/src/com/intellij/openapi/editor/PsiAwareLineWrapPositionStrategy.java +++ b/platform/lang-api/src/com/intellij/openapi/editor/PsiAwareLineWrapPositionStrategy.java @@ -39,14 +39,17 @@ public abstract class PsiAwareLineWrapPositionStrategy implements LineWrapPositi private static final Logger LOG = Logger.getInstance("#" + PsiAwareLineWrapPositionStrategy.class.getName()); private final TokenSet myEnabledTypes; + private final boolean myNonVirtualOnly; /** * Creates new PsiAwareLineWrapPositionStrategy object. * + * @param nonVirtualOnly defines if current PSI-aware logic should be exploited only for 'real wrap' position requests * @param enabledTypes target element/token types where line wrapping is allowed */ - public PsiAwareLineWrapPositionStrategy(@NotNull IElementType ... enabledTypes) { + public PsiAwareLineWrapPositionStrategy(boolean nonVirtualOnly, @NotNull IElementType ... enabledTypes) { myEnabledTypes = TokenSet.create(enabledTypes); + myNonVirtualOnly = nonVirtualOnly; if (enabledTypes.length <= 0) { LOG.warn(String.format("%s instance is created with empty token/element types. That will lead to inability to perform line wrap", getClass().getName())); @@ -59,11 +62,19 @@ public abstract class PsiAwareLineWrapPositionStrategy implements LineWrapPositi int startOffset, int endOffset, int maxPreferredOffset, - boolean allowToBeyondMaxPreferredOffset) { + boolean allowToBeyondMaxPreferredOffset, + boolean virtual) { + if (virtual && myNonVirtualOnly) { + LineWrapPositionStrategy implementation = LanguageLineWrapPositionStrategy.INSTANCE.getDefaultImplementation(); + return implementation.calculateWrapPosition( + document, project, startOffset, endOffset, maxPreferredOffset, allowToBeyondMaxPreferredOffset, virtual + ); + } + if (project == null) { return -1; } - + PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); if (documentManager == null) { return -1; @@ -84,7 +95,7 @@ public abstract class PsiAwareLineWrapPositionStrategy implements LineWrapPositi TextRange textRange = element.getTextRange(); int start = Math.max(textRange.getStartOffset(), startOffset); int end = Math.min(textRange.getEndOffset(), endOffset); - int result = doCalculateWrapPosition(document, project, start, end, end, false); + int result = doCalculateWrapPosition(document, project, start, end, end, false, virtual); if (result >= 0) { return result; } @@ -96,15 +107,15 @@ public abstract class PsiAwareLineWrapPositionStrategy implements LineWrapPositi if (start > startOffset) { return start; - } + } } } return -1; } /** - * Serves for the same purposes as {@link #calculateWrapPosition(Document, Project, int, int, int, boolean)} but ensures that given - * offsets target {@link #PsiAwareLineWrapPositionStrategy(IElementType...) enabled token/element types}. + * Serves for the same purposes as {@link #calculateWrapPosition(Document, Project, int, int, int, boolean, boolean)} but ensures + * that given offsets target {@link #PsiAwareLineWrapPositionStrategy(boolean, IElementType...) enabled token/element types}. * * @param document target document which text is being processed * @param project target project @@ -117,12 +128,13 @@ public abstract class PsiAwareLineWrapPositionStrategy implements LineWrapPositi * @param allowToBeyondMaxPreferredOffset indicates if it's allowed to return value from * (maxPreferredOffset; endOffset] interval in case of inability to * find appropriate offset from (startOffset; maxPreferredOffset] interval + * @param virtual identifies if current request is for virtual wrap (soft wrap) position * @return offset from (startOffset; endOffset] interval where * target line should be wrapped OR -1 if no wrapping should be performed */ protected abstract int doCalculateWrapPosition( @NotNull Document document, @Nullable Project project, int startOffset, int endOffset, int maxPreferredOffset, - boolean allowToBeyondMaxPreferredOffset + boolean allowToBeyondMaxPreferredOffset, boolean virtual ); /** diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java index 656992640479..6fe03bbcde46 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/AutoHardWrapHandler.java @@ -150,7 +150,7 @@ public class AutoHardWrapHandler { new VisualPosition(caretModel.getVisualPosition().line, margin - FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS) )); - int wrapOffset = strategy.calculateWrapPosition(document, project, startOffset, endOffset, maxPreferredOffset, true); + int wrapOffset = strategy.calculateWrapPosition(document, project, startOffset, endOffset, maxPreferredOffset, true, false); if (wrapOffset < 0) { return; } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java index 4841db5a70c1..8b99608be6de 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java @@ -381,7 +381,7 @@ public class CodeFormatterFacade { // We know that current line exceeds right margin if control flow reaches this place, so, wrap it. int wrapOffset = strategy.calculateWrapPosition( document, editor.getProject(), Math.max(startLineOffset, startOffsetToUse), Math.min(endLineOffset, endOffsetToUse), - preferredWrapPosition, false + preferredWrapPosition, false, false ); if (wrapOffset < 0) { continue; diff --git a/platform/platform-api/src/com/intellij/openapi/editor/EditorSettings.java b/platform/platform-api/src/com/intellij/openapi/editor/EditorSettings.java index 21757e3af59f..d39cad7af87c 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/EditorSettings.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/EditorSettings.java @@ -104,7 +104,9 @@ public interface EditorSettings { void setUseSoftWraps(boolean use); boolean isAllSoftWrapsShown(); boolean isUseCustomSoftWrapIndent(); + void setUseCustomSoftWrapIndent(boolean useCustomSoftWrapIndent); int getCustomSoftWrapIndent(); + void setCustomSoftWrapIndent(int indent); boolean isAllowSingleLogicalLineFolding(); void setAllowSingleLogicalLineFolding(boolean allow); diff --git a/platform/platform-api/src/com/intellij/openapi/editor/GenericLineWrapPositionStrategy.java b/platform/platform-api/src/com/intellij/openapi/editor/GenericLineWrapPositionStrategy.java index 93289b0caddd..a3d5988effc3 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/GenericLineWrapPositionStrategy.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/GenericLineWrapPositionStrategy.java @@ -48,7 +48,8 @@ public class GenericLineWrapPositionStrategy implements LineWrapPositionStrategy int startOffset, int endOffset, int maxPreferredOffset, - boolean allowToBeyondMaxPreferredOffset) + boolean allowToBeyondMaxPreferredOffset, + boolean virtual) { if (endOffset <= startOffset) { return endOffset; diff --git a/platform/platform-api/src/com/intellij/openapi/editor/LineWrapPositionStrategy.java b/platform/platform-api/src/com/intellij/openapi/editor/LineWrapPositionStrategy.java index 958db895b793..2e13a3fb8f09 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/LineWrapPositionStrategy.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/LineWrapPositionStrategy.java @@ -45,11 +45,12 @@ public interface LineWrapPositionStrategy { * @param allowToBeyondMaxPreferredOffset indicates if it's allowed to return value from * (maxPreferredOffset; endOffset] interval in case of inability to * find appropriate offset from (startOffset; maxPreferredOffset] interval + * @param virtual identifies if current request is for virtual wrap (soft wrap) position * @return offset from (startOffset; endOffset] interval where * target line should be wrapped OR -1 if no wrapping should be performed */ int calculateWrapPosition( @NotNull Document document, @Nullable Project project, int startOffset, int endOffset, int maxPreferredOffset, - boolean allowToBeyondMaxPreferredOffset + boolean allowToBeyondMaxPreferredOffset, boolean virtual ); } diff --git a/platform/platform-api/testSrc/com/intellij/openapi/editor/DefaultLineWrapPositionStrategyTest.java b/platform/platform-api/testSrc/com/intellij/openapi/editor/DefaultLineWrapPositionStrategyTest.java index 8d5ba9fa4e19..a4b8ddf29bab 100644 --- a/platform/platform-api/testSrc/com/intellij/openapi/editor/DefaultLineWrapPositionStrategyTest.java +++ b/platform/platform-api/testSrc/com/intellij/openapi/editor/DefaultLineWrapPositionStrategyTest.java @@ -85,7 +85,8 @@ public class DefaultLineWrapPositionStrategyTest { final Context context = new Context(document); context.init(); int actual = myStrategy.calculateWrapPosition( - createMockDocument(context.document), myProject, 0, context.document.length(), context.edgeIndex, allowToBeyondMaxPreferredOffset + createMockDocument(context.document), myProject, 0, context.document.length(), context.edgeIndex, + allowToBeyondMaxPreferredOffset, true ); assertSame(context.wrapIndex, actual); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SettingsImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SettingsImpl.java index e00b6928ebaf..ae5672dd1f95 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SettingsImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SettingsImpl.java @@ -77,6 +77,8 @@ public class SettingsImpl implements EditorSettings { private Boolean myIsRefrainFromScrolling = null; private Boolean myUseSoftWraps = null; private Boolean myIsAllSoftWrapsShown = null; + private Boolean myUseCustomSoftWrapIndent = null; + private Integer myCustomSoftWrapIndent = null; public boolean isRightMarginShown() { return myIsRightMarginShown != null @@ -206,8 +208,6 @@ public class SettingsImpl implements EditorSettings { public void reinitSettings() { myCachedTabSize = null; - //TODO den check - //myUseSoftWraps = null; } public int getTabSize(Project project) { @@ -419,12 +419,23 @@ public class SettingsImpl implements EditorSettings { @Override public boolean isUseCustomSoftWrapIndent() { - return EditorSettingsExternalizable.getInstance().isUseCustomSoftWrapIndent(); + return myUseCustomSoftWrapIndent == null ? EditorSettingsExternalizable.getInstance().isUseCustomSoftWrapIndent() + : myUseCustomSoftWrapIndent; + } + + @Override + public void setUseCustomSoftWrapIndent(boolean useCustomSoftWrapIndent) { + myUseCustomSoftWrapIndent = useCustomSoftWrapIndent; } @Override public int getCustomSoftWrapIndent() { - return EditorSettingsExternalizable.getInstance().getCustomSoftWrapIndent(); + return myCustomSoftWrapIndent == null ? EditorSettingsExternalizable.getInstance().getCustomSoftWrapIndent() : myCustomSoftWrapIndent; + } + + @Override + public void setCustomSoftWrapIndent(int indent) { + myCustomSoftWrapIndent = indent; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java index 1a27b73d43de..083c0f47f817 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java @@ -517,10 +517,14 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume myLineWrapPositionStrategy = LanguageLineWrapPositionStrategy.INSTANCE.forEditor(myEditor); } - softWrapOffset = myLineWrapPositionStrategy.calculateWrapPosition(document, myEditor.getProject(), minOffset, maxOffset, preferredOffset, true); + softWrapOffset = myLineWrapPositionStrategy.calculateWrapPosition( + document, myEditor.getProject(), minOffset, maxOffset, preferredOffset, true, true + ); } - if (softWrapOffset >= lineData.endLineOffset || softWrapOffset < 0) { + if (softWrapOffset >= lineData.endLineOffset || softWrapOffset < 0 + || (myCustomIndentUsedLastTime && softWrapOffset == lineData.nonWhiteSpaceSymbolOffset)) + { return null; } @@ -787,8 +791,7 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume public int indentInColumns; public int indentInPixels; public int endLineOffset; - - private int myNonWhiteSpaceSymbolOffset; + public int nonWhiteSpaceSymbolOffset; public void update(int logicalLine, int spaceWidth, Editor editor) { Document document = myEditor.getDocument(); @@ -803,7 +806,7 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume CharSequence text = document.getCharsSequence(); indentInColumns = 0; indentInPixels = 0; - myNonWhiteSpaceSymbolOffset = -1; + nonWhiteSpaceSymbolOffset = -1; for (int i = startLineOffset; i < endLineOffset; i++) { char c = text.charAt(i); @@ -814,7 +817,7 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume indentInColumns += calculateWidthInColumns(c, x - indentInPixels, spaceWidth); indentInPixels = x; break; - default: myNonWhiteSpaceSymbolOffset = i; return; + default: nonWhiteSpaceSymbolOffset = i; return; } } } @@ -828,7 +831,7 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume * @param softWrapOffset offset of the soft wrap that occurred on document line which data is stored at the current object */ public void update(int softWrapOffset) { - if (myNonWhiteSpaceSymbolOffset >= 0 && softWrapOffset > myNonWhiteSpaceSymbolOffset) { + if (nonWhiteSpaceSymbolOffset >= 0 && softWrapOffset > nonWhiteSpaceSymbolOffset) { return; } indentInColumns = 0; 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 ff8f09b3ee29..26ab633d80ca 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 @@ -17,6 +17,7 @@ package com.intellij.openapi.editor.impl.softwrap.mapping; import com.intellij.codeInsight.folding.CodeFoldingManager; import com.intellij.openapi.editor.*; +import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.ex.SoftWrapModelEx; import com.intellij.openapi.editor.impl.AbstractEditorProcessingOnDocumentModificationTest; import com.intellij.openapi.editor.impl.SoftWrapModelImpl; @@ -793,6 +794,21 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorP assertEquals(new VisualPosition(1, 8), getEditor().offsetToVisualPosition(getEditor().getDocument().getTextLength() - 1)); } + public void testNoWrapAtFirstNonWsSymbolWithCustomIndent() throws IOException { + String text = + " 1111111111111111111111111111111"; + init(70, text); + getEditor().getSettings().setCustomSoftWrapIndent(0); + getEditor().getSettings().setUseCustomSoftWrapIndent(true); + int textLength = getEditor().getDocument().getTextLength(); + //Trigger soft wraps recalculation. + assertEquals(new LogicalPosition(0, textLength), myEditor.offsetToLogicalPosition(textLength)); + + // Don't expect soft wraps to be registered as there is no point in wrapping at the first non-white space symbol position + // in all cases when soft wrap is located at the left screen edge. + assertEmpty(getSoftWrapModel().getRegisteredSoftWraps()); + } + public void testXmlWithLongCdata() throws IOException { String text = "\n" + diff --git a/xml/impl/src/com/intellij/psi/formatter/MarkupLineWrapPositionStrategy.java b/xml/impl/src/com/intellij/psi/formatter/MarkupLineWrapPositionStrategy.java index 1f3c21bc9960..7fb5d9a9f821 100644 --- a/xml/impl/src/com/intellij/psi/formatter/MarkupLineWrapPositionStrategy.java +++ b/xml/impl/src/com/intellij/psi/formatter/MarkupLineWrapPositionStrategy.java @@ -30,6 +30,6 @@ import com.intellij.psi.xml.XmlTokenType; public class MarkupLineWrapPositionStrategy extends PsiAwareDefaultLineWrapPositionStrategy { public MarkupLineWrapPositionStrategy() { - super(XmlElementType.XML_TEXT, TokenType.WHITE_SPACE); + super(true, XmlElementType.XML_TEXT, TokenType.WHITE_SPACE); } }