diff --git a/gradle.properties b/gradle.properties index dc667dbe5..7c3e488eb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ plugin_version=2.6.4.212.0 kotlin.code.style=official kotlin_version=1.8.0 junit_version=5.9.2 -itangcent_intellij_version=1.5.8 \ No newline at end of file +itangcent_intellij_version=1.6.0 \ No newline at end of file diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/BasicAnAction.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/BasicAnAction.kt index 066cc9503..318e06957 100644 --- a/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/BasicAnAction.kt +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/plugin/actions/BasicAnAction.kt @@ -7,6 +7,7 @@ import com.itangcent.common.spi.SpiUtils import com.itangcent.idea.config.CachedResourceResolver import com.itangcent.idea.plugin.Initializer import com.itangcent.idea.plugin.log.CustomLogConfig +import com.itangcent.idea.psi.DisableDocSupport import com.itangcent.idea.utils.ConfigurableLogger import com.itangcent.intellij.actions.ActionEventDataContextAdaptor import com.itangcent.intellij.actions.KotlinAnAction @@ -42,6 +43,8 @@ abstract class BasicAnAction : KotlinAnAction { builder.bind(Logger::class, "delegate.logger") { it.with(ConsoleRunnerLogger::class).singleton() } builder.bind(ResourceResolver::class) { it.with(CachedResourceResolver::class).singleton() } + DisableDocSupport.bind(builder) + afterBuildActionContext(event, builder) } diff --git a/idea-plugin/src/main/kotlin/com/itangcent/idea/psi/DisableDocSupport.kt b/idea-plugin/src/main/kotlin/com/itangcent/idea/psi/DisableDocSupport.kt new file mode 100644 index 000000000..dfd7cdc00 --- /dev/null +++ b/idea-plugin/src/main/kotlin/com/itangcent/idea/psi/DisableDocSupport.kt @@ -0,0 +1,62 @@ +package com.itangcent.idea.psi + +import com.google.inject.matcher.Matchers +import com.itangcent.common.logger.Log +import com.itangcent.common.utils.toBool +import com.itangcent.intellij.config.ConfigReader +import com.itangcent.intellij.context.ActionContext +import com.itangcent.intellij.jvm.DocHelper +import org.aopalliance.intercept.MethodInterceptor +import org.aopalliance.intercept.MethodInvocation + +/* + * The DisableDocSupport object is responsible for binding the EmptyInterceptor to the ActionContextBuilder. + * It provides a way to disable the plugin from reading documentation. + */ +object DisableDocSupport { + /* + * Binds the EmptyInterceptor to the ActionContextBuilder, enabling the plugin to intercept method invocations. + * @param builder The ActionContextBuilder to bind the interceptor to. + */ + fun bind(builder: ActionContext.ActionContextBuilder) { + builder.bindInterceptor( + Matchers.subclassesOf(DocHelper::class.java), + Matchers.any(), + EmptyInterceptor() + ) + } +} + +/* + * The EmptyInterceptor class is an interceptor used to disable documentation support. + * Use 'doc.source.disable' configuration property to determine if documentation is enabled or disabled. + */ +class EmptyInterceptor : MethodInterceptor { + + companion object : Log() + + private val disableDoc by lazy { + val disable = ActionContext.getContext() + ?.instance(ConfigReader::class) + ?.first("doc.source.disable") + ?.toBool(false) ?: false + if (disable) { + LOG.info("disable doc") + } + disable + } + + override fun invoke(invocation: MethodInvocation): Any? { + if (disableDoc) { + val returnType = invocation.method.returnType + return when (returnType) { + Map::class.java -> emptyMap() + List::class.java -> emptyList() + String::class.java -> "" + Boolean::class.java, Boolean::class.javaObjectType -> false + else -> null + } + } + return invocation.proceed() + } +} \ No newline at end of file diff --git a/idea-plugin/src/test/kotlin/com/itangcent/idea/psi/DisableDocSupportTest.kt b/idea-plugin/src/test/kotlin/com/itangcent/idea/psi/DisableDocSupportTest.kt new file mode 100644 index 000000000..d3895f028 --- /dev/null +++ b/idea-plugin/src/test/kotlin/com/itangcent/idea/psi/DisableDocSupportTest.kt @@ -0,0 +1,80 @@ +package com.itangcent.idea.psi + +import com.google.inject.Inject +import com.intellij.psi.PsiClass +import com.itangcent.intellij.context.ActionContext +import com.itangcent.intellij.jvm.DocHelper +import com.itangcent.testFramework.PluginContextLightCodeInsightFixtureTestCase + +/** + * Test case of [com.itangcent.idea.psi.DisableDocSupport] + */ +abstract class DisableDocSupportTest : PluginContextLightCodeInsightFixtureTestCase() { + + abstract val disableDoc: Boolean + + protected lateinit var userInfoPsiClass: PsiClass + protected lateinit var userCtrlPsiClass: PsiClass + + @Inject + protected lateinit var docHelper: DocHelper + + override fun bind(builder: ActionContext.ActionContextBuilder) { + super.bind(builder) + + DisableDocSupport.bind(builder) + + userInfoPsiClass = loadClass("model/UserInfo.java")!! + userCtrlPsiClass = loadClass("api/UserCtrl.java")!! + } + + override fun customConfig(): String? { + return super.customConfig() + "\n" + + "doc.source.disable=$disableDoc" + } + + class DisableDocSupportWithConfigTrueTest : DisableDocSupportTest() { + override val disableDoc: Boolean = true + + fun testGetDoc() { + assertEmpty(docHelper.getAttrOfDocComment(userInfoPsiClass)) + + val fields = userInfoPsiClass.findFieldByName("name", false) + assertEmpty(docHelper.getAttrOfDocComment(fields!!)) + assertTrue(docHelper.getTagMapOfDocComment(fields).isEmpty()) + assertEmpty(docHelper.findDocByTag(fields, "mock")) + assertFalse(docHelper.hasTag(fields, "mock")) + + val method = userCtrlPsiClass.findMethodsByName("get", false).first() + assertEmpty(docHelper.getAttrOfDocComment(method!!)) + assertTrue(docHelper.getTagMapOfDocComment(method).isEmpty()) + assertTrue(docHelper.getSubTagMapOfDocComment(method, "param").isEmpty()) + assertEmpty(docHelper.findDocByTag(method, "folder")) + assertEmpty(docHelper.findDocsByTagAndName(method, "param", "id")) + } + } + + class DisableDocSupportWithConfigFalseTest : DisableDocSupportTest() { + override val disableDoc: Boolean = false + + fun testGetDoc() { + assertEquals(docHelper.getAttrOfDocComment(userInfoPsiClass), "user info") + + val fields = userInfoPsiClass.findFieldByName("name", false) + assertEquals(docHelper.getAttrOfDocComment(fields!!), "user name") + assertEquals(docHelper.getTagMapOfDocComment(fields), mapOf("default" to "tangcent", "mock" to "tangcent")) + assertEquals(docHelper.findDocByTag(fields, "mock"), "tangcent") + assertTrue(docHelper.hasTag(fields, "mock")) + + val method = userCtrlPsiClass.findMethodsByName("get", false).first() + assertEquals(docHelper.getAttrOfDocComment(method!!), "get user info") + assertEquals( + docHelper.getTagMapOfDocComment(method), + mapOf("folder" to "update-apis", "param" to "id user id", "undone" to "") + ) + assertEquals(docHelper.getSubTagMapOfDocComment(method, "param"), mapOf("id" to "user id")) + assertEquals(docHelper.findDocByTag(method, "folder"), "update-apis") + assertEquals(docHelper.findDocsByTagAndName(method, "param", "id"), "user id") + } + } +} \ No newline at end of file