or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Simple Terminal Menu

1

2

A Python package which creates simple interactive menus on the command line. It provides customizable terminal menus with navigation, multi-selection, search functionality, and preview capabilities, supporting cross-platform terminal environments with automatic feature detection.

3

4

## Package Information

5

6

- **Package Name**: simple-term-menu

7

- **Language**: Python

8

- **Installation**: `pip install simple-term-menu`

9

- **Supported Platforms**: Linux, macOS

10

- **Python Version**: 3.5+

11

12

## Core Imports

13

14

```python

15

from simple_term_menu import TerminalMenu

16

```

17

18

For exceptions:

19

```python

20

from simple_term_menu import (

21

InvalidParameterCombinationError,

22

InvalidStyleError,

23

NoMenuEntriesError,

24

PreviewCommandFailedError,

25

UnknownMenuEntryError

26

)

27

```

28

29

For utility functions and constants:

30

```python

31

from simple_term_menu import (

32

get_locale,

33

wcswidth,

34

BoxDrawingCharacters,

35

# Default constants (optional, for customization)

36

DEFAULT_MENU_CURSOR,

37

DEFAULT_MENU_CURSOR_STYLE,

38

DEFAULT_QUIT_KEYS

39

)

40

```

41

42

For CLI functions:

43

```python

44

from simple_term_menu import main, parse_arguments, get_argumentparser

45

```

46

47

## Basic Usage

48

49

```python

50

from simple_term_menu import TerminalMenu

51

52

def main():

53

options = ["entry 1", "entry 2", "entry 3"]

54

terminal_menu = TerminalMenu(options)

55

menu_entry_index = terminal_menu.show()

56

57

if menu_entry_index is not None:

58

print(f"You have selected {options[menu_entry_index]}!")

59

else:

60

print("Menu was cancelled")

61

62

if __name__ == "__main__":

63

main()

64

```

65

66

Multi-selection example:

67

```python

68

from simple_term_menu import TerminalMenu

69

70

options = ["Option 1", "Option 2", "Option 3", "Option 4"]

71

terminal_menu = TerminalMenu(

72

options,

73

multi_select=True,

74

show_multi_select_hint=True

75

)

76

menu_entry_indices = terminal_menu.show()

77

78

if menu_entry_indices:

79

selected_options = [options[i] for i in menu_entry_indices]

80

print(f"Selected: {', '.join(selected_options)}")

81

```

82

83

Error handling example:

84

```python

85

from simple_term_menu import (

86

TerminalMenu,

87

NoMenuEntriesError,

88

InvalidParameterCombinationError,

89

PreviewCommandFailedError

90

)

91

92

try:

93

# Example of handling common errors

94

options = [] # Empty list will raise NoMenuEntriesError

95

terminal_menu = TerminalMenu(

96

options,

97

preview_command="invalid_command {}" # May cause PreviewCommandFailedError

98

)

99

result = terminal_menu.show()

100

101

except NoMenuEntriesError as e:

102

print(f"Error: No menu entries provided - {e}")

103

104

except InvalidParameterCombinationError as e:

105

print(f"Error: Invalid parameter combination - {e}")

106

107

except PreviewCommandFailedError as e:

108

print(f"Error: Preview command failed - {e}")

109

110

except KeyboardInterrupt:

111

print("Menu cancelled by user")

112

# Note: Set raise_error_on_interrupt=True to get this exception

113

114

except NotImplementedError as e:

115

print(f"Error: Platform not supported - {e}")

116

# Raised on Windows or when TERM environment variable is missing

117

```

118

119

## Capabilities

120

121

### Terminal Menu Creation

122

123

Creates interactive terminal menus with extensive customization options including cursor styles, keyboard shortcuts, multi-selection, search functionality, and preview windows.

124

125

