diff --git a/spring-shell-core/src/main/java/org/springframework/shell/Shell.java b/spring-shell-core/src/main/java/org/springframework/shell/Shell.java index f09cd81f..94e8df6a 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/Shell.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/Shell.java @@ -99,43 +99,58 @@ public class Shell implements CommandRegistry { resultHandler.handleResult(e); continue; } - if (noInput(input)) { - continue; + if (input == null) { + break; } - - - String line = input.words().stream().collect(Collectors.joining(" ")).trim(); - String command = findLongestCommand(line); - - List words = input.words(); - Object result; - if (command != null) { - MethodTarget methodTarget = methodTargets.get(command); - List wordsForArgs = wordsForArguments(command, words); - Method method = methodTarget.getMethod(); - - try { - Object[] args = resolveArgs(method, wordsForArgs); - validateArgs(args, methodTarget); - result = ReflectionUtils.invokeMethod(method, methodTarget.getBean(), args); - } - catch (Exception e) { - result = e; - } - } - else { - result = new CommandNotFound(words); - } - resultHandler.handleResult(result); + evaluate(input); } } /** - * Return true if the parsed input ends up being empty (e.g. hitting ENTER on an empty line or blank space) + * Evaluate a single "line" of input from the user by trying to map words to a command and arguments. + * + *

This method has public visibility so that it can be invoked by actual commands + * (e.g. a {@literal script} command).

+ */ + public void evaluate(Input input) { + if (noInput(input)) { + return; + } + + String line = input.words().stream().collect(Collectors.joining(" ")).trim(); + String command = findLongestCommand(line); + + List words = input.words(); + Object result; + if (command != null) { + MethodTarget methodTarget = methodTargets.get(command); + List wordsForArgs = wordsForArguments(command, words); + Method method = methodTarget.getMethod(); + + try { + Object[] args = resolveArgs(method, wordsForArgs); + validateArgs(args, methodTarget); + result = ReflectionUtils.invokeMethod(method, methodTarget.getBean(), args); + } + catch (Exception e) { + result = e; + } + } + else { + result = new CommandNotFound(words); + } + resultHandler.handleResult(result); + } + + /** + * Return true if the parsed input ends up being empty (e.g. hitting ENTER on an empty line or blank space). + * + *

Also returns true (i.e. ask to ignore) when input starts with {@literal //}, which is used for comments.

*/ private boolean noInput(Input input) { return input.words().isEmpty() - || (input.words().size() == 1 && input.words().get(0).trim().isEmpty()); + || (input.words().size() == 1 && input.words().get(0).trim().isEmpty()) + || (input.words().iterator().next().matches("\\s*//.*")); } /** @@ -252,6 +267,8 @@ public class Shell implements CommandRegistry { public interface InputProvider { /** * Return text entered by user to invoke commands. + * + *

Returning {@literal null} indicates end of input, requesting shell exit.

*/ Input readInput(); } diff --git a/spring-shell-core/src/test/java/org/springframework/shell/ShellTest.java b/spring-shell-core/src/test/java/org/springframework/shell/ShellTest.java index 238f7f8e..3623e00e 100644 --- a/spring-shell-core/src/test/java/org/springframework/shell/ShellTest.java +++ b/spring-shell-core/src/test/java/org/springframework/shell/ShellTest.java @@ -143,6 +143,15 @@ public class ShellTest { } + @Test + public void comments() throws IOException { + when(parameterResolver.supports(any())).thenReturn(true); + when(inputProvider.readInput()).thenReturn(() -> "// This is a comment", (Input) null); + + shell.run(); + + } + private void helloWorld(String a) { invoked = true; }