listpick 0.1.13.55__py3-none-any.whl → 0.1.13.56__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.
- listpick/listpick_app.py +87 -196
- listpick/ui/footer.py +47 -34
- listpick/utils/utils.py +24 -50
- {listpick-0.1.13.55.dist-info → listpick-0.1.13.56.dist-info}/METADATA +1 -1
- {listpick-0.1.13.55.dist-info → listpick-0.1.13.56.dist-info}/RECORD +9 -12
- listpick/listpick_app_1.py +0 -3250
- listpick/lpapp2.py +0 -3153
- listpick/ui/footer_1.py +0 -213
- {listpick-0.1.13.55.dist-info → listpick-0.1.13.56.dist-info}/WHEEL +0 -0
- {listpick-0.1.13.55.dist-info → listpick-0.1.13.56.dist-info}/entry_points.txt +0 -0
- {listpick-0.1.13.55.dist-info → listpick-0.1.13.56.dist-info}/licenses/LICENSE.txt +0 -0
- {listpick-0.1.13.55.dist-info → listpick-0.1.13.56.dist-info}/top_level.txt +0 -0
listpick/ui/footer.py
CHANGED
|
@@ -39,39 +39,21 @@ class StandardFooter(Footer):
|
|
|
39
39
|
self.stdscr = stdscr
|
|
40
40
|
self.colours_start = colours_start
|
|
41
41
|
self.get_state = get_state_function
|
|
42
|
-
|
|
42
|
+
|
|
43
|
+
self.height = 2
|
|
44
|
+
try:
|
|
45
|
+
state = self.get_state()
|
|
46
|
+
if "footer_string" in state and state["footer_string"]: self.height = 3
|
|
47
|
+
else: self.height = 2
|
|
48
|
+
except:
|
|
49
|
+
logger.error("Error encountered when running StandardFooter.get_state")
|
|
43
50
|
def draw(self, h, w):
|
|
44
51
|
state = self.get_state()
|
|
45
|
-
|
|
46
52
|
# Fill background
|
|
47
|
-
for i in range(
|
|
48
|
-
self.stdscr.addstr(h-
|
|
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))
|
|
53
|
+
for i in range(self.height):
|
|
54
|
+
self.stdscr.addstr(h-self.height+i, 0, ' '*(w-1), curses.color_pair(self.colours_start+20))
|
|
64
55
|
|
|
65
56
|
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
57
|
footer_string_width = min(w-1, len(state["footer_string"])+2)
|
|
76
58
|
|
|
77
59
|
disp_string = f"{state["footer_string"][:footer_string_width]}"
|
|
@@ -79,20 +61,51 @@ class StandardFooter(Footer):
|
|
|
79
61
|
self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
|
|
80
62
|
self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
|
|
81
63
|
|
|
64
|
+
picker_info_y = h-3
|
|
65
|
+
sort_info_y = h-2
|
|
66
|
+
self.height = 3
|
|
82
67
|
|
|
83
68
|
else:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
69
|
+
picker_info_y = h-2
|
|
70
|
+
sort_info_y = h-1
|
|
71
|
+
""
|
|
72
|
+
select_mode = "C"
|
|
73
|
+
if state["is_selecting"]: select_mode = "VS"
|
|
74
|
+
elif state["is_deselecting"]: select_mode = "VDS"
|
|
75
|
+
if state["pin_cursor"]: select_mode = f"{select_mode} "
|
|
87
76
|
self.stdscr.addstr(h - 1, w-35, f"{select_mode:>33} ", curses.color_pair(self.colours_start+20))
|
|
77
|
+
self.height = 2
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if state["filter_query"]:
|
|
81
|
+
self.stdscr.addstr(h - 2, 2, f" Filter: {state['filter_query']} "[:w-40], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
|
|
82
|
+
if state["search_query"]:
|
|
83
|
+
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)
|
|
84
|
+
if state["user_opts"]:
|
|
85
|
+
self.stdscr.addstr(h - 1, 2, f" Opts: {state['user_opts']} "[:w-3], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
|
|
86
|
+
|
|
88
87
|
|
|
88
|
+
|
|
89
|
+
select_mode = "C"
|
|
90
|
+
if state["is_selecting"]: select_mode = "VS"
|
|
91
|
+
elif state["is_deselecting"]: select_mode = "VDS"
|
|
92
|
+
if state["pin_cursor"]: select_mode = f"{select_mode} "
|
|
89
93
|
# Cursor & selection info
|
|
90
94
|
selected_count = sum(state["selections"].values())
|
|
91
95
|
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'])}
|
|
96
|
+
cursor_disp_str = f" [{selected_count}] {state['cursor_pos']+1}/{len(state['indexed_items'])} Page {state['cursor_pos']//state['items_per_page']}/{len(state['indexed_items'])}"
|
|
93
97
|
else:
|
|
94
|
-
cursor_disp_str = f" {state['cursor_pos']+1}/{len(state['indexed_items'])}
|
|
95
|
-
self.stdscr.addstr(
|
|
98
|
+
cursor_disp_str = f" [{selected_count}] {state['cursor_pos']+1}/{len(state['indexed_items'])} | {select_mode}"
|
|
99
|
+
self.stdscr.addstr(picker_info_y, w-35, f"{cursor_disp_str:>33} ", curses.color_pair(self.colours_start+20))
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# Sort info
|
|
103
|
+
sort_column_info = f"{state['sort_column'] if state['sort_column'] is not None else 'None'}"
|
|
104
|
+
sort_method_info = f"{state['SORT_METHODS'][state['columns_sort_method'][state['sort_column']]]}" if state['sort_column'] is not None else "NA"
|
|
105
|
+
sort_order_info = "Desc." if state["sort_reverse"] else "Asc."
|
|
106
|
+
sort_order_info = "▼" if state["sort_reverse"][state['sort_column']] else "▲"
|
|
107
|
+
sort_disp_str = f" Sort: ({sort_column_info}, {sort_method_info}, {sort_order_info}) "
|
|
108
|
+
self.stdscr.addstr(sort_info_y, w-35, f"{sort_disp_str:>34}", curses.color_pair(self.colours_start+20))
|
|
96
109
|
|
|
97
110
|
self.stdscr.refresh()
|
|
98
111
|
|
listpick/utils/utils.py
CHANGED
|
@@ -36,7 +36,7 @@ def clip_left(text, n):
|
|
|
36
36
|
width += char_width
|
|
37
37
|
return text # If the total width is less than n, return the full string
|
|
38
38
|
|
|
39
|
-
def truncate_to_display_width(text: str, max_column_width: int, centre=False
|
|
39
|
+
def truncate_to_display_width(text: str, max_column_width: int, centre=False) -> str:
|
|
40
40
|
"""
|
|
41
41
|
Truncate and/or pad text to max_column_width using wcwidth to ensure visual width is correct
|
|
42
42
|
with foreign character sets.
|
|
@@ -46,36 +46,19 @@ def truncate_to_display_width(text: str, max_column_width: int, centre=False, un
|
|
|
46
46
|
|
|
47
47
|
"""
|
|
48
48
|
# logger.debug("function: truncate_to_display_width (utils.py)")
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
# test_str = text[:max_column_width]
|
|
64
|
-
# while True:
|
|
65
|
-
# width = wcswidth(test_str)
|
|
66
|
-
# if width < max_column_width or width == 0:
|
|
67
|
-
# break
|
|
68
|
-
# test_str = test_str[:-1]
|
|
69
|
-
# result = test_str
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
# Pad if it's shorter
|
|
73
|
-
# padding = max_column_width - wcswidth(result)
|
|
74
|
-
# return result + ' ' * padding
|
|
75
|
-
else:
|
|
76
|
-
result = text[:max_column_width]
|
|
77
|
-
width = len(result)
|
|
78
|
-
padding = max_column_width - width
|
|
49
|
+
result = ''
|
|
50
|
+
width = 0
|
|
51
|
+
for char in text:
|
|
52
|
+
w = wcwidth(char)
|
|
53
|
+
if w < 0:
|
|
54
|
+
continue
|
|
55
|
+
if width + w > max_column_width:
|
|
56
|
+
break
|
|
57
|
+
result += char
|
|
58
|
+
width += w
|
|
59
|
+
# Pad if it's shorter
|
|
60
|
+
padding = max_column_width - wcswidth(result)
|
|
61
|
+
# return result + ' ' * padding
|
|
79
62
|
if centre:
|
|
80
63
|
result = ' '*(padding//2) + result + ' '*(padding//2 + padding%2)
|
|
81
64
|
else:
|
|
@@ -100,7 +83,7 @@ def format_full_row(row:str) -> str:
|
|
|
100
83
|
return '\t'.join(row)
|
|
101
84
|
|
|
102
85
|
|
|
103
|
-
def format_row(row: list[str], hidden_columns: list, column_widths: list[int], separator: str, centre:bool=False
|
|
86
|
+
def format_row(row: list[str], hidden_columns: list, column_widths: list[int], separator: str, centre:bool=False) -> str:
|
|
104
87
|
""" Format list of strings as a single string. Requires separator string and the maximum width of the columns. """
|
|
105
88
|
row_str = ""
|
|
106
89
|
for i, cell in enumerate(row):
|
|
@@ -108,22 +91,20 @@ def format_row(row: list[str], hidden_columns: list, column_widths: list[int], s
|
|
|
108
91
|
# if is_formula_cell(cell):
|
|
109
92
|
# cell = evaluate_cell(cell)
|
|
110
93
|
|
|
111
|
-
val = truncate_to_display_width(str(cell), column_widths[i], centre
|
|
94
|
+
val = truncate_to_display_width(str(cell), column_widths[i], centre)
|
|
112
95
|
row_str += val + separator
|
|
113
96
|
return row_str
|
|
97
|
+
# return row_str.strip()
|
|
114
98
|
|
|
115
|
-
def get_column_widths(items: list[list[str]], header: list[str]=[], max_column_width:int=70, number_columns:bool=True, max_total_width=-1, separator = " "
|
|
99
|
+
def get_column_widths(items: list[list[str]], header: list[str]=[], max_column_width:int=70, number_columns:bool=True, max_total_width=-1, separator = " ") -> list[int]:
|
|
116
100
|
""" Calculate maximum width of each column with clipping. """
|
|
117
101
|
if len(items) == 0: return [0]
|
|
118
102
|
assert len(items) > 0
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
header_widths = [wcswidth(f"{i}. {str(h)}") if number_columns else wcswidth(str(h)) for i, h in enumerate(header)]
|
|
125
|
-
col_widths = [min(max_column_width, max(widths[i], header_widths[i])) for i in range(len(header))]
|
|
126
|
-
|
|
103
|
+
widths = [max(wcswidth(str(row[i])) for row in items) for i in range(len(items[0]))]
|
|
104
|
+
# widths = [max(len(str(row[i])) for row in items) for i in range(len(items[0]))]
|
|
105
|
+
if header:
|
|
106
|
+
header_widths = [wcswidth(f"{i}. {str(h)}") if number_columns else wcswidth(str(h)) for i, h in enumerate(header)]
|
|
107
|
+
col_widths = [min(max_column_width, max(widths[i], header_widths[i])) for i in range(len(header))]
|
|
127
108
|
# actual_max_widths = [max(header_widths[i], widths[i]) for i in range(len(widths))]
|
|
128
109
|
#
|
|
129
110
|
# if sum(col_widths) + len(separator)*(len(col_widths)-1) < max_total_width:
|
|
@@ -143,15 +124,8 @@ def get_column_widths(items: list[list[str]], header: list[str]=[], max_column_w
|
|
|
143
124
|
# else:
|
|
144
125
|
# # Maximise balance.....
|
|
145
126
|
# pass
|
|
146
|
-
else:
|
|
147
|
-
col_widths = [min(max_column_width, width) for width in widths]
|
|
148
127
|
else:
|
|
149
|
-
|
|
150
|
-
if header:
|
|
151
|
-
header_widths = [len(f"{i}. {str(h)}") if number_columns else len(str(h)) for i, h in enumerate(header)]
|
|
152
|
-
col_widths = [min(max_column_width, max(widths[i], header_widths[i])) for i in range(len(header))]
|
|
153
|
-
else:
|
|
154
|
-
col_widths = [min(max_column_width, width) for width in widths]
|
|
128
|
+
col_widths = [min(max_column_width, width) for width in widths]
|
|
155
129
|
return col_widths
|
|
156
130
|
|
|
157
131
|
def get_mode_widths(item_list: list[str]) -> list[int]:
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
listpick/__init__.py,sha256=ExXc97-bibodH--wlwpQivl0zCNR5D1hvpvrf7OBofU,154
|
|
2
2
|
listpick/__main__.py,sha256=wkCjDdqw093W27yWwnlC3nG_sMRKaIad7hHHWy0RBgY,193
|
|
3
|
-
listpick/listpick_app.py,sha256=
|
|
4
|
-
listpick/listpick_app_1.py,sha256=6KULvZKkHpI8y0Z48Qo5_hrKfd1S3khdScLLJtlPIjI,166651
|
|
5
|
-
listpick/lpapp2.py,sha256=x26FOsUPgwjiAecF8gGE8GbfCQF6eJGgf4hccqSZIBU,162376
|
|
3
|
+
listpick/listpick_app.py,sha256=DcijE4rOpAcEF1JE9H6G0iUbDgpYQO5QaSkf2VavfL4,161560
|
|
6
4
|
listpick/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
5
|
listpick/ui/build_help.py,sha256=_rVKKrX3HfFJtw-pyeNb2lQWbml4-AAw8sZIUYGn97Y,8731
|
|
8
|
-
listpick/ui/footer.py,sha256=
|
|
9
|
-
listpick/ui/footer_1.py,sha256=po8abQfaVNoWxYJCw8fENENIdOvNmLIZYfuqTwagz00,10713
|
|
6
|
+
listpick/ui/footer.py,sha256=s1L68MNmhWwbWRy0mn0ChmnE_dMQBAzNlTv917pyHE0,10673
|
|
10
7
|
listpick/ui/help_screen.py,sha256=zbfGIgb-IXtATpl4_Sx7nPbsnRXZ7eiMYlCKGS9EFmw,5608
|
|
11
8
|
listpick/ui/input_field.py,sha256=eyoWHoApdZybjfXcp7Eth7xwb-C-856ZVnq5j_Q3Ojs,30412
|
|
12
9
|
listpick/ui/keys.py,sha256=TzaadgBP_rC7jbp--RFJZDOkHd0EB4K1wToDTiVs6CI,13029
|
|
@@ -25,10 +22,10 @@ listpick/utils/search_and_filter_utils.py,sha256=XxGfkyDVXO9OAKcftPat8IReMTFIuTH
|
|
|
25
22
|
listpick/utils/searching.py,sha256=Xk5UIqamNHL2L90z3ACB_Giqdpi9iRKoAJ6pKaqaD7Q,3093
|
|
26
23
|
listpick/utils/sorting.py,sha256=WZZiVlVA3Zkcpwji3U5SNFlQ14zVEk3cZJtQirBkecQ,5329
|
|
27
24
|
listpick/utils/table_to_list_of_lists.py,sha256=T-i-nV1p6g8UagdgUPKrhIGpKY_YXZDxf4xZzcPepNA,7635
|
|
28
|
-
listpick/utils/utils.py,sha256=
|
|
29
|
-
listpick-0.1.13.
|
|
30
|
-
listpick-0.1.13.
|
|
31
|
-
listpick-0.1.13.
|
|
32
|
-
listpick-0.1.13.
|
|
33
|
-
listpick-0.1.13.
|
|
34
|
-
listpick-0.1.13.
|
|
25
|
+
listpick/utils/utils.py,sha256=8nsjjTDQH13tHTU93YcKklLQ_uuMAz-rbDTmao83T4Q,12783
|
|
26
|
+
listpick-0.1.13.56.dist-info/licenses/LICENSE.txt,sha256=2mP-MRHJptADDNE9VInMNg1tE-C6Qv93Z4CCQKrpg9w,1061
|
|
27
|
+
listpick-0.1.13.56.dist-info/METADATA,sha256=mCnB_Vdd2nwucGm7IdpyuwFJ37RIA0kjEq9kBn6voxI,7988
|
|
28
|
+
listpick-0.1.13.56.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
29
|
+
listpick-0.1.13.56.dist-info/entry_points.txt,sha256=-QCf_BKIkUz35Y9nkYpjZWs2Qg0KfRna2PAs5DnF6BE,43
|
|
30
|
+
listpick-0.1.13.56.dist-info/top_level.txt,sha256=5mtsGEz86rz3qQDe0D463gGjAfSp6A3EWg4J4AGYr-Q,9
|
|
31
|
+
listpick-0.1.13.56.dist-info/RECORD,,
|