listpick 0.1.14.13__tar.gz → 0.1.15.0__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.

Potentially problematic release.


This version of listpick might be problematic. Click here for more details.

Files changed (64) hide show
  1. {listpick-0.1.14.13 → listpick-0.1.15.0}/CHANGELOG.md +6 -1
  2. {listpick-0.1.14.13/src/listpick.egg-info → listpick-0.1.15.0}/PKG-INFO +1 -1
  3. {listpick-0.1.14.13 → listpick-0.1.15.0}/TODO.md +1 -0
  4. {listpick-0.1.14.13 → listpick-0.1.15.0}/setup.py +1 -1
  5. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/listpick_app.py +156 -63
  6. listpick-0.1.15.0/src/listpick/pane/get_data.py +95 -0
  7. listpick-0.1.15.0/src/listpick/pane/pane_functions.py +112 -0
  8. listpick-0.1.15.0/src/listpick/pane/pane_utils.py +89 -0
  9. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/ui/footer.py +1 -1
  10. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/ui/picker_colours.py +23 -0
  11. listpick-0.1.15.0/src/listpick/utils/__init__.py +0 -0
  12. listpick-0.1.15.0/src/listpick/utils/graphing.py +224 -0
  13. {listpick-0.1.14.13 → listpick-0.1.15.0/src/listpick.egg-info}/PKG-INFO +1 -1
  14. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick.egg-info/SOURCES.txt +5 -1
  15. listpick-0.1.14.13/src/listpick/ui/pane_stuff.py +0 -8
  16. {listpick-0.1.14.13 → listpick-0.1.15.0}/.gitignore +0 -0
  17. {listpick-0.1.14.13 → listpick-0.1.15.0}/LICENSE.txt +0 -0
  18. {listpick-0.1.14.13 → listpick-0.1.15.0}/README.md +0 -0
  19. {listpick-0.1.14.13 → listpick-0.1.15.0}/assets/aria2tui_screenshot.png +0 -0
  20. {listpick-0.1.14.13 → listpick-0.1.15.0}/assets/file_compare.png +0 -0
  21. {listpick-0.1.14.13 → listpick-0.1.15.0}/assets/lpfman.png +0 -0
  22. {listpick-0.1.14.13 → listpick-0.1.15.0}/examples/data_generation/list_files.toml +0 -0
  23. {listpick-0.1.14.13 → listpick-0.1.15.0}/examples/data_generation/list_files_empty.toml +0 -0
  24. {listpick-0.1.14.13 → listpick-0.1.15.0}/examples/data_generation/video_duplicates.toml +0 -0
  25. {listpick-0.1.14.13 → listpick-0.1.15.0}/examples/data_generation/video_mediainfo.toml +0 -0
  26. {listpick-0.1.14.13 → listpick-0.1.15.0}/examples/input_files/polynomials.tsv +0 -0
  27. {listpick-0.1.14.13 → listpick-0.1.15.0}/examples/input_guides/gnuplot_graph.md +0 -0
  28. {listpick-0.1.14.13 → listpick-0.1.15.0}/examples/picker/auxiallary_files/2024-25_Premier_League.pkl +0 -0
  29. {listpick-0.1.14.13 → listpick-0.1.15.0}/examples/picker/footer_string_example.py +0 -0
  30. {listpick-0.1.14.13 → listpick-0.1.15.0}/examples/picker/picker_example.py +0 -0
  31. {listpick-0.1.14.13 → listpick-0.1.15.0}/examples/picker/template.py +0 -0
  32. {listpick-0.1.14.13 → listpick-0.1.15.0}/examples/picker/wikipedia_table.py +0 -0
  33. {listpick-0.1.14.13 → listpick-0.1.15.0}/listpick.py +0 -0
  34. {listpick-0.1.14.13 → listpick-0.1.15.0}/requirements.txt +0 -0
  35. {listpick-0.1.14.13 → listpick-0.1.15.0}/setup.cfg +0 -0
  36. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/__init__.py +0 -0
  37. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/__main__.py +0 -0
  38. {listpick-0.1.14.13/src/listpick/ui → listpick-0.1.15.0/src/listpick/pane}/__init__.py +0 -0
  39. {listpick-0.1.14.13/src/listpick/utils → listpick-0.1.15.0/src/listpick/ui}/__init__.py +0 -0
  40. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/ui/build_help.py +0 -0
  41. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/ui/help_screen.py +0 -0
  42. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/ui/input_field.py +0 -0
  43. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/ui/keys.py +0 -0
  44. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/clipboard_operations.py +0 -0
  45. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/config.py +0 -0
  46. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/dump.py +0 -0
  47. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/filtering.py +0 -0
  48. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/generate_data.py +0 -0
  49. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/keycodes.py +0 -0
  50. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/options_selectors.py +0 -0
  51. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/paste_operations.py +0 -0
  52. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/picker_log.py +0 -0
  53. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/search_and_filter_utils.py +0 -0
  54. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/searching.py +0 -0
  55. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/sorting.py +0 -0
  56. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/table_to_list_of_lists.py +0 -0
  57. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/user_input.py +0 -0
  58. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick/utils/utils.py +0 -0
  59. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick.egg-info/dependency_links.txt +0 -0
  60. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick.egg-info/entry_points.txt +0 -0
  61. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick.egg-info/requires.txt +0 -0
  62. {listpick-0.1.14.13 → listpick-0.1.15.0}/src/listpick.egg-info/top_level.txt +0 -0
  63. {listpick-0.1.14.13 → listpick-0.1.15.0}/tests/kitty_control.sh +0 -0
  64. {listpick-0.1.14.13 → listpick-0.1.15.0}/tests/sorting_dates.csv +0 -0
