View on GitHub

consoleui

Tiny java library that enables simple UI elements on ANSI console based terminals

ConsoleUI programming guide

This document contains a brief introduction using ConsoleUI.

Introduction

ConsoleUI is a library for prompting the user for different types of input. It provides simple UI elements on ANSI console-based terminals. ConsoleUI is inspired by Inquirer.js which is written in JavaScript.

Features

Console UI currently supports:

A small example

The following code presents a simple, but complete code example to use CosoleUI for selecting an item from a list.

package de.codeshelf.consoleui;

import de.codeshelf.consoleui.prompt.ConsolePrompt;
import de.codeshelf.consoleui.prompt.PromtResultItemIF;
import de.codeshelf.consoleui.prompt.builder.PromptBuilder;
import jline.TerminalFactory;
import org.fusesource.jansi.AnsiConsole;

import java.io.IOException;
import java.util.HashMap;

import static org.fusesource.jansi.Ansi.ansi;

/**
 * User: Andreas Wegmann
 * Date: 12.08.2020
 */
public class SimpleExample {

  public static void main(String[] args) throws InterruptedException {
    AnsiConsole.systemInstall();                                      // #1
    System.out.println(ansi().eraseScreen().render("Simple list example:"));  

    try {
      ConsolePrompt prompt = new ConsolePrompt();                     // #2
      PromptBuilder promptBuilder = prompt.getPromptBuilder();        // #3

      promptBuilder.createListPrompt()                                // #4
              .name("pizzatype")
              .message("Which pizza do you want?")
              .newItem().text("Margherita").add()  // without name (name defaults to text)
              .newItem("veneziana").text("Veneziana").add()
              .newItem("hawai").text("Hawai").add()
              .newItem("quattro").text("Quattro Stagioni").add()
              .addPrompt();                                         
      
      HashMap<String, ? extends PromtResultItemIF> result = prompt.prompt(promptBuilder.build()); // #5
      System.out.println("result = " + result);
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        TerminalFactory.get().restore();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }}

Basic steps:

  1. ConsoleUI uses jansi, so you have to initialize it first
  2. Create a new ConsolePrompt object.
  3. Create a PromptBuilder. All user interactions can be created with the prompt builder object.
  4. In this example, we create a ListPrompt
    1. give it a name (‘pizzatype’)
    2. assign a prompt message (“Which pizza do you want?”)
    3. create items with and name (optional) and a text and add them to the ListPrompt
    4. to finish call addPrompt() to create the ListPrompt and add it to the prompt builder object.
  5. calling prompt.prompt(promptBuilder.build()) builds all the prompts (in this example only one) and enters the user interaction. After all prompts are processes, the prompt() method returns an object with the user input results.

Prompting for user input

Input

The InputPrompt is a classic entry line like a shell. Because of the underlying readline implementation, it offers you to provide completers (like file name completer or string completer). In addition to his, you can define a mask character that is printed on the screen instead of the typed keys like used for hidden password entry.

promptBuilder.createInputPrompt()                               // #1
  .name("name")                                                 // #2
  .message("Please enter your name")                            // #3
  .defaultValue("John Doe")                                     // #4
  //.mask('*')                                                  // #5
  .addCompleter(new StringsCompleter("Jim", "Jack", "John"))    // #6
  .addPrompt();

Description:

