Skip to content

Commit

Permalink
fix: parse property style.* in a non-shape map
Browse files Browse the repository at this point in the history
  • Loading branch information
develar committed Jan 7, 2024
1 parent 189be42 commit 0cceacd
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 221 deletions.
71 changes: 39 additions & 32 deletions src/gen/org/jetbrains/plugins/d2/lang/D2Parser.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion src/src/lang/D2ElementTypeFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ internal object D2ElementTypeFactory {
}

@JvmStatic
fun element(name: String): IElementType = IElementType(name, D2Language)
fun element(name: String): IElementType {
return IElementType(name, D2Language)
}
}

8 changes: 3 additions & 5 deletions src/src/lang/D2ParserDefinition.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ class D2ParserDefinition : ParserDefinition {
SHAPE_PROPERTY -> ShapeProperty(node)
SHAPE_PROPERTY_KEY -> ShapePropertyKey(node)

ID_PROPERTY_MAP -> IdProperty(node)
ID_PROPERTY -> IdProperty(node)
ID_PROPERTY_KEY -> ASTWrapperPsiElement(node)

ARRAY -> D2Array(node)

SHAPE_DECLARATION -> ShapeDeclaration(node)
Expand All @@ -50,7 +46,9 @@ class D2ParserDefinition : ParserDefinition {
COLOR_VALUE -> ColorValue(node)
OTHER_VALUE -> OtherValue(node)

else -> throw AssertionError("Unknown element type: ${node.elementType}")
ID_PROPERTY_MAP -> IdPropertyMap(node)

else -> ASTWrapperPsiElement(node)
}
}
}
5 changes: 3 additions & 2 deletions src/src/lang/d2.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ OtherValue ::= STRING | ID | INT | FLOAT | TRUE | FALSE | DOT | COLOR | BlockStr
ShapeProperty ::= ShapePropertyKey COLON ShapePropertyValue
// STYLE_KEYWORDS are not allowed, but we parse it (report error as inspection - it is allowed if our parent is "style")
// todo: handle RESERVED_KEYWORD_HOLDERS in the same way as style (do not allow arbitrary ID)
ShapePropertyKey ::= SIMPLE_RESERVED_KEYWORDS | (RESERVED_KEYWORD_HOLDERS DOT ID) | (STYLE_KEYWORD DOT STYLE_KEYWORDS) | CONTAINER_LESS_KEYWORDS | STYLE_KEYWORDS
private PropertyKey ::= SIMPLE_RESERVED_KEYWORDS | (RESERVED_KEYWORD_HOLDERS DOT ID) | (STYLE_KEYWORD DOT STYLE_KEYWORDS) | CONTAINER_LESS_KEYWORDS | STYLE_KEYWORDS
ShapePropertyKey ::= PropertyKey
private ShapePropertyValue ::= UnquotedStringValue | StringValue | ColorValue | OtherValue | Array

IdPropertyMap ::= (COMPOSITE_RESERVED_KEYWORDS | STYLE_KEYWORD) COLON LBRACE PropertyMapContent* RBRACE
Expand All @@ -61,7 +62,7 @@ private PropertyMapContent ::= SubIdPropertyMap | IdProperty | COMMENT | SEMICOL
SubIdPropertyMap ::= IdPropertyKey COLON LBRACE PropertyMapContent* RBRACE

IdProperty ::= IdPropertyKey COLON IdPropertyValue
IdPropertyKey ::= SIMPLE_RESERVED_KEYWORDS | RESERVED_KEYWORD_HOLDERS | STYLE_KEYWORD | CONTAINER_LESS_KEYWORDS | STYLE_KEYWORDS | ID | STRING
IdPropertyKey ::= PropertyKey | ID | STRING
private IdPropertyValue ::= SubIdPropertyMap | UnquotedStringValue | StringValue | ColorValue | OtherValue | Array

Array ::= LBRACKET (ShapePropertyValue SEMICOLON?)* RBRACKET
56 changes: 0 additions & 56 deletions src/src/lang/psi/ShapeId.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFileFactory
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.PsiReference
import com.intellij.psi.util.descendants
import com.intellij.psi.util.descendantsOfType
import com.intellij.psi.util.elementType
import org.jetbrains.plugins.d2.lang.D2ElementTypes
Expand Down Expand Up @@ -71,61 +70,6 @@ internal class ShapeId(node: ASTNode) : ASTWrapperPsiElement(node), PsiNamedElem
}
}

private class ShapePsiReference(private val reference: ShapeId) : PsiReference {
override fun getElement() = reference

override fun getRangeInElement() = reference.getValueTextRange()

// todo FQN
override fun resolve(): PsiElement? {
var lastCandidate: ShapeId? = null
for (element in reference.containingFile.descendants(canGoInside = { it !is IdPropertyMap && it !is D2Array && it !is ShapeProperty })) {
if (element is ShapeDeclaration) {
val shapeId = element.findId()
if (shapeId != null && compare(shapeId, reference)) {
return shapeId
}
} else if (element is ShapeId) {
if (compare(element, reference)) {
lastCandidate = element
}
}

if (element === reference) {
break
}
}

return lastCandidate
}

override fun getCanonicalText(): String = reference.name ?: ""

override fun handleElementRename(newElementName: String): PsiElement? {
return reference.setName(newElementName)
}

override fun bindToElement(element: PsiElement): PsiElement? = null

override fun isReferenceTo(element: PsiElement): Boolean {
if (element !is ShapeId) {
return false
}

// todo FQN
// check first text length to avoid string compare
return compare(reference, element)
}

override fun isSoft() = true
}

