@Nullable protected Pair<PsiElement, TextRange> getRangePair(final PsiFile file, final Editor editor) { final int offset = editor.getCaretModel().getOffset(); final PsiLanguageInjectionHost host = PsiTreeUtil.getParentOfType(file.findElementAt(offset), PsiLanguageInjectionHost.class, false); if (host == null || ElementManipulators.getManipulator(host) == null) return null; final List<Pair<PsiElement, TextRange>> injections = InjectedLanguageManager.getInstance(host.getProject()).getInjectedPsiFiles(host); if (injections == null || injections.isEmpty()) return null; final int offsetInElement = offset - host.getTextRange().getStartOffset(); final Pair<PsiElement, TextRange> rangePair = ContainerUtil.find(injections, new Condition<Pair<PsiElement, TextRange>>() { @Override public boolean value(final Pair<PsiElement, TextRange> pair) { return pair.second.containsRange(offsetInElement, offsetInElement); } }); if (rangePair != null) { final Language language = rangePair.first.getContainingFile().getLanguage(); final Object action = language.getUserData(EDIT_ACTION_AVAILABLE); if (action != null && action.equals(false)) return null; myLastLanguageName = language.getDisplayName(); } return rangePair; }
@Override public int getLineStartOffset(int line) { LOG.assertTrue(line >= 0, line); if (line == 0) return 0; String hostText = myDelegate.getText(); int[] pos = new int[2]; // pos[0] = curLine; pos[1] == offset; synchronized (myLock) { for (PsiLanguageInjectionHost.Shred shred : myShreds) { Segment hostRange = shred.getHostRangeMarker(); if (hostRange == null) continue; int found = countNewLinesIn(shred.getPrefix(), pos, line); if (found != -1) return found; CharSequence text = hostText.subSequence(hostRange.getStartOffset(), hostRange.getEndOffset()); found = countNewLinesIn(text, pos, line); if (found != -1) return found; found = countNewLinesIn(shred.getSuffix(), pos, line); if (found != -1) return found; } } return pos[1]; }
@NotNull private String calcText() { StringBuilder text = new StringBuilder(); CharSequence hostText = myDelegate.getCharsSequence(); synchronized (myLock) { for (PsiLanguageInjectionHost.Shred shred : myShreds) { Segment hostRange = shred.getHostRangeMarker(); if (hostRange != null) { text.append(shred.getPrefix()); text.append(hostText, hostRange.getStartOffset(), hostRange.getEndOffset()); text.append(shred.getSuffix()); } } } return text.toString(); }
@Override public boolean areRangesEqual(@NotNull DocumentWindow otherd) { DocumentWindowImpl window = (DocumentWindowImpl)otherd; Place shreds = getShreds(); Place otherShreds = window.getShreds(); if (shreds.size() != otherShreds.size()) return false; for (int i = 0; i < shreds.size(); i++) { PsiLanguageInjectionHost.Shred shred = shreds.get(i); PsiLanguageInjectionHost.Shred otherShred = otherShreds.get(i); if (!shred.getPrefix().equals(otherShred.getPrefix())) return false; if (!shred.getSuffix().equals(otherShred.getSuffix())) return false; Segment hostRange = shred.getHostRangeMarker(); Segment other = otherShred.getHostRangeMarker(); if (hostRange == null || other == null || hostRange.getStartOffset() != other.getStartOffset()) return false; if (hostRange.getEndOffset() != other.getEndOffset()) return false; } return true; }
@NotNull private static PyInjectionUtil.InjectionResult registerCommentInjection(@NotNull MultiHostRegistrar registrar, @NotNull PsiLanguageInjectionHost host) { final String text = host.getText(); final Matcher m = PyTypingTypeProvider.TYPE_COMMENT_PATTERN.matcher(text); if (m.matches()) { final String annotationText = m.group(1); if (annotationText != null && isTypingAnnotation(annotationText)) { final int start = m.start(1); final int end = m.end(1); if (start < end && allowInjectionInComment(host)) { final Language language = PyDocstringLanguageDialect.getInstance(); registrar.startInjecting(language); registrar.addPlace("", "", host, TextRange.create(start, end)); registrar.doneInjecting(); return new PyInjectionUtil.InjectionResult(true, true); } } } return PyInjectionUtil.InjectionResult.EMPTY; }
@NotNull public Object[] getVariants() { final ArrayList<Object> ret = Lists.newArrayList(super.getVariants()); PsiFile file = myElement.getContainingFile(); final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myElement.getProject()); final PsiLanguageInjectionHost host = languageManager.getInjectionHost(myElement); if (host != null) file = host.getContainingFile(); final PsiElement originalElement = CompletionUtil.getOriginalElement(myElement); final PyQualifiedExpression element = originalElement instanceof PyQualifiedExpression ? (PyQualifiedExpression)originalElement : myElement; // include our own names final CompletionVariantsProcessor processor = new CompletionVariantsProcessor(element); if (file instanceof ScopeOwner) PyResolveUtil.scopeCrawlUp(processor, (ScopeOwner)file, null, null); ret.addAll(processor.getResultList()); return ret.toArray(); }
public void testEscaperOffsetInEscapedBackslash() { final PyStringLiteralExpression expr = createLiteralFromText("'XXX foo.\\\\bar YYY'"); assertNotNull(expr); final LiteralTextEscaper<? extends PsiLanguageInjectionHost> escaper = expr.createLiteralTextEscaper(); final TextRange range = TextRange.create(5, 14); assertEquals(5, escaper.getOffsetInHost(0, range)); assertEquals(6, escaper.getOffsetInHost(1, range)); assertEquals(7, escaper.getOffsetInHost(2, range)); assertEquals(8, escaper.getOffsetInHost(3, range)); assertEquals(9, escaper.getOffsetInHost(4, range)); assertEquals(11, escaper.getOffsetInHost(5, range)); assertEquals(12, escaper.getOffsetInHost(6, range)); assertEquals(13, escaper.getOffsetInHost(7, range)); assertEquals(14, escaper.getOffsetInHost(8, range)); assertEquals(-1, escaper.getOffsetInHost(9, range)); }
@Nullable private static RegExpLanguageHost findRegExpHost(@Nullable final PsiElement element) { if (ApplicationManager.getApplication().isUnitTestMode() && myHost != null) { return myHost; } if (element == null) { return null; } PsiLanguageInjectionHost host = InjectedLanguageManager.getInstance(element.getProject()).getInjectionHost(element); if (host instanceof RegExpLanguageHost) { return (RegExpLanguageHost)host; } if (host != null) { return INSTANCE.forClass(host.getClass()); } return null; }
private static boolean isMatchingText(@NotNull PsiFile regexpFile, @NotNull String sampleText) { final String regExp = regexpFile.getText(); PsiLanguageInjectionHost host = InjectedLanguageUtil.findInjectionHost(regexpFile); int flags = 0; if (host != null) { for (RegExpModifierProvider provider : RegExpModifierProvider.EP.allForLanguage(host.getLanguage())) { flags = provider.getFlags(host, regexpFile); if (flags > 0) break; } } try { return Pattern.compile(regExp, flags).matcher(sampleText).matches(); } catch (Exception ignore) {} return false; }
@Override public void getLanguagesToInject(@NotNull final MultiHostRegistrar registrar, @NotNull final PsiElement host) { Pair<ASTNode, ASTNode> pair = parseConditionalCommentBoundaries(host); if (pair == null) { return; } final TextRange textRange = host.getTextRange(); final int startOffset = textRange.getStartOffset(); Language language = host.getParent().getLanguage(); ASTNode conditionalStart = pair.first; ASTNode conditionalEnd = pair.second; TextRange range = new UnfairTextRange(conditionalStart.getTextRange().getEndOffset() - startOffset, conditionalEnd.getStartOffset() - startOffset); if (range.getStartOffset() < range.getEndOffset()) { registrar.startInjecting(language).addPlace(null, null, (PsiLanguageInjectionHost)host, range).doneInjecting(); } }
@Override public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement host) { if (!host.isValid() || !(host instanceof XmlText) || !HtmlUtil.isHtmlTagContainingFile(host)) { return; } XmlTag scriptTag = ((XmlText)host).getParentTag(); if (scriptTag == null) { return; } final Language language = getScriptLanguageToInject(scriptTag); if (language == null || HtmlScriptInjectionBlockerExtension.isInjectionBlocked(scriptTag, language)) { return; } if (LanguageUtil.isInjectableLanguage(language)) { registrar .startInjecting(language) .addPlace(null, null, (PsiLanguageInjectionHost)host, TextRange.create(0, host.getTextLength())) .doneInjecting(); } }
@Override public void getLanguagesToInject(@NotNull final PsiLanguageInjectionHost host, @NotNull final InjectedLanguagePlaces injectionPlacesRegistrar) { if (!(host instanceof XmlText)) return; final XmlText xmlText = (XmlText)host; if (!MavenPluginParamInfo.isSimpleText(xmlText)) return; MavenPluginParamInfo.ParamInfoList infoList = MavenPluginParamInfo.getParamInfoList(xmlText); for (MavenPluginParamInfo.ParamInfo info : infoList) { Language language = info.getLanguage(); if (language == null) { MavenParamLanguageProvider provider = info.getLanguageProvider(); if (provider != null) { language = provider.getLanguage(xmlText, infoList.getDomCfg()); } } if (language != null) { injectionPlacesRegistrar.addPlace(language, TextRange.from(0, host.getTextLength()), info.getLanguageInjectionPrefix(), info.getLanguageInjectionSuffix()); return; } } }
private static void invokeImpl(Project project, Editor editor, PsiFile file) { final PsiFile psiFile = InjectedLanguageUtil.findInjectedPsiNoCommit(file, editor.getCaretModel().getOffset()); if (psiFile == null) return; final PsiLanguageInjectionHost host = InjectedLanguageManager.getInstance(project).getInjectionHost(psiFile); if (host == null) return; final LanguageInjectionSupport support = psiFile.getUserData(LanguageInjectionSupport.SETTINGS_EDITOR); if (support == null) return; try { if (!support.editInjectionInPlace(host)) { ShowSettingsUtil.getInstance().editConfigurable(project, new InjectionsSettingsUI(project, Configuration.getProjectInstance(project))); } } finally { FileContentUtil.reparseFiles(project, Collections.<VirtualFile>emptyList(), true); } }
@NotNull public List<TextRange> getInjectedArea(final PsiElement element) { final TextRange textRange = ElementManipulators.getValueTextRange(element); if (myCompiledValuePattern == null) { return Collections.singletonList(textRange); } else { final LiteralTextEscaper<? extends PsiLanguageInjectionHost> textEscaper = ((PsiLanguageInjectionHost)element).createLiteralTextEscaper(); final StringBuilder sb = new StringBuilder(); textEscaper.decode(textRange, sb); final List<TextRange> ranges = getMatchingRanges(myCompiledValuePattern.matcher(StringPattern.newBombedCharSequence(sb)), sb.length()); return !ranges.isEmpty() ? ContainerUtil.map(ranges, new Function<TextRange, TextRange>() { public TextRange fun(TextRange s) { return new TextRange(textEscaper.getOffsetInHost(s.getStartOffset(), textRange), textEscaper.getOffsetInHost(s.getEndOffset(), textRange)); } }) : Collections.<TextRange>emptyList(); } }
public void getLanguagesToInject(@NotNull final MultiHostRegistrar registrar, @NotNull final PsiElement context) { if (!(context instanceof PsiLanguageInjectionHost) || context instanceof PsiComment) return; if (!((PsiLanguageInjectionHost)context).isValidHost()) return; PsiLanguageInjectionHost host = (PsiLanguageInjectionHost)context; boolean applicableFound = false; for (LanguageInjectionSupport support : mySupports) { if (!support.isApplicableTo(host)) continue; if (support == myInjectorSupport && applicableFound) continue; applicableFound = true; BaseInjection injection = support.findCommentInjection(host, null); if (injection == null) continue; if (!InjectorUtils.registerInjectionSimple(host, injection, support, registrar)) continue; return; } }
public boolean editInjectionInPlace(final PsiLanguageInjectionHost host) { if (!isMine(host)) return false; final Project project = host.getProject(); final Configuration configuration = Configuration.getProjectInstance(project); final ArrayList<BaseInjection> injections = collectInjections(host, configuration); if (injections.isEmpty()) return false; final BaseInjection originalInjection = injections.get(0); final BaseInjection xmlInjection = createFrom(originalInjection); final BaseInjection newInjection = xmlInjection == null? showDefaultInjectionUI(project, originalInjection.copy()) : showInjectionUI(project, xmlInjection); if (newInjection != null) { configuration.replaceInjectionsWithUndo( project, Collections.singletonList(newInjection), Collections.singletonList(originalInjection), Collections.<PsiElement>emptyList()); } return true; }
@NotNull public static PsiFile[] getFiles(XmlAttribute attribute) { final XmlAttributeValue value = attribute.getValueElement(); if (value != null) { final List<PsiFile> files = new SmartList<PsiFile>(); InjectedLanguageUtil.enumerate(value, new PsiLanguageInjectionHost.InjectedPsiVisitor() { public void visit(@NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) { if (injectedPsi instanceof XPathFile) { files.add(injectedPsi); } } }); return files.isEmpty() ? PsiFile.EMPTY_ARRAY : PsiUtilCore.toPsiFileArray(files); } return PsiFile.EMPTY_ARRAY; }
public void getLanguagesToInject(@NotNull final MultiHostRegistrar registrar, @NotNull final PsiElement host) { if (SCRIPT_PATTERN.accepts(host)) { final List<String> registeredLanguages = JavaFxPsiUtil.parseInjectedLanguages((XmlFile)host.getContainingFile()); for (Language language : Language.getRegisteredLanguages()) { for (String registeredLanguage : registeredLanguages) { if (StringUtil.equalsIgnoreCase(language.getID(), registeredLanguage)) { registrar.startInjecting(language) .addPlace(null, null, (PsiLanguageInjectionHost) host, TextRange.from(0, host.getTextLength() - 1)) .doneInjecting(); break; } } } } }
@Override public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) { if (context instanceof AppleScriptStringLiteralExpression) { AppleScriptCommandHandlerCall asCommand = PsiTreeUtil.getContextOfType(context, AppleScriptCommandHandlerCall.class); if (asCommand != null && asCommand.getCommandName().equalsIgnoreCase("do javascript")) { Collection<Language> javascript = Language.findInstancesByMimeType("javascript"); if (javascript.isEmpty()) return; registrar.startInjecting(javascript.iterator().next()).addPlace(null, null, (PsiLanguageInjectionHost) context, new TextRange(1, context.getTextLength() - 1)).doneInjecting(); } } }
@Override public void getLanguagesToInject( @NotNull final PsiLanguageInjectionHost host, @NotNull final InjectedLanguagePlaces injectionPlacesRegistrar ) { final PsiElement hostParent = host.getParent(); if (host instanceof ImpexStringImpl) { final String hostString = StringUtil.unquoteString(host.getText()).toLowerCase(); if (StringUtil.trim(hostString).startsWith("select ")) { registerInjectionPlace(injectionPlacesRegistrar, host); } } if (hostParent != null) { if (hostParent.getParent() instanceof PsiMethodCallExpressionImpl) { final PsiMethodCallExpressionImpl callExpression = (PsiMethodCallExpressionImpl) hostParent.getParent(); final PsiMethod method = callExpression.resolveMethod(); if (method != null) { final PsiClass containingClass = method.getContainingClass(); if (containingClass != null && "FlexibleSearchService".equals(containingClass.getName()) && "search".equals(method.getName())) { registerInjectionPlace(injectionPlacesRegistrar, host); } } } } }
@Override public boolean canPutAt(@NotNull VirtualFile file, int line, @NotNull Project project) { final Document document = FileDocumentManager.getInstance().getDocument(file); if (document != null) { final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document); if (psiFile != null) { final boolean isMuleAndXml = MuleConfigUtils.isMuleFile(psiFile); if (isMuleAndXml) { final XmlTag xmlTagAt = MuleConfigUtils.getXmlTagAt(project, XDebuggerUtil.getInstance().createPosition(file, line)); if (xmlTagAt != null) { return MuleConfigUtils.getMuleElementTypeFromXmlElement(xmlTagAt) == MuleElementType.MESSAGE_PROCESSOR; } else { final PsiElement firstWeaveElement = WeavePsiUtils.getFirstWeaveElement(project, document, line); if (firstWeaveElement != null) { PsiLanguageInjectionHost parent = PsiTreeUtil.getParentOfType(firstWeaveElement, PsiLanguageInjectionHost.class); if (parent != null) { final PsiElement elementInInjected = InjectedLanguageUtil.findElementInInjected(parent, line); final Language language = elementInInjected.getLanguage(); return language == WeaveLanguage.getInstance(); } } } } } } return false; }
@Override public void getLanguagesToInject(@NotNull PsiLanguageInjectionHost host, @NotNull InjectedLanguagePlaces injectedLanguagePlaces) { if (MuleConfigUtils.isMuleFile(host.getContainingFile())) { if (host instanceof XmlAttributeValue) { // Try to inject a language, somewhat abusing the lazy evaluation of predicates :( for (Pair<String, String> language : languages) { if (tryInjectLanguage(language.getFirst(), language.getSecond(), host, injectedLanguagePlaces)) { break; } } } else if (host instanceof XmlText) { final XmlTag tag = ((XmlText) host).getParentTag(); if (tag != null) { final QName tagName = MuleConfigUtils.getQName(tag); if (tagName.equals(globalFunctions) || tagName.equals(expressionComponent) || tagName.equals(expressionTransformer)) { final String scriptingName = MelLanguage.MEL_LANGUAGE_ID; injectLanguage(host, injectedLanguagePlaces, scriptingName); } else if (tagName.equals(scriptingScript)) { final String engine = tag.getAttributeValue("engine"); if (engine != null) { injectLanguage(host, injectedLanguagePlaces, StringUtil.capitalize(engine)); } } else if (tagName.equals(dwSetPayload) || tagName.equals(dwSetProperty) || tagName.equals(dwSetVariable) || tagName.equals(dwSetSessionVar)) { injectLanguage(host, injectedLanguagePlaces, WEAVE_LANGUAGE_ID); } } } } }
private void injectLanguage(@NotNull PsiLanguageInjectionHost host, @NotNull InjectedLanguagePlaces injectedLanguagePlaces, String scriptingName) { final Language requiredLanguage = Language.findLanguageByID(scriptingName); if (requiredLanguage != null) { final TextRange range = TextRange.from(0, host.getTextRange().getLength()); injectedLanguagePlaces.addPlace(requiredLanguage, range, null, null); } }
private boolean tryInjectLanguage(@NotNull String langPrefix, @NotNull String languageId, @NotNull PsiLanguageInjectionHost host, @NotNull InjectedLanguagePlaces injectedLanguagePlaces) { if (isExpectedLocalName(langPrefix, host)) { injectLanguage(langPrefix, languageId, host, injectedLanguagePlaces); return true; } return false; }
private boolean isExpectedLocalName(@NotNull String langPrefix, @NotNull PsiLanguageInjectionHost psiLanguageInjectionHost) { final XmlAttributeValue attributeValue = (XmlAttributeValue) psiLanguageInjectionHost; final String expressionText = attributeValue.getValue(); return expressionText.startsWith(getLanguagePrefix(langPrefix)) && expressionText.endsWith("]"); }
private void injectLanguage(String langPrefix, @NotNull String languageId, @NotNull PsiLanguageInjectionHost host, @NotNull InjectedLanguagePlaces injectedLanguagePlaces) { // Find the required Language final Language requiredLanguage = Language.findLanguageByID(languageId); if (requiredLanguage == null) { return; } final TextRange textRange = ((XmlAttributeValue) host).getValueTextRange(); final int length = getLanguagePrefix(langPrefix).length() + 1; final TextRange expressionTextRange = TextRange.from(length, textRange.getLength() - length); injectedLanguagePlaces.addPlace(requiredLanguage, expressionTextRange, null, null); }
@Override public void getLanguagesToInject(@NotNull PsiLanguageInjectionHost host, @NotNull InjectedLanguagePlaces injectionPlacesRegistrar) { if (!(host instanceof CupJavaImpl) || !(settings.ENABLE_JAVA_INJECTION)) { return; } final CupJavaImpl cupJavaCode = (CupJavaImpl) host; final String text = cupJavaCode.getText(); if (!(text.startsWith(PREFIX) && text.endsWith(SUFFIX))) { return; } injectionPlacesRegistrar.addPlace(JavaLanguage.INSTANCE, new TextRange(SUFFIX.length(), text.length() - SUFFIX.length()), "public class Dummy { public void dummyMethod(){", "}}"); }
@Override public void getLanguagesToInject(@NotNull PsiLanguageInjectionHost host, @NotNull InjectedLanguagePlaces injectionPlacesRegistrar) { Iterator it = myInjectionConfiguration.getInjections("fusion").iterator(); while(it.hasNext()) { BaseInjection injection = (BaseInjection) it.next(); if (injection.acceptsPsiElement(host)) { Language language = InjectedLanguage.findLanguageById(injection.getInjectedLanguageId()); if (language != null) { injectionPlacesRegistrar.addPlace(language, new TextRange(0, host.getTextLength()), "", ""); } } } }
@NotNull private PsiFile setUpRegexpInjectionAndGetRegexpFile() { final PsiFile file = getFile(); int offsetWithRegexp = file.getText().indexOf("Pattern.compile(\"") + "Pattern.compile(\"".length(); final PsiElement stringLiteralLeaf = file.findElementAt(offsetWithRegexp); assertNotNull(stringLiteralLeaf); assertNotNull(stringLiteralLeaf.getParent()); assertTrue(stringLiteralLeaf.getParent() instanceof PsiLanguageInjectionHost); final PsiLanguageInjectionHost elementWithInjection = ((PsiLanguageInjectionHost)stringLiteralLeaf.getParent()); InjectedLanguageUtil.enumerate(elementWithInjection, file, false, new PsiLanguageInjectionHost.InjectedPsiVisitor() { @Override public void visit(@NotNull final PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) { } }); assertTrue(InjectedLanguageUtil.hasInjections(elementWithInjection)); final PsiElement elementInInjected = InjectedLanguageUtil.findElementInInjected(elementWithInjection, offsetWithRegexp); final PsiFile regexpFile = PsiTreeUtil.getParentOfType(elementInInjected, PsiFile.class); assertNotNull(regexpFile); return regexpFile; }
@Override public void tokenize(@NotNull T element, TokenConsumer consumer) { if (element instanceof PsiLanguageInjectionHost && InjectedLanguageUtil.hasInjections((PsiLanguageInjectionHost)element)) { return; } consumer.consumeToken(element, mySplitter); }
public void testManipulatorRegistered() { LanguageExtensionPoint[] extensions = Extensions.getExtensions(new ExtensionPointName<LanguageExtensionPoint>("com.intellij.lang.parserDefinition")); Set<String> classes = new HashSet<String>(); List<String> failures = new ArrayList<String>(); int total = 0; for (LanguageExtensionPoint e : extensions) { ParserDefinition definition = (ParserDefinition)e.getInstance(); for (IElementType type : IElementType.enumerate(IElementType.TRUE)) { if (type instanceof ILeafElementType) continue; try { CompositeElement treeElement = ASTFactory.composite(type); total++; PsiElement element = treeElement instanceof PsiElement? (PsiElement)treeElement : definition.createElement(treeElement); if (element instanceof PsiLanguageInjectionHost && classes.add(element.getClass().getName())) { boolean ok = ElementManipulators.getManipulator(element) != null; System.out.println((ok ? "OK " : "FAIL") + " " + element.getClass().getSimpleName() + " [" + definition.getClass().getSimpleName() + "]"); if (!ok) failures.add(element.getClass().getName()); } } catch (Throwable ignored) { } } } System.out.println("count: " + classes.size() + ", total: " + total); assertEmpty("PsiLanguageInjectionHost requires " + ElementManipulators.EP_NAME, failures); }
public boolean isValid() { for (PsiLanguageInjectionHost.Shred shred : this) { if (!shred.isValid()) { return false; } } return true; }
@Nullable("null means we were unable to calculate") LogicalPosition hostToInjectedInVirtualSpace(@NotNull LogicalPosition hPos) { // beware the virtual space int hLineStartOffset = hPos.line >= myDelegate.getLineCount() ? myDelegate.getTextLength() : myDelegate.getLineStartOffset(hPos.line); int iLineStartOffset = hostToInjected(hLineStartOffset); int iLine = getLineNumber(iLineStartOffset); synchronized (myLock) { for (int i = myShreds.size() - 1; i >= 0; i--) { PsiLanguageInjectionHost.Shred shred = myShreds.get(i); if (!shred.isValid()) continue; Segment hostRangeMarker = shred.getHostRangeMarker(); if (hostRangeMarker == null) continue; int hShredEndOffset = hostRangeMarker.getEndOffset(); int hShredStartOffset = hostRangeMarker.getStartOffset(); int hShredStartLine = myDelegate.getLineNumber(hShredStartOffset); int hShredEndLine = myDelegate.getLineNumber(hShredEndOffset); if (hShredStartLine <= hPos.line && hPos.line <= hShredEndLine) { int hColumnOfShredEnd = hShredEndOffset - hLineStartOffset; int iColumnOfShredEnd = hostToInjected(hShredEndOffset) - iLineStartOffset; int iColumn = iColumnOfShredEnd + hPos.column - hColumnOfShredEnd; return new LogicalPosition(iLine, iColumn); } } } return null; }
@Override public int getTextLength() { int length = 0; synchronized (myLock) { for (PsiLanguageInjectionHost.Shred shred : myShreds) { Segment hostRange = shred.getHostRangeMarker(); if (hostRange == null) continue; length += shred.getPrefix().length(); length += hostRange.getEndOffset() - hostRange.getStartOffset(); length += shred.getSuffix().length(); } } return length; }
@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; }
@Override public TextRange getHostRange(int hostOffset) { synchronized (myLock) { for (PsiLanguageInjectionHost.Shred shred : myShreds) { Segment currentRange = shred.getHostRangeMarker(); if (currentRange == null) continue; TextRange textRange = ProperTextRange.create(currentRange); if (textRange.grown(1).contains(hostOffset)) return textRange; } } return null; }
@Override @NotNull public Segment[] getHostRanges() { synchronized (myLock) { List<Segment> markers = new ArrayList<Segment>(myShreds.size()); for (PsiLanguageInjectionHost.Shred shred : myShreds) { Segment hostMarker = shred.getHostRangeMarker(); if (hostMarker != null) { markers.add(hostMarker); } } return markers.isEmpty() ? Segment.EMPTY_ARRAY : markers.toArray(new Segment[markers.size()]); } }
@Override public boolean containsRange(int start, int end) { synchronized (myLock) { ProperTextRange query = new ProperTextRange(start, end); for (PsiLanguageInjectionHost.Shred shred : myShreds) { Segment hostRange = shred.getHostRangeMarker(); if (hostRange == null) continue; TextRange textRange = ProperTextRange.create(hostRange); if (textRange.contains(query)) return true; } return false; } }
private String getRangeText(@NotNull String hostText, int hostNum) { synchronized (myLock) { PsiLanguageInjectionHost.Shred shred = myShreds.get(hostNum); Segment hostRangeMarker = shred.getHostRangeMarker(); return shred.getPrefix() + (hostRangeMarker == null ? "" : hostText.substring(hostRangeMarker.getStartOffset(), hostRangeMarker.getEndOffset())) + shred.getSuffix(); } }
@Override public boolean isValid() { PsiLanguageInjectionHost.Shred[] shreds; synchronized (myLock) { shreds = myShreds.toArray(new PsiLanguageInjectionHost.Shred[myShreds.size()]); } // can grab PsiLock in SmartPsiPointer.restore() for (PsiLanguageInjectionHost.Shred shred : shreds) { if (!shred.isValid()) return false; } return true; }