fix: 语法问题

This commit is contained in:
me
2024-05-29 19:30:01 +08:00
parent c6f45b3368
commit ad35338f49
28 changed files with 600 additions and 226 deletions

View File

@@ -0,0 +1,55 @@
package me.zhouxi.slint.completion
import com.intellij.codeInsight.AutoPopupController
import com.intellij.codeInsight.completion.CompletionPhase.EmptyAutoPopup
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl
import com.intellij.codeInsight.editorActions.TypedHandlerDelegate
import com.intellij.codeInsight.lookup.LookupManager
import com.intellij.codeInsight.lookup.impl.LookupImpl
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorModificationUtil
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
/**
* @author zhouxi 2024/5/29
*/
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()
if (LOG.isDebugEnabled) {
LOG.debug("checkAutoPopup: character=$charTyped;")
LOG.debug("phase=$phase")
LOG.debug("lookup=$lookup")
LOG.debug("currentCompletion=" + CompletionServiceImpl.getCompletionService().currentCompletion)
}
if (lookup != null) {
if (editor.selectionModel.hasSelection()) {
lookup.performGuardedChange(Runnable { EditorModificationUtil.deleteSelectedText(editor) })
}
return Result.STOP
}
if (Character.isLetterOrDigit(charTyped) || charTyped == '_' || charTyped == '@') {
if (phase is EmptyAutoPopup && phase.allowsSkippingNewAutoPopup(editor, charTyped)) {
return Result.CONTINUE
}
AutoPopupController.getInstance(project).scheduleAutoPopup(editor)
return Result.STOP
}
return Result.CONTINUE
}
companion object {
private val LOG = Logger.getInstance(
SlintCompletionAutoPopupHandler::class.java
)
}
}

View File

@@ -1,47 +1,30 @@
package me.zhouxi.slint.completion
import com.intellij.codeInsight.completion.CompletionContributor
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.patterns.PlatformPatterns
import com.intellij.openapi.util.Pair
import com.intellij.patterns.ElementPattern
import com.intellij.psi.PsiElement
import me.zhouxi.slint.completion.provider.*
import me.zhouxi.slint.lang.psi.SlintTypes
import me.zhouxi.slint.lang.psi.SlintTypes.Component
import me.zhouxi.slint.lang.psi.stubs.types.SlintFileElementType
class SlintCompletionContributor : CompletionContributor() {
init {
//文件级别
extend(
CompletionType.BASIC,
PlatformPatterns.psiElement().withAncestor(3, PlatformPatterns.psiElement(SlintFileElementType)),
TopKeywordProvider
)
extend(TopKeywordProvider)
extend(BasicTypeProvider)
extend(AtChildrenCompletionProvider)
extend(ElementKeywordProvider)
extend(ComponentProvider)
extend(PropertyBindingProvider)
extend(InheritsCompletionProvider)
}
//类型定义
extend(
CompletionType.BASIC,
PlatformPatterns.psiElement().withAncestor(3, PlatformPatterns.psiElement(SlintTypes.Type)),
BasicTypeProvider
)
//componentBody
extend(
CompletionType.BASIC,
PlatformPatterns.psiElement().withAncestor(2, PlatformPatterns.psiElement(Component)),
ElementKeywordProvider
)
//componentBody
extend(
CompletionType.BASIC,
PlatformPatterns.psiElement().withAncestor(2,PlatformPatterns.psiElement(Component)),
ComponentProvider
)
//propertyBinding
extend(
CompletionType.BASIC,
PlatformPatterns.psiElement().withAncestor(2, PlatformPatterns.psiElement(Component)),
PropertyBindingProvider
)
private fun extend(
provider: AbstractSlintCompletionProvider<CompletionParameters>,
type: CompletionType = CompletionType.BASIC,
) {
extend(type, provider.pattern(), provider)
}
}

View File

@@ -0,0 +1,14 @@
package me.zhouxi.slint.completion.provider
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.patterns.ElementPattern
import com.intellij.psi.PsiElement
/**
* @author zhouxi 2024/5/29
*/
abstract class AbstractSlintCompletionProvider<V : CompletionParameters?> : CompletionProvider<V>() {
abstract fun pattern(): ElementPattern<out PsiElement>
}

