int (int offsetInDecoded, @NotNull TextRange rangeInsideHost) { int currentOffsetInDecoded = 0; TextRange last = null; for (int i = 0; i < contentRanges.size(); i++) { final TextRange range = rangeInsideHost.intersection(contentRanges.get(i)); if (range == null) continue; last = range; String curString = range.subSequence(text).toString(); final List<Pair<TextRange, String>> replacementsForThisLine = myHost.getDecodeReplacements(curString); int encodedOffsetInCurrentLine = 0; for (Pair<TextRange, String> replacement : replacementsForThisLine) { final int deltaLength = replacement.getFirst().getStartOffset() - encodedOffsetInCurrentLine; int currentOffsetBeforeReplacement = currentOffsetInDecoded + deltaLength; if (currentOffsetBeforeReplacement > offsetInDecoded) { return range.getStartOffset() + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded); } else if (currentOffsetBeforeReplacement == offsetInDecoded && !replacement.getSecond().isEmpty()) { return range.getStartOffset() + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded); } currentOffsetInDecoded += deltaLength + replacement.getSecond().length(); encodedOffsetInCurrentLine += deltaLength + replacement.getFirst().getLength(); } final int deltaLength = curString.length() - encodedOffsetInCurrentLine; if (currentOffsetInDecoded + deltaLength > offsetInDecoded) { return range.getStartOffset() + encodedOffsetInCurrentLine + (offsetInDecoded - currentOffsetInDecoded); } currentOffsetInDecoded += deltaLength; } return last != null ? last.getEndOffset() : -1; }