listpick 0.1.13.58__tar.gz → 0.1.13.59__tar.gz

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.
Files changed (57) hide show
  1. {listpick-0.1.13.58 → listpick-0.1.13.59}/CHANGELOG.md +3 -0
  2. {listpick-0.1.13.58/src/listpick.egg-info → listpick-0.1.13.59}/PKG-INFO +1 -1
  3. {listpick-0.1.13.58 → listpick-0.1.13.59}/setup.py +1 -1
  4. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/listpick_app.py +2 -2
  5. listpick-0.1.13.59/src/listpick/ui/footer_1.py +202 -0
  6. {listpick-0.1.13.58 → listpick-0.1.13.59/src/listpick.egg-info}/PKG-INFO +1 -1
  7. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick.egg-info/SOURCES.txt +1 -1
  8. listpick-0.1.13.58/src/listpick/listpick_app_problem_branch.py +0 -3248
  9. {listpick-0.1.13.58 → listpick-0.1.13.59}/.gitignore +0 -0
  10. {listpick-0.1.13.58 → listpick-0.1.13.59}/LICENSE.txt +0 -0
  11. {listpick-0.1.13.58 → listpick-0.1.13.59}/README.md +0 -0
  12. {listpick-0.1.13.58 → listpick-0.1.13.59}/TODO.md +0 -0
  13. {listpick-0.1.13.58 → listpick-0.1.13.59}/assets/aria2tui_screenshot.png +0 -0
  14. {listpick-0.1.13.58 → listpick-0.1.13.59}/assets/file_compare.png +0 -0
  15. {listpick-0.1.13.58 → listpick-0.1.13.59}/assets/lpfman.png +0 -0
  16. {listpick-0.1.13.58 → listpick-0.1.13.59}/examples/footer_string_example.py +0 -0
  17. {listpick-0.1.13.58 → listpick-0.1.13.59}/examples/input.toml +0 -0
  18. {listpick-0.1.13.58 → listpick-0.1.13.59}/examples/input.txt +0 -0
  19. {listpick-0.1.13.58 → listpick-0.1.13.59}/examples/list_files.toml +0 -0
  20. {listpick-0.1.13.58 → listpick-0.1.13.59}/examples/list_files_empty.toml +0 -0
  21. {listpick-0.1.13.58 → listpick-0.1.13.59}/examples/picker_example.py +0 -0
  22. {listpick-0.1.13.58 → listpick-0.1.13.59}/examples/setup.cfg +0 -0
  23. {listpick-0.1.13.58 → listpick-0.1.13.59}/examples/template.py +0 -0
  24. {listpick-0.1.13.58 → listpick-0.1.13.59}/examples/video_duplicates.toml +0 -0
  25. {listpick-0.1.13.58 → listpick-0.1.13.59}/listpick.py +0 -0
  26. {listpick-0.1.13.58 → listpick-0.1.13.59}/requirements.txt +0 -0
  27. {listpick-0.1.13.58 → listpick-0.1.13.59}/setup.cfg +0 -0
  28. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/__init__.py +0 -0
  29. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/__main__.py +0 -0
  30. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/ui/__init__.py +0 -0
  31. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/ui/build_help.py +0 -0
  32. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/ui/footer.py +0 -0
  33. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/ui/help_screen.py +0 -0
  34. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/ui/input_field.py +0 -0
  35. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/ui/keys.py +0 -0
  36. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/ui/pane_stuff.py +0 -0
  37. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/ui/picker_colours.py +0 -0
  38. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/__init__.py +0 -0
  39. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/clipboard_operations.py +0 -0
  40. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/config.py +0 -0
  41. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/dump.py +0 -0
  42. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/filtering.py +0 -0
  43. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/generate_data.py +0 -0
  44. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/options_selectors.py +0 -0
  45. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/paste_operations.py +0 -0
  46. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/picker_log.py +0 -0
  47. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/search_and_filter_utils.py +0 -0
  48. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/searching.py +0 -0
  49. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/sorting.py +0 -0
  50. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/table_to_list_of_lists.py +0 -0
  51. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick/utils/utils.py +0 -0
  52. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick.egg-info/dependency_links.txt +0 -0
  53. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick.egg-info/entry_points.txt +0 -0
  54. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick.egg-info/requires.txt +0 -0
  55. {listpick-0.1.13.58 → listpick-0.1.13.59}/src/listpick.egg-info/top_level.txt +0 -0
  56. {listpick-0.1.13.58 → listpick-0.1.13.59}/tests/kitty_control.sh +0 -0
  57. {listpick-0.1.13.58 → listpick-0.1.13.59}/tests/sorting_dates.csv +0 -0
@@ -26,6 +26,9 @@
26
26
  - Added pin_cursor options which keeps the cursor on the same row during a refresh rather than tracking the id of the highlighted row.
