Moxy Strategie Plugin

Manchmal sind einfache Dinge sehr anstrengend, besonders wenn sie ständig erledigt werden müssen. Eines dieser Dinge bei der Arbeit mit dem Moxy- Framework ist das Hinzufügen von Strategien zu Funktionen. Um diesen Prozess zu beschleunigen, wurde ein Plugin geschrieben, das durch "Alt + Enter" eine Auswahl der Strategie bietet, wenn es nicht vorhanden ist, oder einen Dialog mit einem Ersatz für eine andere Strategie. Wer wissen will, wie es funktioniert, ist herzlich willkommen bei cat.



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, // psiElement
                StrategyIntentionType.MissingStrategy.title,  // description
                *fixes // LocalQuickFix
            )
        }
    }

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.


. - . . . .




Source: https://habr.com/ru/post/undefined/


All Articles