Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[StickyScrolling] Move text and style calculation to StickyLine #2412

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ public class DefaultStickyLinesProvider implements IStickyLinesProvider {
private StickyLinesProperties fProperties;

@Override
public List<StickyLine> getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties) {
public List<IStickyLine> getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties) {
this.fProperties= properties;
LinkedList<StickyLine> stickyLines= new LinkedList<>();
LinkedList<IStickyLine> stickyLines= new LinkedList<>();

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

if (indentation < previousIndetation) {
previousIndetation= indentation;
stickyLines.addFirst(new StickyLine(line, i));
stickyLines.addFirst(new StickyLine(i, textWidget));
}
}
} catch (IllegalArgumentException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2024 SAP SE.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* SAP SE - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.texteditor.stickyscroll;

import org.eclipse.swt.custom.StyleRange;

/**
* Representation of a sticky line.
*/
public interface IStickyLine {

/**
* Returns the line number of the sticky line.
*
* @return the line number of the sticky line
*/
int getLineNumber();

/**
* Returns the text of the sticky line.
*
* @return the text of the sticky line
*/
String getText();

/**
* Returns the style ranges of the sticky line.
*
* @return the style ranges of the sticky line
*/
StyleRange[] getStyleRanges();

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public interface IStickyLinesProvider {
* @param properties Properties for additional information
* @return The list of sticky lines to show
*/
public List<StickyLine> getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties);
public List<IStickyLine> getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties);

/**
* Additional properties and access in order to calculate the sticky lines.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,47 @@
*******************************************************************************/
package org.eclipse.ui.internal.texteditor.stickyscroll;

import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;

/**
*
* A record representing a sticky line containing the text to display, and line number. It serves as
* an abstraction to represent sticky line for sticky scrolling.
*
* @param text the text of the corresponding sticky line
* @param lineNumber the specific line number of the sticky line
* Default implementation of {@link IStickyLine}. Information about the text and style ranges are
* calculated from the given text widget.
*/
public record StickyLine(String text, int lineNumber) {
public class StickyLine implements IStickyLine {

private int lineNumber;

private String text;

private StyledText textWidget;

public StickyLine(int lineNumber, StyledText textWidget) {
this.lineNumber= lineNumber;
this.textWidget= textWidget;
}

@Override
public int getLineNumber() {
return this.lineNumber;
}

@Override
public String getText() {
if (text == null) {
text= textWidget.getLine(lineNumber);
}
return text;
}

@Override
public StyleRange[] getStyleRanges() {
int offsetAtLine= textWidget.getOffsetAtLine(lineNumber);
StyleRange[] styleRanges= textWidget.getStyleRanges(offsetAtLine, getText().length());
for (StyleRange styleRange : styleRanges) {
styleRange.start= styleRange.start - offsetAtLine;
}
return styleRanges;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
package org.eclipse.ui.internal.texteditor.stickyscroll;

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

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

private List<StickyLine> stickyLines;
private List<IStickyLine> stickyLines;

private ISourceViewer sourceViewer;

Expand Down Expand Up @@ -135,7 +133,7 @@ public StickyScrollingControl(ISourceViewer sourceViewer, IVerticalRuler vertica
*
* @param stickyLines The sticky lines to show
*/
public void setStickyLines(List<StickyLine> stickyLines) {
public void setStickyLines(List<IStickyLine> stickyLines) {
if (!stickyLines.equals(this.stickyLines)) {
this.stickyLines= stickyLines;
updateStickyScrollingControls();
Expand Down Expand Up @@ -206,9 +204,9 @@ private void updateStickyScrollingControls() {
StringJoiner stickyLineTextJoiner= new StringJoiner(System.lineSeparator());
StringJoiner stickyLineNumberJoiner= new StringJoiner(System.lineSeparator());
for (int i= 0; i < getNumberStickyLines(); i++) {
StickyLine stickyLine= stickyLines.get(i);
stickyLineTextJoiner.add(stickyLine.text());
int lineNumber= getSourceViewerLineNumber(stickyLine.lineNumber());
IStickyLine stickyLine= stickyLines.get(i);
stickyLineTextJoiner.add(stickyLine.getText());
int lineNumber= getSourceViewerLineNumber(stickyLine.getLineNumber());
stickyLineNumberJoiner.add(fillLineNumberWithLeadingSpaces(lineNumber + 1));
}

Expand Down Expand Up @@ -244,14 +242,20 @@ private void styleStickyLines() {
return;
}

List<StyleRange> stickyLinesStyleRanges= new ArrayList<>();
int stickyLineTextOffset= 0;
for (int i= 0; i < getNumberStickyLines(); i++) {
StickyLine stickyLine= stickyLines.get(i);
stickyLinesStyleRanges.addAll(getStickyLineStyleRanges(stickyLine, stickyLineTextOffset));
stickyLineTextOffset+= stickyLine.text().length() + System.lineSeparator().length();
int stickyLineOffset= 0;
List<StyleRange> styleRanges= new ArrayList<>();
for (IStickyLine stickyLine : stickyLines) {
StyleRange[] ranges= stickyLine.getStyleRanges();
if (ranges != null) {
for (StyleRange styleRange : ranges) {
styleRange.start+= stickyLineOffset;
styleRanges.add(styleRange);
}
}

stickyLineOffset+= stickyLine.getText().length() + System.lineSeparator().length();
}
stickyLineText.setStyleRanges(stickyLinesStyleRanges.toArray(StyleRange[]::new));
stickyLineText.setStyleRanges(styleRanges.toArray(StyleRange[]::new));

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

private List<StyleRange> getStickyLineStyleRanges(StickyLine stickyLine, int stickyLineTextOffset) {
int lineNumber= stickyLine.lineNumber();
try {
StyledText textWidget= sourceViewer.getTextWidget();
int offsetAtLine= textWidget.getOffsetAtLine(lineNumber);
StyleRange[] styleRanges= textWidget.getStyleRanges(offsetAtLine, stickyLine.text().length());
for (StyleRange styleRange : styleRanges) {
styleRange.start= styleRange.start - offsetAtLine + stickyLineTextOffset;
}
return Arrays.asList(styleRanges);
} catch (IllegalArgumentException e) {
//Styling could not be copied, skip!
return Collections.emptyList();
}
}

private void layoutStickyLines() {
if (getNumberStickyLines() == 0) {
stickyLinesCanvas.setVisible(false);
Expand Down Expand Up @@ -365,12 +353,12 @@ private void calculateAndSetStickyLinesCanvasBounds() {

private void navigateToClickedLine(MouseEvent event) {
int clickedStickyLineIndex= stickyLineText.getLineIndex(event.y);
StickyLine clickedStickyLine= stickyLines.get(clickedStickyLineIndex);
IStickyLine clickedStickyLine= stickyLines.get(clickedStickyLineIndex);

try {
int offset= sourceViewer.getDocument().getLineOffset(clickedStickyLine.lineNumber());
int offset= sourceViewer.getDocument().getLineOffset(clickedStickyLine.getLineNumber());
sourceViewer.setSelectedRange(offset, 0);
ensureSourceViewerLineVisible(clickedStickyLine.lineNumber());
ensureSourceViewerLineVisible(clickedStickyLine.getLineNumber());
} catch (BadLocationException e) {
//Do not navigate
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public void viewportChanged(int newVerticalOffset) {
}

private void calculateAndShowStickyLines() {
List<StickyLine> stickyLines= Collections.emptyList();
List<IStickyLine> stickyLines= Collections.emptyList();

StyledText textWidget= sourceViewer.getTextWidget();
int startLine= textWidget.getTopIndex();
Expand All @@ -171,19 +171,19 @@ private void calculateAndShowStickyLines() {
stickyScrollingControl.setStickyLines(stickyLines);
}

private List<StickyLine> adaptStickyLinesToVisibleArea(List<StickyLine> stickyLines, int startLine) {
private List<IStickyLine> adaptStickyLinesToVisibleArea(List<IStickyLine> stickyLines, int startLine) {
if (stickyLines.isEmpty()) {
return stickyLines;
}

LinkedList<StickyLine> adaptedStickyLines= new LinkedList<>(stickyLines);
LinkedList<IStickyLine> 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<StickyLine> stickyLinesInLineI= stickyLinesProvider.getStickyLines(textWidget, i, stickyLinesProperties);
List<IStickyLine> stickyLinesInLineI= stickyLinesProvider.getStickyLines(textWidget, i, stickyLinesProperties);

if (stickyLinesInLineI.size() > adaptedStickyLines.size()) {
adaptedStickyLines= new LinkedList<>(stickyLinesInLineI);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
import static org.junit.Assert.assertEquals;

import java.util.List;

Expand Down Expand Up @@ -51,7 +51,7 @@ public void setup() {

@Test
public void testEmptySourceCode() {
List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 0, stickyLinesProperties);
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 0, stickyLinesProperties);

assertThat(stickyLines, is(empty()));
}
Expand All @@ -63,9 +63,10 @@ public void testSingleStickyLine() {
line 2<""";
setText(text);

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

assertThat(stickyLines, contains(new StickyLine("line 1", 0)));
assertEquals(1, stickyLines.size());
assertEquals(0, stickyLines.get(0).getLineNumber());
}

@Test
Expand All @@ -77,9 +78,10 @@ public void testLineUnderStickyLine() {
line 4""";
setText(text);

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

assertThat(stickyLines, contains(new StickyLine("line 1", 0)));
assertEquals(1, stickyLines.size());
assertEquals(0, stickyLines.get(0).getLineNumber());
}

@Test
Expand All @@ -91,9 +93,10 @@ public void testNewStickyRoot() {
line 4<""";
setText(text);

List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);

assertThat(stickyLines, contains(new StickyLine("line 3", 2)));
assertEquals(1, stickyLines.size());
assertEquals(2, stickyLines.get(0).getLineNumber());
}

@Test
Expand All @@ -106,9 +109,11 @@ public void testIgnoreEmptyLines() {
line 3<""";
setText(text);

List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 4, stickyLinesProperties);
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 4, stickyLinesProperties);

assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine(" line 2", 2)));
assertEquals(2, stickyLines.size());
assertEquals(0, stickyLines.get(0).getLineNumber());
assertEquals(2, stickyLines.get(1).getLineNumber());
}

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

List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 2, stickyLinesProperties);
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 2, stickyLinesProperties);

assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine("\tline 2", 1)));
assertEquals(2, stickyLines.size());
assertEquals(0, stickyLines.get(0).getLineNumber());
assertEquals(1, stickyLines.get(1).getLineNumber());
}

@Test
Expand All @@ -136,9 +143,11 @@ public void testStartAtEmptyLineWithNext() {
textWidget.setText(text);
textWidget.setTopIndex(3);

List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);

assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine(" line 2", 2)));
assertEquals(2, stickyLines.size());
assertEquals(0, stickyLines.get(0).getLineNumber());
assertEquals(2, stickyLines.get(1).getLineNumber());
}

@Test
Expand All @@ -151,9 +160,11 @@ public void testStartAtEmptyLineWithPrevious() {
line 4""";
setText(text);

List<StickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);
List<IStickyLine> stickyLines = stickyLinesProvider.getStickyLines(textWidget, 3, stickyLinesProperties);

assertThat(stickyLines, contains(new StickyLine("line 1", 0), new StickyLine(" line 2", 1)));
assertEquals(2, stickyLines.size());
assertEquals(0, stickyLines.get(0).getLineNumber());
assertEquals(1, stickyLines.get(1).getLineNumber());
}

/**
Expand Down
Loading
Loading