Support option label
- This adds `label` to `CommandOption` which is then used in a Help instead of type. - Fixes #424
This commit is contained in:
@@ -87,6 +87,13 @@ public interface CommandOption {
|
||||
*/
|
||||
int getArityMax();
|
||||
|
||||
/**
|
||||
* Gets a label.
|
||||
*
|
||||
* @return the label
|
||||
*/
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Gets an instance of a default {@link CommandOption}.
|
||||
*
|
||||
@@ -96,7 +103,7 @@ public interface CommandOption {
|
||||
* @return default command option
|
||||
*/
|
||||
public static CommandOption of(String[] longNames, Character[] shortNames, String description) {
|
||||
return of(longNames, shortNames, description, null, false, null, null, null, null);
|
||||
return of(longNames, shortNames, description, null, false, null, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,7 +117,7 @@ public interface CommandOption {
|
||||
*/
|
||||
public static CommandOption of(String[] longNames, Character[] shortNames, String description,
|
||||
ResolvableType type) {
|
||||
return of(longNames, shortNames, description, type, false, null, null, null, null);
|
||||
return of(longNames, shortNames, description, type, false, null, null, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,12 +132,14 @@ public interface CommandOption {
|
||||
* @param position the position value
|
||||
* @param arityMin the min arity
|
||||
* @param arityMax the max arity
|
||||
* @param label the label
|
||||
* @return default command option
|
||||
*/
|
||||
public static CommandOption of(String[] longNames, Character[] shortNames, String description,
|
||||
ResolvableType type, boolean required, String defaultValue, Integer position, Integer arityMin, Integer arityMax) {
|
||||
ResolvableType type, boolean required, String defaultValue, Integer position, Integer arityMin,
|
||||
Integer arityMax, String label) {
|
||||
return new DefaultCommandOption(longNames, shortNames, description, type, required, defaultValue, position,
|
||||
arityMin, arityMax);
|
||||
arityMin, arityMax, label);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,10 +156,11 @@ public interface CommandOption {
|
||||
private int position;
|
||||
private int arityMin;
|
||||
private int arityMax;
|
||||
private String label;
|
||||
|
||||
public DefaultCommandOption(String[] longNames, Character[] shortNames, String description,
|
||||
ResolvableType type, boolean required, String defaultValue, Integer position,
|
||||
Integer arityMin, Integer arityMax) {
|
||||
Integer arityMin, Integer arityMax, String label) {
|
||||
this.longNames = longNames != null ? longNames : new String[0];
|
||||
this.shortNames = shortNames != null ? shortNames : new Character[0];
|
||||
this.description = description;
|
||||
@@ -160,6 +170,7 @@ public interface CommandOption {
|
||||
this.position = position != null && position > -1 ? position : -1 ;
|
||||
this.arityMin = arityMin != null ? arityMin : -1;
|
||||
this.arityMax = arityMax != null ? arityMax : -1;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -206,5 +217,10 @@ public interface CommandOption {
|
||||
public int getArityMax() {
|
||||
return arityMax;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,6 +200,14 @@ public interface CommandRegistration {
|
||||
*/
|
||||
OptionSpec arity(OptionArity arity);
|
||||
|
||||
/**
|
||||
* Define a {@code label} for an option.
|
||||
*
|
||||
* @param label the label
|
||||
* @return option spec for chaining
|
||||
*/
|
||||
OptionSpec label(String label);
|
||||
|
||||
/**
|
||||
* Return a builder for chaining.
|
||||
*
|
||||
@@ -519,6 +527,7 @@ public interface CommandRegistration {
|
||||
private Integer position;
|
||||
private Integer arityMin;
|
||||
private Integer arityMax;
|
||||
private String label;
|
||||
|
||||
DefaultOptionSpec(BaseBuilder builder) {
|
||||
this.builder = builder;
|
||||
@@ -611,6 +620,12 @@ public interface CommandRegistration {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionSpec label(String label) {
|
||||
this.label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder and() {
|
||||
return builder;
|
||||
@@ -651,6 +666,10 @@ public interface CommandRegistration {
|
||||
public Integer getArityMax() {
|
||||
return arityMax;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
static class DefaultTargetSpec implements TargetSpec {
|
||||
@@ -820,7 +839,8 @@ public interface CommandRegistration {
|
||||
public List<CommandOption> getOptions() {
|
||||
return optionSpecs.stream()
|
||||
.map(o -> CommandOption.of(o.getLongNames(), o.getShortNames(), o.getDescription(), o.getType(),
|
||||
o.isRequired(), o.getDefaultValue(), o.getPosition(), o.getArityMin(), o.getArityMax()))
|
||||
o.isRequired(), o.getDefaultValue(), o.getPosition(), o.getArityMin(), o.getArityMax(),
|
||||
o.getLabel()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@@ -327,7 +327,7 @@ public class CommandParserTests extends AbstractCommandTests {
|
||||
public void testBooleanWithDefault() {
|
||||
ResolvableType type = ResolvableType.forType(boolean.class);
|
||||
CommandOption option1 = CommandOption.of(new String[] { "arg1" }, new Character[0], "description", type, false,
|
||||
"true", null, null, null);
|
||||
"true", null, null, null, null);
|
||||
|
||||
List<CommandOption> options = Arrays.asList(option1);
|
||||
String[] args = new String[]{};
|
||||
@@ -359,7 +359,7 @@ public class CommandParserTests extends AbstractCommandTests {
|
||||
|
||||
private static CommandOption longOption(String name, ResolvableType type, boolean required, Integer position, Integer arityMin, Integer arityMax) {
|
||||
return CommandOption.of(new String[] { name }, new Character[0], "desc", type, required, null, position,
|
||||
arityMin, arityMax);
|
||||
arityMin, arityMax, null);
|
||||
}
|
||||
|
||||
private static CommandOption shortOption(char name) {
|
||||
|
||||
@@ -195,6 +195,7 @@ public class CommandRegistrationTests extends AbstractCommandTests {
|
||||
.shortNames('v')
|
||||
.type(boolean.class)
|
||||
.description("some arg1")
|
||||
.label("mylabel")
|
||||
.and()
|
||||
.withTarget()
|
||||
.function(function1)
|
||||
@@ -205,6 +206,7 @@ public class CommandRegistrationTests extends AbstractCommandTests {
|
||||
assertThat(registration.getOptions()).hasSize(1);
|
||||
assertThat(registration.getOptions().get(0).getShortNames()).containsExactly('v');
|
||||
assertThat(registration.getOptions().get(0).getType()).isEqualTo(ResolvableType.forType(boolean.class));
|
||||
assertThat(registration.getOptions().get(0).getLabel()).isEqualTo("mylabel");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell.samples.e2e;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
|
||||
/**
|
||||
* Commands used for e2e test.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
@ShellComponent
|
||||
public class OptionTypeCommands extends BaseE2ECommands {
|
||||
|
||||
@Bean
|
||||
public CommandRegistration testOptionTypeRegistration() {
|
||||
return CommandRegistration.builder()
|
||||
.command(REG, "option-type")
|
||||
.group(GROUP)
|
||||
.withOption()
|
||||
.longNames("arg1")
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("arg2")
|
||||
.type(String.class)
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("arg3")
|
||||
.type(int.class)
|
||||
.and()
|
||||
.withOption()
|
||||
.longNames("arg4")
|
||||
.label("MYLABEL")
|
||||
.and()
|
||||
.withTarget()
|
||||
.consumer(ctx -> {})
|
||||
.and()
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import java.util.stream.Stream;
|
||||
import org.springframework.shell.command.CommandOption;
|
||||
import org.springframework.shell.command.CommandRegistration;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Model encapsulating info about {@code command}.
|
||||
@@ -51,7 +52,7 @@ class CommandInfoModel {
|
||||
List<CommandOption> options = registration.getOptions();
|
||||
List<CommandParameterInfoModel> parameters = options.stream()
|
||||
.map(o -> {
|
||||
String type = o.getType() == null ? "String" : ClassUtils.getShortName(o.getType().getRawClass());
|
||||
String type = commandOptionType(o);
|
||||
List<String> arguments = Stream.concat(
|
||||
Stream.of(o.getLongNames()).map(a -> "--" + a),
|
||||
Stream.of(o.getShortNames()).map(s -> "-" + s))
|
||||
@@ -67,6 +68,15 @@ class CommandInfoModel {
|
||||
return new CommandInfoModel(name, description, parameters);
|
||||
}
|
||||
|
||||
private static String commandOptionType(CommandOption o) {
|
||||
if (StringUtils.hasText(o.getLabel())) {
|
||||
return o.getLabel();
|
||||
}
|
||||
else {
|
||||
return o.getType() == null ? "String" : ClassUtils.getShortName(o.getType().getRawClass());
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user