@@ -1,7 +1,12 @@
1
1
  # CHANGELOG.md
2
2
  Note that the changes between 0.1.11.0 and 1.1.12.0 are listed under 0.1.11
3
3
 
4
- ## [0.1.15] 2025-??-??
4
+ ## [0.1.16] 2025-??-??
5
+ - Feature added: support for dynamic data display in a right pane.
6
+ - Bugs fixed:
7
+ - Fixed ipython not working when data is piped into the picker.
8
+
9
+ ## [0.1.15] 2025-08-27
5
10
  - Added info screen to display all information on the running Picker.
6
11
  - Added keys for file_next and file_prev
7
12
  - Added __sizeof__() function for the Picker class.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: listpick
3
- Version: 0.1.14.13
3
+ Version: 0.1.15.0
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
@@ -22,6 +22,7 @@ ASAP
22
22
  > - [x] Alt+KEY
23
23
  > - [x] Arrow keys
24
24
  > - [x] Add new keycodes to build_help().
25
+ > - [ ] Search count is off
25
26
 
26
27
 
27
28
 
@@ -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.14.13",
19
+ version = "0.1.15.0",
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.",
@@ -41,6 +41,8 @@ from listpick.ui.build_help import build_help_rows
41
41
  from listpick.ui.footer import StandardFooter, CompactFooter, NoFooter
42
42
  from listpick.utils.picker_log import setup_logger
43
43
  from listpick.utils.user_input import get_char, open_tty
44
+ from listpick.pane.pane_functions import right_split_file_attributes, right_split_graph, right_split_display_list
45
+ from listpick.pane.get_data import *
44
46
 
45
47
 
46
48
  try:
@@ -62,7 +64,7 @@ class Picker:
62
64
  items: list[list[str]] = [],
63
65
  cursor_pos: int = 0,
64
66
  colours: dict = get_colours(0),
65
- colour_theme_number: int = 0,
67
+ colour_theme_number: int = 3,
66
68
  max_selected: int = -1,
67
69
  top_gap: int =0,
68
70
  title: str ="Picker",
@@ -186,7 +188,17 @@ class Picker:
186
188
  sheets = ["Untitled"],
187
189
  sheet_name = "Untitled",
188
190
  sheet_index = 0,
189
- sheet_states = [{}],
191
+ sheet_states: list = [{}],
192
+
193
+ split_right: bool = False,
194
+ split_right_proportion: float = 1/2,
195
+ split_right_function: Callable = lambda stdscr, x, y, w, h, state, row, cell, data, test: False,
196
+ split_right_auto_refresh: bool = False,
197
+ split_right_refresh_data: Callable = lambda old_data, arg_dict: [],
198
+ split_right_refresh_data_timer: float = 1.0,
199
+ split_right_data: list = [],
200
+
201
+
190
202
 
191
203
 
192
204
  ):
@@ -337,6 +349,14 @@ class Picker:
337
349
  self.sheet_states = sheet_states
338
350
  self.sheets = sheets
339
351
 
352
+ self.split_right = split_right
353
+ self.split_right_proportion = split_right_proportion
354
+ self.split_right_function = split_right_function
355
+ self.split_right_auto_refresh = split_right_auto_refresh
356
+ self.split_right_refresh_data = split_right_refresh_data
357
+ self.split_right_refresh_data_timer = split_right_refresh_data_timer
358
+ self.split_right_data = split_right_data
359
+
340
360
  self.initialise_picker_state(reset_colours=self.reset_colours)
341
361
 
342
362
  # Note: We have to set the footer after initialising the picker state so that the footer can use the get_function_data method
@@ -405,20 +425,26 @@ class Picker:
405
425
 
406
426
  ## self.top_space
407
427
  h, w = self.stdscr.getmaxyx()
428
+ self.term_h, self.term_w = self.stdscr.getmaxyx()
429
+ if self.split_right and self.split_right_function(self.stdscr, 0,0,0,0,{},[],[],"",test=True):
430
+ self.rows_w, self.rows_h = int(self.term_w*self.split_right_proportion), self.term_h
431
+ else:
432
+ self.rows_w, self.rows_h = self.term_w, self.term_h
433
+
408
434
  self.top_space = self.top_gap
409
435
  if self.title: self.top_space+=1
410
436
  if self.modes and self.display_modes: self.top_space+=1
411
437
  if self.header and self.show_header: self.top_space += 1
412
438
 
413
439
  # self.items_per_page
414
- self.items_per_page = h - self.top_space - self.bottom_space
440
+ self.items_per_page = self.term_h - self.top_space - self.bottom_space
415
441
  if not self.show_footer and self.footer_string: self.items_per_page-=1
416
- self.items_per_page = min(h-self.top_space-1, self.items_per_page)
442
+ self.items_per_page = min(self.term_h-self.top_space-1, self.items_per_page)
417
443
 
418
444
 
419
445
  # Adjust top space if centring vertically and we have fewer rows than terminal lines
420
446
  if self.centre_in_terminal_vertical and len(self.indexed_items) < self.items_per_page:
421
- self.top_space += ((h-(self.top_space+self.bottom_space))-len(self.indexed_items))//2
447
+ self.top_space += ((self.term_h-(self.top_space+self.bottom_space))-len(self.indexed_items))//2
422
448
 
423
449
  # self.column_widths
424
450
  visible_column_widths = [c for i,c in enumerate(self.column_widths) if i not in self.hidden_columns]
@@ -427,8 +453,8 @@ class Picker:
427
453
  # self.startx
