in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererEditorManagerNew.kt [106:199]
fun getMatchingSymbolsFromRecommendation(
editor: Editor,
recommendation: String,
isTruncatedOnRight: Boolean,
sessionContext: SessionContextNew,
): List<Pair<Int, Int>> {
val result = mutableListOf<Pair<Int, Int>>()
val bracketsStack = Stack<Char>()
val quotesStack = Stack<Pair<Char, Pair<Int, Int>>>()
val caretOffset = editor.caretModel.primaryCaret.offset
val document = editor.document
val lineEndOffset = document.getLineEndOffset(document.getLineNumber(caretOffset))
val lineText = document.charsSequence.subSequence(caretOffset, lineEndOffset)
var totalDocLengthChecked = 0
var current = 0
var shouldContinue = true
result.add(0 to caretOffset)
result.add(recommendation.length + 1 to lineEndOffset)
if (isTruncatedOnRight) return result
while (current < recommendation.length &&
totalDocLengthChecked < lineText.length &&
totalDocLengthChecked < recommendation.length
) {
val currentDocChar = lineText[totalDocLengthChecked]
if (!isMatchingSymbol(currentDocChar)) {
// currentDocChar is not a matching symbol, so we try to compare the remaining strings as a last step to match
val recommendationRemaining = recommendation.substring(current)
val rightContextRemaining = lineText.subSequence(totalDocLengthChecked, lineText.length).toString()
if (recommendationRemaining == rightContextRemaining) {
for (i in 1..recommendation.length - current) {
result.add(current + i to caretOffset + totalDocLengthChecked + i)
}
result.sortBy { it.first }
}
break
}
totalDocLengthChecked++
// find symbol in the recommendation that will match this
while (current < recommendation.length && shouldContinue) {
val char = recommendation[current]
current++
// if char isn't a paired symbol, or it is, but it's not the matching currentDocChar or
// the opening version of it, then we're done
if (!isMatchingSymbol(char) ||
(char != currentDocChar && PAIRED_BRACKETS[char] != currentDocChar) ||
PAIRED_BRACKETS[char] == currentDocChar
) {
// if char is an opening bracket, push it to the stack
if (PAIRED_BRACKETS[char] == currentDocChar) {
bracketsStack.push(char)
}
continue
}
// char is currentDocChar, it's one of a bracket, a quote, or a whitespace character.
// If it's a whitespace character, directly add it to the result,
// if it's a bracket or a quote, check if this char is already having a matching opening symbol
// on the stack
if (char.isWhitespace()) {
result.add(current to caretOffset + totalDocLengthChecked)
shouldContinue = false
} else if (bracketsStack.isNotEmpty() && PAIRED_BRACKETS[bracketsStack.peek()] == char) {
bracketsStack.pop()
} else if (quotesStack.isNotEmpty() && quotesStack.peek().first == char) {
result.add(quotesStack.pop().second)
result.add(current to caretOffset + totalDocLengthChecked)
shouldContinue = false
} else {
// char does not have a matching opening symbol in the stack, if it's a (opening) bracket,
// immediately add it to the result; if it's a quote, push it to the stack
if (PAIRED_QUOTES.contains(char)) {
quotesStack.push(char to (current to caretOffset + totalDocLengthChecked))
} else {
result.add(current to caretOffset + totalDocLengthChecked)
}
shouldContinue = false
}
}
}
// if there are any symbols left in the stack, add them to the result
quotesStack.forEach { result.add(it.second) }
result.sortBy { it.first }
sessionContext.insertEndOffset = result[result.size - 2].second
return result
}