Capp — Console Application Package

Capp is the package that powers Finch's command system. It provides argument parsing, option management, formatted terminal output (tables, colors, progress bars), and interactive user input.

You interact with Capp indirectly through Finch's app.commands.add(CappController(...)) API. See Commands for how to register commands in a Finch app.

This page documents the Capp package directly, which is useful if you need advanced console features.

Elements

  • Progress indicators — show a spinner or progress bar during long operations
  • Yes/No input fields — prompt the user with a boolean question
  • Text/Number input fields — read a string or number from stdin
  • Multiple-choice input fields — present a list of options to select from
  • Multi-option selectors — select multiple items from a list
  • Table views — print structured data in an ASCII table
  • JSON viewer — pretty-print a JSON object

Features

  • Argument and Option Management — Define named options with short aliases (-t, --test).
  • User Input Handling — Read input from the terminal with prompts.
  • Structured Output — Display tables and colored messages in the console.
  • Automatic Help Generation--help is generated automatically from your option definitions.

Basic Setup

In a standalone Capp program (outside of Finch):

import 'package:capp/capp.dart';

void main([List<String> args = const []]) {
  var app = CappManager(
    main: CappController(
      '',
      options: [
        CappOption(
          name: 'help',
          shortName: 'h',
          description: 'Show help',
        ),
        CappOption(
          name: 'name',
          shortName: 'n',
          description: 'Your name',
          hasValue: true,
        ),
      ],
      run: (c) async {
        if (c.existsOption('help')) {
          c.showHelp();
          return CappConsole('', CappColors.none);
        }
        var name = c.getOption('name') ?? 'World';
        return CappConsole('Hello, $name!', CappColors.success);
      },
    ),
  );

  app.run(args);
}

Table Output

CappConsole.writeTable(
  [
    ['ID', 'Name', 'Email'],           // header row
    ['1', 'Alice', '[email protected]'],
    ['2', 'Bob',   '[email protected]'],
  ],
  dubleBorder: true,
  color: CappColors.info,
);

Color Reference

Value Color
CappColors.success Green
CappColors.warning Yellow
CappColors.error Red
CappColors.info Cyan
CappColors.none Default terminal color

User Input

// Yes/No prompt
bool confirm = await CappConsole.readBool('Are you sure?');

// Text input
String name = await CappConsole.readString('Enter your name: ');

// Number input
int count = await CappConsole.readInt('How many records?');

// Select from a list
int index = await CappConsole.select(
  'Choose an environment:',
  ['development', 'staging', 'production'],
);

Elements

  • Progress indicators
  • Yes/No input fields
  • Text/Number input fields
  • Multiple-choice input fields
  • Multi-option selectors
  • Table views
  • Json viewer

Features

  • Argument and Option Management: Define and manage command-line arguments and options easily.
  • User Input Handling: Supports reading user inputs with prompts and selection options.
  • Structured Output: Display tables, messages in color, and various progress indicators in the console.
  • Help Generation: Automatically generate a help guide for your console commands and options.

Getting Started

  1. Add capp to your pubspec.yaml.
  2. Import package:capp/capp.dart.
  3. Create commands, options, and user inputs to build your interactive console application.

Example Usage

import "package:capp/capp.dart";

void main([
  List<String> args = const [],
]) {
  var app = CappManager(
    main: CappController(
      '',
      options: [
        CappOption(
          name: 'help',
          shortName: 'h',
          description: 'Show help',
        ),
      ],
      run: (c) async {
        if (c.existsOption('help')) {
          return CappConsole(c.manager.getHelp());
        } else {
          return test(c);
        }
      },
    ),
    args: args,
    controllers: [
      CappController(
        'test',
        options: [],
        run: test,
      ),
    ],
  );

  app.process();
}

Future<CappConsole> test(c) async {
  const options = [
    'Progress circle',
    'Progress bar',
    'Progress spinner',
    'Yes/No questions',
    'Input text',
    'Make a table',
    'Clear screen',
    'Help',
    'Exit',
  ];
  var select = CappConsole.select(
    'Select an option to test Widgets of console:',
    options,
  );
  CappConsole.write('Your selection is: $select', CappColors.success);

  // Progress circle
  if (select == options[0]) {
    await CappConsole.progress(
      'I am waiting here for 5 secounds!',
      () async => Future.delayed(Duration(seconds: 5)),
      type: CappProgressType.circle,
    );
  }
  // Progress bar
  else if (select == options[1]) {
    await CappConsole.progress(
      'I am waiting here for 5 secounds!',
      () async => Future.delayed(Duration(seconds: 5)),
      type: CappProgressType.bar,
    );
  }
  // Progress spinner
  else if (select == options[2]) {
    await CappConsole.progress(
      'I am waiting here for 5 secounds!',
      () async => Future.delayed(Duration(seconds: 5)),
      type: CappProgressType.spinner,
    );
  }
  // Yes/No Questions
  else if (select == options[3]) {
    final res = await CappConsole.yesNo('Do you agree? ');
    CappConsole.write(
      "Your answer is ${res ? 'YES' : 'NO'}",
      CappColors.warning,
    );
  }
  // Input text
  else if (select == options[4]) {
    var age = CappConsole.read(
      'What is your age?',
      isRequired: true,
      isNumber: true,
    );

    CappConsole.write(
      "Your age is: $age",
      CappColors.success,
    );
  }
  // Make a table
  else if (select == options[5]) {
    const table = [
      ['#', 'Name', 'Age', 'City', 'Job'],
      ['1', 'Farhad', '38', 'Amsterdam', 'Engineer'],
      ['2', 'Adrian', '25', 'Berlin', 'Teacher'],
      ['3', 'Arian', '33', 'Frankfort', 'Taxi driver']
    ];

    CappConsole.writeTable(table);

    CappConsole.writeTable(
      table,
      color: CappColors.warning,
      dubleBorder: true,
    );
  }
  // Clear Screen
  else if (select == options[6]) {
    CappConsole.clear();
  }
  // Help
  else if (select == options[7]) {
    CappConsole.write(c.manager.getHelp());
  } else if (select == options.last) {
    return CappConsole('Exit!');
  }

  return test(c);
}

