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

matthiasblaesing pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 94fa014  Exclude less (@{}) and scss (#{}) string interpolation from 
formatting
     new a92befa  Merge pull request #3314 from matthiasblaesing/css_formatting2
94fa014 is described below

commit 94fa014e810fe0f153bb951a3a0ac1bfe6f3b2cf
Author: Matthias Bläsing <mblaes...@doppel-helix.eu>
AuthorDate: Wed Nov 10 21:12:02 2021 +0100

    Exclude less (@{}) and scss (#{}) string interpolation from formatting
---
 ide/css.editor/nbproject/project.properties        |   4 +-
 .../modules/css/editor/indent/CssIndentTask.java   | 124 ++++++++++++---------
 .../test/unit/data/testfiles/case005.less          |   1 +
 .../unit/data/testfiles/case005.less.formatted     |   5 +
 .../test/unit/data/testfiles/case006.scss          |   6 +
 .../unit/data/testfiles/case006.scss.formatted     |   8 ++
 .../modules/css/editor/indent/CssIndenterTest.java |   6 +-
 .../css/editor/indent/LessIndenterTest.java        |  55 +++++++++
 .../css/editor/indent/ScssIndenterTest.java        |  58 ++++++++++
 9 files changed, 213 insertions(+), 54 deletions(-)

diff --git a/ide/css.editor/nbproject/project.properties 
b/ide/css.editor/nbproject/project.properties
index ca4bfda..91a7d02 100644
--- a/ide/css.editor/nbproject/project.properties
+++ b/ide/css.editor/nbproject/project.properties
@@ -15,6 +15,8 @@
 # specific language governing permissions and limitations
 # under the License.
 
+auxiliary.org-netbeans-modules-css-prep.less_2e_configured=true
+auxiliary.org-netbeans-modules-css-prep.sass_2e_configured=true
 release.external/css21-spec.zip=docs/css21-spec.zip
 release.external/css3-spec.zip=docs/css3-spec.zip
 
@@ -33,4 +35,4 @@ test.config.stableBTD.excludes=\
     **/properties/parser/PropertyValueTest.class,\
     **/CssBracketCompleterTest.class
 
-test-unit-sys-prop.netbeans.dirs=${netbeans.dest.dir}/${nb.cluster.ide.dir}
\ No newline at end of file
+test-unit-sys-prop.netbeans.dirs=${netbeans.dest.dir}/${nb.cluster.ide.dir}
diff --git 
a/ide/css.editor/src/org/netbeans/modules/css/editor/indent/CssIndentTask.java 
b/ide/css.editor/src/org/netbeans/modules/css/editor/indent/CssIndentTask.java
index e6bf851..dfb9977 100644
--- 
a/ide/css.editor/src/org/netbeans/modules/css/editor/indent/CssIndentTask.java
+++ 
b/ide/css.editor/src/org/netbeans/modules/css/editor/indent/CssIndentTask.java
@@ -21,6 +21,7 @@ package org.netbeans.modules.css.editor.indent;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.LinkedList;
 import javax.swing.text.BadLocationException;
 import org.netbeans.api.lexer.Token;
 import org.netbeans.api.lexer.TokenHierarchy;
@@ -94,37 +95,76 @@ public class CssIndentTask implements IndentTask, 
Lookup.Provider {
                 .get(context.document())
                 .embeddedTokenSequences(reg.getStartOffset(), false);
             TokenSequence<?> ts = tslist.get(tslist.size() - 1);
-            int blockLevel = determineBlocklevel(ts);
+
+            LinkedList<IndentType> blockLevel = new LinkedList<>();
+
+            // Initialize blockLevel with the indentions created by the
+            // outside context
+            ts.moveStart();
+            Token lastToken = null;
+            if (ts.moveNext()) {
+                List<TokenSequence<?>> tokenSequences = TokenHierarchy
+                        .get(context.document())
+                        .tokenSequenceList(ts.languagePath(), 0, ts.offset());
+                OUTER:
+                for (TokenSequence tsX : tokenSequences) {
+                    tsX.moveStart();
+                    while (tsX.moveNext()) {
+                        if (tsX.offset() >= ts.offset()) {
+                            break OUTER;
+                        }
+                        if (tsX.token().id() == CssTokenId.LBRACE) {
+                            if (isStringInterpolation(lastToken)) {
+                                // The sequence "@{" and "#{" lead in a strong 
interpolation
+                                // in LESS (former) and SCSS (latter).
+                                blockLevel.addLast(IndentType.NONE);
+                            } else {
+                                blockLevel.addLast(IndentType.BLOCK);
+                            }
+                        } else if (tsX.token().id() == CssTokenId.RBRACE) {
+                            blockLevel.pollLast();
+                        }
+                        lastToken = tsX.token();
+                    }
+                }
+            }
+
             ts.moveStart();
             while(ts.moveNext()) {
                 if(ts.token().id() == CssTokenId.LBRACE) {
-                    blockLevel++;
-                    // Ensure, that there is a newline after an block opening
-                    // brace "{"
-                    if(LexerUtils.followsToken(ts, CssTokenId.NL, false, true, 
CssTokenId.WS, CssTokenId.COMMENT) == null) {
-                        while(ts.moveNext()) {
-                            if (ts.token().id() != CssTokenId.WS && 
ts.token().id() != CssTokenId.COMMENT) {
-                                newlinesMissing.add(ts.offset());
-                                ts.movePrevious();
-                                break;
+                    if(! isStringInterpolation(lastToken)) {
+                        blockLevel.add(IndentType.BLOCK);
+                        // Ensure, that there is a newline after an block 
opening
+                        // brace "{"
+                        if(LexerUtils.followsToken(ts, CssTokenId.NL, false, 
true, CssTokenId.WS, CssTokenId.COMMENT) == null) {
+                            while(ts.moveNext()) {
+                                if (ts.token().id() != CssTokenId.WS && 
ts.token().id() != CssTokenId.COMMENT) {
+                                    newlinesMissing.add(ts.offset());
+                                    ts.movePrevious();
+                                    break;
+                                }
                             }
                         }
+                    } else {
+                        blockLevel.add(IndentType.NONE);
                     }
                 } else if (ts.token().id() == CssTokenId.RBRACE) {
-                    blockLevel--;
-                    // Ensure, that there is a newline before an block closing
-                    // brace "}"
-                    if (LexerUtils.followsToken(ts, CssTokenId.NL, true, true, 
CssTokenId.WS, CssTokenId.COMMENT) == null) {
-                        newlinesMissing.add(ts.offset());
-                    }
-                    // Ensure, that there is a newline after an block closing
-                    // brace "}"
-                    if (LexerUtils.followsToken(ts, CssTokenId.NL, false, 
true, CssTokenId.WS, CssTokenId.COMMENT) == null) {
-                        while(ts.moveNext()) {
-                            if (ts.token().id() != CssTokenId.WS && 
ts.token().id() != CssTokenId.COMMENT) {
-                                newlinesMissing.add(ts.offset());
-                                ts.movePrevious();
-                                break;
+                    IndentType it = blockLevel.removeLast();
+                    if (it == IndentType.BLOCK) {
+                        // Ensure, that there is a newline before an block 
closing
+                        // brace "}"
+                        if (LexerUtils.followsToken(ts, CssTokenId.NL, true, 
true, CssTokenId.WS, CssTokenId.COMMENT) == null) {
+                            newlinesMissing.add(ts.offset());
+                        }
+                        // Ensure, that there is a newline after an block 
closing
+                        // brace "}"
+                        if (LexerUtils.followsToken(ts, CssTokenId.NL, false, 
true, CssTokenId.WS, CssTokenId.COMMENT) == null) {
+                            while (ts.moveNext()) {
+                                if (ts.token().id() != CssTokenId.WS && 
ts.token().id() != CssTokenId.COMMENT) {
+                                    newlinesMissing.add(ts.offset());
+                                    ts.movePrevious();
+                                    break;
+                                }
                             }
                         }
                     }
@@ -133,7 +173,7 @@ public class CssIndentTask implements IndentTask, 
Lookup.Provider {
                     // (between property definitions). This should only be done
                     // in regular CSS definitions (rules), but not in inline
                     // style definitions
-                    if (blockLevel > 0 && LexerUtils.followsToken(ts, 
asList(CssTokenId.NL, CssTokenId.RBRACE), false, true, CssTokenId.WS, 
CssTokenId.COMMENT) == null) {
+                    if (!blockLevel.isEmpty() && LexerUtils.followsToken(ts, 
asList(CssTokenId.NL, CssTokenId.RBRACE), false, true, CssTokenId.WS, 
CssTokenId.COMMENT) == null) {
                         while (ts.moveNext()) {
                             if (ts.token().id() != CssTokenId.WS && 
ts.token().id() != CssTokenId.COMMENT) {
                                 newlinesMissing.add(ts.offset());
@@ -143,6 +183,7 @@ public class CssIndentTask implements IndentTask, 
Lookup.Provider {
                         }
                     }
                 }
+                lastToken = ts.token();
             }
         }
         // Remove newline insertions if
@@ -162,6 +203,10 @@ public class CssIndentTask implements IndentTask, 
Lookup.Provider {
         }
     }
 
+    private static boolean isStringInterpolation(Token lastToken) {
+        return lastToken != null && (lastToken.id() == CssTokenId.AT_SIGN || 
lastToken.id() == CssTokenId.HASH_SYMBOL);
+    }
+
     private boolean isPositionInFormatRegions(int pos) {
         for(Region r: context.indentRegions()) {
             if(r.getStartOffset() <= pos && r.getEndOffset() > pos) {
@@ -170,31 +215,6 @@ public class CssIndentTask implements IndentTask, 
Lookup.Provider {
         }
         return false;
     }
-    
-    private int determineBlocklevel(TokenSequence<?> ts) {
-        int blockLevel = 0;
-        ts.moveStart();
-        if (!ts.moveNext()) {
-            return 0;
-        }
-        List<TokenSequence<?>> tokenSequences = TokenHierarchy
-            .get(context.document())
-            .tokenSequenceList(ts.languagePath(), 0, ts.offset());
-        OUTER: for(TokenSequence tsX: tokenSequences) {
-            tsX.moveStart();
-            while(tsX.moveNext()) {
-                if(tsX.offset() >= ts.offset()) {
-                    break OUTER;
-                }
-                if(tsX.token().id() == CssTokenId.LBRACE) {
-                    blockLevel++;
-                } else if (tsX.token().id() == CssTokenId.RBRACE) {
-                    blockLevel--;
-                }
-            }
-        }
-        return blockLevel;
-    }
 
     @Override
     public ExtraLock indentLock() {
@@ -206,4 +226,8 @@ public class CssIndentTask implements IndentTask, 
Lookup.Provider {
         return lookup;
     }
 
+    private static enum IndentType {
+        NONE,
+        BLOCK
+    }
 }
diff --git a/ide/css.editor/test/unit/data/testfiles/case005.less 
b/ide/css.editor/test/unit/data/testfiles/case005.less
new file mode 100644
index 0000000..88439f0
--- /dev/null
+++ b/ide/css.editor/test/unit/data/testfiles/case005.less
@@ -0,0 +1 @@
+.@{my-selector} { font-weight: bold; line-height: 40px; margin: 0 auto; }
diff --git a/ide/css.editor/test/unit/data/testfiles/case005.less.formatted 
b/ide/css.editor/test/unit/data/testfiles/case005.less.formatted
new file mode 100644
index 0000000..f6648e6
--- /dev/null
+++ b/ide/css.editor/test/unit/data/testfiles/case005.less.formatted
@@ -0,0 +1,5 @@
+.@{my-selector} {
+    font-weight: bold;
+    line-height: 40px;
+    margin: 0 auto;
+}
\ No newline at end of file
diff --git a/ide/css.editor/test/unit/data/testfiles/case006.scss 
b/ide/css.editor/test/unit/data/testfiles/case006.scss
new file mode 100644
index 0000000..5abfb9a
--- /dev/null
+++ b/ide/css.editor/test/unit/data/testfiles/case006.scss
@@ -0,0 +1,6 @@
+@mixin corner-icon($name, $top-or-bottom, $left-or-right) {
+    .icon-#{$name} {
+        background-image: url("/icons/#{$name}.svg"); position: absolute;
+        #{$top-or-bottom}: 0; #{$left-or-right}: 0;
+    }
+}
\ No newline at end of file
diff --git a/ide/css.editor/test/unit/data/testfiles/case006.scss.formatted 
b/ide/css.editor/test/unit/data/testfiles/case006.scss.formatted
new file mode 100644
index 0000000..3b21956
--- /dev/null
+++ b/ide/css.editor/test/unit/data/testfiles/case006.scss.formatted
@@ -0,0 +1,8 @@
+@mixin corner-icon($name, $top-or-bottom, $left-or-right) {
+    .icon-#{$name} {
+        background-image: url("/icons/#{$name}.svg");
+        position: absolute;
+        #{$top-or-bottom}: 0;
+        #{$left-or-right}: 0;
+    }
+}
\ No newline at end of file
diff --git 
a/ide/css.editor/test/unit/src/org/netbeans/modules/css/editor/indent/CssIndenterTest.java
 
b/ide/css.editor/test/unit/src/org/netbeans/modules/css/editor/indent/CssIndenterTest.java
index 609d863..1e4c423 100644
--- 
a/ide/css.editor/test/unit/src/org/netbeans/modules/css/editor/indent/CssIndenterTest.java
+++ 
b/ide/css.editor/test/unit/src/org/netbeans/modules/css/editor/indent/CssIndenterTest.java
@@ -186,7 +186,7 @@ public class CssIndenterTest extends TestBase {
     public void testPartitialFormatting() throws Exception {
         IndentPrefs preferences = new IndentPrefs(4, 4);
         String file = "testfiles/partialformatting.css";
-        
+
         FileObject fo = getTestFile(file);
         assertNotNull(fo);
         BaseDocument doc = getDocument(fo);
@@ -201,14 +201,14 @@ public class CssIndenterTest extends TestBase {
         assertDescriptionMatches(file, after, false, ".formatted");
 
         DataObject.find(fo).getLookup().lookup(Closable.class).close();
-        
+
         doc = getDocument(fo);
         setupDocumentIndentation(doc, preferences);
         format(doc, formatter, 857, 904, false);
         after = doc.getText(0, doc.getLength());
         assertDescriptionMatches(file, after, false, ".formatted2");
     }
-    
+
     public void testIndentation() throws Exception {
         // property indentation:
         insertNewline("a{^background: red;\n  }\n", "a{\n    ^background: 
red;\n  }\n", null);
diff --git 
a/ide/css.editor/test/unit/src/org/netbeans/modules/css/editor/indent/LessIndenterTest.java
 
b/ide/css.editor/test/unit/src/org/netbeans/modules/css/editor/indent/LessIndenterTest.java
new file mode 100644
index 0000000..0d45596
--- /dev/null
+++ 
b/ide/css.editor/test/unit/src/org/netbeans/modules/css/editor/indent/LessIndenterTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.netbeans.modules.css.editor.indent;
+
+import org.netbeans.modules.css.editor.test.*;
+import org.netbeans.modules.csl.api.Formatter;
+import org.netbeans.modules.csl.api.test.CslTestBase;
+import org.netbeans.modules.csl.spi.DefaultLanguageConfig;
+import org.netbeans.modules.css.editor.csl.CssLanguage;
+
+
+public class LessIndenterTest extends CslTestBase {
+
+    private static final String PROP_MIME_TYPE = "mimeType"; //NOI18N
+
+    public LessIndenterTest(String name) {
+        super(name);
+    }
+
+    @Override
+    protected DefaultLanguageConfig getPreferredLanguage() {
+        return new CssLanguage();
+    }
+
+    @Override
+    protected String getPreferredMimeType() {
+        return "text/less";
+    }
+
+    @Override
+    public Formatter getFormatter(IndentPrefs preferences) {
+        return null;
+    }
+
+    public void testFormattingCase5() throws Exception {
+        reformatFileContents("testfiles/case005.less", new IndentPrefs(4, 4));
+    }
+
+}
diff --git 
a/ide/css.editor/test/unit/src/org/netbeans/modules/css/editor/indent/ScssIndenterTest.java
 
b/ide/css.editor/test/unit/src/org/netbeans/modules/css/editor/indent/ScssIndenterTest.java
new file mode 100644
index 0000000..66901eb
--- /dev/null
+++ 
b/ide/css.editor/test/unit/src/org/netbeans/modules/css/editor/indent/ScssIndenterTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.netbeans.modules.css.editor.indent;
+
+import org.netbeans.editor.BaseDocument;
+import org.netbeans.modules.csl.api.Formatter;
+import org.netbeans.modules.csl.api.test.CslTestBase;
+import org.netbeans.modules.csl.spi.DefaultLanguageConfig;
+import org.netbeans.modules.css.editor.csl.CssLanguage;
+import org.netbeans.modules.css.lib.TestUtil;
+import org.netbeans.modules.parsing.api.Source;
+import org.openide.filesystems.FileObject;
+
+
+public class ScssIndenterTest extends CslTestBase {
+
+    private static final String PROP_MIME_TYPE = "mimeType"; //NOI18N
+
+    public ScssIndenterTest(String name) {
+        super(name);
+    }
+
+    @Override
+    protected DefaultLanguageConfig getPreferredLanguage() {
+        return new CssLanguage();
+    }
+
+    @Override
+    protected String getPreferredMimeType() {
+        return "text/scss";
+    }
+
+    @Override
+    public Formatter getFormatter(IndentPrefs preferences) {
+        return null;
+    }
+
+    public void testFormattingCase6() throws Exception {
+        reformatFileContents("testfiles/case006.scss", new IndentPrefs(4, 4));
+    }
+
+}

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org
For additional commands, e-mail: commits-h...@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to