private static CompletionContext createCompletionContext(
      PsiFile hostCopy, int hostStartOffset, OffsetMap hostMap, PsiFile originalFile) {
    CompletionAssertions.assertHostInfo(hostCopy, hostMap);

    InjectedLanguageManager injectedLanguageManager =
        InjectedLanguageManager.getInstance(hostCopy.getProject());
    CompletionContext context;
    PsiFile injected = InjectedLanguageUtil.findInjectedPsiNoCommit(hostCopy, hostStartOffset);
    if (injected != null) {
      if (injected instanceof PsiFileImpl) {
        ((PsiFileImpl) injected).setOriginalFile(originalFile);
      }
      DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(injected);
      CompletionAssertions.assertInjectedOffsets(
          hostStartOffset, injectedLanguageManager, injected, documentWindow);

      context =
          new CompletionContext(injected, translateOffsetMapToInjected(hostMap, documentWindow));
    } else {
      context = new CompletionContext(hostCopy, hostMap);
    }

    CompletionAssertions.assertFinalOffsets(originalFile, context, injected);

    return context;
  }
 public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
   final int offset = editor.getCaretModel().getOffset();
   final PsiFile psiFile = InjectedLanguageUtil.findInjectedPsiNoCommit(file, offset);
   if (psiFile == null) return false;
   final LanguageInjectionSupport support =
       psiFile.getUserData(LanguageInjectionSupport.INJECTOR_SUPPORT);
   return support != null;
 }
 private static void invokeImpl(Project project, Editor editor, PsiFile file) {
   final PsiFile psiFile =
       InjectedLanguageUtil.findInjectedPsiNoCommit(file, editor.getCaretModel().getOffset());
   if (psiFile == null) return;
   final PsiLanguageInjectionHost host =
       InjectedLanguageManager.getInstance(project).getInjectionHost(psiFile);
   if (host == null) return;
   final LanguageInjectionSupport support =
       psiFile.getUserData(LanguageInjectionSupport.INJECTOR_SUPPORT);
   if (support == null) return;
   try {
     if (!support.removeInjectionInPlace(host)) {
       defaultFunctionalityWorked(host);
     }
   } finally {
     FileContentUtil.reparseFiles(project, Collections.<VirtualFile>emptyList(), true);
   }
 }
  @Nullable
  public static Pair<PsiFile, Editor> chooseBetweenHostAndInjected(
      PsiFile hostFile, Editor hostEditor, PairProcessor<PsiFile, Editor> predicate) {
    Editor editorToApply = null;
    PsiFile fileToApply = null;

    int offset = hostEditor.getCaretModel().getOffset();
    PsiFile injectedFile = InjectedLanguageUtil.findInjectedPsiNoCommit(hostFile, offset);
    if (injectedFile != null) {
      Editor injectedEditor =
          InjectedLanguageUtil.getInjectedEditorForInjectedFile(hostEditor, injectedFile);
      if (predicate.process(injectedFile, injectedEditor)) {
        editorToApply = injectedEditor;
        fileToApply = injectedFile;
      }
    }

    if (editorToApply == null && predicate.process(hostFile, hostEditor)) {
      editorToApply = hostEditor;
      fileToApply = hostFile;
    }
    if (editorToApply == null) return null;
    return Pair.create(fileToApply, editorToApply);
  }
  private static TextRange preprocess(@NotNull final ASTNode node, @NotNull TextRange range) {
    TextRange result = range;
    PsiElement psi = node.getPsi();
    if (!psi.isValid()) {
      for (PreFormatProcessor processor : Extensions.getExtensions(PreFormatProcessor.EP_NAME)) {
        result = processor.process(node, result);
      }
      return result;
    }

    PsiFile file = psi.getContainingFile();

    // We use a set here because we encountered a situation when more than one PSI leaf points to
    // the same injected fragment
    // (at least for sql injected into sql).
    final LinkedHashSet<TextRange> injectedFileRangesSet = ContainerUtilRt.newLinkedHashSet();

    if (!psi.getProject().isDefault()) {
      List<DocumentWindow> injectedDocuments =
          InjectedLanguageUtil.getCachedInjectedDocuments(file);
      if (!injectedDocuments.isEmpty()) {
        for (DocumentWindow injectedDocument : injectedDocuments) {
          injectedFileRangesSet.add(
              TextRange.from(injectedDocument.injectedToHost(0), injectedDocument.getTextLength()));
        }
      } else {
        Collection<PsiLanguageInjectionHost> injectionHosts = collectInjectionHosts(file, range);
        PsiLanguageInjectionHost.InjectedPsiVisitor visitor =
            new PsiLanguageInjectionHost.InjectedPsiVisitor() {
              @Override
              public void visit(
                  @NotNull PsiFile injectedPsi,
                  @NotNull List<PsiLanguageInjectionHost.Shred> places) {
                for (PsiLanguageInjectionHost.Shred place : places) {
                  Segment rangeMarker = place.getHostRangeMarker();
                  injectedFileRangesSet.add(
                      TextRange.create(rangeMarker.getStartOffset(), rangeMarker.getEndOffset()));
                }
              }
            };
        for (PsiLanguageInjectionHost host : injectionHosts) {
          InjectedLanguageUtil.enumerate(host, visitor);
        }
      }
    }

    if (!injectedFileRangesSet.isEmpty()) {
      List<TextRange> ranges = ContainerUtilRt.newArrayList(injectedFileRangesSet);
      Collections.reverse(ranges);
      for (TextRange injectedFileRange : ranges) {
        int startHostOffset = injectedFileRange.getStartOffset();
        int endHostOffset = injectedFileRange.getEndOffset();
        if (startHostOffset >= range.getStartOffset() && endHostOffset <= range.getEndOffset()) {
          PsiFile injected = InjectedLanguageUtil.findInjectedPsiNoCommit(file, startHostOffset);
          if (injected != null) {
            int startInjectedOffset =
                range.getStartOffset() > startHostOffset
                    ? startHostOffset - range.getStartOffset()
                    : 0;
            int endInjectedOffset = injected.getTextLength();
            if (range.getEndOffset() < endHostOffset) {
              endInjectedOffset -= endHostOffset - range.getEndOffset();
            }
            final TextRange initialInjectedRange =
                TextRange.create(startInjectedOffset, endInjectedOffset);
            TextRange injectedRange = initialInjectedRange;
            for (PreFormatProcessor processor :
                Extensions.getExtensions(PreFormatProcessor.EP_NAME)) {
              injectedRange = processor.process(injected.getNode(), injectedRange);
            }

            // Allow only range expansion (not reduction) for injected context.
            if ((initialInjectedRange.getStartOffset() > injectedRange.getStartOffset()
                    && initialInjectedRange.getStartOffset() > 0)
                || (initialInjectedRange.getEndOffset() < injectedRange.getEndOffset()
                    && initialInjectedRange.getEndOffset() < injected.getTextLength())) {
              range =
                  TextRange.create(
                      range.getStartOffset()
                          + injectedRange.getStartOffset()
                          - initialInjectedRange.getStartOffset(),
                      range.getEndOffset()
                          + initialInjectedRange.getEndOffset()
                          - injectedRange.getEndOffset());
            }
          }
        }
      }
    }

    for (PreFormatProcessor processor : Extensions.getExtensions(PreFormatProcessor.EP_NAME)) {
      result = processor.process(node, result);
    }

    return result;
  }