Skip to content

Commit 97881bf

Browse files
[StickyScrolling] Use source viewer to calculate the sticky lines
Use the source viewer instead of the text widget to calculate the sticky lines. The source viewer is the standard instance for source code operations in JDT and other editors. Preparation for #2398
1 parent ce9874f commit 97881bf

File tree

7 files changed

+117
-108
lines changed

7 files changed

+117
-108
lines changed

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
import org.eclipse.swt.custom.StyledText;
2121

22+
import org.eclipse.jface.text.ITextViewerExtension5;
23+
import org.eclipse.jface.text.source.ISourceViewer;
24+
2225
/**
2326
* This class provides sticky lines for the given source code in the source viewer. The
2427
* implementation is completely based on indentation and therefore works by default for several
@@ -33,14 +36,16 @@ public class DefaultStickyLinesProvider implements IStickyLinesProvider {
3336
private StickyLinesProperties fProperties;
3437

3538
@Override
36-
public List<IStickyLine> getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties) {
39+
public List<IStickyLine> getStickyLines(ISourceViewer sourceViewer, int lineNumber, StickyLinesProperties properties) {
3740
this.fProperties= properties;
3841
LinkedList<IStickyLine> stickyLines= new LinkedList<>();
3942

43+
StyledText textWidget= sourceViewer.getTextWidget();
44+
int textWidgetLineNumber= mapLineNumberToWidget(sourceViewer, lineNumber);
4045
try {
41-
int startIndetation= getStartIndentation(lineNumber, textWidget);
46+
int startIndetation= getStartIndentation(textWidgetLineNumber, textWidget);
4247

43-
for (int i= lineNumber, previousIndetation= startIndetation; i >= 0; i--) {
48+
for (int i= textWidgetLineNumber, previousIndetation= startIndetation; i >= 0; i--) {
4449
String line= textWidget.getLine(i);
4550
int indentation= getIndentation(line);
4651

@@ -50,7 +55,7 @@ public List<IStickyLine> getStickyLines(StyledText textWidget, int lineNumber, S
5055

5156
if (indentation < previousIndetation) {
5257
previousIndetation= indentation;
53-
stickyLines.addFirst(new StickyLine(i, textWidget));
58+
stickyLines.addFirst(new StickyLine(mapLineNumberToViewer(sourceViewer, i), textWidget));
5459
}
5560
}
5661
} catch (IllegalArgumentException e) {
@@ -101,4 +106,18 @@ private int getIndentation(String line) {
101106
return line.length() - line.stripLeading().length();
102107
}
103108

109+
private int mapLineNumberToWidget(ISourceViewer sourceViewer, int line) {
110+
if (sourceViewer instanceof ITextViewerExtension5 extension) {
111+
return extension.modelLine2WidgetLine(line);
112+
}
113+
return line;
114+
}
115+
116+
private int mapLineNumberToViewer(ISourceViewer sourceViewer, int line) {
117+
if (sourceViewer instanceof ITextViewerExtension5 extension) {
118+
return extension.widgetLine2ModelLine(line);
119+
}
120+
return line;
121+
}
122+
104123
}

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

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,35 @@
1515

1616
import java.util.List;
1717

18-
import org.eclipse.swt.custom.StyledText;
19-
2018
import org.eclipse.jface.text.source.ISourceViewer;
2119

2220
/**
23-
* A sticky lines provider calculates the sticky lines for a given text widget. The sticky lines
21+
* A sticky lines provider calculates the sticky lines for a given source viewer. The sticky lines
2422
* will be displayed in the top area of the editor.
2523
*
2624
* TODO move to public package and add since 3.19
2725
*/
2826
public interface IStickyLinesProvider {
2927

3028
/**
31-
* Calculate the sticky lines for the source code of the given textWidget. Specific properties,
32-
* such as the <code>tabWidht</code> and the source viewer, can be retrieved from the
29+
* Calculate the sticky lines for the source code of the given sourceViewer. Specific
30+
* properties, such as the <code>tabWidht</code>, can be retrieved from the
3331
* <code>properties</code>.
3432
*
35-
* @param textWidget The text widget containing the source code
33+
* @param sourceViewer The source viewer containing the source code and gives access to the text
34+
* widget
3635
* @param lineNumber The line number to calculate the sticky lines for
3736
* @param properties Properties for additional information
3837
* @return The list of sticky lines to show
3938
*/
40-
public List<IStickyLine> getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties);
39+
public List<IStickyLine> getStickyLines(ISourceViewer sourceViewer, int lineNumber, StickyLinesProperties properties);
4140

