@Override
  public void handleInsert(InsertionContext context) {
    PsiVariable variable = getObject();

    Document document = context.getDocument();
    document.replaceString(context.getStartOffset(), context.getTailOffset(), variable.getName());
    context.commitDocument();

    if (variable instanceof PsiField) {
      if (willBeImported()) {
        RangeMarker toDelete =
            JavaCompletionUtil.insertTemporary(context.getTailOffset(), document, " ");
        context.commitDocument();
        final PsiReferenceExpression ref =
            PsiTreeUtil.findElementOfClassAtOffset(
                context.getFile(), context.getStartOffset(), PsiReferenceExpression.class, false);
        if (ref != null) {
          ref.bindToElementViaStaticImport(((PsiField) variable).getContainingClass());
          PostprocessReformattingAspect.getInstance(ref.getProject()).doPostponedFormatting();
        }
        if (toDelete.isValid()) {
          document.deleteString(toDelete.getStartOffset(), toDelete.getEndOffset());
        }
        context.commitDocument();
      } else if (shouldQualify((PsiField) variable, context)) {
        qualifyFieldReference(context, (PsiField) variable);
      }
    }

    PsiReferenceExpression ref =
        PsiTreeUtil.findElementOfClassAtOffset(
            context.getFile(), context.getTailOffset() - 1, PsiReferenceExpression.class, false);
    if (ref != null) {
      JavaCodeStyleManager.getInstance(context.getProject()).shortenClassReferences(ref);
    }

    ref =
        PsiTreeUtil.findElementOfClassAtOffset(
            context.getFile(), context.getTailOffset() - 1, PsiReferenceExpression.class, false);
    makeVariableFinalIfNeeded(context, ref);

    final char completionChar = context.getCompletionChar();
    if (completionChar == '=') {
      context.setAddCompletionChar(false);
      TailType.EQ.processTail(context.getEditor(), context.getTailOffset());
    } else if (completionChar == ','
        && getAttribute(LookupItem.TAIL_TYPE_ATTR) != TailType.UNKNOWN) {
      context.setAddCompletionChar(false);
      TailType.COMMA.processTail(context.getEditor(), context.getTailOffset());
      AutoPopupController.getInstance(context.getProject())
          .autoPopupParameterInfo(context.getEditor(), null);
    } else if (completionChar == ':') {
      context.setAddCompletionChar(false);
      TailType.COND_EXPR_COLON.processTail(context.getEditor(), context.getTailOffset());
    } else if (completionChar == '.') {
      AutoPopupController.getInstance(context.getProject())
          .autoPopupMemberLookup(context.getEditor(), null);
    } else if (completionChar == '!' && PsiType.BOOLEAN.isAssignableFrom(variable.getType())) {
      context.setAddCompletionChar(false);
      if (ref != null) {
        FeatureUsageTracker.getInstance()
            .triggerFeatureUsed(CodeCompletionFeatures.EXCLAMATION_FINISH);
        document.insertString(ref.getTextRange().getStartOffset(), "!");
      }
    }
  }
  @Override
  public Result acceptChar(char c, final int prefixLength, final Lookup lookup) {
    if (!lookup.getPsiFile().getLanguage().isKindOf(JavaLanguage.INSTANCE)) {
      return null;
    }

    LookupElement item = lookup.getCurrentItem();
    if (item == null) return null;

    final Object o = item.getObject();
    if (c == '!') {
      if (o instanceof PsiVariable) {
        if (PsiType.BOOLEAN.isAssignableFrom(((PsiVariable) o).getType()))
          return Result.SELECT_ITEM_AND_FINISH_LOOKUP;
      }
      if (o instanceof PsiMethod) {
        final PsiType type = ((PsiMethod) o).getReturnType();
        if (type != null && PsiType.BOOLEAN.isAssignableFrom(type))
          return Result.SELECT_ITEM_AND_FINISH_LOOKUP;
      }
      if (o instanceof PsiKeyword && ((PsiKeyword) o).textMatches(PsiKeyword.INSTANCEOF)) {
        return Result.SELECT_ITEM_AND_FINISH_LOOKUP;
      }

      return null;
    }
    if (c == '.' && isWithinLiteral(lookup)) return Result.ADD_TO_PREFIX;

    if (c == ':') {
      PsiFile file = lookup.getPsiFile();
      PsiDocumentManager.getInstance(file.getProject())
          .commitDocument(lookup.getEditor().getDocument());
      PsiElement leaf = file.findElementAt(lookup.getEditor().getCaretModel().getOffset() - 1);
      if (PsiUtil.getLanguageLevel(file).isAtLeast(LanguageLevel.JDK_1_8)) {
        PsiStatement statement = PsiTreeUtil.getParentOfType(leaf, PsiStatement.class);
        if (statement == null
            || statement.getTextRange().getStartOffset()
                != leaf.getTextRange().getStartOffset()) { // not typing a statement label
          return Result.SELECT_ITEM_AND_FINISH_LOOKUP;
        }
      }
      if (PsiTreeUtil.getParentOfType(leaf, PsiSwitchLabelStatement.class) != null
          || PsiTreeUtil.getParentOfType(leaf, PsiConditionalExpression.class) != null) {
        return Result.SELECT_ITEM_AND_FINISH_LOOKUP;
      }
      return Result.HIDE_LOOKUP;
    }

    if (c == '[' || c == ']' || c == ')' || c == '>')
      return CharFilter.Result.SELECT_ITEM_AND_FINISH_LOOKUP;
    if (c == '<' && o instanceof PsiClass) return Result.SELECT_ITEM_AND_FINISH_LOOKUP;
    if (c == '(') {
      if (o instanceof PsiClass) {
        if (PsiJavaPatterns.psiElement()
            .afterLeaf(PsiKeyword.NEW)
            .accepts(lookup.getPsiElement())) {
          return Result.SELECT_ITEM_AND_FINISH_LOOKUP;
        }
        return Result.HIDE_LOOKUP;
      }
      if (o instanceof PsiType) {
        return Result.HIDE_LOOKUP;
      }
    }
    if ((c == ',' || c == '=') && o instanceof PsiVariable) {
      int lookupStart = lookup.getLookupStart();
      String name = ((PsiVariable) o).getName();
      if (lookupStart >= 0 && name != null && name.equals(lookup.itemPattern(item))) {
        return Result.HIDE_LOOKUP;
      }
    }

    if (c == '#'
        && PsiTreeUtil.getParentOfType(lookup.getPsiElement(), PsiDocComment.class) != null) {
      if (o instanceof PsiClass) {
        return Result.SELECT_ITEM_AND_FINISH_LOOKUP;
      }
    }
    if (c == '(' && PsiKeyword.RETURN.equals(item.getLookupString())) {
      return Result.HIDE_LOOKUP;
    }
    return null;
  }