fix: 语法问题

This commit is contained in:
me
2024-05-31 17:58:39 +08:00
parent ada52875ad
commit 39a81fcb5d
5 changed files with 206 additions and 171 deletions

View File

@@ -2,11 +2,7 @@ package me.zhouxi.slint.completion
import com.intellij.codeInsight.completion.CompletionContributor import com.intellij.codeInsight.completion.CompletionContributor
import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionType import com.intellij.codeInsight.completion.CompletionType
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.completion.provider.*
class SlintCompletionContributor : CompletionContributor() { class SlintCompletionContributor : CompletionContributor() {
@@ -14,8 +10,8 @@ class SlintCompletionContributor : CompletionContributor() {
extend(TopKeywordProvider) extend(TopKeywordProvider)
extend(BasicTypeProvider) extend(BasicTypeProvider)
extend(AtChildrenCompletionProvider) extend(AtChildrenCompletionProvider)
extend(ElementKeywordProvider) extend(ComponentElementKeywordProvider)
extend(ComponentProvider) extend(ComponentNameProvider)
extend(PropertyBindingProvider) extend(PropertyBindingProvider)
extend(InheritsCompletionProvider) extend(InheritsCompletionProvider)
} }

View File

@@ -1,32 +1,31 @@
package me.zhouxi.slint.completion.provider package me.zhouxi.slint.completion.provider
import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.patterns.ElementPattern
import com.intellij.patterns.ElementPattern import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.patterns.PlatformPatterns.psiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElement import com.intellij.util.ProcessingContext
import com.intellij.util.ProcessingContext import me.zhouxi.slint.lang.psi.SlintTypes.Component
import me.zhouxi.slint.lang.psi.SlintTypes.Component
object ComponentElementKeywordProvider : AbstractSlintCompletionProvider<CompletionParameters>() {
object ElementKeywordProvider : AbstractSlintCompletionProvider<CompletionParameters>() { override fun addCompletions(
override fun addCompletions( parameters: CompletionParameters,
parameters: CompletionParameters, context: ProcessingContext,
context: ProcessingContext, result: CompletionResultSet
result: CompletionResultSet ) {
) { result.addAllElements(elementKeywords)
result.addAllElements(elementKeywords) }
}
private val elementKeywords = arrayOf(
private val elementKeywords = arrayOf( "in", "out", "in-out", "callback",
"in", "out", "in-out", "callback", "property", "private", "changed",
"property", "private", "changed", "states", "transitions", "function"
"states", "transitions", "function" ).map { LookupElementBuilder.create(it) }
).map { LookupElementBuilder.create(it) }
override fun pattern(): ElementPattern<out PsiElement> {
override fun pattern(): ElementPattern<out PsiElement> { return psiElement().withParent(psiElement(Component))
return psiElement().withParent(psiElement(Component)) .andNot(AtChildrenCompletionProvider.pattern())
.andNot(AtChildrenCompletionProvider.pattern()) }
} }
}

View File

@@ -1,125 +1,124 @@
package me.zhouxi.slint.completion.provider package me.zhouxi.slint.completion.provider
import com.intellij.codeInsight.completion.* import com.intellij.codeInsight.completion.*
import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.codeInsight.lookup.LookupElementDecorator.withInsertHandler import com.intellij.codeInsight.lookup.LookupElementDecorator.withInsertHandler
import com.intellij.icons.AllIcons import com.intellij.icons.AllIcons
import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VfsUtil
import com.intellij.patterns.ElementPattern import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PlatformPatterns.psiElement import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.patterns.StandardPatterns.or import com.intellij.patterns.StandardPatterns.or
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.psi.search.GlobalSearchScope.projectScope import com.intellij.psi.search.GlobalSearchScope.projectScope
import com.intellij.psi.stubs.StubIndex import com.intellij.psi.stubs.StubIndex
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.childrenOfType import com.intellij.psi.util.childrenOfType
import com.intellij.psi.util.parentOfType import com.intellij.util.ProcessingContext
import com.intellij.util.ProcessingContext import me.zhouxi.slint.lang.createComma
import me.zhouxi.slint.lang.createComma import me.zhouxi.slint.lang.createImport
import me.zhouxi.slint.lang.createImport import me.zhouxi.slint.lang.createImportSpecifier
import me.zhouxi.slint.lang.createImportSpecifier import me.zhouxi.slint.lang.psi.SlintComponent
import me.zhouxi.slint.lang.psi.SlintComponent import me.zhouxi.slint.lang.psi.SlintImport
import me.zhouxi.slint.lang.psi.SlintImport import me.zhouxi.slint.lang.psi.SlintInheritDeclaration
import me.zhouxi.slint.lang.psi.SlintInheritDeclaration import me.zhouxi.slint.lang.psi.SlintTypes.Component
import me.zhouxi.slint.lang.psi.SlintTypes.Component import me.zhouxi.slint.lang.psi.SlintTypes.InheritDeclaration
import me.zhouxi.slint.lang.psi.SlintTypes.InheritDeclaration import me.zhouxi.slint.lang.psi.extension.importNames
import me.zhouxi.slint.lang.psi.extension.importNames import me.zhouxi.slint.lang.psi.stubs.index.StubIndexKeys
import me.zhouxi.slint.lang.psi.stubs.index.StubIndexKeys
object ComponentNameProvider : AbstractSlintCompletionProvider<CompletionParameters>() {
object ComponentProvider : AbstractSlintCompletionProvider<CompletionParameters>() { override fun addCompletions(
override fun addCompletions( parameters: CompletionParameters,
parameters: CompletionParameters, context: ProcessingContext,
context: ProcessingContext, result: CompletionResultSet
result: CompletionResultSet ) {
) { val project = parameters.position.project
val project = parameters.position.project val components = arrayListOf<SlintComponent>()
val components = arrayListOf<SlintComponent>() StubIndex.getInstance().processAllKeys(StubIndexKeys.Component, project) {
StubIndex.getInstance().processAllKeys(StubIndexKeys.Component, project) { if (result.prefixMatcher.prefixMatches(it)) {
if (result.prefixMatcher.prefixMatches(it)) { val elements = StubIndex.getElements(
val elements = StubIndex.getElements( StubIndexKeys.Component,
StubIndexKeys.Component, it,
it, project,
project, projectScope(project),
projectScope(project), SlintComponent::class.java
SlintComponent::class.java )
) components.addAll(elements)
components.addAll(elements) }
} true
true }
} val lookups = components.map {
val lookups = components.map { val targetFile = it.containingFile.originalFile
val targetFile = it.containingFile.originalFile val currentFile = parameters.position.containingFile.originalFile.virtualFile
val currentFile = parameters.position.containingFile.originalFile.virtualFile val path = VfsUtil.findRelativePath(currentFile, targetFile.virtualFile, '/')
val path = VfsUtil.findRelativePath(currentFile, targetFile.virtualFile, '/') val builder = LookupElementBuilder.create(it).withTypeText(path).withIcon(AllIcons.Nodes.Class)
val builder = LookupElementBuilder.create(it).withTypeText(path).withIcon(AllIcons.Nodes.Class) withInsertHandler(builder, ComponentInsertHandler(targetFile, path))
withInsertHandler(builder, ComponentInsertHandler(targetFile, path)) }
} result.addAllElements(lookups)
result.addAllElements(lookups) }
}
class ComponentInsertHandler(
class ComponentInsertHandler( private val targetFile: PsiFile,
private val targetFile: PsiFile, private val path: String?
private val path: String? ) : InsertHandler<LookupElement> {
) : InsertHandler<LookupElement> { override fun handleInsert(context: InsertionContext, item: LookupElement) {
override fun handleInsert(context: InsertionContext, item: LookupElement) { //insert '{}'
//insert '{}' val caretOffset: Int = context.editor.caretModel.offset
val caretOffset: Int = context.editor.caretModel.offset val elementAt = context.file.findElementAt(caretOffset)
val elementAt = context.file.findElementAt(caretOffset) if (elementAt?.prevSibling !is SlintInheritDeclaration) {
if (elementAt?.prevSibling !is SlintInheritDeclaration) { context.document.insertString(caretOffset, " { }")
context.document.insertString(caretOffset, "{}") context.editor.caretModel.moveToOffset(caretOffset + 3)
context.editor.caretModel.moveToOffset(caretOffset + 1) PsiDocumentManager.getInstance(context.project).commitDocument(context.document)
PsiDocumentManager.getInstance(context.project).commitDocument(context.document) }
} val component = item.psiElement as SlintComponent
val component = item.psiElement as SlintComponent if (component.containingFile.isEquivalentTo(context.file)) {
if (component.containingFile.isEquivalentTo(context.file)) { return
return }
} val targetImport = context.file.childrenOfType<SlintImport>().find { import ->
val targetImport = context.file.childrenOfType<SlintImport>().find { import -> val target = import.importElement?.moduleLocation?.reference?.resolve()
val target = import.importElement?.moduleLocation?.reference?.resolve() PsiManager.getInstance(context.project).areElementsEquivalent(target, targetFile)
PsiManager.getInstance(context.project).areElementsEquivalent(target, targetFile) }
} if (targetImport == null) {
if (targetImport == null) { //不存在对指定文件的Import插入
//不存在对指定文件的Import插入 val import = createImport(context.project, component.componentName!!.text, path!!)
val import = createImport(context.project, component.componentName!!.text, path!!) context.file.addBefore(import, context.file.firstChild)
context.file.addBefore(import, context.file.firstChild) return
return }
} //如果导入的Name里面包含了这个ComponentName
//如果导入的Name里面包含了这个ComponentName if (targetImport.importNames().any { it.textMatches(component.componentName!!) }) {
if (targetImport.importNames().any { it.textMatches(component.componentName!!) }) { return
return }
} //引入的文件存在,但是没有导入对应组件
//引入的文件存在,但是没有导入对应组件 val importElement = targetImport.importElement!!
val importElement = targetImport.importElement!! val specifier = createImportSpecifier(context.project, component.componentName!!.text)
val specifier = createImportSpecifier(context.project, component.componentName!!.text) val last = importElement.importSpecifierList.lastOrNull()
val last = importElement.importSpecifierList.lastOrNull() //不存在前置节点
//不存在前置节点 if (last == null) {
if (last == null) { importElement.addAfter(specifier, importElement.childrenOfType<LeafPsiElement>()[0])
importElement.addAfter(specifier, importElement.childrenOfType<LeafPsiElement>()[0]) PsiDocumentManager.getInstance(context.project).commitDocument(context.document)
PsiDocumentManager.getInstance(context.project).commitDocument(context.document) return
return }
} val element = PsiTreeUtil.nextVisibleLeaf(last)
val element = PsiTreeUtil.nextVisibleLeaf(last) if (!element!!.textMatches(",")) {
if (!element!!.textMatches(",")) { val comma = importElement.addAfter(createComma(context.project), last)
val comma = importElement.addAfter(createComma(context.project), last) importElement.addAfter(specifier, comma)
importElement.addAfter(specifier, comma) PsiDocumentManager.getInstance(context.project).commitDocument(context.document)
PsiDocumentManager.getInstance(context.project).commitDocument(context.document) return
return }
} PsiDocumentManager.getInstance(context.project).commitDocument(context.document)
PsiDocumentManager.getInstance(context.project).commitDocument(context.document) importElement.addAfter(specifier, element)
importElement.addAfter(specifier, element) }
} }
}
override fun pattern(): ElementPattern<out PsiElement> {
override fun pattern(): ElementPattern<out PsiElement> { return or(
return or( psiElement().withParent(psiElement(Component)).andNot(AtChildrenCompletionProvider.pattern()),
psiElement().withParent(psiElement(Component)).andNot(AtChildrenCompletionProvider.pattern()), psiElement().withSuperParent(2, psiElement(InheritDeclaration))
psiElement().withSuperParent(2, psiElement(InheritDeclaration)) )
) }
} }
}

