Parallel

Runs commands in parallel (sub-sequence). This is not true concurrency, but rather, each part of each command is run in the order that they are in the constructor. (1’s initialise is run, then 2’s initialise, etc, etc.). It finishes when all commands it contains finish.

The s-expression representation of this command is:

(parallel (
	1
	2))

The Parallel.addCommands() method is non-mutating, and returns a new Parallel.

A command can be chained into a Parallel via the Command.with() method, this code snippet is the same as above:

Sequential

Runs commands in sequence. (1 is run until it finishes, then 2, etc, etc.). It finishes when all commands it contains finish.

The s-expression representation of this command is:

(sequential (
	1
	2))

The Sequential.addCommands() method is non-mutating, and returns a new Sequential.

A command can be chained into a Sequential via the Command.then() method, this code snippet is the same as above:

Race / Deadline

Runs commands the same as Parallel, but Race finishes as soon as any command finishes, and Deadline finishes when the deadline command finishes. This early end does not interrupt the rest of the unfinished commands.

Mercurial only has one class for both of these: Race.

The s-expression representation of this command is:

(race (
	1
	2))

(race deadline (
	1
	2))

deadline is omitted if it is null.

The Race.addCommands() and Race.setDeadline() methods are non-mutating, and return a new Race.

A command can be chained into a Race via the Command.raceWith() method, this code snippet is the same as above:

A command can be chained into a Race as the deadline via the Command.asDeadline() method, this code snippet is the same as above:

Wait

Wait waits its argument in seconds. This example waits 1 second:

The s-expression representation of this command is:

(wait 1.0)

A command can be chained into a Race with a Wait as the deadline via the Command.timeout(duration) method, these two are equivalent:

IfElse

If else takes a BooleanSupplier and a command to run if true and a command to run if false. When the command is initialised it runs the supplier and uses the result to decide if to run trueCommand or falseCommand.

This example will always run 1, because it always returns true.

The s-expression representation of this command is:

(? true 1 2)

StateMachine

StateMachine is a Finite State Machine (FSM) command. It makes it easy to assemble a state machine where each state is a command. It finishes if the command for the current state is finished, and there isn’t a state change underway.

We’ll use this enum for the example:

StateMachine can work with any state type, read more about RefCell in Util.

Its important to note that StateMachine.withState() is non-mutating.

Additionally, you must ensure that the StateMachine never has a state that doesn’t exist while scheduled, as this will cause it to throw an error.

The name that is passed to the withState callback is a preescaped name that matches the name of the state.

The s-expression representation of this command is:

(state-machine START (
	(START demo)
	MIDDLE
	END))

StateMachine displays each state-command pair as (state command) by default, however, if state and command have the same name, then it just becomes state, which we can see above.

Advancing

Advancing is more of a utility for commands bound to user input.

Advancing moves forwards through the list whenever it is schedule()d again. This means that if it is bound to a button or similar, it makes it easy to write some command toggle or state switcher.

In this manner, it acts a bit like Sequential but does not advance by itself. At the same time, it is a bit like a rudimentary StateMachine.

Advancing wraps around, and can be manually advanced like so:

So if you advance at command ‘2’, then it wraps back to ‘1’.

Additionally, manual advancement needs a warning, manual advancement is a ‘request’ for advancement, rather than immediate advancement. This means that the advancement needs to be processed by the advancing command itself before Advancing.advance() will have affect again.

The s-expression representation of this command is:

(advancing (
	1
	2))