make-selection 1.0.2__tar.gz → 1.0.4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: make_selection
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: Package for interactive command line menu
5
5
  Author-email: Steven Frazee <stevefrazee123@gmail.com>
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "make_selection"
3
- version = "1.0.2"
3
+ version = "1.0.4"
4
4
  authors = [
5
5
  { name="Steven Frazee", email="stevefrazee123@gmail.com" },
6
6
  ]
@@ -10,10 +10,11 @@ Ansi escape codes are used as described here: https://gist.github.com/fnky/45871
10
10
  import sys
11
11
  if sys.platform != "win32":
12
12
  raise NotImplementedError("This module is only available on Windows.")
13
- from typing import Any
14
- from copy import copy
15
13
  import msvcrt
16
14
  import ctypes
15
+ from typing import Any
16
+ from copy import copy
17
+ from enum import Enum
17
18
 
18
19
  stdout = -11
19
20
  enable_ansi_codes = 7
@@ -38,6 +39,16 @@ BACKSPACE = 8
38
39
  SPACEBAR = 32
39
40
  CTL_RIGHT = 116
40
41
 
42
+ class Mode(Enum):
43
+ NORMAL = 0
44
+ MULTI_SELECT = 1
45
+ MULTI_DELETE = 2
46
+
47
+ class Option:
48
+ def __init__(self, obj: Any, sub_string_start: int=0) -> None:
49
+ self.value = obj
50
+ self.sub_string_start = sub_string_start
51
+
41
52
  class Menu:
42
53
  def __init__(self, options: list, label: str, window_size: int=10, multi_select: bool=False) -> None:
43
54
  assert options
@@ -45,21 +56,23 @@ class Menu:
45
56
  assert 1 <= window_size and window_size <= 25
46
57
  window_size = min((len(options)), window_size)
47
58
 
48
- self.options_original = options
49
- self.options_current = copy(options)
59
+ self.options_original = [Option(op) for op in options]
60
+ self.options_current = copy(self.options_original)
50
61
  self.options_selected = []
51
- self.search_indices = []
52
62
  self.search_string = ""
53
63
  self.label = label
54
64
  self.selected_index = 0
55
- self.multi_select = multi_select
56
65
  self.window_top = 0
57
66
  self.window_size_original = window_size
58
67
  self.window_size_current = window_size
68
+ self.help_string_multi_select = "Enter: Select, Ctl+C: Cancel, Ctl\u2192: Done"
69
+ self.help_string_normal = "Enter: Select, Ctl+C: Cancel"
59
70
  if multi_select:
60
- self.help_string = "Enter: Select, Ctl+C: Cancel, Ctl\u2192: Done"
71
+ self.mode = Mode.MULTI_SELECT
72
+ self.help_string = self.help_string_multi_select
61
73
  else:
62
- self.help_string = "Enter: Select, Ctl+C: Cancel"
74
+ self.mode = Mode.NORMAL
75
+ self.help_string = self.help_string_normal
63
76
 
64
77
  def show(self):
65
78
  self.printMenu()
@@ -68,9 +81,10 @@ class Menu:
68
81
  char = self.getChar()
69
82
  if char == SPECIAL_KEY:
70
83
  char = self.getChar()
71
- if char == CTL_RIGHT and self.multi_select:
72
- self.printSelected()
73
- return self.options_selected
84
+ if char == CTL_RIGHT:
85
+ if self.mode == Mode.MULTI_SELECT:
86
+ self.printSelected()
87
+ return self.multiSelectGetValues(self.options_selected)
74
88
  elif 1 < len(self.options_current):
75
89
  # NOTE: Update selected index
76
90
  if char == UP_ARROW:
@@ -101,12 +115,12 @@ class Menu:
101
115
  self.search(self.options_original)
102
116
  something_changed = True
103
117
  elif char == ENTER_KEY and self.options_current:
104
- if self.multi_select:
118
+ if self.mode == Mode.MULTI_SELECT:
105
119
  self.multiSelectAdd()
106
120
  something_changed = True
107
- else:
121
+ elif self.mode == Mode.NORMAL:
108
122
  self.printSelected()
109
- return self.options_current[self.selected_index]
123
+ return self.options_current[self.selected_index].value
110
124
  elif char == CTL_C:
111
125
  self.clearMenu()
112
126
  print("cancelled")
@@ -117,15 +131,13 @@ class Menu:
117
131
  self.printMenu()
118
132
 
119
133
  def search(self, search_list: list) -> None:
120
- found_indices = []
121
134
  found_options = []
122
135
  for o in search_list:
123
- found_i = str(o).lower().find(self.search_string.lower())
136
+ found_i = str(o.value).lower().find(self.search_string.lower())
124
137
  if found_i != -1:
125
- found_indices.append(found_i)
138
+ o.sub_string_start = found_i
126
139
  found_options.append(o)