private fun compare(a: ShapeId, b: ShapeId): Boolean {
return a.getValueTextRange().length == b.getValueTextRange().length && a.name == b.name
}

//class ShapeLabel(node: ASTNode) : ASTWrapperPsiElement(node)

class ShapeConnection(node: ASTNode) : ASTWrapperPsiElement(node)

class Connector(node: ASTNode) : ASTWrapperPsiElement(node)
Expand Down
29 changes: 19 additions & 10 deletions src/src/lang/psi/ShapeProperty.kt
Original file line number Diff line number Diff line change
@@ -1,34 +1,43 @@
// This is a generated file. Not intended for manual editing.
package org.jetbrains.plugins.d2.lang.psi

import com.intellij.extapi.psi.ASTDelegatePsiElement
import com.intellij.extapi.psi.ASTWrapperPsiElement
import com.intellij.lang.ASTNode
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.tree.SharedImplUtil
import com.intellij.ui.ColorHexUtil
import org.jetbrains.plugins.d2.NAMED_COLORS
import java.awt.Color

class ShapeProperty(node: ASTNode) : ASTWrapperPsiElement(node)
class ShapeProperty(node: ASTNode) : AstWrapperPsiElement(node)

class ShapePropertyKey(node: ASTNode) : ASTWrapperPsiElement(node)
class ShapePropertyKey(node: ASTNode) : AstWrapperPsiElement(node)

class IdPropertyMap(node: ASTNode) : ASTWrapperPsiElement(node)
class IdProperty(node: ASTNode) : ASTWrapperPsiElement(node)
class IdPropertyMap(node: ASTNode) : AstWrapperPsiElement(node)

class D2Array(node: ASTNode) : ASTWrapperPsiElement(node)
class D2Array(node: ASTNode) : AstWrapperPsiElement(node)

sealed interface PropertyValue : PsiElement

class OtherValue(node: ASTNode) : ASTWrapperPsiElement(node), PropertyValue
class OtherValue(node: ASTNode) : AstWrapperPsiElement(node), PropertyValue

class StringValue(node: ASTNode) : ASTWrapperPsiElement(node), PropertyValue, ColorValueProvider {
class StringValue(node: ASTNode) : AstWrapperPsiElement(node), PropertyValue, ColorValueProvider {
override fun getColor(): Color? = NAMED_COLORS.get(text.removeSurrounding("\""))
}

class UnquotedStringValue(node: ASTNode) : ASTWrapperPsiElement(node), PropertyValue, ColorValueProvider {
class UnquotedStringValue(node: ASTNode) : AstWrapperPsiElement(node), PropertyValue, ColorValueProvider {
override fun getColor(): Color? = NAMED_COLORS.get(text)
}

class ColorValue(node: ASTNode) : ASTWrapperPsiElement(node), PropertyValue, ColorValueProvider {
class ColorValue(node: ASTNode) : AstWrapperPsiElement(node), PropertyValue, ColorValueProvider {
override fun getColor(): Color? = ColorHexUtil.fromHexOrNull(text.removeSurrounding("\""))
}

// toString doesn't print node element type
sealed class AstWrapperPsiElement(private val node: ASTNode) : ASTDelegatePsiElement() {
override fun getParent(): PsiElement = SharedImplUtil.getParent(node)

override fun getNode(): ASTNode = node

override fun toString(): String = javaClass.simpleName
}
58 changes: 58 additions & 0 deletions src/src/lang/psi/ShapePsiReference.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.jetbrains.plugins.d2.lang.psi

import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.psi.util.descendants

internal class ShapePsiReference(private val reference: ShapeId) : PsiReference {
override fun getElement() = reference

override fun getRangeInElement() = reference.getValueTextRange()

// todo FQN
override fun resolve(): PsiElement? {
var lastCandidate: ShapeId? = null
for (element in reference.containingFile.descendants(canGoInside = { it !is IdPropertyMap && it !is D2Array && it !is ShapeProperty })) {
if (element is ShapeDeclaration) {
val shapeId = element.findId()
if (shapeId != null && compare(shapeId, reference)) {
return shapeId
}
} else if (element is ShapeId) {
if (compare(element, reference)) {
lastCandidate = element
}
}

if (element === reference) {
break
}
}

return lastCandidate
}

override fun getCanonicalText(): String = reference.name ?: ""

override fun handleElementRename(newElementName: String): PsiElement? {
return reference.setName(newElementName)
}

override fun bindToElement(element: PsiElement): PsiElement? = null

override fun isReferenceTo(element: PsiElement): Boolean {
if (element !is ShapeId) {
return false
}

// todo FQN
// check first text length to avoid string compare
return compare(reference, element)
}

override fun isSoft() = true
}

private fun compare(a: ShapeId, b: ShapeId): Boolean {
return a.getValueTextRange().length == b.getValueTextRange().length && a.name == b.name
}
Loading

0 comments on commit 0cceacd

Please sign in to comment.