  1. With the prompt builder call createInputPrompt() to create a new input prompt builder
  2. Set a name for the prompt. Setting a name is necessary to pick the right user input from the result object after the user interaction is finished. The resulting object is HashMap where each key is the name of a prompt you have created before.
  3. Add a message which is printed in front of the user input.
  4. (optional) By adding a default value, you offer the user just to press enter to accept the default value. The default value is printed in parentheses after the prompt.
  5. (optional) If you add a masking character, each key pressed by the user echoed as masked character on the console. That’s useful for password entries.
  6. (optional) You can add completers (like simple string completers, file completers or more complex completers) to simplify the user input. The user can use the TAB button to complete partial input. See jline/jline2 for details and examples.

Console

input prompt

User Input

The user can use readline compatible navigation (mainly Emacs control codes) inside the user input area. This includes CTRL-a to go to the beginning of input, CTRL-e to go to the end, and so on.

After the input, the entered value is printed in different color right after the prompt.

Result

The result of this prompt is of type InputResult and has a method getInput() to get user input.

List

The ListPrompt lets the user choose one item from a given list. If the list is bigger than the terminal height, the list is partially shown and scrolled if needed.

promptBuilder.createListPrompt()                                                // #1
  .name("pizzatype")                                                            // #2
  .message("Which pizza do you want?")                                          // #3
  .newItem().text("Margherita").add()  // without name (name defaults to text)     #4
  .newItem("veneziana").text("Veneziana").add()                                 // #5
  .newItem("hawai").text("Hawai").add()                                         
  .newItem("quattro").text("Quattro Stagioni").add()
  // .pageSize(10)                                                                 #6
  // .relativePageSize(66)																											   #7
  .addPrompt();

Description:

  1. With the prompt builder call createListPrompt() to create a new list prompt builder.
  2. Set a name for the prompt.
  3. Add a message which is printed on top of the list.
  4. Add items to the list. If you call newItem() without a name for the item, the text of the item is used in the result.
  5. Add items with newItem(<item_name>) to give the item a name which makes it possible to use a technical key or another value instead of the printed text as a result.
  6. (optional) For long lists, you can use pageSize() to set an absolute number of items to display (default is 10). Even if you choose a higher value than the terminal, the list will never exceed the terminal height.
  7. (optional) Further you can use relativePageSize() to set a percentual size of the terminal as height. In this example, 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is displayed, even when you select a very low value.

Console

list_prompt

User input

The user can use up and down keys or VI like the keys 'j' for down and 'k' for moving the selector in front of the items to the right position. Pressing the enter button selects the item.

After the input, the list is erased from the screen and the selected value is printed in a different color right after the prompt.

Result

The result of this prompt is of type ListResult and has a method getSelectedId() to get user input.

Checkbox

The checkbox input lets the user choose any number of items of a given list. It’s possible to add separators between items. Further, it’s possible to disable items and display a message text, why they are disabled. Sometimes this may be useful to present a consistent user interface with all usually displayed options and an explanation of why some items are not usable here.

promptBuilder.createCheckboxPrompt()                                            // #1
  .name("topping")                                                              // #2
  .message("Please select additional toppings:")                                // #3
  .newSeparator("standard toppings").add()                                      // #4
  .newItem().name("cheese").text("Cheese").add()                                // #5
  .newItem("bacon").text("Bacon").add()                                         // #6
  .newItem("onions").text("Onions").disabledText("Sorry. Out of stock.").add()  // #7
  .newSeparator().text("special toppings").add()                                
  .newItem("salami").text("Very hot salami").check().add()                      // #8
  .newItem("salmon").text("Smoked Salmon").add()
  .newSeparator("and our speciality...").add()
  .newItem("special").text("Anchovies, and olives").checked(true).add()         // #9
  // .pageSize(10)                                                                 #10
  // .relativePageSize(66)																											   #11
  .addPrompt();

Description:

