Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.13.0-beta fixes #137

Merged
merged 9 commits into from
Aug 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import com.intellij.psi.PsiFile
import com.intellij.psi.xml.XmlAttribute

class SvelteHtmlInspectionSuppressor : DefaultXmlSuppressionProvider() {
private val scriptAttributes = listOf("context")
private val styleAttributes = listOf("src", "global")

override fun isSuppressedFor(element: PsiElement, inspectionId: String): Boolean {
if (inspectionId == "XmlUnboundNsPrefix") {
return true
Expand All @@ -14,9 +17,11 @@ class SvelteHtmlInspectionSuppressor : DefaultXmlSuppressionProvider() {
if (inspectionId == "HtmlUnknownAttribute") {
val attribute = element.parent
if (attribute is XmlAttribute) {
if (directives.contains(attribute.namespacePrefix) || suppressedAttributes.contains(attribute.name)) {
return true
}
if (directives.contains(attribute.namespacePrefix)) return true

// TODO refactor into proper descriptors
if (attribute.parent.name == "script" && scriptAttributes.contains(attribute.name)) return true
if (attribute.parent.name == "style" && styleAttributes.contains(attribute.name)) return true
}
}

Expand All @@ -35,4 +40,3 @@ class SvelteHtmlInspectionSuppressor : DefaultXmlSuppressionProvider() {
}

val directives = listOf("on", "bind", "class", "use", "transition", "in", "out", "animate", "let")
private val suppressedAttributes = listOf("context")
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dev.blachut.svelte.lang

import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.lang.javascript.JSTokenTypes
import com.intellij.lang.javascript.validation.ES6KeywordHighlighterVisitor
import dev.blachut.svelte.lang.psi.SvelteInitialTag
import dev.blachut.svelte.lang.psi.SvelteJSLazyPsiElement
Expand All @@ -16,8 +15,8 @@ class SvelteKeywordHighlighterVisitor(holder: HighlightInfoHolder) : ES6KeywordH
}

override fun visitLazyElement(element: SvelteJSLazyPsiElement) {
// Direct children should be safe to treat as identifiers
highlightChildKeywordOfType(element, JSTokenTypes.IDENTIFIER) // debug, html
highlightChildKeywordOfType(element, SvelteTokenTypes.HTML_KEYWORD)
highlightChildKeywordOfType(element, SvelteTokenTypes.DEBUG_KEYWORD)

super.visitLazyElement(element)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import dev.blachut.svelte.lang.directives
import dev.blachut.svelte.lang.isSvelteComponentTag

class SvelteXmlExtension : HtmlXmlExtension() {
private val collapsibleTags = setOf("slot", "style", "script")

override fun isAvailable(file: PsiFile): Boolean = file.language is SvelteHTMLLanguage

/**
* Whether writing self closing `<tag/>` is correct
*/
override fun isSelfClosingTagAllowed(tag: XmlTag): Boolean {
return isSvelteComponentTag(tag.name) || tag.name == "slot" || super.isSelfClosingTagAllowed(tag)
return isSvelteComponentTag(tag.name) || collapsibleTags.contains(tag.name) || super.isSelfClosingTagAllowed(tag)
}

/**
Expand All @@ -29,7 +31,11 @@ class SvelteXmlExtension : HtmlXmlExtension() {
*/
override fun isSingleTagException(tag: XmlTag): Boolean = isSvelteComponentTag(tag.name) || tag.name == "slot"

override fun getAttributeValuePresentation(tag: XmlTag?, attributeName: String, defaultAttributeQuote: String): AttributeValuePresentation {
override fun getAttributeValuePresentation(
tag: XmlTag?,
attributeName: String,
defaultAttributeQuote: String
): AttributeValuePresentation {
if (attributeName == "slot") {
return super.getAttributeValuePresentation(tag, attributeName, defaultAttributeQuote)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.completion.PrioritizedLookupElement
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.xml.XmlAttribute
Expand All @@ -13,18 +14,39 @@ import com.intellij.util.ProcessingContext
import dev.blachut.svelte.lang.icons.SvelteIcons

class SvelteAttributeNameCompletionProvider : CompletionProvider<CompletionParameters>() {
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
override fun addCompletions(
parameters: CompletionParameters,
context: ProcessingContext,
result: CompletionResultSet
) {
val xmlTag = PsiTreeUtil.getParentOfType(parameters.position, XmlTag::class.java, false)
val xmlAttribute = parameters.position.parent as? XmlAttribute
if (xmlTag == null || xmlAttribute == null) return

if (xmlTag.name == "script" && xmlTag.getAttribute("context") == null) {
val element = LookupElementBuilder
.create("context=\"module\"")
.withIcon(SvelteIcons.GRAY)
.let { PrioritizedLookupElement.withPriority(it, 10.0) }
result.addElement(createLookupElement("context=\"module\"", 10))
}

// TODO refactor into proper descriptors
if (xmlTag.name == "style" && xmlTag.getAttribute("global") == null) {
result.addElement(createLookupElement("global"))
}

result.addElement(element)
if (xmlTag.name == "style" && xmlTag.getAttribute("src") == null) {
result.addElement(createLookupElement("src"))
}
}

private fun createLookupElement(text: String, priority: Int? = null): LookupElement {
return LookupElementBuilder
.create(text)
.withIcon(SvelteIcons.GRAY)
.let {
if (priority != null) {
PrioritizedLookupElement.withPriority(it, priority.toDouble())
} else {
it
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,11 @@ class SvelteFoldingBuilder : XmlFoldingBuilder(), DumbAware {
for (child in block.children) {
if (child is SvelteBranch) {
val fragment = child.fragment
val foldingRangeStartOffset = fragment.textRange.startOffset
val foldingRangeEndOffset = fragment.textRange.endOffset
val range = TextRange(foldingRangeStartOffset, foldingRangeEndOffset)
if (fragment.textLength > 0) {
descriptors.add(FoldingDescriptor(block, fragment.textRange))

descriptors.add(FoldingDescriptor(block, range))

doAddForChildren(fragment, descriptors, document)
doAddForChildren(fragment, descriptors, document)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package dev.blachut.svelte.lang.format

import com.intellij.formatting.*
import com.intellij.lang.ASTNode
import com.intellij.lang.LanguageFormatting
import com.intellij.lang.javascript.JSTokenTypes
import com.intellij.psi.formatter.common.AbstractBlock
import com.intellij.psi.formatter.xml.AbstractXmlBlock
import com.intellij.psi.formatter.xml.XmlFormattingPolicy
import dev.blachut.svelte.lang.psi.SvelteTagElementTypes
import dev.blachut.svelte.lang.psi.SvelteTokenTypes

class SvelteExpressionBlock(
node: ASTNode,
private val indent: Indent?,
wrap: Wrap?,
private val policy: XmlFormattingPolicy
) :
AbstractBlock(node, wrap, null) {
override fun isLeaf(): Boolean = false

override fun buildChildren(): MutableList<Block> {
val results = ArrayList<Block>(4)

// borrowed from com.intellij.psi.formatter.common.InjectedLanguageBlockBuilder.addInjectedLanguageBlockWrapper
val nodePsi = myNode.psi
val builder = LanguageFormatting.INSTANCE.forContext(nodePsi.language, nodePsi)

var child = myNode.firstChildNode
while (child != null) {
if (child.textLength > 0 && !AbstractXmlBlock.containsWhiteSpacesOnly(child)) {
if (child.elementType === JSTokenTypes.LBRACE) {
val startTag = SvelteTagElementTypes.START_TAGS.contains(myNode.elementType)
val wrap = if (startTag) Wrap.createWrap(WrapType.ALWAYS, true) else null
results.add(SvelteLeafBlock(child, wrap = wrap))
} else if (child.elementType === JSTokenTypes.RBRACE) {
results.add(SvelteLeafBlock(child, indent = Indent.getNoneIndent()))
} else {
if (builder != null) {
val childModel = builder.createModel(child.psi, policy.settings)
results.add(childModel.rootBlock)
} else {
results.add(SvelteLeafBlock(child))
}
}
}

child = child.treeNext
}

return results
}

override fun getSpacing(child1: Block?, child2: Block): Spacing? {
if (child1 !is ASTBlock || child2 !is ASTBlock) {
return null
}

val node1 = child1.node ?: return null
val node2 = child2.node ?: return null

val type1 = node1.elementType
val type2 = node2.elementType

if (SvelteTokenTypes.KEYWORDS.contains(type1) && type2 !== JSTokenTypes.RBRACE) {
return Spacing.createSpacing(1, 1, 0, true, 0)
}

return null
}

override fun getIndent(): Indent? {
return indent
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import com.intellij.lang.xml.XmlFormattingModel
import com.intellij.psi.PsiElement
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.FormattingDocumentModelImpl
import com.intellij.psi.formatter.xml.HtmlPolicy
import com.intellij.psi.impl.source.SourceTreeToPsiMap

class SvelteFormattingModelBuilder : FormattingModelBuilder {
Expand All @@ -15,7 +14,7 @@ class SvelteFormattingModelBuilder : FormattingModelBuilder {
val documentModel = FormattingDocumentModelImpl.createOn(psiFile)

val astNode = SourceTreeToPsiMap.psiElementToTree(psiFile)
val formattingPolicy = HtmlPolicy(settings, documentModel)
val formattingPolicy = SvelteHtmlPolicy(settings, documentModel)
val block = SvelteXmlBlock(astNode, null, null, formattingPolicy, null, null, false)

return XmlFormattingModel(psiFile, block, documentModel)
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/dev/blachut/svelte/lang/format/SvelteHtmlPolicy.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package dev.blachut.svelte.lang.format

import com.intellij.formatting.FormattingDocumentModel
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.formatter.xml.HtmlPolicy
import com.intellij.psi.xml.XmlTag

class SvelteHtmlPolicy(settings: CodeStyleSettings, documentModel: FormattingDocumentModel) :
HtmlPolicy(settings, documentModel) {

override fun shouldBeWrapped(tag: XmlTag): Boolean {
if (wrappingTags.contains(tag.name)) {
return !tag.value.textRange.isEmpty
}

return super.shouldBeWrapped(tag)
}

companion object {
val wrappingTags = setOf("script", "style")
}
}
19 changes: 19 additions & 0 deletions src/main/java/dev/blachut/svelte/lang/format/SvelteLeafBlock.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package dev.blachut.svelte.lang.format

import com.intellij.formatting.Block
import com.intellij.formatting.Indent
import com.intellij.formatting.Spacing
import com.intellij.formatting.Wrap
import com.intellij.lang.ASTNode
import com.intellij.psi.formatter.common.AbstractBlock

class SvelteLeafBlock(node: ASTNode, private val indent: Indent? = null, wrap: Wrap? = null) :
AbstractBlock(node, wrap, null) {
override fun isLeaf(): Boolean = true

override fun buildChildren(): MutableList<Block> = EMPTY

override fun getSpacing(child1: Block?, child2: Block): Spacing? = null

override fun getIndent(): Indent? = indent
}
Loading