@Override public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { if (!element.isWritable()) return false; boolean isTwigFile = GravFileTemplateUtil.isTwigTemplateFile(element.getContainingFile()) || element.getContainingFile() instanceof HtmlFileImpl; boolean isXmlAttribute = false; if (!isTwigFile) return false; if (element.getParent() instanceof XmlAttributeValueImpl) { XmlAttributeValueImpl parent0 = ((XmlAttributeValueImpl) element.getParent()); boolean hasTwigElement = PsiTreeUtil.findChildOfType(parent0, OuterLanguageElement.class) != null; if (!hasTwigElement && parent0.getParent() instanceof XmlAttributeImpl) { XmlAttributeImpl parent1 = (XmlAttributeImpl) parent0.getParent(); if (parent1.getName().equalsIgnoreCase("href") || parent1.getName().equalsIgnoreCase("src")) isXmlAttribute = true; } } return isXmlAttribute; }
@Override @Nullable public PsiElement findElementAt(int offset, @NotNull Class<? extends Language> lang) { final PsiFile mainRoot = getPsi(getBaseLanguage()); PsiElement ret = null; for (final Language language : getLanguages()) { if (!ReflectionUtil.isAssignable(lang, language.getClass())) continue; if (lang.equals(Language.class) && !getLanguages().contains(language)) continue; final PsiFile psiRoot = getPsi(language); final PsiElement psiElement = findElementAt(psiRoot, offset); if (psiElement == null || psiElement instanceof OuterLanguageElement) continue; if (ret == null || psiRoot != mainRoot) { ret = psiElement; } } return ret; }
@Nullable public static PsiReference findReferenceAt(PsiElement thisElement, int offset, @Nullable Language lang) { if (thisElement == null) return null; PsiElement element = lang != null ? thisElement.getContainingFile().getViewProvider().findElementAt(offset, lang) : thisElement.findElementAt(offset); if (element == null || element instanceof OuterLanguageElement) return null; offset = thisElement.getTextRange().getStartOffset() + offset - element.getTextRange().getStartOffset(); List<PsiReference> referencesList = new ArrayList<PsiReference>(); while (element != null) { addReferences(offset, element, referencesList); offset = element.getStartOffsetInParent() + offset; if (element instanceof PsiFile) break; element = element.getParent(); } if (referencesList.isEmpty()) return null; if (referencesList.size() == 1) return referencesList.get(0); return new PsiMultiReference(referencesList.toArray(new PsiReference[referencesList.size()]), referencesList.get(referencesList.size() - 1).getElement()); }
private boolean testSelectionForNonComments() { if (!myCaret.hasSelection()) { return true; } TextRange range = new TextRange(myCaret.getSelectionStart(), myCaret.getSelectionEnd() - 1); for (PsiElement element = myFile.findElementAt(range.getStartOffset()); element != null && range.intersects(element.getTextRange()); element = element.getNextSibling()) { if (element instanceof OuterLanguageElement) { if (!isInjectedWhiteSpace(range, (OuterLanguageElement)element)) { return false; } } else { if (!isWhiteSpaceOrComment(element, range)) { return false; } } } return true; }
/** * Overrides the findReferenceAt() logic in order to provide a resolve context with origin file for returned references. * The findReferenceAt() is usually invoked from UI operations, and it helps to be able to do deeper analysis in the * current file for such operations. * * @param offset the offset to find the reference at * @return the reference or null. */ @Override public PsiReference findReferenceAt(int offset) { // copy/paste from SharedPsiElementImplUtil PsiElement element = findElementAt(offset); if (element == null || element instanceof OuterLanguageElement) return null; offset = getTextRange().getStartOffset() + offset - element.getTextRange().getStartOffset(); List<PsiReference> referencesList = new ArrayList<PsiReference>(); final PsiFile file = element.getContainingFile(); final PyResolveContext resolveContext = file != null ? PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.codeAnalysis(file.getProject(), file)) : PyResolveContext.defaultContext(); while (element != null) { addReferences(offset, element, referencesList, resolveContext); offset = element.getStartOffsetInParent() + offset; if (element instanceof PsiFile) break; element = element.getParent(); } if (referencesList.isEmpty()) return null; if (referencesList.size() == 1) return referencesList.get(0); return new PsiMultiReference(referencesList.toArray(new PsiReference[referencesList.size()]), referencesList.get(referencesList.size() - 1).getElement()); }
@Override @NotNull public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) { return new XmlElementVisitor() { @Override public void visitXmlToken(final XmlToken token) { if (token.getTokenType() == XmlTokenType.XML_NAME) { PsiElement element = token.getPrevSibling(); while(element instanceof PsiWhiteSpace) element = element.getPrevSibling(); if (element instanceof XmlToken && ((XmlToken)element).getTokenType() == XmlTokenType.XML_START_TAG_START) { PsiElement parent = element.getParent(); if (parent instanceof XmlTag && !(token.getNextSibling() instanceof OuterLanguageElement)) { XmlTag tag = (XmlTag)parent; checkTag(tag, holder, isOnTheFly); } } } } @Override public void visitXmlAttribute(final XmlAttribute attribute) { checkAttribute(attribute, holder, isOnTheFly); } }; }
@Override protected Boolean compute(PsiElement parent, Object p) { OuterLanguageElement element = PsiTreeUtil.getChildOfType(parent, OuterLanguageElement.class); if (element == null) { // JspOuterLanguageElement is located under XmlText for (PsiElement child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { if (child instanceof XmlText) { element = PsiTreeUtil.getChildOfType(child, OuterLanguageElement.class); if (element != null) { break; } } } } if (element == null) return false; PsiFile containingFile = parent.getContainingFile(); return containingFile.getViewProvider().getBaseLanguage() != containingFile.getLanguage(); }
@Override public void visitXmlProcessingInstruction(XmlProcessingInstruction processingInstruction) { super .visitXmlProcessingInstruction(processingInstruction); PsiElement parent = processingInstruction.getParent(); if (parent instanceof XmlProlog && processingInstruction.getText().startsWith("<?xml")) { for(PsiElement e = PsiTreeUtil.prevLeaf(processingInstruction); e != null; e = PsiTreeUtil.prevLeaf(e)) { if (e instanceof PsiWhiteSpace && PsiTreeUtil.prevLeaf(e) != null || e instanceof OuterLanguageElement) { continue; } PsiElement eParent = e.getParent(); if (eParent instanceof PsiComment) e = eParent; if (eParent instanceof XmlProcessingInstruction) break; String description = XmlErrorMessages.message("xml.declaration.should.precede.all.document.content"); addToResults(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(e).descriptionAndTooltip(description).create()); } } checkReferences(processingInstruction); }
private void createLeafBlocks(ASTNode node, List<Block> result) { if (node instanceof OuterLanguageElement) { processChild(result, node, null, null, null); return; } ASTNode child = node.getFirstChildNode(); if (child == null && !(node instanceof PsiWhiteSpace) && node.getElementType() != TokenType.ERROR_ELEMENT && node.getTextLength() > 0) { result.add(new ReadOnlyBlock(node)); return; } while (child != null) { createLeafBlocks(child, result); child = child.getTreeNext(); } }
protected List<Block> splitComment() { if (myNode.getElementType() != XmlElementType.XML_COMMENT) return EMPTY; final ArrayList<Block> result = new ArrayList<Block>(3); ASTNode child = myNode.getFirstChildNode(); boolean hasOuterLangElements = false; while (child != null) { if (child instanceof OuterLanguageElement) { hasOuterLangElements = true; } result.add(new XmlBlock(child, null, null, myXmlFormattingPolicy, getChildIndent(), null, isPreserveSpace())); child = child.getTreeNext(); } if (hasOuterLangElements) { return result; } else { return EMPTY; } }
private static boolean suggestImport(PsiElement context) { if (context.getParent() != null && !(context.getParent() instanceof PsiErrorElement) && GroovyCompletionUtil.isNewStatement(context, false) && context.getParent().getParent() instanceof GroovyFile) { return true; } final PsiElement leaf = GroovyCompletionUtil.getLeafByOffset(context.getTextRange().getStartOffset() - 1, context); if (leaf != null) { PsiElement parent = leaf.getParent(); if (parent instanceof GroovyFile) { return GroovyCompletionUtil.isNewStatement(context, false); } } return context.getTextRange().getStartOffset() == 0 && !(context instanceof OuterLanguageElement); }
@Override public void checkApplicability(final PsiFile psiFile, final Editor editor) throws IncorrectOperationException { final JspFile jspFile = (JspFile)psiFile; final TextRange selectedRange = JavaI18nUtil.getSelectedRange(editor, jspFile); // must contain no or balanced tags only // must not contain scriptlets or custom tags PsiFile root = jspFile.getBaseLanguageRoot(); root.accept(new PsiRecursiveElementVisitor(){ @Override public void visitElement(PsiElement element) { TextRange elementRange = element.getTextRange(); if (elementRange.intersectsStrict(selectedRange)) { // in JSPX base language root is a Jspx file itself if (jspFile.getLanguage() != StdLanguages.JSPX && element instanceof OuterLanguageElement || element instanceof XmlTag && !selectedRange.contains(elementRange) && (!elementRange.contains(selectedRange) || !((XmlTag)element).getValue().getTextRange().contains(selectedRange))) { throw new IncorrectOperationException(CodeInsightBundle.message("i18nize.jsp.error")); } } super.visitElement(element); } }); }
@Override @Nullable public PsiElement findElementAt(int offset, @NotNull Class<? extends Language> lang) { final PsiFile mainRoot = getPsi(getBaseLanguage()); PsiElement ret = null; for (final Language language : getLanguages()) { if (!ReflectionCache.isAssignable(lang, language.getClass())) continue; if (lang.equals(Language.class) && !getLanguages().contains(language)) continue; final PsiFile psiRoot = getPsi(language); final PsiElement psiElement = findElementAt(psiRoot, offset); if (psiElement == null || psiElement instanceof OuterLanguageElement) continue; if (ret == null || psiRoot != mainRoot) { ret = psiElement; } } return ret; }
private boolean testSelectionForNonComments() { SelectionModel model = myEditor.getSelectionModel(); if (!model.hasSelection()) { return true; } TextRange range = new TextRange(model.getSelectionStart(), model.getSelectionEnd() - 1); for (PsiElement element = myFile.findElementAt(range.getStartOffset()); element != null && range.intersects(element.getTextRange()); element = element.getNextSibling()) { if (element instanceof OuterLanguageElement) { if (!isInjectedWhiteSpace(range, (OuterLanguageElement)element)) { return false; } } else { if (!isWhiteSpaceOrComment(element, range)) { return false; } } } return true; }
private void createLeafBlocks(ASTNode node, List<Block> result) { if (node instanceof OuterLanguageElement) { processChild(result, node, null, null, null); return; } ASTNode child = node.getFirstChildNode(); if (child == null && !(node instanceof PsiWhiteSpace) && node.getElementType() != TokenType.ERROR_ELEMENT) { result.add(new ReadOnlyBlock(node)); return; } while (child != null) { createLeafBlocks(child, result); child = child.getTreeNext(); } }
private List<Block> splitComment() { if (myNode.getElementType() != XmlElementType.XML_COMMENT) return EMPTY; final ArrayList<Block> result = new ArrayList<Block>(3); ASTNode child = myNode.getFirstChildNode(); boolean hasOuterLangElements = false; while (child != null) { if (child instanceof OuterLanguageElement) { hasOuterLangElements = true; } result.add(new XmlBlock(child, null, null, myXmlFormattingPolicy, getChildIndent(), null, isPreserveSpace())); child = child.getTreeNext(); } if (hasOuterLangElements) { return result; } else { return EMPTY; } }
private static boolean suggestImport(PsiElement context) { if (context.getParent() != null && !(context.getParent() instanceof PsiErrorElement) && isNewStatement(context, false) && context.getParent().getParent() instanceof GroovyFile) { return true; } final PsiElement leaf = getLeafByOffset(context.getTextRange().getStartOffset() - 1, context); if (leaf != null) { PsiElement parent = leaf.getParent(); if (parent instanceof GroovyFile) { return isNewStatement(context, false); } } return context.getTextRange().getStartOffset() == 0 && !(context instanceof OuterLanguageElement); }
public boolean shouldHighlightErrorElement(@NotNull PsiErrorElement element) { PsiFile templateLanguageFile = PsiUtilCore.getTemplateLanguageFile(element.getContainingFile()); if (templateLanguageFile == null) { return true; } Language language = templateLanguageFile.getLanguage(); if (language != LatteLanguage.INSTANCE) { return true; } if (element.getParent() instanceof XmlElement || element.getParent() instanceof CssElement) { return false; } if (element.getParent().getLanguage() == LatteLanguage.INSTANCE) { return true; } PsiElement nextSibling; for (nextSibling = PsiTreeUtil.nextLeaf(element); nextSibling instanceof PsiWhiteSpace; nextSibling = nextSibling.getNextSibling()); PsiElement psiElement = nextSibling == null ? null : PsiTreeUtil.findCommonParent(nextSibling, element); boolean nextIsOuterLanguageElement = nextSibling instanceof OuterLanguageElement || nextSibling instanceof LatteMacroClassic; return !nextIsOuterLanguageElement || psiElement == null || psiElement instanceof PsiFile; }
@Nullable @RequiredReadAction public static PsiReference findReferenceAt(PsiElement thisElement, int offset, @Nullable Language lang) { if (thisElement == null) return null; PsiElement element = lang != null ? thisElement.getContainingFile().getViewProvider().findElementAt(offset, lang) : thisElement.findElementAt(offset); if (element == null || element instanceof OuterLanguageElement) return null; offset = thisElement.getTextRange().getStartOffset() + offset - element.getTextRange().getStartOffset(); List<PsiReference> referencesList = new ArrayList<PsiReference>(); while (element != null) { addReferences(offset, element, referencesList); if (element instanceof PsiFile) break; if (element instanceof HintedReferenceHost && !((HintedReferenceHost)element).shouldAskParentForReferences(new PsiReferenceService.Hints(null, offset))) { break; } offset = element.getStartOffsetInParent() + offset; element = element.getParent(); } if (referencesList.isEmpty()) return null; if (referencesList.size() == 1) return referencesList.get(0); return new PsiMultiReference(referencesList.toArray(new PsiReference[referencesList.size()]), referencesList.get(referencesList.size() - 1).getElement()); }
@Override @Nullable public PsiElement findElementAt(int offset, @Nonnull Class<? extends Language> lang) { final PsiFile mainRoot = getPsi(getBaseLanguage()); PsiElement ret = null; for (final Language language : getLanguages()) { if (!ReflectionUtil.isAssignable(lang, language.getClass())) continue; if (lang.equals(Language.class) && !getLanguages().contains(language)) continue; final PsiFile psiRoot = getPsi(language); final PsiElement psiElement = findElementAt(psiRoot, offset); if (psiElement == null || psiElement instanceof OuterLanguageElement) continue; if (ret == null || psiRoot != mainRoot) { ret = psiElement; } } return ret; }
private static boolean containsOuterLanguageElements(@NotNull PsiElement element) { PsiElement child = element.getFirstChild(); while(child != null) { if(child instanceof CompositeElement) { return containsOuterLanguageElements(child); } else if(child instanceof OuterLanguageElement) { return true; } child = child.getNextSibling(); } return false; }
@NotNull @Override protected ElementFilter compute() { return new OrFilter(new AndFilter(new LeftNeighbour(new OrFilter(new AndFilter(new TextFilter("{", "}", ";", ":", "else"), new NotFilter(new SuperParentFilter(new ClassFilter (PsiAnnotation.class)))), new ElementFilter() { @Override public boolean isAcceptable(Object element, @Nullable PsiElement context) { return ((PsiElement) element).getText().endsWith("*/"); } @Override public boolean isClassAcceptable(Class hintClass) { return true; } }, new ClassFilter(OuterLanguageElement.class), new AndFilter(new TextFilter(")"), new NotFilter(new OrFilter(new ParentElementFilter(new ClassFilter(PsiExpressionList.class)), new ParentElementFilter(new ClassFilter(PsiParameterList.class)), new ParentElementFilter(new ClassFilter(PsiTypeCastExpression.class))))))), new NotFilter(new TextFilter("."))), START_OF_CODE_FRAGMENT); }
private static ASTNode[] getLuaChildren(final ASTNode node) { PsiElement psi = node.getPsi(); if (psi instanceof OuterLanguageElement) { TextRange range = node.getTextRange(); ArrayList<ASTNode> childList = new ArrayList<ASTNode>(); PsiFile LuaFile = psi.getContainingFile().getViewProvider().getPsi(LuaFileType.LUA_LANGUAGE); if (LuaFile instanceof LuaPsiFileBase) { addChildNodes(LuaFile, childList, range); } return childList.toArray(new ASTNode[childList.size()]); } return node.getChildren(null); }
@NotNull @Override protected ElementFilter compute() { return new OrFilter( new AndFilter( new LeftNeighbour( new OrFilter( new AndFilter ( new TextFilter("{", "}", ";", ":", "else"), new NotFilter ( new SuperParentFilter(new ClassFilter(PsiAnnotation.class)) ) ), new TextFilter("*/"), new TokenTypeFilter(JspElementType.HOLDER_TEMPLATE_DATA), new ClassFilter(OuterLanguageElement.class), new AndFilter( new TextFilter(")"), new NotFilter( new OrFilter( new ParentElementFilter(new ClassFilter(PsiExpressionList.class)), new ParentElementFilter(new ClassFilter(PsiParameterList.class)), new ParentElementFilter(new ClassFilter(PsiTypeCastExpression.class)) ) ) ))), new NotFilter(new TextFilter(".")) ), START_OF_CODE_FRAGMENT ); }
@Override public void encodeInformation(final TreeElement element, final ASTNode original, final Map<Object, Object> encodingState) { boolean shallEncodeEscapedTexts = shallEncodeEscapedTexts(original, encodingState); if (original instanceof CompositeElement) { if (original.getElementType() == JavaElementType.JAVA_CODE_REFERENCE || original.getElementType() == JavaElementType.REFERENCE_EXPRESSION) { encodeInformationInRef(element, original); } else if (original.getElementType() == JavaElementType.MODIFIER_LIST && (original.getTreeParent().getElementType() == JavaElementType.FIELD || original.getTreeParent().getElementType() == JavaElementType.METHOD || original.getTreeParent().getElementType() == JavaElementType.ANNOTATION_METHOD) && original.getTreeParent().getTreeParent().getElementType() == JavaElementType.CLASS && (((PsiClass)SourceTreeToPsiMap.treeElementToPsi(original.getTreeParent().getTreeParent())).isInterface() || ((PsiClass)SourceTreeToPsiMap.treeElementToPsi(original.getTreeParent().getTreeParent())).isAnnotationType())) { element.putUserData(INTERFACE_MODIFIERS_FLAG_KEY, Boolean.TRUE); } } else if (shallEncodeEscapedTexts && original instanceof LeafElement && !(original instanceof OuterLanguageElement)) { if (!isInCData(original)) { final String originalText = element.getText(); final String unescapedText = StringUtil.unescapeXml(originalText); if (!Comparing.equal(originalText, unescapedText)) { LeafElement replaced = ((LeafElement)element).rawReplaceWithText(unescapedText); element.putCopyableUserData(ALREADY_ESCAPED, null); replaced.putCopyableUserData(ALREADY_ESCAPED, null); } } } }
private static boolean isInCData(ASTNode element) { ASTNode leaf = element; while (leaf != null) { if (leaf instanceof OuterLanguageElement) { return leaf.getText().indexOf("<![CDATA[") >= 0; } leaf = TreeUtil.prevLeaf(leaf); } return false; }
private static boolean checkJspTexts(final ASTNode leaf) { ASTNode child = leaf.getFirstChildNode(); while(child != null){ if(child instanceof OuterLanguageElement) return true; child = child.getTreeNext(); } return false; }
public static List<PsiElement> getInjectedElements(@NotNull OuterLanguageElement outerLanguageElement) { PsiElement psi = outerLanguageElement.getContainingFile().getViewProvider().getPsi(outerLanguageElement.getLanguage()); TextRange injectionRange = outerLanguageElement.getTextRange(); List<PsiElement> res = ContainerUtil.newArrayList(); assert psi != null : outerLanguageElement; for (PsiElement element = psi.findElementAt(injectionRange.getStartOffset()); element != null && injectionRange.intersectsStrict(element.getTextRange()); element = element.getNextSibling()) { res.add(element); } return res; }
@Override @NotNull public Language getLanguage() { PsiElement master = this; while (true) { master = master.getNextSibling(); if (master == null || master instanceof OuterLanguageElement) return getParent().getLanguage(); if (master instanceof PsiWhiteSpace || master instanceof PsiErrorElement) continue; return master.getLanguage(); } }
public static void checkForOuters(ASTNode element) { if (element instanceof OuterLanguageElement && element.getCopyableUserData(OUTER_OK) == null) { throw new IllegalArgumentException("Outer element " + element + " is not allowed here"); } ASTNode child = element.getFirstChildNode(); while (child != null) { checkForOuters(child); child = child.getTreeNext(); } }
private boolean isInjectedWhiteSpace(@NotNull TextRange range, @NotNull OuterLanguageElement element) { PsiElement psi = element.getContainingFile().getViewProvider().getPsi(element.getLanguage()); if (psi == null) { return false; } List<PsiElement> injectedElements = PsiTreeUtil.getInjectedElements(element); for (PsiElement el : injectedElements) { if (!isWhiteSpaceOrComment(el, range)) { return false; } } return true; }