Skip to content

Commit 358ffe5

Browse files
committed
Added flag to configure prompt-toolkit tab-completion style
This defaults to the columnar way. But a user can set it to CompleteStyle.READLINE_LIKE to get readline style tab completion. Also: - Renamed `include_bottom_toolbar` flag to just `bottom_toolbar` - Renamed `_bottom_toolbar` method to `get_bottom_toolbar` which is a better name for it - Updated `examples/hello_cmd2.py` to use readline style tab-completion
1 parent dcd9183 commit 358ffe5

File tree

9 files changed

+43
-32
lines changed

9 files changed

+43
-32
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ shell, and the option for a persistent bottom bar that can display realtime stat
2727
`cmd2.Cmd.async_alert`
2828
- Enhancements
2929
- New optional persistent **bottom toolbar** capable of displaying realtime status information,
30-
see the `include_bottom_toolbar` optional argument to the initializer for `cmd2.Cmd` and the
31-
`cmd2.Cmd2._bottom_toolbar` method that can be overridden as well as the updated
30+
see the `bottom_toolbar` optional argument to the initializer for `cmd2.Cmd` and the
31+
`cmd2.Cmd2.get_bottom_toolbar` method that can be overridden as well as the updated
3232
`getting_started.py` example
3333
- Added `cmd2.Cmd._in_prompt` flag that is set to `True` when the prompt is displayed and the
3434
application is waiting for user input

cmd2/cmd2.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,9 @@ def __init__(
307307
auto_load_commands: bool = False,
308308
allow_clipboard: bool = True,
309309
suggest_similar_command: bool = False,
310-
include_bottom_toolbar: bool = False,
311310
intro: RenderableType = '',
311+
bottom_toolbar: bool = False,
312+
complete_style: CompleteStyle = CompleteStyle.COLUMN,
312313
) -> None:
313314
"""Easy but powerful framework for writing line-oriented command interpreters, extends Python's cmd package.
314315
@@ -358,8 +359,10 @@ def __init__(
358359
:param allow_clipboard: If False, cmd2 will disable clipboard interactions
359360
:param suggest_similar_command: if ``True``, then when a command is not found,
360361
[cmd2.Cmd][] will look for similar commands and suggest them.
361-
:param include_bottom_toolbar: if ``True``, then a bottom toolbar will be displayed.
362362
:param intro: introduction to display at startup
363+
:param bottom_toolbar: if ``True``, then a bottom toolbar will be displayed.
364+
:param complete_style: style of prompt-toolkit tab completion to use, defaults to CompleteStyle.COLUMN;
365+
set to CompleteStyle.READLINE_LIKE if you want it like readline
363366
"""
364367
# Check if py or ipy need to be disabled in this instance
365368
if not include_py:
@@ -450,13 +453,13 @@ def _(event: Any) -> None: # pragma: no cover
450453
# Initialize prompt-toolkit PromptSession
451454
self.history_adapter = Cmd2History(self)
452455
self.completer = Cmd2Completer(self)
453-
self.include_bottom_toolbar = include_bottom_toolbar
456+
self.bottom_toolbar = bottom_toolbar
454457

455458
try:
456459
self.session: PromptSession[str] = PromptSession(
457460
history=self.history_adapter,
458461
completer=self.completer,
459-
complete_style=CompleteStyle.COLUMN,
462+
complete_style=complete_style,
460463
complete_in_thread=True,
461464
complete_while_typing=False,
462465
key_bindings=key_bindings,
@@ -470,7 +473,7 @@ def _(event: Any) -> None: # pragma: no cover
470473
completer=self.completer,
471474
input=DummyInput(),
472475
output=DummyOutput(),
473-
complete_style=CompleteStyle.COLUMN,
476+
complete_style=complete_style,
474477
complete_in_thread=True,
475478
complete_while_typing=False,
476479
key_bindings=key_bindings,
@@ -1666,17 +1669,17 @@ def _reset_completion_defaults(self) -> None:
16661669
self.matches_delimited = False
16671670
self.matches_sorted = False
16681671

1669-
def _bottom_toolbar(self) -> list[str | tuple[str, str]] | None:
1672+
def get_bottom_toolbar(self) -> list[str | tuple[str, str]] | None:
16701673
"""Get the bottom toolbar content.
16711674
1672-
If self.include_bottom_toolbar is False, returns None.
1675+
If self.bottom_toolbar is False, returns None.
16731676
16741677
Otherwise returns tokens for prompt-toolkit to populate in the bottom toolbar.
16751678
16761679
NOTE: This content can extend over multiple lines. However we would recommend
16771680
keeping it to a single line or two lines maximum.
16781681
"""
1679-
if self.include_bottom_toolbar:
1682+
if self.bottom_toolbar:
16801683
import datetime
16811684
import shutil
16821685

@@ -3382,15 +3385,15 @@ def get_prompt() -> ANSI | str:
33823385
prompt_to_use,
33833386
completer=completer_to_use,
33843387
pre_run=self.pre_prompt,
3385-
bottom_toolbar=self._bottom_toolbar if self.include_bottom_toolbar else None,
3388+
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
33863389
)
33873390

