Skip to content

Commit 1d59d5a

Browse files
committed
Revert "Remove bottom_toolbar parameter from cmd2.Cmd.__init__ and make default implementation of get_bottom_toolbar just return None."
This reverts commit 4d113c5.
1 parent 42f0db8 commit 1d59d5a

File tree

6 files changed

+50
-68
lines changed

6 files changed

+50
-68
lines changed

CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ 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
3539
- **complete_style**: (enum) style of prompt-toolkit tab completion to use, 3 valid options
3640
are:
3741
- 1. `CompleteStyle.COLUMN` (default) - displays hints with help next to them in one
@@ -46,8 +50,7 @@ shell, and the option for a persistent bottom bar that can display realtime stat
4650
- Added `cmd2.Cmd._in_prompt` flag that is set to `True` when the prompt is displayed and the
4751
application is waiting for user input
4852
- New `cmd2.Cmd` methods
49-
- **get_bottom_toolbar**: override to create and populates a bottom toolbar capable of
50-
displaying realtime status information while the prompt is displayed
53+
- **get_bottom_toolbar**: populates bottom toolbar if `bottom_toolbar` is `True`
5154
- **get_rprompt**: override to populate right prompt
5255
- **pre_prompt**: hook method that is called before the prompt is displayed, but after
5356
`prompt-toolkit` event loop has started

cmd2/cmd2.py

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

471474
self.auto_suggest = None
472475
if auto_suggest:
@@ -475,7 +478,7 @@ def _(event: Any) -> None: # pragma: no cover
475478
try:
476479
self.session: PromptSession[str] = PromptSession(
477480
auto_suggest=self.auto_suggest,
478-
bottom_toolbar=self.get_bottom_toolbar,
481+
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
479482
complete_in_thread=True,
480483
complete_style=complete_style,
481484
complete_while_typing=False,
@@ -490,7 +493,7 @@ def _(event: Any) -> None: # pragma: no cover
490493
# where isatty() is True but there is no real console.
491494
self.session = PromptSession(
492495
auto_suggest=self.auto_suggest,
493-
bottom_toolbar=self.get_bottom_toolbar,
496+
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
494497
complete_in_thread=True,
495498
complete_style=complete_style,
496499
complete_while_typing=False,
@@ -1698,14 +1701,35 @@ def _reset_completion_defaults(self) -> None:
16981701
def get_bottom_toolbar(self) -> list[str | tuple[str, str]] | None:
16991702
"""Get the bottom toolbar content.
17001703
1701-
Override this if you want a bottom toolbar to be displayed.
1704+
If self.bottom_toolbar is False, returns None.
17021705
1703-
:return: tokens for prompt-toolkit to populate in the bottom toolbar
1704-
or None for no bottom toolbar.
1706+
Otherwise returns tokens for prompt-toolkit to populate in the bottom toolbar.
17051707
17061708
NOTE: This content can extend over multiple lines. However we would recommend
17071709
keeping it to a single line or two lines maximum.
17081710
"""
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+
]
17091733
return None
17101734

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

34093433
return temp_session1.prompt(
34103434
prompt_to_use,
3411-
bottom_toolbar=self.get_bottom_toolbar,
3435+
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
34123436
completer=completer_to_use,
34133437
lexer=self.lexer,
34143438
pre_run=self.pre_prompt,
@@ -3418,7 +3442,7 @@ def get_prompt() -> ANSI | str:
34183442
# history is None
34193443
return self.session.prompt(
34203444
prompt_to_use,
3421-
bottom_toolbar=self.get_bottom_toolbar,
3445+
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
34223446
completer=completer_to_use,
34233447
lexer=self.lexer,
34243448
pre_run=self.pre_prompt,
@@ -3437,7 +3461,7 @@ def get_prompt() -> ANSI | str:
34373461
)
34383462
line = temp_session2.prompt(
34393463
prompt,
3440-
bottom_toolbar=self.get_bottom_toolbar,
3464+
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
34413465
pre_run=self.pre_prompt,
34423466
rprompt=self.get_rprompt,
34433467
)
@@ -3454,7 +3478,7 @@ def get_prompt() -> ANSI | str:
34543478
output=self.session.output,
34553479
)
34563480
line = temp_session3.prompt(
3457-
bottom_toolbar=self.get_bottom_toolbar,
3481+
bottom_toolbar=self.get_bottom_toolbar if self.bottom_toolbar else None,
34583482
pre_run=self.pre_prompt,
34593483
rprompt=self.get_rprompt,
34603484
)

docs/features/initialization.md

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

docs/upgrades.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +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 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.
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.
4243

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

examples/getting_started.py

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,9 @@
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
1817
"""
1918

20-
import datetime
2119
import pathlib
22-
import shutil
2320
import threading
2421
import time
2522

@@ -48,6 +45,7 @@ def __init__(self) -> None:
4845
shortcuts.update({'&': 'intro'})
4946
super().__init__(
5047
auto_suggest=True,
48+
bottom_toolbar=True,
5149
include_ipy=True,
5250
multiline_commands=['echo'],
5351
persistent_history_file='cmd2_history.dat',
@@ -98,26 +96,6 @@ def __init__(self) -> None:
9896
)
9997
)
10098

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-
12199
def get_rprompt(self) -> str | FormattedText | None:
122100
current_working_directory = pathlib.Path.cwd()
123101
style = 'bg:ansired fg:ansiwhite'

tests/test_cmd2.py

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3623,39 +3623,14 @@ 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-
36513626
def test_get_bottom_toolbar(base_app, monkeypatch):
36523627
# Test default (disabled)
36533628
assert base_app.get_bottom_toolbar() is None
36543629

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

38383813

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

3818+
base_app.bottom_toolbar = True
38433819
monkeypatch.setattr(sys, 'argv', ['myapp.py'])
38443820

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

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

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

0 commit comments

Comments
 (0)