List<BidiRun> (EditorView view, char[] text, int startOffsetInEditor) { int textLength = text.length; if (view.getEditor().myDisableRtl || !Bidi.requiresBidi(text, 0, textLength)) { return Collections.singletonList(new BidiRun(textLength)); } view.getEditor().bidiTextFound(); List<BidiRun> runs = new ArrayList<>(); int flags = view.getBidiFlags(); if (startOffsetInEditor >= 0) { // skipping indent int relLastOffset = 0; while (relLastOffset < text.length && WHITESPACE_CHARS.indexOf(text[relLastOffset]) >= 0) relLastOffset++; addRuns(runs, text, 0, relLastOffset, flags); // running bidi algorithm separately for text fragments corresponding to different lexer tokens IElementType lastToken = null; HighlighterIterator iterator = view.getEditor().getHighlighter().createIterator(startOffsetInEditor + relLastOffset); while (!iterator.atEnd() && iterator.getStart() - startOffsetInEditor < textLength) { int iteratorRelStart = alignToCodePointBoundary(text, iterator.getStart() - startOffsetInEditor); int iteratorRelEnd = alignToCodePointBoundary(text, iterator.getEnd() - startOffsetInEditor); int relStartOffset = Math.max(relLastOffset, iteratorRelStart); int relEndOffset = Math.min(textLength, Math.max(relStartOffset, iteratorRelEnd)); IElementType currentToken = iterator.getTokenType(); int[] boundaries = getCommentPrefixAndOrSuffixBoundaries(text, relStartOffset, relEndOffset, currentToken); if (boundaries != null) { // for comments, we process prefixes and suffixes separately from comment text addRuns(runs, text, relLastOffset, relStartOffset, flags); addRuns(runs, text, relStartOffset, boundaries[0], flags); addRuns(runs, text, boundaries[0], boundaries[1], flags); lastToken = null; relLastOffset = boundaries[1]; } else if (distinctTokens(lastToken, currentToken)) { addRuns(runs, text, relLastOffset, relStartOffset, flags); lastToken = currentToken; relLastOffset = relStartOffset; } iterator.advance(); } addRuns(runs, text, relLastOffset, textLength, flags); } else { addRuns(runs, text, 0, textLength, flags); } for (BidiRun run : runs) { assert !isInsideSurrogatePair(text, run.startOffset); assert !isInsideSurrogatePair(text, run.endOffset); } return runs; }