Skip to content

Commit f9a9dcb

Browse files
committed
Refactor Symfony commands options and arguments extraction, supporting both traditional and modern approaches
1 parent 12aabef commit f9a9dcb

File tree

4 files changed

+921
-171
lines changed

4 files changed

+921
-171
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/completion/command/PhpCommandGotoCompletionRegistrar.java

Lines changed: 51 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,17 @@
55
import com.intellij.patterns.PlatformPatterns;
66
import com.intellij.psi.PsiElement;
77
import com.intellij.psi.util.PsiTreeUtil;
8-
import com.intellij.util.Processor;
98
import com.jetbrains.php.lang.PhpLanguage;
10-
import com.jetbrains.php.lang.psi.elements.*;
9+
import com.jetbrains.php.lang.psi.elements.PhpClass;
10+
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
1111
import fr.adrienbrault.idea.symfony2plugin.Symfony2Icons;
1212
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionProvider;
1313
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrar;
1414
import fr.adrienbrault.idea.symfony2plugin.codeInsight.GotoCompletionRegistrarParameter;
1515
import fr.adrienbrault.idea.symfony2plugin.util.MethodMatcher;
16-
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
16+
import fr.adrienbrault.idea.symfony2plugin.util.SymfonyCommandUtil;
1717
import org.apache.commons.lang3.StringUtils;
1818
import org.jetbrains.annotations.NotNull;
19-
import org.jetbrains.annotations.Nullable;
2019

2120
import java.util.*;
2221

