添加自动插入
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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 + ")"
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -31,4 +32,10 @@ fun createImport(project: Project?, text: String, location: String): PsiElement
|
|||||||
fun createImportSpecifier(project: Project?, text: String): PsiElement {
|
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]
|
||||||
}
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user