fun getMatchingSymbolsFromRecommendation()

in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererEditorManager.kt [125:216]


    fun getMatchingSymbolsFromRecommendation(
        editor: Editor,
        recommendation: String,
        isTruncatedOnRight: Boolean,
        sessionContext: SessionContext,
    ): 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

        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) {
                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)) {
                    continue
                }

                // 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)
                    break
                } 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)
                    break
                } 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)
                    }
                    break
                }
            }
        }

        // 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
    }