View File

@@ -2,11 +2,20 @@ package me.zhouxi.slint.completion.provider
import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder 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.ElementPattern
import com.intellij.patterns.PlatformPatterns.psiElement import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.util.ProcessingContext import com.intellij.util.ProcessingContext
import me.zhouxi.slint.lang.psi.SlintTypes.Component
import me.zhouxi.slint.lang.psi.stubs.types.SlintFileElementType import me.zhouxi.slint.lang.psi.stubs.types.SlintFileElementType
object TopKeywordProvider : AbstractSlintCompletionProvider<CompletionParameters>() { object TopKeywordProvider : AbstractSlintCompletionProvider<CompletionParameters>() {
@@ -15,13 +24,42 @@ object TopKeywordProvider : AbstractSlintCompletionProvider<CompletionParameters
context: ProcessingContext, context: ProcessingContext,
result: CompletionResultSet result: CompletionResultSet
) { ) {
result.addAllElements(topKeywords) result.addAllElements(completion)
result.addElement(create("component"))
} }
private val topKeywords = val completion = arrayListOf(create("component "), create("struct "), create("enum "))
arrayOf("export", "component", "global", "enum", "struct").map { LookupElementBuilder.create(it) } .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> { override fun pattern(): ElementPattern<out PsiElement> {
return psiElement().withSuperParent(1, psiElement(SlintFileElementType)) 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);
}
})
}
} }
} }

View File

@@ -50,10 +50,13 @@ object SlintComponentElementType :
override fun createStub(tree: LighterAST, node: LighterASTNode, parentStub: StubElement<*>): SlintComponentStub { override fun createStub(tree: LighterAST, node: LighterASTNode, parentStub: StubElement<*>): SlintComponentStub {
val exported = tree.getChildren(node).any { it.tokenType == ExportKeyword } val exported = tree.getChildren(node).any { it.tokenType == ExportKeyword }
val identifier = tree.getChildren(node).first { it.tokenType == ComponentName } val token = tree.getChildren(node).find { it.tokenType == ComponentName }
val token = tree.getChildren(identifier)[0] as LighterASTTokenNode ?.let {
val text = tree.getChildren(it)[0] as LighterASTTokenNode
tree.charTable.intern(text.text)
}
return SlintComponentStubImpl(parentStub, exported, tree.charTable.intern(token.text).toString()) return SlintComponentStubImpl(parentStub, exported, token.toString())
} }
override fun indexStub(stub: SlintComponentStub, sink: IndexSink) { override fun indexStub(stub: SlintComponentStub, sink: IndexSink) {