27
27
  - Updated StandardFooter. Now shows information on two lines rather than three; all cursor and selection information on the first line and the sort information on the second. Cursor, Visual (de)selection now abreviated to C, VS, and VDS.
28
28
  - Added try-except wrapper to draw_screen function to prevent crashes during rapid resizing.
29
+ - Speed improvements:
30
+ - Create and track self.selected_cells_by_row when selections change rather than derive it from the self.cell_selections
31
+ - Much faster with very large data sets as we need to determine selected_cells_by_row every time we run self.draw_screen()
29
32
 
30
33
  ## [0.1.13] 2025-07-28
31
34
  - Cell-based picker is now supported.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: listpick
3
- Version: 0.1.13.58
3
+ Version: 0.1.13.59
4
4
  Summary: Listpick is a powerful TUI data tool for creating TUI apps or viewing/comparing tabulated data.
5
5
  Home-page: https://github.com/grimandgreedy/listpick
6
6
  Author: Grim
@@ -16,7 +16,7 @@ with open("README.md", "r", encoding = "utf-8") as fh:
16
16
 
17
17
  setuptools.setup(
18
18
  name = "listpick",
19
- version = "0.1.13.58",
19
+ version = "0.1.13.59",
20
20
  author = "Grim",
21
21
  author_email = "grimandgreedy@protonmail.com",
22
22
  description = "Listpick is a powerful TUI data tool for creating TUI apps or viewing/comparing tabulated data.",
@@ -1235,7 +1235,7 @@ class Picker:
1235
1235
  while True:
1236
1236
  h, w = stdscr.getmaxyx()
1237
1237
 
1238
- choose_opts_widths = get_column_widths(options)
1238
+ choose_opts_widths = get_column_widths(options, unicode_char_width=self.unicode_char_width)
1239
1239
  window_width = min(max(sum(choose_opts_widths) + 6, 50) + 6, w)
1240
1240
  window_height = min(h//2, max(6, len(options)+3))
1241
1241
 
@@ -3160,7 +3160,7 @@ def main() -> None:
3160
3160
  function_data["display_infobox"] = True
3161
3161
  function_data["infobox_items"] = [["1"], ["2"], ["3"]]
3162
3162
  function_data["infobox_title"] = "Title"
3163
- function_data["footer_string"] = "Title"
3163
+ # function_data["footer_string"] = "Title"
3164
3164
  function_data["highlights"] = highlights
3165
3165
  function_data["show_footer"] = False
3166
3166
  # function_data["debug"] = True
@@ -0,0 +1,202 @@
1
+ """
2
+ footer.py
3
+ Lines to be displayed on the help screen.
4
+
5
+ Author: GrimAndGreedy
6
+ License: MIT
7
+ """
8
+
9
+ import curses
10
+ import logging
11
+
12
+ logger = logging.getLogger('picker_log')
13
+
14
+ class Footer:
15
+ def __init__(self, stdscr, colours_start, get_state_function):
16
+ """
17
+ stdscr: curses screen object
18
+ colours_start: base colour pair index
19
+ get_state_callback: function that returns a dict with all required data for rendering
20
+ """
21
+ self.stdscr = stdscr
22
+ self.colours_start = colours_start
23
+ self.get_state = get_state_function
24
+ self.height = 0
25
+
26
+ def draw(self, h, w):
27
+ """
28
+ Draw the footer. Must be implemented by subclasses.
29
+ """
30
+ raise NotImplementedError
31
+
32
+ class StandardFooter(Footer):
33
+ def __init__(self, stdscr, colours_start, get_state_function):
34
+ """
35
+ stdscr: curses screen object
36
+ colours_start: base colour pair index
37
+ get_state_callback: function that returns a dict with all required data for rendering
38
+ """
39
+ self.stdscr = stdscr
40
+ self.colours_start = colours_start
41
+ self.get_state = get_state_function
42
+ self.height = 3
43
+ def draw(self, h, w):
44
+ state = self.get_state()
45
+
46
+ # Fill background
47
+ for i in range(3):
48
+ self.stdscr.addstr(h-3+i, 0, ' '*(w-1), curses.color_pair(self.colours_start+20))
49
+
50
+ if state["filter_query"]:
51
+ self.stdscr.addstr(h - 2, 2, f" Filter: {state['filter_query']} "[:w-40], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
52
+ if state["search_query"]:
53
+ self.stdscr.addstr(h - 3, 2, f" Search: {state['search_query']} [{state['search_index']}/{state['search_count']}] "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
54
+ if state["user_opts"]:
55
+ self.stdscr.addstr(h - 1, 2, f" Opts: {state['user_opts']} "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
56
+
57
+ # Sort info
58
+ sort_column_info = f"{state['sort_column'] if state['sort_column'] is not None else 'None'}"
59
+ sort_method_info = f"{state['SORT_METHODS'][state['columns_sort_method'][state['sort_column']]]}" if state['sort_column'] is not None else "NA"
60
+ sort_order_info = "Desc." if state["sort_reverse"] else "Asc."
61
+ sort_order_info = "▼" if state["sort_reverse"][state['sort_column']] else "▲"
62
+ sort_disp_str = f" Sort: ({sort_column_info}, {sort_method_info}, {sort_order_info}) "
63
+ self.stdscr.addstr(h - 2, w-35, f"{sort_disp_str:>34}", curses.color_pair(self.colours_start+20))
64
+
65
+ if state["footer_string"]:
66
+ # footer_string_width = min(w-1, max(len(state["footer_string"]), 50))
67
+ # disp_string = f"{state['footer_string'][:footer_string_width]:>{footer_string_width-1}} "
68
+ # self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
69
+ # self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
70
+
71
+ # disp_string = f"{footer_string:>{footer_string_width-1}} "
72
+ # self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
73
+ # self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
74
+
75
+ footer_string_width = min(w-1, len(state["footer_string"])+2)
76
+
77
+ disp_string = f"{state["footer_string"][:footer_string_width]}"
78
+ disp_string = f" {disp_string:>{footer_string_width-2}} "
79
+ self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
80
+ self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
81
+
82
+
83
+ else:
84
+ select_mode = "Cursor"
85
+ if state["is_selecting"]: select_mode = "Visual Selection"
86
+ elif state["is_deselecting"]: select_mode = "Visual deselection"
87
+ self.stdscr.addstr(h - 1, w-35, f"{select_mode:>33} ", curses.color_pair(self.colours_start+20))
88
+
89
+ # Cursor & selection info
90
+ selected_count = sum(state["selections"].values())
91
+ if state["paginate"]:
92
+ cursor_disp_str = f" {state['cursor_pos']+1}/{len(state['indexed_items'])} Page {state['cursor_pos']//state['items_per_page']}/{len(state['indexed_items'])} Selected {selected_count}"
93
+ else:
94
+ cursor_disp_str = f" {state['cursor_pos']+1}/{len(state['indexed_items'])} | Selected {selected_count}"
95
+ self.stdscr.addstr(h - 3, w-35, f"{cursor_disp_str:>33} ", curses.color_pair(self.colours_start+20))
96
+
97
+ self.stdscr.refresh()
98
+
99
+
100
+
101
+ class CompactFooter(Footer):
102
+ def __init__(self, stdscr, colours_start, get_state_function):
103
+ """
104
+ stdscr: curses screen object
105
+ colours_start: base colour pair index
106
+ get_state_callback: function that returns a dict with all required data for rendering
107
+ """
108
+ self.stdscr = stdscr
109
+ self.colours_start = colours_start
110
+ self.get_state = get_state_function
111
+ self.height = 1
112
+
113
+ def draw(self, h, w):
114
+ state = self.get_state()
115
+
116
+ # Fill background
117
+ if state["search_query"]: self.height = 3
118
+ elif state["filter_query"]: self.height = 2
119
+ elif state["user_opts"]: self.height = 1
120
+ elif state["footer_string"]: self.height = 2
121
+ else: self.height = 1
122
+ for i in range(self.height):
123
+ self.stdscr.addstr(h-(i+1), 0, ' '*(w-1), curses.color_pair(self.colours_start+20))
124
+
125
+ if state["user_opts"]:
126
+ self.stdscr.addstr(h - 1, 2, f" Opts: {state['user_opts']} "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
127
+ if state["filter_query"]:
128
+ self.stdscr.addstr(h - 2, 2, f" Filter: {state['filter_query']} "[:w-40], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
129
+ if state["search_query"]:
130
+ self.stdscr.addstr(h - 3, 2, f" Search: {state['search_query']} [{state['search_index']}/{state['search_count']}] "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
131
+
132
+ right_width = 40
133
+ # Sort info
134
+ sort_column_info = f"{state['sort_column'] if state['sort_column'] is not None else 'None'}"
135
+ sort_method_info = f"{state['SORT_METHODS'][state['columns_sort_method'][state['sort_column']]]}" if state['sort_column'] is not None else "NA"
136
+ sort_order_info = "Desc." if state["sort_reverse"][state['sort_column']] else "Asc."
137
+ sort_order_info = "▼" if state["sort_reverse"][state['sort_column']] else "▲"
138
+ sort_disp_str = f" ({sort_column_info}, {sort_method_info}, {sort_order_info}) "
139
+ # self.stdscr.addstr(h - 2, w-right_width, f"{sort_disp_str:>{right_width-1}}", curses.color_pair(self.colours_start+20))
140
+
141
+ if state["footer_string"]:
142
+ footer_string_width = min(w-1, len(state["footer_string"])+2)
143
+
144
+ disp_string = f"{state["footer_string"][:footer_string_width]}"
145
+ disp_string = f" {disp_string:>{footer_string_width-2}} "
146
+ self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
147
+ self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
148
+ selected_count = sum(state["selections"].values())
149
+ if state["paginate"]:
150
+ cursor_disp_str = f" {state['cursor_pos']+1}/{len(state['indexed_items'])} Page {state['cursor_pos']//state['items_per_page']}/{len(state['indexed_items'])} Selected {selected_count}"
151
+ else:
152
+ cursor_disp_str = f"{sort_disp_str} [{selected_count}] {state['cursor_pos']+1}/{len(state['indexed_items'])}"
153
+ self.stdscr.addstr(h-2, w-right_width, f"{cursor_disp_str:>{right_width-2}}"[:right_width-1], curses.color_pair(self.colours_start+20))
154
+ else:
155
+ # Cursor & selection info
156
+ selected_count = sum(state["selections"].values())
157
+ if state["paginate"]:
158
+ cursor_disp_str = f" {state['cursor_pos']+1}/{len(state['indexed_items'])} Page {state['cursor_pos']//state['items_per_page']}/{len(state['indexed_items'])} Selected {selected_count}"
159
+ else:
160
+ cursor_disp_str = f"{sort_disp_str} [{selected_count}] {state['cursor_pos']+1}/{len(state['indexed_items'])}"
161
+ self.stdscr.addstr(h - 1, w-right_width, f"{cursor_disp_str:>{right_width-2}}"[:right_width-1], curses.color_pair(self.colours_start+20))
162
+
163
+ self.stdscr.refresh()
164
+
165
+ class NoFooter(Footer):
166
+ def __init__(self, stdscr, colours_start, get_state_function):
167
+ """
168
+ stdscr: curses screen object
169
+ colours_start: base colour pair index
170
+ get_state_callback: function that returns a dict with all required data for rendering
171
+ """
172
+ self.stdscr = stdscr
173
+ self.colours_start = colours_start
174
+ self.get_state = get_state_function
175
+ self.height = 0
176
+ def draw(self, h, w):
177
+ state = self.get_state()
178
+
179
+ if state["search_query"]: self.height = 3
180
+ elif state["filter_query"]: self.height = 2
181
+ elif state["user_opts"]: self.height = 1
182
+ elif state["footer_string"]: self.height = 1
183
+ else: self.height = 0
184
+
185
+ for i in range(self.height):
186
+ self.stdscr.addstr(h-(i+1), 0, ' '*(w-1), curses.color_pair(self.colours_start+20))
187
+
188
+ if state["user_opts"]:
189
+ self.stdscr.addstr(h - 1, 2, f" Opts: {state['user_opts']} "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
190
+ if state["filter_query"]:
191
+ self.stdscr.addstr(h - 2, 2, f" Filter: {state['filter_query']} "[:w-40], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
192
+ if state["search_query"]:
193
+ self.stdscr.addstr(h - 3, 2, f" Search: {state['search_query']} [{state['search_index']}/{state['search_count']}] "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
194
+ self.height = 3
195
+
196
+
197
+ if state["footer_string"]:
198
+ footer_string_width = min(w-1, len(state["footer_string"])+2)
199
+ disp_string = f"{state["footer_string"][:footer_string_width]}"
200
+ disp_string = f" {disp_string:>{footer_string_width-2}} "
201
+ self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
202
+ self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: listpick
3
- Version: 0.1.13.58
3
+ Version: 0.1.13.59
4
4
  Summary: Listpick is a powerful TUI data tool for creating TUI apps or viewing/comparing tabulated data.
5
5
  Home-page: https://github.com/grimandgreedy/listpick
6
6
  Author: Grim
@@ -21,7 +21,6 @@ examples/video_duplicates.toml
21
21
  src/listpick/__init__.py
22
22
  src/listpick/__main__.py
23
23
  src/listpick/listpick_app.py
24
- src/listpick/listpick_app_problem_branch.py
25
24
  src/listpick.egg-info/PKG-INFO
26
25
  src/listpick.egg-info/SOURCES.txt
27
26
  src/listpick.egg-info/dependency_links.txt
@@ -31,6 +30,7 @@ src/listpick.egg-info/top_level.txt
31
30
  src/listpick/ui/__init__.py
32
31
  src/listpick/ui/build_help.py
33
32
  src/listpick/ui/footer.py
33
+ src/listpick/ui/footer_1.py
34
34
  src/listpick/ui/help_screen.py
35
35
  src/listpick/ui/input_field.py
36
36
  src/listpick/ui/keys.py