428
454
  self.startx = 1 if self.highlight_full_row else 2
429
455
  if self.show_row_header: self.startx += len(str(len(self.items))) + 2
430
- if visible_columns_total_width < w and self.centre_in_terminal:
431
- self.startx += (w - visible_columns_total_width) // 2
456
+ if visible_columns_total_width < self.rows_w and self.centre_in_terminal:
457
+ self.startx += (self.rows_w - visible_columns_total_width) // 2
432
458
 
433
459
  def get_visible_rows(self) -> list[list[str]]:
434
460
 
@@ -614,7 +640,6 @@ class Picker:
614
640
  if len(self.indexed_items) > 0:
615
641
  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
616
642
 
617
- h, w = self.stdscr.getmaxyx()
618
643
 
619
644
  # Adjust variables to ensure correctness if errors
620
645
  ## Move to a selectable row (if applicable)
@@ -761,8 +786,14 @@ class Picker:
761
786
  self.stdscr.erase()
762
787
 
763
788
  h, w = self.stdscr.getmaxyx()
789
+ self.term_h, self.term_w = self.stdscr.getmaxyx()
790
+ if self.split_right and self.split_right_function(self.stdscr, 0,0,0,0,{},[],[],"",test=True):
791
+ self.rows_w, self.rows_h = int(self.term_w*self.split_right_proportion), self.term_h
792
+ else:
793
+ self.rows_w, self.rows_h = self.term_w, self.term_h
794
+
764
795
  # The height of the footer may need to be adjusted if the file changes.
765
- self.footer.adjust_sizes(h,w)
796
+ self.footer.adjust_sizes(self.term_h,self.term_w)
766
797
  self.calculate_section_sizes()
767
798
 
768
799
  # Test if the terminal is of a sufficient size to display the picker
@@ -785,7 +816,7 @@ class Picker:
785
816
  # rows = [v[1] for v in self.indexed_items] if len(self.indexed_items) else self.items
786
817
  # Determine widths based only on the currently displayed indexed rows
787
818
  rows = [v[1] for v in self.indexed_items[start_index:end_index]] if len(self.indexed_items) else self.items
788
- 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)
819
+ 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=self.rows_w, unicode_char_width=self.unicode_char_width)
789
820
  visible_column_widths = [c for i,c in enumerate(self.column_widths) if i not in self.hidden_columns]
790
821
  visible_columns_total_width = sum(visible_column_widths) + len(self.separator)*(len(visible_column_widths)-1)
791
822
 
@@ -797,23 +828,22 @@ class Picker:
797
828
  ## Display title (if applicable)
798
829
  if self.title:
799
830
  padded_title = f" {self.title.strip()} "
800
- self.stdscr.addstr(self.top_gap, 0, f"{' ':^{w}}", curses.color_pair(self.colours_start+16))
801
- title_x = (w-wcswidth(padded_title))//2
802
- # title = f"{title:^{w}}"
831
+ self.stdscr.addstr(self.top_gap, 0, f"{' ':^{self.term_w}}", curses.color_pair(self.colours_start+16))
832
+ title_x = (self.term_w-wcswidth(padded_title))//2
803
833
  self.stdscr.addstr(self.top_gap, title_x, padded_title, curses.color_pair(self.colours_start+16) | curses.A_BOLD)
804
834
  # top_space += 1
805
835
 
806
836
  ## Display modes
807
837
  if self.display_modes and self.modes not in [[{}], []]:
808
- self.stdscr.addstr(self.top_gap+1, 0, ' '*w, curses.A_REVERSE)
838
+ self.stdscr.addstr(self.top_gap+1, 0, ' '*self.term_w, curses.A_REVERSE)
809
839
  modes_list = [f"{mode['name']}" if 'name' in mode else f"{i}. " for i, mode in enumerate(self.modes)]
810
840
  # mode_colours = [mode["colour"] for mode ]
811
841
  mode_widths = get_mode_widths(modes_list)
812
- split_space = (w-sum(mode_widths))//len(self.modes)
842
+ split_space = (self.term_w-sum(mode_widths))//len(self.modes)
813
843
  xmode = 0
814
844
  for i, mode in enumerate(modes_list):
815
845
  if i == len(modes_list)-1:
816
- mode_str = f"{mode:^{mode_widths[i]+split_space+(w-sum(mode_widths))%len(self.modes)}}"
846
+ mode_str = f"{mode:^{mode_widths[i]+split_space+(self.term_w-sum(mode_widths))%len(self.modes)}}"
817
847
  else:
818
848
  mode_str = f"{mode:^{mode_widths[i]+split_space}}"
819
849
  # current mode
@@ -841,21 +871,19 @@ class Picker:
841
871
 
842
872
  header_str = header_str[self.leftmost_char:]
843
873
  header_ypos = self.top_gap + bool(self.title) + bool(self.display_modes and self.modes)
844
- self.stdscr.addstr(header_ypos, 0, ' '*w, curses.color_pair(self.colours_start+4) | curses.A_BOLD)
845
- self.stdscr.addstr(header_ypos, self.startx, header_str[:min(w-self.startx, visible_columns_total_width+1)], curses.color_pair(self.colours_start+4) | curses.A_BOLD)
874
+ self.stdscr.addstr(header_ypos, 0, ' '*self.rows_w, curses.color_pair(self.colours_start+4) | curses.A_BOLD)
875
+ self.stdscr.addstr(header_ypos, self.startx, header_str[:min(self.rows_w-self.startx, visible_columns_total_width+1)], curses.color_pair(self.colours_start+4) | curses.A_BOLD)
846
876
 
