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 complex line adaption to central handler #2399

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 @@ -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
Expand All @@ -36,83 +33,31 @@ public class DefaultStickyLinesProvider implements IStickyLinesProvider {
private StickyLinesProperties fProperties;

@Override
public List<StickyLine> getStickyLines(ISourceViewer sourceViewer, StickyLinesProperties properties) {
if (sourceViewer.getTopIndex() == 0) {
return Collections.emptyList();
}

public List<StickyLine> getStickyLines(StyledText textWidget, int lineNumber, StickyLinesProperties properties) {
this.fProperties= properties;
LinkedList<StickyLine> 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<StickyLine> 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<StickyLine> 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<StickyLine> 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,32 @@
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
*/
public interface IStickyLinesProvider {

/**
* Calculate the sticky lines for the source code of the given sourceViewer. Specific
* properties, such as the <code>tabWidht</code> can be retrieved from the
* Calculate the sticky lines for the source code of the given textWidget. Specific properties,
* such as the <code>tabWidht</code> and the source viewer, can be retrieved from the
* <code>properties</code>.
*
* @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<StickyLine> getStickyLines(ISourceViewer sourceViewer, StickyLinesProperties properties);
public List<StickyLine> 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) {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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();
Expand Down Expand Up @@ -257,9 +265,6 @@ private void styleStickyLines() {

private List<StyleRange> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand All @@ -151,13 +153,52 @@ public void viewportChanged(int newVerticalOffset) {
}

private void calculateAndShowStickyLines() {
List<StickyLine> stickyLines= stickyLinesProvider.getStickyLines(sourceViewer, stickyLinesProperties);
List<StickyLine> 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<StickyLine> adaptStickyLinesToVisibleArea(List<StickyLine> stickyLines, int startLine) {
if (stickyLines.isEmpty()) {
return stickyLines;
}

LinkedList<StickyLine> 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);

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.
Expand Down
Loading
Loading