Skip to content

Commit 300fd47

Browse files
authored
feat: add GoToParametrizeArgsAction (#18)
* add GoToParametrizeArgsAction * fix: set line-ending to lf
1 parent 14f0442 commit 300fd47

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.github.takemikami.intellij.plugin.pytestparametrize
2+
3+
4+
import com.intellij.openapi.actionSystem.*
5+
import com.intellij.openapi.editor.CaretModel
6+
import com.intellij.openapi.editor.ScrollType
7+
import com.intellij.psi.PsiElement
8+
import com.intellij.psi.PsiRecursiveElementVisitor
9+
import com.intellij.refactoring.suggested.endOffset
10+
import com.intellij.refactoring.suggested.startOffset
11+
import com.jetbrains.python.psi.*
12+
13+
14+
class GoToParametrizeArgsAction : AnAction() {
15+
override fun update(event: AnActionEvent) {
16+
val vf = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return
17+
val active = "py".equals(vf.extension) && vf.name.startsWith("test")
18+
event.presentation.isEnabledAndVisible = active
19+
}
20+
21+
class TestVisitor() : PsiRecursiveElementVisitor() {
22+
override fun visitElement(element: PsiElement) {
23+
if (element is PyDecorator
24+
&& "pytest.mark.parametrize".equals(element.qualifiedName.toString())
25+
&& element.hasArgumentList()
26+
&& element.arguments.size >= 2
27+
) {
28+
val valList = element.arguments[1]
29+
if (valList !is PyListLiteralExpression) return
30+
31+
// detect selected id
32+
val idsArguments = element.arguments.filter { it.name.equals("ids") }
33+
if (idsArguments.isEmpty()) return
34+
35+
val targetIndex = idsArguments.first().children.first().children.map {
36+
currentOffset >= it.startOffset && currentOffset <= it.endOffset
37+
}.indexOfFirst { it }
38+
if (targetIndex == -1) return
39+
40+
// detect args offset
41+
val argsOffsets = valList.elements.map { it.startOffset }
42+
if (targetIndex + 1 > argsOffsets.size) return
43+
offset = argsOffsets[targetIndex]
44+
}
45+
super.visitElement(element)
46+
}
47+
48+
var offset = -1
49+
var currentOffset = -1
50+
}
51+
52+
override fun actionPerformed(event: AnActionEvent) {
53+
val editor = event.getData(CommonDataKeys.EDITOR)
54+
val caretModel: CaretModel = editor?.caretModel ?: return
55+
val logicalPosition = caretModel.logicalPosition
56+
57+
// get offset to goto
58+
val psiFile = event.getData(PlatformDataKeys.PSI_FILE)
59+
val visitor: TestVisitor = TestVisitor()
60+
visitor.currentOffset = caretModel.offset
61+
psiFile?.accept(visitor)
62+
if (visitor.offset == -1) return
63+
64+
// move caret
65+
logicalPosition.leanForward(true);
66+
caretModel.moveToOffset(visitor.offset)
67+
editor.scrollingModel.scrollToCaret(ScrollType.CENTER_DOWN)
68+
editor.selectionModel.removeSelection()
69+
}
70+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,10 @@
3131
<extensions defaultExtensionNs="com.intellij">
3232
<codeInsight.inlayProvider language="Python" implementationClass="com.github.takemikami.intellij.plugin.pytestparametrize.PytestParametrizeInlayHintsProvider"/>
3333
</extensions>
34+
35+
<actions>
36+
<action id="go_to_parameter" class="com.github.takemikami.intellij.plugin.pytestparametrize.GoToParametrizeArgsAction" text="Pytest Parametrize Args">
37+
<add-to-group group-id="EditorPopupMenu.GoTo" anchor="last" />
38+
</action>
39+
</actions>
3440
</idea-plugin>

0 commit comments

Comments
 (0)