private void highlightInjectedSyntax( @NotNull PsiFile injectedPsi, @NotNull HighlightInfoHolder holder) { List<Trinity<IElementType, SmartPsiElementPointer<PsiLanguageInjectionHost>, TextRange>> tokens = InjectedLanguageUtil.getHighlightTokens(injectedPsi); if (tokens == null) return; final Language injectedLanguage = injectedPsi.getLanguage(); Project project = injectedPsi.getProject(); SyntaxHighlighter syntaxHighlighter = SyntaxHighlighterFactory.getSyntaxHighlighter( injectedLanguage, project, injectedPsi.getVirtualFile()); final TextAttributes defaultAttrs = myGlobalScheme.getAttributes(HighlighterColors.TEXT); for (Trinity<IElementType, SmartPsiElementPointer<PsiLanguageInjectionHost>, TextRange> token : tokens) { ProgressManager.checkCanceled(); IElementType tokenType = token.getFirst(); PsiLanguageInjectionHost injectionHost = token.getSecond().getElement(); if (injectionHost == null) continue; TextRange textRange = token.getThird(); TextAttributesKey[] keys = syntaxHighlighter.getTokenHighlights(tokenType); if (textRange.getLength() == 0) continue; TextRange annRange = textRange.shiftRight(injectionHost.getTextRange().getStartOffset()); // force attribute colors to override host' ones TextAttributes attributes = null; for (TextAttributesKey key : keys) { TextAttributes attrs2 = myGlobalScheme.getAttributes(key); if (attrs2 != null) { attributes = attributes == null ? attrs2 : TextAttributes.merge(attributes, attrs2); } } TextAttributes forcedAttributes; if (attributes == null || attributes.isEmpty() || attributes.equals(defaultAttrs)) { forcedAttributes = TextAttributes.ERASE_MARKER; } else { HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT) .range(annRange) .textAttributes(TextAttributes.ERASE_MARKER) .createUnconditionally(); holder.add(info); forcedAttributes = new TextAttributes( attributes.getForegroundColor(), attributes.getBackgroundColor(), attributes.getEffectColor(), attributes.getEffectType(), attributes.getFontType()); } HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.INJECTED_LANGUAGE_FRAGMENT) .range(annRange) .textAttributes(forcedAttributes) .createUnconditionally(); holder.add(info); } }
public void initMarkers(Place shreds) { SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(myProject); int curOffset = -1; for (PsiLanguageInjectionHost.Shred shred : shreds) { final RangeMarker rangeMarker = myNewDocument.createRangeMarker( shred.getRange().getStartOffset() + shred.getPrefix().length(), shred.getRange().getEndOffset() - shred.getSuffix().length()); final TextRange rangeInsideHost = shred.getRangeInsideHost(); PsiLanguageInjectionHost host = shred.getHost(); RangeMarker origMarker = myOrigDocument.createRangeMarker( rangeInsideHost.shiftRight(host.getTextRange().getStartOffset())); SmartPsiElementPointer<PsiLanguageInjectionHost> elementPointer = smartPointerManager.createSmartPsiElementPointer(host); Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer> markers = Trinity.<RangeMarker, RangeMarker, SmartPsiElementPointer>create( origMarker, rangeMarker, elementPointer); myMarkers.add(markers); origMarker.setGreedyToRight(true); rangeMarker.setGreedyToRight(true); if (origMarker.getStartOffset() > curOffset) { origMarker.setGreedyToLeft(true); rangeMarker.setGreedyToLeft(true); } curOffset = origMarker.getEndOffset(); } initGuardedBlocks(shreds); }
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(); } }
@Override public void deleteString(final int startOffset, final int endOffset) { assert intersectWithEditable(new TextRange(startOffset, startOffset)) != null; assert intersectWithEditable(new TextRange(endOffset, endOffset)) != null; List<TextRange> hostRangesToDelete; synchronized (myLock) { hostRangesToDelete = new ArrayList<TextRange>(myShreds.size()); int offset = startOffset; int curRangeStart = 0; for (PsiLanguageInjectionHost.Shred shred : myShreds) { curRangeStart += shred.getPrefix().length(); if (offset < curRangeStart) offset = curRangeStart; if (offset >= endOffset) break; Segment hostRange = shred.getHostRangeMarker(); if (hostRange == null) continue; int hostRangeLength = hostRange.getEndOffset() - hostRange.getStartOffset(); TextRange range = TextRange.from(curRangeStart, hostRangeLength); if (range.contains(offset)) { TextRange rangeToDelete = new TextRange(offset, Math.min(range.getEndOffset(), endOffset)); hostRangesToDelete.add( rangeToDelete.shiftRight(hostRange.getStartOffset() - curRangeStart)); offset = rangeToDelete.getEndOffset(); } curRangeStart += hostRangeLength; curRangeStart += shred.getSuffix().length(); } } int delta = 0; for (TextRange hostRangeToDelete : hostRangesToDelete) { myDelegate.deleteString( hostRangeToDelete.getStartOffset() + delta, hostRangeToDelete.getEndOffset() + delta); delta -= hostRangeToDelete.getLength(); } }