Example Output

$ dart ./example/example.dart


Select an option to test Widgets of console:

  [1]. Progress circle
  [2]. Progress bar
  [3]. Progress spinner
  [4]. Yes/No questions
  [5]. Input text
  [6]. Make a table
  [7]. Clear screen
  [8]. Help
  [9]. Exit


Enter the number of the option: 1
Your selection is: Progress circle
I am waiting here for 5 secounds!               ⢿                            


Select an option to test Widgets of console:

  [1]. Progress circle
  [2]. Progress bar
  [3]. Progress spinner
  [4]. Yes/No questions
  [5]. Input text
  [6]. Make a table
  [7]. Clear screen
  [8]. Help
  [9]. Exit


Enter the number of the option: 2
Your selection is: Progress bar
I am waiting here for 5 secounds! █████░████████                            


Select an option to test Widgets of console:

  [1]. Progress circle
  [2]. Progress bar
  [3]. Progress spinner
  [4]. Yes/No questions
  [5]. Input text
  [6]. Make a table
  [7]. Clear screen
  [8]. Help
  [9]. Exit


Enter the number of the option: 3
Your selection is: Progress spinner
I am waiting here for 5 secounds! |----->-------|                          


Select an option to test Widgets of console:

  [1]. Progress circle
  [2]. Progress bar
  [3]. Progress spinner
  [4]. Yes/No questions
  [5]. Input text
  [6]. Make a table
  [7]. Clear screen
  [8]. Help
  [9]. Exit


Enter the number of the option: 4
Your selection is: Yes/No questions


Do you agree?  (y/n): N
Your answer is NO


Select an option to test Widgets of console:

  [1]. Progress circle
  [2]. Progress bar
  [3]. Progress spinner
  [4]. Yes/No questions
  [5]. Input text
  [6]. Make a table
  [7]. Clear screen
  [8]. Help
  [9]. Exit


Enter the number of the option: 5
Your selection is: Input text


What is your age? 33
Your age is: 33


Select an option to test Widgets of console:

  [1]. Progress circle
  [2]. Progress bar
  [3]. Progress spinner
  [4]. Yes/No questions
  [5]. Input text
  [6]. Make a table
  [7]. Clear screen
  [8]. Help
  [9]. Exit


Enter the number of the option: 5
Your selection is: Input text


What is your age? 33
Your age is: 33


Select an option to test Widgets of console:

  [1]. Progress circle
  [2]. Progress bar
  [3]. Progress spinner
  [4]. Yes/No questions
  [5]. Input text
  [6]. Make a table
  [7]. Clear screen
  [8]. Help
  [9]. Exit


Enter the number of the option: 6
Your selection is: Make a table
┌───┬────────┬─────┬────────────┬─────────────┐
│ # │  Name  │ Age │    City    │     Job     │
├───┼────────┼─────┼────────────┼─────────────┤
│ 1 │ Farhad │ 38  │ Amsterdam  │ Engineer    │
├───┼────────┼─────┼────────────┼─────────────┤
│ 2 │ Adrian │ 25  │ Berlin     │ Teacher     │
├───┼────────┼─────┼────────────┼─────────────┤
│ 3 │ Arian  │ 33  │ Frankfort  │ Taxi driver │
└───┴────────┴─────┴────────────┴─────────────┘

╔═══╦════════╦═════╦════════════╦═════════════╗
║ # ║  Name  ║ Age ║    City    ║     Job     ║
╠═══╬════════╬═════╬════════════╬═════════════╣
║ 1 ║ Farhad ║ 38  ║ Amsterdam  ║ Engineer    ║
╠═══╬════════╬═════╬════════════╬═════════════╣
║ 2 ║ Adrian ║ 25  ║ Berlin     ║ Teacher     ║
╠═══╬════════╬═════╬════════════╬═════════════╣
║ 3 ║ Arian  ║ 33  ║ Frankfort  ║ Taxi driver ║
╚═══╩════════╩═════╩════════════╩═════════════╝



Select an option to test Widgets of console:

  [1]. Progress circle
  [2]. Progress bar
  [3]. Progress spinner
  [4]. Yes/No questions
  [5]. Input text
  [6]. Make a table
  [7]. Clear screen
  [8]. Help
  [9]. Exit


Enter the number of the option: 8
Your selection is: Help
Available commands:
1) test:
──────────────────────────────


      --help    Show help
      -h
──────────────────────────────