Skip to content

Commit 31e2f72

Browse files
authored
Merge branch 'main' into breedloj/telemetryTypes
2 parents 8dc6cd1 + fb4ba6c commit 31e2f72

12 files changed

+663
-218
lines changed

plugin/src/software/aws/toolkits/eclipse/amazonq/configuration/PluginStore.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,8 @@ public static String get(final String key) {
2727
return PREFERENCES.get(key, null);
2828
}
2929

30+
public static void remove(final String key) {
31+
PREFERENCES.remove(key);
32+
}
33+
3034
}

plugin/src/software/aws/toolkits/eclipse/amazonq/handlers/QAcceptSuggestionsHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public final boolean isEnabled() {
2323
public final Object execute(final ExecutionEvent event) throws ExecutionException {
2424
var suggestion = QInvocationSession.getInstance().getCurrentSuggestion();
2525
var widget = QInvocationSession.getInstance().getViewer().getTextWidget();
26+
QInvocationSession.getInstance().transitionToDecisionMade();
2627
Display display = widget.getDisplay();
2728
display.syncExec(() -> this.insertSuggestion(suggestion.getInsertText()));
2829
return null;
@@ -36,7 +37,6 @@ private void insertSuggestion(final String suggestion) {
3637
var insertOffset = widget.getCaretOffset();
3738
doc.replace(insertOffset, 0, suggestion);
3839
widget.setCaretOffset(insertOffset + suggestion.length());
39-
QInvocationSession.getInstance().transitionToDecisionMade();
4040
QInvocationSession.getInstance().getViewer().getTextWidget().redraw();
4141
QInvocationSession.getInstance().executeCallbackForCodeReference();
4242
QInvocationSession.getInstance().end();

plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInlineCaretListener.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88

99
public final class QInlineCaretListener implements CaretListener {
1010
private StyledText widget = null;
11+
private int previousLine = -1;
1112

1213
public QInlineCaretListener(final StyledText widget) {
1314
this.widget = widget;
15+
this.previousLine = widget.getLineAtOffset(widget.getCaretOffset());
1416
}
1517

1618
@Override
@@ -21,17 +23,16 @@ public void caretMoved(final CaretEvent event) {
2123
// We want to ignore caret movements induced by text editing
2224
if (caretMovementReason == CaretMovementReason.TEXT_INPUT) {
2325
qInvocationSessionInstance.setCaretMovementReason(CaretMovementReason.UNEXAMINED);
26+
previousLine = widget.getLineAtOffset(widget.getCaretOffset());
2427
return;
2528
}
2629

27-
// There are instances where the caret movement was induced by sources other than user input
28-
// Under these instances, it is observed that the caret would revert back to a position that was last
29-
// placed by the user in the same rendering cycle.
30-
// We want to preserve the preview state and prevent it from terminating by these non-user instructed movements
31-
if (event.caretOffset != widget.getCaretOffset() && qInvocationSessionInstance.isPreviewingSuggestions()) {
32-
qInvocationSessionInstance.transitionToDecisionMade();
30+
if (qInvocationSessionInstance.isPreviewingSuggestions()) {
31+
qInvocationSessionInstance.transitionToDecisionMade(previousLine + 1);
3332
qInvocationSessionInstance.end();
33+
return;
3434
}
35+
36+
previousLine = widget.getCaretOffset();
3537
}
3638
}
37-
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
3+
package software.aws.toolkits.eclipse.amazonq.util;
4+
5+
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
6+
import org.eclipse.core.runtime.preferences.InstanceScope;
7+
import org.eclipse.swt.SWT;
8+
import org.eclipse.swt.custom.StyledText;
9+
import org.eclipse.swt.custom.VerifyKeyListener;
10+
import org.eclipse.swt.events.VerifyEvent;
11+
import org.eclipse.swt.events.VerifyListener;
12+
13+
public final class QInlineInputListener implements VerifyListener, VerifyKeyListener {
14+
private StyledText widget = null;
15+
private int distanceTraversed = 0;
16+
private boolean isAutoClosingEnabled = true;
17+
private LastKeyStrokeType lastKeyStrokeType = LastKeyStrokeType.NORMAL_INPUT;
18+
19+
private enum LastKeyStrokeType {
20+
NORMAL_INPUT, BACKSPACE, NORMAL_BRACKET, CURLY_BRACES, OPEN_CURLY, OPEN_CURLY_FOLLOWED_BY_NEW_LINE,
21+
}
22+
23+
public QInlineInputListener(final StyledText widget) {
24+
IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode("org.eclipse.jdt.ui");
25+
// This needs to be defaulted to true. This key is only present in the
26+
// preference store if it is set to false.
27+
// Therefore if you can't find it, it has been set to true.
28+
this.isAutoClosingEnabled = preferences.getBoolean("closeBrackets", true);
29+
this.widget = widget;
30+
}
31+
32+
@Override
33+
public void verifyKey(final VerifyEvent event) {
34+
var qInvocationSessionInstance = QInvocationSession.getInstance();
35+
if (qInvocationSessionInstance == null || !qInvocationSessionInstance.isPreviewingSuggestions()) {
36+
return;
37+
}
38+
39+
// We need to provide the reason for the caret movement. This way we can perform
40+
// subsequent actions accordingly:
41+
// - If the caret has been moved due to traversals (i.e. arrow keys or mouse
42+
// click) we would want to end the invocation session since that signifies the
43+
// user no longer has the intent for text input at its original location.
44+
if (event.keyCode == SWT.ARROW_UP || event.keyCode == SWT.ARROW_DOWN || event.keyCode == SWT.ARROW_LEFT
45+
|| event.keyCode == SWT.ARROW_RIGHT) {
46+
qInvocationSessionInstance.setCaretMovementReason(CaretMovementReason.MOVEMENT_KEY);
47+
return;
48+
}
49+
50+
qInvocationSessionInstance.setCaretMovementReason(CaretMovementReason.TEXT_INPUT);
51+
52+
// Here we examine all other relevant keystrokes that may be relevant to the
53+
// preview's lifetime:
54+
// - CR (new line)
55+
// - BS (backspace)
56+
String currentSuggestion = qInvocationSessionInstance.getCurrentSuggestion().getInsertText().trim();
57+
switch (event.keyCode) {
58+
case SWT.CR:
59+
if (lastKeyStrokeType == LastKeyStrokeType.OPEN_CURLY && isAutoClosingEnabled) {
60+
lastKeyStrokeType = LastKeyStrokeType.OPEN_CURLY_FOLLOWED_BY_NEW_LINE;
61+
// we need to unset the vertical indent prior to new line otherwise the line inserted by
62+
// eclipse with the closing curly braces would inherit the extra vertical indent.
63+
int line = widget.getLineAtOffset(widget.getCaretOffset());
64+
qInvocationSessionInstance.unsetVerticalIndent(line + 1);
65+
} else {
66+
lastKeyStrokeType = LastKeyStrokeType.NORMAL_INPUT;
67+
}
68+
return;
69+
case SWT.BS:
70+
if (--distanceTraversed < 0) {
71+
qInvocationSessionInstance.transitionToDecisionMade();
72+
qInvocationSessionInstance.end();
73+
return;
74+
}
75+
lastKeyStrokeType = LastKeyStrokeType.BACKSPACE;
76+
return;
77+
case SWT.ESC:
78+
qInvocationSessionInstance.transitionToDecisionMade();
79+
qInvocationSessionInstance.end();
80+
return;
81+
default:
82+
}
83+
84+
// If auto closing of brackets are not enabled we can just treat them as normal
85+
// inputs
86+
// Another scenario
87+
if (!isAutoClosingEnabled) {
88+
return;
89+
}
90+
91+
// If auto cloising of brackets are enabled, SWT will treat the open bracket
92+
// differently.
93+
// Input of the brackets will not trigger a call to verifyText.
94+
// Thus we have to do the typeahead verification here.
95+
// Note that '{' is excluded because
96+
switch (event.character) {
97+
case '<':
98+
if (currentSuggestion.charAt(distanceTraversed++) != '<') {
99+
qInvocationSessionInstance.transitionToDecisionMade();
100+
qInvocationSessionInstance.end();
101+
return;
102+
}
103+
lastKeyStrokeType = LastKeyStrokeType.NORMAL_BRACKET;
104+
return;
105+
case '>':
106+
if (currentSuggestion.charAt(distanceTraversed++) != '>') {
107+
qInvocationSessionInstance.transitionToDecisionMade();
108+
qInvocationSessionInstance.end();
109+
return;
110+
}
111+
lastKeyStrokeType = LastKeyStrokeType.NORMAL_BRACKET;
112+
return;
113+
case '(':
114+
if (currentSuggestion.charAt(distanceTraversed++) != '(') {
115+
qInvocationSessionInstance.transitionToDecisionMade();
116+
qInvocationSessionInstance.end();
117+
return;
118+
}
119+
lastKeyStrokeType = LastKeyStrokeType.NORMAL_BRACKET;
120+
return;
121+
case ')':
122+
if (currentSuggestion.charAt(distanceTraversed++) != ')') {
123+
qInvocationSessionInstance.transitionToDecisionMade();
124+
qInvocationSessionInstance.end();
125+
return;
126+
}
127+
lastKeyStrokeType = LastKeyStrokeType.NORMAL_BRACKET;
128+
return;
129+
case '[':
130+
if (currentSuggestion.charAt(distanceTraversed++) != '[') {
131+
qInvocationSessionInstance.transitionToDecisionMade();
132+
qInvocationSessionInstance.end();
133+
return;
134+
}
135+
lastKeyStrokeType = LastKeyStrokeType.NORMAL_BRACKET;
136+
return;
137+
case ']':
138+
if (currentSuggestion.charAt(distanceTraversed++) != ']') {
139+
qInvocationSessionInstance.transitionToDecisionMade();
140+
qInvocationSessionInstance.end();
141+
return;
142+
}
143+
lastKeyStrokeType = LastKeyStrokeType.NORMAL_BRACKET;
144+
return;
145+
case '{':
146+
if (currentSuggestion.charAt(distanceTraversed++) != '{') {
147+
qInvocationSessionInstance.transitionToDecisionMade();
148+
qInvocationSessionInstance.end();
149+
return;
150+
}
151+
lastKeyStrokeType = LastKeyStrokeType.OPEN_CURLY;
152+
return;
153+
case '}':
154+
if (currentSuggestion.charAt(distanceTraversed++) != '}') {
155+
qInvocationSessionInstance.transitionToDecisionMade();
156+
qInvocationSessionInstance.end();
157+
return;
158+
}
159+
lastKeyStrokeType = LastKeyStrokeType.CURLY_BRACES;
160+
return;
161+
case '"':
162+
if (currentSuggestion.charAt(distanceTraversed++) != '"') {
163+
qInvocationSessionInstance.transitionToDecisionMade();
164+
qInvocationSessionInstance.end();
165+
return;
166+
}
167+
lastKeyStrokeType = LastKeyStrokeType.NORMAL_BRACKET;
168+
default:
169+
}
170+
171+
lastKeyStrokeType = LastKeyStrokeType.NORMAL_INPUT;
172+
}
173+
174+
@Override
175+
public void verifyText(final VerifyEvent event) {
176+
String input = event.text;
177+
switch (lastKeyStrokeType) {
178+
case NORMAL_INPUT:
179+
break;
180+
case OPEN_CURLY_FOLLOWED_BY_NEW_LINE:
181+
input = '\n' + event.text.split("\\R")[1];
182+
break;
183+
default:
184+
return;
185+
}
186+
187+
var qInvocationSessionInstance = QInvocationSession.getInstance();
188+
if (qInvocationSessionInstance == null || !qInvocationSessionInstance.isPreviewingSuggestions()) {
189+
return;
190+
}
191+
192+
String currentSuggestion = qInvocationSessionInstance.getCurrentSuggestion().getInsertText().trim();
193+
int currentOffset = widget.getCaretOffset();
194+
qInvocationSessionInstance
195+
.setHasBeenTypedahead(currentOffset - qInvocationSessionInstance.getInvocationOffset() > 0);
196+
197+
boolean isOutOfBounds = distanceTraversed >= currentSuggestion.length() || distanceTraversed < 0;
198+
if (isOutOfBounds || !isInputAMatch(currentSuggestion, distanceTraversed, input)) {
199+
qInvocationSessionInstance.transitionToDecisionMade();
200+
qInvocationSessionInstance.end();
201+
return;
202+
}
203+
distanceTraversed += input.length();
204+
}
205+
206+
private boolean isInputAMatch(final String currentSuggestion, final int startIdx, final String input) {
207+
boolean res;
208+
if (input.length() > 1) {
209+
res = currentSuggestion.substring(startIdx, startIdx + input.length()).equals(input);
210+
System.out.println("This is a match: " + res);
211+
} else {
212+
res = String.valueOf(currentSuggestion.charAt(startIdx)).equals(input);
213+
}
214+
return res;
215+
}
216+
}

plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInlineRendererListener.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ public final void paintControl(final PaintEvent e) {
7979
int y = location.y + lineHt * 2 - fontHt;
8080
gc.drawText(remainder, x, y, true);
8181
} else {
82-
qInvocationSessionInstance.unsetVerticalIndent();
82+
int line = widget.getLineAtOffset(widget.getCaretOffset());
83+
qInvocationSessionInstance.unsetVerticalIndent(line + 1);
8384
}
8485
}
8586

0 commit comments

Comments
 (0)