fix: 语法问题

This commit is contained in:
me
2024-06-06 15:20:08 +08:00
parent 39a81fcb5d
commit 1b9faa6f09
45 changed files with 578 additions and 444 deletions

View File

@@ -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<JavaExec>().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)

View File

@@ -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 <type> name: value / in property <type> 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

View File

@@ -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; }
}

View File

@@ -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)

View File

@@ -0,0 +1,5 @@
package me.zhouxi.slint.lang.psi;
public interface SlintPsiRefIdentifier extends SlintPsiElement {
}

View File

@@ -1,5 +0,0 @@
package me.zhouxi.slint.lang.psi;
public interface SlintPsiReferencedIdentifier extends SlintPsiElement {
}

View File

@@ -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);
}

View File

@@ -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<T : StubElement<out PsiElement>
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? {

View File

@@ -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<SlintPsiReferencedIdentifier> {
public class SlintElementNameManipulator extends AbstractElementManipulator<SlintPsiRefIdentifier> {
@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<Slin
@Override
@NotNull
public TextRange getRangeInElement(@NotNull final SlintPsiReferencedIdentifier element) {
public TextRange getRangeInElement(@NotNull final SlintPsiRefIdentifier element) {
return new TextRange(0,element.getTextLength());
}
}

View File

@@ -19,12 +19,11 @@ class SlintPairedBraceMatcher : PairedBraceMatcher {
return 0
}
companion object {
val Pair: Array<BracePair> = 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<BracePair> = 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)
)

View File

@@ -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) {

View File

@@ -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(

View File

@@ -8,7 +8,7 @@ import com.intellij.psi.PsiElement
/**
* @author zhouxi 2024/5/29
*/
abstract class AbstractSlintCompletionProvider<V : CompletionParameters?> : CompletionProvider<V>() {
abstract class AbstractSlintCompletionProvider<V : CompletionParameters> : CompletionProvider<V>() {
abstract fun pattern(): ElementPattern<out PsiElement>
}

View File

@@ -22,7 +22,7 @@ object ComponentElementKeywordProvider : AbstractSlintCompletionProvider<Complet
"in", "out", "in-out", "callback",
"property", "private", "changed",
"states", "transitions", "function"
).map { LookupElementBuilder.create(it) }
).map { LookupElementBuilder.create(it).withBoldness(true) }
override fun pattern(): ElementPattern<out PsiElement> {
return psiElement().withParent(psiElement(Component))

View File

@@ -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<CompletionParameters>() {
override fun addCompletions(
@@ -37,88 +21,21 @@ object ComponentNameProvider : AbstractSlintCompletionProvider<CompletionParamet
result: CompletionResultSet
) {
val project = parameters.position.project
val components = arrayListOf<SlintComponent>()
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<LookupElement> {
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<SlintImport>().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<LeafPsiElement>()[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<out PsiElement> {
return or(
psiElement().withParent(psiElement(Component)).andNot(AtChildrenCompletionProvider.pattern()),
psiElement().withSuperParent(2, psiElement(InheritDeclaration))
)
return psiElement()
.withSuperParent(
2, or(
psiElement(InheritDeclaration),
psiElement(ExportSpecifier)
)
)
}
}

View File

@@ -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<CompletionParameters>() {
override fun pattern(): ElementPattern<out PsiElement> {
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<LookupElement> {
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);
}
})
}
}
}

View File

@@ -0,0 +1,5 @@
package me.zhouxi.slint.completion.provider
/**
* @author zhouxi 2024/6/6
*/

View File

@@ -15,7 +15,7 @@ import me.zhouxi.slint.lang.psi.SlintTypes
object InheritsCompletionProvider : AbstractSlintCompletionProvider<CompletionParameters>() {
override fun pattern(): ElementPattern<out PsiElement> {
return PlatformPatterns.psiElement()
.afterLeaf(PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(SlintTypes.ComponentName)))
.afterLeaf(PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(SlintTypes.IDENTIFIER)))
}
override fun addCompletions(

View File

@@ -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<CompletionParameters>() {
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<LookupElement> {
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<SlintImport>().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<LeafPsiElement>()[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<out PsiElement> {
return psiElement()
.withParent(or(psiElement(Component), psiElement(SubComponent)))
.andNot(AtChildrenCompletionProvider.pattern())
}
}

View File

@@ -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<CompletionParameters>() {
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<out PsiElement> {
return psiElement().withSuperParent(2, psiElement(SlintFileElementType))
.andNot(psiElement().withParent(psiElement(Component)))
}
class MyInsertHandler : InsertHandler<LookupElement> {
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<CompletionParameters>() {
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<out PsiElement> {
return psiElement().withSuperParent(2, psiElement(SlintFileElementType))
.andNot(psiElement().withParent(psiElement(Component)))
}
class MyInsertHandler : InsertHandler<LookupElement> {
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);
}
})
}
}
}

View File

@@ -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
)
}

View File

@@ -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,

View File

