public void documentChanged()

in plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInlineInputListener.java [265:384]


    public void documentChanged(final DocumentEvent event) {
        QInvocationSession session = QInvocationSession.getInstance();

        if (session == null || !session.isPreviewingSuggestions()) {
            return;
        }

        String input = event.getText();
        if (input.equals("( ") || input.equals("[ ") || input.equals("< ") || input.equals("\" ")
                || input.equals("\' ")) {
            input = input.substring(0, 1);
        }
        String currentSuggestion = session.getCurrentSuggestion().getInsertText();
        int currentOffset = widget.getCaretOffset();

        if (input.isEmpty()) {
            if (distanceTraversed <= 0) {
                // discard all suggestions as caret position is less than request invocation position
                session.updateCompletionStates(new ArrayList<String>());
                session.transitionToDecisionMade();
                session.end();
                return;
            }
            distanceTraversed = typeaheadProcessor.getNewDistanceTraversedOnDeleteAndUpdateBracketState(
                    event.getLength(), distanceTraversed, brackets);
            if (distanceTraversed < 0) {
                // discard all suggestions as caret position is less than request invocation position
                session.updateCompletionStates(new ArrayList<String>());
                session.transitionToDecisionMade();
                session.end();
            }

            // note: distanceTraversed as 0 is currently understood to be when a user presses BS removing any typeahead
            if (distanceTraversed == 0) {
                // reset completion states for all suggestions when user reverts to request
                // invocation state
                session.resetCompletionStates();
                // mark currently displayed suggestion as seen
                session.markSuggestionAsSeen();
            }

            return;
        }

        // Here we perform "pre-open bracket insertion input sanitation", which consists
        // of the following:
        // - Checks to see if the input contains anything inserted on behalf of user by
        // eclipse (i.e. auto closing bracket).
        // - If it does, get rid of that portion (note that at this point the document
        // has already been changed so we are really deleting the extra portion and
        // replacing it with what should remain).
        // - Lastly, we would want to return early for these two cases. This is because
        // the very act of altering the document will trigger this callback once again
        // so there is no need to validate the input this time around.
        TypeaheadProcessorInstruction preprocessInstruction = typeaheadProcessor
                .preprocessDocumentChangedBuffer(distanceTraversed, currentOffset, input, brackets);
        if (preprocessInstruction.shouldModifyCaretOffset()) {
            widget.setCaretOffset(preprocessInstruction.getCaretOffset());
        }
        if (preprocessInstruction.shouldModifyDocument()) {
            try {
                int expandedOffset = QEclipseEditorUtils.getOffsetInFullyExpandedDocument(session.getViewer(),
                        preprocessInstruction.getDocInsertOffset());
                event.getDocument().replace(expandedOffset, preprocessInstruction.getDocInsertLength(),
                        preprocessInstruction.getDocInsertContent());
                return;
            } catch (BadLocationException e) {
                Activator.getLogger().error("Error performing open bracket sanitation during typeahead", e);
            }
        }

        boolean isOutOfBounds = distanceTraversed + input.length() >= currentSuggestion.length()
                || distanceTraversed < 0;
        if (isOutOfBounds || !isInputAMatch(currentSuggestion, distanceTraversed, input)) {
            distanceTraversed += input.length();
            event.getDocument().removeDocumentListener(this);
            StyledText widget = session.getViewer().getTextWidget();
            int caretLine = widget.getLineAtOffset(widget.getCaretOffset());
            int linesOfInput = input.split(widget.getLineDelimiter()).length;
            int lineToUnsetIndent = caretLine + linesOfInput;
            session.transitionToDecisionMade(lineToUnsetIndent);
            Display.getCurrent().asyncExec(() -> {
                if (session.isActive()) {
                    // discard suggestions and end immediately as typeahead does not match
                    session.updateCompletionStates(new ArrayList<String>());
                    session.endImmediately();
                }
            });
            return;
        }

        // discard all other suggestions except for current one as typeahead matches it
        // also mark current one as seen as it continues to be displayed
        session.updateCompletionStates(List.of(session.getCurrentSuggestion().getItemId()));
        session.markSuggestionAsSeen();

        // Here we perform "post closing bracket insertion caret correction", which
        // consists of the following:
        // - Check if the input is a closing bracket
        // - If it is, check to see if it corresponds to the most recent unresolved open
        // bracket
        // - If it is, we would need to increment the current caret offset, this is
        // because the closing bracket would have been inserted by verifyKey and not
        // organically, which does not advance the caret.
        TypeaheadProcessorInstruction postProcessInstruction = typeaheadProcessor
                .postProcessDocumentChangeBuffer(distanceTraversed, currentOffset, input, brackets);
        if (postProcessInstruction.shouldModifyCaretOffset()) {
            int targetOffset = postProcessInstruction.getCaretOffset();
            widget.setCaretOffset(targetOffset);
        }

        for (int i = distanceTraversed; i < distanceTraversed + input.length(); i++) {
            var bracket = brackets[i];
            if (bracket != null) {
                bracket.onTypeOver();
            }
        }

        distanceTraversed += input.length();
    }