Skip to content

Commit 688f837

Browse files
tobias-melchermickaelistria
authored andcommitted
support rendering of code minings at the very end of the document
if the last line at the end of the document is empty Fixes: #2157
1 parent 5f52c09 commit 688f837

File tree

3 files changed

+156
-13
lines changed

3 files changed

+156
-13
lines changed

bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.eclipse.jface.internal.text.codemining.CodeMiningLineHeaderAnnotation;
2929

3030
import org.eclipse.jface.text.ITextViewer;
31+
import org.eclipse.jface.text.Position;
3132
import org.eclipse.jface.text.source.Annotation;
3233
import org.eclipse.jface.text.source.AnnotationPainter.IDrawingStrategy;
3334

@@ -99,7 +100,7 @@ private Font getAnnotationFont(StyledText textWidget) {
99100
if (annotationFont == null) {
100101
annotationFont = createInlineAnnotationFont(textWidget);
101102
textWidget.setData(INLINE_ANNOTATION_FONT, annotationFont);
102-
textWidget.addDisposeListener(e -> ((Font)textWidget.getData(INLINE_ANNOTATION_FONT)).dispose());
103+
textWidget.addDisposeListener(e -> ((Font) textWidget.getData(INLINE_ANNOTATION_FONT)).dispose());
103104
}
104105
return annotationFont;
105106
}
@@ -154,7 +155,8 @@ public static void draw(AbstractInlinedAnnotation annotation, GC gc, StyledText
154155
private static void draw(LineHeaderAnnotation annotation, GC gc, StyledText textWidget, int offset, int length,
155156
Color color) {
156157
int line= textWidget.getLineAtOffset(offset);
157-
if (isDeleted(annotation)) {
158+
int charCount= textWidget.getCharCount();
159+
if (isDeleted(annotation, charCount)) {
158160
// When annotation is deleted, update metrics to null to remove extra spaces of the line header annotation.
159161
if (textWidget.getLineVerticalIndent(line) > 0)
160162
textWidget.setLineVerticalIndent(line, 0);
@@ -180,9 +182,16 @@ private static void draw(LineHeaderAnnotation annotation, GC gc, StyledText text
180182
textWidget.setLineVerticalIndent(line, 0);
181183
}
182184
// Compute the location of the annotation
183-
Rectangle bounds= textWidget.getTextBounds(offset, offset);
184-
int x= bounds.x;
185-
int y= bounds.y;
185+
int x, y;
186+
if (offset < charCount) {
187+
Rectangle bounds= textWidget.getTextBounds(offset, offset);
188+
x= bounds.x;
189+
y= bounds.y;
190+
} else {
191+
Point locAtOff= textWidget.getLocationAtOffset(offset);
192+
x= locAtOff.x;
193+
y= locAtOff.y - height;
194+
}
186195
// Draw the line header annotation
187196
gc.setBackground(textWidget.getBackground());
188197
annotation.setLocation(x, y);
@@ -193,7 +202,16 @@ private static void draw(LineHeaderAnnotation annotation, GC gc, StyledText text
193202
Rectangle client= textWidget.getClientArea();
194203
textWidget.redraw(0, bounds.y, client.width, bounds.height, false);
195204
} else {
196-
textWidget.redrawRange(offset, length, true);
205+
if (offset >= charCount) {
206+
if (charCount > 0) {
207+
textWidget.redrawRange(charCount - 1, 1, true);
208+
} else {
209+
Rectangle client= textWidget.getClientArea();
210+
textWidget.redraw(0, 0, client.width, client.height, false);
211+
}
212+
} else {
213+
textWidget.redrawRange(offset, length, true);
214+
}
197215
}
198216
}
199217

@@ -212,7 +230,11 @@ private static void draw(LineContentAnnotation annotation, GC gc, StyledText tex
212230
Color color) {
213231
if (annotation instanceof CodeMiningLineContentAnnotation a) {
214232
if (a.isAfterPosition()) {
215-
drawAsLeftOf1stCharacter(annotation, gc, textWidget, widgetOffset, length, color);
233+
if (widgetOffset < textWidget.getCharCount()) {
234+
drawAsLeftOf1stCharacter(annotation, gc, textWidget, widgetOffset, length, color);
235+
} else {
236+
drawAtEndOfDocumentInFirstColumn(annotation, gc, textWidget, widgetOffset, length, color);
237+
}
216238
return;
217239
}
218240
}
@@ -226,7 +248,7 @@ private static void draw(LineContentAnnotation annotation, GC gc, StyledText tex
226248
}
227249

228250
private static void drawAfterLine(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) {
229-
if (isDeleted(annotation)) {
251+
if (isDeleted(annotation, textWidget.getCharCount())) {
230252
return;
231253
}
232254
if (gc != null) {
@@ -247,14 +269,43 @@ private static void drawAfterLine(LineContentAnnotation annotation, GC gc, Style
247269
}
248270
}
249271

272+
private static void drawAtEndOfDocumentInFirstColumn(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) {
273+
if (isDeleted(annotation, textWidget.getCharCount())) {
274+
return;
275+
}
276+
if (gc != null) {
277+
Point locAtOff= textWidget.getLocationAtOffset(widgetOffset);
278+
int x= locAtOff.x;
279+
int y= locAtOff.y;
280+
annotation.setLocation(x, y);
281+
annotation.draw(gc, textWidget, widgetOffset, length, color, x, y);
282+
int width= annotation.getWidth();
283+
if (width != 0) {
284+
if (!gc.getClipping().contains(x, y)) {
285+
Rectangle client= textWidget.getClientArea();
286+
int height= textWidget.getLineHeight();
287+
textWidget.redraw(x, y, client.width, height, false);
288+
}
289+
}
290+
} else {
291+
int charCount= textWidget.getCharCount();
292+
if (charCount > 0) {
293+
textWidget.redrawRange(charCount - 1, 1, true);
294+
} else {
295+
Rectangle client= textWidget.getClientArea();
296+
textWidget.redraw(0, 0, client.width, client.height, false);
297+
}
298+
}
299+
}
300+
250301
protected static void drawAsLeftOf1stCharacter(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) {
251302
StyleRange style= null;
252303
try {
253304
style= textWidget.getStyleRangeAtOffset(widgetOffset);
254305
} catch (Exception e) {
255306
return;
256307
}
257-
if (isDeleted(annotation)) {
308+
if (isDeleted(annotation, textWidget.getCharCount())) {
258309
// When annotation is deleted, update metrics to null to remove extra spaces of the line content annotation.
259310
if (style != null && style.metrics != null) {
260311
style.metrics= null;
@@ -369,7 +420,7 @@ protected static void drawAsRightOfPreviousCharacter(LineContentAnnotation annot
369420
} catch (Exception e) {
370421
return;
371422
}
372-
if (isDeleted(annotation)) {
423+
if (isDeleted(annotation, textWidget.getCharCount())) {
373424
// When annotation is deleted, update metrics to null to remove extra spaces of the line content annotation.
374425
if (style != null && style.metrics != null) {
375426
style.metrics= null;
@@ -449,7 +500,17 @@ protected static void drawAsRightOfPreviousCharacter(LineContentAnnotation annot
449500
* @param annotation the inlined annotation to check
450501
* @return <code>true</code> if inlined annotation is deleted and <code>false</code> otherwise.
451502
*/
452-
private static boolean isDeleted(AbstractInlinedAnnotation annotation) {
453-
return annotation.isMarkedDeleted() || annotation.getPosition().isDeleted() || annotation.getPosition().getLength() == 0;
503+
private static boolean isDeleted(AbstractInlinedAnnotation annotation,int maxOffset) {
504+
if (annotation.isMarkedDeleted()) {
505+
return true;
506+
}
507+
Position pos= annotation.getPosition();
508+
if (pos.isDeleted()) {
509+
return true;
510+
}
511+
if (pos.getLength() == 0 && pos.getOffset() < maxOffset) {
512+
return true;
513+
}
514+
return false;
454515
}
455516
}

tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningTest.java

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.eclipse.swt.graphics.GC;
3636
import org.eclipse.swt.graphics.Image;
3737
import org.eclipse.swt.graphics.ImageData;
38+
import org.eclipse.swt.graphics.Point;
3839
import org.eclipse.swt.graphics.Rectangle;
3940
import org.eclipse.swt.layout.FillLayout;
4041
import org.eclipse.swt.widgets.Display;
@@ -250,6 +251,71 @@ protected boolean condition() {
250251
}.waitForCondition(fViewer.getTextWidget().getDisplay(), 1000));
251252
}
252253

254+
@Test
255+
public void testLineHeaderCodeMiningAtEndOfDocumentWithEmptyLine() throws Exception {
256+
String source= "first\nsecond\n";
257+
fViewer.getDocument().set(source);
258+
fViewer.setCodeMiningProviders(new ICodeMiningProvider[] { new ICodeMiningProvider() {
259+
@Override
260+
public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) {
261+
List<ICodeMining> minings= new ArrayList<>();
262+
try {
263+
minings.add(new LineHeaderCodeMining(new Position(source.length(), 0), this, null) {
264+
@Override
265+
public String getLabel() {
266+
return "multiline first line\nmultiline second line\nmultiline third line\nmultiline fourth line";
267+
}
268+
});
269+
} catch (BadLocationException e) {
270+
e.printStackTrace();
271+
}
272+
return CompletableFuture.completedFuture(minings);
273+
}
274+
275+
@Override
276+
public void dispose() {
277+
}
278+
} });
279+
Assert.assertTrue("Code mining is not visible at end of document", new DisplayHelper() {
280+
@Override
281+
protected boolean condition() {
282+
try {
283+
return hasCodeMiningPrintedAfterTextOnLine(fViewer, 2);
284+
} catch (BadLocationException e) {
285+
e.printStackTrace();
286+
return false;
287+
}
288+
}
289+
}.waitForCondition(fViewer.getTextWidget().getDisplay(), 10_000));
290+
}
291+
292+
@Test
293+
public void testCodeMiningAtEndOfDocumentWithEmptyLine() throws Exception {
294+
String source= "first\nsecond\n";
295+
fViewer.getDocument().set(source);
296+
fViewer.setCodeMiningProviders(new ICodeMiningProvider[] { new ICodeMiningProvider() {
297+
@Override
298+
public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) {
299+
return CompletableFuture.completedFuture(Collections.singletonList(new StaticContentLineCodeMining(new Position(source.length(), 0), true, "mining", this)));
300+
}
301+
302+
@Override
303+
public void dispose() {
304+
}
305+
} });
306+
Assert.assertTrue("Code mining is not visible at end of document", new DisplayHelper() {
307+
@Override
308+
protected boolean condition() {
309+
try {
310+
return hasCodeMiningPrintedAfterTextOnLine(fViewer, 2);
311+
} catch (BadLocationException e) {
312+
e.printStackTrace();
313+
return false;
314+
}
315+
}
316+
}.waitForCondition(fViewer.getTextWidget().getDisplay(), 10_000));
317+
}
318+
253319
@Test
254320
public void testCodeMiningEndOfLine() {
255321
fViewer.getDocument().set("a\n");
@@ -389,7 +455,18 @@ private static boolean hasCodeMiningPrintedAfterTextOnLine(ITextViewer viewer, i
389455
if (lineLength < 0) {
390456
lineLength= 0;
391457
}
392-
Rectangle secondLineBounds= widget.getTextBounds(document.getLineOffset(line), document.getLineOffset(line) + lineLength);
458+
Rectangle secondLineBounds= null;
459+
int lineOffset= document.getLineOffset(line);
460+
if (lineOffset >= document.getLength()) {
461+
int off= document.getLength() - 1;
462+
secondLineBounds= widget.getTextBounds(off, off + lineLength);
463+
Point l= widget.getLocationAtOffset(lineOffset);
464+
int lineVerticalIndent= widget.getLineVerticalIndent(line);
465+
secondLineBounds.x= l.x;
466+
secondLineBounds.y= l.y - lineVerticalIndent;
467+
} else {
468+
secondLineBounds= widget.getTextBounds(lineOffset, lineOffset + lineLength);
469+
}
393470
Image image = new Image(widget.getDisplay(), widget.getSize().x, widget.getSize().y);
394471
GC gc = new GC(widget);
395472
gc.copyArea(image, 0, 0);

tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/StaticContentLineCodeMining.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ public StaticContentLineCodeMining(Position position, String message, ICodeMinin
2424
setLabel(message);
2525
}
2626

27+
public StaticContentLineCodeMining(Position position, boolean afterPosition, String message, ICodeMiningProvider provider) {
28+
super(position, afterPosition, provider);
29+
setLabel(message);
30+
}
31+
2732
public StaticContentLineCodeMining(int i, char c, ICodeMiningProvider repeatLettersCodeMiningProvider) {
2833
super(new Position(i, 1), repeatLettersCodeMiningProvider);
2934
setLabel(Character.toString(c));

0 commit comments

Comments
 (0)