@Override
  public String preprocessOnCopy(final PsiFile file, final int[] startOffsets, final int[] endOffsets, final String text) {
    if (!isSupportedFile(file)) {
      return null;
    }

    // The main idea is to un-escape string/char literals content if necessary.
    // Example:
    //    Suppose we have a following text at the editor: String s = "first <selection>line \n second</selection> line"
    //    When user copies the selection we want to transform text \n to the real line feed, i.e. clipboard should contains the following:
    //        line 
    //        second
    //
    // However, we don't want to un-escape literal content if it's copied completely.
    // Example:
    //     String s = <selection>"my string"</selection>;

    StringBuilder buffer = new StringBuilder();
    int givenTextOffset = 0;
    boolean textWasChanged = false;
    int deducedBlockSelectionWidth = deduceBlockSelectionWidth(startOffsets, endOffsets, text);
    for (int i = 0; i < startOffsets.length && givenTextOffset < text.length(); i++, givenTextOffset++) {
      if (i > 0) {
        buffer.append('\n'); // LF is added for block selection
      }
      // Calculate offsets offsets of the selection interval being processed now.
      final int fileStartOffset = startOffsets[i];
      final int fileEndOffset = endOffsets[i];
      int givenTextStartOffset = givenTextOffset;
      final int givenTextEndOffset = givenTextOffset + (fileEndOffset - fileStartOffset);
      givenTextOffset = givenTextEndOffset;
      if (givenTextOffset > text.length()) {
        // This can happen e.g. line terminators were normalized in copied text, and it became shorter
        // than corresponding fragment in the original document.
        // We don't implement escaping/unescaping logic for documents with non-normalized line terminators currently.
        return null;
      }
      String fragment = text.substring(givenTextStartOffset, givenTextEndOffset);
      PsiElement element = file.findElementAt(fileStartOffset);
      TextRange escapedRange = element == null ? null : getEscapedRange(element);
      if (escapedRange == null || escapedRange.getStartOffset() > fileStartOffset || escapedRange.getEndOffset() < fileEndOffset) {
        buffer.append(fragment);
      }
      else {
        String unescaped = unescape(fragment, element);
        if (unescaped != null) {
          textWasChanged = true;
          buffer.append(unescaped);
        }
        else {
          buffer.append(fragment);
        }
      }
      int blockSelectionPadding = deducedBlockSelectionWidth - (fileEndOffset - fileStartOffset);
      for (int j = 0; j < blockSelectionPadding; j++) {
        buffer.append(' ');
        givenTextOffset++;
      }
    }
    return textWasChanged ? buffer.toString() : null;
  }
@Override
  public String preprocessOnCopy(final PsiFile file, final int[] startOffsets, final int[] endOffsets, final String text)