```python { .api }

126

class TerminalMenu:

127

def __init__(

128

self,

129

menu_entries: Iterable[str],

130

*,

131

accept_keys: Iterable[str] = ("enter",),

132

clear_menu_on_exit: bool = True,

133

clear_screen: bool = False,

134

cursor_index: Optional[int] = None,

135

cycle_cursor: bool = True,

136

exit_on_shortcut: bool = True,

137

menu_cursor: Optional[str] = "> ",

138

menu_cursor_style: Optional[Iterable[str]] = ("fg_red", "bold"),

139

menu_highlight_style: Optional[Iterable[str]] = ("standout",),

140

multi_select: bool = False,

141

multi_select_cursor: str = "[*] ",

142

multi_select_cursor_brackets_style: Optional[Iterable[str]] = ("fg_gray",),

143

multi_select_cursor_style: Optional[Iterable[str]] = ("fg_yellow", "bold"),

144

multi_select_empty_ok: bool = False,

145

multi_select_keys: Optional[Iterable[str]] = (" ", "tab"),

146

multi_select_select_on_accept: bool = True,

147

preselected_entries: Optional[Iterable[Union[str, int]]] = None,

148

preview_border: bool = True,

149

preview_command: Optional[Union[str, Callable[[str], str]]] = None,

150

preview_size: float = 0.25,

151

preview_title: str = "preview",

152

quit_keys: Iterable[str] = ("escape", "q", "ctrl-g"),

153

raise_error_on_interrupt: bool = False,

154

search_case_sensitive: bool = False,

155

search_highlight_style: Optional[Iterable[str]] = ("fg_black", "bg_yellow", "bold"),

156

search_key: Optional[str] = "/",

157

shortcut_brackets_highlight_style: Optional[Iterable[str]] = ("fg_gray",),

158

shortcut_key_highlight_style: Optional[Iterable[str]] = ("fg_blue",),

159

show_multi_select_hint: bool = False,

160

show_multi_select_hint_text: Optional[str] = None,

161

show_search_hint: bool = False,

162

show_search_hint_text: Optional[str] = None,

163

show_shortcut_hints: bool = False,

164

show_shortcut_hints_in_status_bar: bool = True,

165

skip_empty_entries: bool = False,

166

status_bar: Optional[Union[str, Iterable[str], Callable[[str], str]]] = None,

167

status_bar_below_preview: bool = False,

168

status_bar_style: Optional[Iterable[str]] = ("fg_yellow", "bg_black"),

169

title: Optional[Union[str, Iterable[str]]] = None

170

):

171

"""

172

Create a terminal menu.

173

174

Parameters:

175

- menu_entries: List of menu entry strings to display

176

- accept_keys: Keys that accept the current selection

177

- clear_menu_on_exit: Whether to clear the menu when exiting

178

- clear_screen: Whether to clear the screen before showing the menu

179

- cursor_index: Initial cursor position (0-based index)

180

- cycle_cursor: Whether cursor wraps around at ends

181

- exit_on_shortcut: Whether to exit immediately on shortcut key

182

- menu_cursor: String to display as cursor

183

- menu_cursor_style: Style tuple for cursor (e.g., ("fg_red", "bold"))

184

- menu_highlight_style: Style tuple for highlighted entries

185

- multi_select: Enable multi-selection mode

186

- multi_select_cursor: Cursor for selected items in multi-select

187

- multi_select_cursor_brackets_style: Style for selection brackets

188

- multi_select_cursor_style: Style for multi-select cursor

189

- multi_select_empty_ok: Allow empty selection in multi-select

190

- multi_select_keys: Keys for toggling selection in multi-select

191

- multi_select_select_on_accept: Select current item on accept in multi-select

192

- preselected_entries: Pre-selected entries by string or index

193

- preview_border: Show border around preview area

194

- preview_command: Command or function to generate preview content

195

- preview_size: Preview area size as fraction of screen (0.0-1.0)

196

- preview_title: Title for preview area

197

- quit_keys: Keys that quit the menu without selection

198

- raise_error_on_interrupt: Raise exception on keyboard interrupt

199

- search_case_sensitive: Whether search is case sensitive

200

- search_highlight_style: Style for search highlighting

201

- search_key: Key to activate search mode

202

- shortcut_brackets_highlight_style: Style for shortcut brackets

203

- shortcut_key_highlight_style: Style for shortcut keys

204

- show_multi_select_hint: Show multi-select hint text

205

- show_multi_select_hint_text: Custom multi-select hint text

206

- show_search_hint: Show search hint text

207

- show_search_hint_text: Custom search hint text

208

- show_shortcut_hints: Show shortcut hints

209

- show_shortcut_hints_in_status_bar: Show shortcuts in status bar

210

- skip_empty_entries: Skip empty entries in navigation

211

- status_bar: Status bar content (string, list, or callable)

212

- status_bar_below_preview: Position status bar below preview

213

- status_bar_style: Style for status bar

214

- title: Menu title (string or list of strings)

215

"""

216

217

def show(self) -> Optional[Union[int, Tuple[int, ...]]]:

218

"""

219

Display the menu and wait for user interaction.

220

221

Returns:

222

- For single-select: Selected menu entry index (int) or None if cancelled

223

- For multi-select: Tuple of selected indices or None if cancelled

224

"""

225

```

