-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Adds abstractions for bracket matching * Disables auto closing brackets during typeahead * Adds segment factory * Changes inline renderer listener to use segments to paint * Separates rendering of brackets from normal buffer * Renders closing bracket separately from the rest of the suggestion * Highlights bracket pairs * Adds logic to insert closing bracket on premature preview termination * Terminates session should caret have moved prior to suggestion is rendered * Adds logic to check the number characters deleted * Clears suggestion segments prior to priming for new suggestion * Fixes premture preview termination * Dedupes typed ahead content from acceptance insertion * Changes color of the auto closing brackets * Corrects logic for backspacing during typeahead * Fixes caret jumps from editor breaking preview * Untrims first line of suggestion * Adds workbench listener to revert user settings changed on shutdown * Fixes checkstyle errors * Accommodates for scenarios where editor and suggestions do not agree on whitespace format * Improves suggestion text sanitization logic * Fixes checkstyle error * Chanages bracket type NADA member to NONE --------- Co-authored-by: Jonathan Breedlove <[email protected]>
- Loading branch information
Showing
13 changed files
with
800 additions
and
182 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
public enum CaretMovementReason { | ||
UNEXAMINED, | ||
MOVEMENT_KEY, | ||
TEXT_INPUT | ||
TEXT_INPUT, | ||
MOUSE, | ||
} | ||
|
22 changes: 22 additions & 0 deletions
22
plugin/src/software/aws/toolkits/eclipse/amazonq/util/IQInlineBracket.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
|
||
package software.aws.toolkits.eclipse.amazonq.util; | ||
|
||
import org.eclipse.ui.services.IDisposable; | ||
|
||
public interface IQInlineBracket extends IDisposable { | ||
void onTypeOver(); | ||
|
||
void onDelete(); | ||
|
||
void pairUp(IQInlineBracket partner); | ||
|
||
boolean hasPairedUp(); | ||
|
||
String getAutoCloseContent(boolean isBracketSetToAutoClose, boolean isBracesSetToAutoClose, | ||
boolean isStringSetToAutoClose); | ||
|
||
int getRelevantOffset(); | ||
|
||
char getSymbol(); | ||
} |
9 changes: 9 additions & 0 deletions
9
plugin/src/software/aws/toolkits/eclipse/amazonq/util/IQInlineSuggestionSegment.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
|
||
package software.aws.toolkits.eclipse.amazonq.util; | ||
|
||
import org.eclipse.swt.graphics.GC; | ||
|
||
public interface IQInlineSuggestionSegment { | ||
void render(GC gc, int currentCaretOffset); | ||
} |
131 changes: 131 additions & 0 deletions
131
plugin/src/software/aws/toolkits/eclipse/amazonq/util/IQInlineSuggestionSegmentFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
|
||
package software.aws.toolkits.eclipse.amazonq.util; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Stack; | ||
|
||
public final class IQInlineSuggestionSegmentFactory { | ||
|
||
private IQInlineSuggestionSegmentFactory() { | ||
} | ||
|
||
private enum BracketType { | ||
OPEN, CLOSE, NONE; | ||
} | ||
|
||
public static List<IQInlineSuggestionSegment> getSegmentsFromSuggestion(final QInvocationSession qSes) { | ||
var suggestion = qSes.getCurrentSuggestion().getInsertText(); | ||
var suggestionLines = suggestion.split("\\R"); | ||
var res = new ArrayList<IQInlineSuggestionSegment>(); | ||
var widget = qSes.getViewer().getTextWidget(); | ||
int currentOffset = widget.getCaretOffset(); | ||
int distanceTraversed = 0; | ||
Stack<QInlineSuggestionOpenBracketSegment> unresolvedBrackets = new Stack<>(); | ||
for (int i = 0; i < suggestionLines.length; i++) { | ||
int startOffset; | ||
int endOffset; | ||
String currentLine = suggestionLines[i]; | ||
StringBuilder sb; | ||
|
||
startOffset = currentOffset + distanceTraversed; // this line might not exist yet so we need to think of | ||
// something more robust | ||
sb = new StringBuilder(currentLine); | ||
|
||
String currentIndent; | ||
if (i == 0) { | ||
int currentLineInDoc = widget.getLineAtOffset(currentOffset); | ||
String content = widget.getLine(currentLineInDoc); | ||
int leadingWhitespacePosition = !content.isEmpty() ? idxOfFirstNonwhiteSpace(content) : 0; | ||
currentIndent = content.substring(0, leadingWhitespacePosition); | ||
} else { | ||
int leadingWhitespacePosition = idxOfFirstNonwhiteSpace(currentLine); | ||
currentIndent = currentLine.substring(0, leadingWhitespacePosition); | ||
} | ||
for (int j = 0; j < currentLine.length(); j++) { | ||
char c = currentLine.charAt(j); | ||
switch (getBracketType(unresolvedBrackets, suggestion, distanceTraversed + j)) { | ||
case OPEN: | ||
var openBracket = new QInlineSuggestionOpenBracketSegment(startOffset + j, currentIndent, c); | ||
unresolvedBrackets.push(openBracket); | ||
break; | ||
case CLOSE: | ||
if (!unresolvedBrackets.isEmpty()) { | ||
var closeBracket = new QInlineSuggestionCloseBracketSegment(startOffset + j, i, | ||
currentLine.substring(0, j), c); | ||
var top = unresolvedBrackets.pop(); | ||
if (top.isAMatch(closeBracket)) { | ||
top.pairUp(closeBracket); | ||
sb.setCharAt(j, ' '); | ||
res.add(closeBracket); | ||
res.add(top); | ||
} else { | ||
top.dispose(); | ||
closeBracket.dispose(); | ||
} | ||
} | ||
break; | ||
case NONE: | ||
default: | ||
continue; | ||
} | ||
} | ||
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())); | ||
} | ||
return res; | ||
} | ||
|
||
private static BracketType getBracketType(final Stack<QInlineSuggestionOpenBracketSegment> unresolvedBrackets, | ||
final String input, final int idx) { | ||
if (isCloseBracket(input, idx, unresolvedBrackets)) { | ||
// TODO: enrich logic here to eliminate false positive | ||
return BracketType.CLOSE; | ||
} else if (isOpenBracket(input, idx)) { | ||
// TODO: enrich logic here to eliminate false positive | ||
return BracketType.OPEN; | ||
} | ||
return BracketType.NONE; | ||
} | ||
|
||
private static boolean isCloseBracket(final String input, final int idx, | ||
final Stack<QInlineSuggestionOpenBracketSegment> unresolvedBrackets) { | ||
char c = input.charAt(idx); | ||
boolean isBracket = c == ')' || c == ']' || c == '}' || c == '>' || c == '"' || c == '\''; | ||
if (!isBracket) { | ||
return false; | ||
} | ||
if (c == '"' || c == '\'') { | ||
return !unresolvedBrackets.isEmpty() && unresolvedBrackets.peek().getSymbol() == c; | ||
} | ||
// TODO: enrich this check to eliminate false positives | ||
if (idx > 0 && Character.isWhitespace(input.charAt(idx - 1)) && c == '>') { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
private static boolean isOpenBracket(final String input, final int idx) { | ||
char c = input.charAt(idx); | ||
boolean isBracket = c == '(' || c == '[' || c == '{' || c == '<' || c == '"' || c == '\''; | ||
if (!isBracket) { | ||
return false; | ||
} | ||
// TODO: enrich this check to eliminate false postives | ||
if (idx > 0 && Character.isWhitespace(input.charAt(idx - 1)) && c == '<') { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
private static int idxOfFirstNonwhiteSpace(final String input) { | ||
for (int i = 0; i < input.length(); i++) { | ||
if (input.charAt(i) != ' ' && input.charAt(i) != '\t') { | ||
return i; | ||
} | ||
} | ||
return input.length(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.