847
877
  # Highlight sort column
848
878
  try:
849
879
  if self.selected_column != None and self.selected_column not in self.hidden_columns:
850
- if len(self.header) > 1 and (len(up_to_selected_col)-self.leftmost_char) < w:
851
- # if len(up_to_selected_col) + 1 < w or True:
852
- # if self.startx + len(up_to_selected_col) - self.leftmost_char > 0 or True:
880
+ if len(self.header) > 1 and (len(up_to_selected_col)-self.leftmost_char) < self.rows_w:
853
881
  number = f"{self.selected_column}. " if self.number_columns else ""
854
882
  # number = f"{intStringToExponentString(self.selected_column)}. " if self.number_columns else ""
855
883
  # self.startx + len(up_to_selected_col) - self.leftmost_char
856
884
  highlighed_col_startx = max(self.startx, self.startx + len(up_to_selected_col) - self.leftmost_char)
857
885
  highlighted_col_str = (number+f"{self.header[self.selected_column]:^{self.column_widths[self.selected_column]-len(number)}}") + self.separator
858
- end_of_highlighted_col_str = w-(highlighed_col_startx+len(highlighted_col_str)) if (highlighed_col_startx+len(highlighted_col_str)) > w else len(highlighted_col_str)
886
+ end_of_highlighted_col_str = self.rows_w-(highlighed_col_startx+len(highlighted_col_str)) if (highlighed_col_startx+len(highlighted_col_str)) > self.rows_w else len(highlighted_col_str)
859
887
  start_of_highlighted_col_str = max(self.leftmost_char - len(up_to_selected_col), 0)
860
888
  self.stdscr.addstr(header_ypos, highlighed_col_startx , highlighted_col_str[start_of_highlighted_col_str:end_of_highlighted_col_str], curses.color_pair(self.colours_start+19) | curses.A_BOLD)
861
889
  except:
@@ -874,10 +902,10 @@ class Picker:
874
902
  cell_pos = sum(visible_column_widths[:col])+col*len(self.separator)-self.leftmost_char + self.startx
875
903
  # cell_width = self.column_widths[self.selected_column]
876
904
  cell_width = visible_column_widths[col] + len(self.separator)
877
- cell_max_width = w-cell_pos
905
+ cell_max_width = self.rows_w-cell_pos
878
906
  try:
879
907
  # Start of cell is on screen
880
- if self.startx <= cell_pos <= w:
908
+ if self.startx <= cell_pos <= self.rows_w:
881
909
  self.stdscr.addstr(y, cell_pos, (' '*cell_width)[:cell_max_width], curses.color_pair(self.colours_start+colour_pair_number))
882
910
  if self.centre_in_cols:
883
911
  cell_value = f"{self.indexed_items[row][1][col]:^{cell_width-len(self.separator)}}" + self.separator
@@ -888,10 +916,9 @@ class Picker:
888
916
  cell_value = cell_value + self.separator
889
917
  # cell_value = cell_value
890
918
  cell_value = truncate_to_display_width(cell_value, min(cell_width, cell_max_width), self.centre_in_cols, self.unicode_char_width)
891
- # row_str = truncate_to_display_width(row_str_left_adj, min(w-self.startx, visible_columns_total_width))
892
919
  self.stdscr.addstr(y, cell_pos, cell_value, curses.color_pair(self.colours_start+colour_pair_number) | curses.A_BOLD)
893
920
  # Part of the cell is on screen
894
- elif self.startx <= cell_pos+cell_width <= w:
921
+ elif self.startx <= cell_pos+cell_width <= self.rows_w:
895
922
  cell_start = self.startx - cell_pos
896
923
  self.stdscr.addstr(y, self.startx, ' '*(cell_width-cell_start), curses.color_pair(self.colours_start+colour_pair_number))
897
924
  cell_value = self.indexed_items[row][1][col][cell_start:visible_column_widths[col]]
@@ -954,7 +981,7 @@ class Picker:
954
981
  continue
955
982
  highlight_start -= self.leftmost_char
956
983
  highlight_end -= self.leftmost_char
957
- self.stdscr.addstr(y, max(self.startx, self.startx+highlight_start), row_str[max(highlight_start,0):min(w-self.startx, highlight_end)], curses.color_pair(self.colours_start+highlight["color"]) | curses.A_BOLD)
984
+ self.stdscr.addstr(y, max(self.startx, self.startx+highlight_start), row_str[max(highlight_start,0):min(self.rows_w-self.startx, highlight_end)], curses.color_pair(self.colours_start+highlight["color"]) | curses.A_BOLD)
958
985
  except:
959
986
  pass
960
987
 
@@ -978,11 +1005,11 @@ class Picker:
978
1005
  # row_str = truncate_to_display_width(row_str, min(w-self.startx, visible_columns_total_width))
979
1006
  row_str_orig = format_row(item[1], self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols, self.unicode_char_width)
980
1007
  row_str_left_adj = clip_left(row_str_orig, self.leftmost_char)
981
- row_str = truncate_to_display_width(row_str_left_adj, min(w-self.startx, visible_columns_total_width), self.unicode_char_width)
1008
+ row_str = truncate_to_display_width(row_str_left_adj, min(self.rows_w-self.startx, visible_columns_total_width), self.unicode_char_width)
982
1009
  # row_str = truncate_to_display_width(row_str, min(w-self.startx, visible_columns_total_width))[self.leftmost_char:]
983
1010
 
984
1011
  ## Display the standard row
