Improved completion by allowing configuration of whether option values should be completed#1250
Conversation
|
Hello, I’ve just improved @Option(longName = "first", shortName = 'f', completion = false) String firstI’ve also improved the completion provider so you can control whether a completion proposal should be completed or not, as mentioned in #285. See the following examples. This means completion will behave as follows: package org.springframework.shell.samples.helloworld.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.shell.core.command.CommandOption;
import org.springframework.shell.core.command.annotation.Command;
import org.springframework.shell.core.command.annotation.Option;
import org.springframework.shell.core.command.completion.CompletionProposal;
import org.springframework.shell.core.command.completion.CompletionProvider;
import java.util.Collections;
import java.util.stream.Stream;
@SpringBootApplication
public class SpringShellApplication {
public static void main(String[] args) {
SpringApplication.run(SpringShellApplication.class, args);
}
@Command(name = "hello", completionProvider = "helloNameCompletionProvider")
public void sayHello(@Option(longName = "first", shortName = 'f') String first,
@Option(longName = "last", shortName = 'l') String last) {
System.out.println("Hello " + first + " " + last + "!");
}
@Command(name = "hello2", completionProvider = "helloNameCompletionProvider")
public void sayHello2(@Option(longName = "first", shortName = 'f', completion = false) String first,
@Option(longName = "last", shortName = 'l', completion = false) String last) {
System.out.println("Hello2 " + first + " " + last + "!");
}
@Bean
public CompletionProvider helloNameCompletionProvider() {
return completionContext -> {
CommandOption option = completionContext.getCommandOption();
if (option == null) {
return Collections.emptyList();
}
String word = completionContext.getWords().get(completionContext.getWords().size() - 1);
String prefix = word.contains("=") ? word.substring(0, word.indexOf('=') + 1) : "";
Stream<String> options = Stream.empty();
if ("first".equals(option.longName())) {
options = Stream.of("Peter", "Paul", "Mary");
}
else if ("last".equals(option.longName())) {
options = Stream.of("Chan", "Noris");
}
return options.map(str -> new CompletionProposal(prefix + str).displayText(str)).toList();
};
}
}The second example shows how to use a completion provider with completion disabled for its completion proposals. This means completion will behave as follows: In this case, the completion proposals are appended with package org.springframework.shell.samples.helloworld.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.shell.core.command.CommandOption;
import org.springframework.shell.core.command.annotation.Command;
import org.springframework.shell.core.command.annotation.Option;
import org.springframework.shell.core.command.completion.CompletionProposal;
import org.springframework.shell.core.command.completion.CompletionProvider;
import java.util.Collections;
import java.util.stream.Stream;
@SpringBootApplication
public class SpringShellApplication {
public static void main(String[] args) {
SpringApplication.run(SpringShellApplication.class, args);
}
@Command(name = "snake", completionProvider = "snakeCompletionProvider")
public void snake(@Option(longName = "first", shortName = 'f', completion = false) String first,
@Option(longName = "last", shortName = 'l', completion = false) String last) {
System.out.println("Snake " + first + " " + last + "!");
}
@Bean
public CompletionProvider snakeCompletionProvider() {
return completionContext -> {
CommandOption option = completionContext.getCommandOption();
if (option == null) {
return Collections.emptyList();
}
String word = completionContext.getWords().get(completionContext.getWords().size() - 1);
String prefix = word.endsWith("=") || word.endsWith("/") ? word : word + "/";
Stream<String> options = Stream.empty();
if ("first".equals(option.longName())) {
options = Stream.of("Peter", "Paul", "Mary");
}
else if ("last".equals(option.longName())) {
options = Stream.of("Chan", "Noris");
}
return options.map(str -> new CompletionProposal(prefix + str).displayText(str).complete(false)).toList();
};
}
}I’ve also added many tests to cover this behavior. As a next step, it could be useful to allow defining a custom separator character instead of just a space or equals sign, but that would require changes to the command parser as well. |
|
@fmbenhassine Please take a look at this PR. |
a39c294 to
79086d2
Compare
79086d2 to
9b36c4d
Compare
|
Conflicts resolved, it is ready to merge if the change is suitable. Please, let me know. |
9b36c4d to
7e8cc9c
Compare
|
Thank you for the PR! I need more time to think about this new |
|
@fmbenhassine Yes, I’m aware of the new attribute. I’m absolutely fine if you suggest a different solution or attribute name, or if you decide this isn’t a good approach at all. I’ll keep this PR open and resolve all conflicts. |
…s should be completed Signed-off-by: David Pilar <david@czpilar.net>
7e8cc9c to
15bec06
Compare
Improves #1246
Resolves #285