Skip to content

Commit 6a8f59e

Browse files
committed
feat: include context in sender
1 parent b15de04 commit 6a8f59e

File tree

9 files changed

+66
-34
lines changed

9 files changed

+66
-34
lines changed

cloud-spring/src/main/java/org/incendo/cloud/spring/CommandSenderSupplier.java renamed to cloud-spring/src/main/java/org/incendo/cloud/spring/CommandSenderMapper.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,17 @@
2525

2626
import org.apiguardian.api.API;
2727
import org.checkerframework.checker.nullness.qual.NonNull;
28+
import org.checkerframework.checker.nullness.qual.Nullable;
29+
import org.springframework.shell.command.CommandContext;
2830

2931
@API(status = API.Status.STABLE, since = "1.0.0")
30-
public interface CommandSenderSupplier<C> {
32+
public interface CommandSenderMapper<C> {
3133

3234
/**
33-
* Supplies the command sender.
35+
* Maps the given {@code context} to a command sender of type {@link C}.
3436
*
37+
* @param context the context, will be {@code null} during completions
3538
* @return the sender
3639
*/
37-
@NonNull C supply();
40+
@NonNull C map(@Nullable CommandContext context);
3841
}

cloud-spring/src/main/java/org/incendo/cloud/spring/SpringCommandManager.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public class SpringCommandManager<C> extends CommandManager<C> implements Comple
6161
private static final Logger LOGGER = LoggerFactory.getLogger(SpringCommandManager.class);
6262

6363
private final SpringCommandPermissionHandler<C> commandPermissionHandler;
64-
private final CommandSenderSupplier<C> commandSenderSupplier;
64+
private final CommandSenderMapper<C> commandSenderMapper;
6565
private final SuggestionFactory<C, CloudCompletionProposal> suggestionFactory;
6666

6767
/**
@@ -70,17 +70,17 @@ public class SpringCommandManager<C> extends CommandManager<C> implements Comple
7070
* @param commandExecutionCoordinatorResolver the resolver for the execution coordinator
7171
* @param commandPermissionHandler the permission handler
7272
* @param commandRegistrationHandler the registration handler
73-
* @param commandSenderSupplier the supplier of the custom command sender type
73+
* @param commandSenderMapper the mapper for the custom command sender type
7474
*/
7575
public SpringCommandManager(
7676
final @NonNull SpringCommandExecutionCoordinatorResolver<C> commandExecutionCoordinatorResolver,
7777
final @NonNull SpringCommandPermissionHandler<C> commandPermissionHandler,
7878
final @NonNull SpringCommandRegistrationHandler<C> commandRegistrationHandler,
79-
final @NonNull CommandSenderSupplier<C> commandSenderSupplier
79+
final @NonNull CommandSenderMapper<C> commandSenderMapper
8080
) {
8181
super(commandExecutionCoordinatorResolver, commandRegistrationHandler);
8282
this.commandPermissionHandler = commandPermissionHandler;
83-
this.commandSenderSupplier = commandSenderSupplier;
83+
this.commandSenderMapper = commandSenderMapper;
8484
this.suggestionFactory = super.suggestionFactory().mapped(CloudCompletionProposal::fromSuggestion);
8585

8686
this.registerDefaultExceptionHandlers();
@@ -94,7 +94,7 @@ public final boolean hasPermission(final @NonNull C sender, final @NonNull Strin
9494
@EventListener(CommandExecutionEvent.class)
9595
void commandExecutionEvent(final @NonNull CommandExecutionEvent<C> event) {
9696
final CommandInput commandInput = CommandInput.of(Arrays.asList(event.context().getRawArgs()));
97-
this.executeCommand(this.commandSenderSupplier.supply(), commandInput.input());
97+
this.executeCommand(this.commandSenderMapper.map(event.context()), commandInput.input());
9898
}
9999

100100
@Override
@@ -109,7 +109,7 @@ void commandExecutionEvent(final @NonNull CommandExecutionEvent<C> event) {
109109
strings.addAll(completionContext.getWords());
110110
final String input = String.join(" ", strings);
111111

112-
return this.suggestionFactory().suggestImmediately(this.commandSenderSupplier.supply(), input).stream()
112+
return this.suggestionFactory().suggestImmediately(this.commandSenderMapper.map(null), input).stream()
113113
.map(suggestion -> (CompletionProposal) suggestion)
114114
.toList();
115115
}

cloud-spring/src/main/java/org/incendo/cloud/spring/SpringCommandSender.java

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,55 @@
2323
//
2424
package org.incendo.cloud.spring;
2525

26+
import java.util.Objects;
2627
import org.apiguardian.api.API;
2728
import org.checkerframework.checker.nullness.qual.NonNull;
29+
import org.checkerframework.checker.nullness.qual.Nullable;
30+
import org.springframework.shell.command.CommandContext;
2831

2932
/**
30-
* Dummy command sender type for spring.
33+
* Command sender for Spring.
3134
*
3235
* @since 1.0.0
3336
*/
3437
@API(status = API.Status.STABLE, since = "1.0.0")
35-
public interface SpringCommandSender {
36-
37-
SpringCommandSender INSTANCE = new SpringCommandSender() {
38-
};
38+
public sealed interface SpringCommandSender permits SpringCommandSender.SpringCommandSenderImpl {
3939

4040
/**
4141
* Returns the sender instance.
4242
*
43+
* @param context the context
4344
* @return the sender instance
4445
*/
45-
static @NonNull SpringCommandSender sender() {
46-
return INSTANCE;
46+
static @NonNull SpringCommandSender sender(final @Nullable CommandContext context) {
47+
return new SpringCommandSenderImpl(context);
48+
}
49+
50+
/**
51+
* Returns the context.
52+
*
53+
* <p>During suggestions the context will be {@code null}.</p>
54+
*
55+
* @return the context
56+
*/
57+
@Nullable CommandContext context();
58+
59+
/**
60+
* Writes the given {@code line} to the terminal.
61+
*
62+
* <p>A line break will be added to the line before it's written.</p>
63+
*
64+
* <p>Do <b>not</b> use this during suggestions, as {@link #context()} will be null.</p>
65+
*
66+
* @param line the line to write
67+
*/
68+
default void writeLine(final @NonNull String line) {
69+
final CommandContext context = Objects.requireNonNull(this.context());
70+
context.getTerminal().writer().println(line);
71+
}
72+
73+
74+
@API(status = API.Status.INTERNAL, consumers = "org.incendo.cloud.spring.*", since = "1.0.0")
75+
record SpringCommandSenderImpl(@Nullable CommandContext context) implements SpringCommandSender {
4776
}
4877
}

cloud-spring/src/main/java/org/incendo/cloud/spring/config/CloudSpringConfig.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import cloud.commandframework.execution.CommandExecutionCoordinator;
2727
import org.apiguardian.api.API;
2828
import org.checkerframework.checker.nullness.qual.NonNull;
29-
import org.incendo.cloud.spring.CommandSenderSupplier;
29+
import org.incendo.cloud.spring.CommandSenderMapper;
3030
import org.incendo.cloud.spring.SpringCommandExecutionCoordinatorResolver;
3131
import org.incendo.cloud.spring.SpringCommandPermissionHandler;
3232
import org.incendo.cloud.spring.SpringCommandSender;
@@ -56,8 +56,8 @@ public class CloudSpringConfig {
5656
}
5757

5858
@Bean
59-
@ConditionalOnMissingBean(CommandSenderSupplier.class)
60-
@NonNull CommandSenderSupplier<?> commandSenderMapper() {
59+
@ConditionalOnMissingBean(CommandSenderMapper.class)
60+
@NonNull CommandSenderMapper<?> commandSenderMapper() {
6161
return SpringCommandSender::sender;
6262
}
6363
}

cloud-spring/src/test/java/org/incendo/cloud/spring/ApplicationIntegrationTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ static class TestApplication {
8585
static class TestConfig {
8686

8787
@Bean
88-
@NonNull CommandSenderSupplier<TestCommandSender> commandSenderSupplier() {
89-
return TestCommandSender::new;
88+
@NonNull CommandSenderMapper<TestCommandSender> commandSenderSupplier() {
89+
return ctx -> new TestCommandSender();
9090
}
9191

9292
@Bean

example/src/main/java/org/incendo/cloud/spring/example/ExampleConfig.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
import cloud.commandframework.annotations.AnnotationParser;
2727
import org.checkerframework.checker.nullness.qual.NonNull;
28-
import org.incendo.cloud.spring.CommandSenderSupplier;
2928
import org.incendo.cloud.spring.SpringCommandManager;
3029
import org.incendo.cloud.spring.SpringCommandSender;
3130
import org.incendo.cloud.spring.annotation.CommandGroup;
@@ -38,11 +37,6 @@
3837
@Configuration
3938
public class ExampleConfig {
4039

41-
@Bean
42-
@NonNull CommandSenderSupplier<SpringCommandSender> commandSenderMapper() {
43-
return SpringCommandSender::sender;
44-
}
45-
4640
@Bean
4741
@NonNull AnnotationParser<SpringCommandSender> annotationParser(
4842
final @NonNull SpringCommandManager<SpringCommandSender> commandManager

example/src/main/java/org/incendo/cloud/spring/example/commands/AddCatCommand.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ public AddCatCommand(final @NonNull CatService catService) {
7171
}
7272

7373
@Override
74-
protected Command.Builder<SpringCommandSender> configure(final Command.Builder<SpringCommandSender> builder) {
74+
protected Command.@NonNull Builder<SpringCommandSender> configure(
75+
final Command.@NonNull Builder<SpringCommandSender> builder
76+
) {
7577
return builder.literal("add")
7678
.required("name", stringParser(), SuggestionProvider.blocking((ctx, in) -> List.of(
7779
CloudCompletionProposal.of("Missy").displayText("Missy (A cute cat name)"),
@@ -83,10 +85,10 @@ protected Command.Builder<SpringCommandSender> configure(final Command.Builder<S
8385
}
8486

8587
@Override
86-
public void execute(@NonNull final CommandContext<SpringCommandSender> commandContext) {
88+
public void execute(final @NonNull CommandContext<SpringCommandSender> commandContext) {
8789
final String name = commandContext.get("name");
8890
final boolean override = commandContext.flags().hasFlag("override");
8991
final Cat cat = this.catService.addCat(name, override);
90-
LOGGER.info("Added cat {}", cat.name());
92+
commandContext.sender().writeLine(String.format("Added cat: %s", cat.name()));
9193
}
9294
}

example/src/main/java/org/incendo/cloud/spring/example/commands/ListCatCommand.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import cloud.commandframework.annotations.CommandDescription;
2727
import cloud.commandframework.annotations.CommandMethod;
2828
import org.checkerframework.checker.nullness.qual.NonNull;
29+
import org.incendo.cloud.spring.SpringCommandSender;
2930
import org.incendo.cloud.spring.annotation.CommandGroup;
3031
import org.incendo.cloud.spring.annotation.ScanCommands;
3132
import org.incendo.cloud.spring.example.service.CatService;
@@ -52,12 +53,14 @@ public ListCatCommand(final @NonNull CatService catService) {
5253

5354
/**
5455
* Command that lists all registered cats.
56+
*
57+
* @param sender the command sender
5558
*/
5659
@CommandGroup("Cat")
5760
@CommandDescription("List the cats")
5861
@CommandMethod("cat list")
59-
public void listCats() {
60-
LOGGER.info("Cats");
61-
this.catService.cats().forEach(cat -> LOGGER.info("- {}", cat.name()));
62+
public void listCats(final @NonNull SpringCommandSender sender) {
63+
sender.writeLine("Cats");
64+
this.catService.cats().forEach(cat -> sender.writeLine(String.format("- %s", cat.name())));
6265
}
6366
}

example/src/main/java/org/incendo/cloud/spring/example/commands/RemoveCatCommand.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,10 @@ public void execute(@NonNull final CommandContext<SpringCommandSender> commandCo
8282
final String name = commandContext.get("name");
8383
final Cat cat = this.catService.removeCat(name);
8484
if (cat == null) {
85+
commandContext.sender().writeLine("No such cat :(");
8586
LOGGER.error("No such cat :(");
8687
} else {
87-
LOGGER.info("Removed cat {}", cat.name());
88+
commandContext.sender().writeLine(String.format("Removed cat: %s", cat.name()));
8889
}
8990
}
9091
}

0 commit comments

Comments
 (0)