listpick 0.1.16.10__py3-none-any.whl → 0.1.16.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of listpick might be problematic. Click here for more details.
- listpick/listpick_app.py +232 -218
- listpick/ui/keys.py +1 -1
- listpick/ui/picker_colours.py +55 -0
- listpick/utils/utils.py +6 -11
- {listpick-0.1.16.10.dist-info → listpick-0.1.16.11.dist-info}/METADATA +1 -1
- {listpick-0.1.16.10.dist-info → listpick-0.1.16.11.dist-info}/RECORD +10 -10
- {listpick-0.1.16.10.dist-info → listpick-0.1.16.11.dist-info}/WHEEL +0 -0
- {listpick-0.1.16.10.dist-info → listpick-0.1.16.11.dist-info}/entry_points.txt +0 -0
- {listpick-0.1.16.10.dist-info → listpick-0.1.16.11.dist-info}/licenses/LICENSE.txt +0 -0
- {listpick-0.1.16.10.dist-info → listpick-0.1.16.11.dist-info}/top_level.txt +0 -0
listpick/listpick_app.py
CHANGED
|
@@ -20,7 +20,7 @@ import json
|
|
|
20
20
|
import threading
|
|
21
21
|
import string
|
|
22
22
|
import logging
|
|
23
|
-
|
|
23
|
+
import copy
|
|
24
24
|
|
|
25
25
|
from listpick.pane.pane_utils import get_file_attributes
|
|
26
26
|
from listpick.pane.left_pane_functions import *
|
|
@@ -378,6 +378,11 @@ class Picker:
|
|
|
378
378
|
self.getting_data.set()
|
|
379
379
|
|
|
380
380
|
def __sizeof__(self):
|
|
381
|
+
"""
|
|
382
|
+
Return the approximate memory footprint of the Picker instance.
|
|
383
|
+
|
|
384
|
+
This includes the size of the instance itself and the sizes of its attributes.
|
|
385
|
+
"""
|
|
381
386
|
|
|
382
387
|
size = super().__sizeof__()
|
|
383
388
|
|
|
@@ -388,7 +393,19 @@ class Picker:
|
|
|
388
393
|
return size
|
|
389
394
|
|
|
390
395
|
def set_config(self, path: str ="~/.config/listpick/config.toml") -> bool:
|
|
391
|
-
""" Set config from toml file.
|
|
396
|
+
""" Set config from toml file.
|
|
397
|
+
|
|
398
|
+
This method reads a configuration file in TOML format, applies settings
|
|
399
|
+
to the Picker, and returns a boolean indicating success or failure.
|
|
400
|
+
|
|
401
|
+
Args:
|
|
402
|
+
path (str): The path to the configuration file.
|
|
403
|
+
|
|
404
|
+
Returns:
|
|
405
|
+
bool: True if the configuration was successfully set; False otherwise.
|
|
406
|
+
"""
|
|
407
|
+
self.logger.info(f"function: set_config()")
|
|
408
|
+
|
|
392
409
|
path = os.path.expanduser(os.path.expandvars(path))
|
|
393
410
|
if not os.path.exists(path):
|
|
394
411
|
return False
|
|
@@ -397,7 +414,9 @@ class Picker:
|
|
|
397
414
|
except Exception as e:
|
|
398
415
|
self.logger.error(f"get_config({path}) load error. {e}")
|
|
399
416
|
return False
|
|
417
|
+
|
|
400
418
|
|
|
419
|
+
# Change the global theme if colour_theme_number is in the loaded config
|
|
401
420
|
if "general" in config:
|
|
402
421
|
if "colour_theme_number" in config["general"] and config["general"]["colour_theme_number"] != self.colour_theme_number:
|
|
403
422
|
global COLOURS_SET
|
|
@@ -405,7 +424,7 @@ class Picker:
|
|
|
405
424
|
self.colours_end = set_colours(pick=config["general"]["colour_theme_number"], start=1)
|
|
406
425
|
self.colours = get_colours(config["general"]["colour_theme_number"])
|
|
407
426
|
|
|
408
|
-
|
|
427
|
+
# load the rest of the config options
|
|
409
428
|
if "general" in config:
|
|
410
429
|
for key, val in config["general"].items():
|
|
411
430
|
self.logger.info(f"set_config: key={key}, val={val}.")
|
|
@@ -417,30 +436,58 @@ class Picker:
|
|
|
417
436
|
return True
|
|
418
437
|
|
|
419
438
|
def get_config(self, path: str ="~/.config/listpick/config.toml") -> dict:
|
|
420
|
-
"""
|
|
439
|
+
"""
|
|
440
|
+
Retrieve configuration settings from a specified TOML file.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
path (str): The file path of the configuration file. Default is
|
|
444
|
+
~/.config/listpick/config.toml.
|
|
445
|
+
|
|
446
|
+
Returns:
|
|
447
|
+
dict: A dictionary containing the configuration settings loaded
|
|
448
|
+
from the TOML file. In case of an error, an empty dictionary is returned.
|
|
449
|
+
"""
|
|
450
|
+
|
|
421
451
|
self.logger.info(f"function: get_config()")
|
|
422
452
|
import toml
|
|
423
453
|
with open(os.path.expanduser(path), "r") as f:
|
|
424
454
|
config = toml.load(f)
|
|
425
455
|
return config
|
|
426
456
|
|
|
427
|
-
def update_term_size(self):
|
|
457
|
+
def update_term_size(self) -> None:
|
|
458
|
+
"""
|
|
459
|
+
Update self.term_h, self.term_w the function provided to the Picker.
|
|
460
|
+
|
|
461
|
+
Returns:
|
|
462
|
+
None
|
|
463
|
+
"""
|
|
428
464
|
self.term_h, self.term_w = self.screen_size_function(self.stdscr)
|
|
429
465
|
# self.term_h, self.term_w = self.stdscr.getmaxyx()
|
|
430
466
|
# self.term_w, self.term_h = os.get_terminal_size()
|
|
431
467
|
|
|
432
468
|
|
|
433
|
-
def get_term_size(self):
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
469
|
+
def get_term_size(self) -> Tuple[int, int]:
|
|
470
|
+
"""
|
|
471
|
+
Get the current terminal size using the function provided to the Picker.
|
|
472
|
+
|
|
473
|
+
Returns:
|
|
474
|
+
Tuple[int, int]: A tuple containing the (height, width) of the terminal.
|
|
475
|
+
"""
|
|
476
|
+
return self.screen_size_function(self.stdscr)
|
|
477
|
+
# return self.stdscr.getmaxyx()
|
|
478
|
+
# w, h = os.get_terminal_size()
|
|
479
|
+
# return h, w
|
|
437
480
|
|
|
438
|
-
def calculate_section_sizes(self):
|
|
481
|
+
def calculate_section_sizes(self) -> None:
|
|
439
482
|
"""
|
|
440
483
|
Calculte the following for the Picker:
|
|
441
484
|
self.items_per_page: the number of entry rows displayed
|
|
442
485
|
self.bottom_space: the size of the footer + the bottom buffer space
|
|
443
486
|
self.top_space: the size of the space at the top of the picker: title + modes + header + top_gap
|
|
487
|
+
Calculate and update the sizes of various sections of the Picker.
|
|
488
|
+
|
|
489
|
+
Returns:
|
|
490
|
+
None
|
|
444
491
|
"""
|
|
445
492
|
|
|
446
493
|
self.logger.debug(f"function: calculate_section_sizes()")
|
|
@@ -512,16 +559,27 @@ class Picker:
|
|
|
512
559
|
|
|
513
560
|
|
|
514
561
|
def get_visible_rows(self) -> list[list[str]]:
|
|
562
|
+
"""
|
|
563
|
+
Calculate and return the currently visible rows based on the cursor position and pagination settings.
|
|
515
564
|
|
|
565
|
+
This method determines which rows from the indexed items are visible on the screen,
|
|
566
|
+
accounting for pagination and scrolling. It sets the starting and ending indices
|
|
567
|
+
based on the current cursor position and the number of items per page.
|
|
568
|
+
|
|
569
|
+
Returns:
|
|
570
|
+
list[list[str]]: The currently visible rows as a list of lists, where each inner
|
|
571
|
+
list represents a row of data. If there are no indexed items, it returns the
|
|
572
|
+
items array.
|
|
573
|
+
"""
|
|
516
574
|
self.logger.debug(f"function: get_visible_rows()")
|
|
517
575
|
## Scroll with column select
|
|
518
576
|
if self.paginate:
|
|
519
|
-
start_index = (self.cursor_pos//self.items_per_page) * self.items_per_page
|
|
577
|
+
start_index = (self.cursor_pos // self.items_per_page) * self.items_per_page
|
|
520
578
|
end_index = min(start_index + self.items_per_page, len(self.indexed_items))
|
|
521
579
|
## Scroll
|
|
522
580
|
else:
|
|
523
|
-
scrolloff = self.items_per_page//2
|
|
524
|
-
start_index = max(0, min(self.cursor_pos - (self.items_per_page-scrolloff), len(self.indexed_items)-self.items_per_page))
|
|
581
|
+
scrolloff = self.items_per_page // 2
|
|
582
|
+
start_index = max(0, min(self.cursor_pos - (self.items_per_page - scrolloff), len(self.indexed_items) - self.items_per_page))
|
|
525
583
|
end_index = min(start_index + self.items_per_page, len(self.indexed_items))
|
|
526
584
|
if len(self.indexed_items) == 0: start_index, end_index = 0, 0
|
|
527
585
|
|
|
@@ -534,13 +592,15 @@ class Picker:
|
|
|
534
592
|
def initialise_picker_state(self, reset_colours=False) -> None:
|
|
535
593
|
""" Initialise state variables for the picker. These are: debugging and colours. """
|
|
536
594
|
|
|
595
|
+
# Define global curses colours
|
|
537
596
|
if curses.has_colors() and self.colours != None:
|
|
538
|
-
# raise Exception("Terminal does not support color")
|
|
539
597
|
curses.start_color()
|
|
598
|
+
|
|
540
599
|
if reset_colours:
|
|
541
600
|
global COLOURS_SET
|
|
542
601
|
COLOURS_SET = False
|
|
543
602
|
self.colours_end = set_colours(pick=self.colour_theme_number, start=self.colours_start)
|
|
603
|
+
|
|
544
604
|
if curses.COLORS >= 255 and curses.COLOR_PAIRS >= 150:
|
|
545
605
|
self.colours_start = self.colours_start
|
|
546
606
|
self.notification_colours_start = self.colours_start+50
|
|
@@ -557,57 +617,32 @@ class Picker:
|
|
|
557
617
|
self.colours = get_colours(self.colour_theme_number)
|
|
558
618
|
|
|
559
619
|
|
|
620
|
+
# Start logger
|
|
560
621
|
debug_levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL]
|
|
561
622
|
dbglvl = debug_levels[self.debug_level]
|
|
562
623
|
self.logger = setup_logger(name="picker_log", log_file="picker.log", log_enabled=self.debug, level =dbglvl)
|
|
563
624
|
self.logger.info(f"Initialiasing Picker.")
|
|
625
|
+
|
|
564
626
|
self.update_term_size()
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
# 1 2 3 4 5
|
|
569
|
-
# logger = logging.getLogger(__file__)
|
|
570
|
-
# if self.debug_level == 0:
|
|
571
|
-
# logger = logging.getLogger()
|
|
572
|
-
# logger.disabled = True
|
|
573
|
-
# else:
|
|
574
|
-
#
|
|
575
|
-
# file_handler = logging.FileHandler(f"{self.title}.log", mode='w')
|
|
576
|
-
# formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', '%m-%d-%Y %H:%M:%S')
|
|
577
|
-
# file_handler.setFormatter(formatter)
|
|
578
|
-
# logger.addHandler(file_handler)
|
|
579
|
-
# logger.setLevel(debug_levels[self.debug_level-1])
|
|
580
|
-
|
|
581
|
-
# logging.basicConfig(
|
|
582
|
-
# level=debug_levels[self.debug_level-1],
|
|
583
|
-
# format='%(asctime)s - %(levelname)s - %(message)s',
|
|
584
|
-
# datefmt='%m-%d-%Y %H:%M:%S',
|
|
585
|
-
# filename=f"{self.title}.log",
|
|
586
|
-
# filemode="w",
|
|
587
|
-
# )
|
|
588
|
-
#
|
|
589
|
-
# self.logger.info(f"Starging log. Log level {logger.getEffectiveLevel()}")
|
|
590
|
-
# self.logger.info(f"Starging log. Log level {repr(debug_levels)}, {self.debug_level}, {debug_levels[self.debug_level-1]}")
|
|
591
|
-
# self.notification(self.stdscr, f"Starging log. Log level {repr(debug_levels)}, {self.debug_level}, {debug_levels[self.debug_level-1]}")
|
|
592
|
-
# self.notification(self.stdscr, f"{__file__}")
|
|
593
|
-
|
|
594
|
-
## Logging level plan
|
|
595
|
-
# DEBUG: loop functions, draw screen, etc.
|
|
596
|
-
# INFO: main functions
|
|
597
|
-
# WARNING: any try-except fails
|
|
598
|
-
|
|
599
|
-
# No set_escdelay function on windows.
|
|
627
|
+
|
|
628
|
+
# The curses implementation for some systems (e.g., windows) does not allow set_escdelay
|
|
600
629
|
try:
|
|
601
630
|
curses.set_escdelay(25)
|
|
602
631
|
except:
|
|
603
632
|
logging.warning("Error trying to set curses.set_escdelay")
|
|
604
633
|
|
|
605
|
-
# self.stdscr.clear()
|
|
606
|
-
# self.stdscr.refresh()
|
|
607
|
-
# self.draw_screen()
|
|
608
|
-
|
|
609
634
|
def initialise_variables(self, get_data: bool = False) -> None:
|
|
610
|
-
"""
|
|
635
|
+
"""
|
|
636
|
+
This method sets up the internal state of the Picker by initialising various attributes,
|
|
637
|
+
getting new data (if get_data is True), and ensuring that the lists used for tracking
|
|
638
|
+
selections, options, and items are correctly of the correct type, size, and shape. If
|
|
639
|
+
filter or sort queries are set then they are applied (or re-applied as the case may be).
|
|
640
|
+
The cursor_pos and selections are retained by tracking the id of the rows (where the id
|
|
641
|
+
is row[self.id_column]).
|
|
642
|
+
|
|
643
|
+
Parameters:
|
|
644
|
+
- get_data (bool): If True, pulls data synchronously and updates tracking variables.
|
|
645
|
+
"""
|
|
611
646
|
|
|
612
647
|
self.logger.info(f"function: initialise_variables()")
|
|
613
648
|
|
|
@@ -615,6 +650,7 @@ class Picker:
|
|
|
615
650
|
|
|
616
651
|
## Get data synchronously
|
|
617
652
|
if get_data and self.refresh_function != None:
|
|
653
|
+
# Track cursor_pos and selections by ther id (row[self.id_column][col])
|
|
618
654
|
if self.track_entries_upon_refresh and len(self.items) > 0:
|
|
619
655
|
tracking = True
|
|
620
656
|
selected_indices = get_selected_indices(self.selections)
|
|
@@ -622,34 +658,35 @@ class Picker:
|
|
|
622
658
|
self.ids = [item[self.id_column] for i, item in enumerate(self.items) if i in selected_indices]
|
|
623
659
|
self.ids_tuples = [(i, item[self.id_column]) for i, item in enumerate(self.items) if i in selected_indices]
|
|
624
660
|
|
|
625
|
-
if len(self.indexed_items) > 0 and len(self.indexed_items)
|
|
661
|
+
if len(self.indexed_items) > 0 and self.cursor_pos < len(self.indexed_items) and len(self.indexed_items[0][1]) >= self.id_column:
|
|
626
662
|
self.cursor_pos_id = self.indexed_items[self.cursor_pos][1][self.id_column]
|
|
627
663
|
self.cursor_pos_prev = self.cursor_pos
|
|
628
|
-
|
|
629
|
-
|
|
630
664
|
|
|
665
|
+
# Set the state of the threading event
|
|
666
|
+
# Though we are getting data synchronously, we ensure the correct state for self.getting_data
|
|
631
667
|
self.getting_data.clear()
|
|
632
668
|
self.refresh_function(self.items, self.header, self.visible_rows_indices, self.getting_data)
|
|
633
669
|
|
|
634
|
-
self.items = pad_lists_to_same_length(self.items)
|
|
635
670
|
|
|
671
|
+
# Ensure that an emtpy items object has the form [[]]
|
|
636
672
|
if self.items == []: self.items = [[]]
|
|
637
|
-
|
|
673
|
+
|
|
674
|
+
# Ensure that items is a List[List[Str]] object
|
|
638
675
|
if len(self.items) > 0 and not isinstance(self.items[0], list):
|
|
639
676
|
self.items = [[item] for item in self.items]
|
|
640
677
|
# self.items = [[str(cell) for cell in row] for row in self.items]
|
|
641
678
|
|
|
679
|
+
# Ensure that the each of the rows of the items are of the same length
|
|
680
|
+
self.items = pad_lists_to_same_length(self.items)
|
|
642
681
|
|
|
643
682
|
# Ensure that header is of the same length as the rows
|
|
644
683
|
if self.header and len(self.items) > 0 and len(self.header) != len(self.items[0]):
|
|
645
684
|
self.header = [str(self.header[i]) if i < len(self.header) else "" for i in range(len(self.items[0]))]
|
|
646
685
|
|
|
647
|
-
# Constants
|
|
648
|
-
# DEFAULT_ITEMS_PER_PAGE = os.get_terminal_size().lines - top_gap*2-2-int(bool(header))
|
|
649
|
-
|
|
650
686
|
self.calculate_section_sizes()
|
|
651
687
|
|
|
652
|
-
|
|
688
|
+
|
|
689
|
+
# Ensure that the selection-tracking variables are the correct shape
|
|
653
690
|
if len(self.selections) != len(self.items):
|
|
654
691
|
self.selections = {i : False if i not in self.selections else bool(self.selections[i]) for i in range(len(self.items))}
|
|
655
692
|
|
|
@@ -660,31 +697,34 @@ class Picker:
|
|
|
660
697
|
self.cell_selections = {}
|
|
661
698
|
self.selected_cells_by_row = {}
|
|
662
699
|
|
|
700
|
+
def extend_list_to_length(lst, length, default_value):
|
|
701
|
+
"""Extend a list to the target length using a default value."""
|
|
702
|
+
if len(lst) < length:
|
|
703
|
+
lst.extend([copy.deepcopy(default_value) for _ in range(length - len(lst))])
|
|
663
704
|
|
|
664
705
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
if
|
|
670
|
-
self.
|
|
671
|
-
|
|
672
|
-
self.
|
|
673
|
-
|
|
674
|
-
self.editable_columns = self.
|
|
675
|
-
|
|
706
|
+
row_count = len(self.items)
|
|
707
|
+
col_count = len(self.items[0]) if row_count else 0
|
|
708
|
+
|
|
709
|
+
# Ensure that the length of the option lists are of the correct length.
|
|
710
|
+
if row_count > 0:
|
|
711
|
+
extend_list_to_length(self.require_option, length=row_count, default_value=self.require_option_default)
|
|
712
|
+
extend_list_to_length(self.option_functions, length=row_count, default_value=self.default_option_function)
|
|
713
|
+
extend_list_to_length(self.columns_sort_method, length=col_count, default_value=0)
|
|
714
|
+
extend_list_to_length(self.sort_reverse, length=col_count, default_value=False)
|
|
715
|
+
extend_list_to_length(self.editable_columns, length=col_count, default_value=self.editable_by_default)
|
|
716
|
+
|
|
717
|
+
if row_count > 0 and len(self.column_indices) < len(self.items[0]):
|
|
676
718
|
self.column_indices = self.column_indices + [i for i in range(len(self.column_indices), len(self.items[0]))]
|
|
677
719
|
|
|
678
720
|
|
|
679
721
|
|
|
680
|
-
#
|
|
681
|
-
# self.indexed_items = list(enumerate(items2))
|
|
722
|
+
# Create an indexed list of the items which will track the visible rows
|
|
682
723
|
if self.items == [[]]: self.indexed_items = []
|
|
683
724
|
else: self.indexed_items = list(enumerate(self.items))
|
|
684
725
|
|
|
685
|
-
#
|
|
726
|
+
# Apply the filter query
|
|
686
727
|
if self.filter_query:
|
|
687
|
-
# prev_index = self.indexed_items[cursor_pos][0] if len(self.indexed_items)>0 else 0
|
|
688
728
|
# prev_index = self.indexed_items[cursor_pos][0] if len(self.indexed_items)>0 else 0
|
|
689
729
|
self.indexed_items = filter_items(self.items, self.indexed_items, self.filter_query)
|
|
690
730
|
if self.cursor_pos in [x[0] for x in self.indexed_items]: self.cursor_pos = [x[0] for x in self.indexed_items].index(self.cursor_pos)
|
|
@@ -700,22 +740,30 @@ class Picker:
|
|
|
700
740
|
)
|
|
701
741
|
if return_val:
|
|
702
742
|
self.cursor_pos, self.search_index, self.search_count, self.highlights = tmp_cursor, tmp_index, tmp_count, tmp_highlights
|
|
703
|
-
|
|
743
|
+
|
|
744
|
+
# Apply the current sort method
|
|
704
745
|
if len(self.indexed_items) > 0:
|
|
705
746
|
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
|
|
706
747
|
|
|
707
748
|
|
|
708
|
-
#
|
|
709
|
-
## Move to a selectable row (if applicable)
|
|
749
|
+
# If we have more unselectable indices than rows, clear the unselectable_indices
|
|
710
750
|
if len(self.items) <= len(self.unselectable_indices): self.unselectable_indices = []
|
|
711
|
-
new_pos = (self.cursor_pos)%len(self.items)
|
|
712
|
-
while new_pos in self.unselectable_indices and new_pos != self.cursor_pos:
|
|
713
|
-
new_pos = (new_pos + 1) % len(self.items)
|
|
714
751
|
|
|
715
|
-
|
|
716
|
-
self.cursor_pos
|
|
752
|
+
# Move cursur to a selectable row if we are currently on an unselectable row)
|
|
753
|
+
if self.cursor_pos * len(self.items) in self.unselectable_indices:
|
|
754
|
+
original_pos = new_pos = (self.cursor_pos)%len(self.items)
|
|
755
|
+
while new_pos in self.unselectable_indices:
|
|
756
|
+
new_pos = (new_pos + 1) % len(self.items)
|
|
757
|
+
|
|
758
|
+
# Break if we loop back to the original position
|
|
759
|
+
if new_pos == original_pos:
|
|
760
|
+
break
|
|
761
|
+
|
|
762
|
+
self.cursor_pos = max(0, min(new_pos, len(self.items)-1))
|
|
763
|
+
|
|
764
|
+
# Initialise sheets
|
|
765
|
+
extend_list_to_length(self.sheet_states, length=len(self.sheets), default_value={})
|
|
717
766
|
|
|
718
|
-
# Sheets and files
|
|
719
767
|
if len(self.sheet_states) < len(self.sheets):
|
|
720
768
|
self.sheet_states += [{} for _ in range(len(self.sheets) - len(self.sheet_states))]
|
|
721
769
|
if len(self.sheets):
|
|
@@ -723,15 +771,16 @@ class Picker:
|
|
|
723
771
|
self.sheet_index = 0
|
|
724
772
|
self.sheet_name = self.sheets[self.sheet_index]
|
|
725
773
|
|
|
726
|
-
|
|
727
|
-
|
|
774
|
+
# Initialise files
|
|
775
|
+
extend_list_to_length(self.loaded_file_states, length=len(self.loaded_files), default_value={})
|
|
728
776
|
if len(self.loaded_files):
|
|
729
777
|
if self.loaded_file_index >= len(self.loaded_files):
|
|
730
778
|
self.loaded_file_index = 0
|
|
731
779
|
self.loaded_file = self.loaded_files[self.loaded_file_index]
|
|
732
780
|
|
|
733
|
-
|
|
734
|
-
# Ensure that selected indices are
|
|
781
|
+
|
|
782
|
+
# Ensure that the correct cursor_pos and selected indices are reselected
|
|
783
|
+
# if we have fetched new data.
|
|
735
784
|
if self.track_entries_upon_refresh and (self.data_ready or tracking) and len(self.items) > 1:
|
|
736
785
|
selected_indices = []
|
|
737
786
|
all_ids = [item[self.id_column] for item in self.items]
|
|
@@ -754,6 +803,8 @@ class Picker:
|
|
|
754
803
|
|
|
755
804
|
|
|
756
805
|
|
|
806
|
+
# Ensure cursor_pos is set to a valid index
|
|
807
|
+
# If we have fetched new data then we attempt to set cursor_pos to the row with the same id as prev
|
|
757
808
|
if len(self.indexed_items):
|
|
758
809
|
if self.pin_cursor:
|
|
759
810
|
self.cursor_pos = min(self.cursor_pos_prev, len(self.indexed_items)-1)
|
|
@@ -765,7 +816,12 @@ class Picker:
|
|
|
765
816
|
else:
|
|
766
817
|
self.cursor_pos = 0
|
|
767
818
|
|
|
768
|
-
|
|
819
|
+
|
|
820
|
+
# Ensure that the pane indices are within the range of the available panes.
|
|
821
|
+
if len(self.left_panes): self.left_pane_index %= len(self.left_panes)
|
|
822
|
+
else: self.left_pane_index = 0
|
|
823
|
+
if len(self.right_panes): self.right_pane_index %= len(self.right_panes)
|
|
824
|
+
else: self.right_pane_index = 0
|
|
769
825
|
|
|
770
826
|
|
|
771
827
|
|
|
@@ -862,14 +918,11 @@ class Picker:
|
|
|
862
918
|
self.stdscr.erase()
|
|
863
919
|
|
|
864
920
|
self.update_term_size()
|
|
865
|
-
# if self.split_right and len(self.right_panes):
|
|
866
|
-
# proportion = self.right_panes[self.right_pane_index]["proportion"]
|
|
867
|
-
# self.rows_w, self.rows_h = int(self.term_w*proportion), self.term_h
|
|
868
|
-
# else:
|
|
869
|
-
# self.rows_w, self.rows_h = self.term_w, self.term_h
|
|
870
921
|
|
|
871
|
-
#
|
|
922
|
+
# Determine footer size
|
|
872
923
|
self.footer.adjust_sizes(self.term_h,self.term_w)
|
|
924
|
+
|
|
925
|
+
# The height of the footer may need to be adjusted if the file changes.
|
|
873
926
|
self.calculate_section_sizes()
|
|
874
927
|
|
|
875
928
|
# Test if the terminal is of a sufficient size to display the picker
|
|
@@ -887,28 +940,18 @@ class Picker:
|
|
|
887
940
|
end_index = min(start_index + self.items_per_page, len(self.indexed_items))
|
|
888
941
|
if len(self.indexed_items) == 0: start_index, end_index = 0, 0
|
|
889
942
|
|
|
890
|
-
# 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)
|
|
891
|
-
# Determine widths based only on the currently indexed rows
|
|
892
|
-
# rows = [v[1] for v in self.indexed_items] if len(self.indexed_items) else self.items
|
|
893
|
-
# Determine widths based only on the currently displayed indexed rows
|
|
894
|
-
# rows = [v[1] for v in self.indexed_items[start_index:end_index]] if len(self.indexed_items) else self.items
|
|
895
943
|
self.get_visible_rows()
|
|
896
944
|
self.column_widths = get_column_widths(self.visible_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)
|
|
897
945
|
visible_column_widths = [c for i,c in enumerate(self.column_widths) if i not in self.hidden_columns]
|
|
898
946
|
visible_columns_total_width = sum(visible_column_widths) + len(self.separator)*(len(visible_column_widths)-1)
|
|
899
947
|
|
|
900
|
-
# Determine the number of items_per_page, top_size and bottom_size
|
|
901
|
-
# self.calculate_section_sizes()
|
|
902
|
-
|
|
903
|
-
# top_space = self.top_gap
|
|
904
948
|
|
|
905
|
-
## Display title
|
|
949
|
+
## Display title
|
|
906
950
|
if self.title:
|
|
907
951
|
padded_title = f" {self.title.strip()} "
|
|
908
952
|
self.stdscr.addstr(self.top_gap, 0, f"{' ':^{self.term_w}}", curses.color_pair(self.colours_start+16))
|
|
909
953
|
title_x = (self.term_w-wcswidth(padded_title))//2
|
|
910
954
|
self.stdscr.addstr(self.top_gap, title_x, padded_title, curses.color_pair(self.colours_start+16) | curses.A_BOLD)
|
|
911
|
-
# top_space += 1
|
|
912
955
|
|
|
913
956
|
## Display modes
|
|
914
957
|
if self.display_modes and self.modes not in [[{}], []]:
|
|
@@ -930,7 +973,6 @@ class Picker:
|
|
|
930
973
|
else:
|
|
931
974
|
self.stdscr.addstr(self.top_gap+1, xmode, mode_str, curses.color_pair(self.colours_start+15) | curses.A_UNDERLINE)
|
|
932
975
|
xmode += split_space+mode_widths[i]
|
|
933
|
-
# top_space += 1
|
|
934
976
|
|
|
935
977
|
## Display header
|
|
936
978
|
if self.header and self.show_header:
|
|
@@ -954,87 +996,66 @@ class Picker:
|
|
|
954
996
|
header_str = header_str[self.leftmost_char:]
|
|
955
997
|
header_str = header_str[:header_str_w]
|
|
956
998
|
header_ypos = self.top_gap + bool(self.title) + bool(self.display_modes and self.modes)
|
|
999
|
+
|
|
1000
|
+
# Ensure that the full header width is filled--important if the header rows do not fill the terminal width
|
|
957
1001
|
self.stdscr.addstr(header_ypos, self.rows_box_x_i, ' '*self.rows_w, curses.color_pair(self.colours_start+28) | curses.A_BOLD)
|
|
1002
|
+
|
|
1003
|
+
# Draw header string
|
|
958
1004
|
self.stdscr.addstr(header_ypos, self.startx, header_str, curses.color_pair(self.colours_start+4) | curses.A_BOLD)
|
|
959
1005
|
|
|
960
1006
|
# Highlight sort column
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
x_pos = len(up_to_selected_col) - self.leftmost_char + self.startx
|
|
1007
|
+
if self.selected_column != None and self.selected_column not in self.hidden_columns:
|
|
1008
|
+
# start of string is on screen
|
|
1009
|
+
col_width = self.column_widths[self.selected_column]
|
|
1010
|
+
number = f"{self.selected_column}. " if self.number_columns else ""
|
|
1011
|
+
col_str = self.header[self.selected_column][:self.column_widths[self.selected_column]-len(number)]
|
|
1012
|
+
highlighted_col_str = (number+f"{col_str:^{self.column_widths[self.selected_column]-len(number)}}") + self.separator
|
|
1013
|
+
|
|
1014
|
+
if len(self.column_widths) == 1:
|
|
1015
|
+
colour = curses.color_pair(self.colours_start+28) | curses.A_BOLD
|
|
1016
|
+
else:
|
|
1017
|
+
colour = curses.color_pair(self.colours_start+19) | curses.A_BOLD
|
|
1018
|
+
# Start of selected column is on the screen
|
|
1019
|
+
if self.leftmost_char <= len(up_to_selected_col) and self.leftmost_char+self.rows_w-self.left_gutter_width > len(up_to_selected_col):
|
|
1020
|
+
x_pos = len(up_to_selected_col) - self.leftmost_char + self.startx
|
|
976
1021
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1022
|
+
# Whole cell of the selected column is on the screen
|
|
1023
|
+
if len(up_to_selected_col)+col_width - self.leftmost_char < self.rows_w-self.left_gutter_width:
|
|
1024
|
+
disp_str = highlighted_col_str
|
|
980
1025
|
|
|
981
|
-
|
|
982
|
-
else:
|
|
983
|
-
overflow = (len(up_to_selected_col)+len(highlighted_col_str)) - (self.leftmost_char+self.rows_w - self.left_gutter_width)
|
|
984
|
-
disp_str = highlighted_col_str[:-overflow]
|
|
985
|
-
disp_str_w = min(len(disp_str), self.term_w-x_pos)
|
|
986
|
-
disp_str = truncate_to_display_width(disp_str, disp_str_w, self.centre_in_cols, self.unicode_char_width)
|
|
987
|
-
|
|
988
|
-
self.stdscr.addstr(header_ypos, x_pos , disp_str, colour)
|
|
989
|
-
# Start of the cell is to the right of the screen
|
|
990
|
-
elif self.leftmost_char+self.rows_w <= len(up_to_selected_col):
|
|
991
|
-
pass
|
|
992
|
-
# The end of the cell is on the screen, the start of the cell is not
|
|
993
|
-
elif 0 <= len(up_to_selected_col)+col_width - self.leftmost_char <= self.rows_w :
|
|
994
|
-
x_pos = self.startx
|
|
995
|
-
beg = self.leftmost_char - len(up_to_selected_col)
|
|
996
|
-
disp_str = highlighted_col_str[beg:]
|
|
997
|
-
disp_str_w = min(len(disp_str), self.term_w-x_pos)
|
|
998
|
-
disp_str = truncate_to_display_width(disp_str, disp_str_w, self.centre_in_cols, self.unicode_char_width)
|
|
999
|
-
self.stdscr.addstr(header_ypos, x_pos , disp_str, colour)
|
|
1000
|
-
# The middle of the cell is on the screen, the start and end of the cell are not
|
|
1001
|
-
elif self.leftmost_char <= len(up_to_selected_col) + col_width//2 <= self.leftmost_char+self.rows_w:
|
|
1002
|
-
beg = self.leftmost_char - len(up_to_selected_col)
|
|
1003
|
-
overflow = (len(up_to_selected_col)+len(highlighted_col_str)) - (self.leftmost_char+self.rows_w)
|
|
1004
|
-
x_pos = self.startx
|
|
1005
|
-
disp_str = highlighted_col_str[beg:-overflow]
|
|
1006
|
-
disp_str_w = min(len(disp_str), self.term_w-x_pos)
|
|
1007
|
-
disp_str = truncate_to_display_width(disp_str, disp_str_w, self.centre_in_cols, self.unicode_char_width)
|
|
1008
|
-
|
|
1009
|
-
self.stdscr.addstr(header_ypos, x_pos , disp_str, colour)
|
|
1010
|
-
# The cell is to the left of the screen
|
|
1026
|
+
# Start of the cell is on the screen, but the end of the cell is not
|
|
1011
1027
|
else:
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1028
|
+
overflow = (len(up_to_selected_col)+len(highlighted_col_str)) - (self.leftmost_char+self.rows_w - self.left_gutter_width)
|
|
1029
|
+
disp_str = highlighted_col_str[:-overflow]
|
|
1030
|
+
disp_str_w = min(len(disp_str), self.term_w-x_pos)
|
|
1031
|
+
disp_str = truncate_to_display_width(disp_str, disp_str_w, self.centre_in_cols, self.unicode_char_width)
|
|
1032
|
+
|
|
1033
|
+
self.stdscr.addstr(header_ypos, x_pos , disp_str, colour)
|
|
1034
|
+
# Start of the cell is to the right of the screen
|
|
1035
|
+
elif self.leftmost_char+self.rows_w <= len(up_to_selected_col):
|
|
1036
|
+
pass
|
|
1037
|
+
# The end of the cell is on the screen, the start of the cell is not
|
|
1038
|
+
elif 0 <= len(up_to_selected_col)+col_width - self.leftmost_char <= self.rows_w :
|
|
1039
|
+
x_pos = self.startx
|
|
1040
|
+
beg = self.leftmost_char - len(up_to_selected_col)
|
|
1041
|
+
disp_str = highlighted_col_str[beg:]
|
|
1042
|
+
disp_str_w = min(len(disp_str), self.term_w-x_pos)
|
|
1043
|
+
disp_str = truncate_to_display_width(disp_str, disp_str_w, self.centre_in_cols, self.unicode_char_width)
|
|
1044
|
+
self.stdscr.addstr(header_ypos, x_pos , disp_str, colour)
|
|
1045
|
+
# The middle of the cell is on the screen, the start and end of the cell are not
|
|
1046
|
+
elif self.leftmost_char <= len(up_to_selected_col) + col_width//2 <= self.leftmost_char+self.rows_w:
|
|
1047
|
+
beg = self.leftmost_char - len(up_to_selected_col)
|
|
1048
|
+
overflow = (len(up_to_selected_col)+len(highlighted_col_str)) - (self.leftmost_char+self.rows_w)
|
|
1049
|
+
x_pos = self.startx
|
|
1050
|
+
disp_str = highlighted_col_str[beg:-overflow]
|
|
1051
|
+
disp_str_w = min(len(disp_str), self.term_w-x_pos)
|
|
1052
|
+
disp_str = truncate_to_display_width(disp_str, disp_str_w, self.centre_in_cols, self.unicode_char_width)
|
|
1053
|
+
|
|
1054
|
+
self.stdscr.addstr(header_ypos, x_pos , disp_str, colour)
|
|
1055
|
+
|
|
1056
|
+
# The cell is to the left of the focused part of the screen
|
|
1057
|
+
else:
|
|
1058
|
+
pass
|
|
1038
1059
|
|
|
1039
1060
|
# Display row header
|
|
1040
1061
|
if self.show_row_header:
|
|
@@ -1058,41 +1079,34 @@ class Picker:
|
|
|
1058
1079
|
colour = curses.color_pair(self.colours_start+colour_pair_number) | curses.A_BOLD
|
|
1059
1080
|
else:
|
|
1060
1081
|
colour = curses.color_pair(self.colours_start+colour_pair_number)
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
if
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
cell_value = f"{self.indexed_items[row][1][col]:^{cell_width-len(self.separator)}}" + self.separator
|
|
1068
|
-
else:
|
|
1069
|
-
cell_value = self.indexed_items[row][1][col][:self.column_widths[col]] + self.separator
|
|
1070
|
-
# cell_value = cell_value[:min(cell_width, cell_max_width)-len(self.separator)]
|
|
1071
|
-
cell_value = truncate_to_display_width(cell_value, min(cell_width, cell_max_width), self.centre_in_cols, self.unicode_char_width)
|
|
1072
|
-
# cell_value = cell_value + self.separator
|
|
1073
|
-
# cell_value = cell_value
|
|
1074
|
-
cell_value = truncate_to_display_width(cell_value, min(cell_width, cell_max_width), self.centre_in_cols, self.unicode_char_width)
|
|
1075
|
-
if wcswidth(cell_value) + cell_pos > self.term_w:
|
|
1076
|
-
cell_value = truncate_to_display_width(cell_value, self.term_w-cell_pos-10, self.centre_in_cols, self.unicode_char_width)
|
|
1077
|
-
|
|
1078
|
-
self.stdscr.addstr(y, cell_pos, cell_value, colour)
|
|
1079
|
-
# Part of the cell is on screen
|
|
1080
|
-
elif self.startx <= cell_pos+cell_width and cell_pos <= (self.rows_w):
|
|
1081
|
-
s = "max" if cell_max_width <= cell_width else "norm"
|
|
1082
|
-
cell_start = self.startx - cell_pos
|
|
1083
|
-
# self.stdscr.addstr(y, self.startx, ' '*(cell_width-cell_start), curses.color_pair(self.colours_start+colour_pair_number))
|
|
1084
|
-
cell_value = self.indexed_items[row][1][col]
|
|
1085
|
-
cell_value = f"{cell_value:^{self.column_widths[col]}}"
|
|
1086
|
-
|
|
1087
|
-
cell_value = cell_value[cell_start:visible_column_widths[col]][:self.rows_w-self.left_gutter_width]
|
|
1088
|
-
cell_value = truncate_to_display_width(cell_value, min(wcswidth(cell_value), cell_width, cell_max_width), self.centre_in_cols, self.unicode_char_width)
|
|
1089
|
-
cell_value += self.separator
|
|
1090
|
-
cell_value = truncate_to_display_width(cell_value, min(wcswidth(cell_value), cell_width, cell_max_width), self.centre_in_cols, self.unicode_char_width)
|
|
1091
|
-
self.stdscr.addstr(y, self.startx, cell_value, colour)
|
|
1082
|
+
# Start of cell is on screen
|
|
1083
|
+
if self.startx <= cell_pos <= self.rows_w+self.startx:
|
|
1084
|
+
s = "max" if cell_max_width <= cell_width else "norm"
|
|
1085
|
+
self.stdscr.addstr(y, cell_pos, (' '*cell_width)[:cell_max_width], colour)
|
|
1086
|
+
if self.centre_in_cols:
|
|
1087
|
+
cell_value = f"{self.indexed_items[row][1][col]:^{cell_width-len(self.separator)}}" + self.separator
|
|
1092
1088
|
else:
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1089
|
+
cell_value = self.indexed_items[row][1][col][:self.column_widths[col]] + self.separator
|
|
1090
|
+
cell_value = truncate_to_display_width(cell_value, min(cell_width, cell_max_width), self.centre_in_cols, self.unicode_char_width)
|
|
1091
|
+
cell_value = truncate_to_display_width(cell_value, min(cell_width, cell_max_width), self.centre_in_cols, self.unicode_char_width)
|
|
1092
|
+
if wcswidth(cell_value) + cell_pos > self.term_w:
|
|
1093
|
+
cell_value = truncate_to_display_width(cell_value, self.term_w-cell_pos-10, self.centre_in_cols, self.unicode_char_width)
|
|
1094
|
+
|
|
1095
|
+
self.stdscr.addstr(y, cell_pos, cell_value, colour)
|
|
1096
|
+
|
|
1097
|
+
# Part of the cell is on screen
|
|
1098
|
+
elif self.startx <= cell_pos+cell_width and cell_pos <= (self.rows_w):
|
|
1099
|
+
s = "max" if cell_max_width <= cell_width else "norm"
|
|
1100
|
+
cell_start = self.startx - cell_pos
|
|
1101
|
+
cell_value = self.indexed_items[row][1][col]
|
|
1102
|
+
cell_value = f"{cell_value:^{self.column_widths[col]}}"
|
|
1103
|
+
|
|
1104
|
+
cell_value = cell_value[cell_start:visible_column_widths[col]][:self.rows_w-self.left_gutter_width]
|
|
1105
|
+
cell_value = truncate_to_display_width(cell_value, min(wcswidth(cell_value), cell_width, cell_max_width), self.centre_in_cols, self.unicode_char_width)
|
|
1106
|
+
cell_value += self.separator
|
|
1107
|
+
cell_value = truncate_to_display_width(cell_value, min(wcswidth(cell_value), cell_width, cell_max_width), self.centre_in_cols, self.unicode_char_width)
|
|
1108
|
+
self.stdscr.addstr(y, self.startx, cell_value, colour)
|
|
1109
|
+
else:
|
|
1096
1110
|
pass
|
|
1097
1111
|
|
|
1098
1112
|
|
listpick/ui/keys.py
CHANGED
|
@@ -51,7 +51,7 @@ picker_keys = {
|
|
|
51
51
|
"continue_search_forward": [ord('n')],
|
|
52
52
|
"continue_search_backward": [ord('N')],
|
|
53
53
|
"cancel": [27], # Escape key
|
|
54
|
-
"opts_input": [
|
|
54
|
+
"opts_input": [keycodes.META_o],
|
|
55
55
|
"opts_select": [ord('o')],
|
|
56
56
|
"mode_next": [9], # Tab key
|
|
57
57
|
"mode_prev": [353], # Shift+Tab key
|
listpick/ui/picker_colours.py
CHANGED
|
@@ -294,6 +294,61 @@ def get_colours(pick:int=0) -> Dict[str, int]:
|
|
|
294
294
|
'active_column_bg': curses.COLOR_BLACK,
|
|
295
295
|
'active_column_fg': curses.COLOR_WHITE,
|
|
296
296
|
},
|
|
297
|
+
### (6) Use default colors for bg
|
|
298
|
+
# {
|
|
299
|
+
# 'background': -1,
|
|
300
|
+
# 'normal_fg': -1,
|
|
301
|
+
# 'unselected_bg': -1,
|
|
302
|
+
# 'unselected_fg': -1,
|
|
303
|
+
# 'cursor_bg': 21,
|
|
304
|
+
# 'cursor_fg': -1,
|
|
305
|
+
# 'selected_bg': 54,
|
|
306
|
+
# 'selected_fg': -1,
|
|
307
|
+
# 'header_bg': 255,
|
|
308
|
+
# 'header_fg': 232,
|
|
309
|
+
# 'error_bg': 232,
|
|
310
|
+
# 'error_fg': curses.COLOR_RED,
|
|
311
|
+
# 'complete_bg': 232,
|
|
312
|
+
# 'complete_fg': 82,
|
|
313
|
+
# 'waiting_bg': 232,
|
|
314
|
+
# 'waiting_fg': curses.COLOR_YELLOW,
|
|
315
|
+
# 'active_bg': 232,
|
|
316
|
+
# 'active_fg': 33,
|
|
317
|
+
# 'paused_bg': -1,
|
|
318
|
+
# 'paused_fg': 244,
|
|
319
|
+
# 'search_bg': 162,
|
|
320
|
+
# 'search_fg': -1,
|
|
321
|
+
# 'active_input_bg': -1,
|
|
322
|
+
# 'active_input_fg': 232,
|
|
323
|
+
# 'modes_selected_bg': 232,
|
|
324
|
+
# 'modes_selected_fg': -1,
|
|
325
|
+
# 'modes_unselected_bg': 255,
|
|
326
|
+
# 'modes_unselected_fg': 232,
|
|
327
|
+
# 'title_bar': 232,
|
|
328
|
+
# 'title_bg': 232,
|
|
329
|
+
# 'title_fg': -1,
|
|
330
|
+
# 'scroll_bar_bg': 247,
|
|
331
|
+
# 'selected_header_column_bg': 232,
|
|
332
|
+
# 'selected_header_column_fg': -1,
|
|
333
|
+
# 'unselected_header_column_bg': -1,
|
|
334
|
+
# 'unselected_header_column_fg': -1,
|
|
335
|
+
# 'footer_bg': 232,
|
|
336
|
+
# 'footer_fg': -1,
|
|
337
|
+
# 'refreshing_bg': 232,
|
|
338
|
+
# 'refreshing_fg': -1,
|
|
339
|
+
# 'refreshing_inactive_bg': 232,
|
|
340
|
+
# 'refreshing_inactive_fg': 232,
|
|
341
|
+
# '40pc_bg': 232,
|
|
342
|
+
# '40pc_fg': 166,
|
|
343
|
+
# 'footer_string_bg': 232,
|
|
344
|
+
# 'footer_string_fg': -1,
|
|
345
|
+
# 'selected_cell_bg': 54,
|
|
346
|
+
# 'selected_cell_fg': -1,
|
|
347
|
+
# 'deselecting_cell_bg': 162,
|
|
348
|
+
# 'deselecting_cell_fg': -1,
|
|
349
|
+
# 'active_column_bg': 234,
|
|
350
|
+
# 'active_column_fg': -1,
|
|
351
|
+
# },
|
|
297
352
|
]
|
|
298
353
|
for colour in colours:
|
|
299
354
|
colour["20pc_bg"] = colour["background"]
|
listpick/utils/utils.py
CHANGED
|
@@ -15,6 +15,7 @@ import os
|
|
|
15
15
|
from typing import Tuple, Dict
|
|
16
16
|
import logging
|
|
17
17
|
import shlex
|
|
18
|
+
from collections import defaultdict
|
|
18
19
|
|
|
19
20
|
logger = logging.getLogger('picker_log')
|
|
20
21
|
|
|
@@ -205,17 +206,11 @@ def get_selected_cells(cell_selections: Dict[Tuple[int, int], bool]) -> list[Tup
|
|
|
205
206
|
def get_selected_cells_by_row(cell_selections: dict[tuple[int, int], bool]) -> dict[int, list[int]]:
|
|
206
207
|
""" {0: [1,2], 9: [1] }"""
|
|
207
208
|
|
|
208
|
-
d =
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
d[tup[0]].append(tup[1])
|
|
214
|
-
else:
|
|
215
|
-
d[tup[0]] = [tup[1]]
|
|
216
|
-
except:
|
|
217
|
-
pass
|
|
218
|
-
return d
|
|
209
|
+
d = defaultdict(list)
|
|
210
|
+
for (row, col), selected in cell_selections.items():
|
|
211
|
+
if selected:
|
|
212
|
+
d[row].append(col)
|
|
213
|
+
return dict(d)
|
|
219
214
|
|
|
220
215
|
def get_selected_values(items: list[list[str]], selections: dict[int, bool]) -> list[list[str]]:
|
|
221
216
|
""" Return a list of rows based on wich are True in the selections dictionary. """
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
listpick/__init__.py,sha256=ExXc97-bibodH--wlwpQivl0zCNR5D1hvpvrf7OBofU,154
|
|
2
2
|
listpick/__main__.py,sha256=wkCjDdqw093W27yWwnlC3nG_sMRKaIad7hHHWy0RBgY,193
|
|
3
|
-
listpick/listpick_app.py,sha256=
|
|
3
|
+
listpick/listpick_app.py,sha256=IavN099zeGWv36ogNjbR20vHXtvRYR74-pZfqiSFHng,211476
|
|
4
4
|
listpick/pane/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
listpick/pane/get_data.py,sha256=l12mHIb6qoZWIfW5zZZY8K8EqNcyIcRiHgtRaM2CVGs,2735
|
|
6
6
|
listpick/pane/left_pane_functions.py,sha256=SVIW4Ef8uNPBQRk4hL67mEFL3pfgChSFZSMRz06CVzw,5543
|
|
@@ -13,8 +13,8 @@ listpick/ui/draw_screen.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
13
13
|
listpick/ui/footer.py,sha256=NcdH1uO_ma91m0qCczyQZ3zGrexfkiEnwDf5E4tHSMk,15089
|
|
14
14
|
listpick/ui/help_screen.py,sha256=zbfGIgb-IXtATpl4_Sx7nPbsnRXZ7eiMYlCKGS9EFmw,5608
|
|
15
15
|
listpick/ui/input_field.py,sha256=scJjvmSS0QqeDbCky7_0Zgt35Aki7gezRJkrQROlLg4,30034
|
|
16
|
-
listpick/ui/keys.py,sha256=
|
|
17
|
-
listpick/ui/picker_colours.py,sha256=
|
|
16
|
+
listpick/ui/keys.py,sha256=5wXx7K4zLsKw3yt_Q9_GCpgtcGMvQyChXrBhXtuc8-8,13852
|
|
17
|
+
listpick/ui/picker_colours.py,sha256=PYWtJEbBCsiM-Gbm83vJiFoIwfKuJuP4SGKxpozszKY,15159
|
|
18
18
|
listpick/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
listpick/utils/clipboard_operations.py,sha256=ORdNm2kgGbfs51xJSvgJPERgoSmBgT11axuMkvSoP9A,3133
|
|
20
20
|
listpick/utils/config.py,sha256=MEnAZg2Rhfl38XofEIN0uoVAOY7I0ftc79Evk3fOiVw,1654
|
|
@@ -32,10 +32,10 @@ listpick/utils/searching.py,sha256=Xk5UIqamNHL2L90z3ACB_Giqdpi9iRKoAJ6pKaqaD7Q,3
|
|
|
32
32
|
listpick/utils/sorting.py,sha256=WZZiVlVA3Zkcpwji3U5SNFlQ14zVEk3cZJtQirBkecQ,5329
|
|
33
33
|
listpick/utils/table_to_list_of_lists.py,sha256=XBj7eGBDF15BRME-swnoXyOfZWxXCxrXp0pzsBfcJ5g,12224
|
|
34
34
|
listpick/utils/user_input.py,sha256=L3ylI7nnuFM_TP1XKwpiKpxUSkNb2W5cr7mJjTmv_6E,4582
|
|
35
|
-
listpick/utils/utils.py,sha256=
|
|
36
|
-
listpick-0.1.16.
|
|
37
|
-
listpick-0.1.16.
|
|
38
|
-
listpick-0.1.16.
|
|
39
|
-
listpick-0.1.16.
|
|
40
|
-
listpick-0.1.16.
|
|
41
|
-
listpick-0.1.16.
|
|
35
|
+
listpick/utils/utils.py,sha256=_Z3pGDMPnEgPuhl_1BpEtXYi5tfWbuwRitj8Y5TeRUg,13653
|
|
36
|
+
listpick-0.1.16.11.dist-info/licenses/LICENSE.txt,sha256=2mP-MRHJptADDNE9VInMNg1tE-C6Qv93Z4CCQKrpg9w,1061
|
|
37
|
+
listpick-0.1.16.11.dist-info/METADATA,sha256=WRPPZnTIxabHjUTi34ZG_CjXad6aDbMqoO-V_7z7eQk,8025
|
|
38
|
+
listpick-0.1.16.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
39
|
+
listpick-0.1.16.11.dist-info/entry_points.txt,sha256=-QCf_BKIkUz35Y9nkYpjZWs2Qg0KfRna2PAs5DnF6BE,43
|
|
40
|
+
listpick-0.1.16.11.dist-info/top_level.txt,sha256=5mtsGEz86rz3qQDe0D463gGjAfSp6A3EWg4J4AGYr-Q,9
|
|
41
|
+
listpick-0.1.16.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|