diff --git a/spring-shell-docs/src/main/asciidoc/extending-spring-shell.adoc b/spring-shell-docs/src/main/asciidoc/extending-spring-shell.adoc
deleted file mode 100644
index 9e3087fd..00000000
--- a/spring-shell-docs/src/main/asciidoc/extending-spring-shell.adoc
+++ /dev/null
@@ -1,14 +0,0 @@
-[[extending-spring-shell]]
-== Extending Spring Shell
-
-[[support-for-shell-1-and-jcommander]]
-=== Support for Spring Shell 1 and JCommander
-
-
-=== Discovering Methods that Can Act as Commands
-
-=== Resolving Parameter Values
-
-==== Supporting kbd:[TAB] Completion
-
-
diff --git a/spring-shell-docs/src/main/asciidoc/getting-started.adoc b/spring-shell-docs/src/main/asciidoc/getting-started.adoc
new file mode 100644
index 00000000..eb8fccf8
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/getting-started.adoc
@@ -0,0 +1,120 @@
+== Getting Started
+To see what Spring Shell has to offer, we can write a trivial shell application that
+has a simple command to add two numbers.
+
+=== Writing a Simple Boot Application
+
+Starting with version 2, Spring Shell has been rewritten from the ground up with various
+enhancements in mind, one of which is easy integration with Spring Boot, although it is
+not a strong requirement.
+For the purpose of this tutorial, we create a simple Boot application by
+using https://start.spring.io. This minimal application depends only on `spring-boot-starter`
+and configures the `spring-boot-maven-plugin` to generate an executable über-jar:
+
+====
+[source, xml]
+----
+...
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+ ...
+
+----
+====
+
+[[using-spring-shell-add-dependency]]
+=== Adding a Dependency on Spring Shell
+
+The easiest way to get going with Spring Shell is to depend on the `{starter-artifactId}` artifact.
+This comes with everything one needs to use Spring Shell and plays nicely with Boot,
+configuring only the necessary beans as needed:
+
+====
+[source, xml, subs=attributes+]
+----
+...
+
+ org.springframework.shell
+ {spring-shell-starter}
+ {project-version}
+
+...
+----
+====
+
+CAUTION: Given that Spring Shell starts the REPL by virtue of this dependency being present,
+you need to either skip tests when you build (`-DskipTests`) throughout this tutorial or remove the sample integration test
+that was generated by https://start.spring.io. If you do not remove it, the integration test creates
+the Spring `ApplicationContext` and, depending on your build tool, stays stuck in the eval loop or crashes with a NPE.
+
+[[using-spring-shell-your-first-command]]
+=== Your First Command
+
+Now we can add our first command. To do so, create a new class (named whatever you want) and
+annotate it with `@ShellComponent` (a variation of `@Component` that is used to restrict
+the set of classes that are scanned for candidate commands).
+
+Then create an `add` method that takes two ints (`a` and `b`) and returns their sum. Annotate it
+with `@ShellMethod` and provide a description of the command in the annotation (the only piece of
+information that is required):
+
+====
+[source, java]
+----
+package com.example.demo;
+
+import org.springframework.shell.standard.ShellMethod;
+import org.springframework.shell.standard.ShellComponent;
+
+@ShellComponent
+public class MyCommands {
+
+ @ShellMethod("Add two integers together.")
+ public int add(int a, int b) {
+ return a + b;
+ }
+}
+----
+====
+
+[[using-spring-shell-try-application]]
+=== Trying the Application
+
+To build the application and run the generated jar, run the following command:
+
+====
+[source, bash]
+----
+./mvnw clean install -DskipTests
+[...]
+
+java -jar target/demo-0.0.1-SNAPSHOT.jar
+----
+====
+
+You are greeted by the following screen (the banner comes from Spring Boot and can be
+https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-banner[customized]:
+
+====
+[source]
+----
+shell:>
+----
+====
+
+A yellow `shell:>` prompt invites you to type commands. Type `add 1 2`, press `ENTER`, and admire the magic:
+
+====
+[source, bash]
+----
+shell:>add 1 2
+3
+----
+====
+
+Try to play with the shell (hint: there is a `help` command). When you are done, type `exit` and press `ENTER`.
+
+The rest of this document delves deeper into the whole Spring Shell programming model.
diff --git a/spring-shell-docs/src/main/asciidoc/index.adoc b/spring-shell-docs/src/main/asciidoc/index.adoc
index 297cb05e..d5a9dc83 100644
--- a/spring-shell-docs/src/main/asciidoc/index.adoc
+++ b/spring-shell-docs/src/main/asciidoc/index.adoc
@@ -1,11 +1,11 @@
= Spring Shell Reference Documentation
-Eric Bottard; Janne Valkealahti; Jay Bryant;
+Eric Bottard; Janne Valkealahti; Jay Bryant, Corneil du Plessis;
:doctype: book
:hide-uri-scheme:
:icons: font
:experimental: // For kbd: macro
+:spring-shell-starter: spring-shell-starter
-ifdef::backend-html5[]
*{projectVersion}*
(C) 2017 - 2022 VMware, Inc.
@@ -15,10 +15,8 @@ others, provided that you do not charge any fee for such copies and further
provided that each copy contains this Copyright Notice, whether distributed in
print or electronically._
-// ======================================================================================
+include::introduction.adoc[]
-include::what-is-spring-shell.adoc[]
+include::getting-started.adoc[]
-include::using-spring-shell.adoc[]
-
-// include::extending-spring-shell.adoc[]
+include::using-shell.adoc[]
diff --git a/spring-shell-docs/src/main/asciidoc/what-is-spring-shell.adoc b/spring-shell-docs/src/main/asciidoc/introduction.adoc
similarity index 94%
rename from spring-shell-docs/src/main/asciidoc/what-is-spring-shell.adoc
rename to spring-shell-docs/src/main/asciidoc/introduction.adoc
index 2a9d60c5..139e409a 100644
--- a/spring-shell-docs/src/main/asciidoc/what-is-spring-shell.adoc
+++ b/spring-shell-docs/src/main/asciidoc/introduction.adoc
@@ -1,5 +1,6 @@
-== What is Spring Shell?
+== Introduction
+=== What is Spring Shell?
Not all applications need a fancy web user interface!
Sometimes, interacting with an application through an interactive terminal is
the most appropriate way to get things done.
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-availability.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-availability.adoc
new file mode 100644
index 00000000..1eeedc9c
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell-availability.adoc
@@ -0,0 +1,147 @@
+[[dynamic-command-availability]]
+=== Dynamic Command Availability
+
+Registered commands do not always make sense, due to the internal state of the application.
+For example, there may be a `download` command, but it only works once the user has used `connect` on a remote
+server. Now, if the user tries to use the `download` command, the shell should gracefully explain that
+the command exist but that it is not available at the time.
+Spring Shell lets you do that, even letting you provide a short explanation of the reason for
+the command not being available.
+
+There are three possible ways for a command to indicate availability.
+They all leverage a no-arg method that returns an instance of `Availability`.
+Consider the following example:
+
+====
+[source, java]
+----
+@ShellComponent
+public class MyCommands {
+
+ private boolean connected;
+
+ @ShellMethod("Connect to the server.")
+ public void connect(String user, String password) {
+ [...]
+ connected = true;
+ }
+
+ @ShellMethod("Download the nuclear codes.")
+ public void download() {
+ [...]
+ }
+
+ public Availability downloadAvailability() {
+ return connected
+ ? Availability.available()
+ : Availability.unavailable("you are not connected");
+ }
+}
+----
+====
+
+The `connect` method is used to connect to the server (details omitted), altering the state
+of the command through the `connected` boolean when done.
+The `download` command as marked as unavailable until the user has connected, thanks to the presence
+of a method named exactly as the `download` command method with the `Availability` suffix in its name.
+The method returns an instance of `Availability`, constructed with one of the two factory methods.
+If the command is not available, an explanation has to be provided.
+Now, if the user tries to invoke the command while not being connected, here is what happens:
+
+====
+[source]
+----
+shell:>download
+Command 'download' exists but is not currently available because you are not connected.
+Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.
+----
+====
+
+Information about currently unavailable commands is also used in the integrated help. See <>.
+
+[TIP]
+====
+The reason provided when the command is not available should read nicely if appended after "`Because`".
+
+You should not start the sentence with a capital or add a final period
+====
+
+If naming the availability method after the name of the command method does not suit you, you
+can provide an explicit name by using the `@ShellMethodAvailability` annotation:
+
+====
+[source, java]
+----
+ @ShellMethod("Download the nuclear codes.")
+ @ShellMethodAvailability("availabilityCheck") // <1>
+ public void download() {
+ [...]
+ }
+
+ public Availability availabilityCheck() { // <1>
+ return connected
+ ? Availability.available()
+ : Availability.unavailable("you are not connected");
+ }
+----
+<1> the names have to match
+====
+
+Lastly, it is often the case that several commands in the same class share the same internal state and, thus,
+should all be available or unavailable as a group. Instead of having to stick the `@ShellMethodAvailability`
+on all command methods, Spring Shell lets you flip things around and put the `@ShellMethodAvailabilty`
+annotation on the availability method, specifying the names of the commands that it controls:
+
+====
+[source, java]
+----
+ @ShellMethod("Download the nuclear codes.")
+ public void download() {
+ [...]
+ }
+
+ @ShellMethod("Disconnect from the server.")
+ public void disconnect() {
+ [...]
+ }
+
+ @ShellMethodAvailability({"download", "disconnect"})
+ public Availability availabilityCheck() {
+ return connected
+ ? Availability.available()
+ : Availability.unavailable("you are not connected");
+ }
+----
+====
+
+[TIP]
+=====
+The default value for the `@ShellMethodAvailability.value()` attribute is `*`. This special
+wildcard matches all command names. This makes it easy to turn all commands of a single class on or off
+with a single availability method:
+
+====
+[source,java]
+----
+@ShellComponent
+public class Toggles {
+ @ShellMethodAvailability
+ public Availability availabilityOnWeekdays() {
+ return Calendar.getInstance().get(DAY_OF_WEEK) == SUNDAY
+ ? Availability.available()
+ : Availability.unavailable("today is not Sunday");
+ }
+
+ @ShellMethod
+ public void foo() {}
+
+ @ShellMethod
+ public void bar() {}
+}
+----
+====
+=====
+
+TIP: Spring Shell does not impose many constraints on how to write commands and how to organize classes.
+However, it is often good practice to put related commands in the same class, and the availability indicators
+can benefit from that.
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-built-in.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-built-in.adoc
new file mode 100644
index 00000000..244f9675
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell-built-in.adoc
@@ -0,0 +1,139 @@
+[[built-in-commands]]
+=== Built-In Commands
+
+Any application built by using the `{starter-artifactId}` artifact
+(or, to be more precise, the `spring-shell-standard-commands` dependency) comes with a set of built-in commands.
+You can override or disable these commands individually (see <>).
+However, if they are not overridden or disabled, this section describes their behavior.
+
+[[help-command]]
+==== Help
+
+Running a shell application often implies that the user is in a graphically limited
+environment. Also, while we are nearly always connected in the era of mobile phones,
+accessing a web browser or any other rich UI application (such as a PDF viewer) may not always
+be possible. This is why it is important that the shell commands are correctly self documented, and this is where the `help`
+command comes in.
+
+Typing `help` + `ENTER` lists all the commands known to the shell (including <> commands)
+and a short description of what they do, similar to the following:
+
+====
+[source]
+----
+shell:>help
+AVAILABLE COMMANDS
+ add: Add numbers together.
+ * authenticate: Authenticate with the system.
+ * blow-up: Blow Everything up.
+ clear: Clear the shell screen.
+ connect: Connect to the system
+ disconnect: Disconnect from the system.
+ exit, quit: Exit the shell.
+ help: Display help about available commands.
+ register module: Register a new module.
+ script: Read and execute commands from a file.
+ stacktrace: Display the full stacktrace of the last error.
+
+Commands marked with (*) are currently unavailable.
+Type `help ` to learn more.
+----
+====
+
+Typing `help ` shows more detailed information about a command, including the available parameters, their
+type, whether they are mandatory or not, and other details.
+
+The follwoing listing shows the `help` command applied to itself:
+
+====
+----
+shell:>help help
+
+
+NAME
+ help - Display help about available commands.
+
+SYNOPSYS
+ help [[-C] string]
+
+OPTIONS
+ -C or --command string
+ The command to obtain help for. [Optional, default = ]
+----
+====
+
+==== Clear
+The `clear` command does what you would expect and clears the screen, resetting the prompt
+in the top left corner.
+
+==== Exit
+
+The `quit` command (also aliased as `exit`) requests the shell to quit, gracefully
+closing the Spring application context. If not overridden, a JLine `History` bean writes a history of all
+commands to disk, so that they are available again (see <>) on the next launch.
+
+==== Stacktrace
+
+When an exception occurs inside command code, it is caught by the shell and a simple, one-line message is displayed
+so as not to overflow the user with too much information.
+There are cases though when understanding what exactly happened is important (especially if the exception has a nested cause).
+
+To this end, Spring Shell remembers the last exception that occurred, and the user can later use the `stacktrace`
+command to print all the details on the console.
+
+[[script-command]]
+==== Script
+
+The `script` command accepts a local file as an argument and replays commands found there, one at a time.
+
+Reading from the file behaves exactly like inside the interactive shell, so lines starting with `//` are considered
+to be comments and are ignored, while lines ending with `\` trigger line continuation.
+
+==== History
+
+The `history` command shows history of a commands which has been executed.
+
+==== Completion
+
+The `completion` command set allows you to create _scripts_ files which can be used
+with am OS shell implementations to provide completion. This is very usefull when
+working with non-interactive mode.
+
+Currently only implementation is for _bash_ which works with `bash` sub-command.
+
+==== Version
+
+The `version` command shows existing _build_ and _git_ info by integrating into
+Boot's `BuildProperties` and `GitProperties` if those exists in a shell app.
+On default only version info is shown and other can be enabled via configuration
+options.
+
+Settings are under `spring.shell.command.version` where you can use `enabled` to
+disable command and optionally define your own template with `template`. Options
+`show-build-artifact`, `show-build-group`, `show-build-name`, `show-build-time`,
+`show-build-version`, `show-git-branch`, `show-git-commit-id`,
+`show-git-short-commit-id` and `show-git-commit-time` can be used to control
+fields in a default template.
+
+Template default to `classpath:template/version-default.st` and you can define
+your own, for example having:
+
+====
+[source]
+----
+
+----
+====
+
+Which would simply output something like:
+
+====
+[source]
+----
+X.X.X
+----
+====
+
+Attributes added to default template rendering are `buildVersion`, `buildGroup`,
+`buildGroup`, `buildName`, `buildTime`, `gitShortCommitId`, `gitCommitId`,
+`gitBranch` and `gitCommitTime`.
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-customize.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-customize.adoc
new file mode 100644
index 00000000..94f0bfa2
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell-customize.adoc
@@ -0,0 +1,228 @@
+=== Customizing the Shell
+
+[[overriding-or-disabling-built-in-commands]]
+==== Overriding or Disabling Built-In Commands
+
+Spring Shell provides <> to let people achieve everyday tasks that many if not
+all shell applications need. If you are not happy with the way they behave, though, you can disable or override them,
+as explained in this section.
+
+[TIP]
+.Disabling all Built-in Commands
+=====
+If you do not need built-in commands at all, there is an easy way to "`disable`" them: don't include them.
+Either use a maven exclusion on `spring-shell-standard-commands` or, if you are selectively including Spring Shell
+dependencies, don't include that one in. The follwoing example shows how to exclude `spring-shell-standard-commands`:
+
+====
+[source,xml,subs=attributes+]
+----
+
+ org.springframework.shell
+ {starter-artifactId}
+ {project-version}
+
+
+ org.springframework.shell
+ spring-shell-standard-commands
+
+
+
+----
+====
+=====
+
+[[disabling-specific-commands]]
+===== Disabling Specific Commands
+
+To disable a single built-in command, set the `spring.shell.command..enabled` property to `false` in the
+application `Environment`. One way to do so is to pass extra arguments to the Boot application in your `main()`
+entry point:
+
+====
+[source, java]
+----
+ public static void main(String[] args) throws Exception {
+ String[] disabledCommands = {"--spring.shell.command.help.enabled=false"}; // <1>
+ String[] fullArgs = StringUtils.concatenateStringArrays(args, disabledCommands);
+ SpringApplication.run(MyApp.class, fullArgs);
+ }
+----
+<1> This disables the integrated `help` command
+====
+
+===== Overriding Specific Commands
+
+If, instead of disabling a command, you would rather provide your own implementation, then you can either:
+
+* Disable the command as explained <> and have your implementation registered
+with the same name.
+* Have your implementing class implement the `.Command` interface. As an example, here is how
+to override the `clear` command:
++
+====
+[source, java]
+----
+public class MyClear implements Clear.Command {
+
+ @ShellMethod("Clear the screen, only better.")
+ public void clear() {
+ // ...
+ }
+}
+----
+====
+
+[NOTE]
+.Please Consider Contributing your Changes
+====
+If you feel like your implementation of a standard command could be valuable to the community,
+please open a pull-request at https://github.com/spring-projects/spring-shell.
+
+Alternatively, before making any changes on your own, you can open an issue with the project. Feedback is
+always welcome!
+====
+
+// ==== ResultHandlers
+
+// TBD
+
+==== PromptProvider
+After each command invocation, the shell waits for new input from the user, displaying
+a prompt in yellow:
+
+====
+[source]
+----
+shell:>
+----
+====
+
+It is possible to customize this behavior by registering a bean of type `PromptProvider`.
+Such a bean may use internal state to decide what to display to the user (it may, for example,
+react to https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-functionality-events-annotation[application events])
+and can use JLine's `AttributedCharSequence` to display fancy ANSI text.
+
+The following example shows how to use a `PromptProvider`:
+
+====
+[source, java]
+----
+@Component
+public class CustomPromptProvider implements PromptProvider {
+
+ private ConnectionDetails connection;
+
+ @Override
+ public AttributedString getPrompt() {
+ if (connection != null) {
+ return new AttributedString(connection.getHost() + ":>",
+ AttributedStyle.DEFAULT.foreground(AttributedStyle.YELLOW));
+ }
+ else {
+ return new AttributedString("server-unknown:>",
+ AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
+ }
+ }
+
+ @EventListener
+ public void handle(ConnectionUpdatedEvent event) {
+ this.connection = event.getConnectionDetails();
+ }
+}
+----
+====
+
+==== Customizing Command Line Options Behavior
+
+There can be exactly one shell spesific `ShellApplicationRunner` which simply extends
+Boot's `ApplicationRunner`. Default behariour is to have actual runner logic in
+various `ShellRunner` implementations where candidate will be picked up.
+
+[IMPORTANT]
+====
+This is a breaking change in `2.1.x` as previous shell versions had an confusing
+logic how `ApplicationRunner` instances were used. These changes were made
+to have a better support for interactive and non-interactive modes in a same
+shell application as it's convenient to fully work on command-line and still
+have ability to enter interactive mode.
+
+You can override bean type of `ShellApplicationRunner` if there's a need to
+customise shell running logic.
+====
+
+==== Customizing Arguments Conversion
+
+Conversion from text input to actual method arguments uses the standard Spring
+https://docs.spring.io/spring/docs/4.3.11.RELEASE/spring-framework-reference/htmlsingle/#core-convert[conversion] mechanism.
+Spring Shell installs a new `DefaultConversionService` (with built-in converters enabled)
+and registers to it any bean of type `Converter`, `GenericConverter`, or
+`ConverterFactory` that it finds in the application context.
+
+This means that you can customize conversion to your custom objects
+by installing a `Converter` bean in the context:
+
+====
+[source, java]
+----
+@ShellComponent
+class ConversionCommands {
+
+ @ShellMethod("Shows conversion using Spring converter")
+ public String conversionExample(DomainObject object) {
+ return object.getClass();
+ }
+
+}
+
+class DomainObject {
+ private final String value;
+
+ DomainObject(String value) {
+ this.value = value;
+ }
+
+ public String toString() {
+ return value;
+ }
+}
+
+@Component
+class CustomDomainConverter implements Converter {
+
+ @Override
+ public DomainObject convert(String source) {
+ return new DomainObject(source);
+ }
+}
+
+----
+====
+
+[TIP]
+.Mind your String representation
+=====
+As in the preceding example, you should have
+your `toString()` implementations return the converse of what was used
+to create the object instance. This is because, when a value fails
+validation, Spring Shell prints:
+
+====
+[source]
+----
+The following constraints were not met:
+ --arg : (You passed '')
+----
+====
+
+See <> for more information.
+=====
+
+[NOTE]
+====
+If you want to customize the `ConversionService` further, you can:
+
+* Have the default one injected in your code and act upon it in some way.
+* Override it altogether with your own (custom converters need to be registered by hand).
+ The `ConversionService` used by Spring Shell needs to be https://docs.spring.io/spring/docs/4.3.12.RELEASE/spring-framework-reference/htmlsingle/#beans-autowired-annotation-qualifiers[qualified] as `"spring-shell"`.
+====
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-interaction-mode.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-interaction-mode.adoc
new file mode 100644
index 00000000..5206ea7f
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell-interaction-mode.adoc
@@ -0,0 +1,16 @@
+=== Interaction Mode
+
+Starting from _2.1.x_ a build-in support has been added to distinguish between interactive
+and non-interactive modes. This has been added so that it's easier to use shell as a
+simple command-line tool without requiring customisation to accomplish that.
+
+Currently interactive mode is entered if any command line options are passed when starting
+or running a shell from a command-line. This especially works well when shell application
+is compiled with <>.
+
+Some commands may not have any usefull meaning if running on interactive mode
+or vice versa on non-interactive mode. For example a build-in `exit` command
+have no meaning in non-interactive mode as it's used to exit interactive mode.
+
+Annotation `@ShellMethod` has a field `interactionMode` which can be used to instruct
+shell when particular command is available.
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-invoke-command.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-invoke-command.adoc
new file mode 100644
index 00000000..2ce0915a
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell-invoke-command.adoc
@@ -0,0 +1,359 @@
+=== Invoking your Commands
+
+This section addresses how you can control the way in which your commands are invoked.
+
+==== By Name Versus Positional Parameters
+
+As seen <>, decorating a method with `@ShellMethod` is the sole requirement for creating a command.
+
+The user can set the value of all the method parameters in either of two ways:
+
+* By using a parameter key (for example, `--arg value`). This approach is called "`by name parameters.`"
+* Without a key, by setting parameter values in the order in which they appear in the method signature (called "`positional parameters`").
+
+These two approaches can be mixed and matched, with named parameters always taking precedence (as they are less
+prone to ambiguity). Consider the following command definition:
+
+====
+[source, java]
+----
+ @ShellMethod("Display stuff.")
+ public String echo(int a, int b, int c) {
+ return String.format("You said a=%d, b=%d, c=%d", a, b, c);
+ }
+----
+====
+
+Given the preceding command definiton, the following invocations are all equivalent, as shown in the output:
+
+====
+[source, bash]
+----
+shell:>echo 1 2 3 <1>
+You said a=1, b=2, c=3
+
+shell:>echo --a 1 --b 2 --c 3 <2>
+You said a=1, b=2, c=3
+
+shell:>echo --b 2 --c 3 --a 1 <3>
+You said a=1, b=2, c=3
+
+shell:>echo --a 1 2 3 <4>
+You said a=1, b=2, c=3
+
+shell:>echo 1 --c 3 2 <5>
+You said a=1, b=2, c=3
+----
+<1> This uses positional parameters.
+<2> This is an example of full by-name parameters.
+<3> By-name parameters can be reordered as desired.
+<4> You can use a mix of the two approaches.
+<5> The non by-name parameters are resolved in the order in which they appear.
+====
+
+===== Customizing the Named Parameter Keys
+
+As seen <>, the default strategy for deriving the key for a named parameter is to use the Java
+name of the method signature and prefix it with two dashes (`--`). You can customize this in two ways:
+
+* Use the `prefix()` attribute of the `@ShellMethod` annotation to change the default prefix for the whole method.
+* Annotate the parameter with the `@ShellOption` annotation to override the entire key in a per-parameter fashion.
+
+Consider the following example:
+
+====
+[source, java]
+----
+ @ShellMethod(value = "Display stuff.", prefix="-")
+ public String echo(int a, int b, @ShellOption("--third") int c) {
+ return String.format("You said a=%d, b=%d, c=%d", a, b, c);
+ }
+----
+====
+
+For such a setup, the possible parameter keys are `-a`, `-b` and `--third`.
+
+[TIP]
+=====
+You can specify several keys for a single parameter. If you do so, these keys are mutually exclusive (only one of them can be used) ways
+to specify the same parameter. The following example shows the signature of the
+built-in <> command:
+
+====
+[source, java]
+----
+ @ShellMethod("Describe a command.")
+ public String help(@ShellOption({"-C", "--command"}) String command) {
+ ...
+ }
+----
+====
+=====
+
+[[optional-parameters-default-values]]
+==== Optional Parameters and Default Values
+
+Spring Shell provides the ability to give parameters default values, which lets users omit
+those parameters. Consider the following command definition:
+
+====
+[source, java]
+----
+ @ShellMethod("Say hello.")
+ public String greet(@ShellOption(defaultValue="World") String who) {
+ return "Hello " + who;
+ }
+----
+====
+
+With the preceding definition, the `greet` command can still be invoked as `greet Mother` (or `greet --who Mother`), but the following
+is also possible:
+
+====
+[source]
+----
+shell:>greet
+Hello World
+----
+====
+
+==== Parameter Arity
+Up to now, it has always been assumed that each parameter maps to a single word entered by the user.
+Situations may arise, though, when a parameter value should be multi-valued. This is driven by the `arity()`
+attribute of the `@ShellOption` annotation. You can use a collection or array for the parameter type and specify how
+many values are expected:
+
+====
+[source, java]
+----
+ @ShellMethod("Add Numbers.")
+ public float add(@ShellOption(arity=3) float[] numbers) {
+ return numbers[0] + numbers[1] + numbers[2];
+ }
+----
+====
+
+The users can then invoke the command by using any of the following syntax:
+
+====
+[source]
+----
+shell:>add 1 2 3.3
+6.3
+shell:>add --numbers 1 2 3.3
+6.3
+----
+====
+
+[WARNING]
+=====
+When using the _by-name_ parameter approach, the key should *not* be repeated. The following does *not* work:
+
+====
+[source]
+----
+shell:>add --numbers 1 --numbers 2 --numbers 3.3
+----
+====
+=====
+
+===== Varying Amount Arity
+
+The above example demonstrates requiring a known, constant arity for a parameter, three in this case. Allowing any number of multiple values of a parameter can be achieved by leaving `arity` unspecified and using Spring's built-in comma separated value parsing for collections and/or arrays:
+[source, java]
+----
+ @ShellMethod("Add a Varying Amount of Numbers.")
+ public double add(@ShellOption double[] numbers) {
+ return Arrays.stream(numbers).sum();
+ }
+----
+
+The command may then be invoked with any amount of `numbers`:
+
+====
+[source]
+----
+shell:>add 1,2,3.3
+6.3
+shell:>add --numbers 42
+42.0
+shell:>add --numbers 1,2,3.3,4,5
+15.3
+----
+====
+
+===== Special Handling of Boolean Parameters
+
+When it comes to parameter arity, one kind of parameter receives a special treatment by default, as
+is often the case in command-line utilities.
+Boolean (that is, `boolean` as well as `java.lang.Boolean`) parameters behave like they have an `arity()` of `0` by default, allowing users to set their values by using a "`flag`" approach.
+Consider the following command definition:
+
+====
+[source, java]
+----
+ @ShellMethod("Terminate the system.")
+ public String shutdown(boolean force) {
+ return "You said " + force;
+ }
+----
+====
+
+This preceding command definition allows the following invocations:
+
+====
+[source]
+----
+shell:>shutdown
+You said false
+shell:>shutdown --force
+You said true
+----
+====
+
+TIP: This special treatment plays well with the <> specification. Although the default
+for boolean parameters is to have their default value be `false`, you can specify otherwise (that is,
+`@ShellOption(defaultValue="true")`), and the behavior is inverted (that is, not specifying the parameter
+results in the value being `true`, and specifying the flag results in the value being `false`)
+
+[WARNING]
+=====
+Having this behavior of implicit `arity()=0` prevents the user from specifying a value (for example, `shutdown --force true`).
+If you would like to allow this behavior (and forego the flag approach), then force an arity of `1` by using the annotation as follows:
+
+====
+[source, java]
+----
+ @ShellMethod("Terminate the system.")
+ public String shutdown(@ShellOption(arity=1, defaultValue="false") boolean force) {
+ return "You said " + force;
+ }
+----
+====
+=====
+
+[[quotes-handling]]
+==== Quotes Handling
+
+Spring Shell takes user input and tokenizes it into words, splitting on space characters.
+If the user wants to provide a parameter value that contains spaces, that value needs to be quoted.
+Both single (`'`) and double (`"`) quotes are supported, and those quotes are not part of the value:
+Consider the following command definition:
+
+====
+[source, java]
+----
+ @ShellMethod("Prints what has been entered.")
+ public String echo(String what) {
+ return "You said " + what;
+ }
+----
+====
+
+The following commands all invoke the preceding command definition:
+
+====
+[source]
+----
+shell:>echo Hello
+You said Hello
+shell:>echo 'Hello'
+You said Hello
+shell:>echo 'Hello World'
+You said Hello World
+shell:>echo "Hello World"
+You said Hello World
+----
+====
+
+Supporting both single and double quotes lets the user embed one type of quotes into
+a value:
+
+====
+[source]
+----
+shell:>echo "I'm here!"
+You said I'm here!
+shell:>echo 'He said "Hi!"'
+You said He said "Hi!"
+----
+====
+
+That way, the user can use a single quote as an apostrophe in a message.
+
+Should the user need to embed the same kind of quote that was used to quote the whole parameter,
+the escape sequence uses the backslash (`\`) character:
+
+====
+[source]
+----
+shell:>echo 'I\'m here!'
+You said I'm here!
+shell:>echo "He said \"Hi!\""
+You said He said "Hi!"
+shell:>echo I\'m here!
+You said I'm here!
+----
+====
+
+It is also possible to escape space characters when not using enclosing quotes:
+
+====
+[source]
+----
+shell:>echo This\ is\ a\ single\ value
+You said This is a single value
+----
+====
+
+[[interacting-with-the-shell]]
+==== Interacting with the Shell
+
+The Spring Shell project builds on top of the https://github.com/jline/jline3[JLine] library and, as a result, brings
+a lot of nice interactive features, some of which are detailed in this section.
+
+First and foremost, Spring Shell supports tab completion almost everywhere possible. So, if there
+is an `echo` command and the user types `ec` and presses `TAB`, `echo` appears.
+Should there be several commands that start with `ec`, then the user is prompted to choose (using `TAB` or
+`Shift + TAB` to navigate and `ENTER` to select.)
+
+But completion does not stop at command keys. It also works for parameter keys (`--arg`) and even
+parameter values, if the application developer registered the appropriate beans (see <>).
+
+Another nice feature of Spring Shell applications is support for line continuation. If a command and its parameters
+is too long and does not fit nicely on the screen, a user can chunk it by ending a line with a backslash
+(`\`) character, pressing `ENTER`, and continuing on the next line. Upon submission of the whole command, this is
+parsed as if the user entered a single space on line breaks. The following listing shows an example of this behavior:
+
+====
+[source]
+----
+shell:>register module --type source --name foo \ <1>
+> --uri file:///tmp/bar
+Successfully registered module 'source:foo'
+----
+<1> command continues on next line
+====
+
+Line continuation also automatically triggers if the user has opened a quote (see <>)
+and presses `ENTER` while still in the quotes:
+
+====
+[source]
+----
+shell:>echo "Hello <1>
+dquote> World"
+You said Hello World
+----
+<1> The user pressed `ENTER` here.
+====
+
+Finally, Spring Shell applications benefit from a lot of keyboard shortcuts (borrowed from Emacs) with which you may
+already be familiar from working with your regular OS Shell. Notable shortcuts include `Ctrl+r` to perform
+a reverse search, `Ctrl+a`] and `Ctrl+e` to move to the beginning and the end of the current line (respectively),
+and `Esc f` and `Esc b` to move forward or backward (respectively) one word at a time.
+
+[[providing-tab-completion]]
+// ===== Providing TAB Completion Proposals
+
+// TBD
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-native.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-native.adoc
new file mode 100644
index 00000000..a74d2b3b
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell-native.adoc
@@ -0,0 +1,31 @@
+[[native]]
+=== Native Support
+
+Re-work with _2.1.x_ brings in an experimental support for compiling shell application
+into _native_ application with _GraalVM_ and _spring-native_. As underlying _jline_
+library works with _GraalVM_ most of a things should just work.
+
+Project can be compiled with native profile to get sample compiled as an native
+application:
+
+====
+----
+$ ./mvnw clean package -Pnative
+----
+====
+
+You can then run sample either with interactive or non-interactive mode:
+
+====
+----
+$ ./spring-shell-samples/target/spring-shell-samples help
+AVAILABLE COMMANDS
+
+Built-In Commands
+ completion bash: Generate bash completion script
+ help: Display help about available commands.
+ history: Display or save the history of previously run commands
+ script: Read and execute commands from a file.
+...
+----
+====
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-organize.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-organize.adoc
new file mode 100644
index 00000000..100eec47
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell-organize.adoc
@@ -0,0 +1,54 @@
+[[organizing-commands]]
+=== Organizing Commands
+
+When your shell starts to provide a lot of functionality, you may end up
+with a lot of commands, which could be confusing for your users. By typing `help`,
+they would see a daunting list of commands, organized in alphabetical order,
+which may not always make sense.
+
+To alleviate this possible confusion, Spring Shell provides the ability to group commands together,
+with reasonable defaults. Related commands would then end up in the same group (for example, `User Management Commands`)
+and be displayed together in the help screen and other places.
+
+By default, commands are grouped according to the class they are implemented in,
+turning the camel case class name into separate words (so `URLRelatedCommands` becomes `URL Related Commands`).
+This is a very sensible default, as related commands are often already in the class anyway,
+because they need to use the same collaborating objects.
+
+If, however, this behavior does not suit you, you can override the group for a
+command in the following ways, in order of priority:
+
+. Specifying a `group()` in the `@ShellMethod` annotation.
+. Placing a `@ShellCommandGroup` on the class in which the command is defined. This applies
+the group for all commands defined in that class (unless overridden, as explained earlier).
+. Placing a `@ShellCommandGroup` on the package (through `package-info.java`)
+in which the command is defined. This applies to all the commands defined in the
+package (unless overridden at the method or class level, as explained earlier)
+
+The following listing shows an example:
+
+====
+[source,java]
+----
+public class UserCommands {
+ @ShellMethod(value = "This command ends up in the 'User Commands' group")
+ public void foo() {}
+
+ @ShellMethod(value = "This command ends up in the 'Other Commands' group",
+ group = "Other Commands")
+ public void bar() {}
+}
+
+...
+
+@ShellCommandGroup("Other Commands")
+public class SomeCommands {
+ @ShellMethod(value = "This one is in 'Other Commands'")
+ public void wizz() {}
+
+ @ShellMethod(value = "And this one is 'Yet Another Group'",
+ group = "Yet Another Group")
+ public void last() {}
+}
+----
+====
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-styling.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-styling.adoc
new file mode 100644
index 00000000..d8810bc7
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell-styling.adoc
@@ -0,0 +1,49 @@
+[[styling]]
+=== Styling
+
+Starting with _2.1.x_ there is a support for centrally handling styling and theming.
+There is a default theme named _default_ which can be changed using property
+`spring.shell.theme.name`.
+
+To create a new theme register new `Theme` bean with custom `ThemeSettings` where
+you can tweak styles.
+
+====
+[source, java]
+----
+@Configuration
+static class CustomThemeConfig {
+
+ @Bean
+ public Theme myTheme() {
+ return new Theme() {
+ @Override
+ public String getName() {
+ return "mytheme";
+ }
+ @Override
+ public ThemeSettings getSettings() {
+ return new MyThemeSettings();
+ }
+ };
+ }
+}
+
+static class MyThemeSettings extends ThemeSettings {
+}
+----
+====
+
+`ThemeResolver` can be used to resolve styles if you want to create
+_jline_ styled strings programmatically.
+
+====
+[source, java]
+----
+@Autowired
+private ThemeResolver themeResolver;
+
+String resolvedStyle = themeResolver.resolveTag(TAG_TITLE);
+AttributedStyle style = themeResolver.resolveStyle(resolvedStyle);
+----
+====
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-ui-components.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-ui-components.adoc
new file mode 100644
index 00000000..db731cf0
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell-ui-components.adoc
@@ -0,0 +1,368 @@
+[[uicomponents]]
+=== UI Components
+
+Starting from _2.1.x_ there is a new component model which provides
+easier way to create higher level user interaction for usual use cases
+like asking input in a various forms. These usually are just plain text
+input or choosing something from a list.
+
+Templates for build-in components are in classpath under
+_org/springframework/shell/component_.
+
+Build-in components generally follow logic:
+
+* Enter run loop for user input
+* Generate component related context
+* Render runtime status of a component state
+* Exit
+* Render final status of a component state
+
+==== Component Render
+
+There are two ways to implement component rendering, firstly fully
+programmatically or secondly using a _ANTLR Stringtemplate_. Though
+strictly speaking there is just a simple `Function` renderer interface
+which takes `Context` as an input and outputs a list of `AttributedString`
+but this allows to choose between _templating_ and _code_.
+
+Templating is a good choice if you don't need to anything complex or
+you just want to slightly modify existing component layouts. Rendering
+via code then gives you flexibility to do whatever you need.
+
+Programmatic way to render is simple as to create a `Function`:
+
+====
+[source, java]
+----
+class StringInputCustomRenderer implements Function> {
+ @Override
+ public List apply(StringInputContext context) {
+ AttributedStringBuilder builder = new AttributedStringBuilder();
+ builder.append(context.getName());
+ builder.append(" ");
+ if (context.getResultValue() != null) {
+ builder.append(context.getResultValue());
+ }
+ else {
+ String input = context.getInput();
+ if (StringUtils.hasText(input)) {
+ builder.append(input);
+ }
+ else {
+ builder.append("[Default " + context.getDefaultValue() + "]");
+ }
+ }
+ return Arrays.asList(builder.toAttributedString());
+ }
+}
+----
+====
+
+And then hook it with a component:
+
+====
+[source, java]
+----
+@ShellMethod(key = "component stringcustom", value = "String input", group = "Components")
+public String stringInputCustom(boolean mask) {
+ StringInput component = new StringInput(getTerminal(), "Enter value", "myvalue",
+ new StringInputCustomRenderer());
+ component.setResourceLoader(getResourceLoader());
+ component.setTemplateExecutor(getTemplateExecutor());
+ if (mask) {
+ component.setMaskCharater('*');
+ }
+ StringInputContext context = component.run(StringInputContext.empty());
+ return "Got value " + context.getResultValue();
+}
+----
+====
+
+Component have their own context but usually shares some functionality
+from a parent component types, those context variables are shown below.
+
+[[textcomponentcontext-template-variables]]
+.TextComponentContext Template Variables
+|===
+|Key |Description
+
+|resultValue
+|Value after component renders its result.
+
+|name
+|Name of a component, aka its title.
+
+|message
+|Possible message set for component.
+
+|messageLevel
+|Level of a message, either INFO, WARN or ERROR
+
+|hasMessageLevelInfo
+|Return true if level is INFO, false otherwise.
+
+|hasMessageLevelWarn
+|Return true if level is WARN, false otherwise.
+
+|hasMessageLevelError
+|Return true if level is ERROR, false otherwise.
+
+|input
+|Raw user input.
+
+|===
+
+
+[[selectorcomponentcontext-template-variables]]
+.SelectorComponentContext Template Variables
+|===
+|Key |Description
+
+|name
+|Name of a component, aka title.
+
+|input
+|Raw user input, mostly for filter.
+
+|itemStates
+|Full list of item states.
+
+|itemStateView
+|Visible list of item states.
+
+|isResult
+|Return if context is in a result mode.
+
+|cursorRow
+|Current cursor row in a selector
+
+|===
+
+
+==== Build-in Components
+
+===== String Input
+
+Used to ask a simple text input from a user, optionally masking values
+if content contains something sensitive.
+
+====
+[source, java]
+----
+@ShellComponent
+public class ComponentCommands extends AbstractShellComponent {
+
+ @ShellMethod(key = "component string", value = "String input", group = "Components")
+ public String stringInput(boolean mask) {
+ StringInput component = new StringInput(getTerminal(), "Enter value", "myvalue");
+ component.setResourceLoader(getResourceLoader());
+ component.setTemplateExecutor(getTemplateExecutor());
+ if (mask) {
+ component.setMaskCharater('*');
+ }
+ StringInputContext context = component.run(StringInputContext.empty());
+ return "Got value " + context.getResultValue();
+ }
+}
+----
+====
+
+image::images/component-text-input-1.svg[text input]
+
+Context object is `StringInputContext`.
+
+[[stringinputcontext-template-variables]]
+.StringInputContext Template Variables
+|===
+|Key |Description
+
+|defaultValue
+|Default value if set, null otherwise.
+
+|maskedInput
+|Masked input value
+
+|maskedResultValue
+|Masked result value
+
+|maskCharacter
+|Mask character if set, null otherwise.
+
+|hasMaskCharacter
+|Is true if mask character is set, false otherwise.
+
+|model
+|Parent context variables <>
+|===
+
+===== Path Input
+
+Used to ask a `Path` from a user and gives additional info about a path itself.
+
+====
+[source, java]
+----
+@ShellComponent
+public class ComponentCommands extends AbstractShellComponent {
+
+ @ShellMethod(key = "component path", value = "Path input", group = "Components")
+ public String pathInput() {
+ PathInput component = new PathInput(getTerminal(), "Enter value");
+ component.setResourceLoader(getResourceLoader());
+ component.setTemplateExecutor(getTemplateExecutor());
+ PathInputContext context = component.run(PathInputContext.empty());
+ return "Got value " + context.getResultValue();
+ }
+}
+----
+====
+
+image::images/component-path-input-1.svg[text input]
+
+Context object is `PathInputContext`.
+
+[[pathinputcontext-template-variables]]
+.PathInputContext Template Variables
+|===
+|Key |Description
+
+|model
+|Parent context variables <>
+|===
+
+===== Confirmation
+
+Used to ask a simple confirmation from a user and essentially is
+yes/no question.
+
+====
+[source, java]
+----
+@ShellComponent
+public class ComponentCommands extends AbstractShellComponent {
+
+ @ShellMethod(key = "component confirmation", value = "Confirmation input", group = "Components")
+ public String confirmationInput(boolean no) {
+ ConfirmationInput component = new ConfirmationInput(getTerminal(), "Enter value", !no);
+ component.setResourceLoader(getResourceLoader());
+ component.setTemplateExecutor(getTemplateExecutor());
+ ConfirmationInputContext context = component.run(ConfirmationInputContext.empty());
+ return "Got value " + context.getResultValue();
+ }
+}
+----
+====
+
+image::images/component-confirmation-1.svg[text input]
+
+Context object is `ConfirmationInputContext`.
+
+[[confirmationinputcontext-template-variables]]
+.ConfirmationInputContext Template Variables
+|===
+|Key |Description
+
+|defaultValue
+|Default value, either true or false.
+
+|model
+|Parent context variables <>
+|===
+
+===== Single Select
+
+Used to ask an item from a list and is essentially similar to simple
+dropbox implementation.
+
+====
+[source, java]
+----
+@ShellComponent
+public class ComponentCommands extends AbstractShellComponent {
+
+ @ShellMethod(key = "component single", value = "Single selector", group = "Components")
+ public String singleSelector() {
+ List> items = new ArrayList<>();
+ items.add(SelectorItem.of("key1", "value1"));
+ items.add(SelectorItem.of("key2", "value2"));
+ SingleItemSelector> component = new SingleItemSelector<>(getTerminal(),
+ items, "testSimple", null);
+ component.setResourceLoader(getResourceLoader());
+ component.setTemplateExecutor(getTemplateExecutor());
+ SingleItemSelectorContext> context = component
+ .run(SingleItemSelectorContext.empty());
+ String result = context.getResultItem().flatMap(si -> Optional.ofNullable(si.getItem())).get();
+ return "Got value " + result;
+ }
+}
+----
+====
+
+image::images/component-single-select-1.svg[text input]
+
+Context object is `SingleItemSelectorContext`.
+
+[[singleitemselectorcontext-template-variables]]
+.SingleItemSelectorContext Template Variables
+|===
+|Key |Description
+
+|value
+|Returned value when component exists.
+
+|rows
+|Visible items where rows list contains maps of name and selected items.
+
+|model
+|Parent context variables <>
+|===
+
+===== Multi Select
+
+Used to ask an items from a list.
+
+====
+[source, java]
+----
+@ShellComponent
+public class ComponentCommands extends AbstractShellComponent {
+
+ @ShellMethod(key = "component multi", value = "Multi selector", group = "Components")
+ public String multiSelector() {
+ List> items = new ArrayList<>();
+ items.add(SelectorItem.of("key1", "value1"));
+ items.add(SelectorItem.of("key2", "value2", false));
+ items.add(SelectorItem.of("key3", "value3"));
+ MultiItemSelector> component = new MultiItemSelector<>(getTerminal(),
+ items, "testSimple", null);
+ component.setResourceLoader(getResourceLoader());
+ component.setTemplateExecutor(getTemplateExecutor());
+ MultiItemSelectorContext> context = component
+ .run(MultiItemSelectorContext.empty());
+ String result = context.getResultItems().stream()
+ .map(si -> si.getItem())
+ .collect(Collectors.joining(","));
+ return "Got value " + result;
+ }
+}
+----
+====
+
+image::images/component-multi-select-1.svg[text input]
+
+Context object is `MultiItemSelectorContext`.
+
+[[multiitemselectorcontext-template-variables]]
+.MultiItemSelectorContext Template Variables
+|===
+|Key |Description
+
+|values
+|Returned values when component exists.
+
+|rows
+|Visible items where rows list contains maps of name, selected, onrow and enabled items.
+
+|model
+|Parent context variables <>
+|===
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-validate-command.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-validate-command.adoc
new file mode 100644
index 00000000..c33c99b5
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell-validate-command.adoc
@@ -0,0 +1,33 @@
+[[validating-command-arguments]]
+=== Validating Command Arguments
+
+Spring Shell integrates with the https://beanvalidation.org/[Bean Validation API] to support
+automatic and self-documenting constraints on command parameters.
+
+Annotations found on command parameters as well as annotations at the method level are
+honored and trigger validation prior to the command executing. Consider the following command:
+
+====
+[source, java]
+----
+ @ShellMethod("Change password.")
+ public String changePassword(@Size(min = 8, max = 40) String password) {
+ return "Password successfully set to " + password;
+ }
+----
+====
+
+From the preceding example, you get the following behavior for free:
+
+====
+----
+shell:>change-password hello
+The following constraints were not met:
+ --password string : size must be between 8 and 40 (You passed 'hello')
+----
+====
+
+.Applies to All Command Implementations
+NOTE: It is important to note that bean validation applies to all command implementations, whether
+they use the "standard" API or any other API, through the use of an adapter
+(see <>)
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell-write-command.adoc b/spring-shell-docs/src/main/asciidoc/using-shell-write-command.adoc
new file mode 100644
index 00000000..6bdbfefa
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell-write-command.adoc
@@ -0,0 +1,55 @@
+=== Writing Your Own Commands
+
+The way Spring Shell decides to turn a method into an actual shell command is entirely pluggable
+(see <>). However, as of Spring Shell 2.x, the recommended way to write commands
+is to use the new API described in this section (the standard API).
+
+When you use the standard API, methods on beans are turned into executable commands, provided that:
+
+* The bean class bears the `@ShellComponent` annotation. This is used to restrict the set of beans that
+are considered.
+* The method bears the `@ShellMethod` annotation.
+
+[TIP]
+====
+The `@ShellComponent` is a stereotype annotation that is itself meta-annotated with `@Component`. As a result,
+you can used it in addition to the filtering mechanism to declare beans (for example, by using `@ComponentScan`).
+
+You can customize the name of the created bean by using the `value` attribute of the annotation.
+====
+
+[[documenting-the-command]]
+==== Documenting the Command
+
+The only required attribute of the `@ShellMethod` annotation is its `value` attribute, which should have
+a short, one-sentence, description of what the command does. This lets your users
+get consistent help about your commands without having to leave the shell (see <>).
+
+NOTE: The description of your command should be short -- no more than one or two sentences. For better
+consistency, it should starts with a capital letter and end with a period.
+
+==== Customizing the Command Name(s)
+
+By default, there is no need to specify the key for your command (that is, the word(s) that should be used
+to invoke it in the shell). The name of the method is used as the command key, turning camelCase names into
+dashed, gnu-style, names (that is, `sayHello()` becomes `say-hello`).
+
+You can, however, explicitly set the command key, by using the `key` attribute of the annotation:
+
+====
+[source, java]
+----
+ @ShellMethod(value = "Add numbers.", key = "sum")
+ public int add(int a, int b) {
+ return a + b;
+ }
+
+----
+====
+
+NOTE: The `key` attribute accepts multiple values.
+If you set multiple keys for a single method, the command is registered with those different aliases.
+
+TIP: The command key can contain pretty much any character, including spaces. When coming up with names though,
+keep in mind that consistency is often appreciated by users (that is, you should avoid mixing dashed-names with
+spaced names and other inconsistencies).
diff --git a/spring-shell-docs/src/main/asciidoc/using-shell.adoc b/spring-shell-docs/src/main/asciidoc/using-shell.adoc
new file mode 100644
index 00000000..22391e88
--- /dev/null
+++ b/spring-shell-docs/src/main/asciidoc/using-shell.adoc
@@ -0,0 +1,33 @@
+== Using Spring Shell
+This section describes how to use Spring Shell.
+
+[IMPORTANT]
+====
+_Spring Shell 2.1.x_ is a major rework to bring codebase up-to-date with
+existing _Spring Boot_ versions, adding new features and especially
+making it work with _GraalVM_ which makes command-line applications much
+more relevant on a java space. Moving to new major version also allows
+us to clean up codebase and make some needed breaking changes.
+====
+
+include::using-shell-write-command.adoc[]
+
+include::using-shell-invoke-command.adoc[]
+
+include::using-shell-validate-command.adoc[]
+
+include::using-shell-availability.adoc[]
+
+include::using-shell-organize.adoc[]
+
+include::using-shell-built-in.adoc[]
+
+include::using-shell-interaction-mode.adoc[]
+
+include::using-shell-native.adoc[]
+
+include::using-shell-styling.adoc[]
+
+include::using-shell-ui-components.adoc[]
+
+include::using-shell-customize.adoc[]
diff --git a/spring-shell-docs/src/main/asciidoc/using-spring-shell.adoc b/spring-shell-docs/src/main/asciidoc/using-spring-shell.adoc
deleted file mode 100644
index d8e457d5..00000000
--- a/spring-shell-docs/src/main/asciidoc/using-spring-shell.adoc
+++ /dev/null
@@ -1,1627 +0,0 @@
-:starter-artifactId: spring-shell-starter
-
-== Using Spring Shell
-
-This section describes how to use Spring Shell.
-
-[IMPORTANT]
-====
-_Spring Shell 2.1.x_ is a major rework to bring codebase up-to-date with
-existing _Spring Boot_ versions, adding new features and especially
-making it work with _GraalVM_ which makes command-line applications much
-more relevant on a java space. Moving to new major version also allows
-us to clean up codebase and make some needed breaking changes.
-====
-
-=== Getting Started
-
-To see what Spring Shell has to offer, we can write a trivial shell application that
-has a simple command to add two numbers.
-
-==== Writing a Simple Boot Application
-
-Starting with version 2, Spring Shell has been rewritten from the ground up with various
-enhancements in mind, one of which is easy integration with Spring Boot, although it is
-not a strong requirement.
-For the purpose of this tutorial, we create a simple Boot application by
-using https://start.spring.io. This minimal application depends only on `spring-boot-starter`
-and configures the `spring-boot-maven-plugin` to generate an executable über-jar:
-
-====
-[source, xml]
-----
-...
-
-
- org.springframework.boot
- spring-boot-starter
-
- ...
-
-----
-====
-
-==== Adding a Dependency on Spring Shell
-
-The easiest way to get going with Spring Shell is to depend on the `{starter-artifactId}` artifact.
-This comes with everything one needs to use Spring Shell and plays nicely with Boot,
-configuring only the necessary beans as needed:
-
-====
-[source, xml, subs=attributes+]
-----
-...
-
- org.springframework.shell
- {starter-artifactId}
- {project-version}
-
-...
-----
-====
-
-CAUTION: Given that Spring Shell starts the REPL by virtue of this dependency being present,
-you need to either skip tests when you build (`-DskipTests`) throughout this tutorial or remove the sample integration test
-that was generated by https://start.spring.io. If you do not remove it, the integration test creates
-the Spring `ApplicationContext` and, depending on your build tool, stays stuck in the eval loop or crashes with a NPE.
-
-[[your-first-command]]
-==== Your First Command
-
-Now we can add our first command. To do so, create a new class (named whatever you want) and
-annotate it with `@ShellComponent` (a variation of `@Component` that is used to restrict
-the set of classes that are scanned for candidate commands).
-
-Then create an `add` method that takes two ints (`a` and `b`) and returns their sum. Annotate it
-with `@ShellMethod` and provide a description of the command in the annotation (the only piece of
-information that is required):
-
-====
-[source, java]
-----
-package com.example.demo;
-
-import org.springframework.shell.standard.ShellMethod;
-import org.springframework.shell.standard.ShellComponent;
-
-@ShellComponent
-public class MyCommands {
-
- @ShellMethod("Add two integers together.")
- public int add(int a, int b) {
- return a + b;
- }
-}
-----
-====
-
-==== Trying the Application
-
-To build the application and run the generated jar, run the following command:
-
-====
-[source, bash]
-----
-./mvnw clean install -DskipTests
-[...]
-
-java -jar target/demo-0.0.1-SNAPSHOT.jar
-----
-====
-
-You are greeted by the following screen (the banner comes from Spring Boot and can be
-https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-banner[customized]:
-
-====
-[source]
-----
-shell:>
-----
-====
-
-A yellow `shell:>` prompt invites you to type commands. Type `add 1 2`, press `ENTER`, and admire the magic:
-
-====
-[source, bash]
-----
-shell:>add 1 2
-3
-----
-====
-
-Try to play with the shell (hint: there is a `help` command). When you are done, type `exit` and press `ENTER`.
-
-The rest of this document delves deeper into the whole Spring Shell programming model.
-
-=== Writing Your Own Commands
-
-The way Spring Shell decides to turn a method into an actual shell command is entirely pluggable
-(see <>). However, as of Spring Shell 2.x, the recommended way to write commands
-is to use the new API described in this section (the standard API).
-
-When you use the standard API, methods on beans are turned into executable commands, provided that:
-
-* The bean class bears the `@ShellComponent` annotation. This is used to restrict the set of beans that
-are considered.
-* The method bears the `@ShellMethod` annotation.
-
-[TIP]
-====
-The `@ShellComponent` is a stereotype annotation that is itself meta-annotated with `@Component`. As a result, you
-can used it in addition to the filtering mechanism to declare beans (for example, by using `@ComponentScan`).
-
-You can customize the name of the created bean by using the `value` attribute of the annotation.
-====
-
-[[documenting-the-command]]
-==== Documenting the Command
-
-The only required attribute of the `@ShellMethod` annotation is its `value` attribute, which should have
-a short, one-sentence, description of what the command does. This lets your users
-get consistent help about your commands without having to leave the shell (see <>).
-
-NOTE: The description of your command should be short -- no more than one or two sentences. For better consistency, it
-should starts with a capital letter and end with a period.
-
-==== Customizing the Command Name(s)
-
-By default, there is no need to specify the key for your command (that is, the word(s) that should be used
-to invoke it in the shell). The name of the method is used as the command key, turning camelCase names into
-dashed, gnu-style, names (that is, `sayHello()` becomes `say-hello`).
-
-You can, however, explicitly set the command key, by using the `key` attribute of the annotation:
-
-====
-[source, java]
-----
- @ShellMethod(value = "Add numbers.", key = "sum")
- public int add(int a, int b) {
- return a + b;
- }
-
-----
-====
-
-NOTE: The `key` attribute accepts multiple values.
-If you set multiple keys for a single method, the command is registered with those different aliases.
-
-TIP: The command key can contain pretty much any character, including spaces. When coming up with names though,
-keep in mind that consistency is often appreciated by users (that is, you should avoid mixing dashed-names with spaced names and other inconsistencies).
-
-
-=== Invoking your Commands
-
-This section addresses how you can control the way in which your commands are invoked.
-
-==== By Name Versus Positional Parameters
-
-As seen <>, decorating a method with `@ShellMethod` is the sole requirement for creating a command.
-
-The user can set the value of all the method parameters in either of two ways:
-
-* By using a parameter key (for example, `--arg value`). This approach is called "`by name parameters.`"
-* Without a key, by setting parameter values in the order in which they appear in the method signature (called "`positional parameters`").
-
-These two approaches can be mixed and matched, with named parameters always taking precedence (as they are less
-prone to ambiguity). Consider the following command definition:
-
-====
-[source, java]
-----
- @ShellMethod("Display stuff.")
- public String echo(int a, int b, int c) {
- return String.format("You said a=%d, b=%d, c=%d", a, b, c);
- }
-----
-====
-
-Given the preceding command definiton, the following invocations are all equivalent, as shown in the output:
-
-====
-[source, bash]
-----
-shell:>echo 1 2 3 <1>
-You said a=1, b=2, c=3
-
-shell:>echo --a 1 --b 2 --c 3 <2>
-You said a=1, b=2, c=3
-
-shell:>echo --b 2 --c 3 --a 1 <3>
-You said a=1, b=2, c=3
-
-shell:>echo --a 1 2 3 <4>
-You said a=1, b=2, c=3
-
-shell:>echo 1 --c 3 2 <5>
-You said a=1, b=2, c=3
-----
-<1> This uses positional parameters.
-<2> This is an example of full by-name parameters.
-<3> By-name parameters can be reordered as desired.
-<4> You can use a mix of the two approaches.
-<5> The non by-name parameters are resolved in the order in which they appear.
-====
-
-===== Customizing the Named Parameter Keys
-
-As seen <>, the default strategy for deriving the key for a named parameter is to use the Java
-name of the method signature and prefix it with two dashes (`--`). You can customize this in two ways:
-
-* Use the `prefix()` attribute of the `@ShellMethod` annotation to change the default prefix for the whole method.
-* Annotate the parameter with the `@ShellOption` annotation to override the entire key in a per-parameter fashion.
-
-Consider the following example:
-
-====
-[source, java]
-----
- @ShellMethod(value = "Display stuff.", prefix="-")
- public String echo(int a, int b, @ShellOption("--third") int c) {
- return String.format("You said a=%d, b=%d, c=%d", a, b, c);
- }
-----
-====
-
-For such a setup, the possible parameter keys are `-a`, `-b` and `--third`.
-
-[TIP]
-=====
-You can specify several keys for a single parameter. If you do so, these keys are mutually exclusive (only one of them can be used) ways
-to specify the same parameter. The following example shows the signature of the
-built-in <> command:
-
-====
-[source, java]
-----
- @ShellMethod("Describe a command.")
- public String help(@ShellOption({"-C", "--command"}) String command) {
- ...
- }
-----
-====
-=====
-
-[[optional-parameters-default-values]]
-==== Optional Parameters and Default Values
-
-Spring Shell provides the ability to give parameters default values, which lets users omit
-those parameters. Consider the following command definition:
-
-====
-[source, java]
-----
- @ShellMethod("Say hello.")
- public String greet(@ShellOption(defaultValue="World") String who) {
- return "Hello " + who;
- }
-----
-====
-
-With the preceding definition, the `greet` command can still be invoked as `greet Mother` (or `greet --who Mother`), but the following
-is also possible:
-
-====
-[source]
-----
-shell:>greet
-Hello World
-----
-====
-
-==== Parameter Arity
-Up to now, it has always been assumed that each parameter maps to a single word entered by the user.
-Situations may arise, though, when a parameter value should be multi-valued. This is driven by the `arity()`
-attribute of the `@ShellOption` annotation. You can use a collection or array for the parameter type and specify how
-many values are expected:
-
-====
-[source, java]
-----
- @ShellMethod("Add Numbers.")
- public float add(@ShellOption(arity=3) float[] numbers) {
- return numbers[0] + numbers[1] + numbers[2];
- }
-----
-====
-
-The users can then invoke the command by using any of the following syntax:
-
-====
-[source]
-----
-shell:>add 1 2 3.3
-6.3
-shell:>add --numbers 1 2 3.3
-6.3
-----
-====
-
-[WARNING]
-=====
-When using the _by-name_ parameter approach, the key should *not* be repeated. The following does *not* work:
-
-====
-[source]
-----
-shell:>add --numbers 1 --numbers 2 --numbers 3.3
-----
-====
-=====
-
-===== Varying Amount Arity
-
-The above example demonstrates requiring a known, constant arity for a parameter, three in this case. Allowing any number of multiple values of a parameter can be achieved by leaving `arity` unspecified and using Spring's built-in comma separated value parsing for collections and/or arrays:
-[source, java]
-----
- @ShellMethod("Add a Varying Amount of Numbers.")
- public double add(@ShellOption double[] numbers) {
- return Arrays.stream(numbers).sum();
- }
-----
-
-The command may then be invoked with any amount of `numbers`:
-
-====
-[source]
-----
-shell:>add 1,2,3.3
-6.3
-shell:>add --numbers 42
-42.0
-shell:>add --numbers 1,2,3.3,4,5
-15.3
-----
-====
-
-===== Special Handling of Boolean Parameters
-
-When it comes to parameter arity, one kind of parameter receives a special treatment by default, as
-is often the case in command-line utilities.
-Boolean (that is, `boolean` as well as `java.lang.Boolean`) parameters behave like they have an `arity()` of `0` by default, allowing users to set their values by using a "`flag`" approach.
-Consider the following command definition:
-
-====
-[source, java]
-----
- @ShellMethod("Terminate the system.")
- public String shutdown(boolean force) {
- return "You said " + force;
- }
-----
-====
-
-This preceding command definition allows the following invocations:
-
-====
-[source]
-----
-shell:>shutdown
-You said false
-shell:>shutdown --force
-You said true
-----
-====
-
-TIP: This special treatment plays well with the <> specification. Although the default
-for boolean parameters is to have their default value be `false`, you can specify otherwise (that is,
-`@ShellOption(defaultValue="true")`), and the behavior is inverted (that is, not specifying the parameter
-results in the value being `true`, and specifying the flag results in the value being `false`)
-
-[WARNING]
-=====
-Having this behavior of implicit `arity()=0` prevents the user from specifying a value (for example, `shutdown --force true`).
-If you would like to allow this behavior (and forego the flag approach), then force an arity of `1` by using the annotation as follows:
-
-====
-[source, java]
-----
- @ShellMethod("Terminate the system.")
- public String shutdown(@ShellOption(arity=1, defaultValue="false") boolean force) {
- return "You said " + force;
- }
-----
-====
-=====
-
-[[quotes-handling]]
-==== Quotes Handling
-
-Spring Shell takes user input and tokenizes it into words, splitting on space characters.
-If the user wants to provide a parameter value that contains spaces, that value needs to be quoted.
-Both single (`'`) and double (`"`) quotes are supported, and those quotes are not part of the value:
-Consider the following command definition:
-
-====
-[source, java]
-----
- @ShellMethod("Prints what has been entered.")
- public String echo(String what) {
- return "You said " + what;
- }
-----
-====
-
-The following commands all invoke the preceding command definition:
-
-====
-[source]
-----
-shell:>echo Hello
-You said Hello
-shell:>echo 'Hello'
-You said Hello
-shell:>echo 'Hello World'
-You said Hello World
-shell:>echo "Hello World"
-You said Hello World
-----
-====
-
-Supporting both single and double quotes lets the user embed one type of quotes into
-a value:
-
-====
-[source]
-----
-shell:>echo "I'm here!"
-You said I'm here!
-shell:>echo 'He said "Hi!"'
-You said He said "Hi!"
-----
-====
-
-That way, the user can use a single quote as an apostrophe in a message.
-
-Should the user need to embed the same kind of quote that was used to quote the whole parameter,
-the escape sequence uses the backslash (`\`) character:
-
-====
-[source]
-----
-shell:>echo 'I\'m here!'
-You said I'm here!
-shell:>echo "He said \"Hi!\""
-You said He said "Hi!"
-shell:>echo I\'m here!
-You said I'm here!
-----
-====
-
-It is also possible to escape space characters when not using enclosing quotes:
-
-====
-[source]
-----
-shell:>echo This\ is\ a\ single\ value
-You said This is a single value
-----
-====
-
-[[interacting-with-the-shell]]
-==== Interacting with the Shell
-
-The Spring Shell project builds on top of the https://github.com/jline/jline3[JLine] library and, as a result, brings
-a lot of nice interactive features, some of which are detailed in this section.
-
-First and foremost, Spring Shell supports tab completion almost everywhere possible. So, if there
-is an `echo` command and the user types `ec` and presses `TAB`, `echo` appears.
-Should there be several commands that start with `ec`, then the user is prompted to choose (using `TAB` or
-`Shift + TAB` to navigate and `ENTER` to select.)
-
-But completion does not stop at command keys. It also works for parameter keys (`--arg`) and even
-parameter values, if the application developer registered the appropriate beans (see <>).
-
-Another nice feature of Spring Shell applications is support for line continuation. If a command and its parameters
-is too long and does not fit nicely on the screen, a user can chunk it by ending a line with a backslash (`\`) character,
-pressing `ENTER`, and continuing on the next line. Upon submission of the whole command, this is
-parsed as if the user entered a single space on line breaks. The following listing shows an example of this behavior:
-
-====
-[source]
-----
-shell:>register module --type source --name foo \ <1>
-> --uri file:///tmp/bar
-Successfully registered module 'source:foo'
-----
-<1> command continues on next line
-====
-
-Line continuation also automatically triggers if the user has opened a quote (see <>)
-and presses `ENTER` while still in the quotes:
-
-====
-[source]
-----
-shell:>echo "Hello <1>
-dquote> World"
-You said Hello World
-----
-<1> The user pressed `ENTER` here.
-====
-
-Finally, Spring Shell applications benefit from a lot of keyboard shortcuts (borrowed from Emacs) with which you may already be familiar from
-working with your regular OS Shell. Notable shortcuts include `Ctrl+r` to perform
-a reverse search, `Ctrl+a`] and `Ctrl+e` to move to the beginning and the end of the current line (respectively), and `Esc f` and
-`Esc b` to move forward or backward (respectively) one word at a time.
-
-[[providing-tab-completion]]
-// ===== Providing TAB Completion Proposals
-
-// TBD
-
-[[validating-command-arguments]]
-=== Validating Command Arguments
-
-Spring Shell integrates with the https://beanvalidation.org/[Bean Validation API] to support
-automatic and self-documenting constraints on command parameters.
-
-Annotations found on command parameters as well as annotations at the method level are
-honored and trigger validation prior to the command executing. Consider the following command:
-
-====
-[source, java]
-----
- @ShellMethod("Change password.")
- public String changePassword(@Size(min = 8, max = 40) String password) {
- return "Password successfully set to " + password;
- }
-----
-====
-
-From the preceding example, you get the following behavior for free:
-
-====
-----
-shell:>change-password hello
-The following constraints were not met:
- --password string : size must be between 8 and 40 (You passed 'hello')
-----
-====
-
-.Applies to All Command Implementations
-NOTE: It is important to note that bean validation applies to all command implementations, whether
-they use the "standard" API or any other API, through the use of an adapter (see <>)
-
-[[dynamic-command-availability]]
-=== Dynamic Command Availability
-
-Registered commands do not always make sense, due to the internal state of the application.
-For example, there may be a `download` command, but it only works once the user has used `connect` on a remote
-server. Now, if the user tries to use the `download` command, the shell should gracefully explain that
-the command exist but that it is not available at the time.
-Spring Shell lets you do that, even letting you provide a short explanation of the reason for
-the command not being available.
-
-There are three possible ways for a command to indicate availability.
-They all leverage a no-arg method that returns an instance of `Availability`.
-Consider the following example:
-
-====
-[source, java]
-----
-@ShellComponent
-public class MyCommands {
-
- private boolean connected;
-
- @ShellMethod("Connect to the server.")
- public void connect(String user, String password) {
- [...]
- connected = true;
- }
-
- @ShellMethod("Download the nuclear codes.")
- public void download() {
- [...]
- }
-
- public Availability downloadAvailability() {
- return connected
- ? Availability.available()
- : Availability.unavailable("you are not connected");
- }
-}
-----
-====
-
-The `connect` method is used to connect to the server (details omitted), altering the state
-of the command through the `connected` boolean when done.
-The `download` command as marked as unavailable until the user has connected, thanks to the presence
-of a method named exactly as the `download` command method with the `Availability` suffix in its name.
-The method returns an instance of `Availability`, constructed with one of the two factory methods.
-If the command is not available, an explanation has to be provided.
-Now, if the user tries to invoke the command while not being connected, here is what happens:
-
-====
-[source]
-----
-shell:>download
-Command 'download' exists but is not currently available because you are not connected.
-Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.
-----
-====
-
-Information about currently unavailable commands is also used in the integrated help. See <>.
-
-[TIP]
-====
-The reason provided when the command is not available should read nicely if appended after "`Because`".
-
-You should not start the sentence with a capital or add a final period
-====
-
-If naming the availability method after the name of the command method does not suit you, you
-can provide an explicit name by using the `@ShellMethodAvailability` annotation:
-
-====
-[source, java]
-----
- @ShellMethod("Download the nuclear codes.")
- @ShellMethodAvailability("availabilityCheck") // <1>
- public void download() {
- [...]
- }
-
- public Availability availabilityCheck() { // <1>
- return connected
- ? Availability.available()
- : Availability.unavailable("you are not connected");
- }
-----
-<1> the names have to match
-====
-
-Lastly, it is often the case that several commands in the same class share the same internal state and, thus,
-should all be available or unavailable as a group. Instead of having to stick the `@ShellMethodAvailability`
-on all command methods, Spring Shell lets you flip things around and put the `@ShellMethodAvailabilty`
-annotation on the availability method, specifying the names of the commands that it controls:
-
-====
-[source, java]
-----
- @ShellMethod("Download the nuclear codes.")
- public void download() {
- [...]
- }
-
- @ShellMethod("Disconnect from the server.")
- public void disconnect() {
- [...]
- }
-
- @ShellMethodAvailability({"download", "disconnect"})
- public Availability availabilityCheck() {
- return connected
- ? Availability.available()
- : Availability.unavailable("you are not connected");
- }
-----
-====
-
-[TIP]
-=====
-The default value for the `@ShellMethodAvailability.value()` attribute is `*`. This special
-wildcard matches all command names. This makes it easy to turn all commands of a single class on or off
-with a single availability method:
-
-====
-[source,java]
-----
-@ShellComponent
-public class Toggles {
- @ShellMethodAvailability
- public Availability availabilityOnWeekdays() {
- return Calendar.getInstance().get(DAY_OF_WEEK) == SUNDAY
- ? Availability.available()
- : Availability.unavailable("today is not Sunday");
- }
-
- @ShellMethod
- public void foo() {}
-
- @ShellMethod
- public void bar() {}
-}
-----
-====
-=====
-
-TIP: Spring Shell does not impose many constraints on how to write commands and how to organize classes.
-However, it is often good practice to put related commands in the same class, and the availability indicators
-can benefit from that.
-
-[[organizing-commands]]
-=== Organizing Commands
-
-When your shell starts to provide a lot of functionality, you may end up
-with a lot of commands, which could be confusing for your users. By typing `help`,
-they would see a daunting list of commands, organized in alphabetical order,
-which may not always make sense.
-
-To alleviate this possible confusion, Spring Shell provides the ability to group commands together,
-with reasonable defaults. Related commands would then end up in the same group (for example, `User Management Commands`)
-and be displayed together in the help screen and other places.
-
-By default, commands are grouped according to the class they are implemented in,
-turning the camel case class name into separate words (so `URLRelatedCommands` becomes `URL Related Commands`).
-This is a very sensible default, as related commands are often already in the class anyway,
-because they need to use the same collaborating objects.
-
-If, however, this behavior does not suit you, you can override the group for a
-command in the following ways, in order of priority:
-
-. Specifying a `group()` in the `@ShellMethod` annotation.
-. Placing a `@ShellCommandGroup` on the class in which the command is defined. This applies
-the group for all commands defined in that class (unless overridden, as explained earlier).
-. Placing a `@ShellCommandGroup` on the package (through `package-info.java`)
-in which the command is defined. This applies to all the commands defined in the
-package (unless overridden at the method or class level, as explained earlier)
-
-The following listing shows an example:
-
-====
-[source,java]
-----
-public class UserCommands {
- @ShellMethod(value = "This command ends up in the 'User Commands' group")
- public void foo() {}
-
- @ShellMethod(value = "This command ends up in the 'Other Commands' group",
- group = "Other Commands")
- public void bar() {}
-}
-
-...
-
-@ShellCommandGroup("Other Commands")
-public class SomeCommands {
- @ShellMethod(value = "This one is in 'Other Commands'")
- public void wizz() {}
-
- @ShellMethod(value = "And this one is 'Yet Another Group'",
- group = "Yet Another Group")
- public void last() {}
-}
-----
-====
-
-[[built-in-commands]]
-=== Built-In Commands
-
-Any application built by using the `{starter-artifactId}` artifact
-(or, to be more precise, the `spring-shell-standard-commands` dependency) comes with a set of built-in commands.
-You can override or disable these commands individually (see <>).
-However, if they are not overridden or disabled, this section describes their behavior.
-
-[[help-command]]
-==== Help
-
-Running a shell application often implies that the user is in a graphically limited
-environment. Also, while we are nearly always connected in the era of mobile phones,
-accessing a web browser or any other rich UI application (such as a PDF viewer) may not always
-be possible. This is why it is important that the shell commands are correctly self documented, and this is where the `help`
-command comes in.
-
-Typing `help` + `ENTER` lists all the commands known to the shell (including <> commands)
-and a short description of what they do, similar to the following:
-
-====
-[source]
-----
-shell:>help
-AVAILABLE COMMANDS
- add: Add numbers together.
- * authenticate: Authenticate with the system.
- * blow-up: Blow Everything up.
- clear: Clear the shell screen.
- connect: Connect to the system
- disconnect: Disconnect from the system.
- exit, quit: Exit the shell.
- help: Display help about available commands.
- register module: Register a new module.
- script: Read and execute commands from a file.
- stacktrace: Display the full stacktrace of the last error.
-
-Commands marked with (*) are currently unavailable.
-Type `help ` to learn more.
-----
-====
-
-Typing `help ` shows more detailed information about a command, including the available parameters, their
-type, whether they are mandatory or not, and other details.
-
-The follwoing listing shows the `help` command applied to itself:
-
-====
-----
-shell:>help help
-
-
-NAME
- help - Display help about available commands.
-
-SYNOPSYS
- help [[-C] string]
-
-OPTIONS
- -C or --command string
- The command to obtain help for. [Optional, default = ]
-----
-====
-
-==== Clear
-The `clear` command does what you would expect and clears the screen, resetting the prompt
-in the top left corner.
-
-==== Exit
-
-The `quit` command (also aliased as `exit`) requests the shell to quit, gracefully
-closing the Spring application context. If not overridden, a JLine `History` bean writes a history of all
-commands to disk, so that they are available again (see <>) on the next launch.
-
-==== Stacktrace
-
-When an exception occurs inside command code, it is caught by the shell and a simple, one-line message is displayed
-so as not to overflow the user with too much information.
-There are cases though when understanding what exactly happened is important (especially if the exception has a nested cause).
-
-To this end, Spring Shell remembers the last exception that occurred, and the user can later use the `stacktrace`
-command to print all the details on the console.
-
-[[script-command]]
-==== Script
-
-The `script` command accepts a local file as an argument and replays commands found there, one at a time.
-
-Reading from the file behaves exactly like inside the interactive shell, so lines starting with `//` are considered
-to be comments and are ignored, while lines ending with `\` trigger line continuation.
-
-==== History
-
-The `history` command shows history of a commands which has been executed.
-
-==== Completion
-
-The `completion` command set allows you to create _scripts_ files which can be used
-with am OS shell implementations to provide completion. This is very usefull when
-working with non-interactive mode.
-
-Currently only implementation is for _bash_ which works with `bash` sub-command.
-
-==== Version
-
-The `version` command shows existing _build_ and _git_ info by integrating into
-Boot's `BuildProperties` and `GitProperties` if those exists in a shell app.
-On default only version info is shown and other can be enabled via configuration
-options.
-
-Settings are under `spring.shell.command.version` where you can use `enabled` to
-disable command and optionally define your own template with `template`. Options
-`show-build-artifact`, `show-build-group`, `show-build-name`, `show-build-time`,
-`show-build-version`, `show-git-branch`, `show-git-commit-id`,
-`show-git-short-commit-id` and `show-git-commit-time` can be used to control
-fields in a default template.
-
-Template default to `classpath:template/version-default.st` and you can define
-your own, for example having:
-
-====
-[source]
-----
-
-----
-====
-
-Which would simply output something like:
-
-====
-[source]
-----
-X.X.X
-----
-====
-
-Attributes added to default template rendering are `buildVersion`, `buildGroup`,
-`buildGroup`, `buildName`, `buildTime`, `gitShortCommitId`, `gitCommitId`,
-`gitBranch` and `gitCommitTime`.
-
-=== Interaction Mode
-
-Starting from _2.1.x_ a build-in support has been added to distinguish between interactive
-and non-interactive modes. This has been added so that it's easier to use shell as a
-simple command-line tool without requiring customisation to accomplish that.
-
-Currently interactive mode is entered if any command line options are passed when starting
-or running a shell from a command-line. This especially works well when shell application
-is compiled with <>.
-
-Some commands may not have any usefull meaning if running on interactive mode
-or vice versa on non-interactive mode. For example a build-in `exit` command
-have no meaning in non-interactive mode as it's used to exit interactive mode.
-
-Annotation `@ShellMethod` has a field `interactionMode` which can be used to instruct
-shell when particular command is available.
-
-[[native]]
-=== Native Support
-
-Re-work with _2.1.x_ brings in an experimental support for compiling shell application
-into _native_ application with _GraalVM_ and _spring-native_. As underlying _jline_
-library works with _GraalVM_ most of a things should just work.
-
-Project can be compiled with native profile to get sample compiled as an native
-application:
-
-====
-----
-$ ./mvnw clean package -Pnative
-----
-====
-
-You can then run sample either with interactive or non-interactive mode:
-
-====
-----
-$ ./spring-shell-samples/target/spring-shell-samples help
-AVAILABLE COMMANDS
-
-Built-In Commands
- completion bash: Generate bash completion script
- help: Display help about available commands.
- history: Display or save the history of previously run commands
- script: Read and execute commands from a file.
-...
-----
-====
-
-[[styling]]
-=== Styling
-
-Starting with _2.1.x_ there is a support for centrally handling styling and theming.
-There is a default theme named _default_ which can be changed using property
-`spring.shell.theme.name`.
-
-To create a new theme register new `Theme` bean with custom `ThemeSettings` where
-you can tweak styles.
-
-====
-[source, java]
-----
-@Configuration
-static class CustomThemeConfig {
-
- @Bean
- public Theme myTheme() {
- return new Theme() {
- @Override
- public String getName() {
- return "mytheme";
- }
- @Override
- public ThemeSettings getSettings() {
- return new MyThemeSettings();
- }
- };
- }
-}
-
-static class MyThemeSettings extends ThemeSettings {
-}
-----
-====
-
-`ThemeResolver` can be used to resolve styles if you want to create
-_jline_ styled strings programmatically.
-
-====
-[source, java]
-----
-@Autowired
-private ThemeResolver themeResolver;
-
-String resolvedStyle = themeResolver.resolveTag(TAG_TITLE);
-AttributedStyle style = themeResolver.resolveStyle(resolvedStyle);
-----
-====
-
-[[uicomponents]]
-=== UI Components
-
-Starting from _2.1.x_ there is a new component model which provides
-easier way to create higher level user interaction for usual use cases
-like asking input in a various forms. These usually are just plain text
-input or choosing something from a list.
-
-Templates for build-in components are in classpath under
-_org/springframework/shell/component_.
-
-Build-in components generally follow logic:
-
-* Enter run loop for user input
-* Generate component related context
-* Render runtime status of a component state
-* Exit
-* Render final status of a component state
-
-==== Component Render
-
-There are two ways to implement component rendering, firstly fully
-programmatically or secondly using a _ANTLR Stringtemplate_. Though
-strictly speaking there is just a simple `Function` renderer interface
-which takes `Context` as an input and outputs a list of `AttributedString`
-but this allows to choose between _templating_ and _code_.
-
-Templating is a good choice if you don't need to anything complex or
-you just want to slightly modify existing component layouts. Rendering
-via code then gives you flexibility to do whatever you need.
-
-Programmatic way to render is simple as to create a `Function`:
-
-====
-[source, java]
-----
-class StringInputCustomRenderer implements Function> {
- @Override
- public List apply(StringInputContext context) {
- AttributedStringBuilder builder = new AttributedStringBuilder();
- builder.append(context.getName());
- builder.append(" ");
- if (context.getResultValue() != null) {
- builder.append(context.getResultValue());
- }
- else {
- String input = context.getInput();
- if (StringUtils.hasText(input)) {
- builder.append(input);
- }
- else {
- builder.append("[Default " + context.getDefaultValue() + "]");
- }
- }
- return Arrays.asList(builder.toAttributedString());
- }
-}
-----
-====
-
-And then hook it with a component:
-
-====
-[source, java]
-----
-@ShellMethod(key = "component stringcustom", value = "String input", group = "Components")
-public String stringInputCustom(boolean mask) {
- StringInput component = new StringInput(getTerminal(), "Enter value", "myvalue",
- new StringInputCustomRenderer());
- component.setResourceLoader(getResourceLoader());
- component.setTemplateExecutor(getTemplateExecutor());
- if (mask) {
- component.setMaskCharater('*');
- }
- StringInputContext context = component.run(StringInputContext.empty());
- return "Got value " + context.getResultValue();
-}
-----
-====
-
-Component have their own context but usually shares some functionality
-from a parent component types, those context variables are shown below.
-
-[[textcomponentcontext-template-variables]]
-.TextComponentContext Template Variables
-|===
-|Key |Description
-
-|resultValue
-|Value after component renders its result.
-
-|name
-|Name of a component, aka its title.
-
-|message
-|Possible message set for component.
-
-|messageLevel
-|Level of a message, either INFO, WARN or ERROR
-
-|hasMessageLevelInfo
-|Return true if level is INFO, false otherwise.
-
-|hasMessageLevelWarn
-|Return true if level is WARN, false otherwise.
-
-|hasMessageLevelError
-|Return true if level is ERROR, false otherwise.
-
-|input
-|Raw user input.
-
-|===
-
-
-[[selectorcomponentcontext-template-variables]]
-.SelectorComponentContext Template Variables
-|===
-|Key |Description
-
-|name
-|Name of a component, aka title.
-
-|input
-|Raw user input, mostly for filter.
-
-|itemStates
-|Full list of item states.
-
-|itemStateView
-|Visible list of item states.
-
-|isResult
-|Return if context is in a result mode.
-
-|cursorRow
-|Current cursor row in a selector
-
-|===
-
-
-==== Build-in Components
-
-===== String Input
-
-Used to ask a simple text input from a user, optionally masking values
-if content contains something sensitive.
-
-====
-[source, java]
-----
-@ShellComponent
-public class ComponentCommands extends AbstractShellComponent {
-
- @ShellMethod(key = "component string", value = "String input", group = "Components")
- public String stringInput(boolean mask) {
- StringInput component = new StringInput(getTerminal(), "Enter value", "myvalue");
- component.setResourceLoader(getResourceLoader());
- component.setTemplateExecutor(getTemplateExecutor());
- if (mask) {
- component.setMaskCharater('*');
- }
- StringInputContext context = component.run(StringInputContext.empty());
- return "Got value " + context.getResultValue();
- }
-}
-----
-====
-
-image::images/component-text-input-1.svg[text input]
-
-Context object is `StringInputContext`.
-
-[[stringinputcontext-template-variables]]
-.StringInputContext Template Variables
-|===
-|Key |Description
-
-|defaultValue
-|Default value if set, null otherwise.
-
-|maskedInput
-|Masked input value
-
-|maskedResultValue
-|Masked result value
-
-|maskCharacter
-|Mask character if set, null otherwise.
-
-|hasMaskCharacter
-|Is true if mask character is set, false otherwise.
-
-|model
-|Parent context variables <>
-|===
-
-===== Path Input
-
-Used to ask a `Path` from a user and gives additional info about a path itself.
-
-====
-[source, java]
-----
-@ShellComponent
-public class ComponentCommands extends AbstractShellComponent {
-
- @ShellMethod(key = "component path", value = "Path input", group = "Components")
- public String pathInput() {
- PathInput component = new PathInput(getTerminal(), "Enter value");
- component.setResourceLoader(getResourceLoader());
- component.setTemplateExecutor(getTemplateExecutor());
- PathInputContext context = component.run(PathInputContext.empty());
- return "Got value " + context.getResultValue();
- }
-}
-----
-====
-
-image::images/component-path-input-1.svg[text input]
-
-Context object is `PathInputContext`.
-
-[[pathinputcontext-template-variables]]
-.PathInputContext Template Variables
-|===
-|Key |Description
-
-|model
-|Parent context variables <>
-|===
-
-===== Confirmation
-
-Used to ask a simple confirmation from a user and essentially is
-yes/no question.
-
-====
-[source, java]
-----
-@ShellComponent
-public class ComponentCommands extends AbstractShellComponent {
-
- @ShellMethod(key = "component confirmation", value = "Confirmation input", group = "Components")
- public String confirmationInput(boolean no) {
- ConfirmationInput component = new ConfirmationInput(getTerminal(), "Enter value", !no);
- component.setResourceLoader(getResourceLoader());
- component.setTemplateExecutor(getTemplateExecutor());
- ConfirmationInputContext context = component.run(ConfirmationInputContext.empty());
- return "Got value " + context.getResultValue();
- }
-}
-----
-====
-
-image::images/component-confirmation-1.svg[text input]
-
-Context object is `ConfirmationInputContext`.
-
-[[confirmationinputcontext-template-variables]]
-.ConfirmationInputContext Template Variables
-|===
-|Key |Description
-
-|defaultValue
-|Default value, either true or false.
-
-|model
-|Parent context variables <>
-|===
-
-===== Single Select
-
-Used to ask an item from a list and is essentially similar to simple
-dropbox implementation.
-
-====
-[source, java]
-----
-@ShellComponent
-public class ComponentCommands extends AbstractShellComponent {
-
- @ShellMethod(key = "component single", value = "Single selector", group = "Components")
- public String singleSelector() {
- List> items = new ArrayList<>();
- items.add(SelectorItem.of("key1", "value1"));
- items.add(SelectorItem.of("key2", "value2"));
- SingleItemSelector> component = new SingleItemSelector<>(getTerminal(),
- items, "testSimple", null);
- component.setResourceLoader(getResourceLoader());
- component.setTemplateExecutor(getTemplateExecutor());
- SingleItemSelectorContext> context = component
- .run(SingleItemSelectorContext.empty());
- String result = context.getResultItem().flatMap(si -> Optional.ofNullable(si.getItem())).get();
- return "Got value " + result;
- }
-}
-----
-====
-
-image::images/component-single-select-1.svg[text input]
-
-Context object is `SingleItemSelectorContext`.
-
-[[singleitemselectorcontext-template-variables]]
-.SingleItemSelectorContext Template Variables
-|===
-|Key |Description
-
-|value
-|Returned value when component exists.
-
-|rows
-|Visible items where rows list contains maps of name and selected items.
-
-|model
-|Parent context variables <>
-|===
-
-===== Multi Select
-
-Used to ask an items from a list.
-
-====
-[source, java]
-----
-@ShellComponent
-public class ComponentCommands extends AbstractShellComponent {
-
- @ShellMethod(key = "component multi", value = "Multi selector", group = "Components")
- public String multiSelector() {
- List> items = new ArrayList<>();
- items.add(SelectorItem.of("key1", "value1"));
- items.add(SelectorItem.of("key2", "value2", false));
- items.add(SelectorItem.of("key3", "value3"));
- MultiItemSelector> component = new MultiItemSelector<>(getTerminal(),
- items, "testSimple", null);
- component.setResourceLoader(getResourceLoader());
- component.setTemplateExecutor(getTemplateExecutor());
- MultiItemSelectorContext> context = component
- .run(MultiItemSelectorContext.empty());
- String result = context.getResultItems().stream()
- .map(si -> si.getItem())
- .collect(Collectors.joining(","));
- return "Got value " + result;
- }
-}
-----
-====
-
-image::images/component-multi-select-1.svg[text input]
-
-Context object is `MultiItemSelectorContext`.
-
-[[multiitemselectorcontext-template-variables]]
-.MultiItemSelectorContext Template Variables
-|===
-|Key |Description
-
-|values
-|Returned values when component exists.
-
-|rows
-|Visible items where rows list contains maps of name, selected, onrow and enabled items.
-
-|model
-|Parent context variables <>
-|===
-
-=== Customizing the Shell
-
-[[overriding-or-disabling-built-in-commands]]
-==== Overriding or Disabling Built-In Commands
-
-Spring Shell provides <> to let people achieve everyday tasks that many if not
-all shell applications need. If you are not happy with the way they behave, though, you can disable or override them, as explained in this section.
-
-[TIP]
-.Disabling all Built-in Commands
-=====
-If you do not need built-in commands at all, there is an easy way to "`disable`" them: don't include them.
-Either use a maven exclusion on `spring-shell-standard-commands` or, if you are selectively including Spring Shell dependencies,
-don't include that one in.
-The follwoing example shows how to exclude `spring-shell-standard-commands`:
-
-====
-[source,xml,subs=attributes+]
-----
-
- org.springframework.shell
- {starter-artifactId}
- {project-version}
-
-
- org.springframework.shell
- spring-shell-standard-commands
-
-
-
-----
-====
-=====
-
-[[disabling-specific-commands]]
-===== Disabling Specific Commands
-
-To disable a single built-in command, set the `spring.shell.command..enabled` property to `false` in the application
-`Environment`. One way to do so is to pass extra arguments to the Boot application in your `main()` entry point:
-
-====
-[source, java]
-----
- public static void main(String[] args) throws Exception {
- String[] disabledCommands = {"--spring.shell.command.help.enabled=false"}; // <1>
- String[] fullArgs = StringUtils.concatenateStringArrays(args, disabledCommands);
- SpringApplication.run(MyApp.class, fullArgs);
- }
-----
-<1> This disables the integrated `help` command
-====
-
-===== Overriding Specific Commands
-
-If, instead of disabling a command, you would rather provide your own implementation, then you can either:
-
-* Disable the command as explained <> and have your implementation registered with the same name.
-* Have your implementing class implement the `.Command` interface. As an example, here is how
-to override the `clear` command:
-+
-====
-[source, java]
-----
-public class MyClear implements Clear.Command {
-
- @ShellMethod("Clear the screen, only better.")
- public void clear() {
- // ...
- }
-}
-----
-====
-
-[NOTE]
-.Please Consider Contributing your Changes
-====
-If you feel like your implementation of a standard command could be valuable to the community,
-please open a pull-request at https://github.com/spring-projects/spring-shell.
-
-Alternatively, before making any changes on your own, you can open an issue with the project. Feedback is
-always welcome!
-====
-
-// ==== ResultHandlers
-
-// TBD
-
-==== PromptProvider
-After each command invocation, the shell waits for new input from the user, displaying
-a prompt in yellow:
-
-====
-[source]
-----
-shell:>
-----
-====
-
-It is possible to customize this behavior by registering a bean of type `PromptProvider`.
-Such a bean may use internal state to decide what to display to the user (it may, for example,
-react to https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-functionality-events-annotation[application events])
-and can use JLine's `AttributedCharSequence` to display fancy ANSI text.
-
-The following example shows how to use a `PromptProvider`:
-
-====
-[source, java]
-----
-@Component
-public class CustomPromptProvider implements PromptProvider {
-
- private ConnectionDetails connection;
-
- @Override
- public AttributedString getPrompt() {
- if (connection != null) {
- return new AttributedString(connection.getHost() + ":>",
- AttributedStyle.DEFAULT.foreground(AttributedStyle.YELLOW));
- }
- else {
- return new AttributedString("server-unknown:>",
- AttributedStyle.DEFAULT.foreground(AttributedStyle.RED));
- }
- }
-
- @EventListener
- public void handle(ConnectionUpdatedEvent event) {
- this.connection = event.getConnectionDetails();
- }
-}
-----
-====
-
-==== Customizing Command Line Options Behavior
-
-There can be exactly one shell spesific `ShellApplicationRunner` which simply extends
-Boot's `ApplicationRunner`. Default behariour is to have actual runner logic in
-various `ShellRunner` implementations where candidate will be picked up.
-
-[IMPORTANT]
-====
-This is a breaking change in `2.1.x` as previous shell versions had an confusing
-logic how `ApplicationRunner` instances were used. These changes were made
-to have a better support for interactive and non-interactive modes in a same
-shell application as it's convenient to fully work on command-line and still
-have ability to enter interactive mode.
-====
-
-You can override bean type of `ShellApplicationRunner` if there's a need to
-customise shell running logic.
-----
-====
-
-==== Customizing Arguments Conversion
-
-Conversion from text input to actual method arguments uses the standard Spring
-https://docs.spring.io/spring/docs/4.3.11.RELEASE/spring-framework-reference/htmlsingle/#core-convert[conversion] mechanism.
-Spring Shell installs a new `DefaultConversionService` (with built-in converters enabled)
-and registers to it any bean of type `Converter`, `GenericConverter`, or
-`ConverterFactory` that it finds in the application context.
-
-This means that you can customize conversion to your custom objects
-by installing a `Converter` bean in the context:
-
-====
-[source, java]
-----
-@ShellComponent
-class ConversionCommands {
-
- @ShellMethod("Shows conversion using Spring converter")
- public String conversionExample(DomainObject object) {
- return object.getClass();
- }
-
-}
-
-class DomainObject {
- private final String value;
-
- DomainObject(String value) {
- this.value = value;
- }
-
- public String toString() {
- return value;
- }
-}
-
-@Component
-class CustomDomainConverter implements Converter {
-
- @Override
- public DomainObject convert(String source) {
- return new DomainObject(source);
- }
-}
-
-----
-====
-
-[TIP]
-.Mind your String representation
-=====
-As in the preceding example, you should have
-your `toString()` implementations return the converse of what was used
-to create the object instance. This is because, when a value fails
-validation, Spring Shell prints:
-
-====
-[source]
-----
-The following constraints were not met:
- --arg : (You passed '')
-----
-====
-
-See <> for more information.
-=====
-
-[NOTE]
-====
-If you want to customize the `ConversionService` further, you can:
-
-* Have the default one injected in your code and act upon it in some way.
-* Override it altogether with your own (custom converters need to be registered by hand).
- The `ConversionService` used by Spring Shell needs to be https://docs.spring.io/spring/docs/4.3.12.RELEASE/spring-framework-reference/htmlsingle/#beans-autowired-annotation-qualifiers[qualified] as `"spring-shell"`.
-====
-
-//==== Overriding the JLine Parser
-
-//=== Using Without Spring Boot