diff options
author | Linnea Gräf <nea@nea.moe> | 2024-03-19 10:50:48 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-19 10:50:48 +0100 |
commit | 30a6f963fe6a1a9478db26d0db47062f39422eef (patch) | |
tree | 58ae072dfeda5c5b1bfe2278ed1fbb1e27a40362 | |
parent | a4946da8409040003d96c7d8d43ed394597bf675 (diff) | |
download | skyhanni-30a6f963fe6a1a9478db26d0db47062f39422eef.tar.gz skyhanni-30a6f963fe6a1a9478db26d0db47062f39422eef.tar.bz2 skyhanni-30a6f963fe6a1a9478db26d0db47062f39422eef.zip |
Backend: Add open in regex101.com intention (#1210)
3 files changed, 117 insertions, 0 deletions
diff --git a/.live-plugins/regexr/plugin.kts b/.live-plugins/regexr/plugin.kts new file mode 100644 index 000000000..128cadc7a --- /dev/null +++ b/.live-plugins/regexr/plugin.kts @@ -0,0 +1,109 @@ +import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction +import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.util.findParentOfType +import liveplugin.openInBrowser +import liveplugin.registerIntention +import liveplugin.show +import org.intellij.markdown.html.urlEncode +import org.jetbrains.kotlin.kdoc.psi.api.KDoc +import org.jetbrains.kotlin.psi.* + +// depends-on-plugin org.jetbrains.kotlin + +registerIntention(RenameKotlinFunctionToUseCamelCaseIntention()) +if (!isIdeStartup) show("Reloaded Regex intentions") +val logger = + Logger.getInstance("SkyHanni") + +val regexTestPrefix = "REGEX-TEST: " + +class RegexInfo( + val regex: KtValueArgument, + val comment: KDoc?, +) { + fun getRegexText(): String? { + val templateExpr = regex.getArgumentExpression() as? KtStringTemplateExpression ?: return null + val sb = StringBuilder() + for (x in templateExpr.entries) { + when (x) { + is KtEscapeStringTemplateEntry -> sb.append(x.unescapedValue) + is KtLiteralStringTemplateEntry -> sb.append(x.text) + else -> return null + } + } + return sb.toString() + } + + val commentText by lazy { + comment?.text + ?.replace("/*", "") + ?.replace("*/", "") + ?.lines() + ?.map { + it.trim().trimStart('*').trim() + } + } + + fun getExamples(): List<String> { + val examples = commentText?.filter { it.startsWith(regexTestPrefix) } + ?.map { it.substring(regexTestPrefix.length) } + if (examples == null) return listOf() + return examples + } +} + +inner class RenameKotlinFunctionToUseCamelCaseIntention : PsiElementBaseIntentionAction() { + override fun isAvailable(project: Project, editor: Editor?, element: PsiElement): Boolean { + return findRegexInfo(element) != null + } + + fun findRegexInfo(element: PsiElement): RegexInfo? { + val call = element.findParentOfType<KtCallExpression>() ?: return null + if (call.valueArguments.size != 2) return null + val methodName = call.calleeExpression as? KtSimpleNameExpression ?: return null + if (methodName.getReferencedName() != "pattern") return null + val field = call.findParentOfType<KtProperty>() ?: return null + val regex = call.valueArguments[1] ?: return null + val comment = field.docComment + return RegexInfo(regex, comment) + } + + override fun invoke(project: Project, editor: Editor?, element: PsiElement) { + val info = findRegexInfo(element) ?: return + val regex = info.getRegexText() + if (regex == null) { + show("Regex needs to be a bare string literal in order to open it in the browser!") + return + } + openInBrowser( + "https://regex101.com/?regex=${urlEncode(regex)}&testString=${ + urlEncode( + info.getExamples().joinToString("\n") + ) + }" + ) + } + + override fun generatePreview(project: Project, editor: Editor, file: PsiFile): IntentionPreviewInfo { + val element = getElement(editor, file) ?: return IntentionPreviewInfo.EMPTY + val info = findRegexInfo(element) ?: return IntentionPreviewInfo.EMPTY + val exampleCount = info.getExamples().size + return IntentionPreviewInfo.Html( + """ + Opens this regex on regex101.com with $exampleCount example${s(exampleCount)}. + """ + ) + } + + override fun getText() = "Open regex101.com" + override fun getFamilyName() = "OpenRegexExplorerIntention" +} + +fun s(count: Int): String { + return if (count == 1) "" else "s" +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt index 31f06ca01..7ba5102bc 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilter.kt @@ -271,6 +271,9 @@ class ChatFilter { "§eObtain a §r§6Booster Cookie §r§efrom the community shop in the hub!", ) + /** + * REGEX-TEST: §e[NPC] Jacob§f: §rYour §9Anita's Talisman §fis giving you §6+25☘ Carrot Fortune §fduring the contest! + */ private val anitaFortunePattern by RepoPattern.pattern( "chat.jacobevent.accessory", "§e\\[NPC] Jacob§f: §rYour §9Anita's \\w+ §fis giving you §6\\+\\d{1,2}☘ .+ Fortune §fduring the contest!" diff --git a/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPattern.kt b/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPattern.kt index 715c907e4..2e1259343 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPattern.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPattern.kt @@ -84,6 +84,11 @@ interface RepoPattern : ReadOnlyProperty<Any?, Pattern> { /** * Obtain a reference to a [Pattern] backed by either a local regex, or a remote regex. * Check the documentation of [RepoPattern] for more information. + * + * This method supports "Open regex101.com" using [LivePlugin](https://plugins.jetbrains.com/plugin/7282-liveplugin). + * To use it, install LivePlugin, enable "Run plugins on IDE start" and "Run project specific plugins". + * Now you can use ALT+ENTER while hovering over a [pattern] call using your text cursor to access the "Open in regex101.com" intention. + * Add a KDoc comment to the associated variable containing lines starting with `REGEX-TEST: ` to pre-fill examples. */ fun pattern(key: String, @Language("RegExp") fallback: String): RepoPattern { return RepoPatternManager.of(key, fallback) |