Skip to content

Commit e3ed532

Browse files
committed
Ensure the last line is included in projection-based visible regions
This change ensures that setting the visible region with projections enabled does not hide the last line in case there is additional text at the end of the line or the file is using Windows line endings.
1 parent d145b2c commit e3ed532

File tree

2 files changed

+74
-11
lines changed

2 files changed

+74
-11
lines changed

bundles/org.eclipse.jface.text/projection/org/eclipse/jface/text/source/projection/ProjectionViewer.java

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -841,24 +841,20 @@ private void collapseOutsideOfNewVisibleRegion(int start, int end, IDocument doc
841841

842842
private static int computeEndOfVisibleRegion(int start, int length, IDocument document) throws BadLocationException {
843843
int documentLength= document.getLength();
844-
int end= start + length + 1;
845-
// ensure that trailing whitespace is included
846-
// In this case, the line break needs to be included as well
847-
boolean visibleRegionEndsWithTrailingWhitespace= end < documentLength && isWhitespaceButNotNewline(document.getChar(end - 1));
848-
while (end < documentLength && isWhitespaceButNotNewline(document.getChar(end))) {
844+
int end= start + length;
845+
// ensure that the last line is fully included because projections cannot include partial lines
846+
while (end < documentLength && !isLineBreak(document.getChar(end))) {
849847
end++;
850-
visibleRegionEndsWithTrailingWhitespace= true;
851848
}
852-
if (visibleRegionEndsWithTrailingWhitespace && end < documentLength && isLineBreak(document.getChar(end))) {
849+
if (end < documentLength) {
850+
end++;
851+
}
852+
if (end < documentLength && document.getChar(end) == '\n' && document.getChar(end - 1) == '\r') {
853853
end++;
854854
}
855855
return end;
856856
}
857857

858-
private static boolean isWhitespaceButNotNewline(char c) {
859-
return Character.isWhitespace(c) && !isLineBreak(c);
860-
}
861-
862858
private static boolean isLineBreak(char c) {
863859
return c == '\n' || c == '\r';
864860
}

tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/ProjectionViewerTest.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import static org.junit.jupiter.api.Assertions.assertThrows;
1717

1818
import org.junit.jupiter.api.Test;
19+
import org.junit.jupiter.params.ParameterizedTest;
20+
import org.junit.jupiter.params.provider.CsvSource;
1921

2022
import org.eclipse.swt.SWT;
2123
import org.eclipse.swt.dnd.Clipboard;
@@ -516,4 +518,69 @@ private ProjectionAnnotation addVisibleRegionAndProjection(TestProjectionViewer
516518
viewer.getProjectionAnnotationModel().addAnnotation(annotation, new Position(projectionStart, projectionEnd - projectionStart));
517519
return annotation;
518520
}
521+
522+
@ParameterizedTest
523+
@CsvSource({ "true", "false" })
524+
void testDifferentLineEndings(boolean crlf) {
525+
Shell shell= new Shell(Display.getCurrent());
526+
shell.setLayout(new FillLayout());
527+
TestProjectionViewer viewer= new TestProjectionViewer(shell, null, null, true, SWT.ALL);
528+
String documentContent= """
529+
// before
530+
{
531+
// within
532+
}
533+
// after
534+
""";
535+
if (crlf) {
536+
documentContent= documentContent.replace("\n", "\r\n");
537+
}
538+
Document document= new Document(documentContent);
539+
viewer.setDocument(document, new AnnotationModel());
540+
int start= documentContent.indexOf('{');
541+
int end= documentContent.indexOf('}') + 1;
542+
viewer.enableProjection();
543+
viewer.setVisibleRegion(start, end - start);
544+
assertEquals(documentContent.substring(start, documentContent.indexOf("// after")), viewer.getVisibleDocument().get());
545+
}
546+
547+
@Test
548+
void testIncludesLastLineIfAdditionalTextPresent() {
549+
Shell shell= new Shell(Display.getCurrent());
550+
shell.setLayout(new FillLayout());
551+
TestProjectionViewer viewer= new TestProjectionViewer(shell, null, null, true, SWT.ALL);
552+
String documentContent= """
553+
// before
554+
{
555+
// within
556+
}// ...
557+
// should be hidden
558+
""";
559+
Document document= new Document(documentContent);
560+
viewer.setDocument(document, new AnnotationModel());
561+
int start= documentContent.indexOf('{');
562+
int end= documentContent.indexOf('}') + 1;
563+
viewer.enableProjection();
564+
viewer.setVisibleRegion(start, end - start);
565+
assertEquals(documentContent.substring(start, documentContent.indexOf("// should be hidden")), viewer.getVisibleDocument().get());
566+
}
567+
568+
@Test
569+
void testSetVisibleRegionUntilEOF() {
570+
Shell shell= new Shell(Display.getCurrent());
571+
shell.setLayout(new FillLayout());
572+
TestProjectionViewer viewer= new TestProjectionViewer(shell, null, null, true, SWT.ALL);
573+
String documentContent= """
574+
// before
575+
{
576+
// within
577+
}""";
578+
Document document= new Document(documentContent);
579+
viewer.setDocument(document, new AnnotationModel());
580+
int start= documentContent.indexOf('{');
581+
int end= documentContent.indexOf('}') + 1;
582+
viewer.enableProjection();
583+
viewer.setVisibleRegion(start, end - start);
584+
assertEquals(documentContent.substring(start), viewer.getVisibleDocument().get());
585+
}
519586
}

0 commit comments

Comments
 (0)