Migrate docs to antora

- This is basically copy from main branch minus all
  terminal ui things.
- Relates #971
This commit is contained in:
Janne Valkealahti
2024-01-12 14:02:10 +00:00
parent 09d4bfed51
commit 814ed4958f
108 changed files with 637 additions and 1037 deletions

View File

@@ -0,0 +1,43 @@
# PACKAGES antora@3.2.0-alpha.2 @antora/atlas-extension:1.0.0-alpha.1 @antora/collector-extension@1.0.0-alpha.3 @springio/antora-extensions@1.1.0-alpha.2 @asciidoctor/tabs@1.0.0-alpha.12 @opendevise/antora-release-line-extension@1.0.0-alpha.2
#
# The purpose of this Antora playbook is to build the docs in the current branch.
antora:
extensions:
- '@springio/antora-extensions/partial-build-extension'
- require: '@springio/antora-extensions/latest-version-extension'
- require: '@springio/antora-extensions/inject-collector-cache-config-extension'
- '@antora/collector-extension'
- '@antora/atlas-extension'
- require: '@springio/antora-extensions/root-component-extension'
root_component_name: 'shell'
- require: '@springio/antora-extensions/asciinema-extension'
site:
title: Spring Shell
url: https://docs.spring.io/spring-shell/reference/
content:
sources:
- url: ./..
branches: HEAD
start_path: spring-shell-docs
worktrees: true
asciidoc:
attributes:
page-stackoverflow-url: https://stackoverflow.com/tags/spring-shell
page-pagination: ''
hide-uri-scheme: '@'
tabs-sync-option: '@'
chomp: 'all'
extensions:
- '@asciidoctor/tabs'
- '@springio/asciidoctor-extensions'
sourcemap: true
urls:
latest_version_segment: ''
runtime:
log:
failure_level: warn
format: pretty
ui:
bundle:
url: https://github.com/spring-io/antora-ui-spring/releases/download/latest/ui-bundle.zip
snapshot: true

View File

@@ -0,0 +1,20 @@
name: shell
version: true
title: Spring Shell
nav:
- modules/ROOT/nav.adoc
ext:
collector:
run:
command: gradlew -q "-Dorg.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError" :spring-shell-docs:generateAntoraYml
local: true
scan:
dir: ./build/generated-antora-resources
asciidoc:
attributes:
attribute-missing: 'warn'
# FIXME: the copyright is not removed
# FIXME: The package is not renamed
chomp: 'all'
snippets: example$docs-src/test/java/org/springframework/shell/docs

View File

