diff --git a/build.gradle.kts b/build.gradle.kts index ed1db5e..54a9303 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ plugins { id("java") id("org.jetbrains.kotlin.jvm") version "1.9.23" - id("org.jetbrains.intellij") version "1.17.2" + id("org.jetbrains.intellij") version "1.17.3" id("org.jetbrains.grammarkit") version "2022.3.2.2" id("de.undercouch.download") version "5.6.0" } @@ -9,16 +9,16 @@ val slintVersion: String by project //github url val slintGithubUrl = "https://github.com/slint-ui/slint/releases/download/v$slintVersion" //download dir -val slintViewerDownloadDir = "${layout.buildDirectory.get()}/slint-viewer" +val slintViewerDownloadDir = "${layout.buildDirectory.get()}/slint-lsp" //decompression path -val slintViewerBinaryDir = "${layout.buildDirectory.get()}/slint-viewer/$slintVersion" +val slintViewerBinaryDir = "${layout.buildDirectory.get()}/slint-lsp/$slintVersion" val grammarGeneratedRoot = "${layout.buildDirectory.get()}/generated/sources/grammar/" //github filename-> decompression name val slintViewerFilenames = arrayOf( - "slint-viewer-linux.tar.gz" to "slint-viewer-linux", - "slint-viewer-macos.tar.gz" to "slint-viewer-macos", - "slint-viewer-windows.zip" to "slint-viewer-windows.exe", + "slint-lsp-linux.tar.gz" to "slint-lsp-linux", + "slint-lsp-macos.tar.gz" to "slint-lsp-macos", + "slint-lsp-windows.zip" to "slint-lsp-windows.exe", ) sourceSets { @@ -36,22 +36,17 @@ repositories { } intellij { - version.set("IC-2023.2.5") + version.set("IU-2024.1") sandboxDir.set("idea-sandbox") - plugins.set(listOf("java","Kotlin")) + plugins.set(listOf("java")) } dependencies { - compileOnly("org.projectlombok:lombok:1.18.32") - annotationProcessor("org.projectlombok:lombok:1.18.32") - testCompileOnly("org.projectlombok:lombok:1.18.32") - testAnnotationProcessor("org.projectlombok:lombok:1.18.32") -// implementation("org.jetbrains:grammar-kit:2022.3.2") } tasks { buildPlugin { - //copy slint-viewer to plugin dir + //copy slint-lsp to plugin dir from(slintViewerBinaryDir) { - into("/slint-viewer") + into("/slint-lsp") } } withType().configureEach { @@ -61,11 +56,11 @@ tasks { } runIde { - //copy slint-viewer + //copy slint-lsp doFirst { copy { from(slintViewerBinaryDir) - into("idea-sandbox/plugins/intellij-slint/slint-viewer") + into("idea-sandbox/plugins/intellij-slint/slint-lsp") } } } @@ -100,7 +95,7 @@ tasks { jvmArgs("-Djava.awt.headless=true") } - register("downloadSlintViewer") { + register("downloadSlintResource") { doFirst { slintViewerFilenames.forEach { fileDesc -> val (filename, renamed) = fileDesc @@ -118,7 +113,7 @@ tasks { } from(fileTree) //include executable file path - include("slint-viewer/slint-viewer*") + include("slint-lsp/slint-lsp*") eachFile { //rename to platform name this.relativePath = RelativePath(true, renamed) diff --git a/src/main/grammar/main.bnf b/src/main/grammar/main.bnf index a1d084a..fe82228 100644 --- a/src/main/grammar/main.bnf +++ b/src/main/grammar/main.bnf @@ -56,7 +56,7 @@ Percent = "%" Whitespace = "regexp:(\s+)" NumberLiteral = "regexp:\d+(\.(\d+)?)?([a-z]+|%)?" - Identifier = "regexp:^[a-zA-Z_][A-Za-z0-9\-_]*" + IDENTIFIER = "regexp:^[a-zA-Z_][A-Za-z0-9\-_]*" ColorLiteral = "regexp:#([a-zA-Z0-9]+)" StringLiteral = 'regexp:(^"[^"\r\n]*")' LineComment = 'regexp:^//[^\r\n]*' @@ -70,26 +70,25 @@ private recoverTopElement ::= !('component' | 'struct' | 'enum' | 'global'| 'exp private DocumentElement ::= Import | Struct | Enum | GlobalSingleton | Component | Export { recoverWhile=recoverTopElement } -GlobalSingleton ::= ExportKeyword? GlobalKeyword ComponentName '{' ComponentElement* '}' { +GlobalSingleton ::= ExportKeyword? GlobalKeyword Identifier '{' ComponentElement* '}' { pin=2 implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"] mixin="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementImpl" } //import 定义 -Import ::= ImportKeyword (ImportElement|ImportResource)';'{ +Import ::= ImportKeyword (ImportElement|ModuleRef)';'{ pin=1 elementTypeFactory="me.zhouxi.slint.lang.psi.stubs.types.SlintStubTypes.slintImport" stubClass="me.zhouxi.slint.lang.psi.stubs.stub.SlintImportStub" extends="me.zhouxi.slint.lang.psi.impl.SlintStubBasedPsiElementImpl" } -ImportElement ::= '{' ImportSpecifier (',' ImportSpecifier)* '}' FromKeyword ModuleLocation{ +ImportElement ::= '{' ImportSpecifier (',' ImportSpecifier)* '}' FromKeyword ModuleRef{ pin=1 } -ImportResource ::= ModuleLocation // ABc as Def -ImportSpecifier ::= ReferenceIdentifier ImportAlias?{ +ImportSpecifier ::= ComponentRef ImportAlias?{ pin=1 elementTypeFactory="me.zhouxi.slint.lang.psi.stubs.types.SlintStubTypes.importSpecifier" stubClass="me.zhouxi.slint.lang.psi.stubs.stub.SlintImportSpecifierStub" @@ -97,21 +96,21 @@ ImportSpecifier ::= ReferenceIdentifier ImportAlias?{ } private AliasNameRecover::=!(','|'}'|';') -ImportAlias ::= AsKeyword InternalName { +ImportAlias ::= AsKeyword Identifier { pin=1 recoverWhile=AliasNameRecover implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"] extends="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementImpl" } //Struct 定义 -Struct ::= ExportKeyword? StructKeyword TypeName (':=')? StructBody { +Struct ::= ExportKeyword? StructKeyword Identifier (':=')? StructBody { pin=2 } private StructBody ::= '{' FieldDeclarations? '}'{ pin=1 } //EnumDeclaration -Enum ::= ExportKeyword? EnumKeyword EnumName '{' (EnumValue (','EnumValue)*','? )? '}'{ +Enum ::= ExportKeyword? EnumKeyword Identifier '{' (Identifier (','Identifier)*','? )? '}'{ pin=2 implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"] extends="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementImpl" @@ -125,19 +124,19 @@ Export ::= ExportKeyword (ExportType | ExportModule) { ExportType ::= '{' ExportSpecifier (','ExportSpecifier)* ','? '}'{ pin=1 } -ExportSpecifier::= ReferenceIdentifier ExportAlias?{ +ExportSpecifier::= ComponentRef ExportAlias?{ recoverWhile=AliasNameRecover implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"] extends="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementImpl" } -ExportAlias ::= AsKeyword ExternalName{ +ExportAlias ::= AsKeyword Identifier{ pin=1 } -ExportModule ::= '*' FromKeyword ModuleLocation ';'{ +ExportModule ::= '*' FromKeyword ModuleRef ';'{ pin=1 } -Component ::= ExportKeyword? ComponentKeyword ComponentName InheritDeclaration? '{' ComponentElement* '}' { +Component ::= ExportKeyword? ComponentKeyword Identifier InheritDeclaration? '{' ComponentElement* '}' { pin=2 implements=[ "me.zhouxi.slint.lang.psi.SlintPsiNamedElement" @@ -148,7 +147,7 @@ Component ::= ExportKeyword? ComponentKeyword ComponentName InheritDeclaration? } //组件定义 //private LegacyComponent ::= (ComponentName|NamedIdentifier ':=' ) ComponentBody -InheritDeclaration ::= InheritsKeyword ReferenceIdentifier { +InheritDeclaration ::= InheritsKeyword ComponentRef { pin=1 recoverWhile=recoverInherit } @@ -157,18 +156,18 @@ private recoverInherit::=!('{') private ComponentElement ::=ChildrenPlaceholder| Property | Callback | Function | PropertyAnimation | CallbackConnection | Transitions | PropertyChanged - | States | TwoWayBinding|PropertyBinding | ConditionalElement - | RepetitionElement | SubComponent { - recoverWhile(".*")=recoverWhileForComponentBody + | States | TwoWayBinding | ConditionalElement + | RepetitionElement | SubComponent | PropertyBinding { + recoverWhile=recoverWhileForComponentBody } -private recoverWhileForComponentBody::= !('{'|';'|'}'|'@'|GenericIdentifier) +private recoverWhileForComponentBody::= !('{'|';'|'}'|'@'|Identifier) ChildrenPlaceholder ::= '@' 'children'{ pin=1 } //--------------------------------PropertyDeclaration Start---------------------------------------------------- // 属性定义 in property name: value / in property name <=> value -Property ::= PropertyModifier? PropertyKeyword ('<' Type '>')? PropertyName(PropertyValue|PropertyTwoWayBindingValue|';'){ +Property ::= PropertyModifier? PropertyKeyword ('<' Type '>')? Identifier (PropertyValue|PropertyTwoWayBindingValue|';'){ pin=2 implements=[ "me.zhouxi.slint.lang.psi.SlintPsiNamedElement" @@ -181,7 +180,7 @@ PropertyModifier ::= InKeyword|OutKeyword|InOutKeyword|PrivateKeyword private PropertyValue::= ':' BindingStatement { pin=1 } -private PropertyTwoWayBindingValue ::= '<=>' QualifiedPropertyNameReference ';' { +private PropertyTwoWayBindingValue ::= '<=>' QualifiedPropertyRef ';' { pin=1 } //--------------------------------PropertyChanged Start---------------------------------------------------- @@ -190,29 +189,29 @@ PropertyChanged ::= ChangedKeyword LocalVariable '=>' CodeBlock{ } //--------------------------------CallbackDeclaration Start---------------------------------------------------- // 回调定义 pure callback abc()->int; callback abc; callback(..);callback()->type; -Callback ::= PureKeyword? CallbackKeyword FunctionName CallbackBinding? ';'{ +Callback ::= PureKeyword? CallbackKeyword Identifier CallbackBinding? ';'{ pin=2 implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"] extends="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementImpl" } //回调参数定义 -CallbackBinding::= CallbackArgument | ('<=>'QualifiedPropertyNameReference) +CallbackBinding::= CallbackArgument | ('<=>'QualifiedPropertyRef) //入参定义 CallbackArgument ::= '(' (Type (','Type)* ','? )? ')' ReturnType?{ pin=1 } -private ReturnType ::= '->' (NamedType|ArrayType){ +private ReturnType ::= '->' (QualifiedTypeRef|ArrayType){ pin=1 } //--------------------------------TwoWayBindingDeclaration Start---------------------------------------------------- //组件双向绑定 -TwoWayBinding ::= ReferenceIdentifier '<=>' QualifiedPropertyNameReference ';' { +TwoWayBinding ::= PropertyRef '<=>' QualifiedPropertyRef ';' { pin=2 } //--------------------------------FunctionDeclaration Start---------------------------------------------------- //函数定义 protected? pure? function f() -Function ::= FunctionModifiers? FunctionKeyword FunctionName FunctionArguments ReturnType? CodeBlock{ +Function ::= FunctionModifiers? FunctionKeyword Identifier FunctionArguments ReturnType? CodeBlock{ pin=2 implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"] extends="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementImpl" @@ -225,7 +224,7 @@ private FunctionArguments ::= '(' FieldDeclarations* ')'{ //--------------------------------CallbackConnectionDeclaration Start--------------------------------------------------- //回调绑定定义 abc()=> {} -CallbackConnection ::= FunctionReference CallbackConnectionArguments? '=>' CodeBlock ';'?{ +CallbackConnection ::= FunctionRef CallbackConnectionArguments? '=>' CodeBlock ';'?{ pin=3 } private CallbackConnectionArguments ::= '(' (LocalVariable (',' LocalVariable)* ','?)? ')' @@ -245,10 +244,11 @@ RepetitionIndex ::= '[' LocalVariable ']'{ } //--------------------------------SubElementDeclaration Start--------------------------------------------------- //子组件结构元素定义 -SubComponent ::= (PropertyName ':=')? ReferenceIdentifier '{' ComponentElement* '}'{ +SubComponent ::= (Identifier ':=')? ComponentRef '{' ComponentElement* '}'{ pin=3 - recoverWhile=recoverWhileForComponentBody +// recoverWhile=recoverForBrace } +//private recoverForBrace::=!'}' //--------------------------------TransitionsDeclaration Start--------------------------------------------------- //过渡绑定 @@ -272,7 +272,7 @@ State ::= LocalVariable StateCondition? ':' '{' StateItem* '}' { extends="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementImpl" recoverWhile=recoverForRBracket } -private recoverForRBracket::=!(']'|'}'|';'|GenericIdentifier) +private recoverForRBracket::=!(']'|'}'|';'|Identifier) StateCondition ::= WhenKeyword Expression { pin=1 } @@ -283,12 +283,11 @@ StateTransition ::= (InKeyword|OutKeyword) ':' '{' PropertyAnimation* '}'{ } //------------------------------------------------------------------------------------------ //类型定义 -Type ::= NamedType | UnnamedType | ArrayType -private NamedType ::= QualifiedTypeNameReference +Type ::= QualifiedTypeRef | UnnamedType | ArrayType ArrayType ::= '[' Type ']' UnnamedType ::= '{' FieldDeclarations* '}' private FieldDeclarations ::= FieldDeclaration (',' FieldDeclaration)* ','? -private FieldDeclaration ::= PropertyName ':' Type +private FieldDeclaration ::= Identifier ':' Type //代码块 @@ -320,18 +319,17 @@ ElseStatement ::= ElseKeyword CodeBlock { pin=1 } //动画定义 -PropertyAnimation ::= AnimateKeyword ('*'| (QualifiedPropertyNameReference (',' QualifiedPropertyNameReference)*)) '{' QualifiedNamePropertyBinding*'}'{ +PropertyAnimation ::= AnimateKeyword ('*'| (QualifiedPropertyRef (',' QualifiedPropertyRef)*)) '{' QualifiedNamePropertyBinding*'}'{ pin=1 } //组件属性绑定 name: xxx ; name : {}; name : {} //只有对象定义和表达式需要 ; -private QualifiedNamePropertyBinding::= QualifiedPropertyNameReference ':' BindingStatement{ +private QualifiedNamePropertyBinding::= QualifiedPropertyRef ':' BindingStatement{ pin=2 } -PropertyBinding ::= ReferenceIdentifier ':' BindingStatement{ - pin=2 +PropertyBinding ::= PropertyRef ':' BindingStatement{ } -private WhileIdentifier::=!('}'|';'|GenericIdentifier) +private WhileIdentifier::=!('}'|';'|Identifier) //优先尝试表达式解析 {}属于代码块 {name:xx}属于表达式,那么需要预测后面两个token,第二个token不是':'的情况下才是代码块 //所以优先判断对象创建判断,然后进行代码块判断,最后进行表达式 //代码块分号可选 @@ -365,7 +363,7 @@ Expression ::= AtExpression { recoverWhile=recoverForExpression } -private recoverForExpression ::= !(Expression|GenericIdentifier|';') +private recoverForExpression ::= !(Expression|Identifier|';') private BinaryExpression ::= SelfAssignExpression | ComparisonExpression | BooleanExpression //加法表达式 @@ -446,7 +444,7 @@ ParenthesizedExpression ::= '(' Expression ')'{ pin=2 } //fake PropertySuffixExpression::= Expression? '.' GenericIdentifier -PropertyExpression ::= Expression '.' GenericIdentifier { +PropertyExpression ::= Expression '.' Identifier { // pin=2 extends=PropertySuffixExpression elementType=PropertySuffixExpression } FunctionInvocationExpression ::= Expression '(' InvocationArguments? ')'{ @@ -465,7 +463,7 @@ ArrayCreationExpression ::= '[' ArrayElements* ']'{ private ArrayElements ::= Expression (','Expression)* ','? -LiteralExpression ::= Numbers | RawStringLiteral | GenericIdentifier | RawColorLiteral +LiteralExpression ::= Numbers | RawStringLiteral | Identifier | RawColorLiteral //------------------------------------------------- @@ -477,7 +475,7 @@ ObjectCreationExpression ::= '{' ObjectPropertyBindings '}'{ private ObjectPropertyBindings ::= ObjectPropertyBinding (','ObjectPropertyBinding)* ','?{ pin=1 } -private ObjectPropertyBinding ::= PropertyName ':' Expression{ +private ObjectPropertyBinding ::= Identifier ':' Expression{ pin=2 recoverWhile=recover } @@ -513,55 +511,35 @@ PrivateKeyword::='private' ReturnKeyword::='return' //---------NamedIdentifier ,简化PsiTree----------------------------------- //noinspection BnfUnusedRule 用于标记命名节点对应的identifier -Named ::= PropertyName | TypeName |ExternalName | InternalName|ComponentName|FunctionName{ - pin=1 -} -{ - extends("PropertyName|TypeName|ComponentName|FunctionName|InternalName|ExternalName")=Named -} -LocalVariable ::= GenericIdentifier{ +LocalVariable ::= Identifier{ extends="me.zhouxi.slint.lang.psi.impl.SlintPsiNamedElementImpl" implements=["me.zhouxi.slint.lang.psi.SlintPsiNamedElement"] } -FunctionName ::= GenericIdentifier - -ComponentName ::=GenericIdentifier - -InternalName ::= GenericIdentifier - -PropertyName ::= GenericIdentifier - -TypeName ::= GenericIdentifier - -EnumName ::= GenericIdentifier - -EnumValue ::=GenericIdentifier - -ExternalName ::=GenericIdentifier - -ReferenceIdentifier::=GenericIdentifier{ - extends="me.zhouxi.slint.lang.psi.impl.SlintReferencedIdentifierImpl" +fake Referred::=Identifier{ + extends="me.zhouxi.slint.lang.psi.impl.SlintRefIdentifierImpl" } -//----------UnnamedIdentifier------------------ - -PropertyNameReference ::= GenericIdentifier{ - extends="me.zhouxi.slint.lang.psi.impl.SlintReferencedIdentifierImpl" +ComponentRef::=Identifier{ + extends=Referred } -FunctionReference ::=GenericIdentifier{ - +QualifiedPropertyRef ::= PropertyRef ('.' PropertyRef)*{ + extends=PropertyRef } -QualifiedPropertyNameReference ::= PropertyNameReference ('.' PropertyNameReference)*{ - extends=PropertyNameReference +PropertyRef ::= Identifier{ + extends=Referred } -TypeNameReference::=GenericIdentifier - -QualifiedTypeNameReference ::= TypeNameReference ('.' TypeNameReference)*{ - extends=TypeNameReference +QualifiedTypeRef::= TypeRef ('.' TypeRef)*{ + extends=TypeRef } -ModuleLocation ::= RawStringLiteral{ - extends="me.zhouxi.slint.lang.psi.impl.SlintReferencedIdentifierImpl" +TypeRef::=Identifier{ + extends=Referred +} +FunctionRef::=Identifier{ + extends=Referred +} +ModuleRef::=RawStringLiteral{ + extends=Referred } // //noinspection BnfSuspiciousToken @@ -571,7 +549,7 @@ private RawStringLiteral ::= StringLiteral private Numbers ::= NumberLiteral //noinspection BnfSuspiciousToken -private GenericIdentifier::= Identifier +private Identifier::= IDENTIFIER //noinspection BnfSuspiciousToken private RawColorLiteral ::= ColorLiteral diff --git a/src/main/grammar/main.flex b/src/main/grammar/main.flex index 28b5622..145c445 100644 --- a/src/main/grammar/main.flex +++ b/src/main/grammar/main.flex @@ -73,7 +73,7 @@ LINECOMMENT=\/\/[^\r\n]* "|" { return Pipe; } "%" { return Percent; } {NUMBERLITERAL} { return NumberLiteral; } -{IDENTIFIER} { return Identifier; } +{IDENTIFIER} { return IDENTIFIER; } {COLORLITERAL} { return ColorLiteral; } {LINECOMMENT} { return LineComment; } } diff --git a/src/main/grammar/sample.bnf b/src/main/grammar/sample.bnf deleted file mode 100644 index 2625b76..0000000 --- a/src/main/grammar/sample.bnf +++ /dev/null @@ -1,68 +0,0 @@ -{ - 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/java/me/zhouxi/slint/lang/psi/SlintPsiRefIdentifier.java b/src/main/java/me/zhouxi/slint/lang/psi/SlintPsiRefIdentifier.java new file mode 100644 index 0000000..d341e1f --- /dev/null +++ b/src/main/java/me/zhouxi/slint/lang/psi/SlintPsiRefIdentifier.java @@ -0,0 +1,5 @@ +package me.zhouxi.slint.lang.psi; + +public interface SlintPsiRefIdentifier extends SlintPsiElement { + +} diff --git a/src/main/java/me/zhouxi/slint/lang/psi/SlintPsiReferencedIdentifier.java b/src/main/java/me/zhouxi/slint/lang/psi/SlintPsiReferencedIdentifier.java deleted file mode 100644 index b3be86e..0000000 --- a/src/main/java/me/zhouxi/slint/lang/psi/SlintPsiReferencedIdentifier.java +++ /dev/null @@ -1,5 +0,0 @@ -package me.zhouxi.slint.lang.psi; - -public interface SlintPsiReferencedIdentifier extends SlintPsiElement { - -} diff --git a/src/main/java/me/zhouxi/slint/lang/psi/impl/SlintReferencedIdentifierImpl.java b/src/main/java/me/zhouxi/slint/lang/psi/impl/SlintRefIdentifierImpl.java similarity index 70% rename from src/main/java/me/zhouxi/slint/lang/psi/impl/SlintReferencedIdentifierImpl.java rename to src/main/java/me/zhouxi/slint/lang/psi/impl/SlintRefIdentifierImpl.java index fbceabb..0a58b18 100644 --- a/src/main/java/me/zhouxi/slint/lang/psi/impl/SlintReferencedIdentifierImpl.java +++ b/src/main/java/me/zhouxi/slint/lang/psi/impl/SlintRefIdentifierImpl.java @@ -3,12 +3,12 @@ package me.zhouxi.slint.lang.psi.impl; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiReference; import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry; -import me.zhouxi.slint.lang.psi.SlintPsiReferencedIdentifier; +import me.zhouxi.slint.lang.psi.SlintPsiRefIdentifier; import org.jetbrains.annotations.NotNull; -public abstract class SlintReferencedIdentifierImpl extends SlintPsiElementImpl implements SlintPsiReferencedIdentifier { +public abstract class SlintRefIdentifierImpl extends SlintPsiElementImpl implements SlintPsiRefIdentifier { - public SlintReferencedIdentifierImpl(@NotNull ASTNode node) { + public SlintRefIdentifierImpl(@NotNull ASTNode node) { super(node); } diff --git a/src/main/java/me/zhouxi/slint/lang/psi/impl/SlintStubBasedPsiNamedElementImpl.kt b/src/main/java/me/zhouxi/slint/lang/psi/impl/SlintStubBasedPsiNamedElementImpl.kt index 287fe52..9b3b332 100644 --- a/src/main/java/me/zhouxi/slint/lang/psi/impl/SlintStubBasedPsiNamedElementImpl.kt +++ b/src/main/java/me/zhouxi/slint/lang/psi/impl/SlintStubBasedPsiNamedElementImpl.kt @@ -9,9 +9,9 @@ import com.intellij.psi.stubs.IStubElementType import com.intellij.psi.stubs.StubElement import com.intellij.util.IncorrectOperationException import me.zhouxi.slint.lang.createIdentifier -import me.zhouxi.slint.lang.psi.SlintNamed import me.zhouxi.slint.lang.psi.SlintPsiElement import me.zhouxi.slint.lang.psi.SlintPsiNamedElement +import me.zhouxi.slint.lang.psi.SlintTypes /** * @author zhouxi 2024/5/23 @@ -24,7 +24,7 @@ abstract class SlintStubBasedPsiNamedElementImpl constructor(stub: T, nodeType: IStubElementType<*, *>) : super(stub, nodeType) override fun getNameIdentifier(): PsiElement? { - return findChildByClass(SlintNamed::class.java) + return findChildByType(SlintTypes.IDENTIFIER) } override fun getName(): String? { diff --git a/src/main/java/me/zhouxi/slint/reference/SlintElementNameManipulator.java b/src/main/java/me/zhouxi/slint/reference/SlintElementNameManipulator.java index 4b7a2ff..8569808 100644 --- a/src/main/java/me/zhouxi/slint/reference/SlintElementNameManipulator.java +++ b/src/main/java/me/zhouxi/slint/reference/SlintElementNameManipulator.java @@ -3,7 +3,7 @@ package me.zhouxi.slint.reference; import com.intellij.openapi.util.TextRange; import com.intellij.psi.AbstractElementManipulator; import com.intellij.util.IncorrectOperationException; -import me.zhouxi.slint.lang.psi.SlintPsiReferencedIdentifier; +import me.zhouxi.slint.lang.psi.SlintPsiRefIdentifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,9 +12,9 @@ import static me.zhouxi.slint.lang.SlintElementFactoryKt.createIdentifier; /** * @author zhouxi 2024/5/8 */ -public class SlintElementNameManipulator extends AbstractElementManipulator { +public class SlintElementNameManipulator extends AbstractElementManipulator { @Override - public @Nullable SlintPsiReferencedIdentifier handleContentChange(@NotNull SlintPsiReferencedIdentifier element, @NotNull TextRange range, String newContent) throws IncorrectOperationException { + public @Nullable SlintPsiRefIdentifier handleContentChange(@NotNull SlintPsiRefIdentifier element, @NotNull TextRange range, String newContent) throws IncorrectOperationException { final var identifier = element.getFirstChild(); if (identifier==null){ throw new IncorrectOperationException("identifier doesn't exist"); @@ -26,7 +26,7 @@ public class SlintElementNameManipulator extends AbstractElementManipulator = arrayOf( - BracePair(SlintTypes.LBrace, SlintTypes.RBrace, true), - BracePair(SlintTypes.LParent, SlintTypes.RParent, true), - BracePair(SlintTypes.LBracket, SlintTypes.RBracket, true), - BracePair(SlintTypes.LAngle, SlintTypes.RAngle, true) - ) - } } + +val Pair: Array = arrayOf( + BracePair(SlintTypes.LBrace, SlintTypes.RBrace, true), + BracePair(SlintTypes.LParent, SlintTypes.RParent, true), + BracePair(SlintTypes.LBracket, SlintTypes.RBracket, true), + BracePair(SlintTypes.LAngle, SlintTypes.RAngle, true) +) \ No newline at end of file diff --git a/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionAutoPopupHandler.kt b/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionAutoPopupHandler.kt index da6a9c9..e4e3824 100644 --- a/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionAutoPopupHandler.kt +++ b/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionAutoPopupHandler.kt @@ -19,12 +19,12 @@ class SlintCompletionAutoPopupHandler : TypedHandlerDelegate() { override fun checkAutoPopup(charTyped: Char, project: Project, editor: Editor, file: PsiFile): Result { val lookup = LookupManager.getActiveLookup(editor) as LookupImpl? - val phase = CompletionServiceImpl.getCompletionPhase() + val phase = CompletionServiceImpl.completionPhase if (LOG.isDebugEnabled) { LOG.debug("checkAutoPopup: character=$charTyped;") LOG.debug("phase=$phase") LOG.debug("lookup=$lookup") - LOG.debug("currentCompletion=" + CompletionServiceImpl.getCompletionService().currentCompletion) + LOG.debug("currentCompletion=" + CompletionServiceImpl.completionService.currentCompletion) } if (lookup != null) { diff --git a/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionContributor.kt b/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionContributor.kt index 4b57341..bb02d58 100644 --- a/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionContributor.kt +++ b/src/main/kotlin/me/zhouxi/slint/completion/SlintCompletionContributor.kt @@ -4,16 +4,20 @@ import com.intellij.codeInsight.completion.CompletionContributor import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.CompletionType import me.zhouxi.slint.completion.provider.* +import me.zhouxi.slint.completion.provider.ComponentNameProvider +import me.zhouxi.slint.completion.provider.SubComponentNameProvider class SlintCompletionContributor : CompletionContributor() { init { - extend(TopKeywordProvider) + extend(TopElementProvider) extend(BasicTypeProvider) extend(AtChildrenCompletionProvider) extend(ComponentElementKeywordProvider) extend(ComponentNameProvider) extend(PropertyBindingProvider) extend(InheritsCompletionProvider) + extend(ExportElementProvider) + extend(SubComponentNameProvider) } private fun extend( diff --git a/src/main/kotlin/me/zhouxi/slint/completion/provider/AbstractSlintCompletionProvider.kt b/src/main/kotlin/me/zhouxi/slint/completion/provider/AbstractSlintCompletionProvider.kt index c4da9e9..5228f02 100644 --- a/src/main/kotlin/me/zhouxi/slint/completion/provider/AbstractSlintCompletionProvider.kt +++ b/src/main/kotlin/me/zhouxi/slint/completion/provider/AbstractSlintCompletionProvider.kt @@ -8,7 +8,7 @@ import com.intellij.psi.PsiElement /** * @author zhouxi 2024/5/29 */ -abstract class AbstractSlintCompletionProvider : CompletionProvider() { +abstract class AbstractSlintCompletionProvider : CompletionProvider() { abstract fun pattern(): ElementPattern } diff --git a/src/main/kotlin/me/zhouxi/slint/completion/provider/ComponentElementKeywordProvider.kt b/src/main/kotlin/me/zhouxi/slint/completion/provider/ComponentElementKeywordProvider.kt index e585748..e39e17a 100644 --- a/src/main/kotlin/me/zhouxi/slint/completion/provider/ComponentElementKeywordProvider.kt +++ b/src/main/kotlin/me/zhouxi/slint/completion/provider/ComponentElementKeywordProvider.kt @@ -22,7 +22,7 @@ object ComponentElementKeywordProvider : AbstractSlintCompletionProvider { return psiElement().withParent(psiElement(Component)) diff --git a/src/main/kotlin/me/zhouxi/slint/completion/provider/ComponentNameProvider.kt b/src/main/kotlin/me/zhouxi/slint/completion/provider/ComponentNameProvider.kt index 58a2a55..593684b 100644 --- a/src/main/kotlin/me/zhouxi/slint/completion/provider/ComponentNameProvider.kt +++ b/src/main/kotlin/me/zhouxi/slint/completion/provider/ComponentNameProvider.kt @@ -1,34 +1,18 @@ package me.zhouxi.slint.completion.provider -import com.intellij.codeInsight.completion.* -import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.codeInsight.lookup.LookupElementBuilder -import com.intellij.codeInsight.lookup.LookupElementDecorator.withInsertHandler import com.intellij.icons.AllIcons -import com.intellij.openapi.vfs.VfsUtil import com.intellij.patterns.ElementPattern import com.intellij.patterns.PlatformPatterns.psiElement import com.intellij.patterns.StandardPatterns.or -import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import com.intellij.psi.PsiManager -import com.intellij.psi.impl.source.tree.LeafPsiElement -import com.intellij.psi.search.GlobalSearchScope.projectScope -import com.intellij.psi.stubs.StubIndex -import com.intellij.psi.util.PsiTreeUtil -import com.intellij.psi.util.childrenOfType import com.intellij.util.ProcessingContext -import me.zhouxi.slint.lang.createComma -import me.zhouxi.slint.lang.createImport -import me.zhouxi.slint.lang.createImportSpecifier -import me.zhouxi.slint.lang.psi.SlintComponent -import me.zhouxi.slint.lang.psi.SlintImport -import me.zhouxi.slint.lang.psi.SlintInheritDeclaration -import me.zhouxi.slint.lang.psi.SlintTypes.Component +import me.zhouxi.slint.lang.psi.SlintTypes.ExportSpecifier import me.zhouxi.slint.lang.psi.SlintTypes.InheritDeclaration -import me.zhouxi.slint.lang.psi.extension.importNames -import me.zhouxi.slint.lang.psi.stubs.index.StubIndexKeys +import me.zhouxi.slint.lang.psi.extension.relativePathOf +import me.zhouxi.slint.lang.psi.stubs.index.searchComponent object ComponentNameProvider : AbstractSlintCompletionProvider() { override fun addCompletions( @@ -37,88 +21,21 @@ object ComponentNameProvider : AbstractSlintCompletionProvider() - StubIndex.getInstance().processAllKeys(StubIndexKeys.Component, project) { - if (result.prefixMatcher.prefixMatches(it)) { - val elements = StubIndex.getElements( - StubIndexKeys.Component, - it, - project, - projectScope(project), - SlintComponent::class.java - ) - components.addAll(elements) - } - true - } + val components = searchComponent(project) { result.prefixMatcher.prefixMatches(it) } val lookups = components.map { - val targetFile = it.containingFile.originalFile val currentFile = parameters.position.containingFile.originalFile.virtualFile - val path = VfsUtil.findRelativePath(currentFile, targetFile.virtualFile, '/') - val builder = LookupElementBuilder.create(it).withTypeText(path).withIcon(AllIcons.Nodes.Class) - withInsertHandler(builder, ComponentInsertHandler(targetFile, path)) + LookupElementBuilder.create(it).withTypeText(it.relativePathOf(currentFile)).withIcon(AllIcons.Nodes.Class) } result.addAllElements(lookups) } - - class ComponentInsertHandler( - private val targetFile: PsiFile, - private val path: String? - ) : InsertHandler { - override fun handleInsert(context: InsertionContext, item: LookupElement) { - //insert '{}' - val caretOffset: Int = context.editor.caretModel.offset - val elementAt = context.file.findElementAt(caretOffset) - if (elementAt?.prevSibling !is SlintInheritDeclaration) { - context.document.insertString(caretOffset, " { }") - context.editor.caretModel.moveToOffset(caretOffset + 3) - PsiDocumentManager.getInstance(context.project).commitDocument(context.document) - } - val component = item.psiElement as SlintComponent - if (component.containingFile.isEquivalentTo(context.file)) { - return - } - val targetImport = context.file.childrenOfType().find { import -> - val target = import.importElement?.moduleLocation?.reference?.resolve() - PsiManager.getInstance(context.project).areElementsEquivalent(target, targetFile) - } - if (targetImport == null) { - //不存在对指定文件的Import,插入 - val import = createImport(context.project, component.componentName!!.text, path!!) - context.file.addBefore(import, context.file.firstChild) - return - } - //如果导入的Name里面包含了这个ComponentName - if (targetImport.importNames().any { it.textMatches(component.componentName!!) }) { - return - } - //引入的文件存在,但是没有导入对应组件 - val importElement = targetImport.importElement!! - val specifier = createImportSpecifier(context.project, component.componentName!!.text) - val last = importElement.importSpecifierList.lastOrNull() - //不存在前置节点 - if (last == null) { - importElement.addAfter(specifier, importElement.childrenOfType()[0]) - PsiDocumentManager.getInstance(context.project).commitDocument(context.document) - return - } - val element = PsiTreeUtil.nextVisibleLeaf(last) - if (!element!!.textMatches(",")) { - val comma = importElement.addAfter(createComma(context.project), last) - importElement.addAfter(specifier, comma) - PsiDocumentManager.getInstance(context.project).commitDocument(context.document) - return - } - PsiDocumentManager.getInstance(context.project).commitDocument(context.document) - importElement.addAfter(specifier, element) - } - } - override fun pattern(): ElementPattern { - return or( - psiElement().withParent(psiElement(Component)).andNot(AtChildrenCompletionProvider.pattern()), - psiElement().withSuperParent(2, psiElement(InheritDeclaration)) - ) + return psiElement() + .withSuperParent( + 2, or( + psiElement(InheritDeclaration), + psiElement(ExportSpecifier) + ) + ) } } diff --git a/src/main/kotlin/me/zhouxi/slint/completion/provider/ExportElementProvider.kt b/src/main/kotlin/me/zhouxi/slint/completion/provider/ExportElementProvider.kt new file mode 100644 index 0000000..370deb6 --- /dev/null +++ b/src/main/kotlin/me/zhouxi/slint/completion/provider/ExportElementProvider.kt @@ -0,0 +1,60 @@ +package me.zhouxi.slint.completion.provider + +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.completion.CompletionResultSet +import com.intellij.codeInsight.completion.InsertHandler +import com.intellij.codeInsight.completion.InsertionContext +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder.create +import com.intellij.codeInsight.template.Template +import com.intellij.codeInsight.template.TemplateEditingAdapter +import com.intellij.codeInsight.template.TemplateManager +import com.intellij.codeInsight.template.impl.ConstantNode +import com.intellij.patterns.ElementPattern +import com.intellij.patterns.PlatformPatterns.psiElement +import com.intellij.psi.PsiElement +import com.intellij.util.ProcessingContext +import me.zhouxi.slint.lang.psi.SlintTypes.Component +import me.zhouxi.slint.lang.psi.stubs.types.SlintFileElementType + +/** + * @author zhouxi 2024/6/6 + */ +object ExportElementProvider : AbstractSlintCompletionProvider() { + + + override fun pattern(): ElementPattern { + return psiElement().withSuperParent(2, psiElement(SlintFileElementType)) + .andNot(psiElement().withParent(psiElement(Component))) + } + + val lookup = arrayOf( + create("export "), + create("export ").withTailText(" {... }").withInsertHandler(MyInsertHandler()) + ).map { it.withBoldness(true) } + + override fun addCompletions( + parameters: CompletionParameters, + context: ProcessingContext, + result: CompletionResultSet + ) { + result.addAllElements(lookup) + } + + + class MyInsertHandler : InsertHandler { + override fun handleInsert(context: InsertionContext, item: LookupElement) { + val manager = TemplateManager.getInstance(context.project) + val template = manager.createTemplate("", "", "{ \$Name$ }").apply { + isToReformat = true + addVariable("Name", ConstantNode(""), true) + } + manager.startTemplate(context.editor, template, object : TemplateEditingAdapter() { + override fun templateFinished(template: Template, brokenOff: Boolean) { + context.editor.caretModel.moveToOffset(context.tailOffset - 2); + } + }) + } + + } +} diff --git a/src/main/kotlin/me/zhouxi/slint/completion/provider/ImportInsertUtils.kt b/src/main/kotlin/me/zhouxi/slint/completion/provider/ImportInsertUtils.kt new file mode 100644 index 0000000..ec83544 --- /dev/null +++ b/src/main/kotlin/me/zhouxi/slint/completion/provider/ImportInsertUtils.kt @@ -0,0 +1,5 @@ +package me.zhouxi.slint.completion.provider + +/** + * @author zhouxi 2024/6/6 + */ diff --git a/src/main/kotlin/me/zhouxi/slint/completion/provider/InheritsCompletionProvider.kt b/src/main/kotlin/me/zhouxi/slint/completion/provider/InheritsCompletionProvider.kt index b33e928..d686380 100644 --- a/src/main/kotlin/me/zhouxi/slint/completion/provider/InheritsCompletionProvider.kt +++ b/src/main/kotlin/me/zhouxi/slint/completion/provider/InheritsCompletionProvider.kt @@ -15,7 +15,7 @@ import me.zhouxi.slint.lang.psi.SlintTypes object InheritsCompletionProvider : AbstractSlintCompletionProvider() { override fun pattern(): ElementPattern { return PlatformPatterns.psiElement() - .afterLeaf(PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(SlintTypes.ComponentName))) + .afterLeaf(PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(SlintTypes.IDENTIFIER))) } override fun addCompletions( diff --git a/src/main/kotlin/me/zhouxi/slint/completion/provider/SubComponentNameProvider.kt b/src/main/kotlin/me/zhouxi/slint/completion/provider/SubComponentNameProvider.kt new file mode 100644 index 0000000..3331489 --- /dev/null +++ b/src/main/kotlin/me/zhouxi/slint/completion/provider/SubComponentNameProvider.kt @@ -0,0 +1,109 @@ +package me.zhouxi.slint.completion.provider + +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.completion.CompletionResultSet +import com.intellij.codeInsight.completion.InsertHandler +import com.intellij.codeInsight.completion.InsertionContext +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.icons.AllIcons +import com.intellij.patterns.ElementPattern +import com.intellij.patterns.PlatformPatterns.psiElement +import com.intellij.patterns.StandardPatterns.or +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.util.childrenOfType +import com.intellij.util.ProcessingContext +import me.zhouxi.slint.lang.createComma +import me.zhouxi.slint.lang.createImport +import me.zhouxi.slint.lang.createImportSpecifier +import me.zhouxi.slint.lang.psi.SlintComponent +import me.zhouxi.slint.lang.psi.SlintImport +import me.zhouxi.slint.lang.psi.SlintTypes.Component +import me.zhouxi.slint.lang.psi.SlintTypes.SubComponent +import me.zhouxi.slint.lang.psi.extension.importNames +import me.zhouxi.slint.lang.psi.extension.relativePathOf +import me.zhouxi.slint.lang.psi.stubs.index.searchComponent + +object SubComponentNameProvider + : AbstractSlintCompletionProvider() { + override fun addCompletions( + parameters: CompletionParameters, + context: ProcessingContext, + result: CompletionResultSet + ) { + val project = parameters.position.project + val components = searchComponent(project) { result.prefixMatcher.prefixMatches(it) } + val lookups = components.map { + val targetFile = it.containingFile.originalFile + val path = it.relativePathOf(parameters.position) ?: targetFile.name + LookupElementBuilder.create(it) + .withInsertHandler(ImportComponentInsertHandler(targetFile, path)) + .withTypeText(path) + .withIcon(AllIcons.Nodes.Class) + } + result.addAllElements(lookups) + } + + + class ImportComponentInsertHandler( + private val targetFile: PsiFile, + private val path: String + ) : InsertHandler { + override fun handleInsert(context: InsertionContext, item: LookupElement) { + //insert '{}' + val caretOffset: Int = context.editor.caretModel.offset + context.document.insertString(caretOffset, " { }") + context.editor.caretModel.moveToOffset(caretOffset + 3) + PsiDocumentManager.getInstance(context.project).commitDocument(context.document) + val component = item.psiElement as SlintComponent + if (component.containingFile.isEquivalentTo(context.file)) { + return + } + val targetImport = context.file.childrenOfType().find { import -> + val target = import.importElement?.moduleRef?.reference?.resolve() + PsiManager.getInstance(context.project).areElementsEquivalent(target, targetFile) + } + if (targetImport == null) { + //不存在对指定文件的Import,插入 + val import = createImport(context.project, component.identifier!!.text, path) + context.file.addBefore(import, context.file.firstChild) + return + } + //如果导入的Name里面包含了这个ComponentName + if (targetImport.importNames().any { it.textMatches(component.identifier!!) }) { + return + } + //引入的文件存在,但是没有导入对应组件 + val importElement = targetImport.importElement!! + val specifier = createImportSpecifier(context.project, component.identifier!!.text) + val last = importElement.importSpecifierList.lastOrNull() + //不存在前置节点 + if (last == null) { + importElement.addAfter(specifier, importElement.childrenOfType()[0]) + PsiDocumentManager.getInstance(context.project).commitDocument(context.document) + return + } + val element = PsiTreeUtil.nextVisibleLeaf(last) + if (!element!!.textMatches(",")) { + val comma = importElement.addAfter(createComma(context.project), last) + importElement.addAfter(specifier, comma) + PsiDocumentManager.getInstance(context.project).commitDocument(context.document) + return + } + PsiDocumentManager.getInstance(context.project).commitDocument(context.document) + importElement.addAfter(specifier, element) + } + } + + override fun pattern(): ElementPattern { + return psiElement() + .withParent(or(psiElement(Component), psiElement(SubComponent))) + .andNot(AtChildrenCompletionProvider.pattern()) + } +} + diff --git a/src/main/kotlin/me/zhouxi/slint/completion/provider/TopKeywordProvider.kt b/src/main/kotlin/me/zhouxi/slint/completion/provider/TopElementProvider.kt similarity index 68% rename from src/main/kotlin/me/zhouxi/slint/completion/provider/TopKeywordProvider.kt rename to src/main/kotlin/me/zhouxi/slint/completion/provider/TopElementProvider.kt index 9540810..a3340d8 100644 --- a/src/main/kotlin/me/zhouxi/slint/completion/provider/TopKeywordProvider.kt +++ b/src/main/kotlin/me/zhouxi/slint/completion/provider/TopElementProvider.kt @@ -1,65 +1,62 @@ -package me.zhouxi.slint.completion.provider - -import com.intellij.codeInsight.completion.CompletionParameters -import com.intellij.codeInsight.completion.CompletionResultSet -import com.intellij.codeInsight.completion.InsertHandler -import com.intellij.codeInsight.completion.InsertionContext -import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.codeInsight.lookup.LookupElementBuilder.* -import com.intellij.codeInsight.template.Template -import com.intellij.codeInsight.template.TemplateEditingAdapter -import com.intellij.codeInsight.template.TemplateManager -import com.intellij.codeInsight.template.impl.ConstantNode -import com.intellij.icons.AllIcons -import com.intellij.patterns.ElementPattern -import com.intellij.patterns.PlatformPatterns.psiElement -import com.intellij.psi.PsiElement -import com.intellij.util.ProcessingContext -import me.zhouxi.slint.lang.psi.SlintTypes.Component -import me.zhouxi.slint.lang.psi.stubs.types.SlintFileElementType - -object TopKeywordProvider : AbstractSlintCompletionProvider() { - override fun addCompletions( - parameters: CompletionParameters, - context: ProcessingContext, - result: CompletionResultSet - ) { - result.addAllElements(completion) - result.addElement(create("component")) - } - - val completion = arrayListOf(create("component "), create("struct "), create("enum ")) - .flatMap { - arrayListOf( - it, - it.withPresentableText(it.lookupString) - .withTailText("\$Name$ {...}") - .withInsertHandler(MyInsertHandler()), - create("export ${it.lookupString}"), - create("export ${it.lookupString}") - .withTailText("\$Name$ {...}") - .withInsertHandler(MyInsertHandler()), - ) - } - - - override fun pattern(): ElementPattern { - return psiElement().withSuperParent(2, psiElement(SlintFileElementType)) - .andNot(psiElement().withParent(psiElement(Component))) - } - - class MyInsertHandler : InsertHandler { - override fun handleInsert(context: InsertionContext, item: LookupElement) { - val manager = TemplateManager.getInstance(context.project) - val template = manager.createTemplate("", "", " \$Name$ { \n }") - template.isToReformat = true - template.addVariable("Name", ConstantNode(""), true) - manager.startTemplate(context.editor, template, object : TemplateEditingAdapter() { - override fun templateFinished(template: Template, brokenOff: Boolean) { - context.editor.caretModel.moveToOffset(context.tailOffset - 2); - } - }) - } - - } -} +package me.zhouxi.slint.completion.provider + +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.completion.CompletionResultSet +import com.intellij.codeInsight.completion.InsertHandler +import com.intellij.codeInsight.completion.InsertionContext +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder.* +import com.intellij.codeInsight.template.Template +import com.intellij.codeInsight.template.TemplateEditingAdapter +import com.intellij.codeInsight.template.TemplateManager +import com.intellij.codeInsight.template.impl.ConstantNode +import com.intellij.patterns.ElementPattern +import com.intellij.patterns.PlatformPatterns.psiElement +import com.intellij.psi.PsiElement +import com.intellij.util.ProcessingContext +import me.zhouxi.slint.lang.psi.SlintTypes.Component +import me.zhouxi.slint.lang.psi.stubs.types.SlintFileElementType + +object TopElementProvider : AbstractSlintCompletionProvider() { + override fun addCompletions( + parameters: CompletionParameters, + context: ProcessingContext, + result: CompletionResultSet + ) { + result.addAllElements(completion) + } + + val completion = arrayListOf( + create("component"), + create("export component"), + create("export component").withTailText(" Name {...}").withInsertHandler(MyInsertHandler()), + create("struct"), + create("export struct"), + create("export struct").withTailText(" Name {...}").withInsertHandler(MyInsertHandler()), + create("enum"), + create("export enum"), + create("export enum").withTailText(" Name {...}").withInsertHandler(MyInsertHandler()), + ).map { it.withBoldness(true) } + + + override fun pattern(): ElementPattern { + return psiElement().withSuperParent(2, psiElement(SlintFileElementType)) + .andNot(psiElement().withParent(psiElement(Component))) + } + + class MyInsertHandler : InsertHandler { + override fun handleInsert(context: InsertionContext, item: LookupElement) { + val manager = TemplateManager.getInstance(context.project) + val template = manager.createTemplate("", "", " \$Name$ { \n }").apply { + isToReformat = true + addVariable("Name", ConstantNode(""), true) + } + manager.startTemplate(context.editor, template, object : TemplateEditingAdapter() { + override fun templateFinished(template: Template, brokenOff: Boolean) { + context.editor.caretModel.moveToOffset(context.tailOffset - 2); + } + }) + } + + } +} diff --git a/src/main/kotlin/me/zhouxi/slint/formatter/FormattingBlock.kt b/src/main/kotlin/me/zhouxi/slint/formatter/FormattingBlock.kt index 8be189e..4fe16ff 100644 --- a/src/main/kotlin/me/zhouxi/slint/formatter/FormattingBlock.kt +++ b/src/main/kotlin/me/zhouxi/slint/formatter/FormattingBlock.kt @@ -8,6 +8,7 @@ import com.intellij.psi.tree.TokenSet import me.zhouxi.slint.lang.psi.SlintPsiKeyword import me.zhouxi.slint.lang.psi.SlintTypes import me.zhouxi.slint.lang.psi.SlintTypes.* +import me.zhouxi.slint.lang.psi.stubs.types.SlintFileElementType import me.zhouxi.slint.lang.psi.utils.braces import me.zhouxi.slint.lang.psi.utils.expressions import me.zhouxi.slint.lang.psi.utils.keywords @@ -35,6 +36,10 @@ class FormattingBlock( if (child.elementType == TokenType.WHITE_SPACE || child.textLength == 0) { continue } + if (Comment.contains(child.elementType)) { + current.add(FormattingBlock(child, wrap, alignment, myIndent, spacingBuilder)) + continue + } if (child.firstChildNode == null || leafTokens.contains(child.elementType)) { current.add(LeafBlock(child, wrap, alignment, Indent.getNoneIndent(), spacingBuilder)) continue @@ -53,6 +58,13 @@ class FormattingBlock( override fun getIndent() = indent + override fun getChildAttributes(newChildIndex: Int): ChildAttributes { + if (node.elementType == SlintFileElementType) { + return ChildAttributes(Indent.getNoneIndent(), null) + } + return super.getChildAttributes(newChildIndex) + } + override fun getSpacing(child1: Block?, child2: Block): Spacing? { if (child2 is SyntheticBlock) { return Spacing.createSpacing(1, 1, 0, true, 2) @@ -65,21 +77,23 @@ class FormattingBlock( } companion object { + private val Comment = TokenSet.create(BlockComment, LineComment) val leafTokens = TokenSet.create( - ReferenceIdentifier, - ComponentName, - InternalName, + ComponentRef, + PropertyRef, + FunctionRef, + TypeRef, LocalVariable, - PropertyName, PropertyModifier, SlintPsiKeyword.ElementType.TYPE ) + + private val syntheticParentTokens = TokenSet.create( + SubComponent, + Component, + GlobalSingleton + ) } - private val syntheticParentTokens = TokenSet.create( - SubComponent, - Component, - GlobalSingleton - ) } diff --git a/src/main/kotlin/me/zhouxi/slint/formatter/LeafBlock.kt b/src/main/kotlin/me/zhouxi/slint/formatter/LeafBlock.kt index b4b70eb..abe3cde 100644 --- a/src/main/kotlin/me/zhouxi/slint/formatter/LeafBlock.kt +++ b/src/main/kotlin/me/zhouxi/slint/formatter/LeafBlock.kt @@ -6,6 +6,9 @@ import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.formatter.common.ExtraRangesProvider import com.intellij.psi.formatter.common.NodeIndentRangesCalculator +import com.intellij.psi.tree.TokenSet +import me.zhouxi.slint.lang.psi.SlintTypes.BlockComment +import me.zhouxi.slint.lang.psi.SlintTypes.LineComment class LeafBlock( private val treeNode: ASTNode, diff --git a/src/main/kotlin/me/zhouxi/slint/formatter/SlintFormatterModelBuilder.kt b/src/main/kotlin/me/zhouxi/slint/formatter/SlintFormatterModelBuilder.kt index f0db79a..0aef9b3 100644 --- a/src/main/kotlin/me/zhouxi/slint/formatter/SlintFormatterModelBuilder.kt +++ b/src/main/kotlin/me/zhouxi/slint/formatter/SlintFormatterModelBuilder.kt @@ -9,6 +9,7 @@ import com.intellij.psi.tree.TokenSet import me.zhouxi.slint.lang.SlintLanguage import me.zhouxi.slint.lang.psi.SlintTypes import me.zhouxi.slint.lang.psi.SlintTypes.* +import me.zhouxi.slint.lang.psi.stubs.types.SlintFileElementType import me.zhouxi.slint.lang.psi.utils.keywords /** @@ -45,7 +46,7 @@ class SlintFormatterModelBuilder : FormattingModelBuilder { .spaces(0) .before(Semicolon) .spacing(0, 0, 0, false, 0) - .after(Semicolon) + .after(TokenSet.create(Semicolon)) .lineBreakInCode() .after(Colon) .spaces(1) @@ -57,6 +58,8 @@ class SlintFormatterModelBuilder : FormattingModelBuilder { .spaces(1) .after(RAngle) .spaces(1) + .afterInside(TokenSet.ANY, SlintFileElementType) + .lineBreakInCode() } } } diff --git a/src/main/kotlin/me/zhouxi/slint/formatter/SyntheticBlock.kt b/src/main/kotlin/me/zhouxi/slint/formatter/SyntheticBlock.kt index 716bbe5..5f5a9e7 100644 --- a/src/main/kotlin/me/zhouxi/slint/formatter/SyntheticBlock.kt +++ b/src/main/kotlin/me/zhouxi/slint/formatter/SyntheticBlock.kt @@ -39,10 +39,11 @@ class SyntheticBlock( ) { return Spacing.createSpacing(1, 1, 0, false, 0) } - return null + return Spacing.createSpacing(0, 1, 1, true, 1) } - override fun getChildAttributes(newChildIndex: Int) = ChildAttributes(null, subBlocks[0].alignment) + override fun getChildAttributes(newChildIndex: Int) = + ChildAttributes(Indent.getNormalIndent(), subBlocks[0].alignment) override fun isIncomplete() = false diff --git a/src/main/kotlin/me/zhouxi/slint/highlight/KeywordHighlightAnnotator.kt b/src/main/kotlin/me/zhouxi/slint/highlight/KeywordHighlightAnnotator.kt index 40627af..a60e551 100644 --- a/src/main/kotlin/me/zhouxi/slint/highlight/KeywordHighlightAnnotator.kt +++ b/src/main/kotlin/me/zhouxi/slint/highlight/KeywordHighlightAnnotator.kt @@ -24,26 +24,42 @@ class KeywordHighlightAnnotator : Annotator { .create() return } - if (element is SlintTypeNameReference && SlintPsiUtils.isInternalType(element)) { + if (element is SlintTypeRef && SlintPsiUtils.isInternalType(element)) { holder.newSilentAnnotation(HighlightSeverity.INFORMATION) .range(element) .textAttributes(Definitions._KeyWord) .create() return } - if (element is SlintPropertyName) { + if (element is SlintPropertyRef) { holder.newSilentAnnotation(HighlightSeverity.INFORMATION) .range(element) .textAttributes(DefaultLanguageHighlighterColors.INSTANCE_FIELD) .create() + return + } + if (element is SlintProperty) { + holder.newSilentAnnotation(HighlightSeverity.INFORMATION) + .range(element.identifier!!) + .textAttributes(DefaultLanguageHighlighterColors.INSTANCE_FIELD) + .create() + return } if (element is SlintPropertyBinding) { holder.newSilentAnnotation(HighlightSeverity.INFORMATION) - .range(element.getReferenceIdentifier()) + .range(element.propertyRef) .textAttributes(DefaultLanguageHighlighterColors.INSTANCE_FIELD) .create() + return } - if (element is SlintFunctionName || element is SlintFunctionReference) { + if (element is SlintFunction) { + holder.newSilentAnnotation(HighlightSeverity.INFORMATION) + .range(element.nameIdentifier!!) + .textAttributes(DefaultLanguageHighlighterColors.INSTANCE_METHOD) + .create() + return + } + if (element is SlintFunctionRef) { holder.newSilentAnnotation(HighlightSeverity.INFORMATION) .range(element) .textAttributes(DefaultLanguageHighlighterColors.INSTANCE_METHOD) diff --git a/src/main/kotlin/me/zhouxi/slint/lang/SlintElementFactory.kt b/src/main/kotlin/me/zhouxi/slint/lang/SlintElementFactory.kt index 95ffbc6..5cbc6d0 100644 --- a/src/main/kotlin/me/zhouxi/slint/lang/SlintElementFactory.kt +++ b/src/main/kotlin/me/zhouxi/slint/lang/SlintElementFactory.kt @@ -16,7 +16,7 @@ import me.zhouxi.slint.lang.psi.SlintImportSpecifier fun createIdentifier(project: Project?, text: String): PsiElement { val factory = PsiFileFactory.getInstance(project) val file = factory.createFileFromText("dummy.slint", SlintLanguage.INSTANCE, "component $text{}") as SlintFile - return file.findChildByClass(SlintComponent::class.java)!!.componentName!!.identifier + return file.findChildByClass(SlintComponent::class.java)!!.identifier!! } fun createImport(project: Project?, text: String, location: String): PsiElement { diff --git a/src/main/kotlin/me/zhouxi/slint/lang/psi/extension/SlintPsiEx.kt b/src/main/kotlin/me/zhouxi/slint/lang/psi/extension/SlintPsiEx.kt index 48b848d..69b99a8 100644 --- a/src/main/kotlin/me/zhouxi/slint/lang/psi/extension/SlintPsiEx.kt +++ b/src/main/kotlin/me/zhouxi/slint/lang/psi/extension/SlintPsiEx.kt @@ -2,7 +2,10 @@ package me.zhouxi.slint.lang.psi.extension import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.icons.AllIcons +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile import com.intellij.psi.util.parentOfType import me.zhouxi.slint.lang.psi.* @@ -10,16 +13,29 @@ import me.zhouxi.slint.lang.psi.* fun SlintComponent.inheritsProperties(): List { val properties = this.propertyList val inherit = - this.inheritDeclaration?.referenceIdentifier?.reference?.resolve() as SlintComponent? ?: return properties + this.inheritDeclaration?.componentRef?.resolve() ?: return properties if (inherit == this) { return properties } return properties + inherit.inheritsProperties() } +fun SlintComponent.relativePathOf(element: PsiElement): String? { + return relativePathOf(element.containingFile) +} -fun SlintImport.importNames(): List { - return this.importElement?.importSpecifierList?.map { it.referenceIdentifier } ?: emptyList() +fun SlintComponent.relativePathOf(psiFile: PsiFile): String? { + return psiFile.originalFile.virtualFile?.let { relativePathOf(it) } +} + +fun SlintComponent.relativePathOf(file: VirtualFile): String? { + val targetFile = this.containingFile.originalFile + return VfsUtil.findRelativePath(file, targetFile.virtualFile, '/') +} + + +fun SlintImport.importNames(): List { + return this.importElement?.importSpecifierList?.map { it.componentRef } ?: emptyList() } /** @@ -28,18 +44,26 @@ fun SlintImport.importNames(): List { */ fun SlintImport.availableNames(): List { return this.importElement?.importSpecifierList?.map { - it.importAlias?.internalName ?: it.referenceIdentifier + it.importAlias?.identifier ?: it.componentRef } ?: emptyList() } fun SlintSubComponent.resolve(): SlintComponent? { - return this.referenceIdentifier.reference?.resolve() as SlintComponent? + return this.componentRef.reference?.resolve() as SlintComponent? } fun SlintProperty.toLookupElement(): LookupElementBuilder { return LookupElementBuilder.create(this) - .withTypeText(this.parentOfType()?.componentName?.text) + .withTypeText(this.parentOfType()?.identifier?.text) .withIcon(AllIcons.Nodes.Property) +} + +fun SlintComponentRef?.resolve(): SlintComponent? { + return this?.reference?.resolve() as SlintComponent? +} + +fun SlintPropertyRef?.resolve(): SlintProperty? { + return this?.reference?.resolve() as SlintProperty? } \ No newline at end of file diff --git a/src/main/kotlin/me/zhouxi/slint/lang/psi/impl/SlintPsiNamedElementImpl.kt b/src/main/kotlin/me/zhouxi/slint/lang/psi/impl/SlintPsiNamedElementImpl.kt index 4975e26..c6bd9df 100644 --- a/src/main/kotlin/me/zhouxi/slint/lang/psi/impl/SlintPsiNamedElementImpl.kt +++ b/src/main/kotlin/me/zhouxi/slint/lang/psi/impl/SlintPsiNamedElementImpl.kt @@ -7,6 +7,7 @@ import com.intellij.util.IncorrectOperationException import me.zhouxi.slint.lang.createIdentifier import me.zhouxi.slint.lang.psi.SlintNamed import me.zhouxi.slint.lang.psi.SlintPsiNamedElement +import me.zhouxi.slint.lang.psi.SlintTypes /** * @author zhouxi 2024/5/15 @@ -14,7 +15,7 @@ import me.zhouxi.slint.lang.psi.SlintPsiNamedElement abstract class SlintPsiNamedElementImpl(node: ASTNode) : SlintPsiElementImpl(node), SlintPsiNamedElement { override fun getNameIdentifier(): PsiElement? { - return findChildByClass(SlintNamed::class.java) ?: this + return findChildByType(SlintTypes.IDENTIFIER) ?: this } override fun getName(): String? { diff --git a/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/index/ExportedNameIndex.java b/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/index/ExportedNameIndex.java deleted file mode 100644 index caee9a0..0000000 --- a/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/index/ExportedNameIndex.java +++ /dev/null @@ -1,4 +0,0 @@ -package me.zhouxi.slint.lang.psi.stubs.index; - -public class ExportedNameIndex { -} diff --git a/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/index/StubIndexEx.kt b/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/index/StubIndexEx.kt index bff2334..18cccc7 100644 --- a/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/index/StubIndexEx.kt +++ b/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/index/StubIndexEx.kt @@ -3,16 +3,46 @@ package me.zhouxi.slint.lang.psi.stubs.index import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.GlobalSearchScope.projectScope import com.intellij.psi.stubs.StubIndex import me.zhouxi.slint.lang.psi.SlintComponent +import java.util.function.Predicate - +/** + * Search Component With Key + */ fun searchComponent(key: String, project: Project, psiFile: PsiFile? = null): Collection { - val scope = psiFile?.let { GlobalSearchScope.fileScope(it) } ?: GlobalSearchScope.projectScope(project) + val scope = psiFile?.let { GlobalSearchScope.fileScope(it) } ?: projectScope(project) return StubIndex.getElements( StubIndexKeys.Component, key, project, scope, SlintComponent::class.java ) +} + +/** + * Search Component With predicate + */ +fun searchComponent( + project: Project, + psiFile: PsiFile? = null, + predicate: Predicate +): Collection { + val scope = psiFile?.let { GlobalSearchScope.fileScope(it) } ?: projectScope(project) + val components = arrayListOf() + StubIndex.getInstance().processAllKeys(StubIndexKeys.Component, project) { + if (predicate.test(it)) { + val elements = StubIndex.getElements( + StubIndexKeys.Component, + it, + project, + scope, + SlintComponent::class.java + ) + components.addAll(elements) + } + true + } + return components } \ No newline at end of file diff --git a/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintComponentElementType.kt b/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintComponentElementType.kt index 2ee1e25..e7cdff9 100644 --- a/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintComponentElementType.kt +++ b/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintComponentElementType.kt @@ -27,7 +27,7 @@ object SlintComponentElementType : return SlintComponentStubImpl( parentStub, psi.exportKeyword != null, - psi.componentName!!.text + psi.identifier!!.text ) } @@ -50,9 +50,9 @@ object SlintComponentElementType : override fun createStub(tree: LighterAST, node: LighterASTNode, parentStub: StubElement<*>): SlintComponentStub { val exported = tree.getChildren(node).any { it.tokenType == ExportKeyword } - val token = tree.getChildren(node).find { it.tokenType == ComponentName } + val token = tree.getChildren(node).find { it.tokenType == IDENTIFIER } ?.let { - val text = tree.getChildren(it)[0] as LighterASTTokenNode + val text = it as LighterASTTokenNode tree.charTable.intern(text.text) } diff --git a/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintImportSpecifierElementType.kt b/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintImportSpecifierElementType.kt index 762c88d..70075ad 100644 --- a/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintImportSpecifierElementType.kt +++ b/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintImportSpecifierElementType.kt @@ -25,14 +25,14 @@ object SlintImportSpecifierElementType : ): SlintImportSpecifierStub { val children = tree.getChildren(node); val name = run { - val nameNode = children.first { it.tokenType == ReferenceIdentifier } + val nameNode = children.first { it.tokenType == ComponentRef } val token = tree.getChildren(nameNode)[0] as LighterASTTokenNode tree.charTable.intern(token.text).toString() } val alias = run { val aliasNode = children.firstOrNull { it.tokenType == ImportAlias } aliasNode?.let { - val nameNode = tree.getChildren(aliasNode).firstOrNull { it.tokenType == InternalName } + val nameNode = tree.getChildren(aliasNode).firstOrNull { it.tokenType == IDENTIFIER } val token = nameNode?.let { tree.getChildren(nameNode) }?.firstOrNull() as LighterASTTokenNode? token?.let { tree.charTable.intern(it.text).toString() @@ -48,8 +48,8 @@ object SlintImportSpecifierElementType : ): SlintImportSpecifierStub { return SlintImportSpecifierStubImpl( parentStub, - psi.referenceIdentifier.text, - psi.importAlias?.internalName?.text + psi.componentRef.text, + psi.importAlias?.identifier?.text ) } diff --git a/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintPropertyElementType.kt b/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintPropertyElementType.kt index d969945..3bbe1d1 100644 --- a/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintPropertyElementType.kt +++ b/src/main/kotlin/me/zhouxi/slint/lang/psi/stubs/types/SlintPropertyElementType.kt @@ -27,7 +27,7 @@ object SlintPropertyElementType : else -> 0 } } ?: 0 - val name = tree.getChildren(children.first { it.tokenType == PropertyName })[0] as LighterASTTokenNode + val name = children.first { it.tokenType == IDENTIFIER } as LighterASTTokenNode return SlintPropertyStubImpl( parentStub, modifierNode.toShort(), @@ -50,7 +50,7 @@ object SlintPropertyElementType : val modifier = psi.propertyModifier val isIn = modifier?.inKeyword != null || modifier?.inOutKeyword != null val isOut = modifier?.outKeyword != null || modifier?.inOutKeyword != null - val name = psi.propertyName!!.text + val name = psi.identifier!!.text val flag = SlintPropertyStubImpl.pack(isIn, isOut) return SlintPropertyStubImpl(parentStub, flag, name) } diff --git a/src/main/kotlin/me/zhouxi/slint/lsp/SlintLspClient.kt b/src/main/kotlin/me/zhouxi/slint/lsp/SlintLspClient.kt new file mode 100644 index 0000000..fb5cade --- /dev/null +++ b/src/main/kotlin/me/zhouxi/slint/lsp/SlintLspClient.kt @@ -0,0 +1,16 @@ +package me.zhouxi.slint.lsp + +import com.intellij.platform.lsp.api.Lsp4jClient +import com.intellij.platform.lsp.api.LspServerNotificationsHandler +import org.eclipse.lsp4j.jsonrpc.services.JsonNotification + +class SlintLspClient(handler: LspServerNotificationsHandler) : Lsp4jClient(handler) { + + + @JsonNotification("@slint/showPreview") + fun formatDocument() { + println("Formatting document") + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/me/zhouxi/slint/lsp/SlintLspServerDescriptor.kt b/src/main/kotlin/me/zhouxi/slint/lsp/SlintLspServerDescriptor.kt new file mode 100644 index 0000000..4f35e9f --- /dev/null +++ b/src/main/kotlin/me/zhouxi/slint/lsp/SlintLspServerDescriptor.kt @@ -0,0 +1,25 @@ +package me.zhouxi.slint.lsp + +import com.intellij.execution.configurations.GeneralCommandLine +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.platform.lsp.api.Lsp4jClient +import com.intellij.platform.lsp.api.LspServerDescriptor +import com.intellij.platform.lsp.api.LspServerNotificationsHandler +import me.zhouxi.slint.preview.SlintViewer + +/** + * @author zhouxi 2024/6/3 + */ +class SlintLspServerDescriptor(project: Project) : LspServerDescriptor(project, "slint") { + + override fun isSupportedFile(file: VirtualFile) = file.extension == "slint" + + override fun createCommandLine() = GeneralCommandLine(SlintViewer.executable()) + + override fun createLsp4jClient(handler: LspServerNotificationsHandler): Lsp4jClient { + return SlintLspClient(handler) + } + + override val lspCompletionSupport = null +} diff --git a/src/main/kotlin/me/zhouxi/slint/lsp/SlintLspServerSupportProvider.kt b/src/main/kotlin/me/zhouxi/slint/lsp/SlintLspServerSupportProvider.kt new file mode 100644 index 0000000..94a9ce9 --- /dev/null +++ b/src/main/kotlin/me/zhouxi/slint/lsp/SlintLspServerSupportProvider.kt @@ -0,0 +1,18 @@ +package me.zhouxi.slint.lsp + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.platform.lsp.api.LspServerSupportProvider +import org.jetbrains.annotations.ApiStatus + +class SlintLspServerSupportProvider : LspServerSupportProvider { + override fun fileOpened( + project: Project, + file: VirtualFile, + serverStarter: LspServerSupportProvider.LspServerStarter + ) { + if (file.extension == "slint") { + serverStarter.ensureServerStarted(SlintLspServerDescriptor(project)) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/me/zhouxi/slint/preview/PreviewRunLineMarkerContributor.kt b/src/main/kotlin/me/zhouxi/slint/preview/PreviewRunLineMarkerContributor.kt index d3b5f5e..eb40101 100644 --- a/src/main/kotlin/me/zhouxi/slint/preview/PreviewRunLineMarkerContributor.kt +++ b/src/main/kotlin/me/zhouxi/slint/preview/PreviewRunLineMarkerContributor.kt @@ -3,15 +3,17 @@ package me.zhouxi.slint.preview import com.intellij.execution.lineMarker.ExecutorAction import com.intellij.execution.lineMarker.RunLineMarkerContributor import com.intellij.psi.PsiElement +import com.intellij.psi.util.elementType import me.zhouxi.slint.lang.SlintLanguage -import me.zhouxi.slint.lang.psi.SlintComponentName +import me.zhouxi.slint.lang.psi.SlintComponent +import me.zhouxi.slint.lang.psi.SlintTypes /** * @author zhouxi 2024/5/16 */ class PreviewRunLineMarkerContributor : RunLineMarkerContributor() { override fun getInfo(element: PsiElement): Info? { - if (element.parent is SlintComponentName) { + if (element.parent is SlintComponent && element.elementType == SlintTypes.IDENTIFIER) { return Info( SlintLanguage.ICON, null, *ExecutorAction.getActions(1) diff --git a/src/main/kotlin/me/zhouxi/slint/preview/SlintViewer.kt b/src/main/kotlin/me/zhouxi/slint/preview/SlintViewer.kt index ed0795e..3dac8cf 100644 --- a/src/main/kotlin/me/zhouxi/slint/preview/SlintViewer.kt +++ b/src/main/kotlin/me/zhouxi/slint/preview/SlintViewer.kt @@ -10,17 +10,17 @@ import java.nio.file.Paths object SlintViewer { private val executable = if (SystemInfo.isWindows) { - "slint-viewer-windows.exe" + "slint-lsp-windows.exe" } else if (SystemInfo.isLinux) { - "slint-viewer-linux" + "slint-lsp-linux" } else if (SystemInfo.isMac) { - "slint-viewer-macos" + "slint-lsp-macos" } else { throw RuntimeException("Unsupported OS") } fun executable(): String { - return Paths.get(Plugin.Path.toAbsolutePath().toString(), "slint-viewer", executable).toString() + return Paths.get(Plugin.Path.toAbsolutePath().toString(), "slint-lsp", executable).toString() } diff --git a/src/main/kotlin/me/zhouxi/slint/reference/SlintReferenceContributor.kt b/src/main/kotlin/me/zhouxi/slint/reference/SlintReferenceContributor.kt index 37a6f2f..1f514a2 100644 --- a/src/main/kotlin/me/zhouxi/slint/reference/SlintReferenceContributor.kt +++ b/src/main/kotlin/me/zhouxi/slint/reference/SlintReferenceContributor.kt @@ -16,31 +16,17 @@ class SlintReferenceContributor : PsiReferenceContributor() { override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { //component Reference registrar.registerReferenceProvider( - psiElement(ReferenceIdentifier) - .withParent( - or( - psiElement(SubComponent), - psiElement(Component), - psiElement(InheritDeclaration), - psiElement(ImportSpecifier) - ) - ), + psiElement(ComponentRef), ComponentReferenceProvider ) //moduleLocation Reference registrar.registerReferenceProvider( - psiElement(ModuleLocation), + psiElement(ModuleRef), ModuleLocationReferenceProvider() ) //property binding registrar.registerReferenceProvider( - psiElement().withParent( - or( - psiElement(PropertyBinding), - psiElement(Component), - psiElement(SubComponent) - ) - ), + psiElement(PropertyRef), PropertyReferenceProvider ) } diff --git a/src/main/kotlin/me/zhouxi/slint/reference/provider/ComponentReferenceProvider.kt b/src/main/kotlin/me/zhouxi/slint/reference/provider/ComponentReferenceProvider.kt index 7a3666e..b57101b 100644 --- a/src/main/kotlin/me/zhouxi/slint/reference/provider/ComponentReferenceProvider.kt +++ b/src/main/kotlin/me/zhouxi/slint/reference/provider/ComponentReferenceProvider.kt @@ -15,27 +15,27 @@ import me.zhouxi.slint.lang.psi.stubs.index.searchComponent */ object ComponentReferenceProvider : PsiReferenceProvider() { override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array { - return arrayOf(SlintComponentNameReference(element as SlintReferenceIdentifier)) + return arrayOf(SlintComponentNameReference(element as SlintComponentRef)) } - class SlintComponentNameReference(element: SlintReferenceIdentifier) : PsiReferenceBase(element) { + class SlintComponentNameReference(element: SlintComponentRef) : PsiReferenceBase(element) { override fun resolve(): PsiElement? { val file = element.containingFile as SlintFile file.childrenOfType() - .find { it.componentName?.textMatches(element) == true } + .find { it.identifier?.textMatches(element) == true } ?.let { return it } val specifier = if (element.parent is SlintImportSpecifier) { element.parent as SlintImportSpecifier } else { file.childrenOfType() .flatMap { it.importElement?.importSpecifierList ?: arrayListOf() } - .find { (it.importAlias?.internalName ?: it.referenceIdentifier).textMatches(element) } + .find { (it.importAlias?.identifier ?: it.componentRef).textMatches(element) } ?: return null } - val componentName = specifier.referenceIdentifier.text - val location = specifier.parentOfType()?.moduleLocation ?: return null + val componentName = specifier.componentRef.text + val location = specifier.parentOfType()?.moduleRef ?: return null val targetFile = location.reference?.resolve()?.containingFile ?: return null val components = searchComponent(componentName, element.project, targetFile) return components.firstOrNull() diff --git a/src/main/kotlin/me/zhouxi/slint/reference/provider/ModuleLocationReferenceProvider.kt b/src/main/kotlin/me/zhouxi/slint/reference/provider/ModuleLocationReferenceProvider.kt index b593cfd..a275961 100644 --- a/src/main/kotlin/me/zhouxi/slint/reference/provider/ModuleLocationReferenceProvider.kt +++ b/src/main/kotlin/me/zhouxi/slint/reference/provider/ModuleLocationReferenceProvider.kt @@ -4,7 +4,7 @@ import com.intellij.openapi.util.TextRange import com.intellij.openapi.vfs.VfsUtil import com.intellij.psi.* import com.intellij.util.ProcessingContext -import me.zhouxi.slint.lang.psi.SlintModuleLocation +import me.zhouxi.slint.lang.psi.SlintModuleRef /** * @author zhouxi 2024/5/17 @@ -16,7 +16,7 @@ class ModuleLocationReferenceProvider : PsiReferenceProvider() { class ModuleLocationReference(element: PsiElement) : PsiReferenceBase(element) { override fun resolve(): PsiElement? { - val location = element as SlintModuleLocation + val location = element as SlintModuleRef val filenameText = location.stringLiteral.text if (filenameText.length < 3) return null val directory = element.containingFile.originalFile.virtualFile?.parent ?: return null @@ -29,6 +29,7 @@ class ModuleLocationReferenceProvider : PsiReferenceProvider() { override fun calculateDefaultRangeInElement(): TextRange { return TextRange(1, element.textLength - 1) } + override fun bindToElement(element: PsiElement): PsiElement { return element } 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 d650c48..83323cf 100644 --- a/src/main/kotlin/me/zhouxi/slint/reference/provider/PropertyReferenceProvider.kt +++ b/src/main/kotlin/me/zhouxi/slint/reference/provider/PropertyReferenceProvider.kt @@ -9,6 +9,7 @@ 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 +import me.zhouxi.slint.lang.psi.extension.resolve object PropertyReferenceProvider : PsiReferenceProvider() { override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array { @@ -19,11 +20,11 @@ object PropertyReferenceProvider : PsiReferenceProvider() { override fun resolve(): PsiElement? { 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 = subComponent.resolve() ?: return null + return component.inheritsProperties().find { it.identifier?.textMatches(element) == true } } val component = element.parentOfType() ?: return null - return component.inheritsProperties().find { it.propertyName?.textMatches(element) == true } + return component.inheritsProperties().find { it.identifier?.textMatches(element) == true } } } } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 1c5f97a..959353a 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -11,6 +11,9 @@ com.intellij.modules.platform + + + @@ -29,7 +32,7 @@ -