@@ -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()
}
}
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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<SlintProperty> {
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<SlintReferenceIdentifier> {
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<SlintComponentRef> {
return this.importElement?.importSpecifierList?.map { it.componentRef } ?: emptyList()
}
/**
@@ -28,18 +44,26 @@ fun SlintImport.importNames(): List<SlintReferenceIdentifier> {
*/
fun SlintImport.availableNames(): List<PsiElement> {
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<SlintComponent>()?.componentName?.text)
.withTypeText(this.parentOfType<SlintComponent>()?.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?
}

View File

@@ -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? {

View File

@@ -1,4 +0,0 @@
package me.zhouxi.slint.lang.psi.stubs.index;
public class ExportedNameIndex {
}

View File

@@ -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<SlintComponent> {
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<String>
): Collection<SlintComponent> {
val scope = psiFile?.let { GlobalSearchScope.fileScope(it) } ?: projectScope(project)
val components = arrayListOf<SlintComponent>()
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
}

View File

@@ -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)
}

View File

@@ -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
)
}

View File

@@ -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)
}

View File

@@ -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")
}
}

View File

@@ -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
}

View File

@@ -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))
}
}
}

View File

@@ -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)

View File

@@ -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()
}

View File

@@ -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
)
}

View File

@@ -15,27 +15,27 @@ import me.zhouxi.slint.lang.psi.stubs.index.searchComponent
*/
object ComponentReferenceProvider : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {
return arrayOf(SlintComponentNameReference(element as SlintReferenceIdentifier))
return arrayOf(SlintComponentNameReference(element as SlintComponentRef))
}
class SlintComponentNameReference(element: SlintReferenceIdentifier) : PsiReferenceBase<PsiElement?>(element) {
class SlintComponentNameReference(element: SlintComponentRef) : PsiReferenceBase<PsiElement?>(element) {
override fun resolve(): PsiElement? {
val file = element.containingFile as SlintFile
file.childrenOfType<SlintComponent>()
.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<SlintImport>()
.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<SlintImportElement>()?.moduleLocation ?: return null
val componentName = specifier.componentRef.text
val location = specifier.parentOfType<SlintImportElement>()?.moduleRef ?: return null
val targetFile = location.reference?.resolve()?.containingFile ?: return null
val components = searchComponent(componentName, element.project, targetFile)
return components.firstOrNull()

View File

@@ -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<PsiElement?>(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
}

View File

@@ -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<PsiReference> {
@@ -19,11 +20,11 @@ object PropertyReferenceProvider : PsiReferenceProvider() {
override fun resolve(): PsiElement? {
val subComponent = element.parentOfType<SlintSubComponent>()
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<SlintComponent>() ?: return null
return component.inheritsProperties().find { it.propertyName?.textMatches(element) == true }
return component.inheritsProperties().find { it.identifier?.textMatches(element) == true }
}
}
}

View File

@@ -11,6 +11,9 @@
<depends>com.intellij.modules.platform</depends>
<extensions defaultExtensionNs="com.intellij">
<platform.lsp.serverSupportProvider implementation="me.zhouxi.slint.lsp.SlintLspServerSupportProvider"/>
<typedHandler implementation="me.zhouxi.slint.completion.SlintCompletionAutoPopupHandler"
id="completionAutoPopup"
order="first"/>
@@ -29,7 +32,7 @@
<lang.braceMatcher language="Slint"
implementationClass="me.zhouxi.slint.brace.SlintPairedBraceMatcher"/>
<lang.elementManipulator forClass="me.zhouxi.slint.lang.psi.SlintPsiReferencedIdentifier"
<lang.elementManipulator forClass="me.zhouxi.slint.lang.psi.SlintPsiRefIdentifier"
implementationClass="me.zhouxi.slint.reference.SlintElementNameManipulator"/>
<completion.contributor language="Slint"

View File

@@ -1,7 +1,6 @@
import com.intellij.lexer.FlexAdapter;
import com.intellij.lexer.Lexer;
import com.intellij.testFramework.LexerTestCase;
import lombok.extern.slf4j.Slf4j;
import me.zhouxi.slint.lang.lexer.SlintLexer;
import org.jetbrains.annotations.NotNull;
import org.junit.Rule;
@@ -16,7 +15,6 @@ import java.util.concurrent.TimeUnit;
/**
* @author zhouxi 2024/4/30
*/
@Slf4j
public class LexerTest extends LexerTestCase {
@Override
@@ -44,12 +42,12 @@ public class LexerTest extends LexerTestCase {
public Stopwatch stopwatch = new Stopwatch() {
@Override
protected void succeeded(long nanos, Description description) {
log.info("{} succeeded, time taken: {} ms", description.getMethodName(), TimeUnit.NANOSECONDS.toMillis(nanos));
// log.info("{} succeeded, time taken: {} ms", description.getMethodName(), TimeUnit.NANOSECONDS.toMillis(nanos));
}
@Override
protected void failed(long nanos, Throwable e, Description description) {
log.info("{} failed, time taken: {} ms", description.getMethodName(), TimeUnit.NANOSECONDS.toMillis(nanos));
// log.info("{} failed, time taken: {} ms", description.getMethodName(), TimeUnit.NANOSECONDS.toMillis(nanos));
}
};
}

View File

@@ -22,12 +22,12 @@ public class ParserTest extends ParsingTestCase {
public void test() throws IOException {
final var path = Paths.get("src/test/resources/slint/main.slint");
var source = Files.readString(path);
StopWatch started = StopWatch.createStarted();
for (int i = 0; i < 50000; i++) {
doCodeTest(source);
}
started.stop();
System.out.println(started.getNanoTime()/50000);
var source = """
component App{
aaa;
property name;
}
""";
doCodeTest(source);
}
}