Skip to content

Commit 9474c95

Browse files
[StickyScrolling] Move text and style calculation to StickyLine
Move the text and style calculation to the StickyLine itself in order to enable the sticky line provider to overwrite the default behavior. This is needed to apply custom texts or custom styles for the sticky lines. Preparation for #2398
1 parent 56115fc commit 9474c95

File tree

10 files changed

+325
-93
lines changed

10 files changed

+325
-93
lines changed

bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/DefaultStickyLinesProvider.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ public class DefaultStickyLinesProvider implements IStickyLinesProvider {
3333
private StickyLinesProperties fProperties;
3434

3535
@Override
36-
public List<StickyLine> getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties) {
36+
public List<IStickyLine> getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties) {
3737
this.fProperties= properties;
38-
LinkedList<StickyLine> stickyLines= new LinkedList<>();
38+
LinkedList<IStickyLine> stickyLines= new LinkedList<>();
3939

4040
try {
4141
int startIndetation= getStartIndentation(lineNumber, textWidget);
@@ -50,7 +50,7 @@ public List<StickyLine> getStickyLines(StyledText textWidget, int lineNumber, St
5050

5151
if (indentation < previousIndetation) {
5252
previousIndetation= indentation;
53-
stickyLines.addFirst(new StickyLine(line, i));
53+
stickyLines.addFirst(new StickyLine(i, textWidget));
5454
}
5555
}
5656
} catch (IllegalArgumentException e) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 SAP SE.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* SAP SE - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.ui.internal.texteditor.stickyscroll;
15+
16+
import org.eclipse.swt.custom.StyleRange;
17+
18+
/**
19+
* Representation of a sticky line.
20+
*/
21+
public interface IStickyLine {
22+
23+
/**
24+
* Returns the line number of the sticky line.
25+
*
26+
* @return the line number of the sticky line
27+
*/
28+
int getLineNumber();
29+
30+
/**
31+
* Returns the text of the sticky line.
32+
*
33+
* @return the text of the sticky line
34+
*/
35+
String getText();
36+
37+
/**
38+
* Returns the style ranges of the sticky line.
39+
*
40+
* @return the style ranges of the sticky line
41+
*/
42+
StyleRange[] getStyleRanges();
43+
44+
}

bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/IStickyLinesProvider.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public interface IStickyLinesProvider {
3737
* @param properties Properties for additional information
3838
* @return The list of sticky lines to show
3939
*/
40-
public List<StickyLine> getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties);
40+
public List<IStickyLine> getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties);
4141

4242
/**
4343
* Additional properties and access in order to calculate the sticky lines.

bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyLine.java

+41-7
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,47 @@
1313
*******************************************************************************/
1414
package org.eclipse.ui.internal.texteditor.stickyscroll;
1515