33883391
# history is None
33893392
return self.session.prompt(
33903393
prompt_to_use,
33913394
completer=completer_to_use,
33923395
pre_run=self.pre_prompt,
3393-
bottom_toolbar=self._bottom_toolbar if self.include_bottom_toolbar else None,
3396+
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
33943397
)
33953398

33963399
# Otherwise read from self.stdin
@@ -3405,7 +3408,7 @@ def get_prompt() -> ANSI | str:
34053408
line = temp_session2.prompt(
34063409
prompt,
34073410
pre_run=self.pre_prompt,
3408-
bottom_toolbar=self._bottom_toolbar if self.include_bottom_toolbar else None,
3411+
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
34093412
)
34103413
if len(line) == 0:
34113414
raise EOFError
@@ -3420,7 +3423,7 @@ def get_prompt() -> ANSI | str:
34203423
)
34213424
line = temp_session3.prompt(
34223425
pre_run=self.pre_prompt,
3423-
bottom_toolbar=self._bottom_toolbar if self.include_bottom_toolbar else None,
3426+
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
34243427
)
34253428
if len(line) == 0:
34263429
raise EOFError

docs/features/initialization.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ The `cmd2.Cmd` class provides a large number of public instance attributes which
2525
Here are instance attributes of `cmd2.Cmd` which developers might wish to override:
2626

2727
- **always_show_hint**: if `True`, display tab completion hint even when completion suggestions print (Default: `False`)
28+
- **bottom_toolbar**: if `True`, then a bottom toolbar will be displayed (Default: `False`)
29+
- **complete_style**: style to display tab-completion hints in (from `CompleteStyle` options in `prompt-toolkit`)
2830
- **broken_pipe_warning**: if non-empty, this string will be displayed if a broken pipe error occurs
2931
- **continuation_prompt**: used for multiline commands on 2nd+ line of input
3032
- **debug**: if `True`, show full stack trace on error (Default: `False`)
@@ -41,7 +43,6 @@ Here are instance attributes of `cmd2.Cmd` which developers might wish to overri
4143
- **feedback_to_output**: if `True`, send nonessential output to stdout, if `False` send them to stderr (Default: `False`)
4244
- **help_error**: the error that prints when no help information can be found
4345
- **hidden_commands**: commands to exclude from the help menu and tab completion
44-
- **include_bottom_toolbar**: if `True`, then a bottom toolbar will be displayed (Default: `False`)
4546
- **last_result**: stores results from the last command run to enable usage of results in a Python script or interactive console. Built-in commands don't make use of this. It is purely there for user-defined commands and convenience.
4647
- **macros**: dictionary of macro names and their values
4748
- **max_completion_items**: max number of CompletionItems to display during tab completion (Default: 50)

docs/features/prompt.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,22 @@ terminal window while the application is idle and waiting for input.
5656

5757
### Enabling the Toolbar
5858

59-
To enable the toolbar, set `include_bottom_toolbar=True` in the [cmd2.Cmd.__init__][] constructor:
59+
To enable the toolbar, set `bottom_toolbar=True` in the [cmd2.Cmd.__init__][] constructor:
6060

6161
```py
6262
class App(cmd2.Cmd):
6363
def __init__(self):
64-
super().__init__(include_bottom_toolbar=True)
64+
super().__init__(bottom_toolbar=True)
6565
```
6666

6767
### Customizing Toolbar Content
6868

69-
You can customize the content of the toolbar by overriding the [cmd2.Cmd._bottom_toolbar][] method.
70-
This method should return either a string or a list of `(style, text)` tuples for formatted text.
69+
You can customize the content of the toolbar by overriding the [cmd2.Cmd.get_bottom_toolbar][]
70+
method. This method should return either a string or a list of `(style, text)` tuples for formatted
71+
text.
7172

