1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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"
}
|