private synchronized void queryAsync()

in plugin/src/software/aws/toolkits/eclipse/amazonq/util/QInvocationSession.java [179:293]


    private synchronized void queryAsync(final InlineCompletionParams params, final int invocationOffset) {
        var uuid = UUID.randomUUID();
        Activator.getLogger().info(uuid + " queried made at " + invocationOffset);
        var future = ThreadingUtils.executeAsyncTaskAndReturnFuture(() -> {
            try {
                var session = QInvocationSession.getInstance();
                List<InlineCompletionItem> newSuggestions = new ArrayList<InlineCompletionItem>();
                List<String> sessionId = new ArrayList<String>();
                long requestInvocation = System.currentTimeMillis();

                // request lsp for suggestions
                var response = Activator.getLspProvider().getAmazonQServer().get()
                        .inlineCompletionWithReferences(params);
                response.thenAccept(result -> {
                    sessionId.add(result.getSessionId());
                    var suggestions = result.getItems().parallelStream().map(item -> {
                        if (isTabOnly) {
                            String sanitizedText = replaceSpacesWithTabs(item.getInsertText(), tabSize);
                            item.setInsertText(sanitizedText);
                        }
                        return item;
                    }).collect(Collectors.toList());
                    newSuggestions.addAll(suggestions);
                }).get();

                Display.getDefault().asyncExec(() -> {
                    unresolvedTasks.remove(uuid);

                    if (newSuggestions == null || newSuggestions.isEmpty() || sessionId.get(0) == null || sessionId.get(0).isEmpty()) {
                        if (!session.isPreviewingSuggestions()) {
                            end();
                        }
                        Activator.getLogger().info(uuid + " returned with no result.");
                        if (params.getContext().getTriggerKind() == InlineCompletionTriggerKind.Invoke) {
                            Display display = Display.getDefault();
                            String message = "Q returned no suggestions";
                            QEclipseEditorUtils.showToast(message, display, 2000);
                        }
                        return;
                    } else {
                        Activator.getLogger().info(uuid + " returned with " + newSuggestions.size() + " results.");
                    }

                    suggestionsContext.setSessionId(sessionId.get(0));
                    suggestionsContext.setRequestedAtEpoch(requestInvocation);
                    suggestionsContext.getDetails()
                            .addAll(newSuggestions.stream().map(QSuggestionContext::new).collect(Collectors.toList()));

                    initializeSuggestionCompletionResults();

                    // If the caret positions has moved on from the invocation offset, we need to
                    // see if there exists in the suggestions fetched
                    // one more suggestions that qualify for what has been typed since the
                    // invocation.
                    // Note that we should not remove the ones that have been disqualified by the
                    // content typed since the user might still want to explore them.
                    int currentIdxInSuggestion = 0;
                    boolean hasAMatch = false;
                    var viewer = session.getViewer();
                    if (viewer == null || viewer.getTextWidget() == null || viewer.getTextWidget().getCaretOffset() < invocationOffset) {
                        // discard all suggestions since the current caret is behind request position
                        updateCompletionStates(new ArrayList<String>());
                        end();
                        return;
                    }

                    if (viewer != null && viewer.getTextWidget() != null && viewer.getTextWidget().getCaretOffset() > invocationOffset) {
                        var widget = viewer.getTextWidget();
                        int currentOffset = widget.getCaretOffset();
                        String prefix = widget.getTextRange(invocationOffset, currentOffset - invocationOffset);
                        // Computes the typed prefix and typeahead length from when user invocation happened to
                        // before suggestions are first shown in UI
                        // Note: This computation may change later on but follows the same pattern for consistency across IDEs for now
                        session.initialTypeaheadLength = Optional.of(prefix.length());

                        for (int i = 0; i < newSuggestions.size(); i++) {
                            if (newSuggestions.get(i).getInsertText().startsWith(prefix)) {
                                currentIdxInSuggestion = i;
                                hasAMatch = true;
                                break;
                            }
                        }
                        // indicates that typeahead prefix does not match any suggestions
                        if (invocationOffset != currentOffset && !hasAMatch) {
                            // all suggestions filtered out, mark them as discarded
                            updateCompletionStates(new ArrayList<String>());
                            end();
                            return;
                        }

                        // if typeahead exists, mark all suggestions except for current suggestion index with match as discarded
                        // As of Jan 25, current logic blocks users from toggling between suggestions when a typeahead exists in QToggleSuggestionsHandler
                        if (invocationOffset != currentOffset && hasAMatch) {
                            var currentSuggestion = suggestionsContext.getDetails().get(currentIdxInSuggestion);
                            var filteredSuggestions = List.of(currentSuggestion.getInlineCompletionItem().getItemId());
                            updateCompletionStates(filteredSuggestions);
                        }
                    }

                    session.invocationOffset = invocationOffset;
                    suggestionsContext.setCurrentIndex(currentIdxInSuggestion);

                    session.transitionToPreviewingState();
                    attachListeners();
                    session.primeListeners();
                    session.getViewer().getTextWidget().redraw();
                });
            } catch (InterruptedException e) {
                Activator.getLogger().error("Inline completion interrupted", e);
            } catch (ExecutionException e) {
                Activator.getLogger().error("Error executing inline completion", e);
            }
        });
        unresolvedTasks.put(uuid, future);
    }