Skip to content

# Miscellaneous Features

## Timer

Turn the timer setting on, and `cmd2` will show the wall time it takes for each command to execute.

## Exiting

Like many shell applications, `cmd2` applications can be exited by pressing `Ctrl-D` on an empty line, or by executing the `quit` command.

## select

Presents numbered options to user, as bash `select`.

`app.select` is called from within a method (not by the user directly; it is `app.select`, not `app.do_select`).

## `` cmd2.Cmd.select

    select(opts, prompt='Your choice? ')

Present a menu to the user.

Modeled after the bash shell's SELECT. Returns the item chosen.

Argument `opts` can be:

| a single string -> will be split into one-word options | a list of strings -> will be offered as options | a list of tuples -> interpreted as (value, text), so that the return value can differ from the text advertised to the user

Source code in `cmd2/cmd2.py`

    4575
    4576
    4577
    4578
    4579
    4580
    4581
    4582
    4583
    4584
    4585
    4586
    4587
    4588
    4589
    4590
    4591
    4592
    4593
    4594
    4595
    4596
    4597
    4598
    4599
    4600
    4601
    4602
    4603
    4604
    4605
    4606
    4607
    4608
    4609
    4610
    4611
    4612
    4613
    4614
    4615
    4616
    4617
    4618
    4619
    4620
    4621
    4622
    4623
    4624
    4625
    4626
    4627
    4628
    4629
    4630
    4631
    4632
    4633
    4634
    4635
    4636
    4637
    4638
    4639

    def select(self, opts: str | Iterable[str] | Iterable[tuple[Any, str | None]], prompt: str = "Your choice? ") -> Any:
        """Present a menu to the user.

        Modeled after the bash shell's SELECT.  Returns the item chosen.

        Argument ``opts`` can be:

          | a single string -> will be split into one-word options
          | a list of strings -> will be offered as options
          | a list of tuples -> interpreted as (value, text), so
                                that the return value can differ from
                                the text advertised to the user
        """
        local_opts: Iterable[str] | Iterable[tuple[Any, str | None]]
        if isinstance(opts, str):
            local_opts = cast(list[tuple[Any, str | None]], list(zip(opts.split(), opts.split(), strict=False)))
        else:
            local_opts = opts
        fulloptions: list[tuple[Any, str]] = []
        for opt in local_opts:
            if isinstance(opt, str):
                fulloptions.append((opt, opt))
            else:
                try:
                    val = opt[0]
                    text = str(opt[1]) if len(opt) > 1 and opt[1] is not None else str(val)
                    fulloptions.append((val, text))
                except (IndexError, TypeError):
                    fulloptions.append((opt[0], str(opt[0])))

        if self._is_tty_session(self.main_session):
            try:
                while True:
                    with create_app_session(input=self.main_session.input, output=self.main_session.output):
                        result = choice(message=prompt, options=fulloptions)
                    if result is not None:
                        return result
            except KeyboardInterrupt:
                self.poutput("^C")
                raise

        # Non-interactive fallback
        for idx, (_, text) in enumerate(fulloptions):
            self.poutput("  %2d. %s" % (idx + 1, text))  # noqa: UP031

        while True:
            try:
                response = self.read_input(prompt)
            except EOFError:
                response = ""
                self.poutput()
            except KeyboardInterrupt:
                self.poutput("^C")
                raise

            if not response:
                continue

            try:
                choice_idx = int(response)
                if choice_idx < 1:
                    raise IndexError  # noqa: TRY301
                return fulloptions[choice_idx - 1][0]
            except (ValueError, IndexError):
                self.poutput(f"'{response}' isn't a valid choice. Pick a number between 1 and {len(fulloptions)}:")

    def do_eat(self, arg):
        sauce = self.select('sweet salty', 'Sauce? ')
        result = '{food} with {sauce} sauce, yum!'
        result = result.format(food=arg, sauce=sauce)
        self.stdout.write(result + '\n')

    (Cmd) eat wheaties
        1. sweet
        2. salty
    Sauce? 2
    wheaties with salty sauce, yum!

See the `do_eat` method in the read_input.py file for a example of how to use `select.

## Disabling Commands

`cmd2` supports disabling commands during runtime. This is useful if certain commands should only be available when the application is in a specific state. When a command is disabled, it will not show up in the help menu or tab complete. If a user tries to run the command, a command-specific message supplied by the developer will be printed. The following functions support this feature.

- enable_command : Enable an individual command
- enable_category : Enable an entire category of commands
- disable_command : Disable an individual command and set the message that will print when this command is run or help is called on it while disabled
- disable_category : Disable an entire category of commands and set the message that will print when anything in this category is run or help is called on it while disabled

See the definitions of these functions for descriptions of their arguments.

See the `do_enable_commands()` and `do_disable_commands()` functions in the help_categories.py example for a demonstration.