4241
/**
4342
* Additional properties and access in order to calculate the sticky lines.
4443
*
4544
* @param tabWith The with of a tab
46-
* @param sourceViewer The sourceViewer to access additional information
4745
*/
48-
record StickyLinesProperties(int tabWith, ISourceViewer sourceViewer) {
46+
record StickyLinesProperties(int tabWith) {
4947
}
5048

5149
}

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

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ private void updateStickyScrollingControls() {
206206
for (int i= 0; i < getNumberStickyLines(); i++) {
207207
IStickyLine stickyLine= stickyLines.get(i);
208208
stickyLineTextJoiner.add(stickyLine.getText());
209-
int lineNumber= getSourceViewerLineNumber(stickyLine.getLineNumber());
209+
int lineNumber= stickyLine.getLineNumber();
210210
stickyLineNumberJoiner.add(fillLineNumberWithLeadingSpaces(lineNumber + 1));
211211
}
212212

@@ -222,13 +222,6 @@ private void updateStickyScrollingControls() {
222222
}
223223
}
224224

225-
private int getSourceViewerLineNumber(int i) {
226-
if (sourceViewer instanceof ITextViewerExtension5 extension) {
227-
return extension.widgetLine2ModelLine(i);
228-
}
229-
return i;
230-
}
231-
232225
private String fillLineNumberWithLeadingSpaces(int lineNumber) {
233226
int lineCount= sourceViewer.getDocument().getNumberOfLines();
234227
int lineNumberLength= String.valueOf(lineCount).length();
@@ -399,6 +392,8 @@ private int getNumberStickyLines() {
399392
* resized/moved.<br>
400393
*/
401394
private void addSourceViewerListeners() {
395+
StyledText textWidget= sourceViewer.getTextWidget();
396+
402397
if (sourceViewer instanceof ITextViewerExtension4 extension) {
403398
textPresentationListener= e -> {
404399
Job.create("Update sticky lines styling", (ICoreRunnable) monitor -> { //$NON-NLS-1$
@@ -411,13 +406,12 @@ private void addSourceViewerListeners() {
411406
}
412407

413408
caretListener= new StickyScollingCaretListener();
414-
sourceViewer.getTextWidget().addCaretListener(caretListener);
415-
sourceViewer.getTextWidget().addKeyListener(caretListener);
409+
textWidget.addCaretListener(caretListener);
410+
textWidget.addKeyListener(caretListener);
416411

417412
controlListener= new ControlListener() {
418413
@Override
419414
public void controlResized(ControlEvent e) {
420-
StyledText textWidget= sourceViewer.getTextWidget();
421415
limitVisibleStickyLinesToTextWidgetHeight(textWidget);
422416
layoutStickyLines();
423417
if (stickyScrollingHandler != null) {
@@ -430,7 +424,7 @@ public void controlMoved(ControlEvent e) {
430424
layoutStickyLines();
431425
}
432426
};
433-
sourceViewer.getTextWidget().addControlListener(controlListener);
427+
textWidget.addControlListener(controlListener);
434428
}
435429

436430
private void limitVisibleStickyLinesToTextWidgetHeight(StyledText textWidget) {

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import java.util.LinkedList;
2626
import java.util.List;
2727

28-
import org.eclipse.swt.custom.StyledText;
2928
import org.eclipse.swt.graphics.Color;
3029
import org.eclipse.swt.graphics.RGB;
3130

@@ -140,7 +139,7 @@ private StickyScrollingControlSettings loadControlSettings(IPreferenceStore stor
140139

141140
private StickyLinesProperties loadStickyLinesProperties(IPreferenceStore store) {
142141
int tabWidth= store.getInt(EDITOR_TAB_WIDTH);
143-
return new StickyLinesProperties(tabWidth, sourceViewer);
142+
return new StickyLinesProperties(tabWidth);
144143
}
145144

146145
@Override
@@ -155,11 +154,10 @@ public void viewportChanged(int newVerticalOffset) {
155154
private void calculateAndShowStickyLines() {
156155
List<IStickyLine> stickyLines= Collections.emptyList();
157156

158-
StyledText textWidget= sourceViewer.getTextWidget();
159-
int startLine= textWidget.getTopIndex();
157+
int startLine= sourceViewer.getTopIndex();
160158

161159
if (startLine > 0) {
162-
stickyLines= stickyLinesProvider.getStickyLines(textWidget, startLine, stickyLinesProperties);
160+
stickyLines= stickyLinesProvider.getStickyLines(sourceViewer, sourceViewer.getTopIndex(), stickyLinesProperties);
163161
}
164162

165163
if (stickyLines == null) {
@@ -179,11 +177,10 @@ private List<IStickyLine> adaptStickyLinesToVisibleArea(List<IStickyLine> sticky
179177
LinkedList<IStickyLine> adaptedStickyLines= new LinkedList<>(stickyLines);
180178

181179
int firstVisibleLine= startLine + adaptedStickyLines.size();
182-
StyledText textWidget= sourceViewer.getTextWidget();
183-
int maximumLines= textWidget.getLineCount();
180+
int numberOfLines= sourceViewer.getDocument().getNumberOfLines();
184181

185-
for (int i= startLine + 1; i <= firstVisibleLine && i < maximumLines; i++) {
186-
List<IStickyLine> stickyLinesInLineI= stickyLinesProvider.getStickyLines(textWidget, i, stickyLinesProperties);
182+
for (int i= startLine + 1; i <= firstVisibleLine && i < numberOfLines; i++) {
183+
List<IStickyLine> stickyLinesInLineI= stickyLinesProvider.getStickyLines(sourceViewer, i, stickyLinesProperties);
187184

188185
if (stickyLinesInLineI.size() > adaptedStickyLines.size()) {
189186
adaptedStickyLines= new LinkedList<>(stickyLinesInLineI);

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

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@
2525

2626
import org.eclipse.swt.SWT;
2727
import org.eclipse.swt.custom.StyledText;
28+
import org.eclipse.swt.widgets.Composite;
2829
import org.eclipse.swt.widgets.Display;
2930
import org.eclipse.swt.widgets.Shell;
3031

32+
import org.eclipse.jface.text.IRegion;
33+
import org.eclipse.jface.text.ITextViewerExtension5;
34+
import org.eclipse.jface.text.source.IVerticalRuler;
3135
import org.eclipse.jface.text.source.SourceViewer;
3236

3337
import org.eclipse.ui.internal.texteditor.stickyscroll.IStickyLinesProvider.StickyLinesProperties;
@@ -46,12 +50,12 @@ public void setup() {
4650
sourceViewer = new SourceViewer(shell, null, SWT.None);
4751
stickyLinesProvider = new DefaultStickyLinesProvider();
4852
textWidget = sourceViewer.getTextWidget();
49-
stickyLinesProperties = new StickyLinesProperties(4, sourceViewer);
53+
stickyLinesProperties = new StickyLinesProperties(4);
5054
}
5155

5256
@Test
5357
public void testEmptySourceCode() {
54-
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 0, stickyLinesProperties);
58+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 0, stickyLinesProperties);
5559

5660
assertThat(stickyLines, is(empty()));
5761
}
@@ -63,7 +67,7 @@ public void testSingleStickyLine() {
6367
line 2<""";
6468
setText(text);
6569

66-
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 1, stickyLinesProperties);
70+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 1, stickyLinesProperties);
6771

6872
assertEquals(1, stickyLines.size());
6973
assertEquals(0, stickyLines.get(0).getLineNumber());
@@ -78,7 +82,7 @@ public void testLineUnderStickyLine() {
7882
line 4""";
7983
setText(text);
8084

81-
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 1, stickyLinesProperties);
85+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 1, stickyLinesProperties);
8286

8387
assertEquals(1, stickyLines.size());
8488
assertEquals(0, stickyLines.get(0).getLineNumber());
@@ -93,7 +97,7 @@ public void testNewStickyRoot() {
9397
line 4<""";
9498
setText(text);
9599

96-
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
100+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 3, stickyLinesProperties);
97101

98102
assertEquals(1, stickyLines.size());
99103
assertEquals(2, stickyLines.get(0).getLineNumber());
@@ -109,7 +113,7 @@ public void testIgnoreEmptyLines() {
109113
line 3<""";
110114
setText(text);
111115

112-
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 4, stickyLinesProperties);
116+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 4, stickyLinesProperties);
113117

114118
assertEquals(2, stickyLines.size());
115119
assertEquals(0, stickyLines.get(0).getLineNumber());
@@ -118,14 +122,14 @@ public void testIgnoreEmptyLines() {
118122

119123
@Test
120124
public void testLinesWithTabs() {
121-
stickyLinesProperties = new StickyLinesProperties(2, sourceViewer);
125+
stickyLinesProperties = new StickyLinesProperties(2);
122126
String text = """
123127
line 1
124128
\tline 2
125129
\t\tline 3<""";
126130
setText(text);
127131

128-
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 2, stickyLinesProperties);
132+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 2, stickyLinesProperties);
129133

130134
assertEquals(2, stickyLines.size());
131135
assertEquals(0, stickyLines.get(0).getLineNumber());
@@ -143,7 +147,7 @@ public void testStartAtEmptyLineWithNext() {
143147
textWidget.setText(text);
144148
textWidget.setTopIndex(3);
145149

146-
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
150+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 3, stickyLinesProperties);
147151

148152
assertEquals(2, stickyLines.size());
149153
assertEquals(0, stickyLines.get(0).getLineNumber());
@@ -160,13 +164,31 @@ public void testStartAtEmptyLineWithPrevious() {
160164
line 4""";
161165
setText(text);
162166

163-
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
167+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 3, stickyLinesProperties);
164168

165169
assertEquals(2, stickyLines.size());
166170
assertEquals(0, stickyLines.get(0).getLineNumber());
167171
assertEquals(1, stickyLines.get(1).getLineNumber());
168172
}
169173

174+
@Test
175+
public void testStickyLineWithSourceViewerLineMapping() {
176+
sourceViewer = new SourceViewerWithLineMapping(shell, null, SWT.None);
177+
textWidget = sourceViewer.getTextWidget();
178+
179+
String text = """
180+
line 1
181+
line 2<""";
182+
setText(text);
183+
184+
// Source viewer line 43 that is mapped to line 1 in the text widget
185+
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(sourceViewer, 1 + 42, stickyLinesProperties);
186+
187+
assertEquals(1, stickyLines.size());
188+
// Source viewer line 42 that is mapped to line 0 in the text widget
189+
assertEquals(0 + 42, stickyLines.get(0).getLineNumber());
190+
}
191+
170192
/**
171193
* Set the text into the text widget and set the top index to the line
172194
* containing the <.
@@ -175,4 +197,32 @@ private void setText(String text) {
175197
textWidget.setText(text);
176198
}
177199

200+
private class SourceViewerWithLineMapping extends SourceViewer implements ITextViewerExtension5 {
201+
202+
public SourceViewerWithLineMapping(Composite parent, IVerticalRuler ruler, int styles) {
203+
super(parent, ruler, styles);
204+
}
205+
206+
@Override
207+
public IRegion[] getCoveredModelRanges(IRegion modelRange) {
208+
return null;
209+
}
210+
211+
@Override
212+
public boolean exposeModelRange(IRegion modelRange) {
213+
return false;
214+
}
215+
216+
@Override
217+
public int widgetLine2ModelLine(int widgetLine) {
218+
return widgetLine + 42;
219+
}
220+
221+
@Override
222+
public int modelLine2WidgetLine(int widgetLine) {
223+
return widgetLine - 42;
224+
}
225+
226+
}
227+
178228
}

0 commit comments

Comments
 (0)