985
- self.stdscr.addstr(y, self.startx, row_str[:min(w-self.startx, visible_columns_total_width)], curses.color_pair(self.colours_start+2))
1012
+ self.stdscr.addstr(y, self.startx, row_str[:min(self.rows_w-self.startx, visible_columns_total_width)], curses.color_pair(self.colours_start+2))
986
1013
 
987
1014
 
988
1015
  # Draw the level 0 highlights
@@ -1012,15 +1039,15 @@ class Picker:
1012
1039
  # Higlight cursor row and selected rows
1013
1040
  elif self.highlight_full_row:
1014
1041
  if self.selections[item[0]]:
1015
- self.stdscr.addstr(y, self.startx, row_str[:min(w-self.startx, visible_columns_total_width)], curses.color_pair(self.colours_start+25) | curses.A_BOLD)
1042
+ self.stdscr.addstr(y, self.startx, row_str[:min(self.rows_w-self.startx, visible_columns_total_width)], curses.color_pair(self.colours_start+25) | curses.A_BOLD)
1016
1043
  # Visually selected
1017
1044
  if self.is_selecting:
1018
1045
  if self.start_selection <= idx <= self.cursor_pos or self.start_selection >= idx >= self.cursor_pos:
1019
- self.stdscr.addstr(y, self.startx, row_str[:min(w-self.startx, visible_columns_total_width)], curses.color_pair(self.colours_start+25))
1046
+ self.stdscr.addstr(y, self.startx, row_str[:min(self.rows_w-self.startx, visible_columns_total_width)], curses.color_pair(self.colours_start+25))
1020
1047
  # Visually deslected
1021
1048
  elif self.is_deselecting:
1022
1049
  if self.start_selection >= idx >= self.cursor_pos or self.start_selection <= idx <= self.cursor_pos:
1023
- self.stdscr.addstr(y, self.startx, row_str[:min(w-self.startx, visible_columns_total_width)], curses.color_pair(self.colours_start+26))
1050
+ self.stdscr.addstr(y, self.startx, row_str[:min(self.rows_w-self.startx, visible_columns_total_width)], curses.color_pair(self.colours_start+26))
1024
1051
 
1025
1052
  # Highlight the cursor row and the first char of the selected rows.
1026
1053
  else:
@@ -1043,7 +1070,7 @@ class Picker:
1043
1070
  if self.cell_cursor:
1044
1071
  highlight_cell(idx, self.selected_column, visible_column_widths)
1045
1072
  else:
1046
- self.stdscr.addstr(y, self.startx, row_str[:min(w-self.startx, visible_columns_total_width)], curses.color_pair(self.colours_start+5) | curses.A_BOLD)
1073
+ self.stdscr.addstr(y, self.startx, row_str[:min(self.rows_w-self.startx, visible_columns_total_width)], curses.color_pair(self.colours_start+5) | curses.A_BOLD)
1047
1074
 
1048
1075
  if not self.highlights_hide:
1049
1076
  draw_highlights(l2_highlights, idx, y, item)
@@ -1054,36 +1081,49 @@ class Picker:
1054
1081
  if self.cursor_pos <= self.items_per_page//2:
1055
1082
  scroll_bar_start=self.top_space
1056
1083
  elif self.cursor_pos + self.items_per_page//2 >= len(self.indexed_items):
1057
- scroll_bar_start = h - int(bool(self.show_footer))*self.footer.height - scroll_bar_length
1084
+ scroll_bar_start = self.term_h - int(bool(self.show_footer))*self.footer.height - scroll_bar_length
1058
1085
  else:
1059
1086
  scroll_bar_start = int(((self.cursor_pos)/len(self.indexed_items))*self.items_per_page)+self.top_space - scroll_bar_length//2
1060
- scroll_bar_start = min(scroll_bar_start, h-self.top_space-1)
1061
- scroll_bar_length = min(scroll_bar_length, h - scroll_bar_start-1)
1087
+ scroll_bar_start = min(scroll_bar_start, self.term_h-self.top_space-1)
1088
+ scroll_bar_length = min(scroll_bar_length, self.term_h - scroll_bar_start-1)
1062
1089
  scroll_bar_length = max(1, scroll_bar_length)
1063
1090
  for i in range(scroll_bar_length):
