From d22b41453dbb91113969d643bb1b77fb33b209ea Mon Sep 17 00:00:00 2001 From: Christopher Hermann Date: Thu, 10 Oct 2024 14:25:17 +0200 Subject: [PATCH] [StickyScrolling] Move complex line adaption to central handler Move sticky lines adaptation to the growing sticky lines control into the central sticky scrolling handler. This change simplifies the sticky lines provider, making implementations for specific languages more straightforward and maintainable. Preparation for #2398 --- .../DefaultStickyLinesProvider.java | 85 +++-------------- .../stickyscroll/IStickyLinesProvider.java | 22 ++--- .../stickyscroll/StickyScrollingControl.java | 13 ++- .../stickyscroll/StickyScrollingHandler.java | 45 ++++++++- .../DefaultStickyLinesProviderTest.java | 93 +++---------------- .../StickyScrollingControlTest.java | 66 +++++++++++-- .../StickyScrollingHandlerTest.java | 73 ++++++++++++--- 7 files changed, 211 insertions(+), 186 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 f0f1370257f..c4281899d1e 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 @@ -19,9 +19,6 @@ import org.eclipse.swt.custom.StyledText; -import org.eclipse.jface.text.ITextViewerExtension5; -import org.eclipse.jface.text.source.ISourceViewer; - /** * This class provides sticky lines for the given source code in the source viewer. The * implementation is completely based on indentation and therefore works by default for several @@ -36,83 +33,31 @@ public class DefaultStickyLinesProvider implements IStickyLinesProvider { private StickyLinesProperties fProperties; @Override - public List getStickyLines(ISourceViewer sourceViewer, StickyLinesProperties properties) { - if (sourceViewer.getTopIndex() == 0) { - return Collections.emptyList(); - } - + public List getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties) { this.fProperties= properties; LinkedList stickyLines= new LinkedList<>(); try { - StyledText textWidget= sourceViewer.getTextWidget(); - int startLine= textWidget.getTopIndex(); + int startIndetation= getStartIndentation(lineNumber, textWidget); - calculateStickyLinesForLineNumber(stickyLines, sourceViewer, startLine); - calculateStickyLinesUnderStickyLineControl(stickyLines, sourceViewer, startLine); - } catch (IllegalArgumentException e) { - stickyLines.clear(); - } + for (int i= lineNumber, previousIndetation= startIndetation; i >= 0; i--) { + String line= textWidget.getLine(i); + int indentation= getIndentation(line); - return stickyLines; - } + if (indentation == IGNORE_LINE_INDENTATION) { + continue; + } - private void calculateStickyLinesForLineNumber(LinkedList stickyLines, ISourceViewer sourceViewer, int lineNumber) { - StyledText textWidget= sourceViewer.getTextWidget(); - int startIndetation= getStartIndentation(lineNumber, textWidget); - - for (int i= lineNumber, previousIndetation= startIndetation; i >= 0; i--) { - String line= textWidget.getLine(i); - int indentation= getIndentation(line); - - if (indentation == IGNORE_LINE_INDENTATION) { - continue; - } - - if (indentation < previousIndetation) { - previousIndetation= indentation; - stickyLines.addFirst(new StickyLine(line, mapLineNumberToSourceViewerLine(i, sourceViewer))); - } - } - } - - private void calculateStickyLinesUnderStickyLineControl(LinkedList stickyLines, ISourceViewer sourceViewer, int startLine) { - int firstBelowControl= startLine + stickyLines.size(); - StyledText textWidget= sourceViewer.getTextWidget(); - int lineCount= textWidget.getLineCount(); - - for (int i= startLine; i < firstBelowControl && i < lineCount; i++) { - - String line= textWidget.getLine(i); - int indentation= getIndentation(line); - if (indentation == IGNORE_LINE_INDENTATION) { - continue; - } - - while (!stickyLines.isEmpty() && indentation <= getLastStickyLineIndentation(stickyLines) && i < firstBelowControl) { - stickyLines.removeLast(); - firstBelowControl--; - } - - String nextContentLine= getNextContentLine(i, textWidget); - if (getIndentation(nextContentLine) > indentation && i < firstBelowControl) { - stickyLines.addLast(new StickyLine(line, mapLineNumberToSourceViewerLine(i, sourceViewer))); - firstBelowControl++; - continue; + if (indentation < previousIndetation) { + previousIndetation= indentation; + stickyLines.addFirst(new StickyLine(line, i)); + } } + } catch (IllegalArgumentException e) { + stickyLines.clear(); } - } - private int getLastStickyLineIndentation(LinkedList stickyLines) { - String text= stickyLines.getLast().text(); - return getIndentation(text); - } - - private int mapLineNumberToSourceViewerLine(int lineNumber, ISourceViewer sourceViewer) { - if (sourceViewer instanceof ITextViewerExtension5 extension) { - return extension.widgetLine2ModelLine(lineNumber); - } - return lineNumber; + return stickyLines; } private int getStartIndentation(int startFromLine, StyledText styledText) { diff --git a/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/IStickyLinesProvider.java b/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/IStickyLinesProvider.java index 677ae114cd3..522f16cbe4f 100644 --- a/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/IStickyLinesProvider.java +++ b/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/IStickyLinesProvider.java @@ -20,7 +20,7 @@ import org.eclipse.jface.text.source.ISourceViewer; /** - * A sticky lines provider calculates the sticky lines for a given source viewer. The sticky lines + * A sticky lines provider calculates the sticky lines for a given text widget. The sticky lines * will be displayed in the top area of the editor. * * TODO move to public package and add since 3.19 @@ -28,26 +28,24 @@ public interface IStickyLinesProvider { /** - * Calculate the sticky lines for the source code of the given sourceViewer. Specific - * properties, such as the tabWidht can be retrieved from the + * Calculate the sticky lines for the source code of the given textWidget. Specific properties, + * such as the tabWidht and the source viewer, can be retrieved from the * properties. * - * @param sourceViewer The source viewer containing the source code and information about the - * first visible line + * @param textWidget The text widget containing the source code + * @param lineNumber The line number to calculate the sticky lines for + * @param properties Properties for additional information * @return The list of sticky lines to show - * - * @see ISourceViewer#getTopIndex() - * @see ISourceViewer#getTextWidget() - * @see StyledText#getTopIndex() */ - public List getStickyLines(ISourceViewer sourceViewer, StickyLinesProperties properties); + public List getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties); /** - * Properties required to calculate the sticky lines. + * Additional properties and access in order to calculate the sticky lines. * * @param tabWith The with of a tab + * @param sourceViewer The sourceViewer to access additional information */ - record StickyLinesProperties(int tabWith) { + record StickyLinesProperties(int tabWith, ISourceViewer sourceViewer) { } } diff --git a/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingControl.java b/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingControl.java index 414abd5c19c..51179e8c130 100644 --- a/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingControl.java +++ b/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingControl.java @@ -208,7 +208,8 @@ private void updateStickyScrollingControls() { for (int i= 0; i < getNumberStickyLines(); i++) { StickyLine stickyLine= stickyLines.get(i); stickyLineTextJoiner.add(stickyLine.text()); - stickyLineNumberJoiner.add(fillLineNumberWithLeadingSpaces(stickyLine.lineNumber() + 1)); + int lineNumber= getSourceViewerLineNumber(stickyLine.lineNumber()); + stickyLineNumberJoiner.add(fillLineNumberWithLeadingSpaces(lineNumber + 1)); } String newStickyLineText= stickyLineTextJoiner.toString(); @@ -223,6 +224,13 @@ private void updateStickyScrollingControls() { } } + private int getSourceViewerLineNumber(int i) { + if (sourceViewer instanceof ITextViewerExtension5 extension) { + return extension.widgetLine2ModelLine(i); + } + return i; + } + private String fillLineNumberWithLeadingSpaces(int lineNumber) { int lineCount= sourceViewer.getDocument().getNumberOfLines(); int lineNumberLength= String.valueOf(lineCount).length(); @@ -257,9 +265,6 @@ private void styleStickyLines() { private List getStickyLineStyleRanges(StickyLine stickyLine, int stickyLineTextOffset) { int lineNumber= stickyLine.lineNumber(); - if (sourceViewer instanceof ITextViewerExtension5 extension) { - lineNumber= extension.modelLine2WidgetLine(lineNumber); - } try { StyledText textWidget= sourceViewer.getTextWidget(); int offsetAtLine= textWidget.getOffsetAtLine(lineNumber); diff --git a/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingHandler.java b/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingHandler.java index 432ee38f381..df2ea6bee66 100644 --- a/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingHandler.java +++ b/bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingHandler.java @@ -22,8 +22,10 @@ import java.time.Duration; import java.util.Collections; +import java.util.LinkedList; import java.util.List; +import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; @@ -138,7 +140,7 @@ private StickyScrollingControlSettings loadControlSettings(IPreferenceStore stor private StickyLinesProperties loadStickyLinesProperties(IPreferenceStore store) { int tabWidth= store.getInt(EDITOR_TAB_WIDTH); - return new StickyLinesProperties(tabWidth); + return new StickyLinesProperties(tabWidth, sourceViewer); } @Override @@ -151,13 +153,52 @@ public void viewportChanged(int newVerticalOffset) { } private void calculateAndShowStickyLines() { - List stickyLines= stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties); + List stickyLines= Collections.emptyList(); + + StyledText textWidget= sourceViewer.getTextWidget(); + int startLine= textWidget.getTopIndex(); + + if (startLine > 0) { + stickyLines= stickyLinesProvider.getStickyLines(textWidget, startLine, stickyLinesProperties); + } + if (stickyLines == null) { stickyLines= Collections.emptyList(); } + + stickyLines= adaptStickyLinesToVisibleArea(stickyLines, startLine); + stickyScrollingControl.setStickyLines(stickyLines); } + private List adaptStickyLinesToVisibleArea(List stickyLines, int startLine) { + if (stickyLines.isEmpty()) { + return stickyLines; + } + + LinkedList adaptedStickyLines= new LinkedList<>(stickyLines); + + int firstVisibleLine= startLine + adaptedStickyLines.size(); + StyledText textWidget= sourceViewer.getTextWidget(); + int maximumLines= textWidget.getLineCount(); + + for (int i= startLine + 1; i <= firstVisibleLine && i < maximumLines; i++) { + List stickyLinesInLineI= stickyLinesProvider.getStickyLines(textWidget, i, stickyLinesProperties); + + if (stickyLinesInLineI.size() > adaptedStickyLines.size()) { + adaptedStickyLines= new LinkedList<>(stickyLinesInLineI); + firstVisibleLine= startLine + adaptedStickyLines.size(); + } + + while (stickyLinesInLineI.size() < adaptedStickyLines.size() && i < firstVisibleLine) { + adaptedStickyLines.removeLast(); + firstVisibleLine--; + } + } + + return adaptedStickyLines; + } + /** * Uninstalls the sticky scrolling handler from the source viewer. This completely disposes the * {@link StickyScrollingControl} and removes all corresponding listeners. 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 5e9fd440589..afd782d5f91 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 @@ -25,13 +25,9 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; -import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.ITextViewerExtension5; -import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.ui.internal.texteditor.stickyscroll.IStickyLinesProvider.StickyLinesProperties; @@ -50,12 +46,12 @@ public void setup() { sourceViewer = new SourceViewer(shell, null, SWT.None); stickyLinesProvider = new DefaultStickyLinesProvider(); textWidget = sourceViewer.getTextWidget(); - stickyLinesProperties = new StickyLinesProperties(4); + stickyLinesProperties = new StickyLinesProperties(4, sourceViewer); } @Test public void testEmptySourceCode() { - List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties); + List stickyLines = stickyLinesProvider.getStickyLines(textWidget, 0, stickyLinesProperties); assertThat(stickyLines, is(empty())); } @@ -67,7 +63,7 @@ public void testSingleStickyLine() { line 2<"""; setText(text); - List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties); + List stickyLines = stickyLinesProvider.getStickyLines(textWidget, 1, stickyLinesProperties); assertThat(stickyLines, contains(new StickyLine("line 1", 0))); } @@ -81,9 +77,9 @@ public void testLineUnderStickyLine() { line 4"""; setText(text); - List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties); + List stickyLines = stickyLinesProvider.getStickyLines(textWidget, 1, stickyLinesProperties); - assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine(" line 2<", 1))); + assertThat(stickyLines, contains(new StickyLine("line 1", 0))); } @Test @@ -95,7 +91,7 @@ public void testNewStickyRoot() { line 4<"""; setText(text); - List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties); + List stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties); assertThat(stickyLines, contains(new StickyLine("line 3", 2))); } @@ -110,24 +106,23 @@ public void testIgnoreEmptyLines() { line 3<"""; setText(text); - List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties); + List stickyLines = stickyLinesProvider.getStickyLines(textWidget, 4, stickyLinesProperties); assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine(" line 2", 2))); } @Test public void testLinesWithTabs() { - stickyLinesProperties = new StickyLinesProperties(2); + stickyLinesProperties = new StickyLinesProperties(2, sourceViewer); String text = """ line 1 \tline 2 \t\tline 3<"""; setText(text); - List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties); + List stickyLines = stickyLinesProvider.getStickyLines(textWidget, 2, stickyLinesProperties); assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine("\tline 2", 1))); - } @Test @@ -141,10 +136,9 @@ public void testStartAtEmptyLineWithNext() { textWidget.setText(text); textWidget.setTopIndex(3); - List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties); + List stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties); assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine(" line 2", 2))); - } @Test @@ -152,42 +146,14 @@ public void testStartAtEmptyLineWithPrevious() { String text = """ line 1 line 2 - line 3< - line 4"""; - setText(text); - - List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties); - - assertThat(stickyLines, contains(new StickyLine("line 1", 0))); - } - - @Test - public void testRemoveStickyLines() { - String text = """ - line 1 - line 2 - line 3 - line 4<"""; - setText(text); - - List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties); - - assertThat(stickyLines, contains(new StickyLine("line 3", 2))); - } - - @Test - public void testSourceViewerWithDifferentModelAndWindgetLines() { - sourceViewer = new SourceViewerLineMapping(shell, null, SWT.None); - textWidget = sourceViewer.getTextWidget(); + line 3 - String text = """ - line 1 - line 2<"""; + line 4"""; setText(text); - List stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties); + List stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties); - assertThat(stickyLines, contains(new StickyLine("line 1", 42))); + assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine(" line 2", 1))); } /** @@ -196,37 +162,6 @@ public void testSourceViewerWithDifferentModelAndWindgetLines() { */ private void setText(String text) { textWidget.setText(text); - - String[] lines = text.split("\n"); - for (int i = 0; i < lines.length; i++) { - if (lines[i].contains(String.valueOf("<"))) { - textWidget.setTopIndex(i); - return; - } - } - } - - private class SourceViewerLineMapping extends SourceViewer implements ITextViewerExtension5 { - - public SourceViewerLineMapping(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 42; - } - } } diff --git a/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingControlTest.java b/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingControlTest.java index 031e3cfa623..2d0999e6b4d 100644 --- a/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingControlTest.java +++ b/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingControlTest.java @@ -43,6 +43,8 @@ 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; import org.eclipse.jface.text.source.SourceViewer; @@ -56,6 +58,7 @@ public class StickyScrollingControlTest { private Color separatorColor; private StickyScrollingControl stickyScrollingControl; private IVerticalRuler ruler; + private StickyScrollingControlSettings settings; @Before public void setup() { @@ -71,8 +74,8 @@ public void setup() { hoverColor = new Color(1, 1, 1); backgroundColor = new Color(2, 2, 2); separatorColor = new Color(3, 3, 3); - StickyScrollingControlSettings settings = new StickyScrollingControlSettings(2, lineNumberColor, hoverColor, - backgroundColor, separatorColor, true); + settings = new StickyScrollingControlSettings(2, lineNumberColor, hoverColor, backgroundColor, separatorColor, + true); stickyScrollingControl = new StickyScrollingControl(sourceViewer, ruler, settings, null); } @@ -98,6 +101,30 @@ public void testShowStickyLineTexts() { assertEquals(expStickyLineText, stickyLineText.getText()); } + @Test + public void testShowStickyLineTextsWithSourceViewerMapping() { + shell.dispose(); + shell = new Shell(Display.getDefault()); + shell.setSize(200, 200); + shell.setLayout(new FillLayout()); + + sourceViewer = new SourceViewerLineMapping(shell, ruler, SWT.V_SCROLL | SWT.H_SCROLL); + sourceViewer.setDocument(new Document()); + sourceViewer.getTextWidget().setBounds(0, 0, 200, 200); + + stickyScrollingControl = new StickyScrollingControl(sourceViewer, ruler, settings, null); + + List stickyLines = List.of(new StickyLine("line 10", 9), new StickyLine("line 20", 19)); + stickyScrollingControl.setStickyLines(stickyLines); + + StyledText stickyLineNumber = getStickyLineNumber(); + String expLineNumber = "52" + System.lineSeparator() + "62"; + assertEquals(expLineNumber, stickyLineNumber.getText()); + StyledText stickyLineText = getStickyLineText(); + String expStickyLineText = "line 10" + System.lineSeparator() + "line 20"; + assertEquals(expStickyLineText, stickyLineText.getText()); + } + @Test public void testCorrectColorsApplied() { List stickyLines = List.of(new StickyLine("line 10", 9), new StickyLine("line 20", 19)); @@ -119,8 +146,8 @@ public void testLimitStickyLinesCount() { List stickyLines = List.of(new StickyLine("line 10", 9), new StickyLine("line 20", 19)); stickyScrollingControl.setStickyLines(stickyLines); - StickyScrollingControlSettings settings = new StickyScrollingControlSettings(1, lineNumberColor, hoverColor, - backgroundColor, separatorColor, true); + settings = new StickyScrollingControlSettings(1, lineNumberColor, hoverColor, backgroundColor, separatorColor, + true); stickyScrollingControl.applySettings(settings); StyledText stickyLineNumber = getStickyLineNumber(); @@ -147,8 +174,8 @@ public void testCopyStyleRanges() { @Test public void testWithoutVerticalRuler() { sourceViewer = new SourceViewer(shell, null, SWT.None); - StickyScrollingControlSettings settings = new StickyScrollingControlSettings(5, lineNumberColor, hoverColor, - backgroundColor, separatorColor, true); + settings = new StickyScrollingControlSettings(5, lineNumberColor, hoverColor, backgroundColor, separatorColor, + true); stickyScrollingControl = new StickyScrollingControl(sourceViewer, settings); StyledText stickyLineNumber = getStickyLineNumber(); @@ -164,8 +191,8 @@ public void testWithoutLineNumber() { StyledText stickyLineNumber = getStickyLineNumber(); assertThat(stickyLineNumber.getLeftMargin(), greaterThan(0)); - StickyScrollingControlSettings settings = new StickyScrollingControlSettings(5, lineNumberColor, hoverColor, - backgroundColor, separatorColor, false); + settings = new StickyScrollingControlSettings(5, lineNumberColor, hoverColor, backgroundColor, separatorColor, + false); stickyScrollingControl.applySettings(settings); stickyLineNumber = getStickyLineNumber(); @@ -419,4 +446,27 @@ private void drainDisplayEventQueue() { } } + private class SourceViewerLineMapping extends SourceViewer implements ITextViewerExtension5 { + + public SourceViewerLineMapping(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; + } + + } + } diff --git a/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingHandlerTest.java b/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingHandlerTest.java index 3fc500fae2d..2b84f4a86d9 100644 --- a/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingHandlerTest.java +++ b/tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingHandlerTest.java @@ -20,9 +20,12 @@ import static org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -62,14 +65,19 @@ public class StickyScrollingHandlerTest { private IStickyLinesProvider linesProvider; private StickyScrollingHandler stickyScrollingHandler; private StickyLinesProperties stickyLinesProperties; + private StyledText textWidget; @Before public void setup() { shell = new Shell(Display.getDefault()); + shell.setBounds(0, 0, 200, 80); ruler = new CompositeRuler(); sourceViewer = new SourceViewer(shell, ruler, SWT.None); sourceViewer.setDocument(new Document()); - sourceViewer.getTextWidget().setBounds(0, 0, 200, 200); + sourceViewer.getTextWidget().setBounds(0, 0, 200, 100); + textWidget = sourceViewer.getTextWidget(); + textWidget.setText("first 1 \nline 2 \nline 3 \nline 4 \nline 5 \nline 6 \nline 7 \nline 8 \nline 9 \nline 10"); + textWidget.setTopIndex(1); lineNumberColor = new Color(0, 0, 0); hoverColor = new Color(1, 1, 1); @@ -78,7 +86,7 @@ public void setup() { linesProvider = mock(IStickyLinesProvider.class); stickyScrollingHandler = new StickyScrollingHandler(sourceViewer, ruler, store, linesProvider); - stickyLinesProperties = new StickyLinesProperties(4); + stickyLinesProperties = new StickyLinesProperties(4, sourceViewer); } @After @@ -88,7 +96,7 @@ public void teardown() { @Test public void testShowStickyLines() { - when(linesProvider.getStickyLines(sourceViewer, stickyLinesProperties)) + when(linesProvider.getStickyLines(textWidget, 1, stickyLinesProperties)) .thenReturn(List.of(new StickyLine("line 10", 9))); stickyScrollingHandler.viewportChanged(100); @@ -101,6 +109,19 @@ public void testShowStickyLines() { assertEquals(expStickyLineText, stickyLineText.getText()); } + @Test + public void testDontCalculateStickyLinesForFirstLine() { + textWidget.setTopIndex(0); + + stickyScrollingHandler.viewportChanged(100); + + StyledText stickyLineNumber = getStickyLineNumber(); + assertEquals("", stickyLineNumber.getText()); + StyledText stickyLineText = getStickyLineText(); + assertEquals("", stickyLineText.getText()); + verify(linesProvider, never()).getStickyLines(any(), anyInt(), any()); + } + @Test public void testUnistallStickyLines() { Canvas stickyControlCanvas = getStickyControlCanvas(this.shell); @@ -112,7 +133,7 @@ public void testUnistallStickyLines() { @Test public void testPreferencesLoaded() { - when(linesProvider.getStickyLines(sourceViewer, stickyLinesProperties)) + when(linesProvider.getStickyLines(textWidget, 1, stickyLinesProperties)) .thenReturn(List.of(new StickyLine("line 10", 9))); stickyScrollingHandler.viewportChanged(100); @@ -123,7 +144,9 @@ public void testPreferencesLoaded() { @Test public void testPreferencesUpdated() { - when(linesProvider.getStickyLines(sourceViewer, stickyLinesProperties)) + when(linesProvider.getStickyLines(textWidget, 1, stickyLinesProperties)) + .thenReturn(List.of(new StickyLine("line 10", 9), new StickyLine("line 20", 19))); + when(linesProvider.getStickyLines(textWidget, 2, stickyLinesProperties)) .thenReturn(List.of(new StickyLine("line 10", 9), new StickyLine("line 20", 19))); stickyScrollingHandler.viewportChanged(100); @@ -141,13 +164,13 @@ public void testPreferencesUpdated() { @Test public void testThrottledExecution() throws InterruptedException { - when(linesProvider.getStickyLines(sourceViewer, stickyLinesProperties)) + when(linesProvider.getStickyLines(textWidget, 1, stickyLinesProperties)) .thenReturn(List.of(new StickyLine("line 10", 9))); - when(linesProvider.getStickyLines(sourceViewer, stickyLinesProperties)) + when(linesProvider.getStickyLines(textWidget, 1, stickyLinesProperties)) .thenReturn(List.of(new StickyLine("line 10", 9))); - when(linesProvider.getStickyLines(sourceViewer, stickyLinesProperties)) + when(linesProvider.getStickyLines(textWidget, 1, stickyLinesProperties)) .thenReturn(List.of(new StickyLine("line 10", 9))); - when(linesProvider.getStickyLines(sourceViewer, stickyLinesProperties)) + when(linesProvider.getStickyLines(textWidget, 1, stickyLinesProperties)) .thenReturn(List.of(new StickyLine("line 10", 9))); stickyScrollingHandler.viewportChanged(100); @@ -162,8 +185,36 @@ public void testThrottledExecution() throws InterruptedException { // Call to lines provider should be throttled, at least one and at most // 3 calls expected - verify(linesProvider, atMost(3)).getStickyLines(sourceViewer, stickyLinesProperties); - verify(linesProvider, atLeastOnce()).getStickyLines(sourceViewer, stickyLinesProperties); + verify(linesProvider, atMost(3)).getStickyLines(textWidget, 1, stickyLinesProperties); + verify(linesProvider, atLeastOnce()).getStickyLines(textWidget, 1, stickyLinesProperties); + } + + @Test + public void testRemoveStickyLines() { + when(linesProvider.getStickyLines(textWidget, 1, stickyLinesProperties)) + .thenReturn(List.of(new StickyLine("line 1", 0), new StickyLine("line 2", 1))); + when(linesProvider.getStickyLines(textWidget, 2, stickyLinesProperties)) + .thenReturn(List.of(new StickyLine("line 3", 2))); + + stickyScrollingHandler.viewportChanged(100); + + StyledText stickyLineText = getStickyLineText(); + String expStickyLineText = "line 1"; + assertEquals(expStickyLineText, stickyLineText.getText()); + } + + @Test + public void testLineUnderStickyLine() { + when(linesProvider.getStickyLines(textWidget, 1, stickyLinesProperties)) + .thenReturn(List.of(new StickyLine("line 1", 0))); + when(linesProvider.getStickyLines(textWidget, 2, stickyLinesProperties)) + .thenReturn(List.of(new StickyLine("line 1", 0), new StickyLine("line 2", 1))); + + stickyScrollingHandler.viewportChanged(100); + + StyledText stickyLineText = getStickyLineText(); + String expStickyLineText = "line 1" + System.lineSeparator() + "line 2"; + assertEquals(expStickyLineText, stickyLineText.getText()); } private void waitInUi(int ms) throws InterruptedException {