Skip to content

Commit 858c00e

Browse files
committed
Add support for custom completion providers
- Add attribute in Command annotation to specify custom completion provider - Move command completion APIs under command package - Remove ValueProvider as it is a duplicate of CompletionProvider - Remove unused OptionValues annotation
1 parent c94c44e commit 858c00e

File tree

19 files changed

+93
-195
lines changed

19 files changed

+93
-195
lines changed

spring-shell-autoconfigure/src/main/java/org/springframework/shell/boot/SpringShellAutoConfiguration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
@ConditionalOnMissingBean(annotation = EnableCommand.class)
3333
@ImportAutoConfiguration({ ApplicationRunnerAutoConfiguration.class, CommandRegistryAutoConfiguration.class,
3434
ComponentFlowAutoConfiguration.class, JLineShellAutoConfiguration.class, ShellRunnerAutoConfiguration.class,
35-
StandardAPIAutoConfiguration.class, StandardCommandsAutoConfiguration.class, TerminalUIAutoConfiguration.class,
36-
ThemingAutoConfiguration.class, UserConfigAutoConfiguration.class })
35+
StandardCommandsAutoConfiguration.class, TerminalUIAutoConfiguration.class, ThemingAutoConfiguration.class,
36+
UserConfigAutoConfiguration.class })
3737
public class SpringShellAutoConfiguration {
3838

3939
}

spring-shell-autoconfigure/src/main/java/org/springframework/shell/boot/StandardAPIAutoConfiguration.java

Lines changed: 0 additions & 57 deletions
This file was deleted.

spring-shell-core/src/main/java/org/springframework/shell/core/ValueProvider.java

Lines changed: 0 additions & 39 deletions
This file was deleted.

spring-shell-core/src/main/java/org/springframework/shell/core/command/AbstractCommand.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.io.PrintWriter;
1919
import java.util.ArrayList;
20+
import java.util.Collections;
2021
import java.util.List;
2122
import java.util.Objects;
2223

@@ -28,6 +29,7 @@
2829
import org.springframework.shell.core.command.availability.Availability;
2930
import org.springframework.shell.core.command.availability.AvailabilityProvider;
3031
import org.springframework.shell.core.command.exit.ExitStatusExceptionMapper;
32+
import org.springframework.shell.core.command.completion.CompletionProvider;
3133

3234
/**
3335
* Base class helping to build shell commands.
@@ -52,6 +54,8 @@ public abstract class AbstractCommand implements Command {
5254

5355
@Nullable private ExitStatusExceptionMapper exitStatusExceptionMapper;
5456

57+
private CompletionProvider completionProvider = context -> Collections.emptyList();
58+
5559
private List<String> aliases = new ArrayList<>();
5660

5761
public AbstractCommand(String name, String description) {
@@ -121,6 +125,15 @@ public void setExitStatusExceptionMapper(ExitStatusExceptionMapper exitStatusExc
121125
this.exitStatusExceptionMapper = exitStatusExceptionMapper;
122126
}
123127

128+
@Override
129+
public CompletionProvider getCompletionProvider() {
130+
return completionProvider;
131+
}
132+
133+
public void setCompletionProvider(CompletionProvider completionProvider) {
134+
this.completionProvider = completionProvider;
135+
}
136+
124137
@Override
125138
public ExitStatus execute(CommandContext commandContext) throws Exception {
126139
Availability availability = getAvailabilityProvider().get();

spring-shell-core/src/main/java/org/springframework/shell/core/command/Command.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.shell.core.command.adapter.FunctionCommandAdapter;
2929
import org.springframework.shell.core.command.availability.AvailabilityProvider;
3030
import org.springframework.shell.core.command.exit.ExitStatusExceptionMapper;
31+
import org.springframework.shell.core.command.completion.CompletionProvider;
3132
import org.springframework.util.Assert;
3233

3334
/**
@@ -94,6 +95,14 @@ default AvailabilityProvider getAvailabilityProvider() {
9495
return AvailabilityProvider.alwaysAvailable();
9596
}
9697

98+
/**
99+
* Get the completion provider of the command.
100+
* @return the completion provider of the command
101+
*/
102+
default CompletionProvider getCompletionProvider() {
103+
return context -> Collections.emptyList();
104+
}
105+
97106
/**
98107
* Execute the command within the given context.
99108
* @param commandContext the context of the command
@@ -130,6 +139,8 @@ final class Builder {
130139

131140
private AvailabilityProvider availabilityProvider = AvailabilityProvider.alwaysAvailable();
132141

142+
private CompletionProvider completionProvider = context -> Collections.emptyList();
143+
133144
@Nullable ExitStatusExceptionMapper exitStatusExceptionMapper;
134145

135146
private List<String> aliases = new ArrayList<>();
@@ -169,6 +180,11 @@ public Builder exitStatusExceptionMapper(ExitStatusExceptionMapper exitStatusExc
169180
return this;
170181
}
171182

183+
public Builder completionProvider(CompletionProvider completionProvider) {
184+
this.completionProvider = completionProvider;
185+
return this;
186+
}
187+
172188
public Builder aliases(String... aliases) {
173189
this.aliases = Arrays.asList(aliases);
174190
return this;
@@ -181,6 +197,7 @@ public AbstractCommand execute(Consumer<CommandContext> commandExecutor) {
181197
commandExecutor);
182198
command.setAliases(aliases);
183199
command.setAvailabilityProvider(availabilityProvider);
200+
command.setCompletionProvider(completionProvider);
184201
if (exitStatusExceptionMapper != null) {
185202
command.setExitStatusExceptionMapper(exitStatusExceptionMapper);
186203
}
@@ -195,6 +212,7 @@ public AbstractCommand execute(Function<CommandContext, String> commandExecutor)
195212
commandExecutor);
196213
command.setAliases(aliases);
197214
command.setAvailabilityProvider(availabilityProvider);
215+
command.setCompletionProvider(completionProvider);
198216
if (exitStatusExceptionMapper != null) {
199217
command.setExitStatusExceptionMapper(exitStatusExceptionMapper);
200218
}

spring-shell-core/src/main/java/org/springframework/shell/core/command/annotation/Command.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,10 @@
9999
*/
100100
String exitStatusExceptionMapper() default "";
101101

