@Nullable("null means the file is clean")
  public static TextRange getDirtyTextRange(@NotNull Editor editor, int passId) {
    Document document = editor.getDocument();

    FileStatusMap me = DaemonCodeAnalyzerEx.getInstanceEx(editor.getProject()).getFileStatusMap();
    TextRange dirtyScope = me.getFileDirtyScope(document, passId);
    if (dirtyScope == null) return null;
    TextRange documentRange = TextRange.from(0, document.getTextLength());
    return documentRange.intersection(dirtyScope);
  }
 private boolean isWhiteSpaceOrComment(@NotNull PsiElement element, @NotNull TextRange range) {
   final TextRange textRange = element.getTextRange();
   TextRange intersection = range.intersection(textRange);
   if (intersection == null) {
     return false;
   }
   intersection =
       TextRange.create(
           Math.max(intersection.getStartOffset() - textRange.getStartOffset(), 0),
           Math.min(
               intersection.getEndOffset() - textRange.getStartOffset(), textRange.getLength()));
   return isWhiteSpaceOrComment(element)
       || intersection.substring(element.getText()).trim().length() == 0;
 }
 /**
  * intersection may spread over several injected fragments
  *
  * @param rangeToEdit range in encoded(raw) PSI
  * @return list of ranges in encoded (raw) PSI
  */
 @Override
 @SuppressWarnings({"ConstantConditions", "unchecked"})
 @NotNull
 public List<TextRange> intersectWithAllEditableFragments(
     @NotNull PsiFile injectedPsi, @NotNull TextRange rangeToEdit) {
   Place shreds = InjectedLanguageUtil.getShreds(injectedPsi);
   if (shreds == null) return Collections.emptyList();
   Object result = null; // optimization: TextRange or ArrayList
   int count = 0;
   int offset = 0;
   for (PsiLanguageInjectionHost.Shred shred : shreds) {
     TextRange encodedRange =
         TextRange.from(
             offset + shred.getPrefix().length(), shred.getRangeInsideHost().getLength());
     TextRange intersection = encodedRange.intersection(rangeToEdit);
     if (intersection != null) {
       count++;
       if (count == 1) {
         result = intersection;
       } else if (count == 2) {
         TextRange range = (TextRange) result;
         if (range.isEmpty()) {
           result = intersection;
           count = 1;
         } else if (intersection.isEmpty()) {
           count = 1;
         } else {
           List<TextRange> list = new ArrayList<TextRange>();
           list.add(range);
           list.add(intersection);
           result = list;
         }
       } else if (intersection.isEmpty()) {
         count--;
       } else {
         ((List<TextRange>) result).add(intersection);
       }
     }
     offset +=
         shred.getPrefix().length()
             + shred.getRangeInsideHost().getLength()
             + shred.getSuffix().length();
   }
   return count == 0
       ? Collections.<TextRange>emptyList()
       : count == 1 ? Collections.singletonList((TextRange) result) : (List<TextRange>) result;
 }
 @NotNull
 private static RangeMarker combineScopes(
     RangeMarker old, @NotNull TextRange scope, int textLength, @NotNull Document document) {
   if (old == null) {
     if (scope.equalsToRange(0, textLength)) return WHOLE_FILE_DIRTY_MARKER;
     return document.createRangeMarker(scope);
   }
   if (old == WHOLE_FILE_DIRTY_MARKER) return old;
   TextRange oldRange = TextRange.create(old);
   TextRange union = scope.union(oldRange);
   if (old.isValid() && union.equals(oldRange)) {
     return old;
   }
   if (union.getEndOffset() > textLength) {
     union = union.intersection(new TextRange(0, textLength));
   }
   assert union != null;
   return document.createRangeMarker(union);
 }
    private String setup(
        String text,
        Function<String, String> escapeFunction,
        int highlightStartOffset,
        int highlightEndOffset,
        boolean isDisabled,
        boolean strikeout,
        boolean isDisabledBeforeHighlight,
        Color background) {
      StringBuilder buf = new StringBuilder();
      removeAll();

      String[] lines = UIUtil.splitText(text, getFontMetrics(BOLD_FONT), myWidthLimit, ',');

      myOneLineComponents = new OneLineComponent[lines.length];

      int lineOffset = 0;

      boolean hasHighlighting =
          highlightStartOffset >= 0 && highlightEndOffset > highlightStartOffset;
      TextRange highlightingRange =
          hasHighlighting ? new TextRange(highlightStartOffset, highlightEndOffset) : null;

      for (int i = 0; i < lines.length; i++) {
        String line = lines[i];

        myOneLineComponents[i] = new OneLineComponent();

        TextRange lRange = new TextRange(lineOffset, lineOffset + line.length());
        TextRange hr = highlightingRange == null ? null : lRange.intersection(highlightingRange);
        hr = hr == null ? null : hr.shiftRight(-lineOffset);

        String before =
            escapeString(
                hr == null ? line : line.substring(0, hr.getStartOffset()), escapeFunction);
        String in = hr == null ? "" : escapeString(hr.substring(line), escapeFunction);
        String after =
            hr == null
                ? ""
                : escapeString(line.substring(hr.getEndOffset(), line.length()), escapeFunction);

        TextRange escapedHighlightingRange =
            in.isEmpty() ? null : TextRange.create(before.length(), before.length() + in.length());
        buf.append(
            myOneLineComponents[i].setup(
                before + in + after, isDisabled, strikeout, background, escapedHighlightingRange));

        if (isDisabledBeforeHighlight) {
          if (highlightStartOffset < 0 || highlightEndOffset > lineOffset) {
            myOneLineComponents[i].setDisabledBeforeHighlight();
          }
        }

        add(
            myOneLineComponents[i],
            new GridBagConstraints(
                0,
                i,
                1,
                1,
                1,
                0,
                GridBagConstraints.WEST,
                GridBagConstraints.HORIZONTAL,
                new Insets(0, 0, 0, 0),
                0,
                0));

        lineOffset += line.length();
      }
      return buf.toString();
    }