List<HighlightData> (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; }