Skip to content

Commit e9c6070

Browse files
committed
support preview and fix indention feature for mocked methods generator
1 parent 5780ced commit e9c6070

File tree

1 file changed

+76
-32
lines changed

1 file changed

+76
-32
lines changed

src/main/java/de/espend/idea/php/phpunit/intention/AddMockMethodIntention.java

Lines changed: 76 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
package de.espend.idea.php.phpunit.intention;
22

33
import com.intellij.codeInsight.hint.HintManager;
4+
import com.intellij.codeInsight.intention.HighPriorityAction;
45
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
6+
import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils;
57
import com.intellij.openapi.command.WriteCommandAction;
68
import com.intellij.openapi.editor.Editor;
79
import com.intellij.openapi.editor.ScrollType;
810
import com.intellij.openapi.project.Project;
911
import com.intellij.openapi.ui.popup.JBPopupFactory;
12+
import com.intellij.openapi.util.Iconable;
1013
import com.intellij.psi.PsiElement;
1114
import com.intellij.psi.util.PsiTreeUtil;
12-
import com.intellij.ui.components.JBList;
1315
import com.intellij.util.IncorrectOperationException;
1416
import com.jetbrains.php.PhpIndex;
1517
import com.jetbrains.php.lang.psi.PhpPsiElementFactory;
1618
import com.jetbrains.php.lang.psi.elements.*;
19+
import de.espend.idea.php.phpunit.PhpUnitIcons;
1720
import de.espend.idea.php.phpunit.utils.processor.MethodReferenceNameProcessor;
1821
import org.jetbrains.annotations.Nls;
1922
import org.jetbrains.annotations.NotNull;
2023
import org.jetbrains.annotations.Nullable;
2124

22-
import java.util.Set;
23-
import java.util.TreeSet;
25+
import javax.swing.*;
26+
import java.util.*;
2427
import java.util.stream.Collectors;
2528

