From 16c1008c2c4c85f11d2a38cd83b5d4f999153abb Mon Sep 17 00:00:00 2001 From: me Date: Sun, 26 May 2024 15:15:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9bnf?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/grammar/main.bnf | 19 +++--- src/main/grammar/sample.bnf | 68 +++++++++++++++++++ .../completion/SlintCompletionContributor.kt | 11 +-- .../provider/PropertyBindingProvider.kt | 34 ++++++++++ .../lang/psi/extension/SlintComponentEx.kt | 12 ++++ .../reference/SlintReferenceContributor.kt | 2 +- .../provider/PropertyReferenceProvider.kt | 13 ++-- 7 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 src/main/grammar/sample.bnf create mode 100644 src/main/kotlin/me/zhouxi/slint/completion/provider/PropertyBindingProvider.kt create mode 100644 src/main/kotlin/me/zhouxi/slint/lang/psi/extension/SlintComponentEx.kt diff --git a/src/main/grammar/main.bnf b/src/main/grammar/main.bnf index 9c5c038..f9d58ed 100644 --- a/src/main/grammar/main.bnf +++ b/src/main/grammar/main.bnf @@ -151,6 +151,7 @@ InheritDeclaration ::= InheritsKeyword ReferenceIdentifier { } ComponentBody ::= '{' ComponentElement* '}'{ pin=1 + recoverWhile=recoverWhileForComponentBody } //组件元素定义 private ComponentElement ::=ChildrenPlaceholder| Property | Callback @@ -160,11 +161,7 @@ private ComponentElement ::=ChildrenPlaceholder| Property | Callback | RepetitionElement | SubComponent { recoverWhile(".*")=recoverWhileForComponentBody } -private recoverWhileForComponentBody::= !( - 'property'|'callback'|'changed' - |'states'|'transitions'|'pure' - |'function'|'public'|'protected'|'for'|'if'|'}'|';'|'@' - |GenericIdentifier|PropertyModifier) +private recoverWhileForComponentBody::= !('{'|';'|'}'|'@'|GenericIdentifier) ChildrenPlaceholder ::= '@' 'children'{ pin=1 @@ -249,7 +246,8 @@ RepetitionIndex ::= '[' LocalVariable ']'{ //--------------------------------SubElementDeclaration Start--------------------------------------------------- //子组件结构元素定义 SubComponent ::= (PropertyName ':=')? ReferenceIdentifier ComponentBody{ - pin=2 + pin=3 + recoverWhile=recoverWhileForComponentBody } //--------------------------------TransitionsDeclaration Start--------------------------------------------------- @@ -298,11 +296,11 @@ CodeBlock ::= '{' Statement* '}'{ pin=1 } private Statement ::= (ReturnStatement|IfElseStatement|ExpressionStatement) ';'?{ - recoverWhile=recoverWhileStatement + recoverWhile=recoverWhileForComponentBody } ExpressionStatement ::= Expression (';' &Statement)? -private recoverWhileStatement::=!(GenericIdentifier|';'|'}') +//private recoverWhileStatement::=!(GenericIdentifier|';'|'}') ReturnStatement ::= 'return' (Expression)?{ pin=1 @@ -331,11 +329,14 @@ private QualifiedNamePropertyBinding::= QualifiedPropertyNameReference ':' Bindi PropertyBinding ::= ReferenceIdentifier ':' BindingStatement{ pin=2 } +private WhileIdentifier::=!('}'|GenericIdentifier) //优先尝试表达式解析 {}属于代码块 {name:xx}属于表达式,那么需要预测后面两个token,第二个token不是':'的情况下才是代码块 //所以优先判断对象创建判断,然后进行代码块判断,最后进行表达式 //代码块分号可选 //表达式需要分号结尾 -BindingStatement ::=ObjectCreationExpressionWithSem|(CodeBlock ';'?)| ExpressionWithSem +BindingStatement ::=ObjectCreationExpressionWithSem|(CodeBlock ';'?)| ExpressionWithSem{ + recoverWhile=WhileIdentifier +} //用于错误的直观化 private ObjectCreationExpressionWithSem::=ObjectCreationExpression';'{ pin=1 diff --git a/src/main/grammar/sample.bnf b/src/main/grammar/sample.bnf new file mode 100644 index 0000000..2625b76 --- /dev/null +++ b/src/main/grammar/sample.bnf @@ -0,0 +1,68 @@ +{ + generate=[token-case="as-is" element-case="as-is"] + parserClass="me.zhouxi.slint.lang.parser.SlintParser" + implements="me.zhouxi.slint.lang.psi.SlintPsiElement" + extends="me.zhouxi.slint.lang.psi.impl.SlintPsiElementImpl" + elementTypeHolderClass="me.zhouxi.slint.lang.psi.SlintTypes" + elementTypeClass="me.zhouxi.slint.lang.SlintElementType" + tokenTypeClass="me.zhouxi.slint.lang.SlintTokenType" + psiClassPrefix="Slint" + psiImplClassSuffix="Impl" + psiPackage="me.zhouxi.slint.lang.psi" + psiImplPackage="me.zhouxi.slint.lang.psi.impl" + tokens=[ + Comma = "," + FatArrow = "=>" + DoubleArrow = "<=>" + PlusEqual = "+=" + MinusEqual = "-=" + StarEqual = "*=" + DivEqual = "/=" + LessEqual = "<=" + GreaterEqual = ">=" + EqualEqual = "==" + NotEqual = "!=" + ColonEqual = ":=" + Arrow = "->" + OrOr = "||" + AndAnd = "&&" + LBrace = "{" + RBrace = "}" + LParent = "(" + RParent = ")" + LAngle = "<" + RAngle = ">" + LBracket = "[" + RBracket = "]" + Plus = "+" + Minus = "-" + Star = "*" + Div = "/" + Equal = "=" + Colon = ":" + Comma = "," + Semicolon = ";" + Bang = "!" + Dot = "." + Question = "?" + Dollar = "$" + At = "@" + Pipe = "|" + Percent = "%" + Whitespace = "regexp:(\s+)" + NumberLiteral = "regexp:\d+(\.(\d+)?)?([a-z]+|%)?" + Identifier = "regexp:^[a-zA-Z_][A-Za-z0-9\-_]*" + ColorLiteral = "regexp:#([a-zA-Z0-9]+)" + StringLiteral = 'regexp:(^"[^"\r\n]*")' + LineComment = 'regexp:^//[^\r\n]*' + BlockComment = 'regexp:/\*[\s\S]*?\*/' + + ] +} + +Document ::= Binding* +Binding ::=Identifier ':' Identifier ';'{ + pin=2 + recoverWhile=while +} +private while::=!(';'|Identifier) diff --git a/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionContributor.kt b/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionContributor.kt index 75515b0..9be6699 100644 --- a/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionContributor.kt +++ b/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionContributor.kt @@ -3,10 +3,7 @@ package me.zhouxi.slint.completion import com.intellij.codeInsight.completion.CompletionContributor import com.intellij.codeInsight.completion.CompletionType import com.intellij.patterns.PlatformPatterns -import me.zhouxi.slint.completion.provider.BasicTypeProvider -import me.zhouxi.slint.completion.provider.ComponentProvider -import me.zhouxi.slint.completion.provider.ElementKeywordProvider -import me.zhouxi.slint.completion.provider.TopKeywordProvider +import me.zhouxi.slint.completion.provider.* import me.zhouxi.slint.lang.psi.SlintTypes import me.zhouxi.slint.lang.psi.stubs.types.SlintFileElementType @@ -38,6 +35,12 @@ class SlintCompletionContributor : CompletionContributor() { PlatformPatterns.psiElement().withAncestor(2, PlatformPatterns.psiElement(SlintTypes.ComponentBody)), ComponentProvider ) + //propertyBinding + extend( + CompletionType.BASIC, + PlatformPatterns.psiElement().withAncestor(2, PlatformPatterns.psiElement(SlintTypes.ComponentBody)), + PropertyBindingProvider + ) } } \ No newline at end of file diff --git a/src/main/kotlin/me/zhouxi/slint/completion/provider/PropertyBindingProvider.kt b/src/main/kotlin/me/zhouxi/slint/completion/provider/PropertyBindingProvider.kt new file mode 100644 index 0000000..2c35a3f --- /dev/null +++ b/src/main/kotlin/me/zhouxi/slint/completion/provider/PropertyBindingProvider.kt @@ -0,0 +1,34 @@ +package me.zhouxi.slint.completion.provider + +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.completion.CompletionProvider +import com.intellij.codeInsight.completion.CompletionResultSet +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.icons.AllIcons +import com.intellij.psi.util.parentOfType +import com.intellij.util.ProcessingContext +import me.zhouxi.slint.lang.psi.SlintComponent +import me.zhouxi.slint.lang.psi.SlintSubComponent +import me.zhouxi.slint.lang.psi.extension.inheritsProperties + +object PropertyBindingProvider : CompletionProvider() { + override fun addCompletions( + parameters: CompletionParameters, + context: ProcessingContext, + result: CompletionResultSet + ) { + val element = parameters.position + val subComponent = element.parentOfType() + if (subComponent != null) { + val component = subComponent.referenceIdentifier.reference?.resolve() as SlintComponent? ?: return + val builders = component.inheritsProperties() + .map { LookupElementBuilder.create(it).withTypeText(component.name).withIcon(AllIcons.Nodes.Property) } + result.addAllElements(builders) + } else { + val component = element.parentOfType() ?: return + val builders = component.inheritsProperties() + .map { LookupElementBuilder.create(it).withTypeText(component.name).withIcon(AllIcons.Nodes.Property) } + result.addAllElements(builders) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/me/zhouxi/slint/lang/psi/extension/SlintComponentEx.kt b/src/main/kotlin/me/zhouxi/slint/lang/psi/extension/SlintComponentEx.kt new file mode 100644 index 0000000..d5d938f --- /dev/null +++ b/src/main/kotlin/me/zhouxi/slint/lang/psi/extension/SlintComponentEx.kt @@ -0,0 +1,12 @@ +package me.zhouxi.slint.lang.psi.extension + +import me.zhouxi.slint.lang.psi.SlintComponent +import me.zhouxi.slint.lang.psi.SlintProperty + + +fun SlintComponent.inheritsProperties(): List { + val properties = this.componentBody?.propertyList ?: emptyList() + val inherit = + this.inheritDeclaration?.referenceIdentifier?.reference?.resolve() as SlintComponent? ?: return properties + return properties + inherit.inheritsProperties() +} \ No newline at end of file diff --git a/src/main/kotlin/me/zhouxi/slint/reference/SlintReferenceContributor.kt b/src/main/kotlin/me/zhouxi/slint/reference/SlintReferenceContributor.kt index 3f3e769..ef304ba 100644 --- a/src/main/kotlin/me/zhouxi/slint/reference/SlintReferenceContributor.kt +++ b/src/main/kotlin/me/zhouxi/slint/reference/SlintReferenceContributor.kt @@ -41,7 +41,7 @@ class SlintReferenceContributor : PsiReferenceContributor() { psiElement(ComponentBody) ) ), - PropertyReferenceProvider() + PropertyReferenceProvider ) } } diff --git a/src/main/kotlin/me/zhouxi/slint/reference/provider/PropertyReferenceProvider.kt b/src/main/kotlin/me/zhouxi/slint/reference/provider/PropertyReferenceProvider.kt index 0affc5e..803be00 100644 --- a/src/main/kotlin/me/zhouxi/slint/reference/provider/PropertyReferenceProvider.kt +++ b/src/main/kotlin/me/zhouxi/slint/reference/provider/PropertyReferenceProvider.kt @@ -10,18 +10,23 @@ import com.intellij.util.ProcessingContext import me.zhouxi.slint.lang.psi.SlintComponent import me.zhouxi.slint.lang.psi.SlintPropertyBinding import me.zhouxi.slint.lang.psi.SlintSubComponent +import me.zhouxi.slint.lang.psi.extension.inheritsProperties import me.zhouxi.slint.lang.psi.utils.searchProperty -class PropertyReferenceProvider : PsiReferenceProvider() { +object PropertyReferenceProvider : PsiReferenceProvider() { override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array { return arrayOf(PropertyReference(element)) } class PropertyReference(element: PsiElement) : PsiReferenceBase(element) { override fun resolve(): PsiElement? { - val binding = element.parentOfType() ?: return null - val parent = binding.parentOfTypes(SlintSubComponent::class, SlintComponent::class) ?: return null - return searchProperty(parent) { it.propertyName?.textMatches(element) == true } + val subComponent = element.parentOfType() + if (subComponent != null) { + val component = subComponent.referenceIdentifier.reference?.resolve() as SlintComponent? ?: return null + return component.inheritsProperties().find { it.propertyName?.textMatches(element) == true } + } + val component = element.parentOfType() ?: return null + return component.inheritsProperties().find { it.propertyName?.textMatches(element) == true } } } }