127
140
  self.options_current = found_options
128
- self.search_indices = found_indices
129
141
  self.resetWindow()
130
142
 
131
143
  def multiSelectAdd(self) -> None:
@@ -135,6 +147,9 @@ class Menu:
135
147
  self.options_selected.append(selected_option)
136
148
  self.resetWindow()
137
149
 
150
+ def multiSelectGetValues(self, options: list[Option]) -> list[Any]:
151
+ return [op.value for op in options]
152
+
138
153
  def getChar(self) -> int:
139
154
  return ord(msvcrt.getch())
140
155
 
@@ -159,8 +174,8 @@ class Menu:
159
174
  def printMenu(self):
160
175
  header = f"{ANSI_BLUE}{self.label}>{ANSI_RESET}{self.search_string}"
161
176
  header_num_lines = 1
162
- if self.multi_select:
163
- header += f"\n{ANSI_GREEN}{len(self.options_selected)} items added!{ANSI_RESET}"
177
+ if self.mode == Mode.MULTI_SELECT:
178
+ header += f"\n{ANSI_GREEN}{len(self.options_selected)} items in list!{ANSI_RESET}"
164
179
  header_num_lines = 2
165
180
  print(header)
166
181
 
@@ -172,19 +187,16 @@ class Menu:
172
187
  self.window_size_current = 1
173
188
  else:
174
189
  for i in range(self.window_top, bottom):
175
- option_to_print = str(self.options_current[i])
176
- if self.search_indices:
177
- highlight_beg = self.search_indices[i]
178
- highlight_end = highlight_beg + len(self.search_string)
179
- opt_beg = option_to_print[0 : highlight_beg]
180
- opt_mid = option_to_print[highlight_beg : highlight_end]
181
- opt_end = option_to_print[highlight_end :]
182
- if i == self.selected_index:
183
- option_to_print = f"{ANSI_HIGHLIGHT}{opt_beg}{ANSI_HIGHLIGHT_SEARCH_STRING}{opt_mid}{ANSI_HIGHLIGHT}{opt_end}{ANSI_RESET}"
184
- else:
185
- option_to_print = f"{opt_beg}{ANSI_MAGENTA}{opt_mid}{ANSI_RESET}{opt_end}"
186
- elif i == self.selected_index:
187
- option_to_print = f"{ANSI_HIGHLIGHT}{option_to_print}{ANSI_RESET}"
190
+ option_to_print = str(self.options_current[i].value)
191
+ highlight_beg = self.options_current[i].sub_string_start
192
+ highlight_end = highlight_beg + len(self.search_string)
193
+ opt_beg = option_to_print[0 : highlight_beg]
194
+ opt_mid = option_to_print[highlight_beg : highlight_end]
195
+ opt_end = option_to_print[highlight_end :]
196
+ if i == self.selected_index:
197
+ option_to_print = f"{ANSI_HIGHLIGHT}{opt_beg}{ANSI_HIGHLIGHT_SEARCH_STRING}{opt_mid}{ANSI_HIGHLIGHT}{opt_end}{ANSI_RESET}"
198
+ else:
199
+ option_to_print = f"{opt_beg}{ANSI_MAGENTA}{opt_mid}{ANSI_RESET}{opt_end}"
188
200
  print(option_to_print)
189
201
 
190
202
  footer = f"{ANSI_YELLOW}{self.help_string}{ANSI_RESET}\n"
@@ -193,13 +205,15 @@ class Menu:
193
205
 
194
206
  def printSelected(self):
195
207
  self.clearMenu()
196
- if self.multi_select:
197
- if len(self.options_selected) <= 3:
198
- print(f"{self.label}> {self.options_selected} ({len(self.options_selected)} items)")
208
+ if self.mode == Mode.MULTI_SELECT:
209
+ if len(self.options_selected) == 0:
210
+ print(f"{self.label}> (0 items) []")
211
+ elif len(self.options_selected) == 1:
212
+ print(f"{self.label}> (1 item) {self.multiSelectGetValues(self.options_selected)}")
199
213
  else:
200
- print(f"{self.label}> [{self.options_selected[0]}, ..., {self.options_selected[-1]}] ({len(self.options_selected)} items)")
214
+ print(f"{self.label}> ({len(self.options_selected)} items) [{self.options_selected[0].value}, ...]")
201
215
  else:
202
- print(f"{self.label}> {self.options_current[self.selected_index]}")
216
+ print(f"{self.label}> {self.options_current[self.selected_index].value}")
203
217
 
204
218
  def makeSelection(options: list[Any], label: str, window_size: int=None, multi_select: bool=False) -> Any:
205
219
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: make_selection
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: Package for interactive command line menu
5
5
  Author-email: Steven Frazee <stevefrazee123@gmail.com>
6
6
  Classifier: License :: OSI Approved :: MIT License
File without changes
File without changes
File without changes