Terkadang hal-hal sederhana sangat melelahkan, terutama ketika mereka harus dilakukan terus-menerus. Salah satu hal ini ketika bekerja dengan kerangka Moxy adalah menambahkan strategi ke fungsi. Untuk mempercepat proses ini, sebuah plugin ditulis , yang oleh "alt + enter", memberikan pilihan strategi jika tidak ada atau dialog dengan pengganti untuk strategi lain. Mereka yang ingin tahu cara kerjanya, selamat datang di kucing.

Moxy, . , .
, adev_one , .
Inspection
, . code inspections. PSI (Program Structure Interface), , , alt+enter .
code inspections.
PSI β , , .. , , parent child. , , Psi viewer plugin.
.
, KtNamedFunction.
Inpection.
. plugins.xml
    <depends>org.jetbrains.kotlin</depends>
    <depends>com.intellij.modules.lang</depends>
build.gradle
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    implementation "org.jetbrains.kotlin:kotlin-reflect"
    implementation "com.github.moxy-community:moxy:1.0.13"
}
intellij {
 ...
    plugins = ["Kotlin"]
 ...
}
inpection.
AbstractKotlinInspection
class MvpViewStrategyInspection : AbstractKotlinInspection() {}
:
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor 
Visitor, .
Visitor , kotlin - Visitor. KtNamedFunction :
org.jetbrains.kotlin.psi VisitorWrappersKt.class 
public fun namedFunctionVisitor(block: (KtNamedFunction) β Unit): KtVisitorVoid
PSI: , MvpView. , ProblemsHolder.
:
private val fixes = MoxyStrategy.values().map { AddStrategyFix(it) }.toTypedArray()
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
        return namedFunctionVisitor { ktNamedFunction ->
            if (!ktNamedFunction.isClassInheritMvpView() ||
                ktNamedFunction.isHasMoxyAnnotation()
            ) return@namedFunctionVisitor
            holder.registerProblem(
                ktNamedFunction, 
                StrategyIntentionType.MissingStrategy.title,  
                *fixes 
            )
        }
    }
AddStrategyFix? , LocalQuickFix. , :
class AddStrategyFix(
        private val strategy: MoxyStrategy
    ) : LocalQuickFix {
        override fun getFamilyName(): String = "add ${strategy.className}"
        override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
            val ktFunction = (descriptor.psiElement as KtNamedFunction)
            val editor = ktFunction.getProjectEditor()
            ktFunction.addStrategyAnnotation(strategy, project, editor)
        }
    }
getFamilyName β , .
applyFix . .
Inspection plguin.xml, ( Activity Manifest)
 <extensions defaultExtensionNs="com.intellij">
        <localInspection language="kotlin"
                         displayName="missing strategy for function"
                         groupPath="Moxy"
                         groupBundle="messages.InspectionsBundle"
                         groupKey="group.names.probable.bugs"
                         enabledByDefault="true"
                         level="ERROR"
                         implementationClass="com.maksimnovikov.inspection.MvpViewStrategyInspection"/>
    </extensions>
:

StateStrategyType .
AddToEndSingleTagStrategy
tag .

Intention
, . .
Intention.
Inspection, . intention. .
Intention.
PsiElementBaseIntentionAction :
class MvpViewStrategyIntention : PsiElementBaseIntentionAction(){
    override fun getText(): String 
    override fun getFamilyName(): String
    override fun isAvailable(project: Project, editor: Editor?, element: PsiElement): Boolean
    override fun invoke(project: Project, editor: Editor?, element: PsiElement)
}
getText β
getFamilyName β intention
isAvailable β , intention .
invoke β , intention
isAvailable invoke:
isAvailable
, intention . .
child , . .
override fun isAvailable(project: Project, editor: Editor?, element: PsiElement): Boolean {
        if ((element.containingFile ?: return false) !is KtFile) return false
        if (!element.isClassInheritMvpView()) return false
        val ktFunction = element.getParentOfType<KtNamedFunction>() ?: return false
        return ktFunction.isHasMoxyAnnotation()
    }
invoke
Intention , .
IDE swing. , , . β JBPopupFactory
fun <T> Editor.showSelectPopup(
    items: List<T>,
    onSelected: (T) -> Unit
) {
    JBPopupFactory.getInstance()
        .createPopupChooserBuilder(items)
        .setRequestFocus(true)
        .setCancelOnClickOutside(true)
        .setItemChosenCallback { onSelected(it) }
        .createPopup()
        .showInBestPositionFor(this)
}
, , . WriteCommandAction.runWriteCommandAction(project) {}
  override fun invoke(project: Project, editor: Editor, element: PsiElement) {
        editor.showSelectPopup(MoxyStrategy.values().toList()) { selectedStrategy ->
            WriteCommandAction.runWriteCommandAction(project) {
                val ktFunction = element.getParentOfType<KtNamedFunction>() ?: return@runWriteCommandAction
                ktFunction.replaceAnnotation(selectedStrategy, project, editor)
            }
        }
    }
intention plugin.xml
<extensions defaultExtensionNs="com.intellij">
        <intentionAction>
            <className>com.maksimnovikov.intention.MvpViewStrategyIntention</className>
            <category>Moxy intentions</category>
        </intentionAction>
</extensions>
:


. . , , . Moxy.
. - . . . .