IDEA-70602 Soft wrap in xml files: lines after long line are wrapped though they are not too long

This commit is contained in:
Denis Zhdanov
2011-06-03 18:11:08 +04:00
parent d5929b0091
commit 2a792bfeab
12 changed files with 78 additions and 30 deletions
@@ -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);
}
}
@@ -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 <code>PsiAwareLineWrapPositionStrategy</code> 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
* <code>(maxPreferredOffset; endOffset]</code> interval in case of inability to
* find appropriate offset from <code>(startOffset; maxPreferredOffset]</code> interval
* @param virtual identifies if current request is for virtual wrap (soft wrap) position
* @return offset from <code>(startOffset; endOffset]</code> interval where
* target line should be wrapped OR <code>-1</code> 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
);
/**
@@ -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;
}
@@ -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;
@@ -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);
@@ -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;
@@ -45,11 +45,12 @@ public interface LineWrapPositionStrategy {
* @param allowToBeyondMaxPreferredOffset indicates if it's allowed to return value from
* <code>(maxPreferredOffset; endOffset]</code> interval in case of inability to
* find appropriate offset from <code>(startOffset; maxPreferredOffset]</code> interval
* @param virtual identifies if current request is for virtual wrap (soft wrap) position
* @return offset from <code>(startOffset; endOffset]</code> interval where
* target line should be wrapped OR <code>-1</code> 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
);
}
@@ -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);
}
@@ -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
@@ -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;
@@ -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 =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
@@ -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);
}
}