From 28d6b28e876ec6a257c37239c8c1844f200076d0 Mon Sep 17 00:00:00 2001 From: lckj686 Date: Thu, 5 Aug 2021 00:30:43 +0800 Subject: [PATCH] =?UTF-8?q?#Arouter=20helper=20=E6=8F=92=E4=BB=B6=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81kotlin=20=20=20=20=20ARouter.getInstance().bu?= =?UTF-8?q?ild("xx")=EF=BC=8C=20=20@Autowired=E6=B3=A8=E8=A7=A3=20=20=20?= =?UTF-8?q?=20=20=E5=8F=8C=E5=90=91=E5=AF=BC=E8=88=AA=20=20=20=20=20@Route?= =?UTF-8?q?(path=20=3D=20"/xx/xxx")=20=EF=BC=88=E5=8F=AA=E6=94=AF=E6=8C=81?= =?UTF-8?q?kotlin=E5=AF=BC=E8=88=AAkotlin=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../idea/extensions/KtNavigationLineMarker.kt | 244 ++++++++++++++++++ .../src/main/resources/META-INF/plugin.xml | 6 +- .../main/resources/icon/icon_direct_from.png | Bin 0 -> 259 bytes .../main/resources/icon/icon_direct_to.png | Bin 0 -> 247 bytes .../main/resources/icon/icon_firect_warn.png | Bin 0 -> 250 bytes 5 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 arouter-idea-plugin/src/main/kotlin/com/alibaba/android/arouter/idea/extensions/KtNavigationLineMarker.kt create mode 100644 arouter-idea-plugin/src/main/resources/icon/icon_direct_from.png create mode 100644 arouter-idea-plugin/src/main/resources/icon/icon_direct_to.png create mode 100644 arouter-idea-plugin/src/main/resources/icon/icon_firect_warn.png diff --git a/arouter-idea-plugin/src/main/kotlin/com/alibaba/android/arouter/idea/extensions/KtNavigationLineMarker.kt b/arouter-idea-plugin/src/main/kotlin/com/alibaba/android/arouter/idea/extensions/KtNavigationLineMarker.kt new file mode 100644 index 00000000..84786034 --- /dev/null +++ b/arouter-idea-plugin/src/main/kotlin/com/alibaba/android/arouter/idea/extensions/KtNavigationLineMarker.kt @@ -0,0 +1,244 @@ +package com.alibaba.android.arouter.idea.extensions + +import com.intellij.codeInsight.daemon.LineMarkerInfo +import com.intellij.codeInsight.daemon.LineMarkerProvider +import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder +import com.intellij.formatting.blocks.prev +import com.intellij.openapi.editor.markup.GutterIconRenderer +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.IconLoader +import com.intellij.psi.* +import com.intellij.psi.impl.source.tree.CompositeElement +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.search.FilenameIndex +import com.intellij.psi.util.PsiTreeUtil + +import com.intellij.psi.PsiElement +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.util.containers.isNullOrEmpty +import java.util.regex.Pattern +import javax.swing.Icon + +/** + * 支持 kotlin 的Arouter行解读器 + * @author lckj686 + * @version 1.0 + * @since 2021-08-01 + */ +class KtNavigationLineMarker : LineMarkerProvider { + override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? = null + + private var filePath: String? = "" + private var projectPath: String? = "" + private var time: Long = 0 + + override fun collectSlowLineMarkers(elements: List, result: MutableCollection>) { + if (elements.isNullOrEmpty()) { + result + } + time = System.currentTimeMillis() + val project = elements[0].project + projectPath = project.basePath + filePath = elements[0].containingFile.viewProvider.virtualFile.canonicalPath + elements.forEachIndexed { index, psiElement -> + + var target: TargetContent? = null + + //目标注解 + target = getAnnotationContent(psiElement, listOf("Route", "Autowired")) + + if (target == null) { + target = getAnnotationContent2(psiElement) + } + target?.let { + val reva = findProperties(project, target, PsiElement::class.java, listOf("Route")) + if (reva.isNotEmpty()) { + val builder = NavigationGutterIconBuilder.create(getIcon(target)) + builder.setAlignment(GutterIconRenderer.Alignment.CENTER) + builder.setTargets(reva) + builder.setTooltipTitle("Navigation to target Protocol") + result.add(builder.createLineMarkerInfo(psiElement)) + return@forEachIndexed + } else { + val builder = NavigationGutterIconBuilder.create(getIcon(target)) + .setAlignment(GutterIconRenderer.Alignment.CENTER) + .setTargets(listOf()) + .setTooltipTitle("Navigation to none") + result.add(builder.createLineMarkerInfo(psiElement)) + } + logTime("3") + return + } + } + } + + private fun getAnnotationContent2(psiElement: PsiElement): TargetContent? { + if (psiElement.javaClass.name == "org.jetbrains.kotlin.psi.KtDotQualifiedExpression") { + if (psiElement.text.contains("ARouter.getInstance()") && psiElement.text.contains("navigation")) { + var anoContent = matchBuild(psiElement.text) + return TargetContent().apply { + this.type = 2 + this.content = anoContent + } + } + } + return null + } + + /** + * 找到 注解 + */ + private fun getAnnotationContent(element: PsiElement, targetAno: List): TargetContent? { + if (element.text == "(") { + if (element is LeafPsiElement) { + val pre = (element as LeafPsiElement).treeParent.prev() + if (pre is CompositeElement) { + val text = recursionCompositeElementText(pre) + //确实是注解 + if (targetAno.contains(text)) { + //接着去找注解的内容 + val next = element.treeNext + if (next is CompositeElement) { + val ano = recursionCompositeElement(next) + return TargetContent().apply { + this.content = ano + this.type = 1 + //如果注解是 Autowired 和导航一样处理 + if (text == "Autowired") { + this.type = 2 + } + } + } + } + } + } + } + return null + } + + /** + * 找注解内容 + */ + private fun recursionCompositeElement(element: CompositeElement): String { + //接着去找注解的内容 + var result = "" + if (element is CompositeElement && (element.firstChildNode.text == "path" || element.firstChildNode.text == "name")) { + val ano = element.text + result = ano.split("=")[1].trim() + } + return result + } + + private fun recursionCompositeElementText(element: CompositeElement): String { + + val e = element.firstChildNode + if (e is CompositeElement) { + return recursionCompositeElementText(e) + } else if (e is LeafPsiElement) { + val cotent = e.text + return cotent + } else { + return "" + } + } + + private fun findProperties(project: Project, target: TargetContent, clazz: Class, key: List): List { + var result: MutableList = mutableListOf() + val scopes = GlobalSearchScope.projectScope(project) + val virtualFiles = FilenameIndex.getAllFilesByExt(project, "kt", scopes) + println("virtualFiles-size= ${virtualFiles.size}") + if (virtualFiles.isNullOrEmpty()) { + return listOf() + } + for (virtualFile in virtualFiles) { + //当前的这个,不加自己 + if (virtualFile.canonicalPath == filePath) { + continue + } + val psiFile: PsiFile? = PsiManager.getInstance(project).findFile(virtualFile) + psiFile ?: return listOf() + + val properties = PsiTreeUtil.findChildrenOfType(psiFile, clazz) ?: listOf() + val list = properties.toMutableList() + + //src 是导航器->来查找 + if (target.type == 2) { + list.forEach { + if (it.javaClass.simpleName == "KtAnnotationEntry" && it.text.contains(target.content + ?: "") && it.text.contains("Route")) { + result.add(it) + } + } + } else if (target.content?.startsWith("\"") == true) { + list.forEachIndexed { index, property -> + println("2级查找=${property.javaClass.simpleName} ${property.text}") + //KtDotQualifiedExpression + if (target.content?.startsWith("\"") == true && property.javaClass.simpleName == "KtStringTemplateExpression") { + if (property.text == target.content) { + result.add(property) + } + } + } + } else { + list.forEachIndexed { index, property -> + if (property.javaClass.simpleName == "KtDotQualifiedExpression") { + if (property.text == target.content) { + println("--property=${property.javaClass.simpleName} ${property.text} ") + result.add(property) + } + } + } + } + } + return result + } + + fun getIconGoto(): Icon { + return IconLoader.getIcon("/icon/icon_direct_to.png") + } + + fun getIconFrom(): Icon { + return IconLoader.getIcon("/icon/icon_direct_from.png") + } + + fun getIcon(target: TargetContent): Icon { + if (target.type == 2) { + return getIconGoto() + } + return getIconFrom() + } + + fun getMarkWarnIcon(): Icon { + return IconLoader.getIcon("/icon/icon_firect_warn.png") + } + + fun logTime(tag: String = "") { + println("$tag timeOff = ${System.currentTimeMillis() - time}") + } + + + fun matchBuild(srcStr: String): String { + + // 匹配规则 + val reg = "build\\((.*?)\\)" + val pattern = Pattern.compile(reg) + + // 内容 与 匹配规则 的测试 + val matcher = pattern.matcher(srcStr) + if (matcher.find()) { + // 不包含前后的两个字符 + return matcher.group(1) + } else { + return ""; + } + } + + data class TargetContent( + var content: String? = "", + /** + * 类文件头部的注解是1 + * 导航器的是2 + */ + var type: Int = 0 + ) +} diff --git a/arouter-idea-plugin/src/main/resources/META-INF/plugin.xml b/arouter-idea-plugin/src/main/resources/META-INF/plugin.xml index fd1a185e..50147168 100644 --- a/arouter-idea-plugin/src/main/resources/META-INF/plugin.xml +++ b/arouter-idea-plugin/src/main/resources/META-INF/plugin.xml @@ -1,7 +1,7 @@ arouter-roadsign ARouter Helper - 1.0.0 + 1.1.0 Alibaba @@ -12,5 +12,9 @@ + + + \ No newline at end of file diff --git a/arouter-idea-plugin/src/main/resources/icon/icon_direct_from.png b/arouter-idea-plugin/src/main/resources/icon/icon_direct_from.png new file mode 100644 index 0000000000000000000000000000000000000000..fbfd48000d3099cfe848932ba7eb029daaac5c52 GIT binary patch literal 259 zcmV+e0sQ`nP)C3nS{37lg7`A;M_U>QF6&nWwK*7w`#D{d1N--J%7)pw1>kF@iSwoxy z8TFtWC(wzzNC6Okl^IG+dOfSkZ9vU3AqbVoda10(xs4&E_yVcuZV~^BDklH{002ov JPDHLkV1jRDW6%Hq literal 0 HcmV?d00001 diff --git a/arouter-idea-plugin/src/main/resources/icon/icon_direct_to.png b/arouter-idea-plugin/src/main/resources/icon/icon_direct_to.png new file mode 100644 index 0000000000000000000000000000000000000000..18999beb0f996c6b9762ba12a1c17bb45d21187c GIT binary patch literal 247 zcmVM@0r)f% xG=Pw1yas@iGBewGbU&kq7ws|=F);&D0|2Ypa}m1lB*p*$002ovPDHLkV1fWpUfuuz literal 0 HcmV?d00001 diff --git a/arouter-idea-plugin/src/main/resources/icon/icon_firect_warn.png b/arouter-idea-plugin/src/main/resources/icon/icon_firect_warn.png new file mode 100644 index 0000000000000000000000000000000000000000..297c90cfab4d6f93a47ce1c8391e5099218a705c GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!G2E{#}EtuWC_+IjpDzJ>}~GPpUUub5rdjW zue^cLCu1XnGxb~TPcvvSu{#v9Fx)C(ToECE>L{DtpY$K;8ZRv#GfwG$#`I^FqeH{Q z#!TBOylh7*8TlPdAN>E{9U!Lnp>b~GS;13m%u@^wu*SVP|BHW#9Yb!hNb#I9MkOxB qBb5*T|L=DY=DKLw&m@qLz`zi{NwKFkP~|buX$+pOelF{r5}E+ly;CXx literal 0 HcmV?d00001