IDEA-56242 Align When Multiline > Fields/variables groups does not align correctly when using tabs

1. Removed 'Align in columns' option processing for local variables;
2. Corrected white space string generation during 'align fields in columns' processing (tabs are not used for non-first block on a line alignment now);
 3. Green code policy is applied whenever possible;
 4. Corresponding tests are added;
This commit is contained in:
Denis Zhdanov
2010-08-30 12:14:14 +04:00
parent a8a5965505
commit feb72f4b67
10 changed files with 143 additions and 128 deletions
@@ -49,10 +49,10 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
/**
* Holds types of the elements for which <code>'align in column'</code> rule may be preserved.
*
* @see CodeStyleSettings#ALIGN_GROUP_FIELDS_VARIABLES
* @see CodeStyleSettings#ALIGN_GROUP_FIELD_DECLARATIONS
*/
protected static final Set<IElementType> ALIGN_IN_COLUMNS_ELEMENT_TYPES = Collections.unmodifiableSet(new HashSet<IElementType>(asList(
JavaElementType.FIELD, JavaElementType.DECLARATION_STATEMENT, JavaElementType.LOCAL_VARIABLE
JavaElementType.FIELD
)));
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.formatter.java.AbstractJavaBlock");
@@ -60,11 +60,11 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
/**
* Shared thread-safe config object to use during <code>'align in column'</code> processing.
*
* @see CodeStyleSettings#ALIGN_GROUP_FIELDS_VARIABLES
* @see CodeStyleSettings#ALIGN_GROUP_FIELD_DECLARATIONS
*/
private static final AlignmentInColumnsConfig ALIGNMENT_IN_COLUMNS_CONFIG = new AlignmentInColumnsConfig(
JavaTokenType.IDENTIFIER, ElementType.WHITE_SPACE_BIT_SET, ElementType.JAVA_COMMENT_BIT_SET, JavaTokenType.EQ,
JavaElementType.FIELD, JavaElementType.LOCAL_VARIABLE
JavaElementType.FIELD
);
/**
@@ -874,14 +874,14 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
*
* @param child variable declaration child node which alignment is to be defined
* @return alignment to use for the given node
* @see CodeStyleSettings#ALIGN_GROUP_FIELDS_VARIABLES
* @see CodeStyleSettings#ALIGN_GROUP_FIELD_DECLARATIONS
*/
@Nullable
private Alignment getVariableDeclarationSubElementAlignment(ASTNode child) {
// The whole idea of variable declarations alignment is that complete declaration blocks which children are to be aligned hold
// reference to the same AlignmentStrategy object, hence, reuse the same Alignment objects. So, there is no point in checking
// if it's necessary to align sub-blocks if shared strategy is not defined.
if (myAlignmentStrategy == null || !mySettings.ALIGN_GROUP_FIELDS_VARIABLES) {
if (myAlignmentStrategy == null || !mySettings.ALIGN_GROUP_FIELD_DECLARATIONS) {
return null;
}
@@ -1265,7 +1265,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
* @return
*/
protected boolean shouldUseVarDeclarationAlignment(ASTNode node) {
return mySettings.ALIGN_GROUP_FIELDS_VARIABLES && ALIGN_IN_COLUMNS_ELEMENT_TYPES.contains(node.getElementType())
return mySettings.ALIGN_GROUP_FIELD_DECLARATIONS && ALIGN_IN_COLUMNS_ELEMENT_TYPES.contains(node.getElementType())
&& !myAlignmentInColumnsHelper.useDifferentVarDeclarationAlignment(node, ALIGNMENT_IN_COLUMNS_CONFIG);
}
@@ -1,6 +1,7 @@
class FormattingTest {
private static FormattingTest staticFoo;
private FormattingTest instanceFoo;
@SuppressWarnings({"AccessStaticViaInstance"})
@@ -1,6 +1,7 @@
class FormattingTest {
private static FormattingTest staticFoo;
private FormattingTest instanceFoo;
@SuppressWarnings({"AccessStaticViaInstance"})
@@ -150,9 +150,9 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest {
doMethodTest(method, method);
}
public void testVariableDeclarationAlignment() {
public void testFieldInColumnsAlignment() {
// Inspired by IDEA-55147
getSettings().ALIGN_GROUP_FIELDS_VARIABLES = true;
getSettings().ALIGN_GROUP_FIELD_DECLARATIONS = true;
getSettings().FIELD_ANNOTATION_WRAP = CodeStyleSettings.DO_NOT_WRAP;
getSettings().VARIABLE_ANNOTATION_WRAP = CodeStyleSettings.DO_NOT_WRAP;
@@ -179,15 +179,6 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest {
" private transient int iiii5 = 1;\n" +
" /*sdf*/\n" +
" @MyAnnotation(value = 1, text = 2) float f5 = 1;\n" +
"\n" +
" public void foo() {\n" +
" int start = 1;\n" +
" int start2 = 1;\n" +
" @NotNull int end = 2;\n" +
" @NotNull long longValue = 1;\n" +
" Serializable serializable;\n" +
" Object o;\n" +
" }\n" +
"}",
"public class FormattingTest {\n" +
@@ -212,15 +203,26 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest {
" private transient int iiii5 = 1;\n" +
" /*sdf*/\n" +
" @MyAnnotation(value = 1, text = 2) float f5 = 1;\n" +
"\n" +
" public void foo() {\n" +
" int start = 1;\n" +
" int start2 = 1;\n" +
" @NotNull int end = 2;\n" +
" @NotNull long longValue = 1;\n" +
" Serializable serializable;\n" +
" Object o;\n" +
" }\n" +
"}"
);
}
public void testTabsAndFieldsInColumnsAlignment() throws Exception {
// Inspired by IDEA-56242
getSettings().ALIGN_GROUP_FIELD_DECLARATIONS = true;
getIndentOptions().USE_TAB_CHARACTER = true;
doTextTest(
"public class Test {\n" +
"\tprivate Long field2 = null;\n" +
"\tprivate final Object field1 = null;\n" +
"\tprivate int i = 1;\n" +
"}",
"public class Test {\n" +
"\tprivate Long field2 = null;\n" +
"\tprivate final Object field1 = null;\n" +
"\tprivate int i = 1;\n" +
"}"
);
}
@@ -730,21 +730,26 @@ public class JavaFormatterTest extends AbstractJavaFormatterTest {
}
public void testComment1() throws Exception {
doTextTest("class Foo {\n" +
" public boolean mErrorFlage;\n" +
" /**\n" +
" * Reference to New Member Message Source\n" +
" */\n" +
" private NewMemberMessageSource newMemberMessageSource;" +
"\n" +
"}", "class Foo {\n" +
" public boolean mErrorFlage;\n" +
" /**\n" +
" * Reference to New Member Message Source\n" +
" */\n" +
" private NewMemberMessageSource newMemberMessageSource;" +
"\n" +
"}");
doTextTest(
"class Foo {\n" +
" public boolean mErrorFlage;\n" +
"\n" +
" /**\n" +
" * Reference to New Member Message Source\n" +
" */\n" +
" private NewMemberMessageSource newMemberMessageSource;" +
"\n" +
"}",
"class Foo {\n" +
" public boolean mErrorFlage;\n" +
"\n" +
" /**\n" +
" * Reference to New Member Message Source\n" +
" */\n" +
" private NewMemberMessageSource newMemberMessageSource;" +
"\n" +
"}");
}
public void testElseAfterComment() throws Exception {
@@ -434,12 +434,10 @@ public class CodeStyleSettings implements Cloneable, JDOMExternalizable {
//----------------- Group alignments ---------------
/**
* Specifies if subsequent fields/variables declarations and initialisations should be aligned in columns like below:
* Specifies if subsequent fields declarations and initialisations should be aligned in columns like below:
* int start = 1;
* int end = 10;
*/
public boolean ALIGN_GROUP_FIELDS_VARIABLES = false;
public boolean ALIGN_GROUP_FIELD_DECLARATIONS = false;
//----------------- BLANK LINES --------------------
@@ -36,12 +36,12 @@ class FormatProcessor {
private LeafBlockWrapper myCurrentBlock;
private Map<AbstractBlockWrapper, Block> myInfos;
private CompositeBlockWrapper myRootBlockWrapper;
private Map<AbstractBlockWrapper, Block> myInfos;
private CompositeBlockWrapper myRootBlockWrapper;
private TIntObjectHashMap<LeafBlockWrapper> myTextRangeToWrapper;
private final CodeStyleSettings.IndentOptions myIndentOption;
private final CodeStyleSettings mySettings;
private final CodeStyleSettings mySettings;
/**
* Remembers mappings between backward-shifted aligned block and blocks that cause that shift in order to detect
@@ -62,13 +62,13 @@ class FormatProcessor {
private final Map<LeafBlockWrapper, Set<LeafBlockWrapper>> myBackwardShiftedAlignedBlocks
= new HashMap<LeafBlockWrapper, Set<LeafBlockWrapper>>();
private LeafBlockWrapper myWrapCandidate = null;
private LeafBlockWrapper myWrapCandidate = null;
private LeafBlockWrapper myFirstWrappedBlockOnLine = null;
private LeafBlockWrapper myFirstTokenBlock;
private LeafBlockWrapper myLastTokenBlock;
private SortedMap<TextRange,Pair<AbstractBlockWrapper, Boolean>> myPreviousDependencies =
private SortedMap<TextRange, Pair<AbstractBlockWrapper, Boolean>> myPreviousDependencies =
new TreeMap<TextRange, Pair<AbstractBlockWrapper, Boolean>>(new Comparator<TextRange>() {
public int compare(final TextRange o1, final TextRange o2) {
int offsetsDelta = o1.getEndOffset() - o2.getEndOffset();
@@ -81,8 +81,8 @@ class FormatProcessor {
});
private final HashSet<WhiteSpace> myAlignAgain = new HashSet<WhiteSpace>();
private WhiteSpace myLastWhiteSpace;
private boolean myDisposed;
private WhiteSpace myLastWhiteSpace;
private boolean myDisposed;
private CodeStyleSettings.IndentOptions myJavaIndentOptions;
public FormatProcessor(final FormattingDocumentModel docModel,
@@ -183,7 +183,7 @@ class FormatProcessor {
myJavaIndentOptions = mySettings.getIndentOptions(StdFileTypes.JAVA);
}
doModify(blocksToModify, model,myIndentOption, myJavaIndentOptions);
doModify(blocksToModify, model, myIndentOption, myJavaIndentOptions);
}
public void setJavaIndentOptions(final CodeStyleSettings.IndentOptions javaIndentOptions) {
@@ -195,14 +195,14 @@ class FormatProcessor {
final int blocksToModifyCount = blocksToModify.size();
final boolean bulkReformat = blocksToModifyCount > 50;
final DocumentEx updatedDocument = bulkReformat ? getAffectedDocument(model) : null;
if(updatedDocument != null) {
if (updatedDocument != null) {
updatedDocument.setInBulkUpdate(true);
}
try {
int shift = 0;
for (int i = 0; i < blocksToModifyCount; ++i) {
final LeafBlockWrapper block = blocksToModify.get(i);
shift = replaceWhiteSpace(model, block, shift, block.getWhiteSpace().generateWhiteSpace(indentOption),javaOptions);
shift = replaceWhiteSpace(model, block, shift, block.getWhiteSpace().generateWhiteSpace(indentOption), javaOptions);
// block could be gc'd
block.getParent().dispose();
@@ -222,7 +222,7 @@ class FormatProcessor {
private static DocumentEx getAffectedDocument(final FormattingModel model) {
if (model instanceof DocumentBasedFormattingModel) {
final Document document = ((DocumentBasedFormattingModel)model).getDocument();
if (document instanceof DocumentEx) return (DocumentEx)document;
if (document instanceof DocumentEx) return (DocumentEx)document;
}/* else if (false) { // till issue with persistent range markers dropped fixed
Document document = model.getDocumentModel().getDocument();
if (document instanceof DocumentEx) return (DocumentEx)document;
@@ -231,11 +231,11 @@ class FormatProcessor {
}
private static int replaceWhiteSpace(final FormattingModel model,
@NotNull final LeafBlockWrapper block,
int shift,
final CharSequence _newWhiteSpace,
final CodeStyleSettings.IndentOptions options
) {
@NotNull final LeafBlockWrapper block,
int shift,
final CharSequence _newWhiteSpace,
final CodeStyleSettings.IndentOptions options
) {
final WhiteSpace whiteSpace = block.getWhiteSpace();
final TextRange textRange = whiteSpace.getTextRange();
final TextRange wsRange = shiftRange(textRange, shift);
@@ -298,7 +298,7 @@ class FormatProcessor {
}
if (!adjustIndent()) {
return;
return;
}
defineAlignOffset(myCurrentBlock);
@@ -344,7 +344,7 @@ class FormatProcessor {
final DependantSpacingImpl dependantSpaceProperty = (DependantSpacingImpl)spaceProperty;
final TextRange dependency = dependantSpaceProperty.getDependency();
if (dependantSpaceProperty.wasLFUsed()) {
myPreviousDependencies.put(dependency,new Pair<AbstractBlockWrapper, Boolean>(myCurrentBlock, Boolean.TRUE));
myPreviousDependencies.put(dependency, new Pair<AbstractBlockWrapper, Boolean>(myCurrentBlock, Boolean.TRUE));
}
else {
final boolean value = containsLineFeeds(dependency);
@@ -454,9 +454,9 @@ class FormatProcessor {
/**
* Allows to answer if wrap of the {@link #myWrapCandidate} object (if any) may be replaced by the given wrap.
*
* @param wrap wrap candidate to check
* @return <code>true</code> if wrap of the {@link #myWrapCandidate} object (if any) may be replaced by the given wrap;
* <code>false</code> otherwise
* @param wrap wrap candidate to check
* @return <code>true</code> if wrap of the {@link #myWrapCandidate} object (if any) may be replaced by the given wrap;
* <code>false</code> otherwise
*/
private boolean canReplaceWrapCandidate(WrapImpl wrap) {
if (myWrapCandidate == null) return true;
@@ -468,8 +468,8 @@ class FormatProcessor {
private boolean isCandidateToBeWrapped(final WrapImpl wrap) {
return isSuitableInTheCurrentPosition(wrap) &&
(wrap.getType() == WrapImpl.Type.WRAP_AS_NEEDED || wrap.getType() == WrapImpl.Type.CHOP_IF_NEEDED) &&
!myCurrentBlock.getWhiteSpace().isReadOnly();
(wrap.getType() == WrapImpl.Type.WRAP_AS_NEEDED || wrap.getType() == WrapImpl.Type.CHOP_IF_NEEDED) &&
!myCurrentBlock.getWhiteSpace().isReadOnly();
}
private void onCurrentLineChanged() {
@@ -479,9 +479,9 @@ class FormatProcessor {
/**
* Adjusts indent of the current block.
*
* @return <code>true</code> if current formatting iteration should be continued;
* <code>false</code> otherwise (e.g. if previously processed block is shifted inside this method for example
* because of specified alignment options)
* @return <code>true</code> if current formatting iteration should be continued;
* <code>false</code> otherwise (e.g. if previously processed block is shifted inside this method for example
* because of specified alignment options)
*/
private boolean adjustIndent() {
IndentData alignOffset = getAlignOffset();
@@ -509,7 +509,12 @@ class FormatProcessor {
}
if (diff > 0) {
whiteSpace.setSpaces(whiteSpace.getSpaces(), whiteSpace.getIndentSpaces() + diff);
whiteSpace.setSpaces(whiteSpace.getSpaces() + diff, whiteSpace.getIndentSpaces());
// Avoid tabulations usage for aligning blocks that are not the first blocks on a line.
if (!whiteSpace.containsLineFeeds()) {
whiteSpace.setForceSkipTabulationsUsage(true);
}
return true;
}
AlignmentImpl alignment = myCurrentBlock.getAlignmentAtStartOffset();
@@ -545,8 +550,8 @@ class FormatProcessor {
Set<LeafBlockWrapper> blocksCausedRealignment = myBackwardShiftedAlignedBlocks.get(offsetResponsibleBlock);
if (blocksCausedRealignment != null && blocksCausedRealignment.contains(myCurrentBlock)) {
LOG.error(String.format("Formatting error - code block %s is set to be shifted right because of its alignment with "
+ "block %s more than once. I.e. moving the former block because of alignment algorithm causes "
+ "subsequent block to be shifted right as well - cyclic dependency",
+ "block %s more than once. I.e. moving the former block because of alignment algorithm causes "
+ "subsequent block to be shifted right as well - cyclic dependency",
offsetResponsibleBlock.getTextRange(), myCurrentBlock.getTextRange()));
blocksCausedRealignment.add(myCurrentBlock);
return true;
@@ -556,7 +561,11 @@ class FormatProcessor {
blocksCausedRealignment.add(myCurrentBlock);
WhiteSpace previousWhiteSpace = offsetResponsibleBlock.getWhiteSpace();
previousWhiteSpace.setSpaces(previousWhiteSpace.getSpaces(), previousWhiteSpace.getIndentOffset() - diff);
previousWhiteSpace.setSpaces(previousWhiteSpace.getSpaces() - diff, previousWhiteSpace.getIndentOffset());
// Avoid tabulations usage for aligning blocks that are not the first blocks on a line.
if (!previousWhiteSpace.containsLineFeeds()) {
previousWhiteSpace.setForceSkipTabulationsUsage(true);
}
myCurrentBlock = offsetResponsibleBlock.getNextBlock();
onCurrentLineChanged();
@@ -586,7 +595,7 @@ class FormatProcessor {
/**
* Tries to find the closest block that starts before the {@link #myCurrentBlock currently processed block} and contains line feeds.
*
* @return closest block to the currently processed block that contains line feeds if any; <code>null</code> otherwise
* @return closest block to the currently processed block that contains line feeds if any; <code>null</code> otherwise
*/
@Nullable
private AbstractBlockWrapper getPreviousIndentedBlock() {
@@ -626,7 +635,7 @@ class FormatProcessor {
/**
* Ensures that offset of the {@link #myCurrentBlock currently processed block} is not increased if we make a wrap on it.
*
* @return <code>true</code> if it's ok to wrap at the currently processed block; <code>false</code> otherwise
* @return <code>true</code> if it's ok to wrap at the currently processed block; <code>false</code> otherwise
*/
private boolean positionAfterWrappingIsSuitable() {
final WhiteSpace whiteSpace = myCurrentBlock.getWhiteSpace();
@@ -671,12 +680,12 @@ class FormatProcessor {
}
/**
* @return <code>true</code> if {@link #myCurrentBlock currently processed wrapped block} doesn't contain line feeds and
* exceeds right margin; <code>false</code> otherwise
* @return <code>true</code> if {@link #myCurrentBlock currently processed wrapped block} doesn't contain line feeds and
* exceeds right margin; <code>false</code> otherwise
*/
private boolean lineOver() {
return !myCurrentBlock.containsLineFeeds() &&
getOffsetBefore(myCurrentBlock) + myCurrentBlock.getLength() > mySettings.RIGHT_MARGIN;
getOffsetBefore(myCurrentBlock) + myCurrentBlock.getLength() > mySettings.RIGHT_MARGIN;
}
/**
@@ -693,8 +702,8 @@ class FormatProcessor {
* from <code>'whitespace<sub>21</sub>'</code> after its last line feed symbol plus number of symbols at
* <code>block<sub>21</sub></code> plus number of symbols at <code>whitespace<sub>22</sub></code>.
*
* @param info target wrapped block to be used at a boundary during counting non-line feed symbols to the left of it
* @return non-line feed symbols to the left of the given wrapped block
* @param info target wrapped block to be used at a boundary during counting non-line feed symbols to the left of it
* @return non-line feed symbols to the left of the given wrapped block
*/
private static int getOffsetBefore(LeafBlockWrapper info) {
if (info != null) {
@@ -733,7 +742,7 @@ class FormatProcessor {
/**
* Tries to get align-implied indent of the current block.
*
* @return indent of the current block if any; <code>null</code> otherwise
* @return indent of the current block if any; <code>null</code> otherwise
*/
@Nullable
private IndentData getAlignOffset() {
@@ -829,8 +838,8 @@ class FormatProcessor {
static class ChildAttributesInfo {
public final AbstractBlockWrapper parent;
final ChildAttributes attributes;
final int index;
final ChildAttributes attributes;
final int index;
public ChildAttributesInfo(final AbstractBlockWrapper parent, final ChildAttributes attributes, final int index) {
this.parent = parent;
@@ -845,11 +854,11 @@ class FormatProcessor {
if (parent == null) {
final LeafBlockWrapper previousBlock = myCurrentBlock.getPreviousBlock();
if (previousBlock != null) parent = getParentFor(offset, previousBlock);
if (parent == null) return new IndentInfo(0,0,0);
if (parent == null) return new IndentInfo(0, 0, 0);
}
int index = getNewChildPosition(parent, offset);
final Block block = myInfos.get(parent);
if (block == null) {
return new IndentInfo(0, 0, 0);
}
@@ -970,8 +979,8 @@ class FormatProcessor {
if (current.getEndOffset() <= offset) {
while (!current.isIncomplete() &&
current.getParent() != null &&
current.getParent().getEndOffset() <= offset) {
current.getParent() != null &&
current.getParent().getEndOffset() <= offset) {
current = current.getParent();
}
if (current.isIncomplete()) return current;
@@ -1031,7 +1040,7 @@ class FormatProcessor {
private static int calcShift(final IndentInside lastLineIndent, final IndentInside whiteSpaceIndent,
final CodeStyleSettings.IndentOptions options
) {
) {
if (lastLineIndent.equals(whiteSpaceIndent)) return 0;
if (options.USE_TAB_CHARACTER) {
if (lastLineIndent.whiteSpaces > 0) {
@@ -17,38 +17,36 @@
package com.intellij.formatting;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.codeStyle.CodeStyleSettings;
public class IndentInfo {
private final int mySpaces;
private final int myIndentSpaces;
private final int myLineFeeds;
private boolean myIsChanged = true;
private TextRange myInitialTextRange;
/** @see WhiteSpace#setForceSkipTabulationsUsage(boolean) */
private boolean myForceSkipTabulationsUsage;
public IndentInfo(final int lineFeeds, final int indentSpaces, final int spaces) {
this(lineFeeds, indentSpaces, spaces, false);
}
public IndentInfo(final int lineFeeds, final int indentSpaces, final int spaces, final boolean forceSkipTabulationsUsage) {
mySpaces = spaces;
myIndentSpaces = indentSpaces;
myLineFeeds = lineFeeds;
myForceSkipTabulationsUsage = forceSkipTabulationsUsage;
}
public int getSpaces() {
return mySpaces;
}
public void setInitialTextRange(final TextRange initialTextRange) {
myInitialTextRange = initialTextRange;
}
public int getIndentSpaces() {
return myIndentSpaces;
}
public int getLineFeeds() {
return myLineFeeds;
}
/**
* Builds string that contains line feeds, white spaces and tabulation symbols known to the current {@link IndentInfo} object.
*
@@ -58,7 +56,7 @@ public class IndentInfo {
StringBuffer buffer = new StringBuffer();
StringUtil.repeatSymbol(buffer, '\n', myLineFeeds);
if (options.USE_TAB_CHARACTER) {
if (options.USE_TAB_CHARACTER && !myForceSkipTabulationsUsage) {
if (options.SMART_TABS) {
int tabCount = myIndentSpaces / options.TAB_SIZE;
int leftSpaces = myIndentSpaces - tabCount * options.TAB_SIZE;
@@ -90,26 +88,4 @@ public class IndentInfo {
public int getTotalSpaces() {
return myIndentSpaces + mySpaces;
}
public int getIndentCount(final CodeStyleSettings.IndentOptions indentOptions) {
return myIndentSpaces/indentOptions.INDENT_SIZE;
}
public int getSpacesCount(final CodeStyleSettings.IndentOptions indentOptions) {
final int indentSpaces = getIndentCount(indentOptions);
return myIndentSpaces - indentSpaces * indentOptions.INDENT_SIZE + mySpaces;
}
public boolean isChanged() {
return myIsChanged;
}
public void setIsChanged(final boolean value) {
myIsChanged = value;
}
public TextRange getInitialTextRange() {
return myInitialTextRange;
}
}
@@ -48,13 +48,14 @@ class WhiteSpace {
private static final char LINE_FEED = '\n';
private final int myStart;
private int myEnd;
private int myEnd;
private int mySpaces;
private int myIndentSpaces;
private CharSequence myInitial;
private int myFlags;
private int myFlags;
private boolean myForceSkipTabulationsUsage;
private static final byte FIRST = 1;
private static final byte SAFE = 0x2;
@@ -238,7 +239,7 @@ class WhiteSpace {
* {@link WhiteSpace} object
*/
public String generateWhiteSpace(CodeStyleSettings.IndentOptions options) {
return new IndentInfo(getLineFeeds(), myIndentSpaces, mySpaces).generateNewWhiteSpace(options);
return new IndentInfo(getLineFeeds(), myIndentSpaces, mySpaces, myForceSkipTabulationsUsage).generateNewWhiteSpace(options);
}
/**
@@ -401,6 +402,28 @@ class WhiteSpace {
}
/**
* There is a possible case that particular indent info is applied to the code block that is not the first block on a line.
* E.g. we may want to align field name during <code>'align fields in columns'</code> processing:
* <pre>
* public class Test {
* private Object o;
* private int {@code <white space to align>}i;
* }
* </pre>
* We may not want to use tabulation characters then even if user configured
* {@link CodeStyleSettings.IndentOptions#USE_TAB_CHARACTER their usage} because we can't be sure how many visual columns
* will be used for tab representation if there are non-white space symbols before it (IJ editor may use different number of columns
* for single tabulation symbol representation).
* <p/>
* Hence, we can ask current white space object to avoid using tabulation symbols.
*
* @param skip indicates if tabulations symbols usage should be suppressed
*/
public void setForceSkipTabulationsUsage(boolean skip) {
myForceSkipTabulationsUsage = skip;
}
/**
* Allows to get information if target text document continuous 'white space' represented by the current object contained line feed
* symbol(s) initially or contains line feed(s) now.
@@ -209,7 +209,7 @@ checkbox.align.multiline.method.parameters=Method parameters
checkbox.align.multiline.call.arguments=Call arguments
checkbox.align.multiline.extends.list=Extends list
checkbox.align.multiline.throws.list=Throws list
checkbox.align.multiline.fields.variables.groups=Fields/variables groups
checkbox.align.multiline.fields.groups=Field groups
checkbox.align.multiline.parenthesized.expression=Parenthesized expression
checkbox.align.multiline.binary.operation=Binary operation
checkbox.align.multiline.ternary.operation=Ternary operation