@Override
 @NotNull
 public RangeMarker createRangeMarker(final int startOffset, final int endOffset) {
   ProperTextRange hostRange = injectedToHost(new ProperTextRange(startOffset, endOffset));
   RangeMarker hostMarker = myDelegate.createRangeMarker(hostRange);
   int startShift = Math.max(0, hostToInjected(hostRange.getStartOffset()) - startOffset);
   int endShift = Math.max(0, endOffset - hostToInjected(hostRange.getEndOffset()) - startShift);
   return new RangeMarkerWindow(this, (RangeMarkerEx) hostMarker, startShift, endShift);
 }
 private void commitToOriginalInner() {
   final String text = myNewDocument.getText();
   final Map<
           PsiLanguageInjectionHost,
           Set<Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer>>>
       map =
           ContainerUtil.classify(
               myMarkers.iterator(),
               new Convertor<
                   Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer>,
                   PsiLanguageInjectionHost>() {
                 @Override
                 public PsiLanguageInjectionHost convert(
                     final Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer> o) {
                   final PsiElement element = o.third.getElement();
                   return (PsiLanguageInjectionHost) element;
                 }
               });
   PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
   documentManager.commitDocument(myOrigDocument); // commit here and after each manipulator update
   int localInsideFileCursor = 0;
   for (PsiLanguageInjectionHost host : map.keySet()) {
     if (host == null) continue;
     String hostText = host.getText();
     ProperTextRange insideHost = null;
     StringBuilder sb = new StringBuilder();
     for (Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer> entry : map.get(host)) {
       RangeMarker origMarker = entry.first; // check for validity?
       int hostOffset = host.getTextRange().getStartOffset();
       ProperTextRange localInsideHost =
           new ProperTextRange(
               origMarker.getStartOffset() - hostOffset, origMarker.getEndOffset() - hostOffset);
       RangeMarker rangeMarker = entry.second;
       ProperTextRange localInsideFile =
           new ProperTextRange(
               Math.max(localInsideFileCursor, rangeMarker.getStartOffset()),
               rangeMarker.getEndOffset());
       if (insideHost != null) {
         // append unchanged inter-markers fragment
         sb.append(
             hostText.substring(insideHost.getEndOffset(), localInsideHost.getStartOffset()));
       }
       sb.append(
           localInsideFile.getEndOffset() <= text.length() && !localInsideFile.isEmpty()
               ? localInsideFile.substring(text)
               : "");
       localInsideFileCursor = localInsideFile.getEndOffset();
       insideHost = insideHost == null ? localInsideHost : insideHost.union(localInsideHost);
     }
     assert insideHost != null;
     ElementManipulators.getManipulator(host).handleContentChange(host, insideHost, sb.toString());
     documentManager.commitDocument(myOrigDocument);
   }
 }
  private static void highlightTodos(
      @NotNull PsiFile file,
      @NotNull CharSequence text,
      int startOffset,
      int endOffset,
      @NotNull ProgressIndicator progress,
      @NotNull ProperTextRange priorityRange,
      @NotNull Collection<HighlightInfo> result,
      @NotNull Collection<HighlightInfo> outsideResult) {
    PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(file.getProject());
    TodoItem[] todoItems = helper.findTodoItems(file, startOffset, endOffset);
    if (todoItems.length == 0) return;

    for (TodoItem todoItem : todoItems) {
      progress.checkCanceled();
      TextRange range = todoItem.getTextRange();
      String description =
          text.subSequence(range.getStartOffset(), range.getEndOffset()).toString();
      TextAttributes attributes = todoItem.getPattern().getAttributes().getTextAttributes();
      HighlightInfo info =
          HighlightInfo.createHighlightInfo(
              HighlightInfoType.TODO, range, description, description, attributes);
      assert info != null;
      if (priorityRange.containsRange(info.getStartOffset(), info.getEndOffset())) {
        result.add(info);
      } else {
        outsideResult.add(info);
      }
    }
  }
 @Override
 @NotNull
 public RangeMarker createRangeMarker(
     final int startOffset, final int endOffset, final boolean surviveOnExternalChange) {
   if (!surviveOnExternalChange) {
     return createRangeMarker(startOffset, endOffset);
   }
   ProperTextRange hostRange = injectedToHost(new ProperTextRange(startOffset, endOffset));
   // todo persistent?
   RangeMarker hostMarker =
       myDelegate.createRangeMarker(
           hostRange.getStartOffset(), hostRange.getEndOffset(), surviveOnExternalChange);
   int startShift = Math.max(0, hostToInjected(hostRange.getStartOffset()) - startOffset);
   int endShift = Math.max(0, endOffset - hostToInjected(hostRange.getEndOffset()) - startShift);
   return new RangeMarkerWindow(this, (RangeMarkerEx) hostMarker, startShift, endShift);
 }
  public static void renameNonCodeUsages(
      @NotNull Project project, @NotNull NonCodeUsageInfo[] usages) {
    PsiDocumentManager.getInstance(project).commitAllDocuments();
    Map<Document, List<UsageOffset>> docsToOffsetsMap = new HashMap<Document, List<UsageOffset>>();
    final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
    for (NonCodeUsageInfo usage : usages) {
      PsiElement element = usage.getElement();

      if (element == null) continue;
      element = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(element, true);
      if (element == null) continue;

      final ProperTextRange rangeInElement = usage.getRangeInElement();
      if (rangeInElement == null) continue;

      final PsiFile containingFile = element.getContainingFile();
      final Document document = psiDocumentManager.getDocument(containingFile);

      final Segment segment = usage.getSegment();
      LOG.assertTrue(segment != null);
      int fileOffset = segment.getStartOffset();

      List<UsageOffset> list = docsToOffsetsMap.get(document);
      if (list == null) {
        list = new ArrayList<UsageOffset>();
        docsToOffsetsMap.put(document, list);
      }

      list.add(new UsageOffset(fileOffset, fileOffset + rangeInElement.getLength(), usage.newText));
    }

    for (Document document : docsToOffsetsMap.keySet()) {
      List<UsageOffset> list = docsToOffsetsMap.get(document);
      LOG.assertTrue(list != null, document);
      UsageOffset[] offsets = list.toArray(new UsageOffset[list.size()]);
      Arrays.sort(offsets);

      for (int i = offsets.length - 1; i >= 0; i--) {
        UsageOffset usageOffset = offsets[i];
        document.replaceString(usageOffset.startOffset, usageOffset.endOffset, usageOffset.newText);
      }
      PsiDocumentManager.getInstance(project).commitDocument(document);
    }
    PsiDocumentManager.getInstance(project).commitAllDocuments();
  }
 AnchorElementInfo(@NotNull PsiElement anchor, @NotNull PsiFile containingFile) {
   super(
       containingFile.getProject(),
       ProperTextRange.create(anchor.getTextRange()),
       anchor.getClass(),
       containingFile,
       LanguageUtil.getRootLanguage(anchor));
   assert !(anchor instanceof PsiFile) : "FileElementInfo must be used for file: " + anchor;
   myStubElementTypeAndId = pack(-1, null);
 }
 // finds the first nearest text range
 @Nullable("null means invalid")
 private static TextRange findNearestTextRange(
     final DocumentWindow documentWindow, final int startOffset) {
   TextRange textRange = null;
   for (Segment marker : documentWindow.getHostRanges()) {
     TextRange curRange = ProperTextRange.create(marker);
     if (curRange.getStartOffset() > startOffset && textRange != null) break;
     textRange = curRange;
   }
   return textRange;
 }
 // finds the first nearest text range
 private static TextRange findNearestTextRange(
     final DocumentWindow documentWindow, final int startOffset) {
   TextRange textRange = null;
   for (RangeMarker marker : documentWindow.getHostRanges()) {
     TextRange curRange = ProperTextRange.create(marker);
     if (curRange.getStartOffset() > startOffset && textRange != null) break;
     textRange = curRange;
   }
   assert textRange != null;
   return textRange;
 }
 @Override
 public TextRange getHostRange(int hostOffset) {
   synchronized (myLock) {
     for (PsiLanguageInjectionHost.Shred shred : myShreds) {
       Segment currentRange = shred.getHostRangeMarker();
       if (currentRange == null) continue;
       TextRange textRange = ProperTextRange.create(currentRange);
       if (textRange.grown(1).contains(hostOffset)) return textRange;
     }
   }
   return null;
 }
 @Override
 @NotNull
 public TextRange injectedToHost(
     @NotNull PsiElement injectedContext, @NotNull TextRange injectedTextRange) {
   ProperTextRange.assertProperRange(injectedTextRange);
   PsiFile file = injectedContext.getContainingFile();
   if (file == null) return injectedTextRange;
   Document document = PsiDocumentManager.getInstance(file.getProject()).getCachedDocument(file);
   if (!(document instanceof DocumentWindowImpl)) return injectedTextRange;
   DocumentWindowImpl documentWindow = (DocumentWindowImpl) document;
   return documentWindow.injectedToHost(injectedTextRange);
 }
 @Override
 public boolean containsRange(int start, int end) {
   synchronized (myLock) {
     ProperTextRange query = new ProperTextRange(start, end);
     for (PsiLanguageInjectionHost.Shred shred : myShreds) {
       Segment hostRange = shred.getHostRangeMarker();
       if (hostRange == null) continue;
       TextRange textRange = ProperTextRange.create(hostRange);
       if (textRange.contains(query)) return true;
     }
     return false;
   }
 }
 @Override
 @NotNull
 public RangeMarker createRangeMarker(@NotNull final TextRange textRange) {
   final ProperTextRange properTextRange = new ProperTextRange(textRange);
   return createRangeMarker(properTextRange.getStartOffset(), properTextRange.getEndOffset());
 }
  @Override
  public RangeMarker getRangeGuard(final int startOffset, final int endOffset) {
    ProperTextRange hostRange = injectedToHost(new ProperTextRange(startOffset, endOffset));

    return myDelegate.getRangeGuard(hostRange.getStartOffset(), hostRange.getEndOffset());
  }
 @Override
 @NotNull
 public RangeMarker createGuardedBlock(final int startOffset, final int endOffset) {
   ProperTextRange hostRange = injectedToHost(new ProperTextRange(startOffset, endOffset));
   return myDelegate.createGuardedBlock(hostRange.getStartOffset(), hostRange.getEndOffset());
 }