226

227

### Menu Interaction Properties

228

229

Access information about the last menu interaction, including selected entries and the key used to accept the selection.

230

231

```python { .api }

232

@property

233

def chosen_accept_key(self) -> Optional[str]:

234

"""Key used to accept the last selection."""

235

236

@property

237

def chosen_menu_entry(self) -> Optional[str]:

238

"""Text of the last chosen menu entry (single-select)."""

239

240

@property

241

def chosen_menu_entries(self) -> Optional[Tuple[str, ...]]:

242

"""Texts of the last chosen menu entries (multi-select)."""

243

244

@property

245

def chosen_menu_index(self) -> Optional[int]:

246

"""Index of the last chosen menu entry (single-select)."""

247

248

@property

249

def chosen_menu_indices(self) -> Optional[Tuple[int, ...]]:

250

"""Indices of the last chosen menu entries (multi-select)."""

251

```

252

253

### Exception Handling

254

255

Custom exceptions for various error conditions that may occur during menu creation and operation.

256

257

```python { .api }

258

class InvalidParameterCombinationError(Exception):

259

"""Raised when incompatible parameters are used together."""

260

261

class InvalidStyleError(Exception):

262

"""Raised when an invalid style is specified."""

263

264

class NoMenuEntriesError(Exception):

265

"""Raised when no menu entries are provided."""

266

267

class PreviewCommandFailedError(Exception):

268

"""Raised when a preview command fails to execute."""

269

270

class UnknownMenuEntryError(Exception):

271

"""Raised when referencing a non-existent menu entry."""

272

```

273

274

### Box Drawing Characters

275

276

Provides platform-appropriate box drawing characters for terminal UIs. Automatically detects UTF-8 support and uses Unicode or ASCII characters accordingly.

277

278

```python { .api }

279

class BoxDrawingCharacters:

280

"""

281

Box drawing characters that adapt to terminal capabilities.

282

283

Uses Unicode box characters (─│┌┐└┘) for UTF-8 locales,

284

falls back to ASCII characters (-|+++) for other locales.

285

"""

286

horizontal: str # "─" or "-"

287

vertical: str # "│" or "|"

288

upper_left: str # "┌" or "+"

289

upper_right: str # "┐" or "+"

290

lower_left: str # "└" or "+"

291

lower_right: str # "┘" or "+"

292

```

293

294

### Utility Functions

295

296

Helper functions for locale handling and text width calculation, useful for custom terminal applications.

297

298

```python { .api }

299

def get_locale() -> str:

300

"""

301

Get the current system locale.

302

303

Returns:

304

Current locale string

305

"""

306

307

def wcswidth(text: str) -> int:

308

"""

309

Calculate the width of text considering wide characters.

310

311

Parameters:

312

- text: Text string to measure

313

314

Returns:

315

Width of the text in terminal columns

316

"""

317

```

