use of com.intellij.psi.html.HtmlTag in project intellij-community by JetBrains.
the class XmlHighlightVisitor method checkAttribute.
private void checkAttribute(XmlAttribute attribute) {
XmlTag tag = attribute.getParent();
if (tag == null)
return;
final String name = attribute.getName();
PsiElement prevLeaf = PsiTreeUtil.prevLeaf(attribute);
if (!(prevLeaf instanceof PsiWhiteSpace)) {
TextRange textRange = attribute.getTextRange();
HighlightInfoType type = tag instanceof HtmlTag ? HighlightInfoType.WARNING : HighlightInfoType.ERROR;
String description = XmlErrorMessages.message("attribute.should.be.preceded.with.space");
HighlightInfo info = HighlightInfo.newHighlightInfo(type).range(textRange.getStartOffset(), textRange.getStartOffset()).descriptionAndTooltip(description).create();
addToResults(info);
}
if (attribute.isNamespaceDeclaration() || XmlUtil.XML_SCHEMA_INSTANCE_URI.equals(attribute.getNamespace())) {
//checkReferences(attribute.getValueElement());
return;
}
XmlElementDescriptor elementDescriptor = tag.getDescriptor();
if (elementDescriptor == null || elementDescriptor instanceof AnyXmlElementDescriptor || ourDoJaxpTesting) {
return;
}
XmlAttributeDescriptor attributeDescriptor = elementDescriptor.getAttributeDescriptor(attribute);
if (attributeDescriptor == null) {
if (!XmlUtil.attributeFromTemplateFramework(name, tag)) {
final String localizedMessage = XmlErrorMessages.message("attribute.is.not.allowed.here", name);
final HighlightInfo highlightInfo = reportAttributeProblem(tag, name, attribute, localizedMessage);
if (highlightInfo != null) {
PsiFile file = tag.getContainingFile();
if (file != null) {
for (XmlUndefinedElementFixProvider fixProvider : Extensions.getExtensions(XmlUndefinedElementFixProvider.EP_NAME)) {
IntentionAction[] fixes = fixProvider.createFixes(attribute);
if (fixes != null) {
for (IntentionAction action : fixes) {
QuickFixAction.registerQuickFixAction(highlightInfo, action);
}
break;
}
}
}
}
}
} else {
checkDuplicateAttribute(tag, attribute);
// we skip resolve of attribute references since there is separate check when taking attribute descriptors
PsiReference[] attrRefs = attribute.getReferences();
doCheckRefs(attribute, attrRefs, !attribute.getNamespacePrefix().isEmpty() ? 2 : 1);
}
}
use of com.intellij.psi.html.HtmlTag in project intellij-community by JetBrains.
the class RequiredAttributesInspectionBase method hasAttribute.
private static boolean hasAttribute(XmlTag tag, String attrName) {
final XmlAttribute attribute = tag.getAttribute(attrName);
if (attribute == null)
return false;
if (attribute.getValueElement() != null)
return true;
if (!(tag instanceof HtmlTag))
return false;
final XmlAttributeDescriptor descriptor = attribute.getDescriptor();
return descriptor != null && HtmlUtil.isBooleanAttribute(descriptor, tag);
}
use of com.intellij.psi.html.HtmlTag in project intellij-community by JetBrains.
the class XmlGtTypedHandler method beforeCharTyped.
@Override
public Result beforeCharTyped(final char c, final Project project, Editor editor, PsiFile editedFile, final FileType fileType) {
final WebEditorOptions webEditorOptions = WebEditorOptions.getInstance();
if (c == '>' && webEditorOptions != null && webEditorOptions.isAutomaticallyInsertClosingTag() && fileContainsXmlLanguage(editedFile)) {
PsiDocumentManager.getInstance(project).commitAllDocuments();
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
FileViewProvider provider = editedFile.getViewProvider();
int offset = editor.getCaretModel().getOffset();
PsiElement element, elementAtCaret = null;
if (offset < editor.getDocument().getTextLength()) {
elementAtCaret = element = provider.findElementAt(offset, XMLLanguage.class);
if (element == null && offset > 0) {
// seems like a template language
// <xml_code><caret><outer_element>
elementAtCaret = element = provider.findElementAt(offset - 1, XMLLanguage.class);
}
if (!(element instanceof PsiWhiteSpace)) {
boolean nonAcceptableDelimiter = true;
if (element instanceof XmlToken) {
IElementType tokenType = ((XmlToken) element).getTokenType();
if (tokenType == XmlTokenType.XML_START_TAG_START || tokenType == XmlTokenType.XML_END_TAG_START) {
if (offset > 0) {
PsiElement previousElement = provider.findElementAt(offset - 1, XMLLanguage.class);
if (previousElement instanceof XmlToken) {
tokenType = ((XmlToken) previousElement).getTokenType();
element = previousElement;
nonAcceptableDelimiter = false;
}
}
} else if (tokenType == XmlTokenType.XML_NAME || tokenType == XmlTokenType.XML_TAG_NAME) {
if (element.getNextSibling() instanceof PsiErrorElement) {
nonAcceptableDelimiter = false;
}
}
if (tokenType == XmlTokenType.XML_TAG_END || tokenType == XmlTokenType.XML_EMPTY_ELEMENT_END && element.getTextOffset() == offset - 1) {
EditorModificationUtil.moveCaretRelatively(editor, 1);
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
return Result.STOP;
}
}
if (nonAcceptableDelimiter)
return Result.CONTINUE;
} else {
// check if right after empty end
PsiElement previousElement = provider.findElementAt(offset - 1, XMLLanguage.class);
if (previousElement instanceof XmlToken) {
final IElementType tokenType = ((XmlToken) previousElement).getTokenType();
if (tokenType == XmlTokenType.XML_EMPTY_ELEMENT_END) {
return Result.STOP;
}
}
}
PsiElement parent = element.getParent();
if (parent instanceof XmlText) {
final String text = parent.getText();
// check /
final int index = offset - parent.getTextOffset() - 1;
if (index >= 0 && text.charAt(index) == '/') {
// already seen /
return Result.CONTINUE;
}
element = parent.getPrevSibling();
} else if (parent instanceof XmlTag && !(element.getPrevSibling() instanceof XmlTag) && !(element.getPrevSibling() instanceof OuterLanguageElement)) {
element = parent;
} else if (parent instanceof XmlAttributeValue) {
element = parent;
}
} else {
element = provider.findElementAt(editor.getDocument().getTextLength() - 1, XMLLanguage.class);
if (element == null)
return Result.CONTINUE;
element = element.getParent();
}
if (offset > 0 && offset <= editor.getDocument().getTextLength()) {
if (editor.getDocument().getCharsSequence().charAt(offset - 1) == '/') {
// Some languages (e.g. GSP) allow character '/' in tag name.
return Result.CONTINUE;
}
}
if (element instanceof XmlAttributeValue) {
element = element.getParent().getParent();
}
while (element instanceof PsiWhiteSpace || element instanceof OuterLanguageElement) element = element.getPrevSibling();
if (element instanceof XmlDocument) {
// hack for closing tags in RHTML
element = element.getLastChild();
}
if (element == null)
return Result.CONTINUE;
if (!(element instanceof XmlTag)) {
if (element instanceof XmlTokenImpl && element.getPrevSibling() != null && element.getPrevSibling().getText().equals("<")) {
// tag is started and there is another text in the end
EditorModificationUtil.insertStringAtCaret(editor, "</" + element.getText() + ">", false, 0);
}
return Result.CONTINUE;
}
XmlTag tag = (XmlTag) element;
if (XmlUtil.getTokenOfType(tag, XmlTokenType.XML_TAG_END) != null)
return Result.CONTINUE;
if (XmlUtil.getTokenOfType(tag, XmlTokenType.XML_EMPTY_ELEMENT_END) != null)
return Result.CONTINUE;
final XmlToken startToken = XmlUtil.getTokenOfType(tag, XmlTokenType.XML_START_TAG_START);
if (startToken == null || !startToken.getText().equals("<"))
return Result.CONTINUE;
String name = tag.getName();
if (elementAtCaret instanceof XmlToken && (((XmlToken) elementAtCaret).getTokenType() == XmlTokenType.XML_NAME || ((XmlToken) elementAtCaret).getTokenType() == XmlTokenType.XML_TAG_NAME)) {
name = name.substring(0, offset - elementAtCaret.getTextOffset());
}
if (tag instanceof HtmlTag && HtmlUtil.isSingleHtmlTag(name))
return Result.CONTINUE;
if (name.isEmpty())
return Result.CONTINUE;
int tagOffset = tag.getTextRange().getStartOffset();
final XmlToken nameToken = XmlUtil.getTokenOfType(tag, XmlTokenType.XML_NAME);
if (nameToken != null && nameToken.getTextRange().getStartOffset() > offset)
return Result.CONTINUE;
HighlighterIterator iterator = ((EditorEx) editor).getHighlighter().createIterator(tagOffset);
if (BraceMatchingUtil.matchBrace(editor.getDocument().getCharsSequence(), editedFile.getFileType(), iterator, true, true)) {
PsiElement parent = tag.getParent();
boolean hasBalance = true;
loop: while (parent instanceof XmlTag) {
if (name.equals(((XmlTag) parent).getName())) {
hasBalance = false;
ASTNode astNode = XmlChildRole.CLOSING_TAG_NAME_FINDER.findChild(parent.getNode());
if (astNode == null) {
hasBalance = true;
break;
}
for (PsiElement el = parent.getNextSibling(); el != null; el = el.getNextSibling()) {
if (el instanceof PsiErrorElement && el.getText().startsWith("</" + name)) {
hasBalance = true;
break loop;
}
}
}
parent = parent.getParent();
}
if (hasBalance)
return Result.CONTINUE;
}
Collection<TextRange> cdataReformatRanges = null;
final XmlElementDescriptor descriptor = tag.getDescriptor();
EditorModificationUtil.insertStringAtCaret(editor, "</" + name + ">", false, 0);
if (descriptor instanceof XmlElementDescriptorWithCDataContent) {
final XmlElementDescriptorWithCDataContent cDataContainer = (XmlElementDescriptorWithCDataContent) descriptor;
cdataReformatRanges = ContainerUtil.newSmartList();
if (cDataContainer.requiresCdataBracesInContext(tag)) {
@NonNls final String cDataStart = "><![CDATA[";
final String inserted = cDataStart + "\n]]>";
EditorModificationUtil.insertStringAtCaret(editor, inserted, false, cDataStart.length());
int caretOffset = editor.getCaretModel().getOffset();
if (caretOffset >= cDataStart.length()) {
cdataReformatRanges.add(TextRange.from(caretOffset - cDataStart.length(), inserted.length() + 1));
}
}
}
if (cdataReformatRanges != null && !cdataReformatRanges.isEmpty()) {
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
try {
CodeStyleManager.getInstance(project).reformatText(file, cdataReformatRanges);
} catch (IncorrectOperationException e) {
LOG.error(e);
}
}
return cdataReformatRanges != null && !cdataReformatRanges.isEmpty() ? Result.STOP : Result.CONTINUE;
}
return Result.CONTINUE;
}
use of com.intellij.psi.html.HtmlTag in project intellij-community by JetBrains.
the class XmlTagInsertHandler method addRequiredAttributes.
@Nullable
private static StringBuilder addRequiredAttributes(XmlElementDescriptor descriptor, @Nullable XmlTag tag, Template template, PsiFile containingFile) {
boolean htmlCode = HtmlUtil.hasHtml(containingFile) || HtmlUtil.supportsXmlTypedHandlers(containingFile);
Set<String> notRequiredAttributes = Collections.emptySet();
if (tag instanceof HtmlTag) {
final InspectionProfile profile = InspectionProjectProfileManager.getInstance(tag.getProject()).getCurrentProfile();
XmlEntitiesInspection inspection = (XmlEntitiesInspection) profile.getUnwrappedTool(XmlEntitiesInspection.REQUIRED_ATTRIBUTES_SHORT_NAME, tag);
if (inspection != null) {
StringTokenizer tokenizer = new StringTokenizer(inspection.getAdditionalEntries());
notRequiredAttributes = new HashSet<>();
while (tokenizer.hasMoreElements()) notRequiredAttributes.add(tokenizer.nextToken());
}
}
XmlAttributeDescriptor[] attributes = descriptor.getAttributesDescriptors(tag);
StringBuilder indirectRequiredAttrs = null;
if (WebEditorOptions.getInstance().isAutomaticallyInsertRequiredAttributes()) {
final XmlExtension extension = XmlExtension.getExtension(containingFile);
for (XmlAttributeDescriptor attributeDecl : attributes) {
String attributeName = attributeDecl.getName(tag);
boolean shouldBeInserted = extension.shouldBeInserted(attributeDecl);
if (shouldBeInserted && (tag == null || tag.getAttributeValue(attributeName) == null)) {
if (!notRequiredAttributes.contains(attributeName)) {
if (!extension.isIndirectSyntax(attributeDecl)) {
template.addTextSegment(" " + attributeName + "=" + XmlAttributeInsertHandler.getAttributeQuote(htmlCode));
template.addVariable(new MacroCallNode(new CompleteMacro()), true);
template.addTextSegment(XmlAttributeInsertHandler.getAttributeQuote(htmlCode));
} else {
if (indirectRequiredAttrs == null)
indirectRequiredAttrs = new StringBuilder();
indirectRequiredAttrs.append("\n<jsp:attribute name=\"").append(attributeName).append("\"></jsp:attribute>\n");
}
}
} else if (shouldBeInserted && attributeDecl.isFixed() && attributeDecl.getDefaultValue() != null && !htmlCode) {
template.addTextSegment(" " + attributeName + "=" + XmlAttributeInsertHandler.getAttributeQuote(false) + attributeDecl.getDefaultValue() + XmlAttributeInsertHandler.getAttributeQuote(false));
}
}
}
return indirectRequiredAttrs;
}
use of com.intellij.psi.html.HtmlTag in project intellij-community by JetBrains.
the class XmlDocumentationProvider method generateHtmlAdditionalDocTemplate.
static String generateHtmlAdditionalDocTemplate(@NotNull PsiElement element) {
StringBuilder buf = new StringBuilder();
final PsiFile containingFile = element.getContainingFile();
if (containingFile != null) {
final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class, false);
boolean append;
if (tag instanceof HtmlTag) {
append = true;
} else {
final FileViewProvider provider = containingFile.getViewProvider();
Language language;
if (provider instanceof TemplateLanguageFileViewProvider) {
language = ((TemplateLanguageFileViewProvider) provider).getTemplateDataLanguage();
} else {
language = provider.getBaseLanguage();
}
append = language == XHTMLLanguage.INSTANCE;
}
if (tag != null) {
EntityDescriptor descriptor = HtmlDescriptorsTable.getTagDescriptor(tag.getName());
if (descriptor != null && append) {
buf.append("<br>");
buf.append(XmlBundle.message("html.quickdoc.additional.template", descriptor.getHelpRef(), BASE_SITEPOINT_URL + tag.getName()));
}
}
}
return buf.toString();
}
Aggregations