suspend fun extract()

in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/editor/context/focusArea/FocusAreaContextExtractor.kt [27:159]


    suspend fun extract(): FocusAreaContext? {
        val editor = computeOnEdt {
            FileEditorManager.getInstance(project).selectedTextEditor
        } ?: return null

        if (editor.document.text.isBlank()) return null

        // Get 10k characters around the cursor
        val (trimmedFileText, trimmedFileTextSelection) = computeOnEdt {
            val (start, end) = getOffsetRangeAtCursor(MAX_LENGTH, editor)
            val fileTextStartPos = editor.offsetToLogicalPosition(start)
            val fileTextEndPos = editor.offsetToLogicalPosition(end)
            val trimmedFileText = getTextAtOffsets(fileTextStartPos, fileTextEndPos, editor)
            val trimmedFileTextSelection = UICodeSelectionRange(
                start = UICodeSelectionLineRange(
                    row = fileTextStartPos.line,
                    column = fileTextStartPos.column,
                ),
                end = UICodeSelectionLineRange(
                    row = fileTextEndPos.line,
                    column = fileTextEndPos.column,
                ),
            )
            Pair(trimmedFileText, trimmedFileTextSelection)
        }

        // Get user selected code or visible text area
        val (codeSelection, codeSelectionRange) = computeOnEdt {
            val selectionModel: SelectionModel = editor.selectionModel
            val selectedText = selectionModel.selectedText
            if (selectedText == null) {
                // Get visible area text
                val visibleArea = editor.scrollingModel.visibleArea
                val startOffset = editor.xyToLogicalPosition(Point(visibleArea.x, visibleArea.y))
                val endOffset = editor.xyToLogicalPosition(Point(visibleArea.x + visibleArea.width, visibleArea.y + visibleArea.height))

                // Get text of visible area
                val visibleAreaText = getTextAtOffsets(startOffset, endOffset, editor)

                // If visible area text too big use trimmedSurroundingText
                if (visibleAreaText.length > MAX_LENGTH) {
                    Pair(trimmedFileText, trimmedFileTextSelection)
                } else {
                    // Ensure end line isn't beyond the end of the document
                    val endLine = min(endOffset.line, editor.document.lineCount - 1)
                    val endColumn = min(endOffset.column, visibleAreaText.lengthOfLastLine() - 1)

                    val codeSelectionRange = UICodeSelectionRange(
                        start = UICodeSelectionLineRange(
                            row = startOffset.line,
                            column = startOffset.column,
                        ),
                        end = UICodeSelectionLineRange(
                            row = endLine,
                            column = endColumn,
                        ),
                    )
                    Pair(visibleAreaText, codeSelectionRange)
                }
            } else if (selectedText.length > MAX_LENGTH) {
                Pair(trimmedFileText, trimmedFileTextSelection)
            } else {
                // Use selected text ranges
                val selectedStartPos = editor.offsetToLogicalPosition(selectionModel.selectionStart)
                val selectedEndPos = editor.offsetToLogicalPosition(selectionModel.selectionEnd)

                val codeSelectionRange = UICodeSelectionRange(
                    start = UICodeSelectionLineRange(
                        row = selectedStartPos.line,
                        column = selectedStartPos.column,
                    ),
                    end = UICodeSelectionLineRange(
                        row = selectedEndPos.line,
                        column = selectedEndPos.column,
                    ),
                )
                Pair(selectedText, codeSelectionRange)
            }
        }

        // Retrieve <codeNames> from  trimmedFileText
        val fileLanguage = computeOnEdt {
            languageExtractor.extractLanguageNameFromCurrentFile(editor)
        }
        val fileText = editor.document.text
        val fileName = FileEditorManager.getInstance(project).selectedFiles.first().name

        // Offset the selection range to the start of the trimmedFileText
        val selectionInsideTrimmedFileTextRange = codeSelectionRange.let {
            UICodeSelectionRange(
                start = UICodeSelectionLineRange(
                    row = it.start.row - trimmedFileTextSelection.start.row,
                    column = it.start.column
                ),
                end = UICodeSelectionLineRange(
                    row = it.end.row - trimmedFileTextSelection.start.row,
                    column = it.end.column
                ),
            )
        }

        var codeNames: CodeNames? = null
        if (fileLanguage != null) {
            val extractNamesRequest = ExtractNamesRequest(
                language = fileLanguage,
                fileContent = fileText,
                codeSelection = UICodeSelection(
                    selectedCode = trimmedFileText,
                    file = UICodeSelectionFile(
                        name = fileName,
                        range = selectionInsideTrimmedFileTextRange,
                    ),
                ),
            )
            val requestString = ChatController.objectMapper.writeValueAsString(extractNamesRequest)

            codeNames = try {
                fqnWebviewAdapter?.let {
                    ChatController.objectMapper.readValue(it.extractNames(requestString), CodeNamesImpl::class.java)
                } ?: CodeNamesImpl(simpleNames = emptyList(), fullyQualifiedNames = FullyQualifiedNames(used = emptyList()))
            } catch (e: Exception) {
                getLogger<FocusAreaContextExtractor>().warn(e) { "Failed to extract names from file" }
                null
            }
        }

        return FocusAreaContext(
            codeSelection = codeSelection,
            codeSelectionRange = selectionInsideTrimmedFileTextRange,
            trimmedSurroundingFileText = trimmedFileText,
            codeNames = codeNames,
        )
    }