102+
/**
103+
* Define completion provider bean name.
104+
* @return the completion provider bean name
105+
*/
106+
String completionProvider() default "";
107+
102108
}

spring-shell-core/src/main/java/org/springframework/shell/core/command/annotation/OptionValues.java

Lines changed: 0 additions & 42 deletions
This file was deleted.

spring-shell-core/src/main/java/org/springframework/shell/core/command/annotation/support/CommandFactoryBean.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.lang.reflect.Method;
1919
import java.util.Arrays;
20+
import java.util.Collections;
2021

2122
import jakarta.validation.Validator;
2223

@@ -36,6 +37,7 @@
3637
import org.springframework.shell.core.command.adapter.MethodInvokerCommandAdapter;
3738
import org.springframework.shell.core.command.availability.AvailabilityProvider;
3839
import org.springframework.shell.core.command.exit.ExitStatusExceptionMapper;
40+
import org.springframework.shell.core.command.completion.CompletionProvider;
3941
import org.springframework.shell.core.utils.Utils;
4042
import org.springframework.util.Assert;
4143

@@ -76,6 +78,7 @@ public Command getObject() {
7678
String[] aliases = command.alias();
7779
String availabilityProvider = command.availabilityProvider();
7880
String exitStatusExceptionMapper = command.exitStatusExceptionMapper();
81+
String completionProviderBeanName = command.completionProvider();
7982
log.debug("Creating command bean for method '" + this.method + "' with name '" + name + "'");
8083
Class<?> declaringClass = this.method.getDeclaringClass();
8184
Object targetObject;
@@ -127,10 +130,23 @@ Ensure that the declaring class is annotated with a Spring stereotype annotation
127130
catch (BeansException e) {
128131
log.debug("No Validator bean found, using default validator.");
129132
}
133+
CompletionProvider completionProvider = CompletionContext -> Collections.emptyList();
134+
if (!completionProviderBeanName.isEmpty()) {
135+
try {
136+
completionProvider = this.applicationContext.getBean(completionProviderBeanName,
137+
CompletionProvider.class);
138+
}
139+
catch (BeansException e) {
140+
log.debug("No CompletionProvider bean found with name '" + completionProviderBeanName
141+
+ "', using default completion provider.");
142+
}
143+
}
144+
130145
MethodInvokerCommandAdapter methodInvokerCommandAdapter = new MethodInvokerCommandAdapter(name, description,
131146
group, help, hidden, this.method, targetObject, configurableConversionService, validator);
132147
methodInvokerCommandAdapter.setAliases(Arrays.stream(aliases).toList());
133148
methodInvokerCommandAdapter.setAvailabilityProvider(availabilityProviderBean);
149+
methodInvokerCommandAdapter.setCompletionProvider(completionProvider);
134150
if (exitStatusExceptionMapperBean != null) {
135151
methodInvokerCommandAdapter.setExitStatusExceptionMapper(exitStatusExceptionMapperBean);
136152
}

spring-shell-core/src/main/java/org/springframework/shell/core/CommandValueProvider.java renamed to spring-shell-core/src/main/java/org/springframework/shell/core/command/completion/CommandNameCompletionProvider.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,30 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.shell.core;
17+
package org.springframework.shell.core.command.completion;
1818

1919
import java.util.List;
2020
import java.util.stream.Collectors;
2121

2222
import org.springframework.shell.core.command.CommandRegistry;
23-
import org.springframework.shell.core.completion.CompletionContext;
24-
import org.springframework.shell.core.completion.CompletionProposal;
2523

2624
/**
27-
* A {@link ValueProvider} that can be used to auto-complete names of shell commands.
25+
* A {@link CompletionProvider} that can be used to auto-complete names of shell commands.
2826
*
2927
* @author Eric Bottard
3028
* @author Janne Valkealahti
3129
* @author Mahmoud Ben Hassine
3230
*/
33-
public class CommandValueProvider implements ValueProvider {
31+
public class CommandNameCompletionProvider implements CompletionProvider {
3432

3533
private final CommandRegistry commandRegistry;
3634

37-
public CommandValueProvider(CommandRegistry commandRegistry) {
35+
public CommandNameCompletionProvider(CommandRegistry commandRegistry) {
3836
this.commandRegistry = commandRegistry;
3937
}
4038

4139
@Override
42-
public List<CompletionProposal> complete(CompletionContext completionContext) {
40+
public List<CompletionProposal> apply(CompletionContext completionContext) {
4341
return commandRegistry.getCommands()
4442
.stream()
4543
.map(command -> new CompletionProposal(command.getName()))

spring-shell-core/src/main/java/org/springframework/shell/core/completion/CompletionContext.java renamed to spring-shell-core/src/main/java/org/springframework/shell/core/command/completion/CompletionContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.shell.core.completion;
17+
package org.springframework.shell.core.command.completion;
1818

1919
import org.jspecify.annotations.Nullable;
2020
import org.springframework.shell.core.command.CommandOption;

0 commit comments

Comments
 (0)