Formatting: add settings for dot placement in method chains

This commit is contained in:
Roman.Ivanov
2018-12-13 17:54:57 +07:00
parent 5d4a0b8197
commit b3bea36da5
6 changed files with 108 additions and 14 deletions
@@ -201,6 +201,11 @@ public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSett
String groupName = ApplicationBundle.message("wrapping.fields.annotation");
consumer.showCustomOption(JavaCodeStyleSettings.class, "DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION", "Do not wrap after single annotation", groupName);
consumer.showCustomOption(JavaCodeStyleSettings.class,
"PLACE_DOT_ON_NEXT_LINE",
ApplicationBundle.message("checkbox.place.dot.on.next.line"),
CodeStyleSettingsCustomizable.WRAPPING_CALL_CHAIN);
}
else if (settingsType == SettingsType.BLANK_LINES_SETTINGS) {
consumer.showAllStandardOptions();
@@ -100,6 +100,12 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings implements Im
public boolean SPACES_WITHIN_ANGLE_BRACKETS;
public boolean PLACE_DOT_ON_NEXT_LINE = true;
//Type arguments
public boolean SPACE_AFTER_CLOSING_ANGLE_BRACKET_IN_TYPE_ARGUMENT;
@@ -21,6 +21,9 @@ import com.intellij.lang.ASTNode;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.util.CollectionsKt;
import com.siyeh.ig.psiutils.CollectionUtils;
import org.apache.commons.collections.ListUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -58,7 +61,24 @@ public class CallChunkBlockBuilder {
}
return new SyntheticCodeBlock(subBlocks, alignment, mySettings, myJavaSettings, Indent.getContinuationIndent(myIndentSettings.USE_RELATIVE_INDENTS), wrap);
}
return new SyntheticCodeBlock(createJavaBlocks(subNodes), alignment, mySettings, myJavaSettings, Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS), null);
// Support for groovy style dot placement
final ASTNode lastNode = subNodes.get(subNodes.size() - 1);
if (lastNode.getElementType() == JavaTokenType.DOT) {
AlignmentStrategy strategy = AlignmentStrategy.getNullStrategy();
subNodes.remove(subNodes.size() - 1);
if (!subNodes.isEmpty()) {
subBlocks.add(create(subNodes, wrap, null));
}
Block block = newJavaBlock(lastNode, mySettings, myJavaSettings, Indent.getNoneIndent(), Wrap.createWrap(WrapType.ALWAYS, true), strategy, myFormattingMode);
subBlocks.add(block);
SyntheticCodeBlock syntheticCodeBlock = new SyntheticCodeBlock(subBlocks, alignment, mySettings, myJavaSettings,
Indent.getContinuationIndent(myIndentSettings.USE_RELATIVE_INDENTS), Wrap.createWrap(WrapType.NONE, false));
return syntheticCodeBlock;
}
List<Block> blocks = createJavaBlocks(subNodes);
return new SyntheticCodeBlock(blocks, alignment, mySettings, myJavaSettings,
Indent.getContinuationWithoutFirstIndent(myIndentSettings.USE_RELATIVE_INDENTS),
null);
}
@NotNull
@@ -82,7 +82,11 @@ class ChainMethodCallsBlockBuilder {
}
}
else {
wrap = null;
if (!myJavaSettings.PLACE_DOT_ON_NEXT_LINE) {
wrap = Wrap.createWrap(WrapType.ALWAYS, true);
} else {
wrap = null;
}
chainedCallsAlignment = null;
}
@@ -123,23 +127,41 @@ class ChainMethodCallsBlockBuilder {
}
@NotNull
private static List<ChainedCallChunk> splitMethodCallOnChunksByDots(@NotNull List<? extends ASTNode> nodes) {
private List<ChainedCallChunk> splitMethodCallOnChunksByDots(@NotNull List<? extends ASTNode> nodes) {
List<ChainedCallChunk> result = new ArrayList<>();
List<ASTNode> current = new ArrayList<>();
for (ASTNode node : nodes) {
if (node.getElementType() == JavaTokenType.DOT || node.getPsi() instanceof PsiComment) {
if (!current.isEmpty()) {
result.add(new ChainedCallChunk(current));
if (myJavaSettings.PLACE_DOT_ON_NEXT_LINE) {
List<ASTNode> current = new ArrayList<>();
for (ASTNode node : nodes) {
if (node.getElementType() == JavaTokenType.DOT || node.getPsi() instanceof PsiComment) {
if (!current.isEmpty()) {
result.add(new ChainedCallChunk(current));
}
current = new ArrayList<>();
}
current = new ArrayList<>();
current.add(node);
}
if (!current.isEmpty()) {
result.add(new ChainedCallChunk(current));
}
} else {
List<ASTNode> current = new ArrayList<>();
for (ASTNode node : nodes) {
current.add(node);
if (node.getElementType() == JavaTokenType.DOT || node.getPsi() instanceof PsiComment) {
if (!current.isEmpty()) {
result.add(new ChainedCallChunk(current));
}
current = new ArrayList<>();
}
}
if (!current.isEmpty()) {
result.add(new ChainedCallChunk(current));
}
current.add(node);
}
if (!current.isEmpty()) {
result.add(new ChainedCallChunk(current));
}
return result;
}
@@ -935,4 +935,44 @@ public class JavaFormatterWrapTest extends AbstractJavaFormatterTest {
"}"
);
}
public void testDotPlacement() {
//getSettings().WRAP_LONG_LINES = true;
//getSettings().WRAP_COMMENTS = true;
//getSettings().RIGHT_MARGIN = 50;
getJavaSettings().PLACE_DOT_ON_NEXT_LINE = false;
doTextTest(
"public class Chains {\n" +
" static Chains get() {return null;}\n" +
" Chains foo() {\n" +
" return null;\n" +
" }\n" +
" Chains bar() {\n" +
" return null;\n" +
" }\n" +
" public static void main(String[] args) {\n" +
" get()\n" +
" .bar()\n" +
" .foo()\n" +
" .bar()\n" +
" .bar()\n" +
" .foo();\n" +
" }\n" +
"}\n",
"public class Main {\n" +
"\n" +
" /**\n" +
" * {@link #authenticationCompleted(android.app.Activity,\n" +
" * int, int, android.content.Intent)}\n" +
" *\n" +
" * @param args\n" +
" */\n" +
" public static void main(String[] args) {\n" +
" }\n" +
"}"
);
}
}
@@ -511,6 +511,7 @@ group.javadoc.alignment=Alignment
checkbox.enable.javadoc.formatting=Enable JavaDoc formatting
checkbox.align.parameter.descriptions=Align parameter descriptions
checkbox.align.thrown.exception.descriptions=Align thrown exception descriptions
checkbox.place.dot.on.next.line=Place dot on next line in chained calls
checkbox.after.description=After description
checkbox.after.parameter.descriptions=After parameter descriptions
checkbox.after.return.tag=After return tag