@@ -79,26 +78,52 @@ public Collection<LookupElement> getLookupElements() {
7978

8079
Collection<LookupElement> elements = new ArrayList<>();
8180

82-
Map<String, CommandArg> targets = getCommandConfigurationMap(phpClass, addMethod);
81+
if("addOption".equals(addMethod)) {
82+
// For options, use Map<String, CommandOption>
83+
Map<String, SymfonyCommandUtil.CommandOption> targets = SymfonyCommandUtil.getCommandOptions(phpClass);
8384

84-
for(CommandArg key: targets.values()) {
85-
LookupElementBuilder lookup = LookupElementBuilder.create(key.getName()).withIcon(Symfony2Icons.SYMFONY);
85+
for(SymfonyCommandUtil.CommandOption key: targets.values()) {
86+
LookupElementBuilder lookup = LookupElementBuilder.create(key.name()).withIcon(Symfony2Icons.SYMFONY);
8687

87-
String description = key.getDescription();
88-
if(description != null) {
88+
String description = key.description();
89+
if(description != null) {
8990

90-
if(description.length() > 25) {
91-
description = StringUtils.abbreviate(description, 25);
91+
if(description.length() > 25) {
92+
description = StringUtils.abbreviate(description, 25);
93+
}
94+
95+
lookup = lookup.withTypeText(description, true);
9296
}
9397

94-
lookup = lookup.withTypeText(description, true);
95-
}
98+
if(key.defaultValue() != null) {
99+
lookup = lookup.withTailText("(" + key.defaultValue() + ")", true);
100+
}
96101

97-
if(key.getDefaultValue() != null) {
98-
lookup = lookup.withTailText("(" + key.getDefaultValue() + ")", true);
102+
elements.add(lookup);
99103
}
104+
} else {
105+
// For arguments, use Map<String, CommandArgument>
106+
Map<String, SymfonyCommandUtil.CommandArgument> targets = SymfonyCommandUtil.getCommandArguments(phpClass);
107+
108+
for(SymfonyCommandUtil.CommandArgument key: targets.values()) {
109+
LookupElementBuilder lookup = LookupElementBuilder.create(key.name()).withIcon(Symfony2Icons.SYMFONY);
110+
111+
String description = key.description();
112+
if(description != null) {
113+
114+
if(description.length() > 25) {
115+
description = StringUtils.abbreviate(description, 25);
116+
}
117+
118+
lookup = lookup.withTypeText(description, true);
119+
}
120+
121+
if(key.defaultValue() != null) {
122+
lookup = lookup.withTailText("(" + key.defaultValue() + ")", true);
123+
}
100124

101-
elements.add(lookup);
125+
elements.add(lookup);
126+
}
102127
}
103128

104129
return elements;
@@ -118,161 +143,20 @@ public Collection<PsiElement> getPsiTargets(PsiElement element) {
118143
return Collections.emptyList();
119144
}
120145

121-
Map<String, CommandArg> targets = getCommandConfigurationMap(phpClass, addMethod);
122-
if(!targets.containsKey(contents)) {
123-
return Collections.emptyList();
124-
}
125-
126-
return Collections.singletonList(targets.get(contents).getTarget());
127-
}
128-
129-
@Nullable
130-
private String getParameterStringValue(@NotNull PsiElement[] parameters, int index) {
131-
132-
if(index >= parameters.length ) {
133-
return null;
134-
}
135-
136-
if(!(parameters[index] instanceof StringLiteralExpression)) {
137-
return null;
138-
}
139-
140-
String contents = ((StringLiteralExpression) parameters[index]).getContents();
141-
if(StringUtils.isBlank(contents)) {
142-
return null;
143-
}
144-
145-
return contents;
146-
}
147-
148-
private Map<String, CommandArg> getCommandConfigurationMap(@NotNull PhpClass phpClass, final @NotNull String methodName) {
149-
150-
Method configure = phpClass.findMethodByName("configure");
151-
if(configure == null) {
152-
return Collections.emptyMap();
153-
}
154-
155-
Collection<PsiElement> psiElements = PhpElementsUtil.collectMethodElementsWithParents(configure, new CommandDefPsiElementFilter(methodName));
156-
if(psiElements.isEmpty()) {
157-
return Collections.emptyMap();
158-
}
159-
160-
Map<String, CommandArg> targets = new HashMap<>();
161-
162-
for (PsiElement element : psiElements) {
163-
164-
if(!(element instanceof MethodReference)) {
165-
continue;
146+
if("addOption".equals(addMethod)) {
147+
Map<String, SymfonyCommandUtil.CommandOption> targets = SymfonyCommandUtil.getCommandOptions(phpClass);
148+
if(!targets.containsKey(contents)) {
149+
return Collections.emptyList();
166150
}
167-
168-
/*
169-
->setDefinition(new InputArgument())
170-
->setDefinition(array(
171-
new InputArgument(),
172-
new InputOption(),
173-
));
174-
*/
175-
if("setDefinition".equals(((MethodReference) element).getName())) {
176-
177-
Collection<NewExpression> newExpressions = PsiTreeUtil.collectElementsOfType(element, NewExpression.class);
178-
for (NewExpression newExpression : newExpressions) {
179-
if(methodName.equals("addOption") && PhpElementsUtil.getNewExpressionPhpClassWithInstance(newExpression, "Symfony\\Component\\Console\\Input\\InputOption") != null) {
180-
181-
// new InputOption()
182-
PsiElement[] parameters = newExpression.getParameters();
183-
String contents = getParameterStringValue(parameters, 0);
184-
if(contents != null && StringUtils.isNotBlank(contents)) {
185-
targets.put(contents, new CommandArg(parameters[0], contents, getParameterStringValue(parameters, 3), getParameterStringValue(parameters, 4)));
186-
}
187-
188-
} else if(methodName.equals("addArgument") && PhpElementsUtil.getNewExpressionPhpClassWithInstance(newExpression, "Symfony\\Component\\Console\\Input\\InputArgument") != null) {
189-
190-
// new InputArgument()
191-
PsiElement[] parameters = newExpression.getParameters();
192-
String contents = getParameterStringValue(parameters, 0);
193-
if(contents != null && StringUtils.isNotBlank(contents)) {
194-
targets.put(contents, new CommandArg(parameters[0], contents, getParameterStringValue(parameters, 2), getParameterStringValue(parameters, 3)));
195-
}
196-
}
197-
198-
}
199-
200-
} else {
201-
202-
/*
203-
->addArgument('arg3', null, 'desc')
204-
->addOption('opt1', null, null, 'desc', 'default')
205-
*/
206-
PsiElement[] parameters = ((MethodReference) element).getParameters();
207-
if(parameters.length > 0 && parameters[0] instanceof StringLiteralExpression) {
208-
String contents = ((StringLiteralExpression) parameters[0]).getContents();
209-
if(StringUtils.isNotBlank(contents)) {
210-
if(methodName.equals("addOption")) {
211-
targets.put(contents, new CommandArg(parameters[0], contents, getParameterStringValue(parameters, 3), getParameterStringValue(parameters, 4)));
212-
} else if(methodName.equals("addArgument")) {
213-
targets.put(contents, new CommandArg(parameters[0], contents, getParameterStringValue(parameters, 2), getParameterStringValue(parameters, 3)));
214-
}
215-
}
216-
}
217-
}
218-
219-
}
220-
221-
return targets;
222-
}
223-
224-
private record CommandDefPsiElementFilter(String methodName) implements Processor<PsiElement> {
225-
@Override
226-
public boolean process(PsiElement psiElement) {
227-
if (!(psiElement instanceof MethodReference)) {
228-
return false;
151+
return Collections.singletonList(targets.get(contents).target());
152+
} else {
153+
Map<String, SymfonyCommandUtil.CommandArgument> targets = SymfonyCommandUtil.getCommandArguments(phpClass);
154+
if(!targets.containsKey(contents)) {
155+
return Collections.emptyList();
229156
}
230-
231-
String name = ((MethodReference) psiElement).getName();
232-
return methodName.equals(name) || "setDefinition".equals(name);
157+
return Collections.singletonList(targets.get(contents).target());
233158
}
234159
}
235160
}
236161

237-
private static class CommandArg {
238-
239-
@NotNull
240-
private final PsiElement target;
241-
private final String name;
242-
private String description;
243-
private String defaultValue;
244-
245-
public CommandArg(@NotNull PsiElement target, @NotNull String name) {
246-
this.target = target;
247-
this.name = name;
248-
}
249-
250-
private CommandArg(@NotNull PsiElement target, @NotNull String name, @Nullable String description, @Nullable String defaultValue) {
251-
this.target = target;
252-
this.name = name;
253-
this.description = description;
254-
this.defaultValue = defaultValue;
255-
}
256-
257-
@NotNull
258-
public String getName() {
259-
return name;
260-
}
261-
262-
@Nullable
263-
public String getDescription() {
264-
return description;
265-
}
266-
267-
@Nullable
268-
public String getDefaultValue() {
269-
return defaultValue;
270-
}
271-
272-
@NotNull
273-
public PsiElement getTarget() {
274-
return target;
275-
}
276-
}
277-
278162
}

0 commit comments

Comments
 (0)