@@ -1,5 +1,5 @@
{"version": 2, "width": 85, "height": 8, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
[1.590847, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
[1.590847, "o", "java -jar spring-shell-sample-commands.jar"]
[2.774407, "o", "\r\n"]
[4.560309, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
[5.138757, "o", "\u001b[31mc\u001b[0m"]

View File

@@ -1,5 +1,5 @@
{"version": 2, "width": 85, "height": 11, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
[1.590847, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
[1.590847, "o", "java -jar spring-shell-sample-commands.jar"]
[5.030349, "o", "\r\n"]
[7.108752, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
[7.604731, "o", "\u001b[31mf\u001b[0m"]

View File

@@ -1,5 +1,5 @@
{"version": 2, "width": 85, "height": 15, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
[1.590847, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
[1.590847, "o", "java -jar spring-shell-sample-commands.jar"]
[5.968022, "o", "\r\n"]
[8.099727, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
[11.261894, "o", "\u001b[1mflow showcase\u001b[0m"]

View File

@@ -1,5 +1,5 @@
{"version": 2, "width": 85, "height": 9, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
[1.746447, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
[1.746447, "o", "java -jar spring-shell-sample-commands.jar"]
[2.881033, "o", "\r\n"]
[4.603396, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
[5.105471, "o", "\u001b[31mc\u001b[0m"]

View File

@@ -1,5 +1,5 @@
{"version": 2, "width": 85, "height": 6, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
[1.276071, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
[1.276071, "o", "java -jar spring-shell-sample-commands.jar"]
[1.975169, "o", "\r\n"]
[3.730642, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
[4.157171, "o", "\u001b[31mc\u001b[0m"]

View File

@@ -1,5 +1,5 @@
{"version": 2, "width": 85, "height": 10, "timestamp": 1666162443, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
[1.881363, "o", "java -jar spring-shell-samples/build/libs/spring-shell-samples.jar"]
[1.881363, "o", "java -jar spring-shell-sample-commands.jar"]
[2.630692, "o", "\r\n"]
[6.50287, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
[8.347165, "o", "\u001b[1mcomponent path search\u001b[0m"]

View File

@@ -1,5 +1,5 @@
{"version": 2, "width": 85, "height": 8, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
[2.193321, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
[2.193321, "o", "java -jar spring-shell-sample-commands.jar"]
[3.11524, "o", "\r\n"]
[4.904714, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
[5.372714, "o", "\u001b[31mc\u001b[0m"]

View File

@@ -1,5 +1,5 @@
{"version": 2, "width": 85, "height": 6, "timestamp": 1645645867, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
[1.262977, "o", "java -jar spring-shell-samples/target/spring-shell-samples-2.1.0-SNAPSHOT.jar"]
[1.262977, "o", "java -jar spring-shell-sample-commands.jar"]
[2.045105, "o", "\r\n"]
[3.846992, "o", "\u001b[?1h\u001b=\u001b[?2004h\u001b[33mmy-shell:>\u001b[0m"]
[4.717927, "o", "\u001b[31mc\u001b[0m"]

View File

@@ -0,0 +1 @@
../../../src

View File

@@ -0,0 +1,74 @@
* xref:index.adoc[Overview]
* xref:getting-started.adoc[]
* xref:basics/index.adoc[]
** xref:basics/reading.adoc[]
* xref:commands/index.adoc[]
** xref:commands/registration/index.adoc[]
** xref:commands/registration/programmatic.adoc[]
** xref:commands/registration/annotation.adoc[]
** xref:commands/registration/legacyannotation.adoc[]
** xref:commands/organize.adoc[]
** xref:commands/availability.adoc[]
** xref:commands/exceptionhandling/index.adoc[]
*** xref:commands/exceptionhandling/resolving.adoc[]
*** xref:commands/exceptionhandling/mappings.adoc[]
*** xref:commands/exceptionhandling/annotation.adoc[]
** xref:commands/hidden.adoc[]
** xref:commands/helpoptions.adoc[]
** xref:commands/interactionmode.adoc[]
** xref:commands/builtin/index.adoc[]
*** xref:commands/builtin/help.adoc[]
*** xref:commands/builtin/clear.adoc[]
*** xref:commands/builtin/exit.adoc[]
*** xref:commands/builtin/stacktrace.adoc[]
*** xref:commands/builtin/script.adoc[]
*** xref:commands/builtin/history.adoc[]
*** xref:commands/builtin/completion.adoc[]
*** xref:commands/builtin/version.adoc[]
** xref:commands/writing.adoc[]
* xref:options/index.adoc[]
** xref:options/basics/index.adoc[]
*** xref:options/basics/programmatic.adoc[]
*** xref:options/basics/annotation.adoc[]
*** xref:options/basics/legacyannotation.adoc[]
** xref:options/short.adoc[]
** xref:options/arity.adoc[]
** xref:options/positional.adoc[]
** xref:options/optional.adoc[]
** xref:options/default.adoc[]
** xref:options/validation.adoc[]
** xref:options/label.adoc[]
** xref:options/types.adoc[]
** xref:options/naming.adoc[]
* xref:completion.adoc[]
* xref:building.adoc[]
* xref:components/index.adoc[]
** xref:components/flow/index.adoc[]
** xref:components/ui/index.adoc[]
*** xref:components/ui/render.adoc[]
*** xref:components/ui/stringinput.adoc[]
*** xref:components/ui/pathinput.adoc[]
*** xref:components/ui/pathsearch.adoc[]
*** xref:components/ui/confirmation.adoc[]
*** xref:components/ui/singleselect.adoc[]
*** xref:components/ui/multiselect.adoc[]
* xref:customization/index.adoc[]
** xref:customization/styling.adoc[]
** xref:customization/logging.adoc[]
** xref:customization/commandnotfound.adoc[]
** xref:customization/singlecommand.adoc[]
** xref:customization/contextclose.adoc[]
* xref:execution.adoc[]
* xref:testing/index.adoc[]
** xref:testing/basics.adoc[]
** xref:testing/settings.adoc[]
* Appendices
** xref:appendices/techintro/index.adoc[]
*** xref:appendices/techintro/registration.adoc[]
*** xref:appendices/techintro/parser.adoc[]
*** xref:appendices/techintro/execution.adoc[]
*** xref:appendices/techintro/commandcontext.adoc[]
*** xref:appendices/techintro/commandcatalog.adoc[]
*** xref:appendices/techintro/theming.adoc[]
*** xref:appendices/techintro/searchalgorithm.adoc[]
** xref:appendices/debugging/index.adoc[]

View File

@@ -1,5 +1,6 @@
[appendix]
[#appendix-debugging]
== Debugging
= Debugging
:page-section-summary-toc: 1
Please find more info about debugging from https://github.com/spring-projects/spring-shell/wiki/Debugging[project wiki].

View File

@@ -1,43 +1,43 @@
=== Command Catalog
[[command-catalog]]
= Command Catalog
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
The `CommandCatalog` interface defines how command registrations exist in
a shell application. It is possible to dynamically register and de-register
commands, which gives flexibility for use cases where possible commands
come and go, depending on a shell's state. Consider the following example:
====
[source, java, indent=0]
----
include::{snippets}/CommandCatalogSnippets.java[tag=snippet1]
----
====
==== Command Resolver
[[command-resolver]]
== Command Resolver
You can implement the `CommandResolver` interface and define a bean to dynamically
resolve mappings from a command's name to its `CommandRegistration` instances. Consider
the following example:
====
[source, java, indent=0]
----
include::{snippets}/CommandCatalogSnippets.java[tag=snippet2]
----
====
IMPORTANT: A current limitation of a `CommandResolver` is that it is used every time commands are resolved.
Thus, we advise not using it if a command resolution call takes a long time, as it would
make the shell feel sluggish.
==== Command Catalog Customizer
[[command-catalog-customizer]]
== Command Catalog Customizer
You can use the `CommandCatalogCustomizer` interface to customize a `CommandCatalog`.
Its main use is to modify a catalog. Also, within `spring-shell` auto-configuration, this
interface is used to register existing `CommandRegistration` beans into a catalog.
Consider the following example:
====
[source, java, indent=0]
----
include::{snippets}/CommandCatalogSnippets.java[tag=snippet3]
----
====
You can create a `CommandCatalogCustomizer` as a bean, and Spring Shell handles the rest.

View File

@@ -1,20 +1,21 @@
=== Command Context
[[command-context]]
= Command Context
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
The `CommandContext` interface gives access to a currently running
context. You can use it to get access to options:
====
[source, java, indent=0]
----
include::{snippets}/CommandContextSnippets.java[tag=snippet1]
----
====
If you need to print something into a shell, you can get a `Terminal`
and use its writer to print something:
====
[source, java, indent=0]
----
include::{snippets}/CommandContextSnippets.java[tag=snippet2]
----
====

View File

@@ -0,0 +1,8 @@
[[command-execution]]
= Command Execution
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
When command parsing has done its job and command registration has been resolved, command execution
does the hard work of running the code.

View File

@@ -0,0 +1,14 @@
[appendix]
[#appendix-tech-intro]
= Techical Introduction
:page-section-summary-toc: 1
This appendix contains information for developers and others who would like to know more about how Spring Shell
works internally and what its design decisions are.

View File

@@ -1,3 +1,6 @@
=== Command Parser
[[command-parser]]
= Command Parser
:page-section-summary-toc: 1
Before a command can be executed, we need to parse the command and whatever options the user may have provided. Parsing
comes between command registration and command execution.

View File

@@ -1,16 +1,17 @@
[#appendix-tech-intro-registration]
=== Command Registration
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Command Registration
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
Defining a command registration is a first step to introducing the structure of a command and its options
and parameters. This is loosely decoupled from what happens later, such as parsing command-line input and running
actual target code. Essentially, it is the definition of a command API that is shown to a user.
==== Commands
[[commands]]
== Commands
A command in a `spring-shell` structure is defined as an array of commands. This yields a
structure similar to the following example:
====
[source, bash]
----
command1 sub1
@@ -18,12 +19,12 @@ command2 sub1 subsub1
command2 sub2 subsub1
command2 sub2 subsub2
----
====
NOTE: We do not currently support mapping commands to an explicit parent if sub-commands are defined.
For example, `command1 sub1` and `command1 sub1 subsub1` cannot both be registered.
==== Interaction Mode
[[interaction-mode]]
== Interaction Mode
Spring Shell has been designed to work on two modes: interactive (which essentially
is a `REPL` where you have an active shell instance throughout a series of commands) and
non-interactive (where commands are executed one by one from a command line).
@@ -36,70 +37,63 @@ dictates the available information.
Also, being on an active `REPL` session may provide more information about what the user has been
doing within an active session.
==== Options
[[options]]
== Options
Options can be defined as long and short, where the prefixing is `--` and `-`, respectively.
The following examples show long and short options:
====
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationSnippets.java[tag=snippet1]
----
====
====
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationSnippets.java[tag=snippet2]
----
====
==== Target
[[target]]
== Target
The target defines the execution target of a command. It can be a method in a POJO,
a `Consumer`, or a `Function`.
===== Method
[[method]]
=== Method
Using a `Method` in an existing POJO is one way to define a target.
Consider the following class:
====
[source, java, indent=0]
----
include::{snippets}/CommandTargetSnippets.java[tag=snippet11]
----
====
Given the existing class shown in the preceding listing, you can then register its method:
====
[source, java, indent=0]
----
include::{snippets}/CommandTargetSnippets.java[tag=snippet12]
----
====
===== Function
[[function]]
=== Function
Using a `Function` as a target gives a lot of flexibility to handle what
happens in a command execution, because you can handle many things manually by using
a `CommandContext` given to a `Function`. The return type from a `Function` is
then what gets printed into the shell as a result. Consider the following example:
====
[source, java, indent=0]
----
include::{snippets}/CommandTargetSnippets.java[tag=snippet2]
----
====
===== Consumer
[[consumer]]
=== Consumer
Using a `Consumer` is basically the same as using a `Function`, with the difference being
that there is no return type. If you need to print something into a shell,
you can get a reference to a `Terminal` from a context and print something
through it. Consider the following example:
====
[source, java, indent=0]
----
include::{snippets}/CommandTargetSnippets.java[tag=snippet3]
----
====

View File

@@ -1,6 +1,7 @@
[#appendix-tech-intro-searchalgorithm]
=== Search Algorithms
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Search Algorithms
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
`SearchMatch` is an interface to match _text_ with a _pattern_. Match
results are in a returned value `SearchMatchResult`. Match result
@@ -8,7 +9,8 @@ contains info about match positions and overall score of a match.
https://github.com/junegunn/fzf[fzf].
==== Implementations
[[implementations]]
== Implementations
*FuzzyMatchV2Search*
@@ -20,19 +22,18 @@ quickly finding paths.
Port of _fzf ExactMatchNaive_ algorithm. Simple exact match works more accurately
if you know what to search.
==== SearchMatch
[[searchmatch]]
== SearchMatch
Algorithms and default syntax are hidden inside package protected classes
as we don't want to fully open these until we know API's are good to go
for longer support. You need to construct `SearchMatch` via its
build-in builder.
====
[source, java, indent=0]
----
include::{snippets}/SearchAlgorithmsSnippets.java[tag=builder]
----
====
It's possible to configure _case sensitivity_, on what _direction_ search
happens or if text should be _normilized_ before search happens. Normalization
@@ -55,11 +56,10 @@ below table.
|Items that include `stuff`
|===
==== Examples
[[examples]]
== Examples
====
[source, java, indent=0]
----
include::{snippets}/SearchAlgorithmsSnippets.java[tag=simple]
----
====

View File

@@ -1,6 +1,7 @@
[#appendix-tech-intro-theming]
=== Theming
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Theming
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
Styling in a theming is provided by a use of a _AttributedString_ from `JLine`.
Unfortunately styling in `JLine` is mostly undocumented but we try to go through
@@ -22,7 +23,6 @@ applied. Prefixing with `~` will resolve from JLine internal bsd color table.
If rgb format is expected and prefixed with either `x` or `#` a normal
hex format is used.
====
[source, text]
----
fg-red
@@ -31,30 +31,25 @@ fg-rgb:red
fg-rgb:xff3333
fg-rgb:#ff3333
----
====
If spec contains special names `default`, `bold`, `faint`, `italic`, `underline`, `blink`,
`inverse`, `inverse-neg`, `inverseneg`, `conceal`, `crossed-out`, `crossedout` or `hidden`
a style is changed accordingly with an existing color.
====
[source, text]
----
bold
bold,fg:red
----
====
If spec is a number or numbers separated with semicolon, format is a plain part of an ansi
ascii codes.
====
[source, text]
----
31
31;1
----
====
NOTE: JLine special mapping format which would resolve spec starting with dot can't be
used as we don't yet map those into Spring Shell styling names.

View File

@@ -1,5 +1,7 @@
[[using-shell-basics]]
== Basics
= Basics
:page-section-summary-toc: 1
This section covers the basics of Spring Shell. Before going on to define actual commands and options,
we need to go through some of the fundamental concepts of Spring Shell.
@@ -13,4 +15,3 @@ Essentially, a few things needs to happen before you have a working Spring Shell
You can get a full working Spring Shell application without defining any user-level commands
as some basic built-in commands (such as `help` and `history`) are provided.
include::using-shell-basics-reading.adoc[]

View File

@@ -1,11 +1,12 @@
[[using-shell-basics-reading]]
=== Reading Docs
= Reading Docs
:page-section-summary-toc: 1
Throughout this documentation, we make references to configuring something by using
annotations or programmatic examples.
NOTE: There are two annotation models, <<commands-registration-annotation, annotations>>
referred to new annotation model, <<commands-registration-legacyannotation, legacy annotations>>
NOTE: There are two annotation models, xref:commands/registration/annotation.adoc[annotations]
referred to new annotation model, xref:commands/registration/legacyannotation.adoc[legacy annotations]
referred to old legacy annotation model.
Old legacy annotation model mostly relates to use of `@ShellMethod` and `@ShellOption` and
@@ -15,4 +16,4 @@ The programmatic model is how things are actually registered, even if you use an
NOTE: Currently whole documentation structure is in transit to provide better
structure how things can be used using different ways to provide configurations.
So pardon a for little confusion now and there during a transit.
So pardon a for little confusion now and there during a transit.

View File

@@ -1,10 +1,10 @@
[[using-shell-building]]
== Building
= Building
This section covers how to build a Spring Shell application.
[[native]]
=== Native Support
== Native Support
Support for compiling _Spring Shell_ application into a _GraalVM_ binary
mostly comes from _Spring Framework_ and _Spring Boot_ where feature is
@@ -23,7 +23,6 @@ _GraalVM_ installed and `JAVA_HOME` pointing to that.
For _gradle_ add graalvm's native plugin and configure metadata repository.
====
[source, groovy, subs=attributes+]
----
plugins {
@@ -36,7 +35,6 @@ graalvmNative {
}
}
----
====
When gradle build is run with `./gradlew nativeCompile` you should get binary
under `build/native/nativeCompile` directory.
@@ -44,7 +42,6 @@ under `build/native/nativeCompile` directory.
For `maven` use `spring-boot-starter-parent` as parent and you'll get `native`
profile which can be used to do a compilation. You need to configure metadata repository
====
[source, xml, subs=attributes+]
----
<build>
@@ -63,12 +60,11 @@ profile which can be used to do a compilation. You need to configure metadata re
</pluginManagement>
</build>
----
====
NOTE: If you rely on `spring-boot-starter-parent` it manages `native-maven-plugin`
version which is kept up to date.
When maven build is run with `./mvnw package -Pnative` you should get binary
When maven build is run with `./mvnw native:compile -Pnative` you should get binary
under `target` directory.
If everything went well this binary can be run as is instead of executing

View File

@@ -1,5 +1,5 @@
[[dynamic-command-availability]]
=== 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
@@ -12,7 +12,6 @@ There are three possible ways for a command to indicate availability.
They all use a no-arg method that returns an instance of `Availability`.
Consider the following example:
====
[source, java]
----
@ShellComponent
@@ -38,7 +37,6 @@ public class MyCommands {
}
}
----
====
The `connect` method is used to connect to the server (details omitted), altering the state
of the command through the `connected` boolean when done.
@@ -48,16 +46,14 @@ The method returns an instance of `Availability`, constructed with one of the tw
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 <<built-in-commands-help>>.
Information about currently unavailable commands is also used in the integrated help. See xref:commands/builtin/help.adoc[Help].
[TIP]
====
@@ -69,7 +65,6 @@ 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.")
@@ -85,14 +80,12 @@ can provide an explicit name by using the `@ShellMethodAvailability` annotation:
}
----
<1> the names have to match
====
Finally, 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.")
@@ -112,7 +105,6 @@ annotation on the availability method, specifying the names of the commands that
: Availability.unavailable("you are not connected");
}
----
====
[TIP]
=====
@@ -120,7 +112,6 @@ The default value for the `@ShellMethodAvailability.value()` attribute is `*`. T
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
@@ -139,7 +130,6 @@ public class Toggles {
public void bar() {}
}
----
====
=====
TIP: Spring Shell does not impose many constraints on how to write commands and how to organize classes.

View File

@@ -1,4 +1,6 @@
[[built-in-commands-clear]]
==== Clear
= Clear
:page-section-summary-toc: 1
The `clear` command does what you would expect and clears the screen, resetting the prompt
in the top left corner.

View File

@@ -1,5 +1,6 @@
[[built-in-commands-completion]]
==== Completion
= Completion
:page-section-summary-toc: 1
The `completion` command set lets you create script files that can be used
with am OS shell implementations to provide completion. This is very useful when

View File

@@ -1,5 +1,6 @@
[[built-in-commands-exit]]
==== Exit
= Exit
:page-section-summary-toc: 1
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

View File

@@ -1,5 +1,5 @@
[[built-in-commands-help]]
==== Help
= 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,
@@ -7,10 +7,9 @@ accessing a web browser or any other rich UI application (such as a PDF viewer)
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 <<dynamic-command-availability,unavailable>> commands)
Typing `help` + `ENTER` lists all the commands known to the shell (including xref:commands/availability.adoc[unavailable] commands)
and a short description of what they do, similar to the following:
====
[source, bash]
----
my-shell:>help
@@ -27,14 +26,12 @@ Built-In Commands
version: Show version info
script: Read and execute commands from a file.
----
====
Typing `help <command>` shows more detailed information about a command, including the available parameters, their
type, whether they are mandatory or not, and other details.
The following listing shows the `help` command applied to itself:
====
[source, bash]
----
my-shell:>help help
@@ -49,7 +46,6 @@ OPTIONS
The command to obtain help for.
[Optional]
----
====
Help is templated and can be customized if needed. Settings are under `spring.shell.command.help` where you can use
`enabled` to disable command, `grouping-mode` taking `group` or `flat` if you want to hide groups by flattening
@@ -58,7 +54,6 @@ output of a command list.
If `spring.shell.command.help.grouping-mode=flat` is set, then help would show:
====
[source, bash]
----
my-shell:>help help
@@ -74,7 +69,6 @@ completion bash: Generate bash completion script
version: Show version info
script: Read and execute commands from a file.
----
====
Output from `help` and `help <commmand>` are both templated with a default implementation
which can be changed.
@@ -96,10 +90,10 @@ as a model.
|`true` if showing groups is enabled. Otherwise, false.
|`groups`
|The commands variables (see <<groupcommandinfomodel-variables>>).
|The commands variables (see xref:commands/builtin/help.adoc#groupcommandinfomodel-variables[GroupCommandInfoModel Variables]).
|`commands`
|The commands variables (see <<commandinfomodel-variables>>).
|The commands variables (see xref:commands/builtin/help.adoc#commandinfomodel-variables[CommandInfoModel Variables]).
|`hasUnavailableCommands`
|`true` if there is unavailable commands. Otherwise, false.
@@ -114,7 +108,7 @@ as a model.
|The name of a group, if set. Otherwise, empty.
|`commands`
|The commands, if set. Otherwise, empty. Type is a multi value, see <<commandinfomodel-variables>>.
|The commands, if set. Otherwise, empty. Type is a multi value, see xref:commands/builtin/help.adoc#commandinfomodel-variables[CommandInfoModel Variables].
|===
[[commandinfomodel-variables]]
@@ -135,10 +129,10 @@ as a model.
|The description of a command, if set. Otherwise, null.
|`parameters`
|The parameters variables, if set. Otherwise empty. Type is a multi value, see <<commandparameterinfomodel-variables>>.
|The parameters variables, if set. Otherwise empty. Type is a multi value, see xref:commands/builtin/help.adoc#commandparameterinfomodel-variables[CommandParameterInfoModel Variables].
|`availability`
|The availability variables (see <<commandavailabilityinfomodel-variables>>).
|The availability variables (see xref:commands/builtin/help.adoc#commandavailabilityinfomodel-variables[CommandAvailabilityInfoModel Variables]).
|===
[[commandparameterinfomodel-variables]]

View File

@@ -1,5 +1,6 @@
[[built-in-commands-history]]
==== History
= History
:page-section-summary-toc: 1
The `history` command shows the history of commands that has been executed.
@@ -11,6 +12,6 @@ which you can change by setting `spring.shell.history.name`.
By default, a log file is generated to a current working directory, which you can dictate
by setting `spring.shell.config.location`. This property can contain
a placeholder (`{userconfig}`), which resolves to a common shared config directory.
a placeholder (`+{userconfig}+`), which resolves to a common shared config directory.
TIP: Run the Spring Shell application to see how the sample application works as it uses these options.

View File

@@ -0,0 +1,11 @@
[[built-in-commands]]
= Built-In Commands
:page-section-summary-toc: 1

View File

@@ -1,5 +1,6 @@
[[built-in-commands-script]]
==== Script
= Script
:page-section-summary-toc: 1
The `script` command accepts a local file as an argument and replays commands found there, one at a time.

View File

@@ -1,5 +1,6 @@
[[built-in-commands-stacktrace]]
==== Stacktrace
= Stacktrace
:page-section-summary-toc: 1
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.

View File

@@ -1,5 +1,5 @@
[[built-in-commands-version]]
==== Version
= Version
The `version` command shows existing build and git info by integrating into
Boot's `BuildProperties` and `GitProperties` if those exist in the shell application.
@@ -16,21 +16,17 @@ fields in a default template.
The template defaults to `classpath:template/version-default.st`, and you can define
your own, as the following example shows:
====
[source]
----
<buildVersion>
----
====
This setting would output something like the following:
====
[source]
----
X.X.X
----
====
You can add the following attributes to the default template rendering: `buildVersion`, `buildGroup`,
`buildGroup`, `buildName`, `buildTime`, `gitShortCommitId`, `gitCommitId`,

View File

@@ -1,5 +1,6 @@
[[dynamic-command-exitcode-annotation]]
==== @ExceptionResolver
= @ExceptionResolver
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
`@ShellComponent` classes can have `@ExceptionResolver` methods to handle exceptions from component
@@ -17,42 +18,35 @@ is used to sort exceptions based on their depth from the thrown exception type.
Alternatively, the annotation declaration may narrow the exception types to match, as the
following example shows:
====
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-type-in-annotation]
----
====
====
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-type-in-method]
----
====
`@ExceptionResolver` can also return `String` which is used as an output to console. You can
use `@ExitCode` annotation to define return code.
====
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-exitcode-annotation]
----
====
`@ExceptionResolver` with `void` return type is automatically handled as handled exception.
You can then also define `@ExitCode` and use `Terminal` if you need to write something
into console.
====
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-void]
----
====
===== Method Arguments
[[method-arguments]]
== Method Arguments
`@ExceptionResolver` methods support the following arguments:
[Attributes]
@@ -67,7 +61,8 @@ include::{snippets}/ErrorHandlingSnippets.java[tag=exception-resolver-with-void]
|===
===== Return Values
[[return-values]]
== Return Values
`@ExceptionResolver` methods support the following return values:
[Attributes]

View File

@@ -1,5 +1,7 @@
[[dynamic-command-exitcode]]
=== Exception Handling
= Exception Handling
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
Exceptions happen from a user code wether it is intentional or not. This section describes
@@ -12,8 +14,5 @@ this mostly relates when a command is run on a non-interactive mode meaning one
is always executed once with an instance of a `spring-shell`. Take a note that _exit code_
always relates to non-interactive shell.
include::using-shell-commands-exceptionhandling-resolving.adoc[]
include::using-shell-commands-exceptionhandling-mappings.adoc[]
include::using-shell-commands-exceptionhandling-annotation.adoc[]

View File

@@ -1,5 +1,6 @@
[[dynamic-command-exitcode-mappings]]
==== Exit Code Mappings
= Exit Code Mappings
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
Default behaviour of an exit codes is as:
@@ -14,21 +15,17 @@ integrate into that.
Assuming there is an exception show below which would be thrown from a command:
====
[source, java, indent=0]
----
include::{snippets}/ExitCodeSnippets.java[tag=my-exception-class]
----
====
It is possible to define a mapping function between `Throwable` and exit code. You can also
just configure a _class_ to _exit code_ which is just a syntactic sugar within configurations.
====
[source, java, indent=0]
----
include::{snippets}/ExitCodeSnippets.java[tag=example1]
----
====
NOTE: Exit codes cannot be customized with annotation based configuration

View File

@@ -1,5 +1,6 @@
[[dynamic-command-exitcode-resolving]]
==== Exception Resolving
= Exception Resolving
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
Unhandled exceptions will bubble up into shell's `ResultHandlerService` and then eventually
@@ -8,30 +9,24 @@ can be used to resolve exceptions and gives you flexibility to return message to
into console together with exit code which are wrapped within `CommandHandlingResult`.
`CommandHandlingResult` may contain a _message_ and/or _exit code_.
====
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=my-exception-resolver-class]
----
====
`CommandExceptionResolver` implementations can be defined globally as bean.
====
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=my-exception-resolver-class-as-bean]
----
====
or defined per `CommandRegistration` if it's applicable only for a particular command itself.
====
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=example1]
----
====
NOTE: Resolvers defined with a command are handled before global resolvers.
@@ -39,12 +34,10 @@ NOTE: Resolvers defined with a command are handled before global resolvers.
Use you own exception types which can also be an instance of boot's `ExitCodeGenerator` if
you want to define exit code there.
====
[source, java, indent=0]
----
include::{snippets}/ErrorHandlingSnippets.java[tag=my-exception-class]
----
====
Some build in `CommandExceptionResolver` beans are registered to handle common
exceptions thrown from command parsing. These are registered with _order_

View File

@@ -1,5 +1,6 @@
[[commands-helpoptions]]
=== Help Options
= Help Options
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
_Spring Shell_ has a build-in `help` command but not all favour getting command help
@@ -14,16 +15,13 @@ what other command-line options is typed.
Below example shows its default settings.
====
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationHelpOptionsSnippets.java[tag=defaults]
----
====
It is possible to change default behaviour via configuration options.
====
[source, yaml]
----
spring:
@@ -34,7 +32,6 @@ spring:
short-names: h
command: help
----
====
NOTE: Commands defined programmationally or via annotations will automatically add
help options. With annotation model you can only turn things off globally, programmatic

View File

@@ -1,5 +1,6 @@
[[commands-hidden]]
=== Hidden Command
= Hidden Command
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
It is possible to _hide_ a command which is convenient in cases where it is not yet ready for
@@ -17,11 +18,9 @@ from:
Below is an example how to define command as _hidden_. It shows available builder methods
to define _hidden_ state.
====
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationHiddenSnippets.java[tag=snippet1]
----
====
NOTE: Defining hidden commands is not supported with annotation based configuration

View File

@@ -0,0 +1,18 @@
[[commands]]
= Commands
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
In this section, we go through an actual command registration and leave command options
and execution for later in a documentation. You can find more detailed info in
xref:appendices/techintro/registration.adoc[Command Registration].

View File

@@ -1,24 +1,22 @@
[[commands-interactionmode]]
=== Interaction Mode
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Interaction Mode
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
Command registration can define `InteractionMode` which is used to hide commands
depending which mode shell is executing. More about that in <<using-shell-execution-interactionmode>>.
depending which mode shell is executing. More about that in xref:execution.adoc#using-shell-execution-interactionmode[Interaction Mode].
You can define it with `CommandRegisration`.
====
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationInteractionModeSnippets.java[tag=snippet1]
----
====
Or with `@ShellMethod`.
====
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationInteractionModeSnippets.java[tag=snippet2]
----
====

View File

@@ -1,5 +1,5 @@
[[organizing-commands]]
=== 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`,
@@ -27,7 +27,6 @@ package (unless overridden at the method or class level, as explained earlier).
The following listing shows an example:
====
[source,java]
----
public class UserCommands {
@@ -51,4 +50,3 @@ public class SomeCommands {
public void last() {}
}
----
====

View File

@@ -1,27 +1,24 @@
[[commands-registration-annotation]]
==== Annotation
= Annotation
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
`@Command` annotation when used on a method marks it as a candidate for command registration.
In below example a command `example` is defined.
====
[source, java, indent=0]
----
include::{snippets}/CommandAnnotationSnippets.java[tag=command-anno-in-method]
----
====
`@Command` annotation can be placed on a class which either defines defaults or shared settings
for `@Command` methods defined in a same class. In below example a command `parent example` is
defined.
====
[source, java, indent=0]
----
include::{snippets}/CommandAnnotationSnippets.java[tag=command-anno-in-class]
----
====
Using a `@Command` will not automatically register command targets, instead it is required to use
`@EnableCommand` and/or `@CommandScan` annotations. This model is familiar from other parts
@@ -31,12 +28,10 @@ for command targets.
You can define target classes using `@EnableCommand`. It will get picked from all _Configuration_
classes.
====
[source, java, indent=0]
----
include::{snippets}/CommandAnnotationSnippets.java[tag=enablecommand-with-class]
----
====
You can define target classes using `@CommandScan`. It will get picked from all _Configuration_
classes.
@@ -44,9 +39,7 @@ classes.
TIP: Define `@CommandScan` in Spring Boot `App` class on a top level and it will automatically
scan all command targets from all packages and classes under `App`.
====
[source, java, indent=0]
----
include::{snippets}/CommandAnnotationSnippets.java[tag=commandscan-no-args]
----
====

View File

@@ -1,4 +1,7 @@
=== Registration
[[registration]]
= Registration
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
There are two different ways to define a command: through an annotation model and
@@ -8,14 +11,11 @@ In the programmatic model, you use a more low level approach, defining command
registrations (either as beans or by dynamically registering with a command catalog).
Starting from _3.1.x_ a better support for defining commands using
<<commands-registration-annotation, annotations>> were added. Firstly because eventually standard
package providing <<commands-registration-legacyannotation, legacy annotations>> will get deprecated
xref:commands/registration/annotation.adoc[annotations] were added. Firstly because eventually standard
package providing xref:commands/registration/legacyannotation.adoc[legacy annotations] will get deprecated
and removed. Secondly so that we're able to provide same set of features than using underlying
`CommandRegistration`. Creating new a annotation model allows us to rethink and modernise that
part without breaking existing applications.
include::using-shell-commands-registration-programmatic.adoc[]
include::using-shell-commands-registration-annotation.adoc[]
include::using-shell-commands-registration-legacyannotation.adoc[]

View File

@@ -1,5 +1,6 @@
[[commands-registration-legacyannotation]]
==== Legacy Annotation
= Legacy Annotation
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
When you use the standard API, methods on beans are turned into executable commands, provided that:
@@ -16,16 +17,14 @@ you can use it in addition to the filtering mechanism to declare beans (for exam
You can customize the name of the created bean by using the `value` attribute of the annotation.
====
====
[source, java, indent=0]
----
include::{snippets}/AnnotationRegistrationSnippets.java[tag=snippet1]
----
====
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 <<built-in-commands-help>>).
get consistent help about your commands without having to leave the shell (see xref:commands/builtin/help.adoc[Help]).
NOTE: The description of your command should be short -- no more than one or two sentences. For better
consistency, it should start with a capital letter and end with a period.
@@ -36,12 +35,10 @@ dashed, gnu-style, names (for example, `sayHello()` becomes `say-hello`).
You can, however, explicitly set the command key, by using the `key` attribute of the annotation:
====
[source, java, indent=0]
----
include::{snippets}/AnnotationRegistrationSnippets.java[tag=snippet2]
----
====
NOTE: The `key` attribute accepts multiple values.
If you set multiple keys for a single method, the command is registered with those different aliases.

View File

@@ -1,16 +1,15 @@
[[commands-registration-programmatic]]
==== Programmatic
= Programmatic
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
In the programmatic model, `CommandRegistration` can be defined as a `@Bean`
and it will be automatically registered.
====
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationBeanSnippets.java[tag=plain]
----
====
If all your commands have something in common, an instance of
a _CommandRegistration.BuilderSupplier_ is created which can
@@ -18,24 +17,20 @@ be autowired. Default implementation of this supplier returns
a new builder so you don't need to worry about its internal state.
IMPORTANT: Commands registered programmatically automatically
add _help options_ mentioned in <<commands-helpoptions>>.
add _help options_ mentioned in xref:commands/helpoptions.adoc[Help Options].
If bean of this supplier type is defined then auto-configuration
will back off giving you an option to redefine default functionality.
====
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationBeanSnippets.java[tag=fromsupplier]
----
====
`CommandRegistrationCustomizer` beans can be defined if you want to centrally
modify builder instance given you by supplier mentioned above.
====
[source, java, indent=0]
----
include::{snippets}/CommandRegistrationBeanSnippets.java[tag=customizer]
----
====

View File

@@ -1,4 +1,6 @@
=== Writing
[[writing]]
= Writing
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
When something needs to get written into your console you can always
@@ -10,18 +12,14 @@ If using target endpoints, i.e. _consumer_ which is not expected
to return anything given `CommandContext` contains reference to
`Terminal` and writer can be accessed from there.
====
[source, java, indent=0]
----
include::{snippets}/WritingSnippets.java[tag=reg-terminal-writer]
----
====
It's possible to autowire `Terminal` to get access to its writer.
====
[source, java, indent=0]
----
include::{snippets}/WritingSnippets.java[tag=anno-terminal-writer]
----
====

View File

@@ -1,4 +1,6 @@
== Completion
[[completion]]
= Completion
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
Spring Shell can provide completion proposals for both interactive shell
@@ -8,7 +10,8 @@ easier to provide more programmatic ways to provide completion hints.
When shell is purely run as a command-line tool a completion can only
be accomplished with integration into OS level shell's like _bash_.
=== Interactive
[[interactive]]
== Interactive
Hints for completions are calculated with _function_ or _interface_ style
methods which takes `CompletionContext` and returns a list of
@@ -20,45 +23,38 @@ for all commands and scenarious. For example existing completion
implementation `RegistrationOptionsCompletionResolver` handles completions
for a option names.
====
[source, java, indent=0]
----
include::{snippets}/CompletionSnippets.java[tag=resolver-1]
----
====
Option values with builder based command registration can be
defined per option.
====
[source, java, indent=0]
----
include::{snippets}/CompletionSnippets.java[tag=builder-1]
----
====
Option values with annotation based command registration are handled
via `ValueProvider` interface which can be defined with `@ShellOption`
annotation.
====
[source, java, indent=0]
----
include::{snippets}/CompletionSnippets.java[tag=provider-1]
----
====
Actual `ValueProvider` with annotation based command needs to be
registered as a _Bean_.
====
[source, java, indent=0]
----
include::{snippets}/CompletionSnippets.java[tag=anno-method]
----
====
=== Command-Line
[[command-line]]
== Command-Line
Command-line completion currently only support _bash_ and is documented
in a built-in `completion` command <<built-in-commands-completion>>.
in a built-in `completion` command xref:commands/builtin/completion.adoc[Completion].

View File

@@ -1,8 +1,9 @@
[[using-shell-components-flow]]
=== Flow
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Flow
When you use <<using-shell-components-ui>> to build something that involves
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
When you use xref:components/ui/index.adoc[Flow Components] to build something that involves
use of a multiple components, your implementation may become a bit cluttered.
To ease these use cases, we added a
`ComponentFlow` that can hook multiple component executions together
@@ -10,28 +11,31 @@ as a "`flow`".
The following listings show examples of flows and their output in a shell:
====
[source, java, indent=0]
----
include::{snippets}/FlowComponentSnippets.java[tag=snippet1]
----
====
image::images/component-flow-showcase-1.svg[text input]
[asciinema,rows=15]
----
include::example$component-flow-showcase-1.cast[]
----
Normal execution order of a components is same as defined with a builder. It's
possible to conditionally choose where to jump in a flow by using a `next`
function and returning target _component id_. If this returned id is aither _null_
or doesn't exist flow is essentially stopped right there.
====
[source, java, indent=0]
----
include::{snippets}/FlowComponentSnippets.java[tag=snippet2]
----
====
image::images/component-flow-conditional-1.svg[text input]
[asciinema,rows=11]
----
include::example$component-flow-conditional-1.cast[]
----
TIP: The result from running a flow returns `ComponentFlowResult`, which you can
use to do further actions.

View File

@@ -1,11 +1,10 @@
[[using-shell-components]]
== Components
= Components
:page-section-summary-toc: 1
Components are a set of features which are either build-in or something
you can re-use or extend for your own needs. Components in question are
either built-in _commands_ or UI side components providing higher level
features within commands itself.
include::using-shell-components-flow.adoc[]
include::using-shell-components-ui.adoc[]

View File

@@ -1,20 +1,22 @@
[[using-shell-components-ui-confirmation]]
==== Confirmation
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Confirmation
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
The confirmation component asks a user for a simple confirmation. It is essentially a
yes-or-no question.
====
[source, java, indent=0]
----
include::{snippets}/UiComponentSnippets.java[tag=snippet5]
----
====
The following image shows the typical output from a confirmation component:
The following screencast shows the typical output from a confirmation component:
image::images/component-confirmation-1.svg[text input]
[asciinema,rows=8]
----
include::example$component-confirmation-1.cast[]
----
The context object is `ConfirmationInputContext`. The following table describes its context variables:
@@ -27,5 +29,5 @@ The context object is `ConfirmationInputContext`. The following table describes
|The default value -- either `true` or `false`.
|`model`
|The parent context variables (see <<textcomponentcontext-template-variables>>).
|The parent context variables (see xref:components/ui/render.adoc#textcomponentcontext-template-variables[TextComponentContext Template Variables]).
|===

View File

@@ -1,5 +1,6 @@
[[using-shell-components-ui]]
=== Flow Components
= Flow Components
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
Starting from version 2.1.x, a new component model provides an
@@ -18,19 +19,12 @@ Built-in components generally follow this logic:
. Exit.
. Render the final status of a component state.
NOTE: <<using-shell-components-flow>> gives better interface for defining the flow of
NOTE: xref:components/flow/index.adoc[Flow] gives better interface for defining the flow of
components that are better suited for defining interactive command flows.
include::using-shell-components-ui-render.adoc[]
include::using-shell-components-ui-stringinput.adoc[]
include::using-shell-components-ui-pathinput.adoc[]
include::using-shell-components-ui-pathsearch.adoc[]
include::using-shell-components-ui-confirmation.adoc[]
include::using-shell-components-ui-singleselect.adoc[]
include::using-shell-components-ui-multiselect.adoc[]

View File

@@ -1,20 +1,22 @@
[[using-shell-components-ui-multiselect]]
==== Multi Select
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Multi Select
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
The multi select component asks a user to select multiple items from a list.
The following listing shows an example:
====
[source, java, indent=0]
----
include::{snippets}/UiComponentSnippets.java[tag=snippet7]
----
====
The following image shows a typical multi-select component:
The following screencast shows a typical multi-select component:
image::images/component-multi-select-1.svg[text input]
[asciinema,rows=9]
----
include::example$component-multi-select-1.cast[]
----
The context object is `MultiItemSelectorContext`. The following table describes its context variables:
@@ -30,5 +32,5 @@ The context object is `MultiItemSelectorContext`. The following table describes
|The visible items, where rows contain maps of name, selected, on-row, and enabled items.
|`model`
|The parent context variables (see <<selectorcomponentcontext-template-variables>>).
|The parent context variables (see xref:components/ui/render.adoc#selectorcomponentcontext-template-variables[SelectorComponentContext Template Variables]).
|===

View File

@@ -1,19 +1,21 @@
[[using-shell-components-ui-pathinput]]
==== Path Input
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Path Input
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
The path input component asks a user for a `Path` and gives additional information about a path itself.
====
[source, java, indent=0]
----
include::{snippets}/UiComponentSnippets.java[tag=snippet4]
----
====
The following image shows typical output from a path input component:
The following screencast shows typical output from a path input component:
image::images/component-path-input-1.svg[text input]
[asciinema,rows=6]
----
include::example$component-path-input-1.cast[]
----
The context object is `PathInputContext`. The following table describes its context variables:
@@ -23,5 +25,5 @@ The context object is `PathInputContext`. The following table describes its cont
|Key |Description
|`model`
|The parent context variables (see <<textcomponentcontext-template-variables>>).
|The parent context variables (see xref:components/ui/render.adoc#textcomponentcontext-template-variables[TextComponentContext Template Variables]).
|===

View File

@@ -1,24 +1,26 @@
[[using-shell-components-ui-pathsearch]]
==== Path Search
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Path Search
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
The path search component asks base directory for scan and optional search expression.
Results are shown in a single select list where user can pick a path.
`PathSearchConfig` can be used to customise component behaviour.
====
[source, java, indent=0]
----
include::{snippets}/UiComponentSnippets.java[tag=snippet9]
----
====
NOTE: Logic for search is passed as is into algorithms documented
in <<appendix-tech-intro-searchalgorithm>>.
in xref:appendices/techintro/searchalgorithm.adoc[Search Algorithms].
The following image shows typical output from a path search component:
The following screencast shows typical output from a path search component:
image::images/component-path-search-1.svg[text input]
[asciinema,rows=10]
----
include::example$component-path-search-1.cast[]
----
The context object is `PathSearchContext`. The following table describes its context variables:
@@ -31,5 +33,5 @@ The context object is `PathSearchContext`. The following table describes its con
|The items available for rendering search results.
|`model`
|The parent context variables (see <<textcomponentcontext-template-variables>>).
|The parent context variables (see xref:/components/ui/render.adoc#textcomponentcontext-template-variables[TextComponentContext Template Variables]).
|===

View File

@@ -1,5 +1,6 @@
[[using-shell-components-ui-render]]
==== Component Render
= Component Render
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
You can implement component rendering in either of two ways: fully
@@ -14,21 +15,17 @@ through code then gives you flexibility to do whatever you need.
The programmatic way to render is to create a `Function`:
====
[source, java, indent=0]
----
include::{snippets}/UiComponentSnippets.java[tag=snippet1]
----
====
Then you can hook it to a component:
====
[source, java, indent=0]
----
include::{snippets}/UiComponentSnippets.java[tag=snippet2]
----
====
Components have their own context but usually share some functionality
from a parent component types. The following tables show those context variables:

View File

@@ -1,20 +1,22 @@
[[using-shell-components-ui-singleselect]]
==== Single Select
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Single Select
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
A single select component asks a user to choose one item from a list. It is similar to a simple
dropbox implementation. The following listing shows an example:
====
[source, java, indent=0]
----
include::{snippets}/UiComponentSnippets.java[tag=snippet6]
----
====
The following image shows typical output for a single select component:
The following screencast shows typical output for a single select component:
image::images/component-single-select-1.svg[text input]
[asciinema,rows=8]
----
include::example$component-single-select-1.cast[]
----
The context object is `SingleItemSelectorContext`. The following table describes its context variables:
@@ -30,16 +32,14 @@ The context object is `SingleItemSelectorContext`. The following table describes
|The visible items, where rows contains maps of name and selected items.
|`model`
|The parent context variables (see <<selectorcomponentcontext-template-variables>>).
|The parent context variables (see xref:/components/ui/render.adoc#selectorcomponentcontext-template-variables[SelectorComponentContext Template Variables]).
|===
You can pre-select an item by defining it to get exposed. This is
useful if you know the default and lets the user merely press `Enter` to make a choice.
The following listing sets a default:
====
[source, java, indent=0]
----
include::{snippets}/UiComponentSnippets.java[tag=snippet8]
----
====

View File

@@ -1,20 +1,22 @@
[[using-shell-components-ui-stringinput]]
==== String Input
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= String Input
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
The string input component asks a user for simple text input, optionally masking values
if the content contains something sensitive. The following listing shows an example:
====
[source, java, indent=0]
----
include::{snippets}/UiComponentSnippets.java[tag=snippet3]
----
====
The following image shows typical output from a string input component:
The following screencast shows typical output from a string input component:
image::images/component-text-input-1.svg[text input]
[asciinema,rows=6]
----
include::example$component-text-input-1.cast[]
----
The context object is `StringInputContext`. The following table lists its context variables:
@@ -39,5 +41,5 @@ The context object is `StringInputContext`. The following table lists its contex
|`true` if a mask character is set. Otherwise, false.
|`model`
|The parent context variables (see <<textcomponentcontext-template-variables>>).
|The parent context variables (see xref:/components/ui/render.adoc#textcomponentcontext-template-variables[TextComponentContext Template Variables]).
|===

View File

@@ -1,44 +1,37 @@
[[using-shell-customization-commandnotfound]]
=== Command Not Found
= Command Not Found
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
On default a missing command is handled via `CommandNotFoundResultHandler`
and outputs a simple message:
====
[source, text]
----
shell:>missing
No command found for 'missing'
----
====
Internally `CommandNotFoundResultHandler` is using `CommandNotFoundMessageProvider`
which is a simple function taking a `ProviderContext` and returning a text
message. Below is an example what a custom message provider might look like.
====
[source, java, indent=0]
----
include::{snippets}/CommandNotFoundSnippets.java[tag=custom-provider]
----
====
It's possible to change this implementation by defining it as a bean.
====
[source, java, indent=0]
----
include::{snippets}/CommandNotFoundSnippets.java[tag=provider-bean-1]
----
====
`CommandNotFoundResultHandler` is a functional interface so it can
be writter as a lambda.
====
[source, java, indent=0]
----
include::{snippets}/CommandNotFoundSnippets.java[tag=provider-bean-2]
----
====

View File

@@ -1,5 +1,8 @@
[[using-shell-customization-contextclose]]
=== Context Close
= Context Close
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
Command execution logic happens via Spring Boot's `ApplicationRunner` beans.
Normally Spring `ApplicationContext` closes automatically after these runner
@@ -20,4 +23,3 @@ spring:
----
NOTE: This setting is not enabled by default.

View File

@@ -0,0 +1,9 @@
[[using-shell-customization]]
= Customization
:page-section-summary-toc: 1
This section describes how you can customize the shell.

View File

@@ -1,5 +1,5 @@
[[using-shell-customization-logging]]
=== Logging
= Logging
On default a _Spring Boot_ application will log messages into a console which
at minimum is annoying and may also mix output from a shell commands.
@@ -7,29 +7,24 @@ Fortunately there is a simple way to instruct logging changes via boot propertie
Completely silence console logging by defining its pattern as an empty value.
====
[source, yaml]
----
logging:
pattern:
console:
----
====
If you need log from a shell then write those into a file.
====
[source, yaml]
----
logging:
file:
name: shell.log
----
====
If you need different log levels.
====
[source, yaml]
----
logging:
@@ -38,18 +33,15 @@ logging:
springframework:
shell: debug
----
====
Passing contiguration properties as command line options is not supported but
you can use any other ways supported by boot, for example.
====
[source, bash]
----
$ java -Dlogging.level.root=debug -jar demo.jar
$ LOGGING_LEVEL_ROOT=debug java -jar demo.jar
----
====
NOTE: In a GraalVM image settings are locked during compilation which means
you can't change log levels at runtime.

View File

@@ -1,5 +1,7 @@
[[using-shell-customization-singlecommand]]
=== Single Command
= Single Command
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
If your shell application is made for exactly a single purpose having only one
@@ -8,7 +10,6 @@ command it may be beneficial to configure it for this. Property
runners than `NonInteractiveShellRunner` and configures it to use
defined _Primary Command_.
====
[source, yaml]
----
spring:
@@ -16,7 +17,6 @@ spring:
noninteractive:
primary-command: mycommand
----
====
For example if you have a command `mycommand` with option `arg`
it had to be executed with `<shellapp> mycommand --arg hi`, but with above

View File

@@ -1,6 +1,7 @@
[[theming]]
=== Theming
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Theming
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
Current terminal implementations are rich in features and can usually show
something else that just plain text. For example a text can be styled to be
@@ -12,7 +13,7 @@ Spring Shell supports these via it's theming framework which contains two parts,
firstly _styling_ can be used to change text type and secondly _figures_ how
some characters are shown. These two are then combined together as a _theme_.
More about _theming_ internals, see <<appendix-tech-intro-theming>>.
More about _theming_ internals, see xref:appendices/techintro/theming.adoc[Theming].
NOTE: Default theme is named `default` but can be change using property
`spring.shell.theme.name`. Other built-in theme named `dump` uses
@@ -20,49 +21,39 @@ no styling for colors and tries to not use any special figures.
Modify existing style by overriding settings.
====
[source, java, indent=0]
----
include::{snippets}/ThemingSnippets.java[tag=custom-style-class]
----
====
Modify existing figures by overriding settings.
====
[source, java, indent=0]
----
include::{snippets}/ThemingSnippets.java[tag=custom-figure-class]
----
====
To create a new theme, create a `ThemeSettings` and provide your own _style_
and _figure_ implementations.
====
[source, java, indent=0]
----
include::{snippets}/ThemingSnippets.java[tag=custom-theme-class]
----
====
Register a new bean `Theme` where you can return your custom `ThemeSettings`
and a _theme_ name.
====
[source, java, indent=0]
----
include::{snippets}/ThemingSnippets.java[tag=custom-theme-config]
----
====
You can use `ThemeResolver` to resolve _styles_ if you want to create
JLine-styled strings programmatically and _figures_ if you want to
theme characters for being more pretty.
====
[source, java, indent=0]
----
include::{snippets}/ThemingSnippets.java[tag=using-theme-resolver]
----
====

View File

@@ -1,11 +1,12 @@
[[using-shell-execution]]
== Execution
= Execution
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
This section describes how to set up a Spring Shell to work in interactive mode.
[[using-shell-execution-interactionmode]]
=== Interaction Mode
== Interaction Mode
Version 2.1.x introduced built-in support to distinguish between interactive
and non-interactive modes. This makes it easier to use the shell as a
@@ -13,7 +14,7 @@ simple command-line tool without requiring customization.
Currently, interactive mode is entered if any command line options are passed when starting
or running a shell from a command line. This works especially well when a shell application
is compiled with <<native>>.
is compiled with xref:building.adoc#native[Native Support].
Some commands may not have any useful meanings when they run in interactive mode
or (conversely) in non-interactive mode. For example, a built-in `exit` command would
@@ -23,7 +24,7 @@ The `@ShellMethod` annotation has a field called `interactionMode` that you can
shell about when a particular command is available.
[[using-shell-execution-shellrunner]]
=== Shell Runners
== Shell Runners
`ShellApplicationRunner` is a main interface where Boot's `ApplicationArguments` are passed
and its default implementation makes a choice which `ShellRunner` is used. There can be

View File

@@ -1,11 +1,14 @@
== Getting Started
[[getting-started]]
= Getting Started
To see what Spring Shell has to offer, we can write a trivial _hello world_
shell application that has a simple argument.
IMPORTANT: _Spring Shell_ is based on _Spring Boot_ {spring-boot-version} and
_Spring Framework_ {spring-version} and thus requires _JDK 17_.
=== Creating a Project
[[creating-a-project]]
== Creating a Project
For the purpose of this tutorial, we create a simple Spring Boot application by
using https://start.spring.io where you can choose _Spring Shell_ dependency.
@@ -16,7 +19,6 @@ NOTE: _Spring Shell_ version on `start.spring.io` is usually latest release.
With _maven_ you're expected to have something like:
====
[source, xml, subs=attributes+]
----
<properties>
@@ -46,11 +48,9 @@ With _maven_ you're expected to have something like:
</dependencies>
</dependencyManagement>
----
====
With _gradle_ you're expected to have something like:
====
[source, groovy, subs=attributes+]
----
dependencies {
@@ -65,7 +65,6 @@ dependencyManagement {
}
}
----
====
CAUTION: Given that Spring Shell starts the REPL (Read-Eval-Print-Loop) because this
dependency is present, you need to either skip tests when you build (`-DskipTests`)
@@ -76,27 +75,23 @@ the eval loop or crashes with a NPE.
Once compiled it can be run either in interactive mode:
====
[source, text, subs=attributes+]
----
include::code/getting-started-run-interactive.out[]
include::example$getting-started-run-interactive.out[]
----
====
Or in non-interactive mode:
====
[source, text, subs=attributes+]
----
include::code/getting-started-run-noninteractive.out[]
include::example$getting-started-run-noninteractive.out[]
----
====
TIP: Check out <<using-shell-customization-logging>> making logging to work
TIP: Check out xref:/customization/logging.adoc[Logging] making logging to work
better with shell apps.
[[using-spring-shell-your-first-command]]
=== 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` which is a variation of `@Component` that is used to restrict
@@ -107,7 +102,6 @@ returns it with "Hello world". Add `@ShellMethod` and optionally change command
using `key` parameter. You can use `@ShellOption` to define argument default value
if it's not given when running a command.
====
[source, java]
----
package com.example.demo;
@@ -127,21 +121,17 @@ public class MyCommands {
}
}
----
====
New _hello-world_ command becomes visible to _help_:
====
[source, text]
----
My Commands
hello-world:
----
====
And you can run it:
====
[source, text]
----
shell:>hello-world
@@ -150,6 +140,5 @@ Hello world spring
shell:>hello-world --arg boot
Hello world boot
----
====
The rest of this document delves deeper into the whole Spring Shell programming model.

View File

@@ -0,0 +1,18 @@
= Spring Shell
Eric Bottard; Janne Valkealahti; Jay Bryant; Corneil du Plessis
:page-section-summary-toc: 1
**{project-version}**
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.
Spring Shell lets you create such a runnable application, where the user enters textual commands that are run until the program terminates. The Spring Shell project provides the infrastructure to create such a REPL (Read, Eval, Print Loop) application, letting you concentrate on implementing commands by using the familiar Spring programming model.
Spring Shell includes advanced features (such as parsing, tab completion, colorization of output, fancy ASCII-art table display, input conversion, and validation), freeing you to focus on core command logic.
(C) 2017 - 2023 VMware, Inc.
_Copies of this document may be made for your own use and for distribution to
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._

View File

@@ -1,6 +1,7 @@
[[using-shell-options-arity]]
=== Arity
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Arity
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
Arity defines how many parameters option parsing takes.
@@ -8,23 +9,29 @@ NOTE: There are limitations in a `legacy annotation` compared to `annotation`
and `programmatic` use of arity settings. These are mentioned in notes in
below samples.
[tabs]
======
Programmatic::
+
[source,java,indent=0,role="primary"]
.Programmatic
----
include::{snippets}/OptionSnippets.java[tag=option-registration-zeroorone-programmatic]
----
Annotation::
+
[source,java,indent=0,role="secondary"]
.Annotation
----
include::{snippets}/OptionSnippets.java[tag=option-registration-zeroorone-annotation]
----
Legacy Annotation::
+
[source,java,indent=0,role="secondary"]
.Legacy Annotation
----
include::{snippets}/OptionSnippets.java[tag=option-registration-zeroorone-legacyannotation]
----
======
[[using-shell-options-arity-optionarity-table]]
.OptionArity
@@ -50,30 +57,35 @@ include::{snippets}/OptionSnippets.java[tag=option-registration-zeroorone-legacy
NOTE: `legacy annotation` doesn't support defining minimum arity.
[tabs]
======
Programmatic::
+
[source,java,indent=0,role="primary"]
.Programmatic
----
include::{snippets}/OptionSnippets.java[tag=option-registration-zerooronewithminmax-programmatic]
----
Annotation::
+
[source,java,indent=0,role="secondary"]
.Annotation
----
include::{snippets}/OptionSnippets.java[tag=option-registration-zerooronewithminmax-annotation]
----
Legacy Annotation::
+
[source,java,indent=0,role="secondary"]
.Legacy Annotation
----
include::{snippets}/OptionSnippets.java[tag=option-registration-zerooronewithminmax-legacyannotation]
----
======
In below example we have option _arg1_ and it's defined as type _String[]_. Arity
defines that it needs at least 1 parameter and not more that 2. As seen in below
spesific exceptions _TooManyArgumentsOptionException_ and
_NotEnoughArgumentsOptionException_ are thrown to indicate arity mismatch.
====
[source, bash]
----
shell:>e2e reg arity-errors --arg1
@@ -88,4 +100,3 @@ Hello [one, two]
shell:>e2e reg arity-errors --arg1 one two three
Too many arguments --arg1 requires at most 2.
----
====

View File

@@ -1,13 +1,13 @@
[[using-shell-options-basics-annotation]]
==== Annotation
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Annotation
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
`Option` annotation can be used to define an option name if you
don't want it to be same as argument name.
====
[source, java, indent=0]
----
include::{snippets}/OptionSnippets.java[tag=option-with-option-annotation]
----
====

View File

@@ -0,0 +1,12 @@
[[using-shell-options-basics]]
= Basics
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
This section gives a generic idea how an option can be defined. Following
sections, beyond basics, discuss more about how various option behaviour
can be accomplished for a particular use case.

View File

@@ -1,33 +1,28 @@
[[using-shell-options-basics-legacyannotation]]
==== Legacy Annotation
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Legacy Annotation
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
Having a target method with argument is automatically registered with a matching
argument name.
====
[source, java, indent=0]
----
include::{snippets}/OptionSnippets.java[tag=option-without-annotation]
----
====
`@ShellOption` annotation can be used to define an option name if you
don't want it to be same as argument name.
====
[source, java, indent=0]
----
include::{snippets}/OptionSnippets.java[tag=option-with-annotation]
----
====
If option name is defined without prefix, either `-` or `--`, it is discovered
from _ShellMethod#prefix_.
====
[source, java, indent=0]
----
include::{snippets}/OptionSnippets.java[tag=option-with-annotation-without-prefix]
----
====

View File

@@ -1,17 +1,17 @@
[[using-shell-options-basics-registration]]
[[using-shell-options-basics-programmatic]]
==== Programmatic
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Programmatic
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../../../../src/test/java/org/springframework/shell/docs]
Programmatic way with `CommandRegistration` is to use `withOption` to define
an option.
====
[source, java, indent=0]
----
include::{snippets}/OptionSnippets.java[tag=option-registration-longarg]
----
====
`CommandRegistration` can be defined as a bean or manually registered
with a `CommandCatalog`.

View File

@@ -1,26 +1,33 @@
[[using-shell-options-default]]
=== Default Value
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Default Value
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
Having a default value for an option is somewhat related to
<<using-shell-options-optional>>, as there are cases where you
xref:options/optional.adoc[Optional Value], as there are cases where you
may want to know if the user defined an option and change behavior
based on a default value:
[tabs]
======
Programmatic::
+
[source,java,indent=0,role="primary"]
.Programmatic
----
include::{snippets}/OptionSnippets.java[tag=option-default-programmatic]
----
Annotation::
+
[source,java,indent=0,role="secondary"]
.Annotation
----
include::{snippets}/OptionSnippets.java[tag=option-default-annotation]
----
Legacy Annotation::
+
[source,java,indent=0,role="secondary"]
.Legacy Annotation
----
include::{snippets}/OptionSnippets.java[tag=option-default-legacyannotation]
----
======

View File

@@ -1,6 +1,7 @@
[[using-shell-options]]
== Options
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Options
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
Command line arguments can be separated into options and positional parameters.
Following sections describes features how options are defined and used. We first
@@ -17,22 +18,12 @@ arguments or with programmatically using `CommandRegistration`.
NOTE: In below sections `@ShellOption` refer to a _legacy annotation model_
and `@Option` refer to an _annotation model_.
include::using-shell-options-basics.adoc[]
include::using-shell-options-short.adoc[]
include::using-shell-options-arity.adoc[]
include::using-shell-options-positional.adoc[]
include::using-shell-options-optional.adoc[]
include::using-shell-options-default.adoc[]
include::using-shell-options-validation.adoc[]
include::using-shell-options-label.adoc[]
include::using-shell-options-types.adoc[]
include::using-shell-options-naming.adoc[]

View File

@@ -1,6 +1,7 @@
[[using-shell-options-label]]
=== Label
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Label
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
_Option Label_ has no functional behaviour within a shell itself other than
what a default `help` command outputs. Within a command documentation
@@ -9,20 +10,24 @@ you may want to give better descriptive word for an option.
NOTE: Label is not supported with `legacy annotation`.
[tabs]
======
Programmatic::
+
[source,java,indent=0,role="primary"]
.Programmatic
----
include::{snippets}/OptionSnippets.java[tag=option-label-programmatic]
----
Annotation::
+
[source,java,indent=0,role="secondary"]
.Annotation
----
include::{snippets}/OptionSnippets.java[tag=option-label-annotation]
----
======
Defining label is then shown in `help`.
====
[source, bash]
----
my-shell:>help labelOption
@@ -37,4 +42,3 @@ OPTIONS
[Optional]
----
====

View File

@@ -1,6 +1,7 @@
[[using-shell-options-naming]]
=== Naming
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Naming
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
If there is a need to modify option long names that can be done
using `OptionNameModifier` interface which is a simple
@@ -15,22 +16,18 @@ on default.
You can define one with an option in `CommandRegistration`.
====
[source, java, indent=0]
----
include::{snippets}/OptionSnippets.java[tag=option-registration-naming-case-req]
----
====
Add one _singleton bean_ as type `OptionNameModifier` and that becomes
a global default.
====
[source, java, indent=0]
----
include::{snippets}/OptionSnippets.java[tag=option-registration-naming-case-bean]
----
====
It's also possible to just add configuration property with
`spring.shell.option.naming.case-type` which auto-configures
@@ -45,7 +42,6 @@ default via configuration properies only work if using
pre-configured `Builder` instance. See more
<<using-shell-commands-programmaticmodel>>.
====
[source, yaml]
----
spring:
@@ -58,21 +54,17 @@ spring:
# case-type: kebab
# case-type: pascal
----
====
For example options defined in an annotated method like this.
====
[source, java, indent=0]
----
include::{snippets}/OptionSnippets.java[tag=option-registration-naming-case-sample1]
----
====
On default `help` for that command shows names coming
directly from `@ShellOption`.
====
[source, bash]
----
OPTIONS
@@ -88,12 +80,10 @@ OPTIONS
--FromPascal String
[Mandatory]
----
====
Define `spring.shell.option.naming.case-type=kebab` and default
modifier is added and option names then look like.
====
[source, bash]
----
OPTIONS
@@ -110,4 +100,3 @@ OPTIONS
[Mandatory]
----
====

View File

@@ -1,46 +1,59 @@
[[using-shell-options-optional]]
=== Optional Value
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Optional Value
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
An option is either required or not and, generally speaking, how it behaves depends on
a command target.
Making option optional.
[tabs]
======
Programmatic::
+
[source,java,indent=0,role="primary"]
.Programmatic
----
include::{snippets}/OptionSnippets.java[tag=option-optional-programmatic]
----
Annotation::
+
[source,java,indent=0,role="secondary"]
.Annotation
----
include::{snippets}/OptionSnippets.java[tag=option-optional-annotation]
----
Legacy Annotation::
+
[source,java,indent=0,role="secondary"]
.Legacy Annotation
----
include::{snippets}/OptionSnippets.java[tag=option-optional-legacyannotation]
----
======
Making option mandatory.
[tabs]
======
Programmatic::
+
[source,java,indent=0,role="primary"]
.Programmatic
----
include::{snippets}/OptionSnippets.java[tag=option-mandatory-programmatic]
----
Annotation::
+
[source,java,indent=0,role="secondary"]
.Annotation
----
include::{snippets}/OptionSnippets.java[tag=option-mandatory-annotation]
----
Legacy Annotation::
+
[source,java,indent=0,role="secondary"]
.Legacy Annotation
----
include::{snippets}/OptionSnippets.java[tag=option-mandatory-legacyannotation]
----
======

View File

@@ -1,15 +1,14 @@
[[using-shell-options-positional]]
=== Positional
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Positional
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
Positional information is mostly related to a command target method:
====
[source, java, indent=0]
----
include::{snippets}/OptionSnippets.java[tag=option-registration-positional]
----
====
NOTE: Be careful with positional parameters as it may soon
become confusing which options those are mapped to.
@@ -26,36 +25,29 @@ ambiguous arguments.
Let's look what happens when we don't define a position.
====
[source, java, indent=0]
----
include::{snippets}/OptionSnippets.java[tag=option-registration-aritystrings-noposition]
----
====
Option _arg1_ is required and there is no info what to do with argument
`one` resulting error for missing option.
====
[source, bash]
----
shell:>arity-strings-1 one
Missing mandatory option --arg1.
----
====
Now let's define a position `0`.
====
[source, java, indent=0]
----
include::{snippets}/OptionSnippets.java[tag=option-registration-aritystrings-position]
----
====
Arguments are processed until we get up to 2 arguments.
====
[source, bash]
----
shell:>arity-strings-2 one
@@ -67,4 +59,3 @@ Hello [one, two]
shell:>arity-strings-2 one two three
Hello [one, two]
----
====

View File

@@ -1,46 +1,59 @@
[[using-shell-options-short]]
=== Short Format
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Short Format
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
Short style _POSIX_ option is usually just a synonym to long format. As
shown below option `--arg` is equal to `-a`.
[tabs]
======
Programmatic::
+
[source,java,indent=0,role="primary"]
.Programmatic
----
include::{snippets}/ShortOptionSnippets.java[tag=option-type-string-programmatic]
----
Annotation::
+
[source,java,indent=0,role="secondary"]
.Annotation
----
include::{snippets}/ShortOptionSnippets.java[tag=option-type-string-annotation]
----
Legacy Annotation::
+
[source,java,indent=0,role="secondary"]
.Legacy Annotation
----
include::{snippets}/ShortOptionSnippets.java[tag=option-type-string-legacyannotation]
----
======
Short option with combined format is powerful if type is defined as a flag
which means type is a _boolean_. That way you can define a presence of a flags
as `-abc`, `-abc true` or `-abc false`.
[tabs]
======
Programmatic::
+
[source,java,indent=0,role="primary"]
.Programmatic
----
include::{snippets}/ShortOptionSnippets.java[tag=option-type-multiple-booleans-programmatic]
----
Annotation::
+
[source,java,indent=0,role="secondary"]
.Annotation
----
include::{snippets}/ShortOptionSnippets.java[tag=option-type-multiple-booleans-annotation]
----
Legacy Annotation::
+
[source,java,indent=0,role="secondary"]
.Legacy Annotation
----
include::{snippets}/ShortOptionSnippets.java[tag=option-type-multiple-booleans-legacyannotation]
----
======

View File

@@ -1,45 +1,41 @@
[[using-shell-options-types]]
=== Types
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Types
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
This section talks about how particular data type is used as an option value.
==== String
[[string]]
== String
`String` is a most simplest type as there's no conversion involved as what's
coming in from a user is always a string.
====
[source, java, indent=0]
----
include::{snippets}/OptionTypesSnippets.java[tag=option-type-string-anno]
----
====
While it's not strictly required to define type as a `String` it's always
adviced to do so.
====
[source, java, indent=0]
----
include::{snippets}/OptionTypesSnippets.java[tag=option-type-string-reg]
----
====
==== Boolean
[[boolean]]
== Boolean
Using boolean types is a bit more involved as there are `boolean` and
`Boolean` where latter can be _null_. Boolean types are usually used as
flags meaning argument value may not be needed.
====
[source, java, indent=0]
----
include::{snippets}/OptionTypesSnippets.java[tag=option-type-boolean-anno]
----
====
====
[source, bash]
----
shell:>example
@@ -51,16 +47,12 @@ arg1=false arg2=true arg3=false arg4=true arg5=true arg6=false
shell:>example --arg4 false
arg1=false arg2=true arg3=false arg4=false arg5=true arg6=false
----
====
====
[source, java, indent=0]
----
include::{snippets}/OptionTypesSnippets.java[tag=option-type-boolean-reg]
----
====
====
[source, bash]
----
shell:>example
@@ -72,66 +64,54 @@ arg1=false arg2=true arg3=false arg4=true arg5=true arg6=false
shell:>example --arg4 false
arg1=false arg2=true arg3=false arg4=false arg5=true arg6=false
----
====
==== Number
[[number]]
== Number
Numbers are converted as is.
====
[source, java, indent=0]
----
include::{snippets}/OptionTypesSnippets.java[tag=option-type-integer-anno]
----
====
====
[source, java, indent=0]
----
include::{snippets}/OptionTypesSnippets.java[tag=option-type-integer-reg]
----
====
==== Enum
[[enum]]
== Enum
Conversion to enums is possible if given value is exactly matching enum itself.
Currently you can convert assuming case insensitivity.
====
[source, java, indent=0]
----
include::{snippets}/OptionTypesSnippets.java[tag=option-type-enum-class]
----
====
====
[source, java, indent=0]
----
include::{snippets}/OptionTypesSnippets.java[tag=option-type-enum-anno]
----
====
====
[source, java, indent=0]
----
include::{snippets}/OptionTypesSnippets.java[tag=option-type-enum-reg]
----
====
==== Array
[[array]]
== Array
Arrays can be used as is with strings and primitive types.
====
[source, java, indent=0]
----
include::{snippets}/OptionTypesSnippets.java[tag=option-type-string-array-anno]
----
====
====
[source, java, indent=0]
----
include::{snippets}/OptionTypesSnippets.java[tag=option-type-string-array-reg]
----
====

View File

@@ -1,5 +1,5 @@
[[validating-command-arguments]]
=== Validation
= Validation
Spring Shell integrates with the https://beanvalidation.org/[Bean Validation API] to support
automatic and self-documenting constraints on command parameters.
@@ -7,7 +7,6 @@ automatic and self-documenting constraints on command parameters.
Annotations found on command parameters and annotations at the method level are
honored and trigger validation prior to the command executing. Consider the following command:
====
[source, java]
----
@ShellMethod("Change password.")
@@ -15,14 +14,11 @@ honored and trigger validation prior to the command executing. Consider the foll
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')
----
====

View File

@@ -1,6 +1,7 @@
[[using-shell-testing-basics]]
=== Basics
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Basics
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
Spring Shell provides a number of utilities and annotations to help when testing your application.
Test support is provided by two modules: `spring-shell-test` contains core items, and
@@ -8,18 +9,14 @@ Test support is provided by two modules: `spring-shell-test` contains core items
To test _interactive_ commands.
====
[source, java, indent=0]
----
include::{snippets}/TestingSnippets.java[tag=testing-shelltest-interactive]
----
====
To test _non-interactive_ commands.
====
[source, java, indent=0]
----
include::{snippets}/TestingSnippets.java[tag=testing-shelltest-noninteractive]
----
====

View File

@@ -1,6 +1,8 @@
[[using-shell-testing]]
== Testing
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Testing
:page-section-summary-toc: 1
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
Testing cli application is difficult due to various reasons:
@@ -15,6 +17,4 @@ Testing cli application is difficult due to various reasons:
NOTE: Testing support is currently under development and will be
unstable for various parts.
include::using-shell-testing-basics.adoc[]
include::using-shell-testing-settings.adoc[]

View File

@@ -1,6 +1,7 @@
[[using-shell-testing-settings]]
=== Settings
ifndef::snippets[:snippets: ../../test/java/org/springframework/shell/docs]
= Settings
ifndef::snippets[:snippets: ../../../../src/test/java/org/springframework/shell/docs]
Built in emulation uses terminal width 80 and height 24 on default.
Changing dimensions is useful if output would span into multiple
@@ -9,19 +10,15 @@ lines and you don't want to handle those cases in a tests.
These can be changed using properties `spring.shell.test.terminal-width`
or `spring.shell.test.terminal-height`.
====
[source, java, indent=0]
----
include::{snippets}/TestingSnippets.java[tag=testing-shelltest-dimensions-props]
----
====
`ShellTest` annotation have fields `terminalWidth` and `terminalHeight`
which can also be used to change dimensions.
====
[source, java, indent=0]
----
include::{snippets}/TestingSnippets.java[tag=testing-shelltest-dimensions-field]
----
====

View File

@@ -1,35 +0,0 @@
Some info how screen recordings were made
asciinema rec spring-shell-docs/src/main/asciidoc/asciinema/component-text-input-1.cast
asciinema rec spring-shell-docs/src/main/asciidoc/asciinema/component-path-input-1.cast
asciinema rec spring-shell-docs/src/main/asciidoc/asciinema/component-path-search-1.cast
asciinema rec spring-shell-docs/src/main/asciidoc/asciinema/component-confirmation-1.cast
asciinema rec spring-shell-docs/src/main/asciidoc/asciinema/component-single-select-1.cast
asciinema rec spring-shell-docs/src/main/asciidoc/asciinema/component-multi-select-1.cast
asciinema rec spring-shell-docs/src/main/asciidoc/asciinema/component-flow-showcase-1.cast
asciinema rec spring-shell-docs/src/main/asciidoc/asciinema/component-flow-conditional-1.cast
svg-term \
--in spring-shell-docs/src/main/asciidoc/asciinema/component-text-input-1.cast \
--out spring-shell-docs/src/main/asciidoc/images/component-text-input-1.svg
svg-term \
--in spring-shell-docs/src/main/asciidoc/asciinema/component-path-input-1.cast \
--out spring-shell-docs/src/main/asciidoc/images/component-path-input-1.svg
svg-term \
--in spring-shell-docs/src/main/asciidoc/asciinema/component-path-search-1.cast \
--out spring-shell-docs/src/main/asciidoc/images/component-path-search-1.svg
svg-term \
--in spring-shell-docs/src/main/asciidoc/asciinema/component-confirmation-1.cast \
--out spring-shell-docs/src/main/asciidoc/images/component-confirmation-1.svg
svg-term \
--in spring-shell-docs/src/main/asciidoc/asciinema/component-single-select-1.cast \
--out spring-shell-docs/src/main/asciidoc/images/component-single-select-1.svg
svg-term \
--in spring-shell-docs/src/main/asciidoc/asciinema/component-multi-select-1.cast \
--out spring-shell-docs/src/main/asciidoc/images/component-multi-select-1.svg
svg-term \
--in spring-shell-docs/src/main/asciidoc/asciinema/component-flow-showcase-1.cast \
--out spring-shell-docs/src/main/asciidoc/images/component-flow-showcase-1.svg
svg-term \
--in spring-shell-docs/src/main/asciidoc/asciinema/component-flow-conditional-1.cast \
--out spring-shell-docs/src/main/asciidoc/images/component-flow-conditional-1.svg

View File

@@ -1,5 +1,7 @@
plugins {
id 'org.springframework.shell.docs'
id 'org.antora' version '1.0.0'
id 'io.spring.antora.generate-antora-yml' version '0.0.1'
}
description = 'Spring Shell Documentation'
@@ -8,10 +10,41 @@ dependencies {
management platform(project(":spring-shell-management"))
implementation project(':spring-shell-starters:spring-shell-starter')
implementation project(':spring-shell-starters:spring-shell-starter-test')
implementation project(':spring-shell-samples')
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.awaitility:awaitility'
}
asciidoctorj {
version = '2.5.4'
node {
version = '16.15.0'
}
antora {
version = '3.2.0-alpha.2'
options = [clean: true, fetch: !project.gradle.startParameter.offline, stacktrace: true]
dependencies = [
'@antora/atlas-extension': '1.0.0-alpha.1',
'@antora/collector-extension': '1.0.0-alpha.3',
'@asciidoctor/tabs': '1.0.0-beta.3',
'@springio/antora-extensions': '1.8.1',
'@springio/asciidoctor-extensions': '1.0.0-alpha.8',
]
}
tasks.named("generateAntoraYml") {
asciidocAttributes = project.provider( {
def dependencies = resolvedVersions(project.configurations.testRuntimeClasspath)
return ['project-version' : project.version,
'spring-boot-version' : dependencies['spring-boot-starter-version'],
'spring-version': dependencies['spring-core-version']
]
} )
}
def resolvedVersions(Configuration configuration) {
return configuration.resolvedConfiguration
.resolvedArtifacts
.collectEntries { [(it.name + '-version'): it.moduleVersion.id.version] }
}

View File

@@ -1,3 +0,0 @@
=== Command Execution
When command parsing has done its job and command registration has been resolved, command execution
does the hard work of running the code.

View File

@@ -1,19 +0,0 @@
[appendix]
[#appendix-tech-intro]
== Techical Introduction
This appendix contains information for developers and others who would like to know more about how Spring Shell
works internally and what its design decisions are.
include::appendices-techical-intro-registration.adoc[]
include::appendices-techical-intro-parser.adoc[]
include::appendices-techical-intro-execution.adoc[]
include::appendices-techical-intro-commandcontext.adoc[]
include::appendices-techical-intro-commandcatalog.adoc[]
include::appendices-techical-intro-theming.adoc[]
include::appendices-techical-intro-searchalgorithm.adoc[]

View File

@@ -1,3 +0,0 @@
include::appendices-techical-intro.adoc[]
include::appendices-debugging.adoc[]

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.5 KiB

Some files were not shown because too many files have changed in this diff Show More