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.
Files changed (58) hide show
  1. {listpick-0.1.13.55 → listpick-0.1.13.57}/CHANGELOG.md +0 -11
  2. {listpick-0.1.13.55/src/listpick.egg-info → listpick-0.1.13.57}/PKG-INFO +1 -1
  3. {listpick-0.1.13.55 → listpick-0.1.13.57}/TODO.md +0 -4
  4. {listpick-0.1.13.55 → listpick-0.1.13.57}/setup.py +1 -1
  5. listpick-0.1.13.55/src/listpick/lpapp2.py → listpick-0.1.13.57/src/listpick/listpick_app.py +57 -61
  6. listpick-0.1.13.55/src/listpick/ui/footer_1.py → listpick-0.1.13.57/src/listpick/ui/footer.py +6 -4
  7. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/utils.py +24 -50
  8. {listpick-0.1.13.55 → listpick-0.1.13.57/src/listpick.egg-info}/PKG-INFO +1 -1
  9. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick.egg-info/SOURCES.txt +0 -3
  10. listpick-0.1.13.55/src/listpick/listpick_app.py +0 -3250
  11. listpick-0.1.13.55/src/listpick/listpick_app_1.py +0 -3250
  12. listpick-0.1.13.55/src/listpick/ui/footer.py +0 -202
  13. {listpick-0.1.13.55 → listpick-0.1.13.57}/.gitignore +0 -0
  14. {listpick-0.1.13.55 → listpick-0.1.13.57}/LICENSE.txt +0 -0
  15. {listpick-0.1.13.55 → listpick-0.1.13.57}/README.md +0 -0
  16. {listpick-0.1.13.55 → listpick-0.1.13.57}/assets/aria2tui_screenshot.png +0 -0
  17. {listpick-0.1.13.55 → listpick-0.1.13.57}/assets/file_compare.png +0 -0
  18. {listpick-0.1.13.55 → listpick-0.1.13.57}/assets/lpfman.png +0 -0
  19. {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/footer_string_example.py +0 -0
  20. {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/input.toml +0 -0
  21. {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/input.txt +0 -0
  22. {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/list_files.toml +0 -0
  23. {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/list_files_empty.toml +0 -0
  24. {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/picker_example.py +0 -0
  25. {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/setup.cfg +0 -0
  26. {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/template.py +0 -0
  27. {listpick-0.1.13.55 → listpick-0.1.13.57}/examples/video_duplicates.toml +0 -0
  28. {listpick-0.1.13.55 → listpick-0.1.13.57}/listpick.py +0 -0
  29. {listpick-0.1.13.55 → listpick-0.1.13.57}/requirements.txt +0 -0
  30. {listpick-0.1.13.55 → listpick-0.1.13.57}/setup.cfg +0 -0
  31. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/__init__.py +0 -0
  32. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/__main__.py +0 -0
  33. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/__init__.py +0 -0
  34. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/build_help.py +0 -0
  35. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/help_screen.py +0 -0
  36. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/input_field.py +0 -0
  37. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/keys.py +0 -0
  38. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/pane_stuff.py +0 -0
  39. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/ui/picker_colours.py +0 -0
  40. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/__init__.py +0 -0
  41. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/clipboard_operations.py +0 -0
  42. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/config.py +0 -0
  43. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/dump.py +0 -0
  44. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/filtering.py +0 -0
  45. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/generate_data.py +0 -0
  46. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/options_selectors.py +0 -0
  47. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/paste_operations.py +0 -0
  48. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/picker_log.py +0 -0
  49. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/search_and_filter_utils.py +0 -0
  50. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/searching.py +0 -0
  51. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/sorting.py +0 -0
  52. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick/utils/table_to_list_of_lists.py +0 -0
  53. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick.egg-info/dependency_links.txt +0 -0
  54. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick.egg-info/entry_points.txt +0 -0
  55. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick.egg-info/requires.txt +0 -0
  56. {listpick-0.1.13.55 → listpick-0.1.13.57}/src/listpick.egg-info/top_level.txt +0 -0
  57. {listpick-0.1.13.55 → listpick-0.1.13.57}/tests/kitty_control.sh +0 -0
  58. {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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: listpick
3
- Version: 0.1.13.55
3
+ Version: 0.1.13.57
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
@@ -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.55",
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
- self.unicode_char_width = unicode_char_width
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
- row = self.indexed_items[i][0]
1524
- if row not in self.selected_cells_by_row:
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: get_word_list()")
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
- visible_columns_total_width = sum(visible_column_widths) + len(self.separator)*(len(visible_column_widths)-1)
2295
- h, w = self.stdscr.getmaxyx()
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, unicode_char_width=self.unicode_char_width)
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
- if len(self.indexed_items):
2338
- row_width = sum(self.column_widths) + len(self.separator)*(len(self.column_widths)-1)
2339
- if row_width-self.leftmost_char >= w-self.startx:
2340
- self.leftmost_char = self.leftmost_char+5
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[:] = get_column_widths(self.items, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns)
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
- input_arg = args.filename
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()
@@ -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
- # self.stdscr.refresh()
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, unicode_char_width:bool = True) -> str:
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
- if unicode_char_width:
50
- result = ''
51
- width = 0
52
-
53
-
54
- for char in text:
55
- w = wcwidth(char)
56
- if w < 0:
57
- continue
58
- if width + w > max_column_width:
59
- break
60
- result += char
61
- width += w
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, unicode_char_width:bool = True) -> str:
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, unicode_char_width)
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 = " ", unicode_char_width:bool=True) -> list[int]:
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
- if unicode_char_width:
121
- widths = [max(wcswidth(str(row[i])) for row in items) for i in range(len(items[0]))]
122
- # widths = [max(len(str(row[i])) for row in items) for i in range(len(items[0]))]
123
- if header:
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
- widths = [max(len(str(row[i])) for row in items) for i in range(len(items[0]))]
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: listpick
3
- Version: 0.1.13.55
3
+ Version: 0.1.13.57
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,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