private AutoCompletionDecision shouldAutoComplete(
      final CompletionProgressIndicator indicator, final LookupElement[] items) {
    if (!invokedExplicitly) {
      return AutoCompletionDecision.SHOW_LOOKUP;
    }
    final CompletionParameters parameters = indicator.getParameters();
    final LookupElement item = items[0];
    if (items.length == 1) {
      final AutoCompletionPolicy policy = getAutocompletionPolicy(item);
      if (policy == AutoCompletionPolicy.NEVER_AUTOCOMPLETE)
        return AutoCompletionDecision.SHOW_LOOKUP;
      if (policy == AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE)
        return AutoCompletionDecision.insertItem(item);
      if (!indicator.getLookup().itemMatcher(item).isStartMatch(item))
        return AutoCompletionDecision.SHOW_LOOKUP;
    }
    if (!isAutocompleteOnInvocation(parameters.getCompletionType())) {
      return AutoCompletionDecision.SHOW_LOOKUP;
    }
    if (isInsideIdentifier(indicator.getOffsetMap())) {
      return AutoCompletionDecision.SHOW_LOOKUP;
    }
    if (items.length == 1
        && getAutocompletionPolicy(item) == AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE) {
      return AutoCompletionDecision.insertItem(item);
    }

    AutoCompletionContext context =
        new AutoCompletionContext(
            parameters, items, indicator.getOffsetMap(), indicator.getLookup());
    for (final CompletionContributor contributor :
        CompletionContributor.forParameters(parameters)) {
      final AutoCompletionDecision decision = contributor.handleAutoCompletionPossibility(context);
      if (decision != null) {
        return decision;
      }
    }

    return AutoCompletionDecision.SHOW_LOOKUP;
  }
  private static CompletionAssertions.WatchingInsertionContext insertItem(
      final CompletionProgressIndicator indicator,
      final LookupElement item,
      final char completionChar,
      List<LookupElement> items,
      final CompletionLookupArranger.StatisticsUpdate update,
      final Editor editor,
      final PsiFile psiFile,
      final int caretOffset,
      final int idEndOffset) {
    editor.getCaretModel().moveToOffset(caretOffset);
    final int initialStartOffset = caretOffset - item.getLookupString().length();
    assert initialStartOffset >= 0
        : "negative startOffset: " + caretOffset + "; " + item.getLookupString();

    indicator
        .getOffsetMap()
        .addOffset(CompletionInitializationContext.START_OFFSET, initialStartOffset);
    indicator
        .getOffsetMap()
        .addOffset(CompletionInitializationContext.SELECTION_END_OFFSET, caretOffset);
    indicator
        .getOffsetMap()
        .addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, idEndOffset);

    final CompletionAssertions.WatchingInsertionContext context =
        new CompletionAssertions.WatchingInsertionContext(
            indicator.getOffsetMap(), psiFile, completionChar, items, editor);
    ApplicationManager.getApplication()
        .runWriteAction(
            new Runnable() {
              @Override
              public void run() {
                if (caretOffset != idEndOffset && completionChar == Lookup.REPLACE_SELECT_CHAR) {
                  editor.getDocument().deleteString(caretOffset, idEndOffset);
                }

                assert context.getStartOffset() >= 0
                    : "stale startOffset: was "
                        + initialStartOffset
                        + "; selEnd="
                        + caretOffset
                        + "; idEnd="
                        + idEndOffset
                        + "; file="
                        + context.getFile();
                assert context.getTailOffset() >= 0
                    : "stale tail: was "
                        + initialStartOffset
                        + "; selEnd="
                        + caretOffset
                        + "; idEnd="
                        + idEndOffset
                        + "; file="
                        + context.getFile();

                item.handleInsert(context);
                Project project = indicator.getProject();
                PostprocessReformattingAspect.getInstance(project).doPostponedFormatting();

                if (context.shouldAddCompletionChar()) {
                  addCompletionChar(project, context, item, editor, indicator, completionChar);
                }
                if (!editor
                    .getCaretModel()
                    .supportsMultipleCarets()) { // done later, outside of this method
                  context.stopWatching();
                }
                editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
              }
            });
    update.addSparedChars(indicator, item, context, completionChar);
    return context;
  }