Skip to content

Commit 4d113c5

Browse files
committed
Remove bottom_toolbar parameter from cmd2.Cmd.__init__ and make default implementation of get_bottom_toolbar just return None.
Adding a bottom toolbar is now purely dependent on overriding get_bottom_toolbar.
1 parent 20c09bb commit 4d113c5

File tree

6 files changed

+68
-50
lines changed

6 files changed

+68
-50
lines changed

CHANGELOG.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ shell, and the option for a persistent bottom bar that can display realtime stat
3232
- **auto_suggest**: (boolean) if `True`, provide fish shell style auto-suggestions. These
3333
are grayed-out hints based on history. User can press right-arrow key to accept the
3434
provided suggestion.
35-
- **bottom toolbar**: (boolean) if `True`, present a persistent bottom toolbar capable of
36-
displaying realtime status information while the prompt is displayed, see the
37-
`cmd2.Cmd2.get_bottom_toolbar` method that can be overridden as well as the updated
38-
`getting_started.py` example
3935
- **complete_style**: (enum) style of prompt-toolkit tab completion to use, 3 valid options
4036
are:
4137
- 1. `CompleteStyle.COLUMN` (default) - displays hints with help next to them in one
@@ -50,7 +46,8 @@ shell, and the option for a persistent bottom bar that can display realtime stat
5046
- Added `cmd2.Cmd._in_prompt` flag that is set to `True` when the prompt is displayed and the
5147
application is waiting for user input
5248
- New `cmd2.Cmd` methods
53-
- **get_bottom_toolbar**: populates bottom toolbar if `bottom_toolbar` is `True`
49+
- **get_bottom_toolbar**: override to create and populates a bottom toolbar capable of
50+
displaying realtime status information while the prompt is displayed
5451
- **get_rprompt**: override to populate right prompt
5552
- **pre_prompt**: hook method that is called before the prompt is displayed, but after
5653
`prompt-toolkit` event loop has started

