diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/util/IQInlineSuggestionSegmentFactory.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/util/IQInlineSuggestionSegmentFactory.java index e0dbaf54..7402c34a 100644 --- a/plugin/src/software/aws/toolkits/eclipse/amazonq/util/IQInlineSuggestionSegmentFactory.java +++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/util/IQInlineSuggestionSegmentFactory.java @@ -53,7 +53,7 @@ public static List getSegmentsFromSuggestion(final QI case CLOSE: if (!unresolvedBrackets.isEmpty()) { var closeBracket = new QInlineSuggestionCloseBracketSegment(startOffset + j, i, - currentLine.substring(0, j), c); + currentLine.substring(0, j), c, qSes.isMacOS()); var top = unresolvedBrackets.pop(); if (top.isAMatch(closeBracket)) { top.pairUp(closeBracket); @@ -70,7 +70,7 @@ public static List getSegmentsFromSuggestion(final QI } distanceTraversed += sb.length() + 1; // plus one because we got rid of a \\R when we split it endOffset = startOffset + sb.length() - 1; - res.add(new QInlineSuggestionNormalSegment(startOffset, endOffset, i, sb.toString())); + res.add(new QInlineSuggestionNormalSegment(startOffset, endOffset, i, sb.toString(), qSes.isMacOS())); } return res; } diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInlineSuggestionCloseBracketSegment.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInlineSuggestionCloseBracketSegment.java index a7ebb9d0..8055f2cd 100644 --- a/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInlineSuggestionCloseBracketSegment.java +++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInlineSuggestionCloseBracketSegment.java @@ -7,6 +7,8 @@ import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.TextLayout; +import org.eclipse.swt.widgets.Display; public final class QInlineSuggestionCloseBracketSegment implements IQInlineSuggestionSegment, IQInlineBracket { private QInlineSuggestionOpenBracketSegment openBracket; @@ -15,16 +17,28 @@ public final class QInlineSuggestionCloseBracketSegment implements IQInlineSugge private int lineInSuggestion; private String text; private Font adjustedTypedFont; + private TextLayout layout; + private TextLayout measureLayout; + private boolean isMacOS; public QInlineSuggestionCloseBracketSegment(final int caretOffset, final int lineInSuggestion, final String text, - final char symbol) { + final char symbol, final boolean isMacOS) { this.caretOffset = caretOffset; this.symbol = symbol; this.lineInSuggestion = lineInSuggestion; this.text = text; + this.layout = isMacOS ? null : new TextLayout(Display.getCurrent()); + this.isMacOS = isMacOS; var qInvocationSessionInstance = QInvocationSession.getInstance(); adjustedTypedFont = qInvocationSessionInstance.getBoldInlineFont(); + if (!isMacOS) { + int[] tabStops = qInvocationSessionInstance.getViewer().getTextWidget().getTabStops(); + measureLayout = new TextLayout(Display.getCurrent()); + measureLayout.setText(text); + measureLayout.setFont(qInvocationSessionInstance.getInlineTextFont()); + measureLayout.setTabs(tabStops); + } } @Override @@ -57,25 +71,40 @@ public void render(final GC gc, final int currentCaretOffset) { int invocationLine = widget.getLineAtOffset(invocationOffset); int lineHt = widget.getLineHeight(); int fontHt = gc.getFontMetrics().getHeight(); - // educated guess: - int endPadding = gc.getAdvanceWidth(symbol) / 4; y = (invocationLine + lineInSuggestion + 1) * lineHt - fontHt; - x = gc.textExtent(text).x; + x = isMacOS ? gc.textExtent(text).x : (int) measureLayout.getBounds().width; if (lineInSuggestion == 0) { x += widget.getLocationAtOffset(invocationOffset).x; } - + int scrollOffsetY = widget.getTopPixel(); + y -= scrollOffsetY; + String textToRender = String.valueOf(symbol); if (currentCaretOffset > openBracket.getRelevantOffset()) { Color typedColor = widget.getForeground(); - gc.setForeground(typedColor); - gc.setFont(adjustedTypedFont); + if (isMacOS) { + gc.setForeground(typedColor); + gc.setFont(adjustedTypedFont); + gc.drawText(textToRender, x, y, false); + } else { + layout.setFont(adjustedTypedFont); + layout.setText(textToRender); + layout.setTabs(widget.getTabStops()); + gc.setAlpha(255); + layout.draw(gc, x, y); + } } else { - gc.setForeground(Q_INLINE_HINT_TEXT_COLOR); - gc.setFont(qInvocationSessionInstance.getInlineTextFont()); + if (isMacOS) { + gc.setForeground(Q_INLINE_HINT_TEXT_COLOR); + gc.setFont(qInvocationSessionInstance.getInlineTextFont()); + gc.drawText(textToRender, x, y, true); + } else { + layout.setFont(qInvocationSessionInstance.getInlineTextFont()); + layout.setText(textToRender); + layout.setTabs(widget.getTabStops()); + gc.setAlpha(127); + layout.draw(gc, x, y); + } } - int scrollOffsetY = widget.getTopPixel(); - y -= scrollOffsetY; - gc.drawText(String.valueOf(symbol), x, y, true); } @Override @@ -112,5 +141,11 @@ public QInlineSuggestionOpenBracketSegment getOpenBracket() { @Override public void cleanUp() { + if (layout != null) { + layout.dispose(); + } + if (measureLayout != null) { + measureLayout.dispose(); + } } } diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInlineSuggestionNormalSegment.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInlineSuggestionNormalSegment.java index de7481dc..b5472fe0 100644 --- a/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInlineSuggestionNormalSegment.java +++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInlineSuggestionNormalSegment.java @@ -8,6 +8,8 @@ import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.GlyphMetrics; +import org.eclipse.swt.graphics.TextLayout; +import org.eclipse.swt.widgets.Display; import software.aws.toolkits.eclipse.amazonq.plugin.Activator; @@ -17,13 +19,17 @@ public final class QInlineSuggestionNormalSegment implements IQInlineSuggestionS private int lineInSuggestion; private String text; private StyleRange styleRange = new StyleRange(); + private TextLayout layout; + private boolean isMacOS; public QInlineSuggestionNormalSegment(final int startCaretPosition, final int endCaretPosition, - final int lineInSuggestion, final String text) { + final int lineInSuggestion, final String text, final boolean isMacOS) { + this.isMacOS = isMacOS; this.text = text; this.startCaretOffset = startCaretPosition; this.endCaretOffset = endCaretPosition; this.lineInSuggestion = lineInSuggestion; + this.layout = isMacOS ? null : new TextLayout(Display.getCurrent()); } @Override @@ -73,13 +79,24 @@ public void render(final GC gc, final int currentCaretOffset) { int scrollOffsetY = widget.getTopPixel(); y -= scrollOffsetY; - gc.setForeground(Q_INLINE_HINT_TEXT_COLOR); - gc.setFont(qInvocationSessionInstance.getInlineTextFont()); - gc.drawText(textToRender, x, y, true); + if (!isMacOS) { + layout.setText(textToRender); + layout.setFont(qInvocationSessionInstance.getInlineTextFont()); + layout.setTabs(widget.getTabStops()); + gc.setAlpha(127); + layout.draw(gc, x, y); + } else { + gc.setForeground(Q_INLINE_HINT_TEXT_COLOR); + gc.setFont(qInvocationSessionInstance.getInlineTextFont()); + gc.drawText(textToRender, x, y, true); + } } @Override public void cleanUp() { + if (layout != null) { + layout.dispose(); + } QInvocationSession session = QInvocationSession.getInstance(); if (!session.isActive()) { return; diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInvocationSession.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInvocationSession.java index aa2563d8..5b759d69 100644 --- a/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInvocationSession.java +++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInvocationSession.java @@ -36,6 +36,7 @@ public final class QInvocationSession extends QResource { private volatile QInvocationSessionState state = QInvocationSessionState.INACTIVE; private CaretMovementReason caretMovementReason = CaretMovementReason.UNEXAMINED; private boolean suggestionAccepted = false; + private boolean isMacOS; private QSuggestionsContext suggestionsContext = null; @@ -60,6 +61,7 @@ public final class QInvocationSession extends QResource { // Private constructor to prevent instantiation private QInvocationSession() { // Initialization code here + isMacOS = System.getProperty("os.name").toLowerCase().contains("mac"); } // Method to get the single instance @@ -489,6 +491,10 @@ public Font getBoldInlineFont() { return inlineTextFontBold; } + public boolean isMacOS() { + return isMacOS; + } + // Additional methods for the session can be added here @Override public void dispose() {