1064
1091
  v = max(self.top_space+int(bool(self.header)), scroll_bar_start-scroll_bar_length//2)
1065
- self.stdscr.addstr(scroll_bar_start+i, w-1, ' ', curses.color_pair(self.colours_start+18))
1092
+ self.stdscr.addstr(scroll_bar_start+i, self.rows_w-1, ' ', curses.color_pair(self.colours_start+18))
1066
1093
 
1067
1094
  # Display refresh symbol
1068
1095
  if self.auto_refresh:
1069
1096
  if self.refreshing_data:
1070
- self.stdscr.addstr(0,w-3,"  ", curses.color_pair(self.colours_start+21) | curses.A_BOLD)
1097
+ self.stdscr.addstr(0,self.term_w-3,"  ", curses.color_pair(self.colours_start+21) | curses.A_BOLD)
1071
1098
  else:
1072
- self.stdscr.addstr(0,w-3,"  ", curses.color_pair(self.colours_start+23) | curses.A_BOLD)
1099
+ self.stdscr.addstr(0,self.term_w-3,"  ", curses.color_pair(self.colours_start+23) | curses.A_BOLD)
1073
1100
 
1074
1101
  ## Display footer
1075
1102
  if self.show_footer:
1076
1103
  # self.footer = NoFooter(self.stdscr, self.colours_start, self.get_function_data)
1077
1104
  h, w = self.stdscr.getmaxyx()
1078
1105
  try:
1079
- self.footer.draw(h, w)
1106
+ self.footer.draw(self.term_h, self.term_w)
1080
1107
  except:
1081
1108
  pass
1082
1109
  elif self.footer_string:
1083
- footer_string_width = min(w-1, len(self.footer_string)+2)
1110
+ footer_string_width = min(self.term_w-1, len(self.footer_string)+2)
1084
1111
  disp_string = f" {self.footer_string[:footer_string_width]:>{footer_string_width-2}} "
1085
- self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
1086
- self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
1112
+ self.stdscr.addstr(self.term_h - 1, self.term_w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
1113
+ self.stdscr.addstr(self.term_h - 1, self.term_w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
1114
+
1115
+ if self.split_right and self.split_right_function(self.stdscr, 0,0,0,0,{},[],[],"",test=True):
1116
+ self.right_pane_previous_data = self.split_right_function(
1117
+ self.stdscr,
1118
+ x = self.rows_w,
1119
+ y = self.top_space - int(bool(self.show_header and self.header)),
1120
+ w = self.term_w-self.rows_w,
1121
+ h = self.items_per_page + int(bool(self.show_header and self.header)),
1122
+ state = self.get_function_data(),
1123
+ row = self.indexed_items[self.cursor_pos] if self.indexed_items else [],
1124
+ cell = self.indexed_items[self.cursor_pos][1][self.selected_column] if self.indexed_items else "",
1125
+ data=self.split_right_data,
1126
+ )
1087
1127
 
1088
1128
  self.stdscr.refresh()
1089
1129
  ## Display infobox
@@ -1130,6 +1170,7 @@ class Picker:
1130
1170
  "title": title,
1131
1171
  "reset_colours": False,
1132
1172
  "cell_cursor": False,
1173
+ "split_right": False,
1133
1174
  }
1134
1175
 
1135
1176
  OptionPicker = Picker(submenu_win, **infobox_data)
@@ -1244,6 +1285,13 @@ class Picker:
1244
1285
  "sheets": self.sheets,
1245
1286
  "sheet_name": self.sheet_name,
1246
1287
  "sheet_states": self.sheet_states,
1288
+ "split_right": self.split_right,
1289
+ "split_right_proportion": self.split_right_proportion,
1290
+ "split_right_function": self.split_right_function,
1291
+ "split_right_auto_refresh": self.split_right_auto_refresh,
1292
+ "split_right_refresh_data_timer": self.split_right_refresh_data_timer,
1293
+ "split_right_refresh_data": self.split_right_refresh_data,
1294
+ "split_right_data": self.split_right_data,
1247
1295
  }
1248
1296
  return function_data
1249
1297
 
@@ -1278,6 +1326,9 @@ class Picker:
1278
1326
  "centre_in_terminal_vertical",
1279
1327
  "centre_in_cols",
1280
1328
  "centre_in_terminal",
1329
+ "split_right",
1330
+ "split_right_proportion",
1331
+ "split_right_function",
1281
1332
  ]
1282
1333
 
1283
1334
  for var in variables:
@@ -1370,6 +1421,7 @@ class Picker:
1370
1421
  "cancel_is_back": True,
1371
1422
  "number_columns": False,
1372
1423
  "reset_colours": False,
1424
+ "split_right": False,
1373
1425
  }
1374
1426
  while True:
1375
1427
  h, w = stdscr.getmaxyx()
@@ -1425,6 +1477,7 @@ class Picker:
1425
1477
  "top_gap": 0,
1426
1478
  "cancel_is_back": True,
1427
1479
  "reset_colours": False,
1480
+ "split_right": False,
1428
1481
 
1429
1482
  }
1430
1483
  OptionPicker = Picker(submenu_win, **notification_data)
@@ -1562,6 +1615,8 @@ class Picker:
1562
1615
  self.footer_style = (self.footer_style+1)%len(self.footer_options)
1563
1616
  self.footer = self.footer_options[self.footer_style]
1564
1617
  self.initialise_variables()
1618
+ elif setting == "pane":
1619
+ self.toggle_right_pane()
1565
1620
 
1566
1621
  elif setting.startswith("cwd="):
1567
1622
  os.chdir(os.path.expandvars(os.path.expanduser(setting[len("cwd="):])))
@@ -1951,7 +2006,6 @@ class Picker:
1951
2006
 
1952
2007
  self.stdscr = tmp
1953
2008
 
1954
- h, w = self.stdscr.getmaxyx()
1955
2009
  self.notification(self.stdscr, f"{repr(file_to_load)} has been loaded!")
1956
2010
 
1957
2011
  self.set_function_data({}, reset_absent_variables=True)
@@ -2177,6 +2231,9 @@ class Picker:
2177
2231
  self.set_function_data(function_data, reset_absent_variables=True)
2178
2232
  self.load_sheet(self.loaded_file, sheet_number=self.sheet_index)
2179
2233
 
2234
+ def toggle_right_pane(self):
2235
+ if self.split_right_function(self.stdscr, 0,0,0,0,{},[],[],"",test=True):
2236
+ self.split_right = not self.split_right
2180
2237
 
2181
2238
 
2182
2239
  def run(self) -> Tuple[list[int], str, dict]:
@@ -2192,6 +2249,7 @@ class Picker:
2192
2249
 
2193
2250
  initial_time = time.time()
2194
2251
  initial_time_footer = time.time()-self.footer_timer
2252
+ initial_split_time = time.time()-self.split_right_refresh_data_timer
2195
2253
 
2196
2254
  if self.startup_notification:
2197
2255
  self.notification(self.stdscr, message=self.startup_notification)
