添加自动插入

This commit is contained in:
me
2024-05-27 19:17:44 +08:00
parent 088dbd5661
commit 06cf13484d
5 changed files with 87 additions and 29 deletions

View File

@@ -81,7 +81,7 @@ Import ::= ImportKeyword (ImportElement|ImportResource)';'{
extends="me.zhouxi.slint.lang.psi.impl.SlintStubBasedPsiElementImpl<?>" extends="me.zhouxi.slint.lang.psi.impl.SlintStubBasedPsiElementImpl<?>"
} }
ImportElement ::= '{' ImportSpecifier (',' ImportSpecifier)* ','? '}' FromKeyword ModuleLocation{ ImportElement ::= '{' ImportSpecifier (',' ImportSpecifier)* '}' FromKeyword ModuleLocation{
pin=1 pin=1
} }
ImportResource ::= ModuleLocation ImportResource ::= ModuleLocation

View File

@@ -2,6 +2,7 @@ package me.zhouxi.slint.lang.psi.impl
import com.intellij.extapi.psi.StubBasedPsiElementBase import com.intellij.extapi.psi.StubBasedPsiElementBase
import com.intellij.lang.ASTNode import com.intellij.lang.ASTNode
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.IStubElementType import com.intellij.psi.stubs.IStubElementType
import com.intellij.psi.stubs.StubElement import com.intellij.psi.stubs.StubElement
@@ -14,5 +15,8 @@ abstract class SlintStubBasedPsiElementImpl<T : StubElement<out PsiElement>> :
constructor(stub: T, nodeType: IStubElementType<*, *>) : super(stub, nodeType) constructor(stub: T, nodeType: IStubElementType<*, *>) : super(stub, nodeType)
override fun toString(): String {
return StringUtil.trimEnd(this::class.java.simpleName, "Impl") + "(" + elementType + ")"
}
} }

View File

@@ -1,24 +1,28 @@
package me.zhouxi.slint.completion.provider package me.zhouxi.slint.completion.provider
import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.*
import com.intellij.codeInsight.completion.CompletionProvider import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.codeInsight.lookup.LookupElementDecorator import com.intellij.codeInsight.lookup.LookupElementDecorator
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.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
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.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.childrenOfType import com.intellij.psi.util.childrenOfType
import com.intellij.refactoring.extractMethod.newImpl.ExtractMethodHelper.addSiblingAfter import com.intellij.psi.util.parentOfTypes
import com.intellij.testFramework.utils.editor.commitToPsi
import com.intellij.util.ProcessingContext import com.intellij.util.ProcessingContext
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.extension.importNames
import me.zhouxi.slint.lang.psi.stubs.index.StubIndexKeys import me.zhouxi.slint.lang.psi.stubs.index.StubIndexKeys
object ComponentProvider : CompletionProvider<CompletionParameters>() { object ComponentProvider : CompletionProvider<CompletionParameters>() {
@@ -44,31 +48,54 @@ object ComponentProvider : CompletionProvider<CompletionParameters>() {
} }
val lookups = components.map { val lookups = components.map {
val targetFile = it.containingFile.originalFile val targetFile = it.containingFile.originalFile
val currentFile = parameters.position.containingFile.originalFile val currentFile = parameters.position.containingFile.originalFile.virtualFile
val path = VfsUtil.findRelativePath(currentFile.virtualFile, 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)
LookupElementDecorator.withInsertHandler(builder) { context, item -> withInsertHandler(builder, ComponentInsertHandler(targetFile, path))
// val caretOffset: Int = context.editor.caretModel.offset
// context.document.insertString(caretOffset, "{}")
// context.editor.caretModel.moveToOffset(caretOffset + 1)
val currentFile = PsiDocumentManager.getInstance(project).getPsiFile(context.document)!!
val element = item.psiElement as SlintComponent
val targetImport = currentFile.childrenOfType<SlintImport>().find { import ->
val target = import.importElement?.moduleLocation?.reference?.resolve()
PsiManager.getInstance(project).areElementsEquivalent(target, targetFile)
}
if (targetImport == null) {
currentFile.addBefore(
createImport(project, element.componentName!!.text, path!!),
currentFile.firstChild
)
} else {
val importElement = targetImport.importElement!!
val specifier = createImportSpecifier(project, element.componentName!!.text)
importElement.addAfter(specifier,importElement.importSpecifierList.last())
}
}
} }
result.addAllElements(lookups) result.addAllElements(lookups)
} }
class ComponentInsertHandler(
private val targetFile: PsiFile,
private val path: String?
) : InsertHandler<LookupElement> {
override fun handleInsert(context: InsertionContext, item: LookupElement) {
val component = item.psiElement as SlintComponent
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)
}
}
} }

View File

@@ -4,6 +4,7 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFileFactory import com.intellij.psi.PsiFileFactory
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.nextLeafs
import me.zhouxi.slint.lang.psi.SlintComponent import me.zhouxi.slint.lang.psi.SlintComponent
import me.zhouxi.slint.lang.psi.SlintFile import me.zhouxi.slint.lang.psi.SlintFile
import me.zhouxi.slint.lang.psi.SlintImportSpecifier import me.zhouxi.slint.lang.psi.SlintImportSpecifier
@@ -32,3 +33,9 @@ fun createImportSpecifier(project: Project?, text: String): PsiElement {
val element = createImport(project, text, "-") val element = createImport(project, text, "-")
return PsiTreeUtil.findChildOfType(element, SlintImportSpecifier::class.java)!! return PsiTreeUtil.findChildOfType(element, SlintImportSpecifier::class.java)!!
} }
fun createComma(project: Project?): PsiElement {
val factory = PsiFileFactory.getInstance(project)
val file = factory.createFileFromText("dummy.slint", SlintLanguage.INSTANCE, ",")
return file.children[0].children[0]
}

View File

@@ -0,0 +1,20 @@
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()
}