private void doReplaceString(int startOffset, int endOffset, CharSequence s) { assert intersectWithEditable(new TextRange(startOffset, startOffset)) != null; assert intersectWithEditable(new TextRange(endOffset, endOffset)) != null; List<Pair<TextRange, CharSequence>> hostRangesToModify; synchronized (myLock) { hostRangesToModify = new ArrayList<Pair<TextRange, CharSequence>>(myShreds.size()); int offset = startOffset; int curRangeStart = 0; for (int i = 0; i < myShreds.size(); i++) { PsiLanguageInjectionHost.Shred shred = myShreds.get(i); curRangeStart += shred.getPrefix().length(); if (offset < curRangeStart) offset = curRangeStart; Segment hostRange = shred.getHostRangeMarker(); if (hostRange == null) continue; int hostRangeLength = hostRange.getEndOffset() - hostRange.getStartOffset(); TextRange range = TextRange.from(curRangeStart, hostRangeLength); if (range.contains(offset) || range.getEndOffset() == offset /* in case of inserting at the end*/) { TextRange rangeToModify = new TextRange(offset, Math.min(range.getEndOffset(), endOffset)); TextRange hostRangeToModify = rangeToModify.shiftRight(hostRange.getStartOffset() - curRangeStart); CharSequence toReplace = i == myShreds.size() - 1 || range.getEndOffset() + shred.getSuffix().length() >= endOffset ? s : s.subSequence(0, Math.min(hostRangeToModify.getLength(), s.length())); s = toReplace == s ? "" : s.subSequence(toReplace.length(), s.length()); hostRangesToModify.add(Pair.create(hostRangeToModify, toReplace)); offset = rangeToModify.getEndOffset(); } curRangeStart += hostRangeLength; curRangeStart += shred.getSuffix().length(); if (curRangeStart > endOffset) break; } } int delta = 0; for (Pair<TextRange, CharSequence> pair : hostRangesToModify) { TextRange hostRange = pair.getFirst(); CharSequence replace = pair.getSecond(); myDelegate.replaceString( hostRange.getStartOffset() + delta, hostRange.getEndOffset() + delta, replace); delta -= hostRange.getLength() - replace.length(); } }
private static void highlightTodos( @NotNull PsiFile file, @NotNull CharSequence text, int startOffset, int endOffset, @NotNull ProgressIndicator progress, @NotNull ProperTextRange priorityRange, @NotNull Collection<HighlightInfo> result, @NotNull Collection<HighlightInfo> outsideResult) { PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(file.getProject()); TodoItem[] todoItems = helper.findTodoItems(file, startOffset, endOffset); if (todoItems.length == 0) return; for (TodoItem todoItem : todoItems) { progress.checkCanceled(); TextRange range = todoItem.getTextRange(); String description = text.subSequence(range.getStartOffset(), range.getEndOffset()).toString(); TextAttributes attributes = todoItem.getPattern().getAttributes().getTextAttributes(); HighlightInfo info = HighlightInfo.createHighlightInfo( HighlightInfoType.TODO, range, description, description, attributes); assert info != null; if (priorityRange.containsRange(info.getStartOffset(), info.getEndOffset())) { result.add(info); } else { outsideResult.add(info); } } }
private static int getNewIndent(final PsiFile psiFile, final int firstWhitespace) { final Document document = psiFile.getViewProvider().getDocument(); final int startOffset = document.getLineStartOffset(document.getLineNumber(firstWhitespace)); int endOffset = startOffset; final CharSequence charsSequence = document.getCharsSequence(); while (Character.isWhitespace(charsSequence.charAt(endOffset++))) ; final String newIndentStr = charsSequence.subSequence(startOffset, endOffset - 1).toString(); return IndentHelperImpl.getIndent( psiFile.getProject(), psiFile.getFileType(), newIndentStr, true); }
@Override public void replaceString(int startOffset, int endOffset, @NotNull CharSequence s) { if (isOneLine()) { s = StringUtil.replace(s.toString(), "\n", ""); } final CharSequence chars = getCharsSequence(); CharSequence toDelete = chars.subSequence(startOffset, endOffset); int perfixLength = StringUtil.commonPrefixLength(s, toDelete); int suffixLength = StringUtil.commonSuffixLength( toDelete.subSequence(perfixLength, toDelete.length()), s.subSequence(perfixLength, s.length())); startOffset += perfixLength; endOffset -= suffixLength; s = s.subSequence(perfixLength, s.length() - suffixLength); doReplaceString(startOffset, endOffset, s); }
private static void adjustIndentationInRange( final PsiFile file, final Document document, final TextRange[] indents, final int indentAdjustment) { final CharSequence charsSequence = document.getCharsSequence(); for (final TextRange indent : indents) { final String oldIndentStr = charsSequence.subSequence(indent.getStartOffset() + 1, indent.getEndOffset()).toString(); final int oldIndent = IndentHelperImpl.getIndent(file.getProject(), file.getFileType(), oldIndentStr, true); final String newIndentStr = IndentHelperImpl.fillIndent( file.getProject(), file.getFileType(), Math.max(oldIndent + indentAdjustment, 0)); document.replaceString(indent.getStartOffset() + 1, indent.getEndOffset(), newIndentStr); } }
@Override public int getLineNumber(int offset) { int lineNumber = 0; String hostText = myDelegate.getText(); synchronized (myLock) { for (PsiLanguageInjectionHost.Shred shred : myShreds) { String prefix = shred.getPrefix(); String suffix = shred.getSuffix(); lineNumber += StringUtil.getLineBreakCount(prefix.substring(0, Math.min(offset, prefix.length()))); if (offset < prefix.length()) { return lineNumber; } offset -= prefix.length(); Segment currentRange = shred.getHostRangeMarker(); if (currentRange == null) continue; int rangeLength = currentRange.getEndOffset() - currentRange.getStartOffset(); CharSequence rangeText = hostText.subSequence(currentRange.getStartOffset(), currentRange.getEndOffset()); lineNumber += StringUtil.getLineBreakCount(rangeText.subSequence(0, Math.min(offset, rangeLength))); if (offset < rangeLength) { return lineNumber; } offset -= rangeLength; lineNumber += StringUtil.getLineBreakCount(suffix.substring(0, Math.min(offset, suffix.length()))); if (offset < suffix.length()) { return lineNumber; } offset -= suffix.length(); } } lineNumber = getLineCount() - 1; return lineNumber < 0 ? 0 : lineNumber; }