From 9dfcbafd7a210044b85698bb3d94245bd5bd70dc Mon Sep 17 00:00:00 2001 From: Christopher Hermann Date: Fri, 6 Dec 2024 12:36:36 +0100 Subject: [PATCH] [StickyScrolling] Sticky line is considering hidden source viewer lines The source viewer can contain hidden lines, for example via code folding. The sticky line needs to consider this lines (see ITextViewerExtension5) when calculating the text and the style ranges from the text widget --- .../DefaultStickyLinesProvider.java | 2 +- .../texteditor/stickyscroll/StickyLine.java | 26 ++++-- .../DefaultStickyLinesProviderTest.java | 27 +++---- .../stickyscroll/StickyLineTest.java | 79 ++++++++++++++++++- 4 files changed, 107 insertions(+), 27 deletions(-) diff --git a/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/DefaultStickyLinesProvider.java b/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/DefaultStickyLinesProvider.java index 2153768f643..40c3125f1af 100644 --- a/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/DefaultStickyLinesProvider.java +++ b/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/DefaultStickyLinesProvider.java @@ -55,7 +55,7 @@ public List getStickyLines(ISourceViewer sourceViewer, int lineNumb if (indentation < previousIndetation) { previousIndetation= indentation; - stickyLines.addFirst(new StickyLine(mapLineNumberToViewer(sourceViewer, i), textWidget)); + stickyLines.addFirst(new StickyLine(mapLineNumberToViewer(sourceViewer, i), sourceViewer)); } } } catch (IllegalArgumentException e) { diff --git a/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyLine.java b/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyLine.java index e54b0149a79..3533ad07c22 100644 --- a/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyLine.java +++ b/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyLine.java @@ -16,21 +16,24 @@ import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; +import org.eclipse.jface.text.ITextViewerExtension5; +import org.eclipse.jface.text.source.ISourceViewer; + /** * Default implementation of {@link IStickyLine}. Information about the text and style ranges are * calculated from the given text widget. */ public class StickyLine implements IStickyLine { - private int lineNumber; + protected int lineNumber; - private String text; + protected String text; - private StyledText textWidget; + protected ISourceViewer sourceViewer; - public StickyLine(int lineNumber, StyledText textWidget) { + public StickyLine(int lineNumber, ISourceViewer sourceViewer) { this.lineNumber= lineNumber; - this.textWidget= textWidget; + this.sourceViewer= sourceViewer; } @Override @@ -41,14 +44,16 @@ public int getLineNumber() { @Override public String getText() { if (text == null) { - text= textWidget.getLine(lineNumber); + StyledText textWidget= sourceViewer.getTextWidget(); + text= textWidget.getLine(getWidgetLineNumber()); } return text; } @Override public StyleRange[] getStyleRanges() { - int offsetAtLine= textWidget.getOffsetAtLine(lineNumber); + StyledText textWidget= sourceViewer.getTextWidget(); + int offsetAtLine= textWidget.getOffsetAtLine(getWidgetLineNumber()); StyleRange[] styleRanges= textWidget.getStyleRanges(offsetAtLine, getText().length()); for (StyleRange styleRange : styleRanges) { styleRange.start= styleRange.start - offsetAtLine; @@ -56,4 +61,11 @@ public StyleRange[] getStyleRanges() { return styleRanges; } + private int getWidgetLineNumber() { + if (sourceViewer instanceof ITextViewerExtension5 extension) { + return extension.modelLine2WidgetLine(lineNumber); + } + return lineNumber; + } + } diff --git a/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/DefaultStickyLinesProviderTest.java b/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/DefaultStickyLinesProviderTest.java index 0ec92b14dc9..8aaf61e0310 100644 --- a/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/DefaultStickyLinesProviderTest.java +++ b/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/DefaultStickyLinesProviderTest.java @@ -29,6 +29,7 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; +import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewerExtension5; import org.eclipse.jface.text.source.IVerticalRuler; @@ -48,6 +49,7 @@ public class DefaultStickyLinesProviderTest { public void setup() { shell = new Shell(Display.getDefault()); sourceViewer = new SourceViewer(shell, null, SWT.None); + sourceViewer.setDocument(new Document()); stickyLinesProvider = new DefaultStickyLinesProvider(); textWidget = sourceViewer.getTextWidget(); stickyLinesProperties = new StickyLinesProperties(4); @@ -65,12 +67,13 @@ public void testSingleStickyLine() { String text = """ line 1 line 2<"""; - setText(text); + textWidget.setText(text); List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 1, stickyLinesProperties); assertEquals(1, stickyLines.size()); assertEquals(0, stickyLines.get(0).getLineNumber()); + assertEquals("line 1", stickyLines.get(0).getText()); } @Test @@ -80,7 +83,7 @@ public void testLineUnderStickyLine() { line 2< line 3 line 4"""; - setText(text); + textWidget.setText(text); List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 1, stickyLinesProperties); @@ -95,7 +98,7 @@ public void testNewStickyRoot() { line 2 line 3 line 4<"""; - setText(text); + textWidget.setText(text); List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 3, stickyLinesProperties); @@ -111,7 +114,7 @@ public void testIgnoreEmptyLines() { line 2 line 3<"""; - setText(text); + textWidget.setText(text); List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 4, stickyLinesProperties); @@ -127,7 +130,7 @@ public void testLinesWithTabs() { line 1 \tline 2 \t\tline 3<"""; - setText(text); + textWidget.setText(text); List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 2, stickyLinesProperties); @@ -162,7 +165,7 @@ public void testStartAtEmptyLineWithPrevious() { line 3 line 4"""; - setText(text); + textWidget.setText(text); List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 3, stickyLinesProperties); @@ -174,12 +177,13 @@ public void testStartAtEmptyLineWithPrevious() { @Test public void testStickyLineWithSourceViewerLineMapping() { sourceViewer = new SourceViewerWithLineMapping(shell, null, SWT.None); + sourceViewer.setDocument(new Document()); textWidget = sourceViewer.getTextWidget(); String text = """ line 1 line 2<"""; - setText(text); + textWidget.setText(text); // Source viewer line 43 that is mapped to line 1 in the text widget List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 1 + 42, stickyLinesProperties); @@ -187,14 +191,7 @@ public void testStickyLineWithSourceViewerLineMapping() { assertEquals(1, stickyLines.size()); // Source viewer line 42 that is mapped to line 0 in the text widget assertEquals(0 + 42, stickyLines.get(0).getLineNumber()); - } - - /** - * Set the text into the text widget and set the top index to the line - * containing the <. - */ - private void setText(String text) { - textWidget.setText(text); + assertEquals("line 1", stickyLines.get(0).getText()); } private class SourceViewerWithLineMapping extends SourceViewer implements ITextViewerExtension5 { diff --git a/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyLineTest.java b/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyLineTest.java index 483796a0dba..99ee26000f0 100644 --- a/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyLineTest.java +++ b/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyLineTest.java @@ -23,18 +23,29 @@ import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewerExtension5; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.IVerticalRuler; +import org.eclipse.jface.text.source.SourceViewer; + public class StickyLineTest { private Shell shell; private StyledText textWidget; private Color color; + private ISourceViewer sourceViewer; @Before public void setUp() { shell = new Shell(); - textWidget = new StyledText(shell, SWT.NONE); + sourceViewer = new SourceViewer(shell, null, SWT.None); + sourceViewer.setDocument(new Document()); + textWidget = sourceViewer.getTextWidget(); color = new Color(0, 0, 0); } @@ -46,7 +57,7 @@ public void tearDown() { @Test public void testGetLineNumber() { - StickyLine stickyLine = new StickyLine(1, textWidget); + StickyLine stickyLine = new StickyLine(1, sourceViewer); assertEquals(1, stickyLine.getLineNumber()); } @@ -54,7 +65,7 @@ public void testGetLineNumber() { @Test public void testGetText() { textWidget.setText("line1\nline2\nline3"); - StickyLine stickyLine = new StickyLine(1, textWidget); + StickyLine stickyLine = new StickyLine(1, sourceViewer); assertEquals("line2", stickyLine.getText()); } @@ -73,7 +84,7 @@ public void testGetStyleRanges() { // line3 textWidget.setStyleRange(new StyleRange(15, 1, color, null)); - StickyLine stickyLine = new StickyLine(1, textWidget); + StickyLine stickyLine = new StickyLine(1, sourceViewer); StyleRange[] styleRanges = stickyLine.getStyleRanges(); assertEquals(2, styleRanges.length); @@ -83,4 +94,64 @@ public void testGetStyleRanges() { assertEquals(2, styleRanges[1].length); } + @Test + public void WithSourceViewerLineMapping() { + sourceViewer = new SourceViewerWithLineMapping(shell, null, SWT.None); + sourceViewer.setDocument(new Document()); + textWidget = sourceViewer.getTextWidget(); + + textWidget.setText("line1\nline2\nline3"); + + // line1 + textWidget.setStyleRange(new StyleRange(2, 1, color, null)); + + // line2 + textWidget.setStyleRange(new StyleRange(6, 1, color, null)); + textWidget.setStyleRange(new StyleRange(8, 2, color, null)); + + // line3 + textWidget.setStyleRange(new StyleRange(15, 1, color, null)); + + StickyLine stickyLine = new StickyLine(1 + 42, sourceViewer); + StyleRange[] styleRanges = stickyLine.getStyleRanges(); + + assertEquals(1 + 42, stickyLine.getLineNumber()); + + assertEquals("line2", stickyLine.getText()); + + assertEquals(2, styleRanges.length); + assertEquals(0, styleRanges[0].start); + assertEquals(1, styleRanges[0].length); + assertEquals(2, styleRanges[1].start); + assertEquals(2, styleRanges[1].length); + } + + private class SourceViewerWithLineMapping extends SourceViewer implements ITextViewerExtension5 { + + public SourceViewerWithLineMapping(Composite parent, IVerticalRuler ruler, int styles) { + super(parent, ruler, styles); + } + + @Override + public IRegion[] getCoveredModelRanges(IRegion modelRange) { + return null; + } + + @Override + public boolean exposeModelRange(IRegion modelRange) { + return false; + } + + @Override + public int widgetLine2ModelLine(int widgetLine) { + return widgetLine + 42; + } + + @Override + public int modelLine2WidgetLine(int widgetLine) { + return widgetLine - 42; + } + + } + }