diff --git a/bundles/org.eclipse.jface.text/projection/org/eclipse/jface/text/source/projection/ProjectionViewer.java b/bundles/org.eclipse.jface.text/projection/org/eclipse/jface/text/source/projection/ProjectionViewer.java index 34893d66997..5d58ab9ec40 100644 --- a/bundles/org.eclipse.jface.text/projection/org/eclipse/jface/text/source/projection/ProjectionViewer.java +++ b/bundles/org.eclipse.jface.text/projection/org/eclipse/jface/text/source/projection/ProjectionViewer.java @@ -841,24 +841,20 @@ private void collapseOutsideOfNewVisibleRegion(int start, int end, IDocument doc private static int computeEndOfVisibleRegion(int start, int length, IDocument document) throws BadLocationException { int documentLength= document.getLength(); - int end= start + length + 1; - // ensure that trailing whitespace is included - // In this case, the line break needs to be included as well - boolean visibleRegionEndsWithTrailingWhitespace= end < documentLength && isWhitespaceButNotNewline(document.getChar(end - 1)); - while (end < documentLength && isWhitespaceButNotNewline(document.getChar(end))) { + int end= start + length; + // ensure that the last line is fully included because projections cannot include partial lines + while (end < documentLength && !isLineBreak(document.getChar(end))) { end++; - visibleRegionEndsWithTrailingWhitespace= true; } - if (visibleRegionEndsWithTrailingWhitespace && end < documentLength && isLineBreak(document.getChar(end))) { + if (end < documentLength) { + end++; + } + if (end < documentLength && document.getChar(end) == '\n' && document.getChar(end - 1) == '\r') { end++; } return end; } - private static boolean isWhitespaceButNotNewline(char c) { - return Character.isWhitespace(c) && !isLineBreak(c); - } - private static boolean isLineBreak(char c) { return c == '\n' || c == '\r'; } diff --git a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/ProjectionViewerTest.java b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/ProjectionViewerTest.java index e32c54520a7..77832053cc8 100644 --- a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/ProjectionViewerTest.java +++ b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/ProjectionViewerTest.java @@ -16,6 +16,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.Clipboard; @@ -516,4 +518,69 @@ private ProjectionAnnotation addVisibleRegionAndProjection(TestProjectionViewer viewer.getProjectionAnnotationModel().addAnnotation(annotation, new Position(projectionStart, projectionEnd - projectionStart)); return annotation; } + + @ParameterizedTest + @CsvSource({ "true", "false" }) + void testDifferentLineEndings(boolean crlf) { + Shell shell= new Shell(Display.getCurrent()); + shell.setLayout(new FillLayout()); + TestProjectionViewer viewer= new TestProjectionViewer(shell, null, null, true, SWT.ALL); + String documentContent= """ + // before + { + // within + } + // after + """; + if (crlf) { + documentContent= documentContent.replace("\n", "\r\n"); + } + Document document= new Document(documentContent); + viewer.setDocument(document, new AnnotationModel()); + int start= documentContent.indexOf('{'); + int end= documentContent.indexOf('}') + 1; + viewer.enableProjection(); + viewer.setVisibleRegion(start, end - start); + assertEquals(documentContent.substring(start, documentContent.indexOf("// after")), viewer.getVisibleDocument().get()); + } + + @Test + void testIncludesLastLineIfAdditionalTextPresent() { + Shell shell= new Shell(Display.getCurrent()); + shell.setLayout(new FillLayout()); + TestProjectionViewer viewer= new TestProjectionViewer(shell, null, null, true, SWT.ALL); + String documentContent= """ + // before + { + // within + }// ... + // should be hidden + """; + Document document= new Document(documentContent); + viewer.setDocument(document, new AnnotationModel()); + int start= documentContent.indexOf('{'); + int end= documentContent.indexOf('}') + 1; + viewer.enableProjection(); + viewer.setVisibleRegion(start, end - start); + assertEquals(documentContent.substring(start, documentContent.indexOf("// should be hidden")), viewer.getVisibleDocument().get()); + } + + @Test + void testSetVisibleRegionUntilEOF() { + Shell shell= new Shell(Display.getCurrent()); + shell.setLayout(new FillLayout()); + TestProjectionViewer viewer= new TestProjectionViewer(shell, null, null, true, SWT.ALL); + String documentContent= """ + // before + { + // within + }"""; + Document document= new Document(documentContent); + viewer.setDocument(document, new AnnotationModel()); + int start= documentContent.indexOf('{'); + int end= documentContent.indexOf('}') + 1; + viewer.enableProjection(); + viewer.setVisibleRegion(start, end - start); + assertEquals(documentContent.substring(start), viewer.getVisibleDocument().get()); + } }