318

319

### Command Line Interface

320

321

Functions for using simple-term-menu as a command-line tool, allowing integration with shell scripts and other tools.

322

323

```python { .api }

324

def main() -> None:

325

"""

326

Main entry point for command-line usage.

327

328

Parses command-line arguments and creates a terminal menu.

329

Available as 'simple-term-menu' console script.

330

331

Example usage:

332

simple-term-menu "Option 1" "Option 2" "Option 3"

333

simple-term-menu -m "Item 1" "Item 2" "Item 3" # Multi-select

334

echo -e "Choice A\\nChoice B\\nChoice C" | simple-term-menu

335

"""

336

337

def parse_arguments() -> AttributeDict:

338

"""

339

Parse command-line arguments for the CLI interface.

340

341

Returns:

342

Parsed arguments as AttributeDict

343

"""

344

345

def get_argumentparser() -> argparse.ArgumentParser:

346

"""

347

Create and return the argument parser for CLI usage.

348

349

Returns:

350

Configured ArgumentParser instance

351

"""

352

```

353

354

#### CLI Arguments

355

356

The command-line interface supports extensive configuration through these arguments:

357

358

**Navigation and Display:**

359

- `-s, --case-sensitive`: Make searches case sensitive

360

- `-X, --no-clear-menu-on-exit`: Do not clear the menu on exit

361

- `-l, --clear-screen`: Clear the screen before showing menu

362

- `-C, --no-cycle`: Do not cycle the menu selection

363

- `-E, --no-exit-on-shortcut`: Do not exit on shortcut keys

364

- `-i, --cursor-index N`: Initially selected item index (default: 0)

365

- `--cursor STR`: Menu cursor string (default: "> ")

366

367

**Styling:**

368

- `--cursor-style STYLES`: Cursor style as comma-separated list (default: "fg_red,bold")

369

- `--highlight-style STYLES`: Selected entry style (default: "standout")

370

- `--search-highlight-style STYLES`: Search highlight style (default: "fg_black,bg_yellow,bold")

371

372

**Multi-Selection:**

373

- `-m, --multi-select`: Enable multi-selection mode (implies --stdout)

374

- `--multi-select-cursor STR`: Multi-select cursor (default: "[*] ")

375

- `--multi-select-cursor-style STYLES`: Multi-select cursor style (default: "fg_yellow,bold")

376

- `--multi-select-cursor-brackets-style STYLES`: Bracket style (default: "fg_gray")

377

- `--multi-select-keys KEYS`: Toggle keys (default: " ,tab")

378

- `--multi-select-no-select-on-accept`: Don't select current item on accept

379

- `--multi-select-empty-ok`: Allow empty multi-selection

380

381

**Preview:**

382

- `-p, --preview COMMAND`: Preview command for entries

383

- `--preview-size FLOAT`: Preview area size as fraction (default: 0.25)

384

- `--preview-title STR`: Preview area title (default: "preview")

385

- `--no-preview-border`: Disable preview border

386

387

**Search:**

388

- `--search-key KEY`: Search activation key (default: "/")

389

- `--no-search-key`: Activate search on any letter key

390

391

**Shortcuts and Hints:**

392

- `--shortcut-key-highlight-style STYLES`: Shortcut key style (default: "fg_blue")

393

- `--shortcut-brackets-highlight-style STYLES`: Shortcut bracket style (default: "fg_gray")

394

- `--show-shortcut-hints`: Show shortcut hints

395

- `--show-multi-select-hint`: Show multi-select hint

396

- `--show-search-hint`: Show search hint

397

398

**Status Bar:**

399

- `--status-bar STR`: Status bar content

400

- `--status-bar-below-preview`: Position status bar below preview

401

- `--status-bar-style STYLES`: Status bar style (default: "fg_yellow,bg_black")

402

403

**Output:**

404

- `--stdout`: Output to stdout instead of stderr

405

- `--title STR`: Menu title