7273
```py
73-
def _bottom_toolbar(self) -> list[str | tuple[str, str]] | None:
74+
def get_bottom_toolbar(self) -> list[str | tuple[str, str]] | None:
7475
return [
7576
('ansigreen', 'My Application Name'),
7677
('', ' - '),

docs/upgrades.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ While we have strived to maintain compatibility, there are some differences:
3636
`cmd2` now supports an optional, persistent bottom toolbar. This can be used to display information
3737
such as the application name, current state, or even a real-time clock.
3838

39-
- **Enablement**: Set `include_bottom_toolbar=True` in the [cmd2.Cmd.__init__][] constructor.
40-
- **Customization**: Override the [cmd2.Cmd._bottom_toolbar][] method to return the content you wish
41-
to display. The content can be a simple string or a list of `(style, text)` tuples for formatted
42-
text with colors.
39+
- **Enablement**: Set `bottom_toolbar=True` in the [cmd2.Cmd.__init__][] constructor.
40+
- **Customization**: Override the [cmd2.Cmd.get_bottom_toolbar][] method to return the content you
41+
wish to display. The content can be a simple string or a list of `(style, text)` tuples for
42+
formatted text with colors.
4343

4444
See the
4545
[getting_started.py](https://github.com/python-cmd2/cmd2/blob/main/examples/getting_started.py)

examples/getting_started.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def __init__(self) -> None:
4343
shortcuts = cmd2.DEFAULT_SHORTCUTS
4444
shortcuts.update({'&': 'intro'})
4545
super().__init__(
46-
include_bottom_toolbar=True,
46+
bottom_toolbar=True,
4747
include_ipy=True,
4848
multiline_commands=['echo'],
4949
persistent_history_file='cmd2_history.dat',

examples/hello_cmd2.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/usr/bin/env python
22
"""This is intended to be a completely bare-bones cmd2 application suitable for rapid testing and debugging."""
33

4+
from prompt_toolkit.shortcuts import CompleteStyle
5+
46
from cmd2 import (
57
cmd2,
68
)
@@ -9,8 +11,12 @@
911
import sys
1012

1113
# If run as the main application, simply start a bare-bones cmd2 application with only built-in functionality.
12-
# Enable commands to support interactive Python and IPython shells.
13-
app = cmd2.Cmd(include_py=True, include_ipy=True, persistent_history_file='cmd2_history.dat')
14+
app = cmd2.Cmd(
15+
complete_style=CompleteStyle.READLINE_LIKE, # Use readline style tab completion instead of prompt-toolkit style
16+
include_ipy=True, # Enable support for interactive Python shell via py command
17+
include_py=True, # Enable support for interactive IPython shell via ipy command
18+
persistent_history_file='cmd2_history.dat', # Persist history between runs
19+
)
1420
app.self_in_py = True # Enable access to "self" within the py command
1521
app.debug = True # Show traceback if/when an exception occurs
1622
sys.exit(app.cmdloop())

mkdocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ plugins:
7474
unwrap_annotated: true
7575
filters:
7676
- "!^_"
77-
- "_bottom_toolbar"
77+
- "get_bottom_toolbar"
7878
merge_init_into_class: true
7979
docstring_style: sphinx
8080
docstring_section_style: spacy

tests/test_cmd2.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3444,14 +3444,14 @@ def run_alert():
34443444
assert "Main thread is not at the prompt" in str(exceptions[0])
34453445

34463446

3447-
def test_bottom_toolbar(base_app, monkeypatch):
3447+
def test_get_bottom_toolbar(base_app, monkeypatch):
34483448
# Test default (disabled)
3449-
assert base_app._bottom_toolbar() is None
3449+
assert base_app.get_bottom_toolbar() is None
34503450

34513451
# Test enabled
3452-
base_app.include_bottom_toolbar = True
3452+
base_app.bottom_toolbar = True
34533453
monkeypatch.setattr(sys, 'argv', ['myapp.py'])
3454-
toolbar = base_app._bottom_toolbar()
3454+
toolbar = base_app.get_bottom_toolbar()
34553455
assert isinstance(toolbar, list)
34563456
assert toolbar[0] == ('ansigreen', 'myapp.py')
34573457
assert toolbar[2][0] == 'ansiblue'

0 commit comments

Comments
 (0)