-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bracket matching #50
Merged
Merged
Bracket matching #50
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
faa51d6
Adds abstractions for bracket matching
dingfeli b6485ab
Disables auto closing brackets during typeahead
dingfeli eb5a6f4
Adds segment factory
dingfeli a54beb4
Changes inline renderer listener to use segments to paint
dingfeli d470a7f
Separates rendering of brackets from normal buffer
dingfeli cac5764
Renders closing bracket separately from the rest of the suggestion
dingfeli 0d3f437
Highlights bracket pairs
dingfeli f824ac5
Adds logic to insert closing bracket on premature preview termination
dingfeli e384878
Terminates session should caret have moved prior to suggestion is ren…
dingfeli d6ca4d1
Adds logic to check the number characters deleted
dingfeli 00be4d3
Clears suggestion segments prior to priming for new suggestion
dingfeli ba5a871
Fixes premture preview termination
dingfeli a39e415
Dedupes typed ahead content from acceptance insertion
dingfeli 721c2e7
Changes color of the auto closing brackets
dingfeli c4364f3
Corrects logic for backspacing during typeahead
dingfeli 3312be7
Fixes caret jumps from editor breaking preview
dingfeli 740b969
Untrims first line of suggestion
dingfeli 1bed68c
Adds workbench listener to revert user settings changed on shutdown
dingfeli 30a1ed1
Fixes checkstyle errors
dingfeli c814d7e
Accommodates for scenarios where editor and suggestions do not agree …
dingfeli 380712f
Improves suggestion text sanitization logic
dingfeli e3ae679
Merge branch 'main' into bracket-matching
dingfeli 45d58ba
Fixes checkstyle error
dingfeli 066577e
Merge branch 'main' into bracket-matching
breedloj 6c6f2ee
Chanages bracket type NADA member to NONE
dingfeli File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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, NADA; | ||
} | ||
|
||
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 NADA: | ||
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.NADA; | ||
} | ||
|
||
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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This made me chuckle..but maybe
NONE
? 😄