Support line markers for CommandDeclaration

This commit is contained in:
Him188 2020-09-13 22:52:11 +08:00
parent 9351128f38
commit dee84791f1
7 changed files with 103 additions and 50 deletions

View File

@ -128,13 +128,11 @@ object MyCompositeCommand : CompositeCommand(
) {
// 会自动创建一个 ID 为 "org.example.example-plugin:command.manage" 的权限.
// [参数智能解析]
//
// 在控制台执行 "/manage <群号>.<群员> <持续时间>",
// 或在聊天群内发送 "/manage <@一个群员> <持续时间>",
// 或在聊天群内发送 "/manage <目标群员的群名> <持续时间>",
// 或在聊天群内发送 "/manage <目标群员的账号> <持续时间>"
// 时调用这个函数
@SubCommand
suspend fun CommandSender.mute(target: Member, duration: Int) { // 通过 /manage mute <target> <duration> 调用
sendMessage("/manage mute 被调用了, 参数为: $target, $duration")

View File

@ -0,0 +1,14 @@
package org.example.myplugin
import net.mamoe.mirai.console.command.CommandSender
import net.mamoe.mirai.console.command.SimpleCommand
object MySimpleCommand000 : SimpleCommand(
MyPluginMain, "foo",
description = "示例指令"
) {
@Handler
suspend fun CommandSender.handle(int: Int, str: String) {
}
}

View File

@ -0,0 +1,40 @@
package net.mamoe.mirai.console.intellij.line.marker
import com.intellij.codeHighlighting.Pass
import com.intellij.codeInsight.daemon.LineMarkerInfo
import com.intellij.codeInsight.daemon.LineMarkerProvider
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.editor.markup.GutterIconRenderer
import com.intellij.psi.PsiElement
import net.mamoe.mirai.console.intellij.Icons
import net.mamoe.mirai.console.intellij.resolve.isSimpleCommandHandlerOrCompositeCommandSubCommand
import org.jetbrains.kotlin.psi.KtNamedFunction
class CommandDeclarationLineMarkerProvider : LineMarkerProvider {
override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? {
if (element !is KtNamedFunction) return null
if (!element.isSimpleCommandHandlerOrCompositeCommandSubCommand()) return null
return Info(getElementForLineMark(element.funKeyword ?: element.identifyingElement ?: element))
}
@Suppress("DEPRECATION")
class Info(
callElement: PsiElement,
) : LineMarkerInfo<PsiElement>(
callElement,
callElement.textRange,
Icons.CommandDeclaration,
Pass.LINE_MARKERS,
{
"子指令定义"
},
null,
GutterIconRenderer.Alignment.RIGHT
) {
override fun createGutterRenderer(): GutterIconRenderer? {
return object : LineMarkerInfo.LineMarkerGutterIconRenderer<PsiElement>(this) {
override fun getClickAction(): AnAction? = null
}
}
}
}

View File

@ -5,12 +5,10 @@ import com.intellij.codeInsight.daemon.LineMarkerInfo
import com.intellij.codeInsight.daemon.LineMarkerProvider
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.editor.markup.GutterIconRenderer
import com.intellij.openapi.progress.ProgressManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiJavaCodeReferenceCodeFragment
import com.intellij.util.castSafelyTo
import net.mamoe.mirai.console.intellij.Icons
import net.mamoe.mirai.console.intellij.Plugin_FQ_NAME
import org.jetbrains.kotlin.idea.core.util.getLineNumber
import org.jetbrains.kotlin.nj2k.postProcessing.resolve
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtConstructor
@ -19,50 +17,13 @@ import org.jetbrains.kotlin.psi.KtReferenceExpression
class PluginMainLineMarkerProvider : LineMarkerProvider {
override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? {
return null
}
override fun collectSlowLineMarkers(
elements: MutableList<out PsiElement>,
result: MutableCollection<in LineMarkerInfo<*>>,
) {
val markedLineNumbers = HashSet<Int>()
for (element in elements) {
ProgressManager.checkCanceled()
val containingFile = element.containingFile
if (containingFile is PsiJavaCodeReferenceCodeFragment) {
continue
}
when {
element is KtReferenceExpression // constructor call
-> {
val objectDeclaration =
element.parents.filterIsInstance<KtObjectDeclaration>().firstOrNull() ?: continue
val resolved = element.resolve() as? KtConstructor<*> ?: continue
val kotlinPluginClass = resolved.parent as? KtClass ?: continue
if (kotlinPluginClass.allSuperNames.none { it == Plugin_FQ_NAME }) continue
val lineNumber = objectDeclaration.getLineNumber()
if (lineNumber in markedLineNumbers) continue
markedLineNumbers += lineNumber
result += Info(getElementForLineMark(objectDeclaration))
}
}
// if (!element.hasBridgeCalls()) continue
}
if (element !is KtReferenceExpression) return null
val objectDeclaration =
element.parents.filterIsInstance<KtObjectDeclaration>().firstOrNull() ?: return null
val kotlinPluginClass =
element.resolve().castSafelyTo<KtConstructor<*>>()?.parent?.castSafelyTo<KtClass>() ?: return null
if (kotlinPluginClass.allSuperNames.none { it == Plugin_FQ_NAME }) return null
return Info(getElementForLineMark(objectDeclaration))
}
@Suppress("DEPRECATION")

View File

@ -49,4 +49,10 @@ internal fun getElementForLineMark(callElement: PsiElement): PsiElement =
// a fallback,
//but who knows what to reference in KtArrayAccessExpression ?
generateSequence(callElement, { it.firstChild }).last()
}
}
internal val KtAnnotationEntry.annotationClass: KtClass?
get() = calleeExpression?.constructorReferenceExpression?.resolve()?.findParent<KtClass>()
internal fun KtAnnotated.hasAnnotation(fqName: FqName): Boolean =
this.annotationEntries.any { it.annotationClass?.getKotlinFqName() == fqName }

View File

@ -0,0 +1,30 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.console.intellij.resolve
import net.mamoe.mirai.console.intellij.line.marker.hasAnnotation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtNamedFunction
val COMPOSITE_COMMAND_SUB_COMMAND_FQ_NAME = FqName("net.mamoe.mirai.console.command.CompositeCommand.SubCommand")
val SIMPLE_COMMAND_HANDLER_COMMAND_FQ_NAME = FqName("net.mamoe.mirai.console.command.SimpleCommand.Handler")
/**
* For CompositeCommand.SubCommand
*/
fun KtNamedFunction.isCompositeCommandSubCommand(): Boolean = this.hasAnnotation(COMPOSITE_COMMAND_SUB_COMMAND_FQ_NAME)
/**
* SimpleCommand.Handler
*/
fun KtNamedFunction.isSimpleCommandHandler(): Boolean = this.hasAnnotation(SIMPLE_COMMAND_HANDLER_COMMAND_FQ_NAME)
fun KtNamedFunction.isSimpleCommandHandlerOrCompositeCommandSubCommand(): Boolean =
this.isSimpleCommandHandler() || this.isCompositeCommandSubCommand()

View File

@ -17,6 +17,10 @@
implementationClass="net.mamoe.mirai.console.intellij.line.marker.PluginMainLineMarkerProvider"/>
<codeInsight.lineMarkerProvider language="kotlin"
implementationClass="net.mamoe.mirai.console.intellij.line.marker.PluginMainLineMarkerProvider"/>
<codeInsight.lineMarkerProvider language="JAVA"
implementationClass="net.mamoe.mirai.console.intellij.line.marker.CommandDeclarationLineMarkerProvider"/>
<codeInsight.lineMarkerProvider language="kotlin"
implementationClass="net.mamoe.mirai.console.intellij.line.marker.CommandDeclarationLineMarkerProvider"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.kotlin">