private @NotNull List<HighlightData> setupRainbowHighlighting(final @NotNull RainbowColorSettingsPage page,
                                                                final @NotNull List<HighlightData> initialMarkup,
                                                                final TextAttributesKey @NotNull [] rainbowTempKeys,
                                                                boolean isRainbowOn) {
    int colorCount = rainbowTempKeys.length;
    if (colorCount == 0) {
      return initialMarkup;
    }
    List<HighlightData> rainbowMarkup = new ArrayList<>();

    int tempKeyIndex = 0;
    boolean repeatAnchor = true;
    for (HighlightData d : initialMarkup) {
      final TextAttributesKey highlightKey = d.getHighlightKey();
      final boolean rainbowType = page.isRainbowType(highlightKey);
      final boolean rainbowDemoType = highlightKey == RainbowHighlighter.RAINBOW_GRADIENT_DEMO;
      if (rainbowType || rainbowDemoType) {
        final HighlightData rainbowAnchor = new HighlightData(d.getStartOffset(), d.getEndOffset(), RainbowHighlighter.RAINBOW_ANCHOR);
        if (isRainbowOn) {
          // rainbow on
          HighlightData rainbowTemp;
          if (rainbowType) {
            rainbowTemp = getRainbowTemp(rainbowTempKeys, d.getStartOffset(), d.getEndOffset());
          }
          else {
            rainbowTemp = new HighlightData(d.getStartOffset(), d.getEndOffset(), rainbowTempKeys[tempKeyIndex % colorCount]);
            if (repeatAnchor && tempKeyIndex == colorCount/2) {
              // anchor [Color#3] colored twice: it the end and in the beginning of rainbow-demo string
              repeatAnchor = false;
            }
            else {
              ++tempKeyIndex;
            }
          }
          // TODO: <remove the hack>
          // At some point highlighting data is applied in reversed order. To ensure rainbow highlighting is always on top, we add it twice.
          rainbowMarkup.add(rainbowTemp);
          rainbowMarkup.add(rainbowAnchor);
          rainbowMarkup.add(d);
          rainbowMarkup.add(rainbowAnchor);
          rainbowMarkup.add(rainbowTemp);
        }
        else {
          // rainbow off
          if (rainbowType) {
            // TODO: <remove the hack>
            // See above
            rainbowMarkup.add(d);
            rainbowMarkup.add(rainbowAnchor);
            rainbowMarkup.add(d);
          }
          else {
            rainbowMarkup.add(rainbowAnchor);
          }
        }
      }
      else if (!(RainbowHighlighter.isRainbowTempKey(highlightKey) || highlightKey == RainbowHighlighter.RAINBOW_ANCHOR)) {
        // filter rainbow RAINBOW_TEMP and RAINBOW_ANCHOR
        rainbowMarkup.add(d);
      }
    }
    return rainbowMarkup;
  }
private @NotNull List<HighlightData> setupRainbowHighlighting(final @NotNull RainbowColorSettingsPage page,
                                                                final @NotNull List<HighlightData> initialMarkup,
                                                                final TextAttributesKey @NotNull [] rainbowTempKeys,
                                                                boolean isRainbowOn)