@TestOnly
 public static void cleanupForNextTest() {
   CompletionProgressIndicator currentCompletion =
       CompletionServiceImpl.getCompletionService().getCurrentCompletion();
   if (currentCompletion != null) {
     currentCompletion.finishCompletionProcess(true);
     CompletionServiceImpl.assertPhase(CompletionPhase.NoCompletion.getClass());
   } else {
     CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);
   }
   CompletionLookupArranger.cancelLastCompletionStatisticsUpdate();
 }
  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);
    }
  }
 public void addSparedChars(
     CompletionProgressIndicator indicator,
     LookupElement item,
     InsertionContext context,
     char completionChar) {
   String textInserted;
   if (context.getStartOffset() >= 0 && context.getTailOffset() >= context.getStartOffset()) {
     textInserted =
         context
             .getDocument()
             .getText()
             .substring(context.getStartOffset(), context.getTailOffset());
   } else {
     textInserted = item.getLookupString();
   }
   String withoutSpaces =
       StringUtil.replace(
           textInserted, new String[] {" ", "\t", "\n"}, new String[] {"", "", ""});
   int spared = withoutSpaces.length() - indicator.getLookup().itemPattern(item).length();
   if (!LookupEvent.isSpecialCompletionChar(completionChar)
       && withoutSpaces.contains(String.valueOf(completionChar))) {
     spared--;
   }
   if (spared > 0) {
     mySpared += spared;
   }
 }
  protected void lookupItemSelected(
      final CompletionProgressIndicator indicator,
      @NotNull final LookupElement item,
      final char completionChar,
      final List<LookupElement> items) {
    if (indicator.isAutopopupCompletion()) {
      FeatureUsageTracker.getInstance()
          .triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_BASIC);
    }

    CompletionAssertions.WatchingInsertionContext context = null;
    try {
      Lookup lookup = indicator.getLookup();
      CompletionLookupArranger.StatisticsUpdate update =
          CompletionLookupArranger.collectStatisticChanges(item, lookup);
      context = insertItemHonorBlockSelection(indicator, item, completionChar, items, update);
      CompletionLookupArranger.trackStatistics(context, update);
    } finally {
      afterItemInsertion(indicator, context == null ? null : context.getLaterRunnable());
    }
  }
  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 void addCompletionChar(
     Project project,
     CompletionAssertions.WatchingInsertionContext context,
     LookupElement item,
     Editor editor,
     CompletionProgressIndicator indicator,
     char completionChar) {
   int tailOffset = context.getTailOffset();
   if (tailOffset < 0) {
     LOG.info(
         "tailOffset<0 after inserting "
             + item
             + " of "
             + item.getClass()
             + "; invalidated at: "
             + context.invalidateTrace
             + "\n--------");
   } else {
     editor.getCaretModel().moveToOffset(tailOffset);
   }
   if (context.getCompletionChar() == Lookup.COMPLETE_STATEMENT_SELECT_CHAR) {
     final Language language = PsiUtilBase.getLanguageInEditor(editor, project);
     if (language != null) {
       for (SmartEnterProcessor processor : SmartEnterProcessors.INSTANCE.forKey(language)) {
         if (processor.processAfterCompletion(editor, indicator.getParameters().getOriginalFile()))
           break;
       }
     }
   } else if (!editor
       .getCaretModel()
       .supportsMultipleCarets()) { // this will be done outside of runForEach caret context
     DataContext dataContext =
         DataManager.getInstance().getDataContext(editor.getContentComponent());
     EditorActionManager.getInstance()
         .getTypedAction()
         .getHandler()
         .execute(editor, completionChar, dataContext);
   }
 }
 private static void afterItemInsertion(
     final CompletionProgressIndicator indicator, final Runnable laterRunnable) {
   if (laterRunnable != null) {
     final Runnable runnable1 =
         new Runnable() {
           @Override
           public void run() {
             if (!indicator.getProject().isDisposed()) {
               laterRunnable.run();
             }
             indicator.disposeIndicator();
           }
         };
     if (ApplicationManager.getApplication().isUnitTestMode()) {
       runnable1.run();
     } else {
       ApplicationManager.getApplication().invokeLater(runnable1);
     }
   } else {
     indicator.disposeIndicator();
   }
 }
  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;
  }
  private static CompletionAssertions.WatchingInsertionContext insertItemHonorBlockSelection(
      final CompletionProgressIndicator indicator,
      final LookupElement item,
      final char completionChar,
      final List<LookupElement> items,
      final CompletionLookupArranger.StatisticsUpdate update) {
    final Editor editor = indicator.getEditor();

    final int caretOffset = editor.getCaretModel().getOffset();
    int idEndOffset = indicator.getIdentifierEndOffset();
    if (idEndOffset < 0) {
      idEndOffset = CompletionInitializationContext.calcDefaultIdentifierEnd(editor, caretOffset);
    }
    final int idEndOffsetDelta = idEndOffset - caretOffset;

    CompletionAssertions.WatchingInsertionContext context = null;
    if (editor.getSelectionModel().hasBlockSelection()
        && editor.getSelectionModel().getBlockSelectionEnds().length > 0) {
      List<RangeMarker> insertionPoints = new ArrayList<RangeMarker>();
      int idDelta = 0;
      Document document = editor.getDocument();
      int caretLine = document.getLineNumber(editor.getCaretModel().getOffset());

      for (int point : editor.getSelectionModel().getBlockSelectionEnds()) {
        insertionPoints.add(document.createRangeMarker(point, point));
        if (document.getLineNumber(point) == document.getLineNumber(idEndOffset)) {
          idDelta = idEndOffset - point;
        }
      }

      List<RangeMarker> caretsAfter = new ArrayList<RangeMarker>();
      for (RangeMarker marker : insertionPoints) {
        if (marker.isValid()) {
          int insertionPoint = marker.getStartOffset();
          context =
              insertItem(
                  indicator,
                  item,
                  completionChar,
                  items,
                  update,
                  editor,
                  indicator.getParameters().getOriginalFile(),
                  insertionPoint,
                  idDelta + insertionPoint);
          int offset = editor.getCaretModel().getOffset();
          caretsAfter.add(document.createRangeMarker(offset, offset));
        }
      }
      assert context != null;

      restoreBlockSelection(editor, caretsAfter, caretLine);

      for (RangeMarker insertionPoint : insertionPoints) {
        insertionPoint.dispose();
      }
      for (RangeMarker marker : caretsAfter) {
        marker.dispose();
      }

    } else if (editor.getCaretModel().supportsMultipleCarets()) {
      final List<CompletionAssertions.WatchingInsertionContext> contexts =
          new ArrayList<CompletionAssertions.WatchingInsertionContext>();
      final Editor hostEditor = InjectedLanguageUtil.getTopLevelEditor(editor);
      hostEditor
          .getCaretModel()
          .runForEachCaret(
              new CaretAction() {
                @Override
                public void perform(Caret caret) {
                  PsiFile hostFile =
                      InjectedLanguageUtil.getTopLevelFile(
                          indicator.getParameters().getOriginalFile());
                  PsiFile targetFile =
                      InjectedLanguageUtil.findInjectedPsiNoCommit(hostFile, caret.getOffset());
                  Editor targetEditor =
                      InjectedLanguageUtil.getInjectedEditorForInjectedFile(hostEditor, targetFile);
                  int targetCaretOffset = targetEditor.getCaretModel().getOffset();
                  CompletionAssertions.WatchingInsertionContext currentContext =
                      insertItem(
                          indicator,
                          item,
                          completionChar,
                          items,
                          update,
                          targetEditor,
                          targetFile == null ? hostFile : targetFile,
                          targetCaretOffset,
                          targetCaretOffset + idEndOffsetDelta);
                  contexts.add(currentContext);
                }
              },
              true);
      context = contexts.get(contexts.size() - 1);
      if (context.shouldAddCompletionChar()
          && context.getCompletionChar() != Lookup.COMPLETE_STATEMENT_SELECT_CHAR) {
        ApplicationManager.getApplication()
            .runWriteAction(
                new Runnable() {
                  @Override
                  public void run() {
                    DataContext dataContext =
                        DataManager.getInstance().getDataContext(editor.getContentComponent());
                    EditorActionManager.getInstance()
                        .getTypedAction()
                        .getHandler()
                        .execute(editor, completionChar, dataContext);
                  }
                });
      }
      for (CompletionAssertions.WatchingInsertionContext insertionContext : contexts) {
        insertionContext.stopWatching();
      }
    } else {
      context =
          insertItem(
              indicator,
              item,
              completionChar,
              items,
              update,
              editor,
              indicator.getParameters().getOriginalFile(),
              caretOffset,
              idEndOffset);
    }
    return context;
  }
  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();
  }
  @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
  @Override
  public Result beforeCharTyped(
      final char charTyped, Project project, final Editor editor, PsiFile file, FileType fileType) {
    assert !inside;
    inside = true;
    try {
      final LookupImpl lookup = (LookupImpl) LookupManager.getActiveLookup(editor);
      if (lookup == null) {
        return Result.CONTINUE;
      }

      if (charTyped == ' '
          && ChooseItemReplaceAction.hasTemplatePrefix(lookup, TemplateSettings.SPACE_CHAR)) {
        return Result.CONTINUE;
      }

      final CharFilter.Result result = getLookupAction(charTyped, lookup);
      if (lookup.isLookupDisposed()) {
        return Result.CONTINUE;
      }

      if (!lookup.performGuardedChange(
          new Runnable() {
            @Override
            public void run() {
              EditorModificationUtil.deleteSelectedText(editor);
            }
          })) {
        return Result.STOP;
      }
      if (result == CharFilter.Result.ADD_TO_PREFIX) {
        Document document = editor.getDocument();
        long modificationStamp = document.getModificationStamp();

        if (!lookup.performGuardedChange(
            new Runnable() {
              @Override
              public void run() {
                EditorModificationUtil.typeInStringAtCaretHonorBlockSelection(
                    editor, String.valueOf(charTyped), true);
              }
            })) {
          return Result.STOP;
        }
        lookup.appendPrefix(charTyped);
        if (lookup.isStartCompletionWhenNothingMatches() && lookup.getItems().isEmpty()) {
          final CompletionProgressIndicator completion =
              CompletionServiceImpl.getCompletionService().getCurrentCompletion();
          if (completion != null) {
            completion.scheduleRestart();
          } else {
            AutoPopupController.getInstance(editor.getProject()).scheduleAutoPopup(editor, null);
          }
        }

        AutoHardWrapHandler.getInstance()
            .wrapLineIfNecessary(
                editor,
                DataManager.getInstance().getDataContext(editor.getContentComponent()),
                modificationStamp);

        final CompletionProgressIndicator completion =
            CompletionServiceImpl.getCompletionService().getCurrentCompletion();
        if (completion != null) {
          completion.prefixUpdated();
        }
        return Result.STOP;
      }

      if (result == CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP && lookup.isFocused()) {
        LookupElement item = lookup.getCurrentItem();
        if (item != null) {
          if (completeTillTypedCharOccurrence(charTyped, lookup, item)) {
            return Result.STOP;
          }

          inside = false;
          ((CommandProcessorEx) CommandProcessor.getInstance()).enterModal();
          try {
            finishLookup(charTyped, lookup);
          } finally {
            ((CommandProcessorEx) CommandProcessor.getInstance()).leaveModal();
          }
          return Result.STOP;
        }
      }

      lookup.hide();
      TypedHandler.autoPopupCompletion(editor, charTyped, project);
      return Result.CONTINUE;
    } finally {
      inside = false;
    }
  }
  private static CompletionAssertions.WatchingInsertionContext insertItemHonorBlockSelection(
      final CompletionProgressIndicator indicator,
      final LookupElement item,
      final char completionChar,
      final List<LookupElement> items,
      final CompletionLookupArranger.StatisticsUpdate update) {
    final Editor editor = indicator.getEditor();

    final int caretOffset = editor.getCaretModel().getOffset();
    int idEndOffset = indicator.getIdentifierEndOffset();
    if (idEndOffset < 0) {
      idEndOffset = CompletionInitializationContext.calcDefaultIdentifierEnd(editor, caretOffset);
    }
    final int idEndOffsetDelta = idEndOffset - caretOffset;

    CompletionAssertions.WatchingInsertionContext context = null;
    if (editor.getSelectionModel().hasBlockSelection()
        && editor.getSelectionModel().getBlockSelectionEnds().length > 0) {
      List<RangeMarker> insertionPoints = new ArrayList<RangeMarker>();
      int idDelta = 0;
      Document document = editor.getDocument();
      int caretLine = document.getLineNumber(editor.getCaretModel().getOffset());

      for (int point : editor.getSelectionModel().getBlockSelectionEnds()) {
        insertionPoints.add(document.createRangeMarker(point, point));
        if (document.getLineNumber(point) == document.getLineNumber(idEndOffset)) {
          idDelta = idEndOffset - point;
        }
      }

      List<RangeMarker> caretsAfter = new ArrayList<RangeMarker>();
      for (RangeMarker marker : insertionPoints) {
        if (marker.isValid()) {
          int insertionPoint = marker.getStartOffset();
          context =
              insertItem(
                  indicator,
                  item,
                  completionChar,
                  items,
                  update,
                  editor,
                  insertionPoint,
                  idDelta + insertionPoint);
          int offset = editor.getCaretModel().getOffset();
          caretsAfter.add(document.createRangeMarker(offset, offset));
        }
      }
      assert context != null;

      restoreBlockSelection(editor, caretsAfter, caretLine);

      for (RangeMarker insertionPoint : insertionPoints) {
        insertionPoint.dispose();
      }
      for (RangeMarker marker : caretsAfter) {
        marker.dispose();
      }

    } else {
      final Ref<CompletionAssertions.WatchingInsertionContext> contextRef =
          new Ref<CompletionAssertions.WatchingInsertionContext>();
      editor
          .getCaretModel()
          .runForEachCaret(
              new CaretAction() {
                @Override
                public void perform(Caret caret) {
                  CompletionAssertions.WatchingInsertionContext currentContext =
                      insertItem(
                          indicator,
                          item,
                          completionChar,
                          items,
                          update,
                          editor,
                          caret.getOffset(),
                          caret.getOffset() + idEndOffsetDelta);
                  if (caret
                      .getVisualPosition()
                      .equals(editor.getCaretModel().getPrimaryCaret().getVisualPosition())) {
                    contextRef.set(currentContext);
                  }
                }
              });
      context = contextRef.get();
    }
    return context;
  }
 @NotNull
 private CompletionSorterImpl obtainSorter(LookupElement element) {
   return myProcess.getSorter(element);
 }
  private static CompletionAssertions.WatchingInsertionContext insertItemHonorBlockSelection(
      CompletionProgressIndicator indicator,
      LookupElement item,
      char completionChar,
      List<LookupElement> items,
      CompletionLookupArranger.StatisticsUpdate update) {
    final Editor editor = indicator.getEditor();

    final int caretOffset = editor.getCaretModel().getOffset();
    int idEndOffset = indicator.getIdentifierEndOffset();
    if (idEndOffset < 0) {
      idEndOffset = CompletionInitializationContext.calcDefaultIdentifierEnd(editor, caretOffset);
    }

    CompletionAssertions.WatchingInsertionContext context = null;
    if (editor.getSelectionModel().hasBlockSelection()
        && editor.getSelectionModel().getBlockSelectionEnds().length > 0) {
      List<RangeMarker> insertionPoints = new ArrayList<RangeMarker>();
      int idDelta = 0;
      Document document = editor.getDocument();
      int caretLine = document.getLineNumber(editor.getCaretModel().getOffset());

      for (int point : editor.getSelectionModel().getBlockSelectionEnds()) {
        insertionPoints.add(document.createRangeMarker(point, point));
        if (document.getLineNumber(point) == document.getLineNumber(idEndOffset)) {
          idDelta = idEndOffset - point;
        }
      }

      List<RangeMarker> caretsAfter = new ArrayList<RangeMarker>();
      for (RangeMarker marker : insertionPoints) {
        if (marker.isValid()) {
          int insertionPoint = marker.getStartOffset();
          context =
              insertItem(
                  indicator,
                  item,
                  completionChar,
                  items,
                  update,
                  editor,
                  insertionPoint,
                  idDelta + insertionPoint);
          int offset = editor.getCaretModel().getOffset();
          caretsAfter.add(document.createRangeMarker(offset, offset));
        }
      }
      assert context != null;

      restoreBlockSelection(editor, caretsAfter, caretLine);

      for (RangeMarker insertionPoint : insertionPoints) {
        insertionPoint.dispose();
      }
      for (RangeMarker marker : caretsAfter) {
        marker.dispose();
      }

    } else {
      context =
          insertItem(
              indicator, item, completionChar, items, update, editor, caretOffset, idEndOffset);
    }
    return context;
  }