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 b9590a7  [NETBEANS-6328] avoid IllegalArgumentException in 
FoldManagerImpl
     new 5b265f9  Merge pull request #3385 from MKuettner/lsp-improvements
b9590a7 is described below

commit b9590a77f48d51847d78d12695910a59948b3269
Author: MKuettner <cutter....@gmx.de>
AuthorDate: Wed Dec 22 11:02:30 2021 +0100

    [NETBEANS-6328] avoid IllegalArgumentException in FoldManagerImpl
    
    Extracts FoldInfo list computation into a new method in order to be
    testable in unit tests. Adds some unit tests.
    Introduces Utils.getEndCharacter(..) that gets last character index of
    given line.
    Changes FoldInfo calculation in case of FoldingRanges endCharacter is
    NULL.
---
 .../src/org/netbeans/modules/lsp/client/Utils.java |  10 ++
 .../lsp/client/bindings/FoldManagerImpl.java       |  41 +++---
 .../lsp/client/bindings/FoldManagerImplTest.java   | 150 +++++++++++++++++++++
 3 files changed, 184 insertions(+), 17 deletions(-)

diff --git a/ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java
index d8f36fb..746eff4 100644
--- a/ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java
+++ b/ide/lsp.client/src/org/netbeans/modules/lsp/client/Utils.java
@@ -79,6 +79,16 @@ public class Utils {
     public static int getOffset(Document doc, Position pos) {
         return LineDocumentUtils.getLineStartFromIndex((LineDocument) doc, 
pos.getLine()) + pos.getCharacter();
     }
+    
+    public static int getEndCharacter(Document doc, int line) {
+        int start = LineDocumentUtils.getLineStartFromIndex((LineDocument) 
doc, line);
+        try {
+            return LineDocumentUtils.getLineEnd((LineDocument) doc, start) - 
start;
+        } catch (BadLocationException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+        return 0;
+    }
 
     public static void applyWorkspaceEdit(WorkspaceEdit edit) {
         if (edit.getDocumentChanges() != null) {
diff --git 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/FoldManagerImpl.java
 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/FoldManagerImpl.java
index 168a009..f9fd065 100644
--- 
a/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/FoldManagerImpl.java
+++ 
b/ide/lsp.client/src/org/netbeans/modules/lsp/client/bindings/FoldManagerImpl.java
@@ -113,23 +113,40 @@ public class FoldManagerImpl implements FoldManager, 
BackgroundTask {
         EditorCookie ec = file.getLookup().lookup(EditorCookie.class);
         Document doc = ec != null ? ec.getDocument() : null;
         if (doc == null) {
-            return ;
+            return;
         }
-        Set<FoldingRangeInfo2> foldingRangesSeen = new HashSet<>();
+
         List<FoldingRange> ranges = computeRanges(bindings, file);
+        List<FoldInfo> infos = computeInfos(doc, ranges);
+        SwingUtilities.invokeLater(() -> {
+            doc.render(() -> {
+                operation.getHierarchy().render(() -> {
+                    try {
+                        operation.update(infos, null, null);
+                    } catch (BadLocationException ex) {
+                        LOG.log(Level.FINE, null, ex);
+                    }
+                });
+            });
+        });
+    }
+    
+    static List<FoldInfo> computeInfos(Document doc, List<FoldingRange> 
ranges) {
+        Set<FoldingRangeInfo2> foldingRangesSeen = new HashSet<>();
         List<FoldInfo> infos = new ArrayList<>();
         if (ranges != null) {
             for (FoldingRange r : ranges) {
                 int start = Utils.getOffset(doc, new 
Position(r.getStartLine(), r.getStartCharacter() != null ? 
r.getStartCharacter() : 0));
                 int end;
                 if (r.getEndCharacter() == null) {
-                    end = Utils.getOffset(doc, new Position(r.getEndLine() + 
1, 0)) - 1;
+                    int endCharacter = Utils.getEndCharacter(doc, 
r.getEndLine());
+                    end = Utils.getOffset(doc, new Position(r.getEndLine(), 
endCharacter));
                 } else {
                     end = Utils.getOffset(doc, new Position(r.getEndLine(), 
r.getEndCharacter()));
                 }
                 // Map the fold range type to netbeans as far as possible
                 FoldType foldType;
-                if("comment".equals(r.getKind())) {
+                if ("comment".equals(r.getKind())) {
                     foldType = FoldType.COMMENT;
                 } else if ("imports".equals(r.getKind())) {
                     foldType = FoldType.IMPORT;
@@ -137,25 +154,15 @@ public class FoldManagerImpl implements FoldManager, 
BackgroundTask {
                     foldType = FoldType.CODE_BLOCK;
                 }
                 FoldingRangeInfo2 fri2 = new FoldingRangeInfo2(start, end, 
foldType);
-                if(! foldingRangesSeen.contains(fri2)) {
+                if (!foldingRangesSeen.contains(fri2)) {
                     infos.add(FoldInfo.range(start, end, foldType));
                     foldingRangesSeen.add(fri2);
                 }
             }
         }
-        SwingUtilities.invokeLater(() -> {
-            doc.render(() -> {
-                operation.getHierarchy().render(() -> {
-                    try {
-                        operation.update(infos, null, null);
-                    } catch (BadLocationException ex) {
-                        LOG.log(Level.FINE, null, ex);
-                    }
-                });
-            });
-        });
+        return infos;
     }
-
+   
     static List<FoldingRange> computeRanges(LSPBindings bindings, FileObject 
file) {
         if (bindings.getInitResult() != null &&
             bindings.getInitResult().getCapabilities() != null &&
diff --git 
a/ide/lsp.client/test/unit/src/org/netbeans/modules/lsp/client/bindings/FoldManagerImplTest.java
 
b/ide/lsp.client/test/unit/src/org/netbeans/modules/lsp/client/bindings/FoldManagerImplTest.java
new file mode 100644
index 0000000..449cbe0
--- /dev/null
+++ 
b/ide/lsp.client/test/unit/src/org/netbeans/modules/lsp/client/bindings/FoldManagerImplTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.lsp.client.bindings;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.text.Document;
+import org.eclipse.lsp4j.FoldingRange;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import org.junit.Test;
+import org.netbeans.editor.BaseDocument;
+import org.netbeans.spi.editor.fold.FoldInfo;
+
+/**
+ * Unit tests for FoldManagerImpl.
+ *
+ * @author MKuettner
+ */
+public class FoldManagerImplTest {
+
+    private static final String EXAMPLE_SIMPLE = "line 1\n"
+            + "line 2\n"
+            + "line 3\n"
+            + "line 4\n"
+            + "line 5\n";
+
+    private static final String EXAMPLE_PY_NEWLINE = "from pattern_imports 
import *\n"
+            + "\n"
+            + "def call(interface):\n"
+            + "    \"\"\"\n"
+            + "    \"\"\"\n"
+            + "    print(\"Dummy call was called!\")\n"
+            + "";
+
+    private static final String EXAMPLE_PY_NO_NEWLINE = "from pattern_imports 
import *\n"
+            + "\n"
+            + "def call(interface):\n"
+            + "    \"\"\"\n"
+            + "    \"\"\"\n"
+            + "    print(\"Dummy call was called!\")";
+
+    @Test
+    public void computeFoldInfosWithoutStartEndCharacterTest() throws 
Exception {
+        Document doc = createDocument(EXAMPLE_SIMPLE);
+
+        List<FoldingRange> ranges = new ArrayList<>();
+        ranges.add(new FoldingRange(0, 2));
+
+        List<FoldInfo> infos = FoldManagerImpl.computeInfos(doc, ranges);
+        assertEquals(1, infos.size());
+        assertEquals(0, infos.get(0).getStart());
+        assertEquals(20, infos.get(0).getEnd());
+    }
+
+    @Test
+    public void computeFoldInfosWithStartEndCharacterTest() throws Exception {
+        Document doc = createDocument(EXAMPLE_SIMPLE);
+
+        FoldingRange range = new FoldingRange(0, 2);
+        range.setStartCharacter(0);
+        range.setEndCharacter(6);
+
+        List<FoldingRange> ranges = new ArrayList<>();
+        ranges.add(range);
+
+        List<FoldInfo> infos = FoldManagerImpl.computeInfos(doc, ranges);
+        assertEquals(1, infos.size());
+        assertEquals(0, infos.get(0).getStart());
+        assertEquals(20, infos.get(0).getEnd());
+    }
+
+    @Test
+    public void computeFoldInfosDuplicateFoldTest() throws Exception {
+        Document doc = createDocument(EXAMPLE_SIMPLE);
+
+        List<FoldingRange> ranges = new ArrayList<>();
+        // duplicate ranges
+        ranges.add(new FoldingRange(0, 2));
+        ranges.add(new FoldingRange(0, 2));
+        ranges.add(new FoldingRange(0, 2));
+
+        List<FoldInfo> infos = FoldManagerImpl.computeInfos(doc, ranges);
+        assertEquals(1, infos.size());
+    }
+
+    @Test
+    public void computeFoldInfosDocEndsWithNewlineTest() throws Exception {
+        Document doc = createDocument(EXAMPLE_PY_NEWLINE);
+        List<FoldInfo> infos = FoldManagerImpl.computeInfos(doc, 
computeRanges());
+        assertFoldInfos(infos);
+    }
+
+    /**
+     * Test to reproduce https://issues.apache.org/jira/browse/NETBEANS-6328
+     */
+    @Test
+    public void computeFoldInfosFoldUntilEndOfDocTest() throws Exception {
+        Document doc = createDocument(EXAMPLE_PY_NO_NEWLINE);
+        List<FoldInfo> infos = FoldManagerImpl.computeInfos(doc, 
computeRanges());
+        assertFoldInfos(infos);
+    }
+
+    private void assertFoldInfos(List<FoldInfo> infos) {
+        assertNotNull(infos);
+        assertEquals(2, infos.size());
+        // first fold
+        assertEquals(31, infos.get(0).getStart());
+        assertEquals(103, infos.get(0).getEnd());
+        // second fold
+        assertEquals(52, infos.get(1).getStart());
+        assertEquals(67, infos.get(1).getEnd());
+    }
+
+    /**
+     * Returns a fixed list of FoldingRanges comming e.g. from language server.
+     */
+    private List<FoldingRange> computeRanges() {
+        List<FoldingRange> ranges = new ArrayList<>();
+        // original ranges from language server
+        ranges.add(new FoldingRange(2, 5));
+        ranges.add(new FoldingRange(3, 4));
+        return ranges;
+    }
+
+    /**
+     * Creates a test Document from gievn content.
+     */
+    private Document createDocument(String content) throws Exception {
+        BaseDocument doc = new BaseDocument(true, "text/python");
+        doc.insertString(0, content, null);
+        return doc;
+    }
+}

---------------------------------------------------------------------
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