TextRange (PsiElement e, int cursorOffset) { assert e.getParent() instanceof GrString; PsiElement next = e; int startOffset = cursorOffset; int endOffset = cursorOffset; if (e.getNode().getElementType() == GroovyTokenTypes.mGSTRING_CONTENT) { final String text = e.getText(); int cur; int index = -1; while (true) { cur = text.indexOf('\n', index + 1); if (cur < 0 || cur + e.getTextOffset() > cursorOffset) break; index = cur; } if (index >= 0) { startOffset = e.getTextOffset() + index + 1; } index = text.indexOf('\n', cursorOffset - e.getTextOffset()); if (index >= 0) { endOffset = e.getTextOffset() + index + 1; } } if (startOffset == cursorOffset) { do { if (next == null) break; final ASTNode node = next.getNode(); if (node == null) break; final IElementType type = node.getElementType(); if (type == GroovyTokenTypes.mGSTRING_BEGIN) { startOffset = next.getTextRange().getEndOffset(); break; } if (type == GroovyElementTypes.GSTRING_CONTENT) { final String text; if (startOffset == cursorOffset && next.getTextRange().contains(cursorOffset)) { text = next.getText().substring(0, startOffset - next.getTextOffset()); } else { text = next.getText(); } final int i = text.lastIndexOf('\n'); if (i >= 0) { startOffset = next.getTextOffset() + i + 1; break; } } startOffset = next.getTextOffset(); next = next.getPrevSibling(); } while (true); } if (endOffset == cursorOffset) { next = e; do { if (next == null) break; final ASTNode node = next.getNode(); if (node == null) break; final IElementType type = node.getElementType(); if (type == GroovyTokenTypes.mGSTRING_END) { endOffset = next.getTextOffset(); break; } if (type == GroovyElementTypes.GSTRING_CONTENT) { final String text; final int offset; if (endOffset == cursorOffset && next.getTextRange().contains(cursorOffset)) { offset = endOffset - next.getTextOffset(); text = next.getText().substring(offset); } else { offset = 0; text = next.getText(); } final int i = text.indexOf('\n'); if (i >= 0) { endOffset = next.getTextOffset() + offset + i; break; } } endOffset = next.getTextOffset() + next.getTextLength(); next = next.getNextSibling(); } while (true); } return new TextRange(startOffset, endOffset); }