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