listpick 0.1.13.55__tar.gz → 0.1.13.57__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.
- {listpick-0.1.13.55 → listpick-0.1.13.57}/CHANGELOG.md +0 -11
- {listpick-0.1.13.55/src/listpick.egg-info → listpick-0.1.13.57}/PKG-INFO +1 -1
- {listpick-0.1.13.55 → listpick-0.1.13.57}/TODO.md +0 -4
- {listpick-0.1.13.55 → listpick-0.1.13.57}/setup.py +1 -1
- listpick-0.1.13.55/src/listpick/lpapp2.py → listpick-0.1.13.57/src/listpick/listpick_app.py +57 -61
- listpick-0.1.13.55/src/listpick/ui/footer_1.py → listpick-0.1.13.57/src/listpick/ui/footer.py +6 -4
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/utils.py +24 -50
- {listpick-0.1.13.55 → listpick-0.1.13.57/src/listpick.egg-info}/PKG-INFO +1 -1
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick.egg-info/SOURCES.txt +0 -3
- listpick-0.1.13.55/src/listpick/listpick_app.py +0 -3250
- listpick-0.1.13.55/src/listpick/listpick_app_1.py +0 -3250
- listpick-0.1.13.55/src/listpick/ui/footer.py +0 -202
- {listpick-0.1.13.55 → listpick-0.1.13.57}/.gitignore +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/LICENSE.txt +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/README.md +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/assets/aria2tui_screenshot.png +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/assets/file_compare.png +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/assets/lpfman.png +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/footer_string_example.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/input.toml +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/input.txt +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/list_files.toml +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/list_files_empty.toml +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/picker_example.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/setup.cfg +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/template.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/video_duplicates.toml +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/listpick.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/requirements.txt +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/setup.cfg +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/__init__.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/__main__.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/__init__.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/build_help.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/help_screen.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/input_field.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/keys.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/pane_stuff.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/picker_colours.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/__init__.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/clipboard_operations.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/config.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/dump.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/filtering.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/generate_data.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/options_selectors.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/paste_operations.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/picker_log.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/search_and_filter_utils.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/searching.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/sorting.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/table_to_list_of_lists.py +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick.egg-info/dependency_links.txt +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick.egg-info/entry_points.txt +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick.egg-info/requires.txt +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick.egg-info/top_level.txt +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/tests/kitty_control.sh +0 -0
- {listpick-0.1.13.55 → listpick-0.1.13.57}/tests/sorting_dates.csv +0 -0
|
@@ -25,17 +25,6 @@
|
|
|
25
25
|
- Setup logging for the Picker class. Currently still very basic but will track to the last function that was run before crash if the --debug flag is passed to the picker.
|
|
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
|
-
- Reduced flickering when displaying an infobox.
|
|
29
|
-
- Optimised cpu usage by created a class variable selected_cells_by_row which updates with selection/deselection rather than being determined each time the draw_screen loop is run.
|
|
30
|
-
- Added unicode_char_width option which will set the calculating character widths. If True then wcwidth will be used to calculate the display with if False then len will be used.
|
|
31
|
-
- unicode_char_width should be set to true if special characters will be displayed
|
|
32
|
-
- Special characters=East Asian scripts, emojis, etc.
|
|
33
|
-
- With data that has several thousand columns wcwidth is extremely slow so unicode_char_width should be set to False.
|
|
34
|
-
- Speed improvements:
|
|
35
|
-
- get_column_widths calculated only once when drawing the screen.
|
|
36
|
-
- unicode_char_width option to improve performance with large (in particular wide) data sets.
|
|
37
|
-
- truncate_to_display width now guesses the target width and then adjusts rather than adding one display-width character at a time. 5-10 times faster.
|
|
38
|
-
- Reduced number of calls to draw_screen. It is called (1) when a key is pressed, (2) before showing a notification, and (3) when the data is refreshed.
|
|
39
28
|
|
|
40
29
|
## [0.1.13] 2025-07-28
|
|
41
30
|
- Cell-based picker is now supported.
|
|
@@ -5,9 +5,6 @@ ASAP
|
|
|
5
5
|
> - [ ] Unify in-app load and command-line input file
|
|
6
6
|
> - [ ] Implement default_option_selector and pass the picker options (!!!)
|
|
7
7
|
> - [ ] Make sure that all class initialisation variables are returned in the get_function_variables function.
|
|
8
|
-
> - [ ] Adjust leftmost_char when:
|
|
9
|
-
> - [ ] cursor_down
|
|
10
|
-
> - [ ] 'g', 'G'
|
|
11
8
|
|
|
12
9
|
|
|
13
10
|
|
|
@@ -117,7 +114,6 @@ ASAP
|
|
|
117
114
|
> - [x] Support pasting copied cells into the picker
|
|
118
115
|
> - [ ] Ensure that we can only paste when cells are editable.
|
|
119
116
|
> - [ ] Add option to insert cells; e.g., insert two columns and move the data to the right of the selected column across
|
|
120
|
-
> - [ ] Add support for pasting as a string
|
|
121
117
|
> - [ ] Support inserting cells/rows.
|
|
122
118
|
> - [ ] Bulk edit in nvim
|
|
123
119
|
> - [ ] Add formula and display value...
|
|
@@ -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.
|
|
19
|
+
version = "0.1.13.57",
|
|
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.",
|
|
@@ -140,7 +140,6 @@ class Picker:
|
|
|
140
140
|
footer_string_refresh_function: Optional[Callable] = None,
|
|
141
141
|
footer_timer: float=1,
|
|
142
142
|
get_footer_string_startup=False,
|
|
143
|
-
unicode_char_width: bool = True,
|
|
144
143
|
|
|
145
144
|
colours_start: int =0,
|
|
146
145
|
colours_end: int =-1,
|
|
@@ -257,7 +256,7 @@ class Picker:
|
|
|
257
256
|
self.footer_string_refresh_function = footer_string_refresh_function
|
|
258
257
|
self.footer_timer = footer_timer
|
|
259
258
|
self.get_footer_string_startup = get_footer_string_startup,
|
|
260
|
-
|
|
259
|
+
|
|
261
260
|
|
|
262
261
|
|
|
263
262
|
self.colours_start = colours_start
|
|
@@ -313,6 +312,8 @@ class Picker:
|
|
|
313
312
|
self.debug_level = debug_level
|
|
314
313
|
|
|
315
314
|
|
|
315
|
+
|
|
316
|
+
|
|
316
317
|
self.initialise_picker_state(reset_colours=self.reset_colours)
|
|
317
318
|
|
|
318
319
|
|
|
@@ -323,7 +324,6 @@ class Picker:
|
|
|
323
324
|
# self.footer = CompactFooter(self.stdscr, colours_start, self.get_function_data)
|
|
324
325
|
|
|
325
326
|
|
|
326
|
-
|
|
327
327
|
def calculate_section_sizes(self):
|
|
328
328
|
"""
|
|
329
329
|
Calculte the following for the Picker:
|
|
@@ -384,6 +384,7 @@ class Picker:
|
|
|
384
384
|
def initialise_picker_state(self, reset_colours=False) -> None:
|
|
385
385
|
""" Initialise state variables for the picker. These are: debugging and colours. """
|
|
386
386
|
|
|
387
|
+
|
|
387
388
|
if curses.has_colors() and self.colours != None:
|
|
388
389
|
# raise Exception("Terminal does not support color")
|
|
389
390
|
curses.start_color()
|
|
@@ -473,6 +474,7 @@ class Picker:
|
|
|
473
474
|
|
|
474
475
|
if len(self.indexed_items) > 0 and len(self.indexed_items) >= self.cursor_pos and len(self.indexed_items[0][1]) >= self.id_column:
|
|
475
476
|
self.cursor_pos_id = self.indexed_items[self.cursor_pos][1][self.id_column]
|
|
477
|
+
self.cursor_pos_prev = self.cursor_pos
|
|
476
478
|
|
|
477
479
|
self.items, self.header = self.refresh_function()
|
|
478
480
|
|
|
@@ -656,6 +658,14 @@ class Picker:
|
|
|
656
658
|
self.stdscr.refresh()
|
|
657
659
|
|
|
658
660
|
def draw_screen(self, indexed_items: list[Tuple[int, list[str]]], highlights: list[dict] = [{}], clear: bool = True) -> None:
|
|
661
|
+
""" Try-except wrapper for the draw_screen_ function. """
|
|
662
|
+
try:
|
|
663
|
+
self.draw_screen_(self.indexed_items, self.highlights)
|
|
664
|
+
except Exception as e:
|
|
665
|
+
self.logger.warning(f"self.draw_screen_() error. {e}")
|
|
666
|
+
pass
|
|
667
|
+
|
|
668
|
+
def draw_screen_(self, indexed_items: list[Tuple[int, list[str]]], highlights: list[dict] = [{}], clear: bool = True) -> None:
|
|
659
669
|
""" Draw Picker screen. """
|
|
660
670
|
self.logger.debug("Draw screen.")
|
|
661
671
|
|
|
@@ -679,12 +689,12 @@ class Picker:
|
|
|
679
689
|
end_index = min(start_index + self.items_per_page, len(self.indexed_items))
|
|
680
690
|
if len(self.indexed_items) == 0: start_index, end_index = 0, 0
|
|
681
691
|
|
|
682
|
-
# self.column_widths = get_column_widths(self.items, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns)
|
|
692
|
+
# self.column_widths = get_column_widths(self.items, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w)
|
|
683
693
|
# Determine widths based only on the currently indexed rows
|
|
684
694
|
# rows = [v[1] for v in self.indexed_items] if len(self.indexed_items) else self.items
|
|
685
695
|
# Determine widths based only on the currently displayed indexed rows
|
|
686
696
|
rows = [v[1] for v in self.indexed_items[start_index:end_index]] if len(self.indexed_items) else self.items
|
|
687
|
-
self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns)
|
|
697
|
+
self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w)
|
|
688
698
|
visible_column_widths = [c for i,c in enumerate(self.column_widths) if i not in self.hidden_columns]
|
|
689
699
|
visible_columns_total_width = sum(visible_column_widths) + len(self.separator)*(len(visible_column_widths)-1)
|
|
690
700
|
|
|
@@ -982,7 +992,6 @@ class Picker:
|
|
|
982
992
|
disp_string = f" {self.footer_string[:footer_string_width]:>{footer_string_width-2}} "
|
|
983
993
|
self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
|
|
984
994
|
self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
|
|
985
|
-
self.stdscr.refresh()
|
|
986
995
|
|
|
987
996
|
## Display infobox
|
|
988
997
|
if self.display_infobox:
|
|
@@ -1131,7 +1140,6 @@ class Picker:
|
|
|
1131
1140
|
"debug": self.debug,
|
|
1132
1141
|
"debug_level": self.debug_level,
|
|
1133
1142
|
"reset_colours": self.reset_colours,
|
|
1134
|
-
"unicode_char_width": self.unicode_char_width,
|
|
1135
1143
|
}
|
|
1136
1144
|
return function_data
|
|
1137
1145
|
|
|
@@ -1385,8 +1393,6 @@ class Picker:
|
|
|
1385
1393
|
self.initialise_variables()
|
|
1386
1394
|
elif setting == "pc":
|
|
1387
1395
|
self.pin_cursor = not self.pin_cursor
|
|
1388
|
-
elif setting == "unicode":
|
|
1389
|
-
self.unicode_char_width = not self.unicode_char_width
|
|
1390
1396
|
|
|
1391
1397
|
elif setting.startswith("ft"):
|
|
1392
1398
|
if len(setting) > 2 and setting[2:].isnumeric():
|
|
@@ -1450,6 +1456,7 @@ class Picker:
|
|
|
1450
1456
|
self.draw_screen(self.indexed_items, self.highlights)
|
|
1451
1457
|
self.notification(self.stdscr, message=f"Theme {self.colour_theme_number} applied.")
|
|
1452
1458
|
|
|
1459
|
+
|
|
1453
1460
|
else:
|
|
1454
1461
|
self.user_settings = ""
|
|
1455
1462
|
return None
|
|
@@ -1520,18 +1527,9 @@ class Picker:
|
|
|
1520
1527
|
xend = max(self.start_selection_col, self.selected_column)
|
|
1521
1528
|
for i in range(ystart, yend + 1):
|
|
1522
1529
|
if self.indexed_items[i][0] not in self.unselectable_indices:
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
self.selected_cells_by_row[row] = []
|
|
1526
|
-
|
|
1527
|
-
for col in range(xstart, xend+1):
|
|
1528
|
-
cell_index = (row, col)
|
|
1530
|
+
for j in range(xstart, xend+1):
|
|
1531
|
+
cell_index = (self.indexed_items[i][0], j)
|
|
1529
1532
|
self.cell_selections[cell_index] = True
|
|
1530
|
-
|
|
1531
|
-
self.selected_cells_by_row[row].append(col)
|
|
1532
|
-
# Remove duplicates
|
|
1533
|
-
self.selected_cells_by_row[row] = list(set(self.selected_cells_by_row[row]))
|
|
1534
|
-
|
|
1535
1533
|
self.start_selection = -1
|
|
1536
1534
|
self.end_selection = -1
|
|
1537
1535
|
self.is_selecting = False
|
|
@@ -1565,6 +1563,8 @@ class Picker:
|
|
|
1565
1563
|
def cursor_down(self, count=1) -> bool:
|
|
1566
1564
|
""" Move cursor down. """
|
|
1567
1565
|
self.logger.info(f"function: cursor_down()")
|
|
1566
|
+
if len(self.indexed_items) == 0 or self.cursor_pos == len(self.indexed_items) -1:
|
|
1567
|
+
return False
|
|
1568
1568
|
# Returns: whether page is turned
|
|
1569
1569
|
new_pos = self.cursor_pos + 1
|
|
1570
1570
|
new_pos = min(self.cursor_pos+count, len(self.indexed_items)-1)
|
|
@@ -1783,6 +1783,7 @@ class Picker:
|
|
|
1783
1783
|
|
|
1784
1784
|
if len(self.indexed_items) > 0 and len(self.indexed_items) >= self.cursor_pos and len(self.indexed_items[0][1]) >= self.id_column:
|
|
1785
1785
|
self.cursor_pos_id = self.indexed_items[self.cursor_pos][1][self.id_column]
|
|
1786
|
+
self.cursor_pos_prev = self.cursor_pos
|
|
1786
1787
|
with self.data_lock:
|
|
1787
1788
|
self.items, self.header = tmp_items, tmp_header
|
|
1788
1789
|
self.data_ready = True
|
|
@@ -1832,7 +1833,7 @@ class Picker:
|
|
|
1832
1833
|
|
|
1833
1834
|
def get_word_list(self) -> list[str]:
|
|
1834
1835
|
""" Get a list of all words used in any cell of the picker. Used for completion in search/filter input_field. """
|
|
1835
|
-
self.logger.info(f"function:
|
|
1836
|
+
self.logger.info(f"function: infobox()")
|
|
1836
1837
|
translator = str.maketrans('', '', string.punctuation)
|
|
1837
1838
|
|
|
1838
1839
|
words = []
|
|
@@ -1940,6 +1941,7 @@ class Picker:
|
|
|
1940
1941
|
|
|
1941
1942
|
while True:
|
|
1942
1943
|
key = self.stdscr.getch()
|
|
1944
|
+
h, w = self.stdscr.getmaxyx()
|
|
1943
1945
|
if key in self.disabled_keys: continue
|
|
1944
1946
|
clear_screen=True
|
|
1945
1947
|
|
|
@@ -1960,7 +1962,6 @@ class Picker:
|
|
|
1960
1962
|
|
|
1961
1963
|
elif self.check_key("refresh", key, self.keys_dict) or self.remapped_key(key, curses.KEY_F5, self.key_remappings) or (self.auto_refresh and (time.time() - initial_time) >= self.timer):
|
|
1962
1964
|
self.logger.debug(f"Get new data (refresh).")
|
|
1963
|
-
h, w = self.stdscr.getmaxyx()
|
|
1964
1965
|
self.stdscr.addstr(0,w-3," ", curses.color_pair(self.colours_start+21) | curses.A_BOLD)
|
|
1965
1966
|
self.stdscr.refresh()
|
|
1966
1967
|
if self.get_new_data and self.refresh_function:
|
|
@@ -1974,7 +1975,6 @@ class Picker:
|
|
|
1974
1975
|
|
|
1975
1976
|
# Refresh data synchronously
|
|
1976
1977
|
# if self.check_key("refresh", key, self.keys_dict) or self.remapped_key(key, curses.KEY_F5, self.key_remappings) or (self.auto_refresh and (time.time() - initial_time) > self.timer):
|
|
1977
|
-
# h, w = self.stdscr.getmaxyx()
|
|
1978
1978
|
# self.stdscr.addstr(0,w-3," ", curses.color_pair(self.colours_start+21) | curses.A_BOLD)
|
|
1979
1979
|
# self.stdscr.refresh()
|
|
1980
1980
|
# if self.get_new_data and self.refresh_function:
|
|
@@ -2076,7 +2076,6 @@ class Picker:
|
|
|
2076
2076
|
options += [["rh", "Toggle row header"]]
|
|
2077
2077
|
options += [["modes", "Toggle modes"]]
|
|
2078
2078
|
options += [["ft", "Cycle through footer styles (accepts ft#)"]]
|
|
2079
|
-
options += [["unicode", "Toggle b/w using len and wcwidth to calculate char width."]]
|
|
2080
2079
|
options += [[f"s{i}", f"Select col. {i}"] for i in range(len(self.items[0]))]
|
|
2081
2080
|
options += [[f"!{i}", f"Toggle col. {i}"] for i in range(len(self.items[0]))]
|
|
2082
2081
|
options += [["ara", "Add empty row after cursor."]]
|
|
@@ -2102,7 +2101,7 @@ class Picker:
|
|
|
2102
2101
|
# self.selected_column = (self.selected_column-1)%len(self.column_indices)
|
|
2103
2102
|
# # self.notification(self.stdscr, f"{str(self.column_indices)}, {tmp1}, {tmp2}")
|
|
2104
2103
|
# self.initialise_variables()
|
|
2105
|
-
# self.column_widths = get_column_widths([v[1] for v in self.indexed_items], header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns)
|
|
2104
|
+
# self.column_widths = get_column_widths([v[1] for v in self.indexed_items], header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w)
|
|
2106
2105
|
# self.draw_screen(self.indexed_items, self.highlights)
|
|
2107
2106
|
# # self.move_column(direction=-1)
|
|
2108
2107
|
#
|
|
@@ -2120,19 +2119,22 @@ class Picker:
|
|
|
2120
2119
|
page_turned = self.cursor_down()
|
|
2121
2120
|
if not page_turned: clear_screen = False
|
|
2122
2121
|
elif self.check_key("half_page_down", key, self.keys_dict):
|
|
2123
|
-
clear_screen = False
|
|
2124
2122
|
self.cursor_down(count=self.items_per_page//2)
|
|
2123
|
+
clear_screen = True
|
|
2125
2124
|
elif self.check_key("five_down", key, self.keys_dict):
|
|
2126
2125
|
clear_screen = False
|
|
2127
2126
|
self.cursor_down(count=5)
|
|
2127
|
+
clear_screen = True
|
|
2128
2128
|
elif self.check_key("cursor_up", key, self.keys_dict):
|
|
2129
2129
|
page_turned = self.cursor_up()
|
|
2130
2130
|
if not page_turned: clear_screen = False
|
|
2131
2131
|
elif self.check_key("five_up", key, self.keys_dict):
|
|
2132
2132
|
# if self.cursor_up(count=5): clear_screen = True
|
|
2133
2133
|
self.cursor_up(count=5)
|
|
2134
|
+
clear_screen = True
|
|
2134
2135
|
elif self.check_key("half_page_up", key, self.keys_dict):
|
|
2135
2136
|
self.cursor_up(count=self.items_per_page//2)
|
|
2137
|
+
clear_screen = True
|
|
2136
2138
|
|
|
2137
2139
|
elif self.check_key("toggle_select", key, self.keys_dict):
|
|
2138
2140
|
if len(self.indexed_items) > 0:
|
|
@@ -2143,25 +2145,6 @@ class Picker:
|
|
|
2143
2145
|
self.toggle_item(item_index)
|
|
2144
2146
|
|
|
2145
2147
|
self.cell_selections[cell_index] = not self.cell_selections[cell_index]
|
|
2146
|
-
## Set self.selected_cells_by_row
|
|
2147
|
-
# If any cells in the current row are selected
|
|
2148
|
-
if row in self.selected_cells_by_row:
|
|
2149
|
-
# If the current cell is selected then remove it
|
|
2150
|
-
if col in self.selected_cells_by_row[row]:
|
|
2151
|
-
# If the current cell is the only cell in the row that is selected then remove the row from the dict
|
|
2152
|
-
if len(self.selected_cells_by_row[row]) == 1:
|
|
2153
|
-
|
|
2154
|
-
del self.selected_cells_by_row[row]
|
|
2155
|
-
# else remove only the index of the current cell
|
|
2156
|
-
else:
|
|
2157
|
-
self.selected_cells_by_row[row].remove(col)
|
|
2158
|
-
# If there are cells in the row that are selected then append the current cell to the row
|
|
2159
|
-
else:
|
|
2160
|
-
self.selected_cells_by_row[row].append(col)
|
|
2161
|
-
# Add the a list containing only the current column
|
|
2162
|
-
else:
|
|
2163
|
-
self.selected_cells_by_row[row] = [col]
|
|
2164
|
-
|
|
2165
2148
|
self.cursor_down()
|
|
2166
2149
|
elif self.check_key("select_all", key, self.keys_dict): # Select all (m or ctrl-a)
|
|
2167
2150
|
self.select_all()
|
|
@@ -2186,7 +2169,12 @@ class Picker:
|
|
|
2186
2169
|
else: break
|
|
2187
2170
|
if new_pos < len(self.items) and new_pos >= 0:
|
|
2188
2171
|
self.cursor_pos = new_pos
|
|
2189
|
-
|
|
2172
|
+
self.draw_screen(self.indexed_items, self.highlights)
|
|
2173
|
+
# current_row = items_per_page - 1
|
|
2174
|
+
# if current_page + 1 == (len(self.indexed_items) + items_per_page - 1) // items_per_page:
|
|
2175
|
+
#
|
|
2176
|
+
# current_row = (len(self.indexed_items) +items_per_page - 1) % items_per_page
|
|
2177
|
+
# self.draw_screen(self.indexed_items, self.highlights)
|
|
2190
2178
|
elif self.check_key("enter", key, self.keys_dict):
|
|
2191
2179
|
self.logger.info(f"key_function enter")
|
|
2192
2180
|
# Print the selected indices if any, otherwise print the current index
|
|
@@ -2266,6 +2254,7 @@ class Picker:
|
|
|
2266
2254
|
if len(self.indexed_items) > 0:
|
|
2267
2255
|
current_index = self.indexed_items[self.cursor_pos][0]
|
|
2268
2256
|
sort_items(self.indexed_items, sort_method=self.columns_sort_method[self.sort_column], sort_column=self.sort_column, sort_reverse=self.sort_reverse[self.sort_column]) # Re-sort self.items based on new column
|
|
2257
|
+
self.draw_screen(self.indexed_items, self.highlights)
|
|
2269
2258
|
self.cursor_pos = [row[0] for row in self.indexed_items].index(current_index)
|
|
2270
2259
|
self.logger.info(f"key_function cycle_sort_order. (sort_column, sort_method, sort_reverse) = ({self.sort_column}, {self.columns_sort_method[self.sort_column]}, {self.sort_reverse[self.sort_column]})")
|
|
2271
2260
|
elif self.check_key("col_select", key, self.keys_dict):
|
|
@@ -2289,10 +2278,10 @@ class Picker:
|
|
|
2289
2278
|
|
|
2290
2279
|
## Scroll with column select
|
|
2291
2280
|
rows = self.get_visible_rows()
|
|
2292
|
-
self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns)
|
|
2281
|
+
self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w)
|
|
2293
2282
|
visible_column_widths = [c for i,c in enumerate(self.column_widths) if i not in self.hidden_columns]
|
|
2294
|
-
|
|
2295
|
-
|
|
2283
|
+
column_set_width = sum(visible_column_widths)+len(self.separator)*len(visible_column_widths)
|
|
2284
|
+
start_of_cell = sum(visible_column_widths[:self.selected_column])+len(self.separator)*self.selected_column
|
|
2296
2285
|
end_of_cell = sum(visible_column_widths[:self.selected_column+1])+len(self.separator)*(self.selected_column+1)
|
|
2297
2286
|
display_width = w-self.startx
|
|
2298
2287
|
# If the full column is within the current display then don't do anything
|
|
@@ -2316,7 +2305,8 @@ class Picker:
|
|
|
2316
2305
|
|
|
2317
2306
|
## Scroll with column select
|
|
2318
2307
|
rows = self.get_visible_rows()
|
|
2319
|
-
self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w
|
|
2308
|
+
self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w)
|
|
2309
|
+
|
|
2320
2310
|
visible_column_widths = [c for i,c in enumerate(self.column_widths) if i not in self.hidden_columns]
|
|
2321
2311
|
column_set_width = sum(visible_column_widths)+len(self.separator)*len(visible_column_widths)
|
|
2322
2312
|
start_of_cell = sum(visible_column_widths[:self.selected_column])+len(self.separator)*self.selected_column
|
|
@@ -2331,13 +2321,18 @@ class Picker:
|
|
|
2331
2321
|
self.leftmost_char = start_of_cell
|
|
2332
2322
|
|
|
2333
2323
|
self.leftmost_char = max(0, min(column_set_width - display_width + 5, self.leftmost_char))
|
|
2334
|
-
|
|
2324
|
+
#
|
|
2335
2325
|
elif self.check_key("scroll_right", key, self.keys_dict):
|
|
2336
2326
|
self.logger.info(f"key_function scroll_right")
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2327
|
+
rows = self.get_visible_rows()
|
|
2328
|
+
longest_row_str_len = 0
|
|
2329
|
+
for i in range(len(rows)):
|
|
2330
|
+
item = rows[i]
|
|
2331
|
+
row_str = format_row(item, self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols)[self.leftmost_char:]
|
|
2332
|
+
if len(row_str) > longest_row_str_len: longest_row_str_len=len(row_str)
|
|
2333
|
+
|
|
2334
|
+
if longest_row_str_len >= w-self.startx:
|
|
2335
|
+
self.leftmost_char = self.leftmost_char+5
|
|
2341
2336
|
|
|
2342
2337
|
elif self.check_key("scroll_left", key, self.keys_dict):
|
|
2343
2338
|
self.logger.info(f"key_function scroll_left")
|
|
@@ -2434,13 +2429,13 @@ class Picker:
|
|
|
2434
2429
|
self.logger.info(f"key_function decrease_column_width")
|
|
2435
2430
|
if self.max_column_width > 10:
|
|
2436
2431
|
self.max_column_width -= 10
|
|
2437
|
-
self.column_widths
|
|
2432
|
+
# self.column_widths = get_column_widths(self.items, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=2)
|
|
2438
2433
|
self.draw_screen(self.indexed_items, self.highlights)
|
|
2439
2434
|
elif self.check_key("increase_column_width", key, self.keys_dict):
|
|
2440
2435
|
self.logger.info(f"key_function increase_column_width")
|
|
2441
2436
|
if self.max_column_width < 1000:
|
|
2442
2437
|
self.max_column_width += 10
|
|
2443
|
-
self.column_widths = get_column_widths(self.items, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns)
|
|
2438
|
+
# self.column_widths = get_column_widths(self.items, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w)
|
|
2444
2439
|
self.draw_screen(self.indexed_items, self.highlights)
|
|
2445
2440
|
elif self.check_key("visual_selection_toggle", key, self.keys_dict):
|
|
2446
2441
|
self.logger.info(f"key_function visual_selection_toggle")
|
|
@@ -2455,7 +2450,7 @@ class Picker:
|
|
|
2455
2450
|
elif key == curses.KEY_RESIZE: # Terminal resize signal
|
|
2456
2451
|
|
|
2457
2452
|
self.calculate_section_sizes()
|
|
2458
|
-
self.column_widths = get_column_widths(self.items, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns)
|
|
2453
|
+
self.column_widths = get_column_widths(self.items, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w)
|
|
2459
2454
|
|
|
2460
2455
|
self.draw_screen(self.indexed_items, self.highlights)
|
|
2461
2456
|
|
|
@@ -2982,7 +2977,7 @@ def set_colours(pick: int = 0, start: int = 0) -> Optional[int]:
|
|
|
2982
2977
|
def parse_arguments() -> Tuple[argparse.Namespace, dict]:
|
|
2983
2978
|
""" Parse command line arguments. """
|
|
2984
2979
|
parser = argparse.ArgumentParser(description='Convert table to list of lists.')
|
|
2985
|
-
parser.add_argument('filename', type=str, help='The file to process')
|
|
2980
|
+
# parser.add_argument('filename', type=str, help='The file to process')
|
|
2986
2981
|
parser.add_argument('-i', dest='file', help='File containing the table to be converted.')
|
|
2987
2982
|
parser.add_argument('--load', '-l', dest='load', type=str, help='Load file from Picker dump.')
|
|
2988
2983
|
parser.add_argument('--stdin', dest='stdin', action='store_true', help='Table passed on stdin')
|
|
@@ -3010,8 +3005,8 @@ def parse_arguments() -> Tuple[argparse.Namespace, dict]:
|
|
|
3010
3005
|
input_arg = '--stdin'
|
|
3011
3006
|
elif args.stdin2:
|
|
3012
3007
|
input_arg = '--stdin2'
|
|
3013
|
-
elif args.filename:
|
|
3014
|
-
|
|
3008
|
+
# elif args.filename:
|
|
3009
|
+
# input_arg = args.filename
|
|
3015
3010
|
|
|
3016
3011
|
elif args.generate:
|
|
3017
3012
|
function_data["refresh_function"] = lambda : generate_picker_data(args.generate)
|
|
@@ -3122,6 +3117,7 @@ def main() -> None:
|
|
|
3122
3117
|
function_data["track_entries_upon_refresh"] = True
|
|
3123
3118
|
function_data["centre_in_terminal_vertical"] = True
|
|
3124
3119
|
function_data["highlight_full_row"] = True
|
|
3120
|
+
function_data["pin_cursor"] = True
|
|
3125
3121
|
# function_data["debug"] = True
|
|
3126
3122
|
# function_data["debug_level"] = 1
|
|
3127
3123
|
stdscr = start_curses()
|
listpick-0.1.13.55/src/listpick/ui/footer_1.py → listpick-0.1.13.57/src/listpick/ui/footer.py
RENAMED
|
@@ -50,9 +50,6 @@ class StandardFooter(Footer):
|
|
|
50
50
|
def draw(self, h, w):
|
|
51
51
|
state = self.get_state()
|
|
52
52
|
# Fill background
|
|
53
|
-
if "footer_string" in state and state["footer_string"]: self.height = 3
|
|
54
|
-
else: self.height = 2
|
|
55
|
-
|
|
56
53
|
for i in range(self.height):
|
|
57
54
|
self.stdscr.addstr(h-self.height+i, 0, ' '*(w-1), curses.color_pair(self.colours_start+20))
|
|
58
55
|
|
|
@@ -66,14 +63,19 @@ class StandardFooter(Footer):
|
|
|
66
63
|
|
|
67
64
|
picker_info_y = h-3
|
|
68
65
|
sort_info_y = h-2
|
|
66
|
+
self.height = 3
|
|
67
|
+
|
|
69
68
|
else:
|
|
70
69
|
picker_info_y = h-2
|
|
71
70
|
sort_info_y = h-1
|
|
71
|
+
""
|
|
72
72
|
select_mode = "C"
|
|
73
73
|
if state["is_selecting"]: select_mode = "VS"
|
|
74
74
|
elif state["is_deselecting"]: select_mode = "VDS"
|
|
75
75
|
if state["pin_cursor"]: select_mode = f"{select_mode} "
|
|
76
76
|
self.stdscr.addstr(h - 1, w-35, f"{select_mode:>33} ", curses.color_pair(self.colours_start+20))
|
|
77
|
+
self.height = 2
|
|
78
|
+
|
|
77
79
|
|
|
78
80
|
if state["filter_query"]:
|
|
79
81
|
self.stdscr.addstr(h - 2, 2, f" Filter: {state['filter_query']} "[:w-40], curses.color_pair(self.colours_start+20) | curses.A_BOLD)
|
|
@@ -105,7 +107,7 @@ class StandardFooter(Footer):
|
|
|
105
107
|
sort_disp_str = f" Sort: ({sort_column_info}, {sort_method_info}, {sort_order_info}) "
|
|
106
108
|
self.stdscr.addstr(sort_info_y, w-35, f"{sort_disp_str:>34}", curses.color_pair(self.colours_start+20))
|
|
107
109
|
|
|
108
|
-
|
|
110
|
+
self.stdscr.refresh()
|
|
109
111
|
|
|
110
112
|
|
|
111
113
|
|
|
@@ -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]:
|
|
@@ -21,8 +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_1.py
|
|
25
|
-
src/listpick/lpapp2.py
|
|
26
24
|
src/listpick.egg-info/PKG-INFO
|
|
27
25
|
src/listpick.egg-info/SOURCES.txt
|
|
28
26
|
src/listpick.egg-info/dependency_links.txt
|
|
@@ -32,7 +30,6 @@ src/listpick.egg-info/top_level.txt
|
|
|
32
30
|
src/listpick/ui/__init__.py
|
|
33
31
|
src/listpick/ui/build_help.py
|
|
34
32
|
src/listpick/ui/footer.py
|
|
35
|
-
src/listpick/ui/footer_1.py
|
|
36
33
|
src/listpick/ui/help_screen.py
|
|
37
34
|
src/listpick/ui/input_field.py
|
|
38
35
|
src/listpick/ui/keys.py
|