You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by jo...@apache.org on 2021/10/28 21:42:01 UTC

[royale-compiler] 02/02: formatter: MXML attribute whitespace options

This is an automated email from the ASF dual-hosted git repository.

joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git

commit 16ffb9e46941ccb7c1d48df6c5f4bae21bd47728
Author: Josh Tynjala <jo...@apache.org>
AuthorDate: Thu Oct 28 14:41:39 2021 -0700

    formatter: MXML attribute whitespace options
---
 .../org/apache/royale/formatter/FORMATTER.java     | 103 +++++++++++++--------
 .../royale/formatter/config/Configuration.java     |  36 +++++++
 .../org/apache/royale/formatter/TestMXMLTag.java   |  60 ++++++++++++
 3 files changed, 160 insertions(+), 39 deletions(-)

diff --git a/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java b/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java
index 132c246..9f8d1bc 100644
--- a/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java
+++ b/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java
@@ -120,6 +120,8 @@ public class FORMATTER {
 	public Semicolons semicolons = Semicolons.INSERT;
 	public boolean ignoreProblems = false;
 	public boolean collapseEmptyBlocks = false;
+	public boolean mxmlAlignAttributes = false;
+	public boolean mxmlInsertNewLineBetweenAttributes = false;
 
 	private ProblemQuery problems;
 	private List<File> inputFiles = new ArrayList<File>();
@@ -324,6 +326,8 @@ public class FORMATTER {
 			insertSpaceBeforeAndAfterBinaryOperators = configuration.getInsertSpaceBeforeAndAfterBinaryOperators();
 			insertSpaceAtStartOfLineComment = configuration.getInsertSpaceAtStartOfLineComment();
 			insertSpaces = configuration.getInsertSpaces();
+			mxmlInsertNewLineBetweenAttributes = configuration.getMxmlInsertNewLineBetweenAttributes();
+			mxmlAlignAttributes = configuration.getMxmlAlignAttributes();
 			listChangedFiles = configuration.getListFiles();
 			maxPreserveNewLines = configuration.getMaxPreserveNewLines();
 			placeOpenBraceOnNewLine = configuration.getPlaceOpenBraceOnNewLine();
@@ -1573,15 +1577,37 @@ public class FORMATTER {
 		return Math.max(0, indent - 1);
 	}
 
+	private String getIndent() {
+		if (insertSpaces) {
+			String result = "";
+			for (int j = 0; j < tabSize; j++) {
+				result += " ";
+			}
+			return result;
+		}
+		return "\t";
+	}
+
+	private String getAttributeIndent(IMXMLToken openTagToken) {
+		if (!mxmlAlignAttributes) {
+			return getIndent();
+		}
+		int indentSize = openTagToken.getText().length() + 1;
+		String result = "";
+		while (indentSize >= tabSize) {
+			result += getIndent();
+			indentSize -= tabSize;
+		}
+		for (int i = 0; i < indentSize; i++) {
+			result += " ";
+		}
+		return result;
+	}
+
 	private void appendIndent(StringBuilder builder, int indent) {
+		String indentString = getIndent();
 		for (int i = 0; i < indent; i++) {
-			if (insertSpaces) {
-				for (int j = 0; j < tabSize; j++) {
-					builder.append(" ");
-				}
-			} else {
-				builder.append("\t");
-			}
+			builder.append(indentString);
 		}
 	}
 
@@ -1634,8 +1660,7 @@ public class FORMATTER {
 		IMXMLToken[] originalTokens = null;
 		try {
 			originalTokens = mxmlTokenizer.getTokens(textReader);
-		}
-		finally {
+		} finally {
 			IOUtils.closeQuietly(textReader);
 			IOUtils.closeQuietly(mxmlTokenizer);
 		}
@@ -1653,7 +1678,7 @@ public class FORMATTER {
 		boolean requiredSpace = false;
 		boolean inOpenTag = false;
 		boolean inCloseTag = false;
-		boolean indentedAttributes = false;
+		String attributeIndent = "";
 		IMXMLToken prevToken = null;
 		IMXMLToken prevTokenOrExtra = null;
 		IMXMLToken token = null;
@@ -1677,10 +1702,9 @@ public class FORMATTER {
 				prevTokenOrExtra = token;
 				continue;
 			} else if (token.getType() == MXMLTokenTypes.TOKEN_WHITESPACE) {
-				if(elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
+				if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
 					numRequiredNewLines = Math.max(numRequiredNewLines, countNewLinesInExtra(token));
-				}
-				else {
+				} else {
 					// if the parent element contains text, treat whitespace
 					// the same as text, and don't reformat it
 					// text is never reformatted because some components use it
@@ -1734,12 +1758,13 @@ public class FORMATTER {
 				case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
 					inOpenTag = true;
 					// if the parent contains text, children should be the same
-					boolean containsText = !elementStack.isEmpty() && elementStack.get(elementStack.size() - 1).containsText;
+					boolean containsText = !elementStack.isEmpty()
+							&& elementStack.get(elementStack.size() - 1).containsText;
 					elementStack.add(new ElementStackItem(token, token.getText().substring(1), containsText));
 					break;
 				}
 				case MXMLTokenTypes.TOKEN_CLOSE_TAG_START: {
-					if(elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
+					if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
 						indent = decreaseIndent(indent);
 					}
 					inCloseTag = true;
@@ -1753,12 +1778,11 @@ public class FORMATTER {
 
 			if (prevToken != null) {
 				if (numRequiredNewLines > 0) {
-					if (inOpenTag && token.getType() != MXMLTokenTypes.TOKEN_OPEN_TAG_START && !indentedAttributes) {
-						indentedAttributes = true;
-						indent = increaseIndent(indent);
-					}
 					appendNewLines(builder, numRequiredNewLines);
 					appendIndent(builder, indent);
+					if (attributeIndent.length() > 0) {
+						builder.append(attributeIndent);
+					}
 				} else if (requiredSpace) {
 					builder.append(' ');
 				}
@@ -1798,6 +1822,7 @@ public class FORMATTER {
 				case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
 					if (nextToken != null && nextToken.getType() != MXMLTokenTypes.TOKEN_TAG_END
 							&& nextToken.getType() != MXMLTokenTypes.TOKEN_EMPTY_TAG_END) {
+						attributeIndent = getAttributeIndent(token);
 						requiredSpace = true;
 					}
 					break;
@@ -1808,43 +1833,43 @@ public class FORMATTER {
 						if (!element.containsText) {
 							element.containsText = elementContainsText(tokens, i + 1, element.token);
 						}
-						if(elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
+						if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
 							indent = increaseIndent(indent);
 						}
-					}
-					else {
-						if(elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
+					} else {
+						if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
 							numRequiredNewLines = Math.max(numRequiredNewLines, 1);
 						}
 					}
 					inOpenTag = false;
-					if (indentedAttributes) {
-						indentedAttributes = false;
-						indent = decreaseIndent(indent);
-					}
+					attributeIndent = "";
 					inCloseTag = false;
 					break;
 				}
 				case MXMLTokenTypes.TOKEN_EMPTY_TAG_END: {
 					if (inOpenTag) {
 						elementStack.remove(elementStack.size() - 1);
-					}
-					else {
-						if(elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
+					} else {
+						if (elementStack.isEmpty() || !elementStack.get(elementStack.size() - 1).containsText) {
 							numRequiredNewLines = Math.max(numRequiredNewLines, 1);
 						}
 					}
 					inOpenTag = false;
 					// no need to change nested indent after this tag
 					// however, we may need to remove attribute indent
-					if (indentedAttributes) {
-						indentedAttributes = false;
-						indent = decreaseIndent(indent);
-					}
+					attributeIndent = "";
 					// we shouldn't find an empty close tag, but clear flag anyway
 					inCloseTag = false;
 					break;
 				}
+				case MXMLTokenTypes.TOKEN_STRING: {
+					if (inOpenTag && mxmlInsertNewLineBetweenAttributes && nextToken != null
+							&& nextToken.getType() != MXMLTokenTypes.TOKEN_TAG_END
+							&& nextToken.getType() != MXMLTokenTypes.TOKEN_EMPTY_TAG_END) {
+						numRequiredNewLines = Math.max(numRequiredNewLines, 1);
+					}
+					break;
+				}
 			}
 
 			prevToken = token;
@@ -1857,11 +1882,11 @@ public class FORMATTER {
 	private boolean elementContainsText(List<IMXMLToken> tokens, int startIndex, IMXMLToken openTagToken) {
 		ArrayList<IMXMLToken> elementStack = new ArrayList<IMXMLToken>();
 		elementStack.add(openTagToken);
-		for(int i = startIndex; i < tokens.size(); i++) {
+		for (int i = startIndex; i < tokens.size(); i++) {
 			IMXMLToken token = tokens.get(i);
-			switch(token.getType()) {
+			switch (token.getType()) {
 				case MXMLTokenTypes.TOKEN_TEXT:
-					if(elementStack.size() == 1) {
+					if (elementStack.size() == 1) {
 						return true;
 					}
 					break;
@@ -1870,13 +1895,13 @@ public class FORMATTER {
 					break;
 				case MXMLTokenTypes.TOKEN_EMPTY_TAG_END:
 					elementStack.remove(elementStack.size() - 1);
-					if(elementStack.size() == 0) {
+					if (elementStack.size() == 0) {
 						return false;
 					}
 					break;
 				case MXMLTokenTypes.TOKEN_CLOSE_TAG_START:
 					elementStack.remove(elementStack.size() - 1);
-					if(elementStack.size() == 0) {
+					if (elementStack.size() == 0) {
 						return false;
 					}
 					break;
diff --git a/formatter/src/main/java/org/apache/royale/formatter/config/Configuration.java b/formatter/src/main/java/org/apache/royale/formatter/config/Configuration.java
index 440be23..dd5c0ac 100644
--- a/formatter/src/main/java/org/apache/royale/formatter/config/Configuration.java
+++ b/formatter/src/main/java/org/apache/royale/formatter/config/Configuration.java
@@ -471,4 +471,40 @@ public class Configuration {
     {
         this.ignoreParsingProblems = b;
     }
+
+    //
+    // 'mxml-align-attributes' option
+    //
+
+    private boolean mxmlAlignAttributes = false;
+
+    public boolean getMxmlAlignAttributes()
+    {
+        return mxmlAlignAttributes;
+    }
+
+    @Config(advanced = true)
+    @Mapping("mxml-align-attributes")
+    public void setMxmlAlignAttributes(ConfigurationValue cv, boolean b)
+    {
+        this.mxmlAlignAttributes = b;
+    }
+
+    //
+    // 'mxml-insert-new-line-attributes' option
+    //
+
+    private boolean mxmlInsertNewLineBetweenAttributes = false;
+
+    public boolean getMxmlInsertNewLineBetweenAttributes()
+    {
+        return mxmlInsertNewLineBetweenAttributes;
+    }
+
+    @Config(advanced = true)
+    @Mapping("mxml-insert-new-line-attributes")
+    public void setMxmlInsertNewLineBetweenAttributes(ConfigurationValue cv, boolean b)
+    {
+        this.mxmlInsertNewLineBetweenAttributes = b;
+    }
 }
diff --git a/formatter/src/test/java/org/apache/royale/formatter/TestMXMLTag.java b/formatter/src/test/java/org/apache/royale/formatter/TestMXMLTag.java
index 8096322..20c85f7 100644
--- a/formatter/src/test/java/org/apache/royale/formatter/TestMXMLTag.java
+++ b/formatter/src/test/java/org/apache/royale/formatter/TestMXMLTag.java
@@ -211,4 +211,64 @@ public class TestMXMLTag extends BaseFormatterTests {
 				// @formatter:on
 				result);
 	}
+
+	@Test
+	public void testMultipleAttributes() {
+		FORMATTER formatter = new FORMATTER();
+		formatter.insertSpaces = false;
+		formatter.mxmlInsertNewLineBetweenAttributes = false;
+		formatter.mxmlAlignAttributes = false;
+		String result = formatter.formatMXMLText(
+		// @formatter:off
+			"<s:Tag one=\"1\"   two=\"2\"/>",
+			// @formatter:on
+			problems
+		);
+		assertEquals(
+		// @formatter:off
+				"<s:Tag one=\"1\" two=\"2\"/>",
+				// @formatter:on
+				result);
+	}
+
+	@Test
+	public void testMultipleAttributesOnePerLine() {
+		FORMATTER formatter = new FORMATTER();
+		formatter.insertSpaces = false;
+		formatter.mxmlInsertNewLineBetweenAttributes = true;
+		formatter.mxmlAlignAttributes = false;
+		String result = formatter.formatMXMLText(
+		// @formatter:off
+			"<s:Tag one=\"1\" two=\"2\"/>",
+			// @formatter:on
+			problems
+		);
+		assertEquals(
+		// @formatter:off
+				"<s:Tag one=\"1\"\n" +
+				"\ttwo=\"2\"/>",
+				// @formatter:on
+				result);
+	}
+
+	@Test
+	public void testMXMLAlignAttributes() {
+		FORMATTER formatter = new FORMATTER();
+		formatter.insertSpaces = false;
+		formatter.mxmlInsertNewLineBetweenAttributes = true;
+		formatter.mxmlAlignAttributes = true;
+		String result = formatter.formatMXMLText(
+		// @formatter:off
+			"<s:Tag one=\"1\" two=\"2\" three=\"3\"/>",
+			// @formatter:on
+			problems
+		);
+		assertEquals(
+		// @formatter:off
+				"<s:Tag one=\"1\"\n" +
+				"\t   two=\"2\"\n" +
+				"\t   three=\"3\"/>",
+				// @formatter:on
+				result);
+	}
 }
\ No newline at end of file