How to create an auto complete text field which adds items async?

I have tried to implemented autocomplete textbox using TextFieldCompletionProvider, but how to add lookup elements from webservice call?

3 comments
Comment actions Permalink

The completion is already asynchronous. addCompletionVariants() is called in a background thread, and the completion is updated as you call result.addElement().

0
Comment actions Permalink
public class MultiValueAutoComplete {
    private static final char[] SEPARATORS = {','};

    public static EditorTextField create(Project project, DataProvider dataProvider) {
        List<EditorCustomization> customizations =
                Arrays.<EditorCustomization>asList(SoftWrapsEditorCustomization.ENABLED, SpellCheckingEditorCustomization.DISABLED);
        EditorTextField editorField = ServiceManager.getService(project, EditorTextFieldProvider.class)
                .getEditorField(FileTypes.PLAIN_TEXT.getLanguage(), project, customizations);
        new CommaSeparatedTextFieldCompletion(dataProvider).apply(editorField);
        return editorField;

    }

    public interface DataProvider {
        List<String> getValues(String prefix);
    }

    private static class CommaSeparatedTextFieldCompletion extends TextFieldCompletionProvider {
        private DataProvider dataProvider;

        public CommaSeparatedTextFieldCompletion(DataProvider dataProvider) {
            this.dataProvider = dataProvider;
        }

        @NotNull
        @Override
        protected String getPrefix(@NotNull String currentTextPrefix) {
            final int separatorPosition = lastSeparatorPosition(currentTextPrefix);
            return separatorPosition == -1 ? currentTextPrefix : currentTextPrefix.substring(separatorPosition + 1).trim();
        }

        private static int lastSeparatorPosition(@NotNull String text) {
            int lastPosition = -1;
            for (char separator : SEPARATORS) {
                int lio = text.lastIndexOf(separator);
                if (lio > lastPosition) {
                    lastPosition = lio;
                }
            }
            return lastPosition;
        }

        @Override
        protected void addCompletionVariants(@NotNull String text, int offset, @NotNull String prefix,
                                             @NotNull CompletionResultSet result) {

            result.addLookupAdvertisement("Select one or more users separated with comma, | or new lines");
            List<String> values = dataProvider.getValues(prefix); // Web serice Call
            for (String completionVariant : values) {
                final LookupElementBuilder element = LookupElementBuilder.create(completionVariant);
                result.addElement(element.withLookupString(completionVariant.toLowerCase()));
            }

        }
    }
}


This is my code snipet.
As I type in the text field Intellij hangs. I'm not able to figure out what is missing. Thanks :)

0
Comment actions Permalink

To avoid IDE freezing, completion thread must not perform any blocking calls, and should call ProgressManager.checkCanceled often enough (e.g. every 50ms). You can start another thread, wait for the web service to return there (while doing a busy-loop with checkCanceled on the completion thread), and cancel this operation if checkCanceled throws ProcessCanceledException. Then, after you get all the variants from the web service, you can feed them into CompletionResultSet on the completion thread again.

0

Please sign in to leave a comment.