Skip to content

Commit

Permalink
additional constructor param afterPosition in LineContentCodeMining
Browse files Browse the repository at this point in the history
which allows to render a code mining where the cursor selection does not
include the code mining at the given source position.
  • Loading branch information
tobias-melcher committed Sep 30, 2024
1 parent dfb9e06 commit 46e6ea3
Show file tree
Hide file tree
Showing 10 changed files with 242 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public class CodeMiningLineContentAnnotation extends LineContentAnnotation imple
*/
private IProgressMonitor fMonitor;

private final boolean afterPosition;

/**
* Code mining annotation constructor.
*
Expand All @@ -72,6 +74,21 @@ public CodeMiningLineContentAnnotation(Position position, ISourceViewer viewer)
fResolvedMinings= null;
fMinings= new ArrayList<>();
fBounds= new ArrayList<>();
afterPosition= false;
}

/**
* Code mining annotation constructor.
*
* @param position the position
* @param viewer the viewer
*/
public CodeMiningLineContentAnnotation(Position position, ISourceViewer viewer, boolean afterPosition) {
super(position, viewer);
fResolvedMinings= null;
fMinings= new ArrayList<>();
fBounds= new ArrayList<>();
this.afterPosition= afterPosition;
}

@Override
Expand Down Expand Up @@ -183,4 +200,16 @@ public Consumer<MouseEvent> getAction(MouseEvent e) {
public boolean isInVisibleLines() {
return super.isInVisibleLines();
}

public final boolean isAfterPosition() {
return afterPosition;
}

@Override
protected boolean drawRightToPreviousChar(int widgetOffset, StyledText textWidget) {
if (isAfterPosition()) {
return false;
}
return super.drawRightToPreviousChar(widgetOffset, textWidget);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.codemining.ICodeMining;
import org.eclipse.jface.text.codemining.ICodeMiningProvider;
import org.eclipse.jface.text.codemining.LineContentCodeMining;
import org.eclipse.jface.text.codemining.LineHeaderCodeMining;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.inlined.AbstractInlinedAnnotation;
Expand Down Expand Up @@ -251,12 +252,17 @@ private void renderCodeMinings(Map<Position, List<ICodeMining>> groups, ISourceV

Position pos= new Position(g.getKey().offset, g.getKey().length);
List<ICodeMining> minings= g.getValue();
boolean inLineHeader= !minings.isEmpty() ? (minings.get(0) instanceof LineHeaderCodeMining) : true;
ICodeMining first= minings.get(0);
boolean inLineHeader= !minings.isEmpty() ? (first instanceof LineHeaderCodeMining) : true;
// Try to find existing annotation
AbstractInlinedAnnotation ann= fInlinedAnnotationSupport.findExistingAnnotation(pos);
if (ann == null) {
// The annotation doesn't exists, create it.
ann= inLineHeader ? new CodeMiningLineHeaderAnnotation(pos, viewer) : new CodeMiningLineContentAnnotation(pos, viewer);
boolean afterPosition= false;
if (first instanceof LineContentCodeMining m) {
afterPosition= m.isAfterPosition();
}
ann= inLineHeader ? new CodeMiningLineHeaderAnnotation(pos, viewer) : new CodeMiningLineContentAnnotation(pos, viewer, afterPosition);
} else if (ann instanceof ICodeMiningAnnotation && ((ICodeMiningAnnotation) ann).isInVisibleLines()) {
// annotation is in visible lines
annotationsToRedraw.add((ICodeMiningAnnotation) ann);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
*******************************************************************************/
package org.eclipse.jface.text;

import java.util.HashSet;
import java.util.Set;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
Expand Down Expand Up @@ -405,6 +405,10 @@ private void drawCharRange(GC gc, int startOffset, int endOffset, int lineOffset
break;
case '\r':
if (fShowCarriageReturn) {
if (visibleChar.length() > 0 && cache.contains(fTextWidget, lineOffset + textOffset)) {
textOffset--;
break;
}
visibleChar.append(CARRIAGE_RETURN_SIGN);
}
if (textOffset >= endOffsetInLine - 1 || lineText.charAt(textOffset + 1) != '\n') {
Expand All @@ -414,6 +418,10 @@ private void drawCharRange(GC gc, int startOffset, int endOffset, int lineOffset
continue;
case '\n':
if (fShowLineFeed) {
if (visibleChar.length() > 0 && cache.contains(fTextWidget, lineOffset + textOffset)) {
textOffset--;
break;
}
visibleChar.append(LINE_FEED_SIGN);
}
eol= true;
Expand All @@ -439,7 +447,7 @@ private void drawCharRange(GC gc, int startOffset, int endOffset, int lineOffset
fg= styleRange.foreground;
}
}
draw(gc, widgetOffset, visibleChar.toString(), fg);
draw(gc, widgetOffset, visibleChar.toString(), fg, cache);
}
visibleChar.delete(0, visibleChar.length());
}
Expand Down Expand Up @@ -492,40 +500,57 @@ private void redrawAll() {
* @param s the string to be drawn
* @param fg the foreground color
*/
private void draw(GC gc, int offset, String s, Color fg) {
private void draw(GC gc, int offset, String s, Color fg,StyleRangeWithMetricsOffsets cache) {
// Compute baseline delta (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=165640)
int baseline= fTextWidget.getBaseline(offset);
FontMetrics fontMetrics= gc.getFontMetrics();
int fontBaseline= fontMetrics.getAscent() + fontMetrics.getLeading();
int baslineDelta= baseline - fontBaseline;

Point pos= fTextWidget.getLocationAtOffset(offset);
StyleRange styleRange= cache.get(fTextWidget, offset);
if (styleRange != null && styleRange.metrics != null) { // code mining at \r or \n character - line break character should be drawn at end of code mining
String charBeforeOffset= " "; //$NON-NLS-1$
if (offset > 0) {
charBeforeOffset= fTextWidget.getText(offset - 1, offset - 1);
}
Point extCharBeforeOffset= gc.textExtent(charBeforeOffset);
pos.x= pos.x + styleRange.metrics.width - extCharBeforeOffset.x;
}
gc.setForeground(fg);
gc.drawString(s, pos.x, pos.y + baslineDelta, true);
}

private static class StyleRangeWithMetricsOffsets {
private Set<Integer> offsets= null;
private Map<Integer, StyleRange> offsets= null;

public boolean contains(StyledText st, int offset) {
if (offsets == null) {
fillSet(st);
fillMap(st);
}
if (offsets.contains(offset)) {
if (offsets.containsKey(offset)) {
return true;
}
return false;
}

private void fillSet(StyledText st) {
offsets= new HashSet<>();
public StyleRange get(StyledText st, int offset) {
if (offsets == null) {
fillMap(st);
}
StyleRange styleRange= offsets.get(offset);
return styleRange;
}

private void fillMap(StyledText st) {
offsets= new HashMap<>();
StyleRange[] ranges= st.getStyleRanges();
if (ranges == null) {
return;
}
for (StyleRange range : ranges) {
if (range != null && range.metrics != null) {
offsets.add(range.start);
offsets.put(range.start, range);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
*/
public abstract class LineContentCodeMining extends AbstractCodeMining {

/**
* indicates if code mining should be rendered after given position; cursor and selection does
* not include the code mining if set to true.
*/

Check warning on line 32 in bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/codemining/LineContentCodeMining.java

View check run for this annotation

Jenkins - Eclipse Platform / Compiler and API Tools

Other

ERROR: The field org.eclipse.jface.text.codemining.LineContentCodeMining.afterPosition has been added to a class

Check warning on line 32 in bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/codemining/LineContentCodeMining.java

View check run for this annotation

Jenkins - Eclipse Platform / Compiler and API Tools

Other

ERROR: Missing @SInCE tag on afterPosition
protected boolean afterPosition= false;

/**
* CodeMining constructor to locate the code mining in a given position.
*
Expand All @@ -36,6 +42,18 @@ public LineContentCodeMining(Position position, ICodeMiningProvider provider) {
this(position, provider, null);
}

/**
* CodeMining constructor to locate the code mining in a given position.
*
* @param position the position where the mining must be drawn.
* @param afterPosition if true code mining is treated as suffix code mining where cursor and
* selection is not including the mining
* @param provider the owner codemining provider which creates this mining.
*/

Check warning on line 52 in bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/codemining/LineContentCodeMining.java

View check run for this annotation

Jenkins - Eclipse Platform / Compiler and API Tools

Other

ERROR: Missing @SInCE tag on LineContentCodeMining(Position, boolean, ICodeMiningProvider)
public LineContentCodeMining(Position position, boolean afterPosition, ICodeMiningProvider provider) {
this(position, afterPosition, provider, null);
}

/**
* CodeMining constructor to locate the code mining in a given position.
*
Expand All @@ -44,7 +62,25 @@ public LineContentCodeMining(Position position, ICodeMiningProvider provider) {
* @param action the action to execute when mining is clicked and null otherwise.
*/
public LineContentCodeMining(Position position, ICodeMiningProvider provider, Consumer<MouseEvent> action) {
this(position, false, provider, action);
}

/**
* CodeMining constructor to locate the code mining in a given position.
*
* @param position the position where the mining must be drawn.
* @param provider the owner codemining provider which creates this mining.
* @param action the action to execute when mining is clicked and null otherwise.
* @param afterPosition if true code mining is treated as suffix code mining where cursor and
* selection is not including the mining
*/

Check warning on line 76 in bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/codemining/LineContentCodeMining.java

View check run for this annotation

Jenkins - Eclipse Platform / Compiler and API Tools

Other

ERROR: Missing @SInCE tag on LineContentCodeMining(Position, boolean, ICodeMiningProvider, Consumer )
public LineContentCodeMining(Position position, boolean afterPosition, ICodeMiningProvider provider, Consumer<MouseEvent> action) {
super(position, provider, action);
this.afterPosition= afterPosition;
}

Check warning on line 81 in bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/codemining/LineContentCodeMining.java

View check run for this annotation

Jenkins - Eclipse Platform / Compiler and API Tools

Other

ERROR: Missing @SInCE tag on isAfterPosition()
public boolean isAfterPosition() {
return afterPosition;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;

import org.eclipse.jface.internal.text.codemining.CodeMiningLineContentAnnotation;

import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.AnnotationPainter.IDrawingStrategy;
Expand Down Expand Up @@ -202,9 +204,15 @@ private static void draw(LineHeaderAnnotation annotation, GC gc, StyledText text
*/
private static void draw(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length,
Color color) {
if (annotation instanceof CodeMiningLineContentAnnotation a) {
if (a.isAfterPosition()) {
drawAsLeftOf1stCharacter(annotation, gc, textWidget, widgetOffset, length, color);
return;
}
}
if (annotation.isEmptyLine(widgetOffset, textWidget)) {
drawAfterLine(annotation, gc, textWidget, widgetOffset, length, color);
} else if (LineContentAnnotation.drawRightToPreviousChar(widgetOffset, textWidget)) {
} else if (annotation.drawRightToPreviousChar(widgetOffset, textWidget)) {
drawAsRightOfPreviousCharacter(annotation, gc, textWidget, widgetOffset, length, color);
} else {
drawAsLeftOf1stCharacter(annotation, gc, textWidget, widgetOffset, length, color);
Expand Down Expand Up @@ -254,9 +262,18 @@ protected static void drawAsLeftOf1stCharacter(LineContentAnnotation annotation,

// Compute the location of the annotation
Rectangle bounds= textWidget.getTextBounds(widgetOffset, widgetOffset);
int x= bounds.x + (isEndOfLine ? bounds.width * 2 : 0);
int y= bounds.y;

int x;
if (isEndOfLine) {
// getTextBounds at offset with char '\r' or '\n' returns incorrect x position, use getLocationAtOffset instead
x= textWidget.getLocationAtOffset(widgetOffset).x;
} else {
x= bounds.x;
}
int y= bounds.y;
if (isAfterPosition(annotation)) {
isEndOfLine= false;
}
// When line text has line header annotation, there is a space on the top, adjust the y by using char height
y+= bounds.height - textWidget.getLineHeight();

Expand All @@ -275,7 +292,10 @@ protected static void drawAsLeftOf1stCharacter(LineContentAnnotation annotation,
// Get size of the character where GlyphMetrics width is added
Point charBounds= gc.stringExtent(hostCharacter);
int charWidth= charBounds.x;

if (charWidth == 0 && ("\r".equals(hostCharacter) || "\n".equals(hostCharacter))) { //$NON-NLS-1$ //$NON-NLS-2$
// charWidth is 0 for '\r' on font Consolas, but not on other fonts, why?
charWidth= gc.stringExtent(" ").x; //$NON-NLS-1$
}
// FIXME: remove this code when we need not redraw the character (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=531769)
// START TO REMOVE
annotation.setRedrawnCharacterWidth(charWidth);
Expand Down Expand Up @@ -328,6 +348,13 @@ protected static void drawAsLeftOf1stCharacter(LineContentAnnotation annotation,
}
}

private static boolean isAfterPosition(LineContentAnnotation annotation) {
if (annotation instanceof CodeMiningLineContentAnnotation a) {
return a.isAfterPosition();
}
return false;
}

protected static void drawAsRightOfPreviousCharacter(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) {
StyleRange style= null;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ StyleRange updateStyle(StyleRange style, FontMetrics fontMetrics, ITextViewer vi
return style;
}

Check warning on line 160 in bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java

View check run for this annotation

Jenkins - Eclipse Platform / Compiler and API Tools

Other

ERROR: The static method org.eclipse.jface.text.source.inlined.LineContentAnnotation.drawRightToPreviousChar(int, StyledText) has been converted to an instance method

Check warning on line 160 in bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java

View check run for this annotation

Jenkins - Eclipse Platform / Compiler and API Tools

Other

ERROR: Missing @SInCE tag on drawRightToPreviousChar(int, StyledText)
static boolean drawRightToPreviousChar(int widgetOffset, StyledText textWidget) {
protected boolean drawRightToPreviousChar(int widgetOffset, StyledText textWidget) {
return widgetOffset > 0 && widgetOffset < textWidget.getCharCount() &&
textWidget.getLineAtOffset(widgetOffset) == textWidget.getLineAtOffset(widgetOffset - 1);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
import java.util.concurrent.atomic.AtomicReference;

import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewerExtension2;
import org.eclipse.jface.text.WhitespaceCharacterPainter;
import org.eclipse.jface.text.codemining.ICodeMiningProvider;
import org.eclipse.jface.text.reconciler.DirtyRegion;
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
Expand All @@ -42,6 +44,8 @@
*/
public class CodeMiningDemo {

private static boolean showWhitespaces = false;

public static void main(String[] args) throws Exception {

Display display = new Display();
Expand All @@ -54,7 +58,13 @@ public static void main(String[] args) throws Exception {
endOfLineText.setText(endOfLineString.get());
GridDataFactory.fillDefaults().grab(true, false).applyTo(endOfLineText);

ISourceViewer sourceViewer = new SourceViewer(shell, null, SWT.V_SCROLL | SWT.BORDER);
SourceViewer sourceViewer = new SourceViewer(shell, null, SWT.V_SCROLL | SWT.BORDER);
sourceViewer.getTextWidget().setFont(JFaceResources.getTextFont());
if (showWhitespaces) {
WhitespaceCharacterPainter whitespaceCharPainter = new WhitespaceCharacterPainter(sourceViewer, true, true,
true, true, true, true, true, true, true, true, true, 100);
sourceViewer.addPainter(whitespaceCharPainter);
}
sourceViewer.setDocument(
new Document("// Type class & new keyword and see references CodeMining\n"
+ "// Name class with a number N to emulate Nms before resolving the references CodeMining\n"
Expand All @@ -71,7 +81,8 @@ public static void main(String[] args) throws Exception {
+ "new 5\n" //
+ "new 5\n" //
+ "multiline \n" //
+ "multiline \n\n"),
+ "multiline \n\n" //
+ "suffix \n"),
new AnnotationModel());
GridDataFactory.fillDefaults().grab(true, true).applyTo(sourceViewer.getTextWidget());
// Add AnnotationPainter (required by CodeMining)
Expand All @@ -83,7 +94,8 @@ public static void main(String[] args) throws Exception {
new ToEchoWithHeaderAndInlineCodeMiningProvider("echo"), //
new MultilineCodeMiningProvider(), //
new EmptyLineCodeMiningProvider(), //
new EchoAtEndOfLineCodeMiningProvider(endOfLineString) });
new EchoAtEndOfLineCodeMiningProvider(endOfLineString), //
new LineContentCodeMiningAfterPositionProvider() });
// Execute codemining in a reconciler
MonoReconciler reconciler = new MonoReconciler(new IReconcilingStrategy() {

Expand Down
Loading

0 comments on commit 46e6ea3

Please sign in to comment.