@@ -2226,6 +2284,11 @@ class Picker:
2226
2284
  tty_fd = open_tty()
2227
2285
 
2228
2286
  h, w = self.stdscr.getmaxyx()
2287
+ self.term_h, self.term_w = self.stdscr.getmaxyx()
2288
+ if self.split_right and self.split_right_function(self.stdscr, 0,0,0,0,{},[],[],"",test=True):
2289
+ self.rows_w, self.rows_h = int(self.term_w*self.split_right_proportion), self.term_h
2290
+ else:
2291
+ self.rows_w, self.rows_h = self.term_w, self.term_h
2229
2292
  def terminal_resized(old_w, old_h) -> bool:
2230
2293
  w, h = os.get_terminal_size()
2231
2294
  if old_h != h or old_w != w: return True
@@ -2246,6 +2309,11 @@ class Picker:
2246
2309
  key = curses.KEY_RESIZE
2247
2310
 
2248
2311
  h, w = self.stdscr.getmaxyx()
2312
+ self.term_h, self.term_w = self.stdscr.getmaxyx()
2313
+ if self.split_right and self.split_right_function(self.stdscr, 0,0,0,0,{},[],[],"",test=True):
2314
+ self.rows_w, self.rows_h = int(self.term_w*self.split_right_proportion), self.term_h
2315
+ else:
2316
+ self.rows_w, self.rows_h = self.term_w, self.term_h
2249
2317
 
2250
2318
  if key in self.disabled_keys: continue
2251
2319
  clear_screen=True
@@ -2267,7 +2335,7 @@ class Picker:
2267
2335
 
2268
2336
  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):
2269
2337
  self.logger.debug(f"Get new data (refresh).")
2270
- self.stdscr.addstr(0,w-3,"  ", curses.color_pair(self.colours_start+21) | curses.A_BOLD)
2338
+ self.stdscr.addstr(0,self.term_w-3,"  ", curses.color_pair(self.colours_start+21) | curses.A_BOLD)
2271
2339
  self.stdscr.refresh()
2272
2340
  if self.get_new_data and self.refresh_function:
2273
2341
  self.refreshing_data = True
@@ -2297,6 +2365,9 @@ class Picker:
2297
2365
  self.footer_string = self.footer_string_refresh_function()
2298
2366
  initial_time_footer = time.time()
2299
2367
  self.draw_screen(self.indexed_items, self.highlights)
2368
+ if self.split_right_auto_refresh and ((time.time() - initial_split_time) > self.split_right_refresh_data_timer):
2369
+ self.split_right_data = self.split_right_refresh_data(self.split_right_data, self.get_function_data())
2370
+ initial_split_time = time.time()
2300
2371
 
2301
2372
  if self.check_key("help", key, self.keys_dict):
2302
2373
  self.logger.info(f"key_function help")
@@ -2320,6 +2391,7 @@ class Picker:
2320
2391
  "hidden_columns": [],
2321
2392
  "reset_colours": False,
2322
2393
  "cell_cursor": False,
2394
+ "split_right": False,
2323
2395
 
2324
2396
  }
2325
2397
  OptionPicker = Picker(self.stdscr, **help_data)
@@ -2431,6 +2503,7 @@ class Picker:
2431
2503
  "hidden_columns": [],
2432
2504
  "reset_colours": False,
2433
2505
  "cell_cursor": False,
2506
+ "split_right": False,
2434
2507
 
2435
2508
  }
2436
2509
  OptionPicker = Picker(self.stdscr, **info_data)
@@ -2741,12 +2814,12 @@ class Picker:
2741
2814
 
2742
2815
  ## Scroll with column select
2743
2816
  rows = self.get_visible_rows()
2744
- 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)
2817
+ 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=self.rows_w, unicode_char_width=self.unicode_char_width)
2745
2818
  visible_column_widths = [c for i,c in enumerate(self.column_widths) if i not in self.hidden_columns]
2746
2819
  column_set_width = sum(visible_column_widths)+len(self.separator)*len(visible_column_widths)
2747
2820
  start_of_cell = sum(visible_column_widths[:self.selected_column])+len(self.separator)*self.selected_column
2748
2821
  end_of_cell = sum(visible_column_widths[:self.selected_column+1])+len(self.separator)*(self.selected_column+1)
2749
- display_width = w-self.startx
2822
+ display_width = self.rows_w-self.startx
2750
2823
  # If the full column is within the current display then don't do anything
2751
2824
  if start_of_cell >= self.leftmost_char and end_of_cell <= self.leftmost_char + display_width:
2752
2825
  pass
@@ -2768,12 +2841,12 @@ class Picker:
2768
2841
 
2769
2842
  ## Scroll with column select
2770
2843
  rows = self.get_visible_rows()
2771
- 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)
2844
+ 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=self.rows_w, unicode_char_width=self.unicode_char_width)
2772
2845
  visible_column_widths = [c for i,c in enumerate(self.column_widths) if i not in self.hidden_columns]
2773
2846
  column_set_width = sum(visible_column_widths)+len(self.separator)*len(visible_column_widths)
2774
2847
  start_of_cell = sum(visible_column_widths[:self.selected_column])+len(self.separator)*self.selected_column
2775
2848
  end_of_cell = sum(visible_column_widths[:self.selected_column+1])+len(self.separator)*(self.selected_column+1)
2776
- display_width = w-self.startx
2849
+ display_width = self.rows_w-self.startx
2777
2850
 
2778
2851
  # If the entire column is within the current display then don't do anything
2779
2852
  if start_of_cell >= self.leftmost_char and end_of_cell <= self.leftmost_char + display_width:
@@ -2788,7 +2861,7 @@ class Picker:
2788
2861
  self.logger.info(f"key_function scroll_right")
2789
2862
  if len(self.indexed_items):
2790
2863
  row_width = sum(self.column_widths) + len(self.separator)*(len(self.column_widths)-1)
2791
- if row_width-self.leftmost_char >= w-self.startx:
2864
+ if row_width-self.leftmost_char >= self.rows_w-self.startx:
2792
2865
  self.leftmost_char = self.leftmost_char+5
2793
2866
 
2794
2867
  elif self.check_key("scroll_left", key, self.keys_dict):
@@ -2813,7 +2886,7 @@ class Picker:
2813
2886
  # row_str = format_row(item[1], self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols)
2814
2887
  # if len(row_str) > longest_row_str_len: longest_row_str_len=len(row_str)
2815
2888
  # self.notification(self.stdscr, f"{longest_row_str_len}")
2816
- self.leftmost_char = max(0, longest_row_str_len-w+2+self.startx)
2889
+ self.leftmost_char = max(0, longest_row_str_len-self.rows_w+2+self.startx)
2817
2890
  if len(self.items):
2818
2891
  self.selected_column = len(self.items[0])-1
2819
2892
 
@@ -2907,7 +2980,7 @@ class Picker:
2907
2980
  elif key == curses.KEY_RESIZE: # Terminal resize signal
2908
2981
 
2909
2982
  self.calculate_section_sizes()
2910
- 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, unicode_char_width=self.unicode_char_width)
2983
+ 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=self.rows_w, unicode_char_width=self.unicode_char_width)
2911
2984
 
2912
2985
  self.draw_screen(self.indexed_items, self.highlights)
2913
2986
 
@@ -3190,10 +3263,11 @@ class Picker:
3190
3263
 
3191
3264
  if not selected_indices:
3192
3265
  if len(self.indexed_items):
3193
- if " " in self.items[self.cursor_pos][self.selected_column]:
3194
- full_values = [repr(self.items[self.cursor_pos][self.selected_column])]
3266
+ pos = self.indexed_items[self.cursor_pos][0]
3267
+ if " " in self.items[pos][self.selected_column]:
3268
+ full_values = [repr(self.items[pos][self.selected_column])]
3195
3269
  else:
3196
- full_values = [self.items[self.cursor_pos][self.selected_column]]
3270
+ full_values = [self.items[pos][self.selected_column]]
3197
3271
 
3198
3272
  else:
3199
3273
  return None
@@ -3322,7 +3396,7 @@ class Picker:
3322
3396
  self.history_edits.append(usrtxt)
3323
3397
  elif self.check_key("edit_ipython", key, self.keys_dict):
3324
3398
  self.logger.info(f"key_function edit_picker")
3325
- import IPython
3399
+ import IPython, termios
3326
3400
  self.stdscr.clear()
3327
3401
  restrict_curses(self.stdscr)
3328
3402
  self.stdscr.clear()
@@ -3337,10 +3411,24 @@ class Picker:
3337
3411
  # ]
3338
3412
  msg = "The active Picker object has variable name self.\n"
3339
3413
  msg += "\te.g., self.items will display the items in Picker"
3414
+ tty_in = open("/dev/tty", "r")
3415
+ tty_out = open("/dev/tty", "w")
3416
+
3417
+ fd = tty_in.fileno()
3418
+ old_attrs = termios.tcgetattr(fd)
3419
+ new_attrs = termios.tcgetattr(fd)
3420
+ new_attrs[3] |= termios.ECHO # lflags
3421
+ termios.tcsetattr(fd, termios.TCSADRAIN, new_attrs)
3422
+
3423
+ sys.stdin = tty_in
3424
+ sys.stdout = tty_out
3425
+ sys.stderr = tty_out
3340
3426
  IPython.embed(header=msg, config=c)
3341
3427
 
3342
3428
  unrestrict_curses(self.stdscr)
3343
3429
 
3430
+ tty_in.close()
3431
+ tty_out.close()
3344
3432
  self.stdscr.clear()
3345
3433
  self.stdscr.refresh()
3346
3434
  self.initialise_variables()
@@ -3656,16 +3744,21 @@ def main() -> None:
3656
3744
  # function_data["paginate"] = True
3657
3745
  # function_data["debug"] = True
3658
3746
  # function_data["debug_level"] = 1
3747
+ # function_data["split_right"] = True
3748
+ # function_data["split_right_proportion"] = 2/3
3749
+ # function_data["split_right_refresh_data"] = data_refresh_randint_title
3750
+ # function_data["split_right_refresh_data"] = get_dl
3751
+
3752
+
3753
+ # function_data["split_right_function"] = right_split_file_attributes
3754
+ # function_data["split_right_auto_refresh"] = True
3755
+ # function_data["split_right_function"] = right_split_graph
3756
+ # function_data["split_right_function"] = right_split_display_list
3757
+ # function_data["split_right_data"] = ["Files", [str(x) for x in range(100)]]
3758
+
3659
3759
  stdscr = start_curses()
3660
3760
  try:
3661
3761
  # Run the Picker
3662
- # h, w = stdscr.getmaxyx()
3663
- # if (h>8 and w >20):
3664
- # curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK)
3665
- # stdscr.bkgd(' ', curses.color_pair(1)) # Apply background color
3666
- # s = "Listpick is loading your data..."
3667
- # stdscr.addstr(h//2, (w-len(s))//2, s)
3668
- # stdscr.refresh()
3669
3762
 
3670
3763
  # app = Picker(stdscr, **function_data)
3671
3764
  app = Picker(stdscr)