void (Document document) { String text = document.getText(); String pat = ".*?((<" + LINE_MARKER + ")(?: descr=\"((?:[^\"\\\\]|\\\\\")*)\")?(?: icon=\"((?:[^\"\\\\]|\\\\\")*)\")?>)(.*)"; Pattern openingTagRx = Pattern.compile(pat, Pattern.DOTALL); Pattern closingTagRx = Pattern.compile("(.*?)(</" + LINE_MARKER + ">)(.*)", Pattern.DOTALL); while (true) { Matcher opening = openingTagRx.matcher(text); if (!opening.matches()) break; int startOffset = opening.start(1); String descr = opening.group(3) != null ? opening.group(3) : ANY_TEXT; String icon = opening.group(4) != null ? opening.group(4) : ANY_TEXT; String rest = opening.group(5); Matcher closing = closingTagRx.matcher(rest); if (!closing.matches()) { fail("Cannot find closing </" + LINE_MARKER + ">"); } document.replaceString(startOffset, opening.end(1), ""); String content = closing.group(1); int endOffset = startOffset + closing.start(3); String endTag = closing.group(2); document.replaceString(startOffset, endOffset, content); endOffset -= endTag.length(); TextRange range = new TextRange(startOffset, endOffset); String tooltip = StringUtil.unescapeStringCharacters(descr); LineMarkerInfo<PsiElement> markerInfo = new MyLineMarkerInfo(range, GutterIconRenderer.Alignment.RIGHT, tooltip, icon); myLineMarkerInfos.put(document.createRangeMarker(startOffset, endOffset), markerInfo); text = document.getText(); } }