hspylib-clitt 0.9.120__py3-none-any.whl → 0.9.122__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hspylib-clitt might be problematic. Click here for more details.
- clitt/.version +1 -1
- clitt/__init__.py +3 -3
- clitt/addons/__init__.py +3 -3
- clitt/addons/appman/__init__.py +3 -3
- clitt/addons/appman/templates/__init__.py +3 -3
- clitt/addons/widman/__init__.py +3 -3
- clitt/addons/widman/widgets/__init__.py +3 -3
- clitt/core/__init__.py +3 -3
- clitt/core/exception/__init__.py +3 -3
- clitt/core/icons/__init__.py +3 -3
- clitt/core/icons/emojis/__init__.py +3 -3
- clitt/core/icons/font_awesome/__init__.py +3 -3
- clitt/core/term/__init__.py +3 -3
- clitt/core/tui/__init__.py +3 -3
- clitt/core/tui/line_input/__init__.py +3 -3
- clitt/core/tui/line_input/keyboard_input.py +104 -61
- clitt/core/tui/mchoose/__init__.py +3 -3
- clitt/core/tui/mdashboard/__init__.py +3 -3
- clitt/core/tui/menu/__init__.py +3 -3
- clitt/core/tui/minput/__init__.py +3 -3
- clitt/core/tui/minput/menu_input.py +7 -15
- clitt/core/tui/mselect/__init__.py +3 -3
- clitt/core/tui/table/__init__.py +3 -3
- clitt/utils/__init__.py +3 -3
- {hspylib_clitt-0.9.120.dist-info → hspylib_clitt-0.9.122.dist-info}/METADATA +2 -2
- hspylib_clitt-0.9.122.dist-info/RECORD +97 -0
- {hspylib_clitt-0.9.120.dist-info → hspylib_clitt-0.9.122.dist-info}/top_level.txt +0 -1
- build/lib/build/lib/build/lib/clitt/__classpath__.py +0 -28
- build/lib/build/lib/build/lib/clitt/__init__.py +0 -13
- build/lib/build/lib/build/lib/clitt/__main__.py +0 -139
- build/lib/build/lib/build/lib/clitt/addons/__init__.py +0 -12
- build/lib/build/lib/build/lib/clitt/addons/appman/__init__.py +0 -13
- build/lib/build/lib/build/lib/clitt/addons/appman/appman.py +0 -305
- build/lib/build/lib/build/lib/clitt/addons/appman/appman_enums.py +0 -39
- build/lib/build/lib/build/lib/clitt/addons/appman/templates/__init__.py +0 -11
- build/lib/build/lib/build/lib/clitt/addons/widman/__init__.py +0 -14
- build/lib/build/lib/build/lib/clitt/addons/widman/widget.py +0 -70
- build/lib/build/lib/build/lib/clitt/addons/widman/widget_entry.py +0 -54
- build/lib/build/lib/build/lib/clitt/addons/widman/widgets/__init__.py +0 -14
- build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_free.py +0 -110
- build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_punch.py +0 -246
- build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_send_msg.py +0 -272
- build/lib/build/lib/build/lib/clitt/addons/widman/widgets/widget_time_calc.py +0 -146
- build/lib/build/lib/build/lib/clitt/addons/widman/widman.py +0 -123
- build/lib/build/lib/build/lib/clitt/core/__init__.py +0 -15
- build/lib/build/lib/build/lib/clitt/core/exception/__init__.py +0 -11
- build/lib/build/lib/build/lib/clitt/core/exception/exceptions.py +0 -19
- build/lib/build/lib/build/lib/clitt/core/icons/__init__.py +0 -12
- build/lib/build/lib/build/lib/clitt/core/icons/emojis/__init__.py +0 -12
- build/lib/build/lib/build/lib/clitt/core/icons/emojis/emojis.py +0 -41
- build/lib/build/lib/build/lib/clitt/core/icons/emojis/face_smiling.py +0 -40
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/__init__.py +0 -18
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/app_icons.py +0 -55
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/awesome.py +0 -76
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/dashboard_icons.py +0 -93
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/form_icons.py +0 -69
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/game_icons.py +0 -59
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/nav_icons.py +0 -42
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/trickplay_icons.py +0 -39
- build/lib/build/lib/build/lib/clitt/core/icons/font_awesome/widget_icons.py +0 -37
- build/lib/build/lib/build/lib/clitt/core/preferences.py +0 -87
- build/lib/build/lib/build/lib/clitt/core/term/__init__.py +0 -14
- build/lib/build/lib/build/lib/clitt/core/term/commons.py +0 -106
- build/lib/build/lib/build/lib/clitt/core/term/cursor.py +0 -174
- build/lib/build/lib/build/lib/clitt/core/term/screen.py +0 -106
- build/lib/build/lib/build/lib/clitt/core/term/terminal.py +0 -202
- build/lib/build/lib/build/lib/clitt/core/tui/__init__.py +0 -20
- build/lib/build/lib/build/lib/clitt/core/tui/line_input/__init__.py +0 -12
- build/lib/build/lib/build/lib/clitt/core/tui/line_input/keyboard_input.py +0 -229
- build/lib/build/lib/build/lib/clitt/core/tui/line_input/line_input.py +0 -31
- build/lib/build/lib/build/lib/clitt/core/tui/mchoose/__init__.py +0 -12
- build/lib/build/lib/build/lib/clitt/core/tui/mchoose/mchoose.py +0 -43
- build/lib/build/lib/build/lib/clitt/core/tui/mchoose/menu_choose.py +0 -192
- build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/__init__.py +0 -14
- build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_builder.py +0 -54
- build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_item.py +0 -31
- build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/mdashboard.py +0 -26
- build/lib/build/lib/build/lib/clitt/core/tui/mdashboard/menu_dashboard.py +0 -148
- build/lib/build/lib/build/lib/clitt/core/tui/menu/__init__.py +0 -16
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu.py +0 -111
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_action.py +0 -47
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_factory.py +0 -117
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_item.py +0 -196
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_ui.py +0 -98
- build/lib/build/lib/build/lib/clitt/core/tui/menu/tui_menu_view.py +0 -57
- build/lib/build/lib/build/lib/clitt/core/tui/minput/__init__.py +0 -19
- build/lib/build/lib/build/lib/clitt/core/tui/minput/access_type.py +0 -26
- build/lib/build/lib/build/lib/clitt/core/tui/minput/field_builder.py +0 -117
- build/lib/build/lib/build/lib/clitt/core/tui/minput/form_builder.py +0 -72
- build/lib/build/lib/build/lib/clitt/core/tui/minput/form_field.py +0 -180
- build/lib/build/lib/build/lib/clitt/core/tui/minput/input_type.py +0 -30
- build/lib/build/lib/build/lib/clitt/core/tui/minput/input_validator.py +0 -98
- build/lib/build/lib/build/lib/clitt/core/tui/minput/menu_input.py +0 -292
- build/lib/build/lib/build/lib/clitt/core/tui/minput/minput.py +0 -44
- build/lib/build/lib/build/lib/clitt/core/tui/minput/minput_utils.py +0 -156
- build/lib/build/lib/build/lib/clitt/core/tui/mselect/__init__.py +0 -12
- build/lib/build/lib/build/lib/clitt/core/tui/mselect/menu_select.py +0 -170
- build/lib/build/lib/build/lib/clitt/core/tui/mselect/mselect.py +0 -36
- build/lib/build/lib/build/lib/clitt/core/tui/table/__init__.py +0 -12
- build/lib/build/lib/build/lib/clitt/core/tui/table/table_enums.py +0 -47
- build/lib/build/lib/build/lib/clitt/core/tui/table/table_renderer.py +0 -339
- build/lib/build/lib/build/lib/clitt/core/tui/tui_application.py +0 -52
- build/lib/build/lib/build/lib/clitt/core/tui/tui_component.py +0 -154
- build/lib/build/lib/build/lib/clitt/core/tui/tui_preferences.py +0 -103
- build/lib/build/lib/build/lib/clitt/utils/__init__.py +0 -11
- build/lib/build/lib/build/lib/clitt/utils/git_utils.py +0 -66
- build/lib/build/lib/clitt/__classpath__.py +0 -28
- build/lib/build/lib/clitt/__init__.py +0 -13
- build/lib/build/lib/clitt/__main__.py +0 -139
- build/lib/build/lib/clitt/addons/__init__.py +0 -12
- build/lib/build/lib/clitt/addons/appman/__init__.py +0 -13
- build/lib/build/lib/clitt/addons/appman/appman.py +0 -305
- build/lib/build/lib/clitt/addons/appman/appman_enums.py +0 -39
- build/lib/build/lib/clitt/addons/appman/templates/__init__.py +0 -11
- build/lib/build/lib/clitt/addons/widman/__init__.py +0 -14
- build/lib/build/lib/clitt/addons/widman/widget.py +0 -70
- build/lib/build/lib/clitt/addons/widman/widget_entry.py +0 -54
- build/lib/build/lib/clitt/addons/widman/widgets/__init__.py +0 -14
- build/lib/build/lib/clitt/addons/widman/widgets/widget_free.py +0 -110
- build/lib/build/lib/clitt/addons/widman/widgets/widget_punch.py +0 -246
- build/lib/build/lib/clitt/addons/widman/widgets/widget_send_msg.py +0 -272
- build/lib/build/lib/clitt/addons/widman/widgets/widget_time_calc.py +0 -146
- build/lib/build/lib/clitt/addons/widman/widman.py +0 -123
- build/lib/build/lib/clitt/core/__init__.py +0 -15
- build/lib/build/lib/clitt/core/exception/__init__.py +0 -11
- build/lib/build/lib/clitt/core/exception/exceptions.py +0 -19
- build/lib/build/lib/clitt/core/icons/__init__.py +0 -12
- build/lib/build/lib/clitt/core/icons/emojis/__init__.py +0 -12
- build/lib/build/lib/clitt/core/icons/emojis/emojis.py +0 -41
- build/lib/build/lib/clitt/core/icons/emojis/face_smiling.py +0 -40
- build/lib/build/lib/clitt/core/icons/font_awesome/__init__.py +0 -18
- build/lib/build/lib/clitt/core/icons/font_awesome/app_icons.py +0 -55
- build/lib/build/lib/clitt/core/icons/font_awesome/awesome.py +0 -76
- build/lib/build/lib/clitt/core/icons/font_awesome/dashboard_icons.py +0 -93
- build/lib/build/lib/clitt/core/icons/font_awesome/form_icons.py +0 -69
- build/lib/build/lib/clitt/core/icons/font_awesome/game_icons.py +0 -59
- build/lib/build/lib/clitt/core/icons/font_awesome/nav_icons.py +0 -42
- build/lib/build/lib/clitt/core/icons/font_awesome/trickplay_icons.py +0 -39
- build/lib/build/lib/clitt/core/icons/font_awesome/widget_icons.py +0 -37
- build/lib/build/lib/clitt/core/preferences.py +0 -87
- build/lib/build/lib/clitt/core/term/__init__.py +0 -14
- build/lib/build/lib/clitt/core/term/commons.py +0 -106
- build/lib/build/lib/clitt/core/term/cursor.py +0 -174
- build/lib/build/lib/clitt/core/term/screen.py +0 -106
- build/lib/build/lib/clitt/core/term/terminal.py +0 -202
- build/lib/build/lib/clitt/core/tui/__init__.py +0 -20
- build/lib/build/lib/clitt/core/tui/line_input/__init__.py +0 -12
- build/lib/build/lib/clitt/core/tui/line_input/keyboard_input.py +0 -229
- build/lib/build/lib/clitt/core/tui/line_input/line_input.py +0 -31
- build/lib/build/lib/clitt/core/tui/mchoose/__init__.py +0 -12
- build/lib/build/lib/clitt/core/tui/mchoose/mchoose.py +0 -43
- build/lib/build/lib/clitt/core/tui/mchoose/menu_choose.py +0 -192
- build/lib/build/lib/clitt/core/tui/mdashboard/__init__.py +0 -14
- build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_builder.py +0 -54
- build/lib/build/lib/clitt/core/tui/mdashboard/dashboard_item.py +0 -31
- build/lib/build/lib/clitt/core/tui/mdashboard/mdashboard.py +0 -26
- build/lib/build/lib/clitt/core/tui/mdashboard/menu_dashboard.py +0 -148
- build/lib/build/lib/clitt/core/tui/menu/__init__.py +0 -16
- build/lib/build/lib/clitt/core/tui/menu/tui_menu.py +0 -111
- build/lib/build/lib/clitt/core/tui/menu/tui_menu_action.py +0 -47
- build/lib/build/lib/clitt/core/tui/menu/tui_menu_factory.py +0 -117
- build/lib/build/lib/clitt/core/tui/menu/tui_menu_item.py +0 -196
- build/lib/build/lib/clitt/core/tui/menu/tui_menu_ui.py +0 -98
- build/lib/build/lib/clitt/core/tui/menu/tui_menu_view.py +0 -57
- build/lib/build/lib/clitt/core/tui/minput/__init__.py +0 -19
- build/lib/build/lib/clitt/core/tui/minput/access_type.py +0 -26
- build/lib/build/lib/clitt/core/tui/minput/field_builder.py +0 -117
- build/lib/build/lib/clitt/core/tui/minput/form_builder.py +0 -72
- build/lib/build/lib/clitt/core/tui/minput/form_field.py +0 -180
- build/lib/build/lib/clitt/core/tui/minput/input_type.py +0 -30
- build/lib/build/lib/clitt/core/tui/minput/input_validator.py +0 -98
- build/lib/build/lib/clitt/core/tui/minput/menu_input.py +0 -292
- build/lib/build/lib/clitt/core/tui/minput/minput.py +0 -44
- build/lib/build/lib/clitt/core/tui/minput/minput_utils.py +0 -156
- build/lib/build/lib/clitt/core/tui/mselect/__init__.py +0 -12
- build/lib/build/lib/clitt/core/tui/mselect/menu_select.py +0 -170
- build/lib/build/lib/clitt/core/tui/mselect/mselect.py +0 -36
- build/lib/build/lib/clitt/core/tui/table/__init__.py +0 -12
- build/lib/build/lib/clitt/core/tui/table/table_enums.py +0 -47
- build/lib/build/lib/clitt/core/tui/table/table_renderer.py +0 -339
- build/lib/build/lib/clitt/core/tui/tui_application.py +0 -52
- build/lib/build/lib/clitt/core/tui/tui_component.py +0 -154
- build/lib/build/lib/clitt/core/tui/tui_preferences.py +0 -103
- build/lib/build/lib/clitt/utils/__init__.py +0 -11
- build/lib/build/lib/clitt/utils/git_utils.py +0 -66
- build/lib/clitt/__classpath__.py +0 -28
- build/lib/clitt/__init__.py +0 -13
- build/lib/clitt/__main__.py +0 -139
- build/lib/clitt/addons/__init__.py +0 -12
- build/lib/clitt/addons/appman/__init__.py +0 -13
- build/lib/clitt/addons/appman/appman.py +0 -305
- build/lib/clitt/addons/appman/appman_enums.py +0 -39
- build/lib/clitt/addons/appman/templates/__init__.py +0 -11
- build/lib/clitt/addons/widman/__init__.py +0 -14
- build/lib/clitt/addons/widman/widget.py +0 -70
- build/lib/clitt/addons/widman/widget_entry.py +0 -54
- build/lib/clitt/addons/widman/widgets/__init__.py +0 -14
- build/lib/clitt/addons/widman/widgets/widget_free.py +0 -110
- build/lib/clitt/addons/widman/widgets/widget_punch.py +0 -246
- build/lib/clitt/addons/widman/widgets/widget_send_msg.py +0 -272
- build/lib/clitt/addons/widman/widgets/widget_time_calc.py +0 -146
- build/lib/clitt/addons/widman/widman.py +0 -123
- build/lib/clitt/core/__init__.py +0 -15
- build/lib/clitt/core/exception/__init__.py +0 -11
- build/lib/clitt/core/exception/exceptions.py +0 -19
- build/lib/clitt/core/icons/__init__.py +0 -12
- build/lib/clitt/core/icons/emojis/__init__.py +0 -12
- build/lib/clitt/core/icons/emojis/emojis.py +0 -41
- build/lib/clitt/core/icons/emojis/face_smiling.py +0 -40
- build/lib/clitt/core/icons/font_awesome/__init__.py +0 -18
- build/lib/clitt/core/icons/font_awesome/app_icons.py +0 -55
- build/lib/clitt/core/icons/font_awesome/awesome.py +0 -76
- build/lib/clitt/core/icons/font_awesome/dashboard_icons.py +0 -93
- build/lib/clitt/core/icons/font_awesome/form_icons.py +0 -69
- build/lib/clitt/core/icons/font_awesome/game_icons.py +0 -59
- build/lib/clitt/core/icons/font_awesome/nav_icons.py +0 -42
- build/lib/clitt/core/icons/font_awesome/trickplay_icons.py +0 -39
- build/lib/clitt/core/icons/font_awesome/widget_icons.py +0 -37
- build/lib/clitt/core/preferences.py +0 -87
- build/lib/clitt/core/term/__init__.py +0 -14
- build/lib/clitt/core/term/commons.py +0 -106
- build/lib/clitt/core/term/cursor.py +0 -174
- build/lib/clitt/core/term/screen.py +0 -106
- build/lib/clitt/core/term/terminal.py +0 -202
- build/lib/clitt/core/tui/__init__.py +0 -20
- build/lib/clitt/core/tui/line_input/__init__.py +0 -12
- build/lib/clitt/core/tui/line_input/keyboard_input.py +0 -229
- build/lib/clitt/core/tui/line_input/line_input.py +0 -31
- build/lib/clitt/core/tui/mchoose/__init__.py +0 -12
- build/lib/clitt/core/tui/mchoose/mchoose.py +0 -43
- build/lib/clitt/core/tui/mchoose/menu_choose.py +0 -192
- build/lib/clitt/core/tui/mdashboard/__init__.py +0 -14
- build/lib/clitt/core/tui/mdashboard/dashboard_builder.py +0 -54
- build/lib/clitt/core/tui/mdashboard/dashboard_item.py +0 -31
- build/lib/clitt/core/tui/mdashboard/mdashboard.py +0 -26
- build/lib/clitt/core/tui/mdashboard/menu_dashboard.py +0 -148
- build/lib/clitt/core/tui/menu/__init__.py +0 -16
- build/lib/clitt/core/tui/menu/tui_menu.py +0 -111
- build/lib/clitt/core/tui/menu/tui_menu_action.py +0 -47
- build/lib/clitt/core/tui/menu/tui_menu_factory.py +0 -117
- build/lib/clitt/core/tui/menu/tui_menu_item.py +0 -196
- build/lib/clitt/core/tui/menu/tui_menu_ui.py +0 -98
- build/lib/clitt/core/tui/menu/tui_menu_view.py +0 -57
- build/lib/clitt/core/tui/minput/__init__.py +0 -19
- build/lib/clitt/core/tui/minput/access_type.py +0 -26
- build/lib/clitt/core/tui/minput/field_builder.py +0 -117
- build/lib/clitt/core/tui/minput/form_builder.py +0 -72
- build/lib/clitt/core/tui/minput/form_field.py +0 -180
- build/lib/clitt/core/tui/minput/input_type.py +0 -30
- build/lib/clitt/core/tui/minput/input_validator.py +0 -98
- build/lib/clitt/core/tui/minput/menu_input.py +0 -292
- build/lib/clitt/core/tui/minput/minput.py +0 -44
- build/lib/clitt/core/tui/minput/minput_utils.py +0 -156
- build/lib/clitt/core/tui/mselect/__init__.py +0 -12
- build/lib/clitt/core/tui/mselect/menu_select.py +0 -170
- build/lib/clitt/core/tui/mselect/mselect.py +0 -36
- build/lib/clitt/core/tui/table/__init__.py +0 -12
- build/lib/clitt/core/tui/table/table_enums.py +0 -47
- build/lib/clitt/core/tui/table/table_renderer.py +0 -339
- build/lib/clitt/core/tui/tui_application.py +0 -52
- build/lib/clitt/core/tui/tui_component.py +0 -154
- build/lib/clitt/core/tui/tui_preferences.py +0 -103
- build/lib/clitt/utils/__init__.py +0 -11
- build/lib/clitt/utils/git_utils.py +0 -66
- hspylib_clitt-0.9.120.dist-info/RECORD +0 -334
- {hspylib_clitt-0.9.120.dist-info → hspylib_clitt-0.9.122.dist-info}/WHEEL +0 -0
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
@project: HsPyLib
|
|
6
|
-
@package: clitt.core.tui.mselect
|
|
7
|
-
@file: menu_select.py
|
|
8
|
-
@created: Wed, 17 May 2023
|
|
9
|
-
@author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
|
|
10
|
-
@site: https://github.com/yorevs/hspylib
|
|
11
|
-
@license: MIT - Please refer to <https://opensource.org/licenses/MIT>
|
|
12
|
-
|
|
13
|
-
Copyright·(c)·2024,·HSPyLib
|
|
14
|
-
"""
|
|
15
|
-
from clitt.core.icons.font_awesome.nav_icons import NavIcons
|
|
16
|
-
from clitt.core.term.commons import Direction, Portion
|
|
17
|
-
from clitt.core.tui.tui_component import TUIComponent
|
|
18
|
-
from hspylib.modules.cli.keyboard import Keyboard
|
|
19
|
-
from typing import List, Optional, TypeAlias, TypeVar
|
|
20
|
-
|
|
21
|
-
T = TypeVar("T")
|
|
22
|
-
|
|
23
|
-
MSelectItems: TypeAlias = List[T]
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class MenuSelect(TUIComponent):
|
|
27
|
-
"""Terminal UI menu select input method"""
|
|
28
|
-
|
|
29
|
-
NAV_ICONS = NavIcons.compose(NavIcons.UP, NavIcons.DOWN)
|
|
30
|
-
|
|
31
|
-
ROW_OFFSET = 5
|
|
32
|
-
|
|
33
|
-
MIN_ROWS = 3
|
|
34
|
-
|
|
35
|
-
def __init__(self, title: str, items: MSelectItems):
|
|
36
|
-
super().__init__(title)
|
|
37
|
-
self._items = items
|
|
38
|
-
self._show_from = 0
|
|
39
|
-
self._show_to = self._max_rows()
|
|
40
|
-
self._diff_index = self._show_to - self._show_from
|
|
41
|
-
self._sel_index = 0
|
|
42
|
-
self._max_line_length = max(len(str(item)) for item in items)
|
|
43
|
-
|
|
44
|
-
def execute(self) -> Optional[T]:
|
|
45
|
-
"""Execute the component's main flow."""
|
|
46
|
-
|
|
47
|
-
if (length := len(self._items)) == 0:
|
|
48
|
-
return None
|
|
49
|
-
if length == 1: # When only one option is provided, select the element at index 0 and return
|
|
50
|
-
return self._items[0]
|
|
51
|
-
|
|
52
|
-
self._prepare_render()
|
|
53
|
-
keypress = self._loop()
|
|
54
|
-
|
|
55
|
-
return self._items[self._sel_index] if keypress.isEnter() else None
|
|
56
|
-
|
|
57
|
-
def render(self) -> None:
|
|
58
|
-
"""Renders the TUI component."""
|
|
59
|
-
|
|
60
|
-
length = len(self._items)
|
|
61
|
-
self.cursor.restore()
|
|
62
|
-
self.writeln(f"{self.prefs.title_color.placeholder}{self.title}%EOL%%NC%")
|
|
63
|
-
|
|
64
|
-
for idx in range(self._show_from, self._show_to):
|
|
65
|
-
if idx >= length:
|
|
66
|
-
break # When the index is greater than the number of items, stop rendering
|
|
67
|
-
|
|
68
|
-
option_line = str(self._items[idx])
|
|
69
|
-
self.cursor.erase(Portion.LINE)
|
|
70
|
-
# Print the selector if the index is currently selected
|
|
71
|
-
selector = self.draw_selector(idx == self._sel_index)
|
|
72
|
-
# fmt: off
|
|
73
|
-
line_fmt = (
|
|
74
|
-
" {:>" + f"{len(str(length))}" + "} "
|
|
75
|
-
+ "{:>" + f"{len(selector)}" + "} "
|
|
76
|
-
+ "{:<" + f"{self._max_line_length}" + "} "
|
|
77
|
-
)
|
|
78
|
-
# fmt: on
|
|
79
|
-
self.draw_line(line_fmt, idx + 1, selector, option_line)
|
|
80
|
-
|
|
81
|
-
self.draw_navbar(self.navbar(to=length))
|
|
82
|
-
self._re_render = False
|
|
83
|
-
|
|
84
|
-
def navbar(self, **kwargs) -> str:
|
|
85
|
-
return (
|
|
86
|
-
f"%EOL%{self.prefs.navbar_color.placeholder}"
|
|
87
|
-
f"[Enter] Select [{self.NAV_ICONS}] "
|
|
88
|
-
f"Navigate [Esc] Quit [1..{kwargs['to']}] Goto: %NC%"
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
def handle_keypress(self) -> Keyboard:
|
|
92
|
-
if keypress := Keyboard.wait_keystroke():
|
|
93
|
-
match keypress:
|
|
94
|
-
case _ as key if key in Keyboard.break_keys():
|
|
95
|
-
self._done = True
|
|
96
|
-
case Keyboard.VK_UP:
|
|
97
|
-
self._handle_key_up()
|
|
98
|
-
case Keyboard.VK_DOWN:
|
|
99
|
-
self._handle_key_down()
|
|
100
|
-
case Keyboard.VK_TAB:
|
|
101
|
-
self._handle_tab()
|
|
102
|
-
case Keyboard.VK_SHIFT_TAB:
|
|
103
|
-
self._handle_shift_tab()
|
|
104
|
-
case _ as key if key in Keyboard.digits():
|
|
105
|
-
self._handle_digit(keypress)
|
|
106
|
-
|
|
107
|
-
return keypress
|
|
108
|
-
|
|
109
|
-
def _handle_digit(self, digit: Keyboard) -> None:
|
|
110
|
-
"""TODO"""
|
|
111
|
-
length = len(self._items)
|
|
112
|
-
typed_index = digit.value
|
|
113
|
-
self.cursor.write(f"{digit.value}") # echo the digit typed
|
|
114
|
-
index_len = 1
|
|
115
|
-
while len(typed_index) < len(str(length)):
|
|
116
|
-
keystroke = Keyboard.wait_keystroke()
|
|
117
|
-
if not keystroke or not keystroke.isdigit():
|
|
118
|
-
typed_index = None if keystroke != Keyboard.VK_ENTER else typed_index
|
|
119
|
-
break
|
|
120
|
-
typed_index = f"{typed_index}{keystroke.value if keystroke else ''}"
|
|
121
|
-
self.cursor.write(f"{keystroke.value if keystroke else ''}")
|
|
122
|
-
index_len += 1
|
|
123
|
-
# Erase the index typed by the user
|
|
124
|
-
self.cursor.move(index_len, Direction.LEFT)
|
|
125
|
-
self.cursor.erase(Direction.RIGHT)
|
|
126
|
-
if typed_index and 1 <= int(typed_index) <= length:
|
|
127
|
-
self._show_to = max(int(typed_index), self._diff_index)
|
|
128
|
-
self._show_from = self._show_to - self._diff_index
|
|
129
|
-
self._sel_index = int(typed_index) - 1
|
|
130
|
-
self._re_render = True
|
|
131
|
-
|
|
132
|
-
def _handle_key_up(self) -> None:
|
|
133
|
-
"""TODO"""
|
|
134
|
-
if self._sel_index == self._show_from and self._show_from > 0:
|
|
135
|
-
self._show_from -= 1
|
|
136
|
-
self._show_to -= 1
|
|
137
|
-
if self._sel_index - 1 >= 0:
|
|
138
|
-
self._sel_index -= 1
|
|
139
|
-
self._re_render = True
|
|
140
|
-
|
|
141
|
-
def _handle_key_down(self) -> None:
|
|
142
|
-
"""TODO"""
|
|
143
|
-
length = len(self._items)
|
|
144
|
-
if self._sel_index + 1 == self._show_to and self._show_to < length:
|
|
145
|
-
self._show_from += 1
|
|
146
|
-
self._show_to += 1
|
|
147
|
-
if self._sel_index + 1 < length:
|
|
148
|
-
self._sel_index += 1
|
|
149
|
-
self._re_render = True
|
|
150
|
-
|
|
151
|
-
def _handle_tab(self) -> None:
|
|
152
|
-
"""TODO"""
|
|
153
|
-
length = len(self._items)
|
|
154
|
-
page_index = min(self._show_to + self._diff_index, length)
|
|
155
|
-
self._show_to = max(page_index, self._diff_index)
|
|
156
|
-
self._show_from = self._show_to - self._diff_index
|
|
157
|
-
self._sel_index = self._show_from
|
|
158
|
-
self._re_render = True
|
|
159
|
-
|
|
160
|
-
def _handle_shift_tab(self) -> None:
|
|
161
|
-
"""TODO"""
|
|
162
|
-
page_index = max(self._show_from - self._diff_index, 0)
|
|
163
|
-
self._show_from = min(page_index, self._diff_index)
|
|
164
|
-
self._show_to = self._show_from + self._diff_index
|
|
165
|
-
self._sel_index = self._show_from
|
|
166
|
-
self._re_render = True
|
|
167
|
-
|
|
168
|
-
def _max_rows(self) -> int:
|
|
169
|
-
screen_lines = self.screen.lines - self.ROW_OFFSET
|
|
170
|
-
return min(self.prefs.max_rows, screen_lines)
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
@project: HsPyLib
|
|
6
|
-
@package: clitt.core.tui.mselect
|
|
7
|
-
@file: mselect.py
|
|
8
|
-
@created: Tue, 4 May 2021
|
|
9
|
-
@author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
|
|
10
|
-
@site: https://github.com/yorevs/hspylib
|
|
11
|
-
@license: MIT - Please refer to <https://opensource.org/licenses/MIT>
|
|
12
|
-
|
|
13
|
-
Copyright·(c)·2024,·HSPyLib
|
|
14
|
-
"""
|
|
15
|
-
from clitt.core.tui.mselect.menu_select import MenuSelect
|
|
16
|
-
from hspylib.core.enums.charset import Charset
|
|
17
|
-
from typing import List, Optional, TypeVar
|
|
18
|
-
|
|
19
|
-
T = TypeVar("T")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def mselect(items: List[T], title: str = "Please select one", output: str = None) -> Optional[T]:
|
|
23
|
-
"""
|
|
24
|
-
Terminal UI menu select input method.
|
|
25
|
-
:param items: the provided items to select from.
|
|
26
|
-
:param title: the title to be displayed before the options.
|
|
27
|
-
:param output: optional output file containing the selected item.
|
|
28
|
-
:return: the selected item.
|
|
29
|
-
"""
|
|
30
|
-
result = MenuSelect(title, items).execute()
|
|
31
|
-
|
|
32
|
-
if result and output:
|
|
33
|
-
with open(output, "w", encoding=Charset.UTF_8.val) as f_out:
|
|
34
|
-
f_out.write(result)
|
|
35
|
-
|
|
36
|
-
return result
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
@project: HsPyLib
|
|
6
|
-
@package: clitt.core.tui.table
|
|
7
|
-
@file: table_enums.py
|
|
8
|
-
@created: Tue, 4 Jul 2023
|
|
9
|
-
@author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
|
|
10
|
-
@site: https://github.com/yorevs/hspylib
|
|
11
|
-
@license: MIT - Please refer to <https://opensource.org/licenses/MIT>
|
|
12
|
-
|
|
13
|
-
Copyright·(c)·2024,·HSPyLib
|
|
14
|
-
"""
|
|
15
|
-
from enum import auto
|
|
16
|
-
from hspylib.core.enums.enumeration import Enumeration
|
|
17
|
-
from hspylib.core.tools import text_tools
|
|
18
|
-
from typing import Callable
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class TextAlignment(Enumeration):
|
|
22
|
-
"""Table cell/header text justification helper."""
|
|
23
|
-
|
|
24
|
-
# fmt: off
|
|
25
|
-
LEFT = auto(), text_tools.justified_left
|
|
26
|
-
CENTER = auto(), text_tools.justified_center
|
|
27
|
-
RIGHT = auto(), text_tools.justified_right
|
|
28
|
-
# fmt: on
|
|
29
|
-
|
|
30
|
-
def val(self) -> Callable:
|
|
31
|
-
return self.value[1]
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class TextCase(Enumeration):
|
|
35
|
-
"""Table cell/header text case helper."""
|
|
36
|
-
|
|
37
|
-
# fmt: off
|
|
38
|
-
TITLE = auto(), text_tools.titlecase
|
|
39
|
-
SNAKE = auto(), text_tools.snakecase
|
|
40
|
-
CAMEL = auto(), text_tools.camelcase
|
|
41
|
-
KEBAB = auto(), text_tools.kebabcase
|
|
42
|
-
LOWER = auto(), text_tools.lowercase
|
|
43
|
-
UPPER = auto(), text_tools.uppercase
|
|
44
|
-
# fmt: on
|
|
45
|
-
|
|
46
|
-
def val(self) -> Callable:
|
|
47
|
-
return self.value[1]
|
|
@@ -1,339 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
@project: HsPyLib
|
|
6
|
-
@package: clitt.core.tui.table
|
|
7
|
-
@file: table_renderer.py
|
|
8
|
-
@created: Tue, 4 May 2021
|
|
9
|
-
@author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
|
|
10
|
-
@site: https://github.com/yorevs/hspylib
|
|
11
|
-
@license: MIT - Please refer to <https://opensource.org/licenses/MIT>
|
|
12
|
-
|
|
13
|
-
Copyright·(c)·2024,·HSPyLib
|
|
14
|
-
"""
|
|
15
|
-
from clitt.core.term.screen import Screen
|
|
16
|
-
from clitt.core.term.terminal import Terminal
|
|
17
|
-
from clitt.core.tui.table.table_enums import TextAlignment, TextCase
|
|
18
|
-
from clitt.core.tui.tui_preferences import TUIPreferences
|
|
19
|
-
from functools import cached_property, partial, reduce
|
|
20
|
-
from hspylib.core.preconditions import check_argument
|
|
21
|
-
from hspylib.core.tools.commons import file_is_not_empty
|
|
22
|
-
from hspylib.core.tools.text_tools import elide_text, ensure_endswith
|
|
23
|
-
from operator import add
|
|
24
|
-
from typing import Any, Callable, Iterable, List, Tuple, TypeAlias
|
|
25
|
-
|
|
26
|
-
import csv
|
|
27
|
-
import os
|
|
28
|
-
|
|
29
|
-
# fmt: off
|
|
30
|
-
AlignmentFn : TypeAlias = Callable[[str, int], str]
|
|
31
|
-
TestCaseFn : TypeAlias = Callable[[str], str]
|
|
32
|
-
# fmt: on
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class TableRenderer:
|
|
36
|
-
"""Utility class to render terminal UI tables."""
|
|
37
|
-
|
|
38
|
-
DEFAULT_MINIMUM_CELL_SIZE = 6
|
|
39
|
-
|
|
40
|
-
@staticmethod
|
|
41
|
-
def import_csv(
|
|
42
|
-
filepath: str, caption: str | None = None, has_headers: bool = True, delimiter: chr = ","
|
|
43
|
-
) -> "TableRenderer":
|
|
44
|
-
"""Render the table based on a CSV file."""
|
|
45
|
-
check_argument(file_is_not_empty(filepath), f"File not found: {filepath}")
|
|
46
|
-
headers, data = None, []
|
|
47
|
-
with open(filepath, encoding="UTF8") as csv_file:
|
|
48
|
-
csv_reader = csv.reader(csv_file, delimiter=delimiter)
|
|
49
|
-
line_count = 0
|
|
50
|
-
for row in csv_reader:
|
|
51
|
-
line_count += 1
|
|
52
|
-
if line_count == 1:
|
|
53
|
-
if has_headers:
|
|
54
|
-
headers = row
|
|
55
|
-
continue
|
|
56
|
-
headers = [f"C{idx}" for idx, _ in enumerate(row)]
|
|
57
|
-
data.append(row)
|
|
58
|
-
return TableRenderer(headers, data, caption)
|
|
59
|
-
|
|
60
|
-
def __init__(self, headers: List[str], data: Iterable, caption: str | None = None):
|
|
61
|
-
"""
|
|
62
|
-
:param headers: table headers to be displayed.
|
|
63
|
-
:param data: table record set with the selected rows.
|
|
64
|
-
:param caption: table caption to be displayed.
|
|
65
|
-
"""
|
|
66
|
-
|
|
67
|
-
self._terminal: Terminal = Terminal.INSTANCE
|
|
68
|
-
self._headers: List[str] = headers
|
|
69
|
-
self._data: List[Any] = data if data else []
|
|
70
|
-
self._caption: str = caption
|
|
71
|
-
self._columns: range = range(self.columns)
|
|
72
|
-
self._min_cell_size: int = self.DEFAULT_MINIMUM_CELL_SIZE
|
|
73
|
-
self._header_alignment: TextAlignment = TextAlignment.CENTER
|
|
74
|
-
self._cell_alignment: TextAlignment = TextAlignment.LEFT
|
|
75
|
-
self._header_case: TextCase = TextCase.UPPER
|
|
76
|
-
self._adjust_cells = None
|
|
77
|
-
|
|
78
|
-
check_argument(self.columns >= 1, "Headers are required")
|
|
79
|
-
self._cell_sizes = [0 for _ in range(self.columns)]
|
|
80
|
-
self.adjust_cells_auto()
|
|
81
|
-
if data:
|
|
82
|
-
c_len = len(min(data, key=len))
|
|
83
|
-
check_argument(
|
|
84
|
-
c_len == self.columns, "Headers and Columns must have the same size: {} vs {}", c_len, self.columns
|
|
85
|
-
)
|
|
86
|
-
self._footer = f":: Displaying {c_len} of {c_len} records"
|
|
87
|
-
else:
|
|
88
|
-
self._footer = ":: No data to display"
|
|
89
|
-
|
|
90
|
-
@property
|
|
91
|
-
def terminal(self) -> Terminal:
|
|
92
|
-
return self._terminal
|
|
93
|
-
|
|
94
|
-
@property
|
|
95
|
-
def screen(self) -> Screen:
|
|
96
|
-
return self.terminal.screen
|
|
97
|
-
|
|
98
|
-
@property
|
|
99
|
-
def prefs(self) -> TUIPreferences:
|
|
100
|
-
return self.screen.preferences
|
|
101
|
-
|
|
102
|
-
@property
|
|
103
|
-
def column_sizes(self) -> List[int]:
|
|
104
|
-
return self._cell_sizes
|
|
105
|
-
|
|
106
|
-
@cached_property
|
|
107
|
-
def columns(self) -> int:
|
|
108
|
-
return len(self.headers)
|
|
109
|
-
|
|
110
|
-
@property
|
|
111
|
-
def cell_alignment(self) -> AlignmentFn:
|
|
112
|
-
return self._cell_alignment.val()
|
|
113
|
-
|
|
114
|
-
@property
|
|
115
|
-
def header_alignment(self) -> AlignmentFn:
|
|
116
|
-
return self._header_alignment.val()
|
|
117
|
-
|
|
118
|
-
@property
|
|
119
|
-
def header_case(self) -> TestCaseFn:
|
|
120
|
-
return self._header_case.val()
|
|
121
|
-
|
|
122
|
-
@property
|
|
123
|
-
def caption(self) -> str:
|
|
124
|
-
return self._caption
|
|
125
|
-
|
|
126
|
-
@property
|
|
127
|
-
def footer(self) -> str:
|
|
128
|
-
return self._footer
|
|
129
|
-
|
|
130
|
-
@footer.setter
|
|
131
|
-
def footer(self, other: str) -> None:
|
|
132
|
-
self._footer = other
|
|
133
|
-
|
|
134
|
-
@property
|
|
135
|
-
def data(self) -> Iterable:
|
|
136
|
-
return self._data
|
|
137
|
-
|
|
138
|
-
@property
|
|
139
|
-
def headers(self) -> List[str]:
|
|
140
|
-
return self._headers
|
|
141
|
-
|
|
142
|
-
def set_header_alignment(self, alignment: TextAlignment) -> None:
|
|
143
|
-
"""Set table headers alignment.
|
|
144
|
-
:param alignment: table header text alignment function.
|
|
145
|
-
:return None
|
|
146
|
-
"""
|
|
147
|
-
self._header_alignment = alignment
|
|
148
|
-
|
|
149
|
-
def set_header_case(self, test_case: TextCase) -> None:
|
|
150
|
-
"""Set table headers alignment.
|
|
151
|
-
:param test_case: table header text case function.
|
|
152
|
-
:return None
|
|
153
|
-
"""
|
|
154
|
-
self._header_case = test_case
|
|
155
|
-
|
|
156
|
-
def set_cell_alignment(self, alignment: TextAlignment) -> None:
|
|
157
|
-
"""Set table cell alignment.
|
|
158
|
-
:param alignment: table cell text alignment function.
|
|
159
|
-
:return None
|
|
160
|
-
"""
|
|
161
|
-
self._cell_alignment = alignment
|
|
162
|
-
|
|
163
|
-
def set_cell_sizes(self, sizes: Tuple[int, ...]) -> None:
|
|
164
|
-
"""Render table based on a list of fixed sizes.
|
|
165
|
-
:param sizes: the list of specific cell sizes.
|
|
166
|
-
:return None
|
|
167
|
-
"""
|
|
168
|
-
max_cell_size = self.screen.columns if self._fits(sizes) else int(self.screen.columns / self.columns)
|
|
169
|
-
for idx, size in enumerate(sizes[: self.columns]):
|
|
170
|
-
self._cell_sizes[idx] = min(max_cell_size, max(self._min_cell_size, size))
|
|
171
|
-
|
|
172
|
-
def set_min_cell_size(self, size: int) -> None:
|
|
173
|
-
"""Set the minimum length of a cell.
|
|
174
|
-
:param size: minimum table cell size.
|
|
175
|
-
:return None
|
|
176
|
-
"""
|
|
177
|
-
self._min_cell_size = max(self.DEFAULT_MINIMUM_CELL_SIZE, size)
|
|
178
|
-
self.set_cell_sizes(*(max(self._cell_sizes[idx], size) for idx, _ in enumerate(self.headers)))
|
|
179
|
-
|
|
180
|
-
def adjust_cells_by_headers(self) -> None:
|
|
181
|
-
"""Adjust cell sizes based on the column header length.
|
|
182
|
-
:return None
|
|
183
|
-
"""
|
|
184
|
-
args = [max(self._min_cell_size, len(header)) for header in self.headers]
|
|
185
|
-
self._adjust_cells = partial(self.set_cell_sizes, args)
|
|
186
|
-
|
|
187
|
-
def adjust_cells_by_largest_header(self) -> None:
|
|
188
|
-
"""Adjust cell sizes based on the maximum length of a header.
|
|
189
|
-
:return None
|
|
190
|
-
"""
|
|
191
|
-
max_len = len(max(self.headers))
|
|
192
|
-
args = [max(self._min_cell_size, max_len) for _ in self.headers]
|
|
193
|
-
self._adjust_cells = partial(self.set_cell_sizes, args)
|
|
194
|
-
|
|
195
|
-
def adjust_cells_by_largest_cell(self) -> None:
|
|
196
|
-
"""Adjust cell sizes based on the maximum length of a cell.
|
|
197
|
-
:return None
|
|
198
|
-
"""
|
|
199
|
-
max_len = 0
|
|
200
|
-
for row in self.data:
|
|
201
|
-
max_len = max(max_len, len(max(list(map(str, row)), key=len)))
|
|
202
|
-
args = [max_len for _ in self.headers]
|
|
203
|
-
self._adjust_cells = partial(self.set_cell_sizes, args)
|
|
204
|
-
|
|
205
|
-
def adjust_cells_by_fixed_size(self, size: int) -> None:
|
|
206
|
-
"""Adjust cell sizes to a fixed size.
|
|
207
|
-
:param size: the fixed cell size.
|
|
208
|
-
:return None
|
|
209
|
-
"""
|
|
210
|
-
args = [size for _ in self.headers]
|
|
211
|
-
self._adjust_cells = partial(self.set_cell_sizes, args)
|
|
212
|
-
|
|
213
|
-
def adjust_cells_to_fit_screen(self) -> None:
|
|
214
|
-
"""Adjust cell sizes accordingly to fill the screen size
|
|
215
|
-
:return None
|
|
216
|
-
"""
|
|
217
|
-
distributed_size = int(self.screen.columns / self.columns) - 3
|
|
218
|
-
self.adjust_cells_by_fixed_size(distributed_size)
|
|
219
|
-
|
|
220
|
-
def adjust_cells_auto(self) -> None:
|
|
221
|
-
"""Ensure all cells and headers are visible with the minimum size possible.
|
|
222
|
-
:return None
|
|
223
|
-
"""
|
|
224
|
-
if not self.data:
|
|
225
|
-
self.adjust_cells_by_headers()
|
|
226
|
-
else:
|
|
227
|
-
sizes = self._cell_sizes
|
|
228
|
-
for cell, c_size in zip(self.data, sizes):
|
|
229
|
-
sizes = [
|
|
230
|
-
max(len(self.headers[idx]), max(sizes[idx], max(c_size, len(str(cell[idx])))))
|
|
231
|
-
for idx, _ in enumerate(self.headers)
|
|
232
|
-
]
|
|
233
|
-
args = [size for size in sizes]
|
|
234
|
-
self._adjust_cells = partial(self.set_cell_sizes, args)
|
|
235
|
-
|
|
236
|
-
def render(self) -> None:
|
|
237
|
-
"""Render the table.
|
|
238
|
-
:return None
|
|
239
|
-
"""
|
|
240
|
-
self._adjust_cells()
|
|
241
|
-
header_line, data_lines = self._format_header_row(), self._format_data_rows()
|
|
242
|
-
table_line = "+" + "+".join(f"{'-' * (self._cell_sizes[idx] + 2)}" for idx in self._columns) + "+"
|
|
243
|
-
self._render_table(table_line, header_line, data_lines)
|
|
244
|
-
|
|
245
|
-
def export_csv(self, filepath: str, delimiter: chr = ",", has_headers: bool = True) -> None:
|
|
246
|
-
"""Export the table to CSV format.
|
|
247
|
-
:return None
|
|
248
|
-
"""
|
|
249
|
-
csv_file = ensure_endswith(filepath, ".csv")
|
|
250
|
-
with open(csv_file, "w", encoding="UTF8") as csv_file:
|
|
251
|
-
writer = csv.writer(csv_file, delimiter=delimiter)
|
|
252
|
-
if has_headers:
|
|
253
|
-
writer.writerow(self.headers)
|
|
254
|
-
writer.writerows(self.data)
|
|
255
|
-
|
|
256
|
-
def _format_header_row(self) -> str:
|
|
257
|
-
"""Format the table header using the defined preferences.
|
|
258
|
-
:return the formatted header row.
|
|
259
|
-
"""
|
|
260
|
-
header_cols = [self.header_alignment(self._header_text(idx), self._cell_sizes[idx]) for idx in self._columns]
|
|
261
|
-
return f"| {' | '.join(header_cols)} |"
|
|
262
|
-
|
|
263
|
-
def _format_data_rows(self) -> List[str]:
|
|
264
|
-
"""Format the table rows using the defined preferences.
|
|
265
|
-
:return a list containing the formatted data rows.
|
|
266
|
-
"""
|
|
267
|
-
# fmt: off
|
|
268
|
-
return [
|
|
269
|
-
"| " +
|
|
270
|
-
' | '.join(
|
|
271
|
-
f"{self.cell_alignment(self._cell_text(row, column), self._cell_sizes[column])}"
|
|
272
|
-
for column in self._columns
|
|
273
|
-
) +
|
|
274
|
-
" |" for row in self.data
|
|
275
|
-
]
|
|
276
|
-
# fmt: on
|
|
277
|
-
|
|
278
|
-
def _display_data(self, data: Any, end: str = os.linesep) -> None:
|
|
279
|
-
"""Display data on the screen.
|
|
280
|
-
:param data the data to be printed.
|
|
281
|
-
:param end the terminating string.
|
|
282
|
-
:return None
|
|
283
|
-
"""
|
|
284
|
-
self.terminal.cursor.write(data, end)
|
|
285
|
-
|
|
286
|
-
def _fits(self, sizes: Tuple[int, ...]) -> bool:
|
|
287
|
-
"""Return whether the expected table size fits the screen or not.
|
|
288
|
-
:param sizes the expected sizes to check.
|
|
289
|
-
:return True if the table fits the screen; False otherwise.
|
|
290
|
-
"""
|
|
291
|
-
extra_len = 4 + ((self.columns - 1) * 3) # 4 for '| |' and 3 for each '-+-'
|
|
292
|
-
exp_table_size = reduce(add, sizes) + extra_len
|
|
293
|
-
return exp_table_size < self.screen.columns
|
|
294
|
-
|
|
295
|
-
def _header_text(self, column: int) -> str:
|
|
296
|
-
"""Return a header for the specified column.
|
|
297
|
-
:param column the specified table column.
|
|
298
|
-
:return the header text at (row, column).
|
|
299
|
-
"""
|
|
300
|
-
return self.header_case(elide_text(self.headers[column], self._cell_size(column)))
|
|
301
|
-
|
|
302
|
-
def _cell_text(self, row: tuple, column: int) -> str:
|
|
303
|
-
"""Return a text for the specified cell (row, column).
|
|
304
|
-
:param row the specified table row.
|
|
305
|
-
:param column the specified table column.
|
|
306
|
-
:return the cell text at (row, column).
|
|
307
|
-
"""
|
|
308
|
-
return elide_text(str(row[column]), self._cell_size(column))
|
|
309
|
-
|
|
310
|
-
def _cell_size(self, column: int) -> int:
|
|
311
|
-
"""Return the size of the specified column.
|
|
312
|
-
:param column the specified table column.
|
|
313
|
-
:return the cell size at (row, column).
|
|
314
|
-
"""
|
|
315
|
-
return self._cell_sizes[column]
|
|
316
|
-
|
|
317
|
-
def _render_table(self, table_line: str, header_line: str, data_rows: List[str]) -> None:
|
|
318
|
-
"""Renders the table data.
|
|
319
|
-
:param table_line: a formatted line composed by all columns.
|
|
320
|
-
:param header_line: a formatted line composed by the table header.
|
|
321
|
-
:param data_rows: the formatted table data rows.
|
|
322
|
-
:return None
|
|
323
|
-
"""
|
|
324
|
-
magic_num = 4 # this is the length of the starting and ending characters: '| |'
|
|
325
|
-
line_length, render_line = len(table_line) - magic_num, f"+{table_line[1:-1]}+"
|
|
326
|
-
self._display_data("")
|
|
327
|
-
if self.caption:
|
|
328
|
-
border_line = render_line.replace("+", "-")
|
|
329
|
-
self._display_data(border_line)
|
|
330
|
-
self._display_data("| " + self.prefs.caption_color.placeholder, end="")
|
|
331
|
-
self._display_data(f"{elide_text(self.caption, line_length): ^{line_length}}", end="")
|
|
332
|
-
self._display_data("%NC%" + " |")
|
|
333
|
-
self._display_data(render_line)
|
|
334
|
-
self._display_data(header_line)
|
|
335
|
-
self._display_data(render_line)
|
|
336
|
-
self._display_data(os.linesep.join(data_rows) if data_rows else f"| {'<empty>': ^{line_length}} |")
|
|
337
|
-
self._display_data(render_line)
|
|
338
|
-
if self.footer:
|
|
339
|
-
self._display_data(self.footer)
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
"""
|
|
5
|
-
@project: HsPyLib-Clitt
|
|
6
|
-
@package: clitt.core.tui
|
|
7
|
-
@file: tui_application.py
|
|
8
|
-
@created: Tue, 4 May 2021
|
|
9
|
-
@author: <B>H</B>ugo <B>S</B>aporetti <B>J</B>unior"
|
|
10
|
-
@site: https://github.com/yorevs/hspylib
|
|
11
|
-
@license: MIT - Please refer to <https://opensource.org/licenses/MIT>
|
|
12
|
-
|
|
13
|
-
Copyright·(c)·2024,·HSPyLib
|
|
14
|
-
"""
|
|
15
|
-
from clitt.core.term.screen import screen
|
|
16
|
-
from clitt.core.term.terminal import terminal
|
|
17
|
-
from hspylib.core.metaclass.classpath import AnyPath
|
|
18
|
-
from hspylib.core.metaclass.singleton import AbstractSingleton
|
|
19
|
-
from hspylib.modules.application.application import Application
|
|
20
|
-
from hspylib.modules.application.exit_status import ExitStatus
|
|
21
|
-
from hspylib.modules.application.version import Version
|
|
22
|
-
|
|
23
|
-
import os
|
|
24
|
-
import sys
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class TUIApplication(Application, metaclass=AbstractSingleton):
|
|
28
|
-
"""Terminal UI application base class."""
|
|
29
|
-
|
|
30
|
-
def __init__(
|
|
31
|
-
self,
|
|
32
|
-
name: str | None,
|
|
33
|
-
version: Version = Version.initial(),
|
|
34
|
-
description: str = None,
|
|
35
|
-
usage: str = None,
|
|
36
|
-
epilog: str = None,
|
|
37
|
-
resource_dir: AnyPath = None,
|
|
38
|
-
log_dir: AnyPath = None,
|
|
39
|
-
):
|
|
40
|
-
super().__init__(name, version, description, usage, epilog, resource_dir, log_dir)
|
|
41
|
-
self._app_name = os.path.basename(sys.argv[0]) if name is None else name
|
|
42
|
-
|
|
43
|
-
def _setup_arguments(self) -> None:
|
|
44
|
-
pass
|
|
45
|
-
|
|
46
|
-
def _main(self, *params, **kwargs) -> ExitStatus:
|
|
47
|
-
pass
|
|
48
|
-
|
|
49
|
-
def _cleanup(self) -> None:
|
|
50
|
-
if screen.alternate and self._exit_code == ExitStatus.SUCCESS:
|
|
51
|
-
screen.alternate = not screen.alternate
|
|
52
|
-
terminal.restore()
|