@Override public Optional<String> extractTextFromElement(PsiElement element, boolean concatString, boolean stripWhitespace) { // maybe its xml then try that if (element instanceof XmlAttributeValue) { return Optional.ofNullable(((XmlAttributeValue) element).getValue()); } else if (element instanceof XmlText) { return Optional.ofNullable(((XmlText) element).getValue()); } else if (element instanceof XmlToken) { // it may be a token which is a part of an combined attribute if (concatString) { XmlAttributeValue xml = PsiTreeUtil.getParentOfType(element, XmlAttributeValue.class); if (xml != null) { return Optional.ofNullable(getInnerText(xml.getValue())); } } else { String returnText = element.getText(); final PsiElement prevSibling = element.getPrevSibling(); if (prevSibling != null && prevSibling.getText().equalsIgnoreCase("&")) { returnText = prevSibling.getText() + returnText; } return Optional.ofNullable(getInnerText(returnText)); } } return Optional.empty(); }
@Nullable private PsiElement getPsiElement() { if (myDomElement instanceof DomFileElement) { return ((DomFileElement)myDomElement).getFile(); } if (myDomElement instanceof GenericAttributeValue) { final GenericAttributeValue attributeValue = (GenericAttributeValue)myDomElement; final XmlAttributeValue value = attributeValue.getXmlAttributeValue(); return value != null && StringUtil.isNotEmpty(value.getText()) ? value : attributeValue.getXmlElement(); } final XmlTag tag = myDomElement.getXmlTag(); if (myDomElement instanceof GenericValue && tag != null) { final XmlText[] textElements = tag.getValue().getTextElements(); if (textElements.length > 0) { return textElements[0]; } } return tag; }
@Override @NotNull public TextRange getRangeInElement(@NotNull final XmlTag tag) { if (tag.getSubTags().length > 0) { // Text range in tag with subtags is not supported, return empty range, consider making this function nullable. return TextRange.EMPTY_RANGE; } final XmlTagValue value = tag.getValue(); final XmlText[] texts = value.getTextElements(); switch (texts.length) { case 0: return value.getTextRange().shiftRight(-tag.getTextOffset()); case 1: return getValueRange(texts[0]); default: return TextRange.EMPTY_RANGE; } }
public void testInsertAtOffset() throws Exception { new WriteCommandAction(getProject()) { @Override protected void run(@NotNull final Result result) throws Throwable { String xml = "<root>0123456789</root>"; XmlFile file = (XmlFile)PsiFileFactory.getInstance(getProject()) .createFileFromText("foo.xml", StdFileTypes.XML, xml, (long)1, true, false); //System.out.println(DebugUtil.psiToString(file, false)); XmlTag root = file.getDocument().getRootTag(); final XmlText text1 = root.getValue().getTextElements()[0]; assertFalse(CodeEditUtil.isNodeGenerated(root.getNode())); final XmlText text = text1; final XmlElement element = text.insertAtOffset(XmlElementFactory.getInstance(getProject()).createTagFromText("<bar/>"), 5); assertNotNull(element); assertTrue(element instanceof XmlText); assertEquals("01234", element.getText()); assertEquals("<root>01234<bar/>56789</root>", text.getContainingFile().getText()); } }.execute(); }
@NotNull @Override public ThreeState shouldSkipAutopopup(@NotNull PsiElement contextElement, @NotNull PsiFile psiFile, int offset) { ASTNode node = contextElement.getNode(); if (node != null && node.getElementType() == XmlTokenType.XML_DATA_CHARACTERS) { PsiElement parent = contextElement.getParent(); if (parent instanceof XmlText || parent instanceof XmlDocument) { String contextElementText = contextElement.getText(); int endOffset = offset - contextElement.getTextRange().getStartOffset(); String prefix = contextElementText.substring(0, Math.min(contextElementText.length(), endOffset)); if (!StringUtil.startsWithChar(prefix, '<') && !StringUtil.startsWithChar(prefix, '&')) { return ThreeState.YES; } } } return ThreeState.UNSURE; }
@Nullable @Override public PsiElement adjustElement(Editor editor, int flags, @Nullable PsiElement element, @Nullable PsiElement contextElement) { if (element != null) return element; if (contextElement == null) return null; final PsiElement parent = contextElement.getParent(); if (parent instanceof XmlText || parent instanceof XmlAttributeValue) { final PsiElement gParent = parent.getParent(); if (gParent == null) return null; return TargetElementUtil.getInstance().findTargetElement(editor, flags, gParent.getTextRange().getStartOffset() + 1); } else if (parent instanceof XmlTag || parent instanceof XmlAttribute) { return TargetElementUtil.getInstance().findTargetElement(editor, flags, parent.getTextRange().getStartOffset() + 1); } return null; }
public static boolean isInContext(@NotNull PsiElement element) { if (PsiTreeUtil.getParentOfType(element, XmlComment.class) != null) { return false; } if (PsiTreeUtil.getParentOfType(element, XmlText.class) != null) { return true; } if (element.getNode().getElementType() == XmlTokenType.XML_START_TAG_START) { return true; } PsiElement parent = element.getParent(); if (parent instanceof PsiErrorElement) { parent = parent.getParent(); } return parent instanceof XmlDocument; }
private static boolean checkAndMove(Editor editor, Document doc, int offset, PsiElement current) { if (current == null) return false; if (current.getParent() instanceof XmlText) { final int line = doc.getLineNumber(offset); final int lineStart = doc.getLineStartOffset(line); final int lineEnd = doc.getLineEndOffset(line); final CharSequence text = doc.getCharsSequence().subSequence(lineStart, lineEnd); if (StringUtil.isEmptyOrSpaces(text) && moveCaret(editor, current, lineEnd)) { return true; } } else if (isEmptyEditPoint(current) && moveCaret(editor, current, current.getTextRange().getStartOffset())) { return true; } return false; }
@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 protected boolean isAvailableOnElementInEditorAndFile(@NotNull PsiElement element, @NotNull Editor editor, @NotNull PsiFile file, @NotNull DataContext context) { final XmlTag[] tags = getXmlTagsFromExternalContext(context); if (tags.length > 0) { return AndroidFacet.getInstance(tags[0]) != null && isEnabledForTags(tags); } final TextRange range = getNonEmptySelectionRange(editor); if (range != null) { final Pair<PsiElement, PsiElement> psiRange = getExtractableRange( file, range.getStartOffset(), range.getEndOffset()); return psiRange != null && isEnabledForPsiRange(psiRange.getFirst(), psiRange.getSecond()); } if (element == null || AndroidFacet.getInstance(element) == null || PsiTreeUtil.getParentOfType(element, XmlText.class) != null) { return false; } final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class); return tag != null && isEnabledForTags(new XmlTag[]{tag}); }
/** * Returns the text content of a given tag */ public static String getTextContent(@NonNull XmlTag tag) { // We can't just use tag.getValue().getTrimmedText() here because we need to remove // intermediate elements such as <xliff> text: // TODO: Make sure I correct handle HTML content for XML items in <string> nodes! // For example, for the following string we want to compute "Share with %s": // <string name="share">Share with <xliff:g id="application_name" example="Bluetooth">%s</xliff:g></string> XmlTag[] subTags = tag.getSubTags(); XmlText[] textElements = tag.getValue().getTextElements(); if (subTags.length == 0) { if (textElements.length == 1) { return getXmlTextValue(textElements[0]); } else if (textElements.length == 0) { return ""; } } StringBuilder sb = new StringBuilder(40); appendText(sb, tag); return sb.toString(); }
@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; } } }
@NotNull @Override public PsiReference[] getReferencesByElement(@NotNull final PsiElement element, @NotNull final ProcessingContext context) { final XmlText xmlText = (XmlText)element.getParent(); if (!MavenPluginParamInfo.isSimpleText(xmlText)) return PsiReference.EMPTY_ARRAY; MavenPluginParamInfo.ParamInfoList paramInfos = MavenPluginParamInfo.getParamInfoList(xmlText); for (ParamInfo info : paramInfos) { MavenParamReferenceProvider providerInstance = info.getProviderInstance(); if (providerInstance != null) { return providerInstance.getReferencesByElement(xmlText, paramInfos.getDomCfg(), context); } } return PsiReference.EMPTY_ARRAY; }
@Nullable @Override public Language getLanguage(@NotNull XmlText xmlText, @NotNull MavenDomConfiguration configuration) { // Parameter 'source' of gmaven-plugin can be a peace of groovy code or file path or URL. String text = xmlText.getText(); if (text.indexOf('\n') >= 0) { // URL or file path can not be multiline so it's a groovy code return GroovyLanguage.INSTANCE; } if (text.indexOf('(') >= 0) { // URL or file path hardly contains '(', but code usually contain '(' return GroovyLanguage.INSTANCE; } return null; }
@NotNull private Collection<PsiElement> getControllerActionElements(@NotNull XmlText xmlText) { PsiElement xmlTag = xmlText.getParent(); if(!(xmlTag instanceof XmlTag)) { return Collections.emptyList(); } String controllerName = ShopwareXmlCompletion.getControllerOnScope((XmlTag) xmlTag); if (controllerName == null) { return Collections.emptyList(); } String value = xmlText.getValue(); Collection<PsiElement> targets = new HashSet<>(); ShopwareUtil.collectControllerAction(xmlText.getProject(), controllerName, (method, methodStripped, moduleName, controllerName1) -> { if(value.equalsIgnoreCase(methodStripped)) { targets.add(method); } }, "Backend"); return targets; }
@Nullable @Override public PsiElement adjustElement(final Editor editor, final int flags, final PsiElement element, final PsiElement contextElement) { if (element != null) { if (element instanceof PsiAnonymousClass) { return ((PsiAnonymousClass)element).getBaseClassType().resolve(); } return element; } if (contextElement == null) return null; final PsiElement parent = contextElement.getParent(); if (parent instanceof XmlText || parent instanceof XmlAttributeValue) { return TargetElementUtilBase.getInstance().findTargetElement(editor, flags, parent.getParent().getTextRange().getStartOffset() + 1); } else if (parent instanceof XmlTag || parent instanceof XmlAttribute) { return TargetElementUtilBase.getInstance().findTargetElement(editor, flags, parent.getTextRange().getStartOffset() + 1); } return null; }
public void testInsertAtOffset() throws Exception { new WriteCommandAction(getProject()) { @Override protected void run(final Result result) throws Throwable { String xml = "<root>0123456789</root>"; XmlFile file = (XmlFile)PsiFileFactory.getInstance(getProject()) .createFileFromText("foo.xml", StdFileTypes.XML, xml, (long)1, true, false); //System.out.println(DebugUtil.psiToString(file, false)); XmlTag root = file.getDocument().getRootTag(); final XmlText text1 = root.getValue().getTextElements()[0]; assertFalse(CodeEditUtil.isNodeGenerated(root.getNode())); final XmlText text = text1; final XmlElement element = text.insertAtOffset(XmlElementFactory.getInstance(getProject()).createTagFromText("<bar/>"), 5); assertNotNull(element); assertTrue(element instanceof XmlText); assertEquals("01234", element.getText()); assertEquals("<root>01234<bar/>56789</root>", text.getContainingFile().getText()); } }.execute(); }
public XmlText handleContentChange(XmlText text, TextRange range, String newContent) throws IncorrectOperationException { final String newValue; final String value = text.getValue(); if (range.equals(getRangeInElement(text))) { newValue = newContent; } else { final StringBuilder replacement = new StringBuilder(value); replacement.replace( range.getStartOffset(), range.getEndOffset(), newContent ); newValue = replacement.toString(); } if (Comparing.equal(value, newValue)) return text; if (newValue.length() > 0) { text.setValue(newValue); } else { text.deleteChildRange(text.getFirstChild(), text.getLastChild()); } return text; }
public TextRange getRangeInElement(final XmlTag tag) { if (tag.getSubTags().length > 0) { // Text range in tag with subtags is not supported, return empty range, consider making this function nullable. return TextRange.EMPTY_RANGE; } final XmlTagValue value = tag.getValue(); final XmlText[] texts = value.getTextElements(); switch (texts.length) { case 0: return value.getTextRange().shiftRight(-tag.getTextOffset()); case 1: return getValueRange(texts[0]); default: return TextRange.EMPTY_RANGE; } }
@Nullable @Override public Language getLanguage(@NotNull XmlText xmlText, @NotNull MavenDomConfiguration configuration) { // Parameter 'source' of gmaven-plugin can be a peace of groovy code or file path or URL. String text = xmlText.getText(); if (text.indexOf('\n') >= 0) { // URL or file path can not be multiline so it's a groovy code return GroovyFileType.GROOVY_LANGUAGE; } if (text.indexOf('(') >= 0) { // URL or file path hardly contains '(', but code usually contain '(' return GroovyFileType.GROOVY_LANGUAGE; } return null; }
/** * get all text in xml tag including sub tags * * @param xmlTag xml tag * @return xml text */ @SuppressWarnings({"ConstantConditions"}) public static String getAllTextInTag(XmlTag xmlTag) { StringBuilder sql = new StringBuilder(); PsiElement[] children = xmlTag.getChildren(); for (PsiElement child : children) { if (child instanceof XmlTag) { XmlTag tag = (XmlTag) child; if (tag.getName().equals("include")) { // include element XmlAttribute refid = tag.getAttribute("refid"); if (refid != null && StringUtil.isNotEmpty(refid.getText())) { PsiElement psiElement = refid.getValueElement().getReference().resolve(); if (psiElement instanceof XmlTag) { XmlTag target = (XmlTag) psiElement; sql.append(" ").append(target.getText()); } } } else { sql.append(getAllTextInTag(tag)); } } else if (child instanceof XmlText) { sql.append(" ").append(((XmlText) child).getValue()); } } return sql.toString(); }
/** * get the SQL code in xml tag * * @param xmlTag xml tag * @return SQL in xml tag */ @SuppressWarnings({"ConstantConditions"}) @NotNull public static String getSQLForXmlTag(XmlTag xmlTag) { StringBuilder sql = new StringBuilder(); PsiElement[] children = xmlTag.getChildren(); for (PsiElement child : children) { if (child instanceof XmlTag) { XmlTag tag = (XmlTag) child; if (tag.getName().equals("include")) { XmlAttribute refid = tag.getAttribute("refid"); if (refid != null && StringUtil.isNotEmpty(refid.getText())) { PsiElement psiElement = refid.getValueElement().getReference().resolve(); if (psiElement != null && psiElement instanceof XmlTag) { Sql sqlDom = (Sql) DomManager.getDomManager(psiElement.getProject()).getDomElement((XmlTag) psiElement); if (sqlDom != null) sql.append(" ").append(sqlDom.getSQL()); } } } } else if (child instanceof XmlText) { sql.append(" ").append(((XmlText) child).getValue()); } } return sql.toString(); }
@NotNull @Override public ResolveResult[] multiResolve(boolean b) { PsiElement element = getElement(); PsiElement parent = element.getParent(); String text = null; if(parent instanceof XmlText) { // <route><default key="_controller">Fo<caret>o\Bar</default></route> text = parent.getText(); } else if(parent instanceof XmlAttribute) { // <route controller=""/> text = ((XmlAttribute) parent).getValue(); } if(text == null || StringUtils.isBlank(text)) { return new ResolveResult[0]; } return PsiElementResolveResult.createResults( RouteHelper.getMethodsOnControllerShortcut(getElement().getProject(), text) ); }
@Override @NotNull public XmlText[] getTextElements() { XmlText[] textElements = myTextElements; if(textElements != null) { return textElements; } final List<XmlText> textElementsList = new ArrayList<XmlText>(); for(final XmlTagChild element : myElements) { if(element instanceof XmlText) { textElementsList.add((XmlText) element); } } return myTextElements = textElementsList.isEmpty() ? XmlText.EMPTY_ARRAY : ContainerUtil.toArray(textElementsList, new XmlText[textElementsList.size()]); }
@Override @NotNull public String getTrimmedText() { String trimmedText = myTrimmedText; if(trimmedText != null) { return trimmedText; } final StringBuilder consolidatedText = new StringBuilder(); final XmlText[] textElements = getTextElements(); for(final XmlText textElement : textElements) { consolidatedText.append(textElement.getValue()); } return myTrimmedText = consolidatedText.toString().trim(); }
@Override public boolean hasCDATA() { for(XmlText xmlText : myTextElements) { PsiElement[] children = xmlText.getChildren(); for(PsiElement child : children) { if(child.getNode().getElementType() == XmlElementType.XML_CDATA) { return true; } } } return false; }
public static boolean shouldSkipAutopopupInHtml(@NotNull PsiElement contextElement, int offset) { ASTNode node = contextElement.getNode(); if(node != null && node.getElementType() == XmlTokenType.XML_DATA_CHARACTERS) { PsiElement parent = contextElement.getParent(); if(parent instanceof XmlText || parent instanceof XmlDocument) { String contextElementText = contextElement.getText(); int endOffset = offset - contextElement.getTextRange().getStartOffset(); String prefix = contextElementText.substring(0, Math.min(contextElementText.length(), endOffset)); return !StringUtil.startsWithChar(prefix, '<') && !StringUtil.startsWithChar(prefix, '&'); } } return false; }
public static boolean isWithinTag(Lookup lookup) { if(isInXmlContext(lookup)) { PsiElement psiElement = lookup.getPsiElement(); final PsiElement parentElement = psiElement != null ? psiElement.getParent() : null; if(parentElement instanceof XmlTag) { return true; } if(parentElement instanceof PsiErrorElement && parentElement.getParent() instanceof XmlDocument) { return true; } return (parentElement instanceof XmlDocument || parentElement instanceof XmlText) && (psiElement.textMatches("<") || psiElement.textMatches("\"")); } return false; }
@Override @NotNull public TextRange getRangeInElement(@NotNull final XmlTag tag) { if(tag.getSubTags().length > 0) { // Text range in tag with subtags is not supported, return empty range, consider making this function nullable. return TextRange.EMPTY_RANGE; } final XmlTagValue value = tag.getValue(); final XmlText[] texts = value.getTextElements(); switch(texts.length) { case 0: return value.getTextRange().shiftRight(-tag.getTextOffset()); case 1: return getValueRange(texts[0]); default: return TextRange.EMPTY_RANGE; } }
public static TextRange[] getValueRanges(@NotNull final XmlTag tag) { final XmlTagValue value = tag.getValue(); final XmlText[] texts = value.getTextElements(); if(texts.length == 0) { return new TextRange[]{value.getTextRange().shiftRight(-tag.getTextOffset())}; } else { final TextRange[] ranges = new TextRange[texts.length]; for(int i = 0; i < texts.length; i++) { ranges[i] = getValueRange(texts[i]); } return ranges; } }
@Override public void injectLanguages(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement host) { if (!(host instanceof XmlText)) { return; } XmlTag scriptTag = ((XmlText)host).getParentTag(); if (!"script".equalsIgnoreCase(scriptTag.getLocalName())) { return; } String mimeType = scriptTag.getAttributeValue("type"); Collection<Language> languages = Language.findInstancesByMimeType(mimeType); Language language = languages.isEmpty() ? null : languages.iterator().next(); if (language != null && LanguageUtil.isInjectableLanguage(language)) { registrar .startInjecting(language) .addPlace(null, null, (PsiLanguageInjectionHost)host, TextRange.create(0, host.getTextLength())) .doneInjecting(); } }
public boolean isInContext(@NotNull final PsiFile file, final int offset) { if (!MuleConfigUtils.isMuleFile(file)) { return false; } PsiElement element = file.findElementAt(offset); return element != null && PsiTreeUtil.getParentOfType(element, XmlText.class) != null; }
@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 boolean available(PsiElement element) { PsiElement context = element.getContext(); return context instanceof JSBlockStatement || context instanceof CssDeclaration || context instanceof XmlAttributeValue || context instanceof XmlText; }