2629
/**
@@ -29,40 +32,65 @@
2932
*
3033
* @author Daniel Espendiller <daniel@espendiller.net>
3134
*/
32-
public class AddMockMethodIntention extends PsiElementBaseIntentionAction {
35+
public class AddMockMethodIntention extends PsiElementBaseIntentionAction implements Iconable, HighPriorityAction {
3336
@Override
3437
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement psiElement) throws IncorrectOperationException {
3538
String parameter = getMockInstanceFromMethodReferenceScope(psiElement);
3639

3740
if(parameter == null) {
38-
HintManager.getInstance().showErrorHint(editor, "No mock context found");
41+
if (!IntentionPreviewUtils.isPreviewElement(psiElement)) {
42+
HintManager.getInstance().showErrorHint(editor, "No mock context found");
43+
}
44+
3945
return;
4046
}
4147

4248
Set<String> methods = new TreeSet<>();
4349
for (PhpClass phpClass : PhpIndex.getInstance(psiElement.getProject()).getAnyByFQN(parameter)) {
4450
methods.addAll(phpClass.getMethods().stream()
45-
.filter(method -> method.getAccess().isPublic() && !method.getName().startsWith("__"))
51+
.filter(method -> method.getAccess().isPublic() && !method.getName().startsWith("__") && !method.isStatic() && !method.isFinal())
4652
.map(PhpNamedElement::getName).collect(Collectors.toSet())
4753
);
4854
}
4955

5056
if(methods.size() == 0) {
51-
HintManager.getInstance().showErrorHint(editor, "No public method found");
57+
if (!IntentionPreviewUtils.isPreviewElement(psiElement)) {
58+
HintManager.getInstance().showErrorHint(editor, "No public method found");
59+
}
60+
61+
return;
62+
}
63+
64+
if (IntentionPreviewUtils.isPreviewElement(psiElement)) {
65+
new MyMockWriteCommand(editor, methods, psiElement, false).run();
66+
5267
return;
5368
}
5469

5570
// Single item direct execution without selection
5671
if(methods.size() == 1) {
57-
new MyMockWriteCommand(editor, methods.iterator().next(), psiElement).execute();
72+
WriteCommandAction.runWriteCommandAction(
73+
psiElement.getProject(),
74+
getText(),
75+
"",
76+
new MyMockWriteCommand(editor, new ArrayList<>(methods), psiElement, true),
77+
psiElement.getContainingFile()
78+
);
79+
5880
return;
5981
}
6082

61-
final JBList<String> list = new JBList<>(methods);
83+
final List<String> list = new ArrayList<>(methods);
6284

63-
JBPopupFactory.getInstance().createListPopupBuilder(list)
85+
JBPopupFactory.getInstance().createPopupChooserBuilder(list)
6486
.setTitle("PHPUnit: Mock Method")
65-
.setItemChoosenCallback(() -> new MyMockWriteCommand(editor, list.getSelectedValue(), psiElement).execute())
87+
.setItemsChosenCallback(strings -> WriteCommandAction.runWriteCommandAction(
88+
psiElement.getProject(),
89+
getText(),
90+
"",
91+
new MyMockWriteCommand(editor, new ArrayList<>(strings), psiElement, true),
92+
psiElement.getContainingFile()
93+
))
6694
.createPopup()
6795
.showInBestPositionFor(editor);
6896

@@ -115,25 +143,25 @@ public boolean startInWriteAction() {
115143
return true;
116144
}
117145

118-
private static class MyMockWriteCommand extends WriteCommandAction.Simple {
146+
private static class MyMockWriteCommand implements Runnable {
119147
@NotNull
120148
private final Editor editor;
121149

122150
@NotNull
123-
private final String selectedValue;
151+
private final Collection<String> selectedValues;
124152

125153
@NotNull
126154
private final PsiElement psiElement;
155+
private final boolean jumpToLastElement;
127156

128-
private MyMockWriteCommand(@NotNull Editor editor, @NotNull String selectedValue, @NotNull PsiElement psiElement) {
129-
super(editor.getProject(), "Add method mock");
157+
private MyMockWriteCommand(@NotNull Editor editor, @NotNull Collection<String> selectedValues, @NotNull PsiElement psiElement, boolean jumpToLastElement) {
130158
this.editor = editor;
131-
this.selectedValue = selectedValue;
159+
this.selectedValues = selectedValues;
132160
this.psiElement = psiElement;
161+
this.jumpToLastElement = jumpToLastElement;
133162
}
134163

135-
@Override
136-
protected void run() {
164+
public void run() {
137165
Statement statement = PsiTreeUtil.getParentOfType(psiElement, Statement.class);
138166
if(statement == null) {
139167
HintManager.getInstance().showErrorHint(editor, "No mock context found");
@@ -149,25 +177,41 @@ protected void run() {
149177
// $foobar
150178
String prefix = childOfAnyType.getText();
151179

152-
Statement methodReference = PhpPsiElementFactory.createStatement(
153-
psiElement.getProject(),
154-
String.format("%s->method('%s')->willReturn();", prefix, selectedValue)
155-
);
180+
PsiElement elementJumpTo = null;
156181

157-
PsiElement add = statement.add(methodReference);
182+
for (String selectedValue : selectedValues) {
183+
Project project = psiElement.getProject();
158184

159-
for (MethodReference reference : PsiTreeUtil.getChildrenOfTypeAsList(add, MethodReference.class)) {
160-
if(!"willReturn".equals(reference.getName())) {
161-
continue;
162-
}
185+
Statement methodReference = PhpPsiElementFactory.createStatement(
186+
project,
187+
String.format("%s->method('%s')->willReturn();", prefix, selectedValue)
188+
);
189+
190+
elementJumpTo = statement.add(methodReference);
191+
statement.add(PhpPsiElementFactory.createNewLine(project));
192+
}
193+
194+
if (this.jumpToLastElement && elementJumpTo != null) {
195+
for (MethodReference reference : PsiTreeUtil.getChildrenOfTypeAsList(elementJumpTo, MethodReference.class)) {
196+
if(!"willReturn".equals(reference.getName())) {
197+
continue;
198+
}
163199

164-
PsiElement lastChild = reference.getLastChild();
165-
if(lastChild != null) {
166-
editor.getCaretModel().moveToOffset(lastChild.getTextRange().getStartOffset());
167-
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
200+
PsiElement lastChild = reference.getLastChild();
201+
if(lastChild != null) {
202+
editor.getCaretModel().moveToOffset(lastChild.getTextRange().getStartOffset());
203+
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
204+
}
205+
206+
break;
168207
}
169-
return;
170208
}
209+
171210
}
172211
}
212+
213+
@Override
214+
public Icon getIcon(int flags) {
215+
return PhpUnitIcons.PHPUNIT;
216+
}
173217
}

0 commit comments

Comments
 (0)