406

- `-V, --version`: Show version and exit

407

408

## Styling Options

409

410

The package supports extensive styling through tuples of style keywords:

411

412

### Color Options

413

- **Foreground colors**: `fg_black`, `fg_blue`, `fg_cyan`, `fg_gray`, `fg_green`, `fg_purple`, `fg_red`, `fg_yellow`

414

- **Background colors**: `bg_black`, `bg_blue`, `bg_cyan`, `bg_gray`, `bg_green`, `bg_purple`, `bg_red`, `bg_yellow`

415

416

### Style Options

417

- **Text formatting**: `bold`, `dim`, `italic`, `underline`, `blink`, `reverse`, `strikethrough`

418

- **Special**: `standout` (platform-specific highlighting)

419

420

Example styling:

421

```python

422

menu = TerminalMenu(

423

options,

424

menu_cursor_style=("fg_red", "bold"),

425

menu_highlight_style=("bg_blue", "fg_white"),

426

search_highlight_style=("bg_yellow", "fg_black", "bold")

427

)

428

```

429

430

## Keyboard Navigation

431

432

### Default Key Bindings

433

- **Navigation**: Arrow keys, `j`/`k` (vim-style), `Ctrl-n`/`Ctrl-p` (emacs-style), Page Up/Down, `Ctrl-f`/`Ctrl-b`

434

- **Selection**: Enter (accept), Space/Tab (multi-select toggle)

435

- **Search**: `/` (activate search), Escape (exit search)

436

- **Exit**: Escape, `q`, `Ctrl-g`, `Ctrl-c`

437

438

### Shortcut Keys

439

Menu entries can include shortcut keys for quick selection. Enclose the shortcut character in brackets:

440

```python

441

options = ["[a]pple", "[b]anana", "[c]herry"]

442

menu = TerminalMenu(options)

443

```

444

445

### Search Feature

446

Built-in search functionality allows filtering menu entries:

447

- Default search key: `/` (like vim, less)

448

- Search supports regex patterns

449

- Set `search_key=None` to activate search on any letter key

450

- Case sensitivity controlled by `search_case_sensitive` parameter

451

452

### Custom Key Configuration

453

Keys can be customized through the various `*_keys` parameters. Keys are specified as strings:

454

- Single characters: `"a"`, `"/"`, `" "` (space)

455

- Special keys: `"enter"`, `"escape"`, `"tab"`, `"space"`

456

- Control combinations: `"ctrl-g"`, `"ctrl-c"`

457

- Alt combinations: `"alt-a"`, `"alt-x"`

458

459

## Types

460

461

```python { .api }

462

from typing import Iterable, Optional, Union, Tuple, Callable, Any, Dict

463

464

# Menu entry types

465

MenuEntry = str

466

MenuEntries = Iterable[MenuEntry]

467

468

# Selection result types

469

SingleSelection = Optional[int]

470

MultiSelection = Optional[Tuple[int, ...]]

471

Selection = Union[SingleSelection, MultiSelection]

472

473

# Style specification

474

StyleTuple = Tuple[str, ...]

475

Style = Optional[StyleTuple]

476

477

# Preview command types

478

PreviewCommand = Union[str, Callable[[str], str]]

479

480

# Status bar types

481

StatusBar = Union[str, Iterable[str], Callable[[str], str]]

482

483

# Title types

484

Title = Union[str, Iterable[str]]

485

486

# CLI argument dictionary

487

class AttributeDict(dict):

488

"""

489

Dictionary that allows attribute-style access to keys.

490

491

Used by parse_arguments() to return CLI arguments that can be

492

accessed as attributes (args.multi_select) or dict keys (args['multi_select']).

493

"""

494

def __getattr__(self, attr: str) -> Any: ...

495

def __setattr__(self, attr: str, value: Any) -> None: ...

496

497

# Key specification types

498

KeySpec = str # Key names like "enter", "escape", "ctrl-g", "alt-x"

499

KeySequence = Iterable[KeySpec]

500

501

# Preselection types

502

PreselectedEntry = Union[str, int] # Menu entry by text or index

503

PreselectedEntries = Iterable[PreselectedEntry]

504

```