View File

@@ -0,0 +1,32 @@
package me.zhouxi.slint.completion.provider
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionResultSet
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.psi.PsiElement
import com.intellij.util.ProcessingContext
import me.zhouxi.slint.lang.psi.SlintTypes.Component
/**
* @author zhouxi 2024/5/29
*/
object AtChildrenCompletionProvider : AbstractSlintCompletionProvider<CompletionParameters>() {
override fun pattern(): ElementPattern<out PsiElement> {
return psiElement()
.afterLeaf(psiElement().withText("@"))
.withParent(psiElement(Component))
}
val element = LookupElementBuilder.create("children").withIcon(AllIcons.Nodes.Annotationtype)
override fun addCompletions(
parameters: CompletionParameters,
context: ProcessingContext,
result: CompletionResultSet
) {
result.addElement(element)
}
}

View File

@@ -1,13 +1,16 @@
package me.zhouxi.slint.completion.provider
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.psi.PsiElement
import com.intellij.util.ProcessingContext
import me.zhouxi.slint.lang.psi.SlintPsiUtils.InternalTypes
import me.zhouxi.slint.lang.psi.SlintTypes.Type
object BasicTypeProvider : CompletionProvider<CompletionParameters>() {
object BasicTypeProvider : AbstractSlintCompletionProvider<CompletionParameters>() {
override fun addCompletions(
parameters: CompletionParameters,
context: ProcessingContext,
@@ -17,4 +20,9 @@ object BasicTypeProvider : CompletionProvider<CompletionParameters>() {
}
private val basicTypes = InternalTypes.map { LookupElementBuilder.create(it) }
override fun pattern(): ElementPattern<out PsiElement> {
return psiElement().withAncestor(3, psiElement(Type))
}
}

View File

@@ -3,11 +3,14 @@ package me.zhouxi.slint.completion.provider
import com.intellij.codeInsight.completion.*
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.codeInsight.lookup.LookupElementDecorator
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
@@ -15,17 +18,20 @@ 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.psi.util.parentOfTypes
import com.intellij.psi.util.parentOfType
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.InheritDeclaration
import me.zhouxi.slint.lang.psi.extension.importNames
import me.zhouxi.slint.lang.psi.stubs.index.StubIndexKeys
object ComponentProvider : CompletionProvider<CompletionParameters>() {
object ComponentProvider : AbstractSlintCompletionProvider<CompletionParameters>() {
override fun addCompletions(
parameters: CompletionParameters,
context: ProcessingContext,
@@ -62,7 +68,18 @@ object ComponentProvider : CompletionProvider<CompletionParameters>() {
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 + 1)
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)
@@ -98,4 +115,11 @@ object ComponentProvider : CompletionProvider<CompletionParameters>() {
importElement.addAfter(specifier, element)
}
}
override fun pattern(): ElementPattern<out PsiElement> {
return or(
psiElement().withParent(psiElement(Component)).andNot(AtChildrenCompletionProvider.pattern()),
psiElement().withSuperParent(2, psiElement(InheritDeclaration))
)
}
}

View File

@@ -4,9 +4,13 @@ import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.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
object ElementKeywordProvider : CompletionProvider<CompletionParameters>() {
object ElementKeywordProvider : AbstractSlintCompletionProvider<CompletionParameters>() {
override fun addCompletions(
parameters: CompletionParameters,
context: ProcessingContext,
@@ -18,6 +22,11 @@ object ElementKeywordProvider : CompletionProvider<CompletionParameters>() {
private val elementKeywords = arrayOf(
"in", "out", "in-out", "callback",
"property", "private", "changed",
"states", "transitions", "@children"
"states", "transitions", "function"
).map { LookupElementBuilder.create(it) }
override fun pattern(): ElementPattern<out PsiElement> {
return psiElement().withParent(psiElement(Component))
.andNot(AtChildrenCompletionProvider.pattern())
}
}

View File

@@ -0,0 +1,28 @@
package me.zhouxi.slint.completion.provider
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PlatformPatterns
import com.intellij.psi.PsiElement
import com.intellij.util.ProcessingContext
import me.zhouxi.slint.lang.psi.SlintTypes
/**
* @author zhouxi 2024/5/29
*/
object InheritsCompletionProvider : AbstractSlintCompletionProvider<CompletionParameters>() {
override fun pattern(): ElementPattern<out PsiElement> {
return PlatformPatterns.psiElement()
.afterLeaf(PlatformPatterns.psiElement().withParent(PlatformPatterns.psiElement(SlintTypes.ComponentName)))
}
override fun addCompletions(
parameters: CompletionParameters,
context: ProcessingContext,
result: CompletionResultSet
) {
result.addElement(LookupElementBuilder.create("inherits"))
}
}

View File

@@ -5,30 +5,36 @@ import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.icons.AllIcons
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.patterns.StandardPatterns.or
import com.intellij.psi.PsiElement
import com.intellij.psi.util.parentOfType
import com.intellij.util.ProcessingContext
import me.zhouxi.slint.lang.psi.SlintComponent
import me.zhouxi.slint.lang.psi.SlintSubComponent
import me.zhouxi.slint.lang.psi.SlintTypes.Component
import me.zhouxi.slint.lang.psi.SlintTypes.SubComponent
import me.zhouxi.slint.lang.psi.extension.inheritsProperties
import me.zhouxi.slint.lang.psi.extension.resolve
import me.zhouxi.slint.lang.psi.extension.toLookupElement
object PropertyBindingProvider : CompletionProvider<CompletionParameters>() {
object PropertyBindingProvider : AbstractSlintCompletionProvider<CompletionParameters>() {
override fun addCompletions(
parameters: CompletionParameters,
context: ProcessingContext,
result: CompletionResultSet
) {
val element = parameters.position
val subComponent = element.parentOfType<SlintSubComponent>()
if (subComponent != null) {
val component = subComponent.referenceIdentifier.reference?.resolve() as SlintComponent? ?: return
val builders = component.inheritsProperties()
.map { LookupElementBuilder.create(it).withTypeText(component.name).withIcon(AllIcons.Nodes.Property) }
result.addAllElements(builders)
} else {
val component = element.parentOfType<SlintComponent>() ?: return
val builders = component.inheritsProperties()
.map { LookupElementBuilder.create(it).withTypeText(component.name).withIcon(AllIcons.Nodes.Property) }
result.addAllElements(builders)
val component = element.parentOfType<SlintSubComponent>()?.resolve()
?: element.parentOfType<SlintComponent>()
component?.let {
result.addAllElements(it.inheritsProperties().map { it.toLookupElement() })
}
}
override fun pattern(): ElementPattern<out PsiElement> {
return psiElement().withParent(or(psiElement(Component), psiElement(SubComponent)))
.andNot(AtChildrenCompletionProvider.pattern())
}
}

View File

@@ -1,12 +1,15 @@
package me.zhouxi.slint.completion.provider
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.psi.PsiElement
import com.intellij.util.ProcessingContext
import me.zhouxi.slint.lang.psi.stubs.types.SlintFileElementType
object TopKeywordProvider : CompletionProvider<CompletionParameters>() {
object TopKeywordProvider : AbstractSlintCompletionProvider<CompletionParameters>() {
override fun addCompletions(
parameters: CompletionParameters,
context: ProcessingContext,
@@ -17,4 +20,8 @@ object TopKeywordProvider : CompletionProvider<CompletionParameters>() {
private val topKeywords =
arrayOf("export", "component", "global", "enum", "struct").map { LookupElementBuilder.create(it) }
override fun pattern(): ElementPattern<out PsiElement> {
return psiElement().withSuperParent(1, psiElement(SlintFileElementType))
}
}

View File

@@ -0,0 +1,79 @@
package me.zhouxi.slint.formatter
import com.intellij.formatting.*
import com.intellij.lang.ASTNode
import com.intellij.psi.TokenType
import com.intellij.psi.formatter.common.AbstractBlock
import com.intellij.psi.tree.TokenSet
import me.zhouxi.slint.lang.psi.SlintTypes
import me.zhouxi.slint.lang.psi.SlintTypes.*
import me.zhouxi.slint.lang.psi.utils.braces
import me.zhouxi.slint.lang.psi.utils.expressions
import me.zhouxi.slint.lang.psi.utils.keywords
/**
* @author zhouxi 2024/5/28
*/
class FormattingBlock(
node: ASTNode,
wrap: Wrap?,
alignment: Alignment?,
private val indent: Indent?,
private val spacingBuilder: SpacingBuilder
) : AbstractBlock(node, wrap, alignment) {
override fun buildChildren(): List<Block> {
val childBlocks = arrayListOf<Block>()
val syntheticBlocks = arrayListOf<Block>()
var current = childBlocks
var myIndent: Indent? = indent
for (child in node.getChildren(null)) {
if (braces.contains(child.elementType) && (node.elementType == SubComponent || node.elementType == Component)) {
current = syntheticBlocks
myIndent = Indent.getNormalIndent()
}
if (child.elementType == TokenType.WHITE_SPACE || child.textLength == 0) {
continue
}
if (child.firstChildNode == null || leafTokens.contains(child.elementType)) {
current.add(LeafBlock(child, wrap, alignment, Indent.getNoneIndent(), spacingBuilder))
continue
}
if (expressions.contains(child.elementType)) {
current.add(FormattingBlock(child, wrap, alignment, null, spacingBuilder))
continue
}
current.add(FormattingBlock(child, wrap, alignment, myIndent, spacingBuilder))
}
if (syntheticBlocks.isNotEmpty()) {
childBlocks.add(SyntheticBlock(syntheticBlocks, wrap, Indent.getNormalIndent(), alignment, spacingBuilder))
}
return childBlocks
}
override fun getIndent() = indent
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
if (child2 is SyntheticBlock) {
return Spacing.createSpacing(1, 1, 0, true, 2)
}
return spacingBuilder.getSpacing(this, child1, child2)
}
override fun isLeaf(): Boolean {
return false
}
companion object {
val leafTokens =
TokenSet.orSet(
TokenSet.create(
ReferenceIdentifier,
ComponentName,
InternalName,
LocalVariable,
PropertyName
),
keywords
)
}
}

View File

@@ -0,0 +1,55 @@
package me.zhouxi.slint.formatter
import com.intellij.formatting.*
import com.intellij.lang.ASTNode
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
class LeafBlock(
private val treeNode: ASTNode,
private val wrap: Wrap?,
private val alignment: Alignment?,
private val indent: Indent?,
private val spacingBuilder: SpacingBuilder
) : ASTBlock, ExtraRangesProvider {
override fun getNode() = treeNode
override fun getTextRange(): TextRange = treeNode.textRange
override fun getSubBlocks() = EMPTY_SUB_BLOCKS
override fun getWrap() = wrap
override fun getIndent() = indent
override fun getAlignment() = alignment
override fun getSpacing(child1: Block?, child2: Block) = null
override fun getChildAttributes(newChildIndex: Int) = ChildAttributes(indent, null)
override fun isIncomplete() = false
override fun isLeaf() = true
override fun getExtraRangesToFormat(info: FormattingRangesInfo): List<TextRange>? {
val startOffset = textRange.startOffset
if (info.isOnInsertedLine(startOffset) && treeNode.textLength == 1 && treeNode.textContains('}')) {
val parent = treeNode.treeParent
return NodeIndentRangesCalculator(parent).calculateExtraRanges()
}
return null
}
override fun toString(): String {
return javaClass.simpleName + " '" + StringUtil.escapeLineBreak(node.text) + "' " + textRange
}
companion object {
private val EMPTY_SUB_BLOCKS = ArrayList<Block>()
}
}

View File

@@ -0,0 +1,61 @@
package me.zhouxi.slint.formatter
import com.intellij.formatting.*
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiFile
import com.intellij.psi.codeStyle.CodeStyleSettings
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.utils.keywords
/**
* @author zhouxi 2024/5/7
*/
class SlintFormatterModelBuilder : FormattingModelBuilder {
override fun createModel(formattingContext: FormattingContext): FormattingModel {
val element = formattingContext.psiElement
val spacingBuilder = createSpaceBuilder(formattingContext.codeStyleSettings)
val slintBlock = FormattingBlock(
formattingContext.node,
null,
null,
Indent.getNoneIndent(),
spacingBuilder
)
return FormattingModelProvider.createFormattingModelForPsiFile(
element.containingFile,
slintBlock,
formattingContext.codeStyleSettings
)
}
override fun getRangeAffectingIndent(file: PsiFile, offset: Int, elementAtOffset: ASTNode): TextRange? {
return file.textRange
}
companion object {
private fun createSpaceBuilder(settings: CodeStyleSettings): SpacingBuilder {
return SpacingBuilder(settings, SlintLanguage.INSTANCE)
.after(Comma)
.spaces(1)
.before(Comma)
.spaces(0)
.before(Semicolon)
.spacing(0, 0, 0, false, 0)
.after(Semicolon)
.lineBreakInCode()
.after(Colon)
.spaces(1)
.around(TokenSet.create(DoubleArrow, Plus, Minus, Star, Div))
.spaces(1)
.before(CodeBlock)
.spacing(1, 1, 0, true, 2)
.around(keywords)
.spaces(1)
}
}
}

View File

@@ -20,19 +20,19 @@ class SlintLineIndentProvider : JavaLikeLangLineIndentProvider() {
}
companion object {
val SyntaxMap: Map<IElementType, SyntaxElement> = java.util.Map.ofEntries<IElementType, SyntaxElement>(
java.util.Map.entry(SlintTypes.LBracket, JavaLikeElement.BlockOpeningBrace),
java.util.Map.entry(SlintTypes.RBracket, JavaLikeElement.BlockClosingBrace),
java.util.Map.entry(SlintTypes.LBrace, JavaLikeElement.BlockOpeningBrace),
java.util.Map.entry(SlintTypes.RBrace, JavaLikeElement.BlockClosingBrace),
java.util.Map.entry(TokenType.WHITE_SPACE, JavaLikeElement.Whitespace),
java.util.Map.entry(SlintTypes.Semicolon, JavaLikeElement.Semicolon),
java.util.Map.entry(SlintTypes.LineComment, JavaLikeElement.LineComment),
java.util.Map.entry(SlintTypes.BlockComment, JavaLikeElement.BlockComment),
java.util.Map.entry(SlintTypes.Colon, JavaLikeElement.Colon),
java.util.Map.entry(SlintTypes.Comma, JavaLikeElement.Comma),
java.util.Map.entry(SlintTypes.LParent, JavaLikeElement.LeftParenthesis),
java.util.Map.entry(SlintTypes.RParent, JavaLikeElement.RightParenthesis)
val SyntaxMap: Map<IElementType, SyntaxElement> = mapOf(
SlintTypes.LBracket to JavaLikeElement.BlockOpeningBrace,
SlintTypes.RBracket to JavaLikeElement.BlockClosingBrace,
SlintTypes.LBrace to JavaLikeElement.BlockOpeningBrace,
SlintTypes.RBrace to JavaLikeElement.BlockClosingBrace,
TokenType.WHITE_SPACE to JavaLikeElement.Whitespace,
SlintTypes.Semicolon to JavaLikeElement.Semicolon,
SlintTypes.LineComment to JavaLikeElement.LineComment,
SlintTypes.BlockComment to JavaLikeElement.BlockComment,
SlintTypes.Colon to JavaLikeElement.Colon,
SlintTypes.Comma to JavaLikeElement.Comma,
SlintTypes.LParent to JavaLikeElement.LeftParenthesis,
SlintTypes.RParent to JavaLikeElement.RightParenthesis
)
}
}

View File

@@ -0,0 +1,52 @@
package me.zhouxi.slint.formatter
import com.intellij.formatting.*
import com.intellij.openapi.util.TextRange
import com.intellij.psi.formatter.common.ExtraRangesProvider
import com.intellij.psi.formatter.common.NodeIndentRangesCalculator
import me.zhouxi.slint.lang.psi.SlintTypes
import me.zhouxi.slint.lang.psi.SlintTypes.LBrace
import me.zhouxi.slint.lang.psi.SlintTypes.RBrace
/**
* @author zhouxi 2024/5/28
*/
class SyntheticBlock(
private val subBlocks: List<Block>,
private val wrap: Wrap?,
private val indent: Indent,
private val alignment: Alignment?,
private val spacingBuilder: SpacingBuilder
) : Block {
override fun getTextRange(): TextRange {
return TextRange(subBlocks.first().textRange.startOffset, subBlocks.last().textRange.endOffset)
}
override fun getSubBlocks(): List<Block> {
return subBlocks
}
override fun getWrap() = wrap
override fun getIndent() = indent
override fun getAlignment() = alignment
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
if (child2 is ASTBlock && child2.node!!.elementType == SlintTypes.Semicolon) {
return Spacing.createSpacing(1, 1, 0, true, 2)
}
if (child1 is ASTBlock && child2 is ASTBlock
&& child1.node!!.elementType == LBrace && child2.node!!.elementType == RBrace
) {
return Spacing.createSpacing(1, 1, 0, false, 0)
}
return null
}
override fun getChildAttributes(newChildIndex: Int) = ChildAttributes(null, subBlocks[0].alignment)
override fun isIncomplete() = false
override fun isLeaf() = false
}

View File

@@ -5,7 +5,9 @@ import com.intellij.openapi.editor.HighlighterColors
import com.intellij.openapi.editor.colors.TextAttributesKey
object Definitions {
@JvmField
val _Annotation =
TextAttributesKey.createTextAttributesKey("_Annotation", DefaultLanguageHighlighterColors.METADATA)
val _KeyWord: TextAttributesKey =
TextAttributesKey.createTextAttributesKey("_KeyWord", DefaultLanguageHighlighterColors.KEYWORD)
@@ -55,4 +57,6 @@ object Definitions {
val SemiColon: Array<TextAttributesKey> = arrayOf(_SemiColon)
val Error: Array<TextAttributesKey> = arrayOf(_Error)
val Annotation: Array<TextAttributesKey> = arrayOf(_Annotation)
}

View File

@@ -10,6 +10,13 @@ import me.zhouxi.slint.lang.psi.keyword.SlintPsiKeywordIdentifier
class KeywordHighlightAnnotator : Annotator {
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
if (element is SlintChildrenPlaceholder) {
holder.newSilentAnnotation(HighlightSeverity.INFORMATION)
.range(element)
.textAttributes(Definitions._Annotation)
.create()
return
}
if (element is SlintPsiKeywordIdentifier) {
holder.newSilentAnnotation(HighlightSeverity.INFORMATION)
.range(element)

View File

@@ -0,0 +1,29 @@
package me.zhouxi.slint.lang.psi.builder
import com.intellij.lang.PsiBuilder
import com.intellij.lang.impl.DelegateMarker
import com.intellij.lang.impl.PsiBuilderAdapter
import com.intellij.psi.tree.IElementType
/**
* @author zhouxi 2024/5/29
*/
class SlintPsiBuilder(delegate: PsiBuilder) : PsiBuilderAdapter(delegate) {
override fun mark(): PsiBuilder.Marker {
return SlintMarker(super.mark())
}
/**
* @author zhouxi 2024/5/29
*/
class SlintMarker(delegate: PsiBuilder.Marker) : DelegateMarker(delegate) {
override fun precede(): PsiBuilder.Marker {
return SlintMarker(super.precede())
}
override fun done(type: IElementType) {
println(type)
super.done(type)
}
}
}

View File

@@ -1,12 +0,0 @@
package me.zhouxi.slint.lang.psi.extension
import me.zhouxi.slint.lang.psi.SlintComponent
import me.zhouxi.slint.lang.psi.SlintProperty
fun SlintComponent.inheritsProperties(): List<SlintProperty> {
val properties = this.propertyList
val inherit =
this.inheritDeclaration?.referenceIdentifier?.reference?.resolve() as SlintComponent? ?: return properties
return properties + inherit.inheritsProperties()
}

View File

@@ -1,20 +0,0 @@
package me.zhouxi.slint.lang.psi.extension
import com.intellij.psi.PsiElement
import me.zhouxi.slint.lang.psi.SlintImport
import me.zhouxi.slint.lang.psi.SlintReferenceIdentifier
fun SlintImport.importNames(): List<SlintReferenceIdentifier> {
return this.importElement?.importSpecifierList?.map { it.referenceIdentifier } ?: emptyList()
}
/**
* 导入的有效的名字,
* psiElement可能是identifier或者internalName
*/
fun SlintImport.availableNames(): List<PsiElement> {
return this.importElement?.importSpecifierList?.map {
it.importAlias?.internalName ?: it.referenceIdentifier
} ?: emptyList()
}

View File

@@ -0,0 +1,45 @@
package me.zhouxi.slint.lang.psi.extension
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.icons.AllIcons
import com.intellij.psi.PsiElement
import com.intellij.psi.util.parentOfType
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
if (inherit == this) {
return properties
}
return properties + inherit.inheritsProperties()
}
fun SlintImport.importNames(): List<SlintReferenceIdentifier> {
return this.importElement?.importSpecifierList?.map { it.referenceIdentifier } ?: emptyList()
}
/**
* 导入的有效的名字,
* psiElement可能是identifier或者internalName
*/
fun SlintImport.availableNames(): List<PsiElement> {
return this.importElement?.importSpecifierList?.map {
it.importAlias?.internalName ?: it.referenceIdentifier
} ?: emptyList()
}
fun SlintSubComponent.resolve(): SlintComponent? {
return this.referenceIdentifier.reference?.resolve() as SlintComponent?
}
fun SlintProperty.toLookupElement(): LookupElementBuilder {
return LookupElementBuilder.create(this)
.withTypeText(this.parentOfType<SlintComponent>()?.componentName?.text)
.withIcon(AllIcons.Nodes.Property)
}

View File

@@ -33,8 +33,10 @@ object SlintImportSpecifierElementType :
val aliasNode = children.firstOrNull { it.tokenType == ImportAlias }
aliasNode?.let {
val nameNode = tree.getChildren(aliasNode).firstOrNull { it.tokenType == InternalName }
val token = nameNode?.let { tree.getChildren(nameNode) }?.first() as LighterASTTokenNode
tree.charTable.intern(token.text).toString()
val token = nameNode?.let { tree.getChildren(nameNode) }?.firstOrNull() as LighterASTTokenNode?
token?.let {
tree.charTable.intern(it.text).toString()
}
}
}
return SlintImportSpecifierStubImpl(parentStub, name, alias)

View File

@@ -1,118 +0,0 @@
package me.zhouxi.slint.lang.psi.utils
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import me.zhouxi.slint.lang.psi.*
import java.util.function.Function
import java.util.function.Predicate
fun resolveComponent(element: SlintReferenceIdentifier?): SlintComponent? {
if (element == null) {
return null
}
val maybeComponent = element.reference?.resolve()
if (maybeComponent is SlintComponent) {
return maybeComponent
}
return resolveReferencedComponent(maybeComponent ?: return null)
}
fun resolveComponent(element: SlintInternalName): SlintComponent? {
//内部名字解析引用
val resolve = element.reference?.resolve()
if (resolve is SlintComponent) {
return resolve
}
//InternalName解析不到东西,换成External试一下
if (resolve == null) {
val externalName = PsiTreeUtil.getPrevSiblingOfType(element, SlintExternalName::class.java)
if (externalName == null) {
val externalName1 = PsiTreeUtil.getNextSiblingOfType(element, SlintExternalName::class.java) ?: return null
return resolveReferencedComponent(externalName1)
}
return resolveReferencedComponent(externalName)
}
return resolveReferencedComponent(resolve)
}
fun resolveComponent(element: SlintExternalName): SlintComponent? {
val resolve = element.reference?.resolve()
if (resolve is SlintComponent) {
return resolve
}
//InternalName解析不到东西,换成External试一下
if (resolve == null) {
val internalName = PsiTreeUtil.getPrevSiblingOfType(element, SlintInternalName::class.java)
if (internalName == null) {
val internalName1 = PsiTreeUtil.getNextSiblingOfType(element, SlintInternalName::class.java) ?: return null
return resolveReferencedComponent(internalName1)
}
return resolveReferencedComponent(internalName)
}
return resolveReferencedComponent(resolve)
}
fun resolveReferencedComponent(element: PsiElement?): SlintComponent? {
if (element == null) {
return null
}
when (element) {
is SlintComponentName -> return element.parent as SlintComponent?
is SlintComponent -> return element
is SlintReferenceIdentifier -> return resolveComponent(element)
is SlintInternalName -> return resolveComponent(element)
is SlintExternalName -> return resolveComponent(element)
}
return null
}
fun searchProperty(
component: PsiElement?,
predicate: Predicate<SlintProperty>
): SlintProperty? {
if (component is SlintSubComponent) {
return searchProperty(component, predicate)
}
if (component is SlintComponent) {
return searchElementInParents(component, predicate) { it.propertyList }
}
return null
}
fun searchProperty(
subComponent: SlintSubComponent?,
predicate: Predicate<SlintProperty>
): SlintProperty? {
val component = resolveComponent(subComponent?.referenceIdentifier) ?: return null
return searchElementInParents(component, predicate) { it.propertyList }
}
fun searchCallback(
subComponent: SlintSubComponent?,
predicate: Predicate<SlintCallback>
): SlintCallback? {
val component = subComponent?.referenceIdentifier?.reference?.resolve() ?: return null
return searchElementInParents(
component as SlintComponent,
predicate
) { it.callbackList }
}
fun <T> searchElementInParents(
component: SlintComponent?,
predicate: Predicate<T>,
function: Function<SlintComponent, List<T>?>
): T? {
if (component == null) {
return null
}
val properties = function.apply(component) ?: arrayListOf<T>()
for (property in properties) {
if (predicate.test(property)) {
return property
}
}
val inheritComponent = resolveReferencedComponent(component.inheritDeclaration?.referenceIdentifier)
return searchElementInParents(inheritComponent, predicate, function)
}

View File

@@ -0,0 +1,21 @@
package me.zhouxi.slint.lang.psi.utils
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import me.zhouxi.slint.lang.psi.SlintTypes
val keywords = TokenSet.create(*SlintTypes::class.java.declaredFields
.filter { it.name.endsWith("Keyword") }
.map { it.get(null) as IElementType }.toTypedArray()
)
val braces = TokenSet.create(
SlintTypes.LBrace,
SlintTypes.LParent,
SlintTypes.LBracket
)
val expressions = TokenSet.create(*SlintTypes::class.java.declaredFields
.filter { it.name.endsWith("Expression") }
.map { it.get(null) as IElementType }.toTypedArray()
)

View File

@@ -5,13 +5,10 @@ import com.intellij.psi.PsiReference
import com.intellij.psi.PsiReferenceBase
import com.intellij.psi.PsiReferenceProvider
import com.intellij.psi.util.parentOfType
import com.intellij.psi.util.parentOfTypes
import com.intellij.util.ProcessingContext
import me.zhouxi.slint.lang.psi.SlintComponent
import me.zhouxi.slint.lang.psi.SlintPropertyBinding
import me.zhouxi.slint.lang.psi.SlintSubComponent
import me.zhouxi.slint.lang.psi.extension.inheritsProperties
import me.zhouxi.slint.lang.psi.utils.searchProperty
object PropertyReferenceProvider : PsiReferenceProvider() {
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<PsiReference> {