From 28f94ae3f387cf72f3562c86877132fe844856e2 Mon Sep 17 00:00:00 2001 From: Tobias Melcher Date: Thu, 5 Sep 2024 17:52:43 +0200 Subject: [PATCH] code minings drawn more consistently always via drawAsLeftOf1stCharacter this improves the selection behavior for the scenario where the selection end offset contains a LineContentAnnotation. Selection is no longer extended with the code mining. --- .../text/WhitespaceCharacterPainter.java | 45 ++++-- .../InlinedAnnotationDrawingStrategy.java | 151 +++--------------- .../source/inlined/LineContentAnnotation.java | 19 --- .../examples/codemining/CodeMiningDemo.java | 12 +- .../tests/TestWhitespaceCharacterPainter.java | 36 ++++- .../text/tests/codemining/CodeMiningTest.java | 6 +- .../source/inlined/AnnotationOnTabTest.java | 5 +- 7 files changed, 106 insertions(+), 168 deletions(-) diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/WhitespaceCharacterPainter.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/WhitespaceCharacterPainter.java index 24a6526f064..43c6e53e7c5 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/WhitespaceCharacterPainter.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/WhitespaceCharacterPainter.java @@ -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; @@ -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') { @@ -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; @@ -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()); } @@ -492,7 +500,7 @@ 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(); @@ -500,32 +508,49 @@ private void draw(GC gc, int offset, String s, Color fg) { 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 offsets= null; + private Map 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); } } } diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java index 09464aef653..4fd784741ab 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java @@ -202,35 +202,7 @@ 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.isEmptyLine(widgetOffset, textWidget)) { - drawAfterLine(annotation, gc, textWidget, widgetOffset, length, color); - } else if (LineContentAnnotation.drawRightToPreviousChar(widgetOffset, textWidget)) { - drawAsRightOfPreviousCharacter(annotation, gc, textWidget, widgetOffset, length, color); - } else { - drawAsLeftOf1stCharacter(annotation, gc, textWidget, widgetOffset, length, color); - } - } - - private static void drawAfterLine(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) { - if (isDeleted(annotation)) { - return; - } - if (gc != null) { - if (textWidget.getCharCount() == 0) { - annotation.draw(gc, textWidget, widgetOffset, length, color, 0, 0); - } else { - int line= textWidget.getLineAtOffset(widgetOffset); - int lineEndOffset= (line == textWidget.getLineCount() - 1) ? // - textWidget.getCharCount() - 1 : // - textWidget.getOffsetAtLine(line + 1) - 1; - Rectangle bounds= textWidget.getTextBounds(lineEndOffset, lineEndOffset); - int lineEndX= bounds.x + bounds.width + gc.stringExtent(" ").x; //$NON-NLS-1$ - annotation.setLocation(lineEndX, textWidget.getLinePixel(line) + textWidget.getLineVerticalIndent(line)); - annotation.draw(gc, textWidget, widgetOffset, length, color, lineEndX, textWidget.getLinePixel(line) + textWidget.getLineVerticalIndent(line)); - } - } else { - textWidget.redrawRange(widgetOffset, length, true); - } + drawAsLeftOf1stCharacter(annotation, gc, textWidget, widgetOffset, length, color); } protected static void drawAsLeftOf1stCharacter(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) { @@ -254,9 +226,16 @@ 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 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; + 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(); @@ -265,107 +244,20 @@ protected static void drawAsLeftOf1stCharacter(LineContentAnnotation annotation, annotation.draw(gc, textWidget, widgetOffset, length, color, x, y); int width= annotation.getWidth(); if (width != 0) { - if (isEndOfLine) { - if (!gc.getClipping().contains(x, y)) { - // The draw of mining is not inside the gc clipping, redraw the area which contains the mining to draw. - Rectangle client= textWidget.getClientArea(); - textWidget.redraw(x, y, client.width, bounds.height, false); - } - } else { - // Get size of the character where GlyphMetrics width is added - Point charBounds= gc.stringExtent(hostCharacter); - int charWidth= charBounds.x; - - // 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); - // END TO REMOVE - - // Annotation takes place, add GlyphMetrics width to the style - StyleRange newStyle= annotation.updateStyle(style, gc.getFontMetrics(), textWidget.getData() instanceof ITextViewer viewer ? viewer : annotation.getViewer()); - if (newStyle != null) { - textWidget.setStyleRange(newStyle); - return; - } - - // 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 - // The inline annotation replaces one character by taking a place width - // GlyphMetrics - // Here we need to redraw this first character because GlyphMetrics clip this - // character. - int redrawnHostCharX= x + bounds.width - charWidth; - int redrawnHostCharY= y; - gc.setForeground(textWidget.getForeground()); - gc.setBackground(textWidget.getBackground()); - gc.setFont(textWidget.getFont()); - if (style != null) { - if (style.background != null) { - gc.setBackground(style.background); - gc.fillRectangle(redrawnHostCharX, redrawnHostCharY, charWidth + 1, bounds.height); - } - if (style.foreground != null) { - gc.setForeground(style.foreground); - } - if (style.font != null) { - gc.setFont(style.font); - } - } - if (textWidget.getSelection().x <= widgetOffset && textWidget.getSelection().y > widgetOffset) { - gc.setForeground(textWidget.getSelectionForeground()); - gc.setBackground(textWidget.getSelectionBackground()); - } - gc.drawString(hostCharacter, redrawnHostCharX, redrawnHostCharY, true); + // 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$ } - // END TO REMOVE - } else if (style != null && style.metrics != null && style.metrics.width != 0) { - // line content annotation had an , reset it - style.metrics= null; - textWidget.setStyleRange(style); - } - } else { - textWidget.redrawRange(widgetOffset, length, true); - } - } - - protected static void drawAsRightOfPreviousCharacter(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) { - StyleRange style= null; - try { - style= textWidget.getStyleRangeAtOffset(widgetOffset - 1); - } catch (Exception e) { - return; - } - if (isDeleted(annotation)) { - // When annotation is deleted, update metrics to null to remove extra spaces of the line content annotation. - if (style != null && style.metrics != null) { - style.metrics= null; - textWidget.setStyleRange(style); - } - return; - } - if (gc != null) { - char hostCharacter= textWidget.getText(widgetOffset - 1, widgetOffset - 1).charAt(0); - // use gc.stringExtent instead of gc.geCharWidth because of bug 548866 - int redrawnCharacterWidth= hostCharacter != '\t' ? gc.stringExtent(Character.toString(hostCharacter)).x : textWidget.getTabs() * gc.stringExtent(" ").x; //$NON-NLS-1$ - Rectangle charBounds= textWidget.getTextBounds(widgetOffset - 1, widgetOffset - 1); - Rectangle annotationBounds= new Rectangle(charBounds.x + redrawnCharacterWidth, charBounds.y, annotation.getWidth(), charBounds.height); - - // When line text has line header annotation, there is a space on the top, adjust the y by using char height - int verticalDrawingOffset= charBounds.height - textWidget.getLineHeight(); - annotationBounds.y += verticalDrawingOffset; - - // Draw the line content annotation - annotation.setLocation(annotationBounds.x, annotationBounds.y); - annotation.draw(gc, textWidget, widgetOffset, length, color, annotationBounds.x, annotationBounds.y); - int width= annotation.getWidth(); - if (width != 0) { // 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(redrawnCharacterWidth); + annotation.setRedrawnCharacterWidth(charWidth); // END TO REMOVE // Annotation takes place, add GlyphMetrics width to the style - StyleRange newStyle= annotation.updateStyle(style, gc.getFontMetrics(), InlinedAnnotationSupport.getSupport(textWidget).getViewer()); + StyleRange newStyle= annotation.updateStyle(style, gc.getFontMetrics(), textWidget.getData() instanceof ITextViewer viewer ? viewer : annotation.getViewer()); if (newStyle != null) { textWidget.setStyleRange(newStyle); return; @@ -377,13 +269,15 @@ protected static void drawAsRightOfPreviousCharacter(LineContentAnnotation annot // GlyphMetrics // Here we need to redraw this first character because GlyphMetrics clip this // character. + int redrawnHostCharX= x + bounds.width - charWidth; + int redrawnHostCharY= y; gc.setForeground(textWidget.getForeground()); gc.setBackground(textWidget.getBackground()); gc.setFont(textWidget.getFont()); if (style != null) { if (style.background != null) { gc.setBackground(style.background); - gc.fillRectangle(charBounds.x, annotationBounds.y, redrawnCharacterWidth, charBounds.height); + gc.fillRectangle(redrawnHostCharX, redrawnHostCharY, charWidth + 1, bounds.height); } if (style.foreground != null) { gc.setForeground(style.foreground); @@ -392,12 +286,11 @@ protected static void drawAsRightOfPreviousCharacter(LineContentAnnotation annot gc.setFont(style.font); } } - int toRedrawCharOffset= widgetOffset - 1; - if (textWidget.getSelection().x <= toRedrawCharOffset && textWidget.getSelection().y > toRedrawCharOffset) { + if (textWidget.getSelection().x <= widgetOffset && textWidget.getSelection().y > widgetOffset) { gc.setForeground(textWidget.getSelectionForeground()); gc.setBackground(textWidget.getSelectionBackground()); } - gc.drawString(Character.toString(hostCharacter), charBounds.x, charBounds.y + verticalDrawingOffset, true); + gc.drawString(hostCharacter, redrawnHostCharX, redrawnHostCharY, true); // END TO REMOVE } else if (style != null && style.metrics != null && style.metrics.width != 0) { // line content annotation had an , reset it diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java index e6cc355c90f..e35268bd832 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java @@ -122,8 +122,6 @@ StyleRange updateStyle(StyleRange style, FontMetrics fontMetrics, ITextViewer vi if (widgetPosition == null) { return null; } - StyledText textWidget = viewer.getTextWidget(); - boolean usePreviousChar= drawRightToPreviousChar(widgetPosition.getOffset(), textWidget); if (width == 0 || getRedrawnCharacterWidth() == 0) { return null; } @@ -131,9 +129,6 @@ StyleRange updateStyle(StyleRange style, FontMetrics fontMetrics, ITextViewer vi if (style == null) { style= new StyleRange(); style.start= widgetPosition.getOffset(); - if (usePreviousChar) { - style.start--; - } style.length= 1; } GlyphMetrics metrics= style.metrics; @@ -157,18 +152,4 @@ StyleRange updateStyle(StyleRange style, FontMetrics fontMetrics, ITextViewer vi style.metrics= metrics; return style; } - - static boolean drawRightToPreviousChar(int widgetOffset, StyledText textWidget) { - return widgetOffset > 0 && widgetOffset < textWidget.getCharCount() && - textWidget.getLineAtOffset(widgetOffset) == textWidget.getLineAtOffset(widgetOffset - 1); - } - - boolean isEmptyLine(int widgetOffset, StyledText text) { - if (text.getCharCount() <= widgetOffset) { // Assuming widgetOffset >= 0 - return true; - } - int line= text.getLineAtOffset(widgetOffset); - String lineStr= text.getLine(line); - return lineStr.length() == 0; - } } diff --git a/examples/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/codemining/CodeMiningDemo.java b/examples/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/codemining/CodeMiningDemo.java index 1cc8a5cf656..166c742037c 100644 --- a/examples/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/codemining/CodeMiningDemo.java +++ b/examples/org.eclipse.jface.text.examples/src/org/eclipse/jface/text/examples/codemining/CodeMiningDemo.java @@ -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; @@ -42,6 +44,8 @@ */ public class CodeMiningDemo { + private static boolean showWhitespaces = false; + public static void main(String[] args) throws Exception { Display display = new Display(); @@ -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" diff --git a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/TestWhitespaceCharacterPainter.java b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/TestWhitespaceCharacterPainter.java index 5b3298d050d..9a1d57a3e34 100644 --- a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/TestWhitespaceCharacterPainter.java +++ b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/TestWhitespaceCharacterPainter.java @@ -19,6 +19,9 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.util.Arrays; +import java.util.List; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -62,15 +65,30 @@ public void after() { @Test public void glyphMetricsTakenIntoAccount() throws Exception { + verifyDrawStringCalledNTimes("first \nsecond \nthird \n", Arrays.asList(6, 15), 5); + } + + @Test + public void glyphMetricsAtNewTakenIntoAccount() throws Exception { + verifyDrawStringCalledNTimes("first \nsecond", Arrays.asList(7), 2); + } + + @Test + public void glyphMetricsAtCarriageReturnTakenIntoAccount() throws Exception { + verifyDrawStringCalledNTimes("first \r\nsecond", Arrays.asList(7), 2); + } + + private void verifyDrawStringCalledNTimes(String str, List styleRangeOffsets, int times) { SourceViewer sourceViewer= new SourceViewer(shell, null, SWT.V_SCROLL | SWT.BORDER); - sourceViewer.setDocument(new Document("first \nsecond \nthird \n")); + sourceViewer.setDocument(new Document(str)); StyledText textWidget= sourceViewer.getTextWidget(); textWidget.setFont(JFaceResources.getTextFont()); WhitespaceCharacterPainter whitespaceCharPainter= new WhitespaceCharacterPainter(sourceViewer, true, true, true, true, true, true, true, true, true, true, true, 100); sourceViewer.addPainter(whitespaceCharPainter); - textWidget.setStyleRange(createStyleRangeWithMetrics(6)); - textWidget.setStyleRange(createStyleRangeWithMetrics(15)); + for (Integer offset : styleRangeOffsets) { + textWidget.setStyleRange(createStyleRangeWithMetrics(offset)); + } Event e= new Event(); e.widget= textWidget; PaintEvent ev= new PaintEvent(e); @@ -87,6 +105,16 @@ public Point answer(InvocationOnMock invocation) throws Throwable { return result; } }); + when(ev.gc.textExtent(anyString())).thenAnswer(new Answer() { + @Override + public Point answer(InvocationOnMock invocation) throws Throwable { + GC gc= new GC(shell); + gc.setFont(JFaceResources.getTextFont()); + Point result= gc.textExtent(invocation.getArgument(0)); + gc.dispose(); + return result; + } + }); when(ev.gc.getFontMetrics()).thenAnswer(new Answer() { @Override public FontMetrics answer(InvocationOnMock invocation) throws Throwable { @@ -102,7 +130,7 @@ public FontMetrics answer(InvocationOnMock invocation) throws Throwable { ev.width= 100; ev.height= 100; whitespaceCharPainter.paintControl(ev); - verify(ev.gc, times(5)).drawString(anyString(), anyInt(), anyInt(), anyBoolean()); + verify(ev.gc, times(times)).drawString(anyString(), anyInt(), anyInt(), anyBoolean()); } private StyleRange createStyleRangeWithMetrics(int start) { diff --git a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningTest.java b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningTest.java index f9c3eba068e..98a988a262a 100644 --- a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningTest.java +++ b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningTest.java @@ -239,7 +239,7 @@ public void dispose() { protected boolean condition() { try { StyleRange range= widget.getStyleRangeAtOffset(0); - return range == null && hasCodeMiningPrintedAfterTextOnLine(fViewer, 0); + return range != null && hasCodeMiningPrintedAfterTextOnLine(fViewer, 0); } catch (BadLocationException e) { e.printStackTrace(); return false; @@ -266,8 +266,8 @@ public void dispose() { @Override protected boolean condition() { try { - StyleRange range= widget.getStyleRangeAtOffset(0); - return range != null && range.metrics != null && hasCodeMiningPrintedAfterTextOnLine(fViewer, 0) == false; + StyleRange range= widget.getStyleRangeAtOffset(1); + return range != null && range.metrics != null && hasCodeMiningPrintedAfterTextOnLine(fViewer, 0); } catch (BadLocationException e) { e.printStackTrace(); return false; diff --git a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/source/inlined/AnnotationOnTabTest.java b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/source/inlined/AnnotationOnTabTest.java index 4cf6795c238..279a6fb8ccd 100644 --- a/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/source/inlined/AnnotationOnTabTest.java +++ b/tests/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/source/inlined/AnnotationOnTabTest.java @@ -74,7 +74,7 @@ public void testTextBoundsMatchPaintedArea() { // add annotations int annotationIndex = sourceViewer.getDocument().get().indexOf("annotated"); LineContentAnnotation annotation= new LineContentAnnotation(new Position(annotationIndex, 1), sourceViewer); - annotation.setText("a"); // single char, so overall annoation is 3 chars, less than default 4 chars + annotation.setText("a"); // single char, so overall annotation is 3 chars, less than default 4 chars support.updateAnnotations(Collections.singleton(annotation)); fParent.open(); Assert.assertTrue(new DisplayHelper() { @@ -87,6 +87,7 @@ protected boolean condition() { int referenceIndex = textWidget.getText().indexOf("reference"); Rectangle referenceBounds = textWidget.getTextBounds(referenceIndex, referenceIndex); Rectangle annotatedCharactedBounds = textWidget.getTextBounds(annotationIndex, annotationIndex); - Assert.assertTrue("Annotation didn't shift target character to the right, it most likely replaced the tab instead of expanding it", referenceBounds.x < annotatedCharactedBounds.x); + Assert.assertTrue("Annotation didn't shift target character to the right, it most likely replaced the tab instead of expanding it", + referenceBounds.x + referenceBounds.width < annotatedCharactedBounds.x + annotatedCharactedBounds.width); } }