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 15d4b7ba3d0f8252cbee512be6b10d06e9ece128
Author: Josh Tynjala <[email protected]>
AuthorDate: Thu Oct 28 14:08:46 2021 -0700

    formatter: MXML whitespace improvements
---
 .../org/apache/royale/formatter/FORMATTER.java     |  94 ++++++---
 .../org/apache/royale/formatter/TestMXMLTag.java   | 214 +++++++++++++++++++++
 2 files changed, 286 insertions(+), 22 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 31d30cd..132c246 100644
--- a/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java
+++ b/formatter/src/main/java/org/apache/royale/formatter/FORMATTER.java
@@ -1677,7 +1677,18 @@ public class FORMATTER {
                                prevTokenOrExtra = token;
                                continue;
                        } else if (token.getType() == 
MXMLTokenTypes.TOKEN_WHITESPACE) {
-                               numRequiredNewLines = 
Math.max(numRequiredNewLines, countNewLinesInExtra(token));
+                               if(elementStack.isEmpty() || 
!elementStack.get(elementStack.size() - 1).containsText) {
+                                       numRequiredNewLines = 
Math.max(numRequiredNewLines, countNewLinesInExtra(token));
+                               }
+                               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
+                                       // without collapsing whitespace, and 
developers would be
+                                       // confused if whitespace that they 
deliberately added were
+                                       // to be removed
+                                       builder.append(token.getText());
+                               }
                                if (i == (tokens.size() - 1)) {
                                        // if the last token is whitespace, 
append new lines
                                        appendNewLines(builder, 
numRequiredNewLines);
@@ -1721,18 +1732,16 @@ public class FORMATTER {
                        // characters that must appear before the token
                        switch (token.getType()) {
                                case MXMLTokenTypes.TOKEN_OPEN_TAG_START: {
-                                       if (prevToken == null || 
prevToken.getType() != MXMLTokenTypes.TOKEN_TEXT) {
-                                               numRequiredNewLines = 
Math.max(numRequiredNewLines, 1);
-                                       }
                                        inOpenTag = true;
-                                       elementStack.add(new 
ElementStackItem(token.getText().substring(1)));
+                                       // if the parent contains text, 
children should be the same
+                                       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 (prevToken == null || 
prevToken.getType() != MXMLTokenTypes.TOKEN_TEXT) {
-                                               numRequiredNewLines = 
Math.max(numRequiredNewLines, 1);
+                                       if(elementStack.isEmpty() || 
!elementStack.get(elementStack.size() - 1).containsText) {
+                                               indent = decreaseIndent(indent);
                                        }
-                                       indent = decreaseIndent(indent);
                                        inCloseTag = true;
                                        break;
                                }
@@ -1740,12 +1749,6 @@ public class FORMATTER {
                                        requiredSpace = true;
                                        break;
                                }
-                               case MXMLTokenTypes.TOKEN_TAG_END: {
-                                       break;
-                               }
-                               case MXMLTokenTypes.TOKEN_EMPTY_TAG_END: {
-                                       break;
-                               }
                        }
 
                        if (prevToken != null) {
@@ -1762,6 +1765,8 @@ public class FORMATTER {
                        }
 
                        // include the token's own text
+                       // no token gets reformatted before being appended
+                       // whitespace is the only special case, but that's not 
handled here
                        builder.append(token.getText());
 
                        // characters that must appear after the token
@@ -1798,11 +1803,19 @@ public class FORMATTER {
                                        break;
                                }
                                case MXMLTokenTypes.TOKEN_TAG_END: {
-                                       if (!inOpenTag || nextToken == null || 
nextToken.getType() != MXMLTokenTypes.TOKEN_TEXT) {
-                                               numRequiredNewLines = 
Math.max(numRequiredNewLines, 1);
-                                       }
                                        if (inOpenTag) {
-                                               indent = increaseIndent(indent);
+                                               ElementStackItem element = 
elementStack.get(elementStack.size() - 1);
+                                               if (!element.containsText) {
+                                                       element.containsText = 
elementContainsText(tokens, i + 1, element.token);
+                                               }
+                                               if(elementStack.isEmpty() || 
!elementStack.get(elementStack.size() - 1).containsText) {
+                                                       indent = 
increaseIndent(indent);
+                                               }
+                                       }
+                                       else {
+                                               if(elementStack.isEmpty() || 
!elementStack.get(elementStack.size() - 1).containsText) {
+                                                       numRequiredNewLines = 
Math.max(numRequiredNewLines, 1);
+                                               }
                                        }
                                        inOpenTag = false;
                                        if (indentedAttributes) {
@@ -1813,12 +1826,14 @@ public class FORMATTER {
                                        break;
                                }
                                case MXMLTokenTypes.TOKEN_EMPTY_TAG_END: {
-                                       if (!inOpenTag || nextToken == null || 
nextToken.getType() != MXMLTokenTypes.TOKEN_TEXT) {
-                                               numRequiredNewLines = 
Math.max(numRequiredNewLines, 1);
-                                       }
                                        if (inOpenTag) {
                                                
elementStack.remove(elementStack.size() - 1);
                                        }
+                                       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
@@ -1839,6 +1854,37 @@ public class FORMATTER {
                return builder.toString();
        }
 
+       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++) {
+                       IMXMLToken token = tokens.get(i);
+                       switch(token.getType()) {
+                               case MXMLTokenTypes.TOKEN_TEXT:
+                                       if(elementStack.size() == 1) {
+                                               return true;
+                                       }
+                                       break;
+                               case MXMLTokenTypes.TOKEN_OPEN_TAG_START:
+                                       elementStack.add(token);
+                                       break;
+                               case MXMLTokenTypes.TOKEN_EMPTY_TAG_END:
+                                       elementStack.remove(elementStack.size() 
- 1);
+                                       if(elementStack.size() == 0) {
+                                               return false;
+                                       }
+                                       break;
+                               case MXMLTokenTypes.TOKEN_CLOSE_TAG_START:
+                                       elementStack.remove(elementStack.size() 
- 1);
+                                       if(elementStack.size() == 0) {
+                                               return false;
+                                       }
+                                       break;
+                       }
+               }
+               return false;
+       }
+
        private int countNewLinesInExtra(IMXMLToken token) {
                if (token == null
                                || (token.getType() != 
MXMLTokenTypes.TOKEN_WHITESPACE && token.getType() != TOKEN_TYPE_EXTRA)) {
@@ -1854,10 +1900,14 @@ public class FORMATTER {
        }
 
        private static class ElementStackItem {
-               public ElementStackItem(String elementName) {
+               public ElementStackItem(IMXMLToken token, String elementName, 
boolean containsText) {
+                       this.token = token;
                        this.elementName = elementName;
+                       this.containsText = containsText;
                }
 
+               public IMXMLToken token;
                public String elementName;
+               public boolean containsText = false;
        }
 }
\ No newline at end of file
diff --git 
a/formatter/src/test/java/org/apache/royale/formatter/TestMXMLTag.java 
b/formatter/src/test/java/org/apache/royale/formatter/TestMXMLTag.java
new file mode 100644
index 0000000..8096322
--- /dev/null
+++ b/formatter/src/test/java/org/apache/royale/formatter/TestMXMLTag.java
@@ -0,0 +1,214 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package org.apache.royale.formatter;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class TestMXMLTag extends BaseFormatterTests {
+       @Test
+       public void testSelfClosingTag() {
+               FORMATTER formatter = new FORMATTER();
+               formatter.insertSpaces = false;
+               String result = formatter.formatMXMLText(
+               // @formatter:off
+                       "<s:Tag/>",
+                       // @formatter:on
+                       problems
+               );
+               assertEquals(
+               // @formatter:off
+                               "<s:Tag/>",
+                               // @formatter:on
+                               result);
+       }
+
+       @Test
+       public void testTagWithEmptyText() {
+               FORMATTER formatter = new FORMATTER();
+               formatter.insertSpaces = false;
+               String result = formatter.formatMXMLText(
+               // @formatter:off
+                       "<s:Tag></s:Tag>",
+                       // @formatter:on
+                       problems
+               );
+               assertEquals(
+               // @formatter:off
+                               "<s:Tag></s:Tag>",
+                               // @formatter:on
+                               result);
+       }
+
+       @Test
+       public void testTagWithText() {
+               FORMATTER formatter = new FORMATTER();
+               formatter.insertSpaces = false;
+               String result = formatter.formatMXMLText(
+               // @formatter:off
+                       "<s:Tag>Hello World</s:Tag>",
+                       // @formatter:on
+                       problems
+               );
+               assertEquals(
+               // @formatter:off
+                               "<s:Tag>Hello World</s:Tag>",
+                               // @formatter:on
+                               result);
+       }
+
+       @Test
+       public void testTagWithTextAndNewLines() {
+               FORMATTER formatter = new FORMATTER();
+               formatter.insertSpaces = false;
+               String result = formatter.formatMXMLText(
+               // @formatter:off
+                       "<s:Tag>\n" +
+                       "\tHello World\n" +
+                       "</s:Tag>",
+                       // @formatter:on
+                       problems
+               );
+               assertEquals(
+               // @formatter:off
+                               "<s:Tag>\n" +
+                               "\tHello World\n" +
+                               "</s:Tag>",
+                               // @formatter:on
+                               result);
+       }
+
+       @Test
+       public void testTagWithNewLineText() {
+               FORMATTER formatter = new FORMATTER();
+               formatter.insertSpaces = false;
+               String result = formatter.formatMXMLText(
+               // @formatter:off
+                       "<s:Tag>\n" +
+                       "</s:Tag>",
+                       // @formatter:on
+                       problems
+               );
+               assertEquals(
+               // @formatter:off
+                               "<s:Tag>\n" +
+                               "</s:Tag>",
+                               // @formatter:on
+                               result);
+       }
+
+       @Test
+       public void testNewLinesBetweenTags() {
+               FORMATTER formatter = new FORMATTER();
+               formatter.insertSpaces = false;
+               String result = formatter.formatMXMLText(
+               // @formatter:off
+                       "<s:Tag>\n" +
+                       "\n" +
+                       "</s:Tag>\n" +
+                       "\n" +
+                       "<s:Tag/>",
+                       // @formatter:on
+                       problems
+               );
+               assertEquals(
+               // @formatter:off
+                               "<s:Tag>\n" +
+                               "\n" +
+                               "</s:Tag>\n" +
+                               "\n" +
+                               "<s:Tag/>",
+                               // @formatter:on
+                               result);
+       }
+
+       @Test
+       public void testExcessWhitespaceBetweenTags() {
+               FORMATTER formatter = new FORMATTER();
+               formatter.insertSpaces = false;
+               String result = formatter.formatMXMLText(
+               // @formatter:off
+                       "<s:Tag>\t\n" +
+                       "\n\t" +
+                       "\t</s:Tag>",
+                       // @formatter:on
+                       problems
+               );
+               assertEquals(
+               // @formatter:off
+                               "<s:Tag>\n" +
+                               "\n" +
+                               "</s:Tag>",
+                               // @formatter:on
+                               result);
+       }
+
+       @Test
+       public void testMixedTextAndTagChildren1() {
+               FORMATTER formatter = new FORMATTER();
+               formatter.insertSpaces = false;
+               String result = formatter.formatMXMLText(
+               // @formatter:off
+                       "<s:Tag>text <s:Tag/></s:Tag>",
+                       // @formatter:on
+                       problems
+               );
+               assertEquals(
+               // @formatter:off
+                               "<s:Tag>text <s:Tag/></s:Tag>",
+                               // @formatter:on
+                               result);
+       }
+
+       @Test
+       public void testMixedTextAndTagChildren2() {
+               FORMATTER formatter = new FORMATTER();
+               formatter.insertSpaces = false;
+               String result = formatter.formatMXMLText(
+               // @formatter:off
+                       "<s:Tag><s:Tag/> text</s:Tag>",
+                       // @formatter:on
+                       problems
+               );
+               assertEquals(
+               // @formatter:off
+                               "<s:Tag><s:Tag/> text</s:Tag>",
+                               // @formatter:on
+                               result);
+       }
+
+       @Test
+       public void testMixedTextAndTagChildren3() {
+               FORMATTER formatter = new FORMATTER();
+               formatter.insertSpaces = false;
+               String result = formatter.formatMXMLText(
+               // @formatter:off
+                       "<s:Tag><s:Tag/> text <s:Tag/></s:Tag>",
+                       // @formatter:on
+                       problems
+               );
+               assertEquals(
+               // @formatter:off
+                               "<s:Tag><s:Tag/> text <s:Tag/></s:Tag>",
+                               // @formatter:on
+                               result);
+       }
+}
\ No newline at end of file

Reply via email to