505

506

## Module Constants

507

508

### Version and Package Information

509

510

```python { .api }

511

__author__: str = "Ingo Meyer"

512

__email__: str = "i.meyer@fz-juelich.de"

513

__copyright__: str = "Copyright © 2021 Forschungszentrum Jülich GmbH. All rights reserved."

514

__license__: str = "MIT"

515

__version_info__: Tuple[int, int, int] = (1, 6, 6)

516

__version__: str = "1.6.6"

517

```

518

519

### Default Configuration Values

520

521

Default parameter values used by TerminalMenu constructor:

522

523

```python { .api }

524

# Navigation and behavior defaults

525

DEFAULT_ACCEPT_KEYS: Tuple[str, ...] = ("enter",)

526

DEFAULT_QUIT_KEYS: Tuple[str, ...] = ("escape", "q", "ctrl-g")

527

DEFAULT_CYCLE_CURSOR: bool = True

528

DEFAULT_EXIT_ON_SHORTCUT: bool = True

529

530

# Display defaults

531

DEFAULT_CLEAR_MENU_ON_EXIT: bool = True

532

DEFAULT_CLEAR_SCREEN: bool = False

533

DEFAULT_MENU_CURSOR: str = "> "

534

DEFAULT_MENU_CURSOR_STYLE: Tuple[str, ...] = ("fg_red", "bold")

535

DEFAULT_MENU_HIGHLIGHT_STYLE: Tuple[str, ...] = ("standout",)

536

537

# Multi-selection defaults

538

DEFAULT_MULTI_SELECT: bool = False

539

DEFAULT_MULTI_SELECT_CURSOR: str = "[*] "

540

DEFAULT_MULTI_SELECT_CURSOR_BRACKETS_STYLE: Tuple[str, ...] = ("fg_gray",)

541

DEFAULT_MULTI_SELECT_CURSOR_STYLE: Tuple[str, ...] = ("fg_yellow", "bold")

542

DEFAULT_MULTI_SELECT_KEYS: Tuple[str, ...] = (" ", "tab")

543

DEFAULT_MULTI_SELECT_SELECT_ON_ACCEPT: bool = True

544

545

# Search defaults

546

DEFAULT_SEARCH_CASE_SENSITIVE: bool = False

547

DEFAULT_SEARCH_HIGHLIGHT_STYLE: Tuple[str, ...] = ("fg_black", "bg_yellow", "bold")

548

DEFAULT_SEARCH_KEY: str = "/"

549

550

# Preview defaults

551

DEFAULT_PREVIEW_BORDER: bool = True

552

DEFAULT_PREVIEW_SIZE: float = 0.25

553

DEFAULT_PREVIEW_TITLE: str = "preview"

554

555

# Shortcut and hint defaults

556

DEFAULT_SHORTCUT_BRACKETS_HIGHLIGHT_STYLE: Tuple[str, ...] = ("fg_gray",)

557

DEFAULT_SHORTCUT_KEY_HIGHLIGHT_STYLE: Tuple[str, ...] = ("fg_blue",)

558

DEFAULT_SHOW_MULTI_SELECT_HINT: bool = False

559

DEFAULT_SHOW_SEARCH_HINT: bool = False

560

DEFAULT_SHOW_SHORTCUT_HINTS: bool = False

561

DEFAULT_SHOW_SHORTCUT_HINTS_IN_STATUS_BAR: bool = True

562

563

# Status bar defaults

564

DEFAULT_STATUS_BAR_BELOW_PREVIEW: bool = False

565

DEFAULT_STATUS_BAR_STYLE: Tuple[str, ...] = ("fg_yellow", "bg_black")

566

567

# Layout constraints

568

MIN_VISIBLE_MENU_ENTRIES_COUNT: int = 3

569

```