cmd2/cmd2.py

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,6 @@ def __init__(
299299
allow_redirection: bool = True,
300300
auto_load_commands: bool = False,
301301
auto_suggest: bool = True,
302-
bottom_toolbar: bool = False,
303302
command_sets: Iterable[CommandSet] | None = None,
304303
complete_style: CompleteStyle = CompleteStyle.COLUMN,
305304
include_ipy: bool = False,
@@ -338,7 +337,6 @@ def __init__(
338337
must be manually installed with `register_command_set`.
339338
:param auto_suggest: If True, cmd2 will provide fish shell style auto-suggestions
340339
based on history. If False, these will not be provided.
341-
:param bottom_toolbar: if ``True``, then a bottom toolbar will be displayed.
342340
:param command_sets: Provide CommandSet instances to load during cmd2 initialization.
343341
This allows CommandSets with custom constructor parameters to be
344342
loaded. This also allows the a set of CommandSets to be provided
@@ -469,7 +467,6 @@ def _(event: Any) -> None: # pragma: no cover
469467
self.history_adapter = Cmd2History(self)
470468
self.completer = Cmd2Completer(self)
471469
self.lexer = Cmd2Lexer(self)
472-
self.bottom_toolbar = bottom_toolbar
473470

474471
self.auto_suggest = None
475472
if auto_suggest:
@@ -478,7 +475,7 @@ def _(event: Any) -> None: # pragma: no cover
478475
try:
479476
self.session: PromptSession[str] = PromptSession(
480477
auto_suggest=self.auto_suggest,
481-
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
478+
bottom_toolbar=self.get_bottom_toolbar,
482479
complete_in_thread=True,
483480
complete_style=complete_style,
484481
complete_while_typing=False,
@@ -493,7 +490,7 @@ def _(event: Any) -> None: # pragma: no cover
493490
# where isatty() is True but there is no real console.
494491
self.session = PromptSession(
495492
auto_suggest=self.auto_suggest,
496-
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
493+
bottom_toolbar=self.get_bottom_toolbar,
497494
complete_in_thread=True,
498495
complete_style=complete_style,
499496
complete_while_typing=False,
@@ -1701,35 +1698,14 @@ def _reset_completion_defaults(self) -> None:
17011698
def get_bottom_toolbar(self) -> list[str | tuple[str, str]] | None:
17021699
"""Get the bottom toolbar content.
17031700
1704-
If self.bottom_toolbar is False, returns None.
1701+
Override this if you want a bottom toolbar to be displayed.
17051702
1706-
Otherwise returns tokens for prompt-toolkit to populate in the bottom toolbar.
1703+
:return: tokens for prompt-toolkit to populate in the bottom toolbar
1704+
or None for no bottom toolbar.
17071705
17081706
NOTE: This content can extend over multiple lines. However we would recommend
17091707
keeping it to a single line or two lines maximum.
17101708
"""
1711-
if self.bottom_toolbar:
1712-
import datetime
1713-
import shutil
1714-
1715-
# Get the current time in ISO format with 0.01s precision
1716-
dt = datetime.datetime.now(datetime.timezone.utc).astimezone()
1717-
now = dt.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-4] + dt.strftime('%z')
1718-
left_text = sys.argv[0]
1719-
1720-
# Get terminal width to calculate padding for right-alignment
1721-
cols, _ = shutil.get_terminal_size()
1722-
padding_size = cols - len(left_text) - len(now) - 1
1723-
if padding_size < 1:
1724-
padding_size = 1
1725-
padding = ' ' * padding_size
1726-
1727-
# Return formatted text for prompt-toolkit
1728-
return [
1729-
('ansigreen', left_text),
1730-
('', padding),
1731-
('ansicyan', now),
1732-
]
17331709
return None
17341710

17351711
def get_rprompt(self) -> str | FormattedText | None:
@@ -3432,7 +3408,7 @@ def get_prompt() -> ANSI | str:
34323408

34333409
return temp_session1.prompt(
34343410
prompt_to_use,
3435-
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
3411+
bottom_toolbar=self.get_bottom_toolbar,
34363412
completer=completer_to_use,
34373413
lexer=self.lexer,
34383414
pre_run=self.pre_prompt,
@@ -3442,7 +3418,7 @@ def get_prompt() -> ANSI | str:
34423418
# history is None
34433419
return self.session.prompt(
34443420
prompt_to_use,
3445-
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
3421+
bottom_toolbar=self.get_bottom_toolbar,
34463422
completer=completer_to_use,
34473423
lexer=self.lexer,
34483424
pre_run=self.pre_prompt,
@@ -3461,7 +3437,7 @@ def get_prompt() -> ANSI | str:
34613437
)
34623438
line = temp_session2.prompt(
34633439
prompt,
3464-
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
3440+
bottom_toolbar=self.get_bottom_toolbar,
34653441
pre_run=self.pre_prompt,
34663442
rprompt=self.get_rprompt,
34673443
)
@@ -3478,7 +3454,7 @@ def get_prompt() -> ANSI | str:
34783454
output=self.session.output,
34793455
)
34803456
line = temp_session3.prompt(
3481-
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
3457+
bottom_toolbar=self.get_bottom_toolbar,
34823458
pre_run=self.pre_prompt,
34833459
rprompt=self.get_rprompt,
34843460
)

docs/features/initialization.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ 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`)
2928
- **complete_style**: style to display tab-completion hints in (from `CompleteStyle` options in `prompt-toolkit`)
3029
- **broken_pipe_warning**: if non-empty, this string will be displayed if a broken pipe error occurs
3130
- **continuation_prompt**: used for multiline commands on 2nd+ line of input

docs/upgrades.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,9 @@ 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 `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.
39+
- **Enablement and Customization**: Override the [cmd2.Cmd.get_bottom_toolbar][] method to return
40+
the content you wish to display. The content can be a simple string or a list of `(style, text)`
41+
tuples for formatted text with colors.
4342

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

examples/getting_started.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414
10) How to make custom attributes settable at runtime.
1515
11) Shortcuts for commands
1616
12) Persistent bottom toolbar with realtime status updates
17+
13) Right prompt contextual information display
1718
"""
1819

20+
import datetime
1921
import pathlib
22+
import shutil
2023
import threading
2124
import time
2225

@@ -45,7 +48,6 @@ def __init__(self) -> None:
4548
shortcuts.update({'&': 'intro'})
4649
super().__init__(
4750
auto_suggest=True,
48-
bottom_toolbar=True,
4951
include_ipy=True,
5052
multiline_commands=['echo'],
5153
persistent_history_file='cmd2_history.dat',
@@ -96,6 +98,26 @@ def __init__(self) -> None:
9698
)
9799
)
98100

101+
def get_bottom_toolbar(self) -> list[str | tuple[str, str]] | None:
102+
# Get the current time in ISO format with 0.01s precision
103+
dt = datetime.datetime.now(datetime.timezone.utc).astimezone()
104+
now = dt.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-4] + dt.strftime('%z')
105+
left_text = sys.argv[0]
106+
107+
# Get terminal width to calculate padding for right-alignment
108+
cols, _ = shutil.get_terminal_size()
109+
padding_size = cols - len(left_text) - len(now) - 1
110+
if padding_size < 1:
111+
padding_size = 1
112+
padding = ' ' * padding_size
113+
114+
# Return formatted text for prompt-toolkit
115+
return [
116+
('ansigreen', left_text),
117+
('', padding),
118+
('ansicyan', now),
119+
]
120+
99121
def get_rprompt(self) -> str | FormattedText | None:
100122
current_working_directory = pathlib.Path.cwd()
101123
style = 'bg:ansired fg:ansiwhite'

tests/test_cmd2.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3623,14 +3623,39 @@ def run_alert():
36233623
assert "Main thread is not at the prompt" in str(exceptions[0])
36243624

36253625

3626+
class ToolbarApp(cmd2.Cmd):
3627+
def get_bottom_toolbar(self) -> list[str | tuple[str, str]] | None:
3628+
import datetime
3629+
import shutil
3630+
3631+
# Get the current time in ISO format with 0.01s precision
3632+
dt = datetime.datetime.now(datetime.timezone.utc).astimezone()
3633+
now = dt.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-4] + dt.strftime('%z')
3634+
left_text = sys.argv[0]
3635+
3636+
# Get terminal width to calculate padding for right-alignment
3637+
cols, _ = shutil.get_terminal_size()
3638+
padding_size = cols - len(left_text) - len(now) - 1
3639+
if padding_size < 1:
3640+
padding_size = 1
3641+
padding = ' ' * padding_size
3642+
3643+
# Return formatted text for prompt-toolkit
3644+
return [
3645+
('ansigreen', left_text),
3646+
('', padding),
3647+
('ansicyan', now),
3648+
]
3649+
3650+
36263651
def test_get_bottom_toolbar(base_app, monkeypatch):
36273652
# Test default (disabled)
36283653
assert base_app.get_bottom_toolbar() is None
36293654

3630-
# Test enabled
3631-
base_app.bottom_toolbar = True
3655+
# Test overridden via custom class
36323656
monkeypatch.setattr(sys, 'argv', ['myapp.py'])
3633-
toolbar = base_app.get_bottom_toolbar()
3657+
app = ToolbarApp()
3658+
toolbar = app.get_bottom_toolbar()
36343659
assert isinstance(toolbar, list)
36353660
assert toolbar[0] == ('ansigreen', 'myapp.py')
36363661
assert toolbar[2][0] == 'ansicyan'
@@ -3811,19 +3836,19 @@ def my_pre_prompt():
38113836
assert loop_check['running']
38123837

38133838

3814-
def test_get_bottom_toolbar_narrow_terminal(base_app, monkeypatch):
3839+
def test_get_bottom_toolbar_narrow_terminal(monkeypatch):
38153840
"""Test get_bottom_toolbar when terminal is too narrow for calculated padding"""
38163841
import shutil
38173842

3818-
base_app.bottom_toolbar = True
38193843
monkeypatch.setattr(sys, 'argv', ['myapp.py'])
38203844

38213845
# Mock shutil.get_terminal_size to return a very small width (e.g. 5)
38223846
# Calculated padding_size = 5 - len('myapp.py') - len(now) - 1
38233847
# Since len(now) is ~29, this will definitely be < 1
38243848
monkeypatch.setattr(shutil, 'get_terminal_size', lambda: os.terminal_size((5, 20)))
38253849

3826-
toolbar = base_app.get_bottom_toolbar()
3850+
app = ToolbarApp()
3851+
toolbar = app.get_bottom_toolbar()
38273852
assert isinstance(toolbar, list)
38283853

38293854
# The padding (index 1) should be exactly 1 space

0 commit comments

Comments
 (0)