  1. With the prompt builder call createCheckboxPrompt() to create a new checkbox prompt builder.
  2. Set a name for the prompt.
  3. Add a message which is printed on top of the list.
  4. Use newSeparator() to add a separation element with a describing text.
  5. Use newItem() like in the list prompt to add selectable elements to the checkbox prompt.
  6. The name can be set directly with newItem(<name>) instead of using the name() method.
  7. With disabledText() the item is not selectable, the text is displayed after the item. Note: even when the item is disabled it can be checked by default.
  8. Use the check() method to pre-check the corresponding item.
  9. For more flexibility, you can use checked() with a boolean value to select if the item is checked by default.
  10. (optional) For long lists, you can use pageSize() to set an absolute number of items to display (default is 10). Even if you choose a higher value than the terminal, the list will never exceed the terminal height.
  11. (optional) Further you can use relativePageSize() to set a percentual size of the terminal as height. In this example, 66 is 66/100 or 2/3 of the terminal used for the list items. At least one line is displayed even when you select a very low value.

Console

checkbox_prompt

User input

The user can use up and down keys or VI like the keys 'j' for down and 'k' for moving the selector in front of the items to the right position. Toggling selection on an item is done with the space bar. Pressing the enter button finished the input.

After the input, the list is erased from the screen and the names of the selected values are printed in a different color right after the prompt.

Result

The result of this prompt is of type CheckboxResult and has a method getSelectedIds() to get user input which is of typeHashSet<String> containing the names of the selected items.

Expandable choice

The choice prompt lets the user choose one from a given number of possible answers. It is used for requesting input that would be done in a graphical user interface by a message box. It’s usable for choices like “yes/no/cancel”. Each entry is assigned to a single keystroke to provide a quick input by pressing that key.

By default, only the message and the possible keys are displayed which may make it difficult for new users to know what keystroke is associated with what answer. To get around this, a help mode is integrated. If the user pressed the ‘h’ button (for help), all possible answers with explanations are shown as a list where the user can choose from.

promptBuilder.createChoicePrompt()                                          // #1
  .name("payment")                                                          // #2
  .message("How do you want to pay?")                                       // #3
  .newItem().name("cash").message("Cash").key('c').asDefault().add()        // #4
  .newItem("visa").message("Visa Card").key('v').add()                      // #5
  .newItem("master").message("Master Card").key('m').add()
  .newSeparator("online payment").add()                                     // #6
  .newItem("paypal").message("Paypal").key('p').add()
  .addPrompt();

Description:

  1. With the prompt builder call createChoicePrompt() to create a new choice prompt builder.
  2. Set a name for the prompt.
  3. Add a message which is printed on the screen.
  4. Create new items with name, message, and an associated key. One of the items can be a default.
  5. Create other non-default items.
  6. Use newSeparator() to add a separation element with a describing text.

Console and user input

By default, the message is displayed and a list of all short keys for selection. The default value key is printed in upper case to indicate the default value. The letter ‘h’ is added to the list by default to activate the more detailed helpful list view.

expandable_choice_prompt_1

If the user presses one of the choice keys, the corresponding message is displayed and can be confirmed with the enter key.

expandable_choice_prompt_2

If the user presses the ‘h’ key, the long list is displayed.

expandable_choice_prompt_3

The detailed navigation is usable like the list prompt by pressing up and down arrow keys and selecting a value with the enter key.

Result

The result of this prompt is of type ExpandableChoiceResult and has a method getSelectedId() to get user input.

Confirmation

The confirmation prompt lets the user answer with ‘yes’ or ‘no’ to a given question. This is the minimalistic version of the choice prompt.

promptBuilder.createConfirmPromp()                       // #1
  .name("delivery")                                      // #2
  .message("Is this pizza for delivery?")                // #3
  .defaultValue(ConfirmChoice.ConfirmationValue.YES)     // #4
  .addPrompt();

Description:

  1. With the prompt builder call createChonfirmPrompt() to create a new confirmation prompt builder.
  2. Set a name for the prompt.
  3. Add a message which is printed as prompt.
  4. With defaultValue() you can set either ‘yes’ or ‘no’ as a default.

Console

confirmation_prompt

User input

By pressing ‘y’ or ‘n’ (or ‘j/n’ in the german localization) the user can select between ‘yes’ and ‘no’ as an answer. By pressing the enter key the user confirms the input.

Result

The result of this prompt is of type ConfirmResult and has a method getConfirmed() to get user input of type ConfirmChoice.ConfirmationValue which is an enum of either ‘YES’ or ‘NO’.