16+
import org.eclipse.swt.custom.StyleRange;
17+
import org.eclipse.swt.custom.StyledText;
18+
1619
/**
17-
*
18-
* A record representing a sticky line containing the text to display, and line number. It serves as
19-
* an abstraction to represent sticky line for sticky scrolling.
20-
*
21-
* @param text the text of the corresponding sticky line
22-
* @param lineNumber the specific line number of the sticky line
20+
* Default implementation of {@link IStickyLine}. Information about the text and style ranges are
21+
* calculated from the given text widget.
2322
*/
24-
public record StickyLine(String text, int lineNumber) {
23+
public class StickyLine implements IStickyLine {
24+
25+
private int lineNumber;
26+
27+
private String text;
28+
29+
private StyledText textWidget;
30+
31+
public StickyLine(int lineNumber, StyledText textWidget) {
32+
this.lineNumber= lineNumber;
33+
this.textWidget= textWidget;
34+
}
35+
36+
@Override
37+
public int getLineNumber() {
38+
return this.lineNumber;
39+
}
40+
41+
@Override
42+
public String getText() {
43+
if (text == null) {
44+
text= textWidget.getLine(lineNumber);
45+
}
46+
return text;
47+
}
48+
49+
@Override
50+
public StyleRange[] getStyleRanges() {
51+
int offsetAtLine= textWidget.getOffsetAtLine(lineNumber);
52+
StyleRange[] styleRanges= textWidget.getStyleRanges(offsetAtLine, getText().length());
53+
for (StyleRange styleRange : styleRanges) {
54+
styleRange.start= styleRange.start - offsetAtLine;
55+
}
56+
return styleRanges;
57+
}
58+
2559
}

bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingControl.java

+22-34
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
package org.eclipse.ui.internal.texteditor.stickyscroll;
1515

1616
import java.util.ArrayList;
17-
import java.util.Arrays;
18-
import java.util.Collections;
1917
import java.util.Iterator;
2018
import java.util.List;
2119
import java.util.StringJoiner;
@@ -65,7 +63,7 @@
6563
/**
6664
* This class builds a control that is rendered on top of the given source viewer. The controls
6765
* shows the sticky lines that are set via {@link #setStickyLines(List)} on top of the source
68-
* viewer. The {@link StickyLine#lineNumber()} is linked to to corresponding line number in the
66+
* viewer. The {@link StickyLine#getLineNumber()} is linked to to corresponding line number in the
6967
* given source viewer, with index starting at 0.
7068
*
7169
* As part of its responsibilities, the class handles layout arrangement and styling of the sticky
@@ -87,7 +85,7 @@ public class StickyScrollingControl {
8785

8886
private static final String DISABLE_CSS= "org.eclipse.e4.ui.css.disabled"; //$NON-NLS-1$
8987

90-
private List<StickyLine> stickyLines;
88+
private List<IStickyLine> stickyLines;
9189

9290
private ISourceViewer sourceViewer;
9391

@@ -135,7 +133,7 @@ public StickyScrollingControl(ISourceViewer sourceViewer, IVerticalRuler vertica
135133
*
136134
* @param stickyLines The sticky lines to show
137135
*/
138-
public void setStickyLines(List<StickyLine> stickyLines) {
136+
public void setStickyLines(List<IStickyLine> stickyLines) {
139137
if (!stickyLines.equals(this.stickyLines)) {
140138
this.stickyLines= stickyLines;
141139
updateStickyScrollingControls();
@@ -206,9 +204,9 @@ private void updateStickyScrollingControls() {
206204
StringJoiner stickyLineTextJoiner= new StringJoiner(System.lineSeparator());
207205
StringJoiner stickyLineNumberJoiner= new StringJoiner(System.lineSeparator());
208206
for (int i= 0; i < getNumberStickyLines(); i++) {
209-
StickyLine stickyLine= stickyLines.get(i);
210-
stickyLineTextJoiner.add(stickyLine.text());
211-
int lineNumber= getSourceViewerLineNumber(stickyLine.lineNumber());
207+
IStickyLine stickyLine= stickyLines.get(i);
208+
stickyLineTextJoiner.add(stickyLine.getText());
209+
int lineNumber= getSourceViewerLineNumber(stickyLine.getLineNumber());
212210
stickyLineNumberJoiner.add(fillLineNumberWithLeadingSpaces(lineNumber + 1));
213211
}
214212

@@ -244,14 +242,20 @@ private void styleStickyLines() {
244242
return;
245243
}
246244

247-
List<StyleRange> stickyLinesStyleRanges= new ArrayList<>();
248-
int stickyLineTextOffset= 0;
249-
for (int i= 0; i < getNumberStickyLines(); i++) {
250-
StickyLine stickyLine= stickyLines.get(i);
251-
stickyLinesStyleRanges.addAll(getStickyLineStyleRanges(stickyLine, stickyLineTextOffset));
252-
stickyLineTextOffset+= stickyLine.text().length() + System.lineSeparator().length();
245+
int stickyLineOffset= 0;
246+
List<StyleRange> styleRanges= new ArrayList<>();
247+
for (IStickyLine stickyLine : stickyLines) {
248+
StyleRange[] ranges= stickyLine.getStyleRanges();
249+
if (ranges != null) {
250+
for (StyleRange styleRange : ranges) {
251+
styleRange.start+= stickyLineOffset;
252+
styleRanges.add(styleRange);
253+
}
254+
}
255+
256+
stickyLineOffset+= stickyLine.getText().length() + System.lineSeparator().length();
253257
}
254-
stickyLineText.setStyleRanges(stickyLinesStyleRanges.toArray(StyleRange[]::new));
258+
stickyLineText.setStyleRanges(styleRanges.toArray(StyleRange[]::new));
255259

256260
stickyLineNumber.setFont(textWidget.getFont());
257261
stickyLineNumber.setStyleRange(new StyleRange(0, stickyLineNumber.getText().length(), settings.lineNumberColor(), null));
@@ -263,22 +267,6 @@ private void styleStickyLines() {
263267
stickyLineText.setLeftMargin(textWidget.getLeftMargin());
264268
}
265269

266-
private List<StyleRange> getStickyLineStyleRanges(StickyLine stickyLine, int stickyLineTextOffset) {
267-
int lineNumber= stickyLine.lineNumber();
268-
try {
269-
StyledText textWidget= sourceViewer.getTextWidget();
270-
int offsetAtLine= textWidget.getOffsetAtLine(lineNumber);
271-
StyleRange[] styleRanges= textWidget.getStyleRanges(offsetAtLine, stickyLine.text().length());
272-
for (StyleRange styleRange : styleRanges) {
273-
styleRange.start= styleRange.start - offsetAtLine + stickyLineTextOffset;
274-
}
275-
return Arrays.asList(styleRanges);
276-
} catch (IllegalArgumentException e) {
277-
//Styling could not be copied, skip!
278-
return Collections.emptyList();
279-
}
280-
}
281-
282270
private void layoutStickyLines() {
283271
if (getNumberStickyLines() == 0) {
284272
stickyLinesCanvas.setVisible(false);
@@ -365,12 +353,12 @@ private void calculateAndSetStickyLinesCanvasBounds() {
365353

366354
private void navigateToClickedLine(MouseEvent event) {
367355
int clickedStickyLineIndex= stickyLineText.getLineIndex(event.y);
368-
StickyLine clickedStickyLine= stickyLines.get(clickedStickyLineIndex);
356+
IStickyLine clickedStickyLine= stickyLines.get(clickedStickyLineIndex);
369357

370358
try {
371-
int offset= sourceViewer.getDocument().getLineOffset(clickedStickyLine.lineNumber());
359+
int offset= sourceViewer.getDocument().getLineOffset(clickedStickyLine.getLineNumber());
372360
sourceViewer.setSelectedRange(offset, 0);
373-
ensureSourceViewerLineVisible(clickedStickyLine.lineNumber());
361+
ensureSourceViewerLineVisible(clickedStickyLine.getLineNumber());
374362
} catch (BadLocationException e) {
375363
//Do not navigate
376364
}

bundles/org.eclipse.ui.editors/src/org/eclipse/ui/internal/texteditor/stickyscroll/StickyScrollingHandler.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public void viewportChanged(int newVerticalOffset) {
153153
}
154154

155155
private void calculateAndShowStickyLines() {
156-
List<StickyLine> stickyLines= Collections.emptyList();
156+
List<IStickyLine> stickyLines= Collections.emptyList();
157157

158158
StyledText textWidget= sourceViewer.getTextWidget();
159159
int startLine= textWidget.getTopIndex();
@@ -171,19 +171,19 @@ private void calculateAndShowStickyLines() {
171171
stickyScrollingControl.setStickyLines(stickyLines);
172172
}
173173

174-
private List<StickyLine> adaptStickyLinesToVisibleArea(List<StickyLine> stickyLines, int startLine) {
174+
private List<IStickyLine> adaptStickyLinesToVisibleArea(List<IStickyLine> stickyLines, int startLine) {
175175
if (stickyLines.isEmpty()) {
176176
return stickyLines;
177177
}
178178

179-
LinkedList<StickyLine> adaptedStickyLines= new LinkedList<>(stickyLines);
179+
LinkedList<IStickyLine> adaptedStickyLines= new LinkedList<>(stickyLines);
180180

181181
int firstVisibleLine= startLine + adaptedStickyLines.size();
182182
StyledText textWidget= sourceViewer.getTextWidget();
183183
int maximumLines= textWidget.getLineCount();
184184

185185
for (int i= startLine + 1; i <= firstVisibleLine && i < maximumLines; i++) {
186-
List<StickyLine> stickyLinesInLineI= stickyLinesProvider.getStickyLines(textWidget, i, stickyLinesProperties);
186+
List<IStickyLine> stickyLinesInLineI= stickyLinesProvider.getStickyLines(textWidget, i, stickyLinesProperties);
187187

188188
if (stickyLinesInLineI.size() > adaptedStickyLines.size()) {
189189
adaptedStickyLines= new LinkedList<>(stickyLinesInLineI);

tests/org.eclipse.ui.editors.tests/src/org/eclipse/ui/internal/texteditor/stickyscroll/DefaultStickyLinesProviderTest.java

+27-16
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import static org.hamcrest.MatcherAssert.assertThat;
1717
import static org.hamcrest.Matchers.empty;
1818
import static org.hamcrest.Matchers.is;
19-
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
19+
import static org.junit.Assert.assertEquals;
2020

2121
import java.util.List;
2222

@@ -51,7 +51,7 @@ public void setup() {
5151

5252
@Test
5353
public void testEmptySourceCode() {
54-
List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 0, stickyLinesProperties);
54+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 0, stickyLinesProperties);
5555

5656
assertThat(stickyLines, is(empty()));
5757
}
@@ -63,9 +63,10 @@ public void testSingleStickyLine() {
6363
line 2<""";
6464
setText(text);
6565

66-
List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 1, stickyLinesProperties);
66+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 1, stickyLinesProperties);
6767

68-
assertThat(stickyLines, contains(new StickyLine("line 1", 0)));
68+
assertEquals(1, stickyLines.size());
69+
assertEquals(0, stickyLines.get(0).getLineNumber());
6970
}
7071

7172
@Test
@@ -77,9 +78,10 @@ public void testLineUnderStickyLine() {
7778
line 4""";
7879
setText(text);
7980

80-
List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 1, stickyLinesProperties);
81+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 1, stickyLinesProperties);
8182

82-
assertThat(stickyLines, contains(new StickyLine("line 1", 0)));
83+
assertEquals(1, stickyLines.size());
84+
assertEquals(0, stickyLines.get(0).getLineNumber());
8385
}
8486

8587
@Test
@@ -91,9 +93,10 @@ public void testNewStickyRoot() {
9193
line 4<""";
9294
setText(text);
9395

94-
List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
96+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
9597

96-
assertThat(stickyLines, contains(new StickyLine("line 3", 2)));
98+
assertEquals(1, stickyLines.size());
99+
assertEquals(2, stickyLines.get(0).getLineNumber());
97100
}
98101

99102
@Test
@@ -106,9 +109,11 @@ public void testIgnoreEmptyLines() {
106109
line 3<""";
107110
setText(text);
108111

109-
List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 4, stickyLinesProperties);
112+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 4, stickyLinesProperties);
110113

111-
assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine(" line 2", 2)));
114+
assertEquals(2, stickyLines.size());
115+
assertEquals(0, stickyLines.get(0).getLineNumber());
116+
assertEquals(2, stickyLines.get(1).getLineNumber());
112117
}
113118

114119
@Test
@@ -120,9 +125,11 @@ public void testLinesWithTabs() {
120125
\t\tline 3<""";
121126
setText(text);
122127

123-
List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 2, stickyLinesProperties);
128+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 2, stickyLinesProperties);
124129

125-
assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine("\tline 2", 1)));
130+
assertEquals(2, stickyLines.size());
131+
assertEquals(0, stickyLines.get(0).getLineNumber());
132+
assertEquals(1, stickyLines.get(1).getLineNumber());
126133
}
127134

128135
@Test
@@ -136,9 +143,11 @@ public void testStartAtEmptyLineWithNext() {
136143
textWidget.setText(text);
137144
textWidget.setTopIndex(3);
138145

139-
List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
146+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
140147

141-
assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine(" line 2", 2)));
148+
assertEquals(2, stickyLines.size());
149+
assertEquals(0, stickyLines.get(0).getLineNumber());
150+
assertEquals(2, stickyLines.get(1).getLineNumber());
142151
}
143152

144153
@Test
@@ -151,9 +160,11 @@ public void testStartAtEmptyLineWithPrevious() {
151160
line 4""";
152161
setText(text);
153162

154-
List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
163+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
155164

156-
assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine(" line 2", 1)));
165+
assertEquals(2, stickyLines.size());
166+
assertEquals(0, stickyLines.get(0).getLineNumber());
167+
assertEquals(1, stickyLines.get(1).getLineNumber());
157168
}
158169

159170
/**

0 commit comments

Comments
 (0)