protected void completionFinished(
      final int offset1,
      final int offset2,
      final CompletionProgressIndicator indicator,
      final LookupElement[] items,
      boolean hasModifiers) {
    if (items.length == 0) {
      LookupManager.getInstance(indicator.getProject()).hideActiveLookup();
      indicator.handleEmptyLookup(true);
      checkNotSync(indicator, items);
      return;
    }

    LOG.assertTrue(!indicator.isRunning(), "running");
    LOG.assertTrue(!indicator.isCanceled(), "canceled");

    indicator.getLookup().refreshUi(true, false);
    final AutoCompletionDecision decision = shouldAutoComplete(indicator, items);
    if (decision == AutoCompletionDecision.SHOW_LOOKUP) {
      CompletionServiceImpl.setCompletionPhase(new CompletionPhase.ItemsCalculated(indicator));
      indicator.getLookup().setCalculating(false);
      indicator.showLookup();
    } else if (decision instanceof AutoCompletionDecision.InsertItem) {
      final Runnable restorePrefix = rememberDocumentState(indicator.getEditor());

      final LookupElement item = ((AutoCompletionDecision.InsertItem) decision).getElement();
      CommandProcessor.getInstance()
          .executeCommand(
              indicator.getProject(),
              new Runnable() {
                @Override
                public void run() {
                  indicator.setMergeCommand();
                  indicator.getLookup().finishLookup(Lookup.AUTO_INSERT_SELECT_CHAR, item);
                }
              },
              "Autocompletion",
              null);

      // the insert handler may have started a live template with completion
      if (CompletionService.getCompletionService().getCurrentCompletion() == null
          && !ApplicationManager.getApplication().isUnitTestMode()) {
        CompletionServiceImpl.setCompletionPhase(
            hasModifiers
                ? new CompletionPhase.InsertedSingleItem(indicator, restorePrefix)
                : CompletionPhase.NoCompletion);
      }
      checkNotSync(indicator, items);
    } else if (decision == AutoCompletionDecision.CLOSE_LOOKUP) {
      LookupManager.getInstance(indicator.getProject()).hideActiveLookup();
      checkNotSync(indicator, items);
    }
  }
  private void doComplete(
      CompletionInitializationContext initContext,
      boolean hasModifiers,
      int invocationCount,
      PsiFile hostCopy,
      OffsetMap hostMap,
      OffsetTranslator translator) {
    final Editor editor = initContext.getEditor();
    CompletionAssertions.checkEditorValid(editor);

    CompletionContext context =
        createCompletionContext(
            hostCopy,
            hostMap.getOffset(CompletionInitializationContext.START_OFFSET),
            hostMap,
            initContext.getFile());
    LookupImpl lookup = obtainLookup(editor);
    CompletionParameters parameters = createCompletionParameters(invocationCount, context, editor);

    CompletionPhase phase = CompletionServiceImpl.getCompletionPhase();
    if (phase instanceof CompletionPhase.CommittingDocuments) {
      if (phase.indicator != null) {
        phase.indicator.closeAndFinish(false);
      }
      ((CompletionPhase.CommittingDocuments) phase).replaced = true;
    } else {
      CompletionServiceImpl.assertPhase(CompletionPhase.NoCompletion.getClass());
    }

    final Semaphore freezeSemaphore = new Semaphore();
    freezeSemaphore.down();
    final CompletionProgressIndicator indicator =
        new CompletionProgressIndicator(
            editor,
            parameters,
            this,
            freezeSemaphore,
            initContext.getOffsetMap(),
            hasModifiers,
            lookup);
    Disposer.register(indicator, hostMap);
    Disposer.register(indicator, context.getOffsetMap());
    Disposer.register(indicator, translator);

    CompletionServiceImpl.setCompletionPhase(
        synchronous
            ? new CompletionPhase.Synchronous(indicator)
            : new CompletionPhase.BgCalculation(indicator));

    final AtomicReference<LookupElement[]> data = indicator.startCompletion(initContext);

    if (!synchronous) {
      return;
    }

    if (freezeSemaphore.waitFor(2000)) {
      final LookupElement[] allItems = data.get();
      if (allItems != null
          && !indicator.isRunning()
          && !indicator
              .isCanceled()) { // the completion is really finished, now we may auto-insert or show
        // lookup
        completionFinished(
            initContext.getStartOffset(),
            initContext.getSelectionEndOffset(),
            indicator,
            allItems,
            hasModifiers);
        checkNotSync(indicator, allItems);
        return;
      }
    }

    CompletionServiceImpl.setCompletionPhase(new CompletionPhase.BgCalculation(indicator));
    indicator.showLookup();
  }