listpick 0.1.14.8__py3-none-any.whl → 0.1.14.10__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 +25 -59
- listpick/ui/input_field.py +101 -105
- listpick/ui/keys.py +4 -2
- listpick/utils/keycodes.py +88 -0
- listpick/utils/user_input.py +104 -0
- {listpick-0.1.14.8.dist-info → listpick-0.1.14.10.dist-info}/METADATA +1 -1
- {listpick-0.1.14.8.dist-info → listpick-0.1.14.10.dist-info}/RECORD +11 -10
- listpick/ui/keycodes.py +0 -70
- {listpick-0.1.14.8.dist-info → listpick-0.1.14.10.dist-info}/WHEEL +0 -0
- {listpick-0.1.14.8.dist-info → listpick-0.1.14.10.dist-info}/entry_points.txt +0 -0
- {listpick-0.1.14.8.dist-info → listpick-0.1.14.10.dist-info}/licenses/LICENSE.txt +0 -0
- {listpick-0.1.14.8.dist-info → listpick-0.1.14.10.dist-info}/top_level.txt +0 -0
listpick/listpick_app.py
CHANGED
|
@@ -40,6 +40,7 @@ from listpick.utils.dump import dump_state, load_state, dump_data
|
|
|
40
40
|
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
|
+
from listpick.utils.user_input import get_char, open_tty
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
try:
|
|
@@ -187,6 +188,8 @@ class Picker:
|
|
|
187
188
|
sheet_index = 0,
|
|
188
189
|
sheet_states = [{}],
|
|
189
190
|
|
|
191
|
+
redraw_screen_accessory: Callable = lambda : None,
|
|
192
|
+
|
|
190
193
|
):
|
|
191
194
|
self.stdscr = stdscr
|
|
192
195
|
self.items = items
|
|
@@ -335,6 +338,7 @@ class Picker:
|
|
|
335
338
|
self.sheet_states = sheet_states
|
|
336
339
|
self.sheets = sheets
|
|
337
340
|
|
|
341
|
+
self.redraw_screen_accessory = redraw_screen_accessory
|
|
338
342
|
self.initialise_picker_state(reset_colours=self.reset_colours)
|
|
339
343
|
|
|
340
344
|
# Note: We have to set the footer after initialising the picker state so that the footer can use the get_function_data method
|
|
@@ -747,6 +751,8 @@ class Picker:
|
|
|
747
751
|
|
|
748
752
|
def draw_screen_(self, indexed_items: list[Tuple[int, list[str]]], highlights: list[dict] = [{}], clear: bool = True) -> None:
|
|
749
753
|
""" Draw Picker screen. """
|
|
754
|
+
|
|
755
|
+
self.redraw_screen_accessory()
|
|
750
756
|
self.logger.debug("Draw screen.")
|
|
751
757
|
|
|
752
758
|
if clear:
|
|
@@ -1236,6 +1242,7 @@ class Picker:
|
|
|
1236
1242
|
"sheets": self.sheets,
|
|
1237
1243
|
"sheet_name": self.sheet_name,
|
|
1238
1244
|
"sheet_states": self.sheet_states,
|
|
1245
|
+
"redraw_screen_accessory": self.redraw_screen_accessory,
|
|
1239
1246
|
}
|
|
1240
1247
|
return function_data
|
|
1241
1248
|
|
|
@@ -1270,6 +1277,7 @@ class Picker:
|
|
|
1270
1277
|
"centre_in_terminal_vertical",
|
|
1271
1278
|
"centre_in_cols",
|
|
1272
1279
|
"centre_in_terminal",
|
|
1280
|
+
"redraw_screen_accessory",
|
|
1273
1281
|
]
|
|
1274
1282
|
|
|
1275
1283
|
for var in variables:
|
|
@@ -1362,7 +1370,6 @@ class Picker:
|
|
|
1362
1370
|
"cancel_is_back": True,
|
|
1363
1371
|
"number_columns": False,
|
|
1364
1372
|
"reset_colours": False,
|
|
1365
|
-
"cell_cursor": False,
|
|
1366
1373
|
}
|
|
1367
1374
|
while True:
|
|
1368
1375
|
h, w = stdscr.getmaxyx()
|
|
@@ -1382,7 +1389,7 @@ class Picker:
|
|
|
1382
1389
|
if s:
|
|
1383
1390
|
return {x: options[x] for x in s}, o, f
|
|
1384
1391
|
return {}, "", f
|
|
1385
|
-
|
|
1392
|
+
|
|
1386
1393
|
|
|
1387
1394
|
|
|
1388
1395
|
def notification(self, stdscr: curses.window, message: str="", title:str="Notification", colours_end: int=0, duration:int=4) -> None:
|
|
@@ -1393,12 +1400,7 @@ class Picker:
|
|
|
1393
1400
|
message_width = notification_width-5
|
|
1394
1401
|
|
|
1395
1402
|
if not message: message = "!!"
|
|
1396
|
-
|
|
1397
|
-
mw = message_width
|
|
1398
|
-
submenu_items = [[message[i*mw:(i+1)*mw]] for i in range(len(message)//mw+1)]
|
|
1399
|
-
elif type(message) != type([]):
|
|
1400
|
-
submenu_items = [[" !!"]]
|
|
1401
|
-
|
|
1403
|
+
submenu_items = [" "+message[i*message_width:(i+1)*message_width] for i in range(len(message)//message_width+1)]
|
|
1402
1404
|
|
|
1403
1405
|
notification_remap_keys = {
|
|
1404
1406
|
curses.KEY_RESIZE: curses.KEY_F5,
|
|
@@ -1408,7 +1410,6 @@ class Picker:
|
|
|
1408
1410
|
h, w = stdscr.getmaxyx()
|
|
1409
1411
|
|
|
1410
1412
|
submenu_win = curses.newwin(notification_height, notification_width, 3, w - (notification_width+4))
|
|
1411
|
-
# submenu_win = self.stdscr.subwin(notification_height, notification_width, 3, w - (notification_width+4))
|
|
1412
1413
|
notification_data = {
|
|
1413
1414
|
"items": submenu_items,
|
|
1414
1415
|
"title": title,
|
|
@@ -1425,11 +1426,6 @@ class Picker:
|
|
|
1425
1426
|
"cancel_is_back": True,
|
|
1426
1427
|
"reset_colours": False,
|
|
1427
1428
|
|
|
1428
|
-
"loaded_files": [],
|
|
1429
|
-
"loaded_file_states": [],
|
|
1430
|
-
"loaded_file": "",
|
|
1431
|
-
"loaded_file_index": 0,
|
|
1432
|
-
"cell_cursor": False,
|
|
1433
1429
|
}
|
|
1434
1430
|
OptionPicker = Picker(submenu_win, **notification_data)
|
|
1435
1431
|
s, o, f = OptionPicker.run()
|
|
@@ -2229,6 +2225,13 @@ class Picker:
|
|
|
2229
2225
|
# Open tty to accept input
|
|
2230
2226
|
tty_fd = open_tty()
|
|
2231
2227
|
|
|
2228
|
+
h, w = self.stdscr.getmaxyx()
|
|
2229
|
+
def terminal_resized(old_w, old_h) -> bool:
|
|
2230
|
+
w, h = os.get_terminal_size()
|
|
2231
|
+
if old_h != h or old_w != w: return True
|
|
2232
|
+
else: return False
|
|
2233
|
+
|
|
2234
|
+
COLS, LINES = os.get_terminal_size()
|
|
2232
2235
|
# Main loop
|
|
2233
2236
|
while True:
|
|
2234
2237
|
# key = self.stdscr.getch()
|
|
@@ -2236,7 +2239,14 @@ class Picker:
|
|
|
2236
2239
|
key = get_char(tty_fd, timeout=0.2)
|
|
2237
2240
|
if key != -1:
|
|
2238
2241
|
self.logger.info(f"key={key}")
|
|
2242
|
+
|
|
2243
|
+
self.term_resize_event = terminal_resized(COLS, LINES)
|
|
2244
|
+
COLS, LINES = os.get_terminal_size()
|
|
2245
|
+
if self.term_resize_event:
|
|
2246
|
+
key = curses.KEY_RESIZE
|
|
2247
|
+
|
|
2239
2248
|
h, w = self.stdscr.getmaxyx()
|
|
2249
|
+
|
|
2240
2250
|
if key in self.disabled_keys: continue
|
|
2241
2251
|
clear_screen=True
|
|
2242
2252
|
|
|
@@ -3091,7 +3101,7 @@ class Picker:
|
|
|
3091
3101
|
self.logger.info(f"key_function opts_select")
|
|
3092
3102
|
s, o, f = self.choose_option(self.stdscr, self.options_list)
|
|
3093
3103
|
if self.user_opts.strip(): self.user_opts += " "
|
|
3094
|
-
self.user_opts += " ".join([x for x in s.values()])
|
|
3104
|
+
self.user_opts += " ".join([x[0] for x in s.values()])
|
|
3095
3105
|
elif self.check_key("notification_toggle", key, self.keys_dict):
|
|
3096
3106
|
self.logger.info(f"key_function notification_toggle")
|
|
3097
3107
|
self.notification(self.stdscr, colours_end=self.colours_end)
|
|
@@ -3580,50 +3590,6 @@ def unrestrict_curses(stdscr: curses.window) -> None:
|
|
|
3580
3590
|
curses.curs_set(False)
|
|
3581
3591
|
|
|
3582
3592
|
|
|
3583
|
-
def open_tty():
|
|
3584
|
-
""" Return a file descriptor for the tty that we are opening"""
|
|
3585
|
-
tty_fd = os.open('/dev/tty', os.O_RDONLY)
|
|
3586
|
-
tty.setraw(tty_fd)
|
|
3587
|
-
return tty_fd
|
|
3588
|
-
|
|
3589
|
-
def get_char(tty_fd, timeout: float = 0.2, secondary: bool = False) -> int:
|
|
3590
|
-
""" Get character from a tty_fd with a timeout. """
|
|
3591
|
-
rlist, _, _ = select.select([tty_fd], [], [], timeout)
|
|
3592
|
-
if rlist:
|
|
3593
|
-
# key = ord(tty_fd.read(1))
|
|
3594
|
-
key = ord(os.read(tty_fd, 1))
|
|
3595
|
-
if not secondary:
|
|
3596
|
-
if key == 27:
|
|
3597
|
-
key2 = get_char(tty_fd, timeout=0.01, secondary=True)
|
|
3598
|
-
key3 = get_char(tty_fd, timeout=0.01, secondary=True)
|
|
3599
|
-
key4 = get_char(tty_fd, timeout=0.01, secondary=True)
|
|
3600
|
-
key5 = get_char(tty_fd, timeout=0.01, secondary=True)
|
|
3601
|
-
if key2 == ord('O') and key3 == ord('B'):
|
|
3602
|
-
key = curses.KEY_DOWN
|
|
3603
|
-
elif key2 == ord('O') and key3 == ord('A'):
|
|
3604
|
-
key = curses.KEY_UP
|
|
3605
|
-
elif key2 == ord('O') and key3 == ord('D'):
|
|
3606
|
-
key = curses.KEY_LEFT
|
|
3607
|
-
elif key2 == ord('O') and key3 == ord('C'):
|
|
3608
|
-
key = curses.KEY_RIGHT
|
|
3609
|
-
elif key2 == ord('[') and key3 == ord('Z'):
|
|
3610
|
-
key = 353
|
|
3611
|
-
elif key2 == ord('O') and key3 == ord('F'):
|
|
3612
|
-
key = curses.KEY_END
|
|
3613
|
-
elif key2 == ord('O') and key3 == ord('H'):
|
|
3614
|
-
key = curses.KEY_HOME
|
|
3615
|
-
elif key2 == ord('[') and key3 == ord('3') and key4 == ord('~'):
|
|
3616
|
-
key = curses.KEY_DC
|
|
3617
|
-
elif key2 == ord('[') and key3 == ord('3') and key4 == ord('~'):
|
|
3618
|
-
key = curses.KEY_DC
|
|
3619
|
-
elif key2 == ord('O') and key3 == ord('P'):
|
|
3620
|
-
key = curses.KEY_F1
|
|
3621
|
-
elif key2 == ord('[') and key3 == ord('1') and key4 == ord('5') and key5 == ord('~'):
|
|
3622
|
-
key = curses.KEY_F5
|
|
3623
|
-
|
|
3624
|
-
else:
|
|
3625
|
-
key = -1
|
|
3626
|
-
return key
|
|
3627
3593
|
|
|
3628
3594
|
def main() -> None:
|
|
3629
3595
|
""" Main function when listpick is executed. Deals with command line arguments and starts a Picker. """
|
listpick/ui/input_field.py
CHANGED
|
@@ -18,22 +18,24 @@ import logging
|
|
|
18
18
|
logger = logging.getLogger('picker_log')
|
|
19
19
|
import select
|
|
20
20
|
import tty
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
21
|
+
from listpick.utils.user_input import get_char, open_tty
|
|
22
|
+
from listpick.utils import keycodes
|
|
23
|
+
|
|
24
|
+
# def open_tty():
|
|
25
|
+
# """ Return a file descriptor for the tty that we are opening"""
|
|
26
|
+
# tty_fd = os.open('/dev/tty', os.O_RDONLY)
|
|
27
|
+
# tty.setraw(tty_fd)
|
|
28
|
+
# return tty_fd
|
|
29
|
+
#
|
|
30
|
+
# def get_char(tty_fd, timeout: float = 0.2) -> int:
|
|
31
|
+
# """ Get character from a tty_fd with a timeout. """
|
|
32
|
+
# rlist, _, _ = select.select([tty_fd], [], [], timeout)
|
|
33
|
+
# if rlist:
|
|
34
|
+
# # key = ord(tty_fd.read(1))
|
|
35
|
+
# key = ord(os.read(tty_fd, 1))
|
|
36
|
+
# else:
|
|
37
|
+
# key = -1
|
|
38
|
+
# return key
|
|
37
39
|
|
|
38
40
|
def input_field(
|
|
39
41
|
stdscr: curses.window,
|
|
@@ -230,100 +232,94 @@ def input_field(
|
|
|
230
232
|
key = get_char(tty_fd, timeout=0.5)
|
|
231
233
|
# key = stdscr.getch()
|
|
232
234
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
for word_separator_char in word_separator_chars:
|
|
247
|
-
tmp_index = search_txt[::-1].find(word_separator_char)
|
|
248
|
-
if tmp_index > -1:
|
|
249
|
-
if index == -1:
|
|
250
|
-
index = tmp_index
|
|
251
|
-
else:
|
|
252
|
-
index = min(index, tmp_index)
|
|
253
|
-
|
|
254
|
-
if index == -1:
|
|
255
|
-
if cursor == 0:
|
|
256
|
-
kill_ring.append(usrtxt)
|
|
257
|
-
usrtxt = ""
|
|
258
|
-
else:
|
|
259
|
-
kill_ring.append(usrtxt[:-(cursor+1)])
|
|
260
|
-
usrtxt = usrtxt[-(cursor+1):]
|
|
261
|
-
cursor = len(usrtxt)
|
|
262
|
-
else:
|
|
263
|
-
if index == 0:
|
|
264
|
-
kill_ring.append(search_txt[-1:])
|
|
265
|
-
usrtxt = search_txt[:-1] + usrtxt[len(search_txt):]
|
|
235
|
+
|
|
236
|
+
if key in [27, 7]: # ESC/ALT key or Ctrl+g
|
|
237
|
+
return "", False
|
|
238
|
+
|
|
239
|
+
elif key == keycodes.META_BS:
|
|
240
|
+
# Delete to backslash or space (word_separator_chars)
|
|
241
|
+
search_txt = usrtxt[:-cursor] if cursor > 0 else usrtxt
|
|
242
|
+
index = -1
|
|
243
|
+
for word_separator_char in word_separator_chars:
|
|
244
|
+
tmp_index = search_txt[::-1].find(word_separator_char)
|
|
245
|
+
if tmp_index > -1:
|
|
246
|
+
if index == -1:
|
|
247
|
+
index = tmp_index
|
|
266
248
|
else:
|
|
267
|
-
|
|
268
|
-
usrtxt = search_txt[:-index] + usrtxt[len(search_txt):]
|
|
249
|
+
index = min(index, tmp_index)
|
|
269
250
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
# Forward word
|
|
275
|
-
search_txt = usrtxt[-cursor:]
|
|
276
|
-
index = -1
|
|
277
|
-
for word_separator_char in word_separator_chars:
|
|
278
|
-
tmp_index = search_txt.find(word_separator_char)
|
|
279
|
-
|
|
280
|
-
if tmp_index > -1:
|
|
281
|
-
if index == -1:
|
|
282
|
-
index = tmp_index
|
|
283
|
-
else:
|
|
284
|
-
index = min(index, tmp_index)
|
|
285
|
-
|
|
286
|
-
if index == -1:
|
|
287
|
-
cursor = 0
|
|
251
|
+
if index == -1:
|
|
252
|
+
if cursor == 0:
|
|
253
|
+
kill_ring.append(usrtxt)
|
|
254
|
+
usrtxt = ""
|
|
288
255
|
else:
|
|
289
|
-
cursor
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
index = -1
|
|
297
|
-
for word_separator_char in word_separator_chars:
|
|
298
|
-
tmp_index = search_txt[::-1].find(word_separator_char)
|
|
299
|
-
|
|
300
|
-
if tmp_index == 0:
|
|
301
|
-
tmp_index = search_txt[:-1][::-1].find(word_separator_char)
|
|
302
|
-
|
|
303
|
-
if tmp_index > -1:
|
|
304
|
-
if index == -1:
|
|
305
|
-
index = tmp_index
|
|
306
|
-
else:
|
|
307
|
-
index = min(index, tmp_index)
|
|
308
|
-
|
|
309
|
-
if index == -1:
|
|
310
|
-
cursor = len(usrtxt)
|
|
256
|
+
kill_ring.append(usrtxt[:-(cursor+1)])
|
|
257
|
+
usrtxt = usrtxt[-(cursor+1):]
|
|
258
|
+
cursor = len(usrtxt)
|
|
259
|
+
else:
|
|
260
|
+
if index == 0:
|
|
261
|
+
kill_ring.append(search_txt[-1:])
|
|
262
|
+
usrtxt = search_txt[:-1] + usrtxt[len(search_txt):]
|
|
311
263
|
else:
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
264
|
+
kill_ring.append(search_txt[-index:])
|
|
265
|
+
usrtxt = search_txt[:-index] + usrtxt[len(search_txt):]
|
|
266
|
+
|
|
267
|
+
potential_path = usrtxt
|
|
268
|
+
kill_ring_active = False
|
|
269
|
+
|
|
270
|
+
elif key == keycodes.META_f:
|
|
271
|
+
# Forward word
|
|
272
|
+
search_txt = usrtxt[-cursor:]
|
|
273
|
+
index = -1
|
|
274
|
+
for word_separator_char in word_separator_chars:
|
|
275
|
+
tmp_index = search_txt.find(word_separator_char)
|
|
276
|
+
|
|
277
|
+
if tmp_index > -1:
|
|
278
|
+
if index == -1:
|
|
279
|
+
index = tmp_index
|
|
280
|
+
else:
|
|
281
|
+
index = min(index, tmp_index)
|
|
282
|
+
|
|
283
|
+
if index == -1:
|
|
284
|
+
cursor = 0
|
|
285
|
+
else:
|
|
286
|
+
cursor -= index + 1
|
|
287
|
+
cursor = max(cursor, 0)
|
|
288
|
+
kill_ring_active = False
|
|
289
|
+
|
|
290
|
+
elif key == keycodes.META_b:
|
|
291
|
+
# Backwards word
|
|
292
|
+
search_txt = usrtxt[:-cursor] if cursor > 0 else usrtxt
|
|
293
|
+
index = -1
|
|
294
|
+
for word_separator_char in word_separator_chars:
|
|
295
|
+
tmp_index = search_txt[::-1].find(word_separator_char)
|
|
296
|
+
|
|
297
|
+
if tmp_index == 0:
|
|
298
|
+
tmp_index = search_txt[:-1][::-1].find(word_separator_char)
|
|
299
|
+
|
|
300
|
+
if tmp_index > -1:
|
|
301
|
+
if index == -1:
|
|
302
|
+
index = tmp_index
|
|
322
303
|
else:
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
304
|
+
index = min(index, tmp_index)
|
|
305
|
+
|
|
306
|
+
if index == -1:
|
|
307
|
+
cursor = len(usrtxt)
|
|
308
|
+
else:
|
|
309
|
+
cursor += index + 1
|
|
310
|
+
kill_ring_active = False
|
|
311
|
+
|
|
312
|
+
elif key == keycodes.META_y:
|
|
313
|
+
# Kill ring
|
|
314
|
+
prev_kill_ring_index = kill_ring_index
|
|
315
|
+
kill_ring_index = (kill_ring_index + 1)%len(kill_ring)
|
|
316
|
+
if kill_ring_active and len(kill_ring):
|
|
317
|
+
if cursor == 0:
|
|
318
|
+
usrtxt = usrtxt[:-len(kill_ring[prev_kill_ring_index])]
|
|
319
|
+
usrtxt += kill_ring[kill_ring_index]
|
|
320
|
+
else:
|
|
321
|
+
usrtxt = usrtxt[-cursor:-(cursor+len(kill_ring[prev_kill_ring_index]))]
|
|
322
|
+
usrtxt = usrtxt[:-cursor] + kill_ring[kill_ring_index] + usrtxt[-cursor:]
|
|
327
323
|
|
|
328
324
|
elif key == 3: # ctrl+c
|
|
329
325
|
# Immediate exit
|
listpick/ui/keys.py
CHANGED
|
@@ -9,6 +9,7 @@ License: MIT
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
import curses
|
|
12
|
+
from listpick.utils import keycodes
|
|
12
13
|
|
|
13
14
|
picker_keys = {
|
|
14
15
|
"refresh": [curses.KEY_F5],
|
|
@@ -25,8 +26,8 @@ picker_keys = {
|
|
|
25
26
|
"page_down": [curses.KEY_NPAGE, 6], # Ctrl+f
|
|
26
27
|
"cursor_bottom": [ord('G'), curses.KEY_END],
|
|
27
28
|
"cursor_top": [ord('g'), curses.KEY_HOME],
|
|
28
|
-
"five_up": [ord('K')],
|
|
29
|
-
"five_down": [ord('J')],
|
|
29
|
+
"five_up": [ord('K'), keycodes.META_k],
|
|
30
|
+
"five_down": [ord('J'), keycodes.META_j],
|
|
30
31
|
"toggle_select": [ord(' ')],
|
|
31
32
|
"select_all": [ord('m'), 1], # Ctrl-a
|
|
32
33
|
"select_none": [ord('M'), 18], # Ctrl-r
|
|
@@ -135,6 +136,7 @@ notification_keys = {
|
|
|
135
136
|
"five_up": [ord('K')],
|
|
136
137
|
"five_down": [ord('J')],
|
|
137
138
|
"redraw_screen": [12], # Ctrl-l
|
|
139
|
+
"refresh": [curses.KEY_F5, curses.KEY_RESIZE],
|
|
138
140
|
}
|
|
139
141
|
|
|
140
142
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Set a base value to ensure that we have no collisions with any unicode characters
|
|
2
|
+
BASE_VALUE = 2**32
|
|
3
|
+
|
|
4
|
+
# Define constants for alt+a to alt+z
|
|
5
|
+
META_A = BASE_VALUE + 1000
|
|
6
|
+
META_B = BASE_VALUE + 1001
|
|
7
|
+
META_C = BASE_VALUE + 1002
|
|
8
|
+
META_D = BASE_VALUE + 1003
|
|
9
|
+
META_E = BASE_VALUE + 1004
|
|
10
|
+
META_F = BASE_VALUE + 1005
|
|
11
|
+
META_G = BASE_VALUE + 1006
|
|
12
|
+
META_H = BASE_VALUE + 1007
|
|
13
|
+
META_I = BASE_VALUE + 1008
|
|
14
|
+
META_J = BASE_VALUE + 1009
|
|
15
|
+
META_K = BASE_VALUE + 1010
|
|
16
|
+
META_L = BASE_VALUE + 1011
|
|
17
|
+
META_M = BASE_VALUE + 1012
|
|
18
|
+
META_N = BASE_VALUE + 1013
|
|
19
|
+
META_O = BASE_VALUE + 1014
|
|
20
|
+
META_P = BASE_VALUE + 1015
|
|
21
|
+
META_Q = BASE_VALUE + 1016
|
|
22
|
+
META_R = BASE_VALUE + 1017
|
|
23
|
+
META_S = BASE_VALUE + 1018
|
|
24
|
+
META_T = BASE_VALUE + 1019
|
|
25
|
+
META_U = BASE_VALUE + 1020
|
|
26
|
+
META_V = BASE_VALUE + 1021
|
|
27
|
+
META_W = BASE_VALUE + 1022
|
|
28
|
+
META_X = BASE_VALUE + 1023
|
|
29
|
+
META_Y = BASE_VALUE + 1024
|
|
30
|
+
META_Z = BASE_VALUE + 1025
|
|
31
|
+
|
|
32
|
+
# Define constants for alt+A to alt+Z (using uppercase)
|
|
33
|
+
META_a = BASE_VALUE + 1050
|
|
34
|
+
META_b = BASE_VALUE + 1051
|
|
35
|
+
META_c = BASE_VALUE + 1052
|
|
36
|
+
META_d = BASE_VALUE + 1053
|
|
37
|
+
META_e = BASE_VALUE + 1054
|
|
38
|
+
META_f = BASE_VALUE + 1055
|
|
39
|
+
META_g = BASE_VALUE + 1056
|
|
40
|
+
META_h = BASE_VALUE + 1057
|
|
41
|
+
META_i = BASE_VALUE + 1058
|
|
42
|
+
META_j = BASE_VALUE + 1059
|
|
43
|
+
META_k = BASE_VALUE + 1060
|
|
44
|
+
META_l = BASE_VALUE + 1061
|
|
45
|
+
META_m = BASE_VALUE + 1062
|
|
46
|
+
META_n = BASE_VALUE + 1063
|
|
47
|
+
META_o = BASE_VALUE + 1064
|
|
48
|
+
META_p = BASE_VALUE + 1065
|
|
49
|
+
META_q = BASE_VALUE + 1066
|
|
50
|
+
META_r = BASE_VALUE + 1067
|
|
51
|
+
META_s = BASE_VALUE + 1068
|
|
52
|
+
META_t = BASE_VALUE + 1069
|
|
53
|
+
META_u = BASE_VALUE + 1070
|
|
54
|
+
META_v = BASE_VALUE + 1071
|
|
55
|
+
META_w = BASE_VALUE + 1072
|
|
56
|
+
META_x = BASE_VALUE + 1073
|
|
57
|
+
META_y = BASE_VALUE + 1074
|
|
58
|
+
META_z = BASE_VALUE + 1075
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
META_0 = BASE_VALUE + 1090
|
|
62
|
+
META_1 = BASE_VALUE + 1091
|
|
63
|
+
META_2 = BASE_VALUE + 1092
|
|
64
|
+
META_3 = BASE_VALUE + 1093
|
|
65
|
+
META_4 = BASE_VALUE + 1094
|
|
66
|
+
META_5 = BASE_VALUE + 1095
|
|
67
|
+
META_6 = BASE_VALUE + 1096
|
|
68
|
+
META_7 = BASE_VALUE + 1097
|
|
69
|
+
META_8 = BASE_VALUE + 1098
|
|
70
|
+
META_9 = BASE_VALUE + 1099
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
META_BS = BASE_VALUE + 1100
|
|
74
|
+
|
|
75
|
+
# Dictionary to map character to its constant value
|
|
76
|
+
META_KEY_MAP = {
|
|
77
|
+
'a': META_a, 'b': META_b, 'c': META_c, 'd': META_d, 'e': META_e,
|
|
78
|
+
'f': META_f, 'g': META_g, 'h': META_h, 'i': META_i, 'j': META_j,
|
|
79
|
+
'k': META_k, 'l': META_l, 'm': META_m, 'n': META_n, 'o': META_o,
|
|
80
|
+
'p': META_p, 'q': META_q, 'r': META_r, 's': META_s, 't': META_t,
|
|
81
|
+
'u': META_u, 'v': META_v, 'w': META_w, 'x': META_x, 'y': META_y,
|
|
82
|
+
'z': META_z, 'A': META_A, 'B': META_B, 'C': META_C, 'D': META_D,
|
|
83
|
+
'E': META_E, 'F': META_F, 'G': META_G, 'H': META_H, 'I': META_I,
|
|
84
|
+
'J': META_J, 'K': META_K, 'L': META_L, 'M': META_M, 'N': META_N,
|
|
85
|
+
'O': META_O, 'P': META_P, 'Q': META_Q, 'R': META_R, 'S': META_S,
|
|
86
|
+
'T': META_T, 'U': META_U, 'V': META_V, 'W': META_W, 'X': META_X,
|
|
87
|
+
'Y': META_Y, 'Z': META_Z
|
|
88
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from listpick.utils import keycodes
|
|
2
|
+
import os, tty, select, curses
|
|
3
|
+
|
|
4
|
+
def open_tty():
|
|
5
|
+
""" Return a file descriptor for the tty that we are opening"""
|
|
6
|
+
tty_fd = os.open('/dev/tty', os.O_RDONLY)
|
|
7
|
+
tty.setraw(tty_fd)
|
|
8
|
+
return tty_fd
|
|
9
|
+
|
|
10
|
+
def get_char(tty_fd, timeout: float = 0.2, secondary: bool = False) -> int:
|
|
11
|
+
""" Get character from a tty_fd with a timeout. """
|
|
12
|
+
rlist, _, _ = select.select([tty_fd], [], [], timeout)
|
|
13
|
+
if rlist:
|
|
14
|
+
# key = ord(tty_fd.read(1))
|
|
15
|
+
key = ord(os.read(tty_fd, 1))
|
|
16
|
+
if not secondary:
|
|
17
|
+
if key == 27:
|
|
18
|
+
key2 = get_char(tty_fd, timeout=0.01, secondary=True)
|
|
19
|
+
key3 = get_char(tty_fd, timeout=0.01, secondary=True)
|
|
20
|
+
key4 = get_char(tty_fd, timeout=0.01, secondary=True)
|
|
21
|
+
key5 = get_char(tty_fd, timeout=0.01, secondary=True)
|
|
22
|
+
key6 = get_char(tty_fd, timeout=0.01, secondary=True)
|
|
23
|
+
|
|
24
|
+
keys = [key2, key3, key4, key5, key6]
|
|
25
|
+
|
|
26
|
+
key_str = "".join([chr(k) for k in keys if k != -1])
|
|
27
|
+
|
|
28
|
+
## Arrow Keys
|
|
29
|
+
if key2 == ord('O') and key3 == ord('B'):
|
|
30
|
+
key = curses.KEY_DOWN
|
|
31
|
+
elif key2 == ord('O') and key3 == ord('A'):
|
|
32
|
+
key = curses.KEY_UP
|
|
33
|
+
elif key2 == ord('O') and key3 == ord('D'):
|
|
34
|
+
key = curses.KEY_LEFT
|
|
35
|
+
elif key2 == ord('O') and key3 == ord('C'):
|
|
36
|
+
key = curses.KEY_RIGHT
|
|
37
|
+
|
|
38
|
+
## Shift+ Tab
|
|
39
|
+
elif key2 == ord('[') and key3 == ord('Z'):
|
|
40
|
+
key = 353
|
|
41
|
+
|
|
42
|
+
## Home, End, Pgup, Pgdn
|
|
43
|
+
elif key2 == ord('O') and key3 == ord('F'):
|
|
44
|
+
key = curses.KEY_END
|
|
45
|
+
elif key2 == ord('O') and key3 == ord('H'):
|
|
46
|
+
key = curses.KEY_HOME
|
|
47
|
+
elif key2 == ord('[') and key3 == ord('6') and key4 == ord("~"):
|
|
48
|
+
key = curses.KEY_NPAGE
|
|
49
|
+
elif key2 == ord('[') and key3 == ord('5') and key4 == ord("~"):
|
|
50
|
+
key = curses.KEY_PPAGE
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Delete key
|
|
54
|
+
elif key_str == "[3~": ## Delete
|
|
55
|
+
key = curses.KEY_DC
|
|
56
|
+
elif key_str == "[3;2~": ## Shift+Delete
|
|
57
|
+
key = 383
|
|
58
|
+
|
|
59
|
+
## Function Keys
|
|
60
|
+
elif key2 == ord('O') and key3 == ord('P'):
|
|
61
|
+
key = curses.KEY_F1
|
|
62
|
+
elif key_str == "OQ":
|
|
63
|
+
key = curses.KEY_F2
|
|
64
|
+
elif key_str == "OR":
|
|
65
|
+
key = curses.KEY_F3
|
|
66
|
+
elif key_str == "OS":
|
|
67
|
+
key = curses.KEY_F4
|
|
68
|
+
elif key_str == "[15~":
|
|
69
|
+
key = curses.KEY_F5
|
|
70
|
+
elif key_str == "[17~":
|
|
71
|
+
key = curses.KEY_F6
|
|
72
|
+
elif key_str == "[17~":
|
|
73
|
+
key = curses.KEY_F7
|
|
74
|
+
elif key_str == "[19~":
|
|
75
|
+
key = curses.KEY_F8
|
|
76
|
+
elif key_str == "[20~":
|
|
77
|
+
key = curses.KEY_F9
|
|
78
|
+
elif key_str == "[21~":
|
|
79
|
+
key = curses.KEY_F10
|
|
80
|
+
elif key_str == "[23~":
|
|
81
|
+
key = curses.KEY_F11
|
|
82
|
+
elif key_str == "[24~":
|
|
83
|
+
key = curses.KEY_F12
|
|
84
|
+
|
|
85
|
+
## Alt+KEY
|
|
86
|
+
elif key2 >= ord('a') and key2 <= ord('z') and key3 == -1: ## Alt+[a-zA-Z]
|
|
87
|
+
key = keycodes.META_a + (key2 - ord('a'))
|
|
88
|
+
elif key2 >= ord('A') and key2 <= ord('Z') and key3 == -1: ## Alt+[a-zA-Z]
|
|
89
|
+
key = keycodes.META_A + (key2 - ord('A'))
|
|
90
|
+
elif key2 == ord('0') and key3 == -1: ## Alt+0
|
|
91
|
+
key = keycodes.META_0
|
|
92
|
+
elif key2 >= ord('1') and key2 <= ord('9') and key3 == -1: ## Alt+1-9
|
|
93
|
+
key = keycodes.META_1 + (key2 - ord('1'))
|
|
94
|
+
elif key2 == 127: ## Alt+BS
|
|
95
|
+
key = keycodes.META_BS
|
|
96
|
+
|
|
97
|
+
# If it is an unknown key with an escape sequence then return -1.
|
|
98
|
+
elif key2 != -1:
|
|
99
|
+
key = -1
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
else:
|
|
103
|
+
key = -1
|
|
104
|
+
return key
|
|
@@ -1,13 +1,12 @@
|
|
|
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=SL9lgTIoTYHi3fcs01HFKBoCnxEUMHPkZHxW_nuCFxI,187280
|
|
4
4
|
listpick/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
listpick/ui/build_help.py,sha256=8QtsRosIE2IMagRc_remzmwSWpCurFgLenLL7w1ly94,8949
|
|
6
6
|
listpick/ui/footer.py,sha256=ZM5OWCxOZqy5RG6tFTe1ipvu9PRu6Gh3JCA8KXBR_Wc,15004
|
|
7
7
|
listpick/ui/help_screen.py,sha256=zbfGIgb-IXtATpl4_Sx7nPbsnRXZ7eiMYlCKGS9EFmw,5608
|
|
8
|
-
listpick/ui/input_field.py,sha256=
|
|
9
|
-
listpick/ui/
|
|
10
|
-
listpick/ui/keys.py,sha256=C9wG_VPhaXq_c2bREBGKhd4Tb-AKqqOgub7y4W8xQmI,13182
|
|
8
|
+
listpick/ui/input_field.py,sha256=ylf3fiLXdAD4pueHWfzIrlwaRb9f5zm8f1UGkEPBxgM,30539
|
|
9
|
+
listpick/ui/keys.py,sha256=7ZhJfsSatpk-jwfXj_FvzgQsQdUoF7JkD5Mniu9XZ0o,13328
|
|
11
10
|
listpick/ui/pane_stuff.py,sha256=7GXa4UnV_7YmBv-baRi5moN51wYcuS4p0odl5C3m0Tc,169
|
|
12
11
|
listpick/ui/picker_colours.py,sha256=FLOzvkq83orrN2bL0Mw-6RugWOZyuwUjQCrUFMUnKGY,11563
|
|
13
12
|
listpick/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -16,6 +15,7 @@ listpick/utils/config.py,sha256=MEnAZg2Rhfl38XofEIN0uoVAOY7I0ftc79Evk3fOiVw,1654
|
|
|
16
15
|
listpick/utils/dump.py,sha256=60YVIMNtBoYvWhmzfTJOsNGcetOvcCB3_T7yv-bYTPQ,3838
|
|
17
16
|
listpick/utils/filtering.py,sha256=uS9sW0inmFvq0cIrwRC1BfuP8kjAD5IWWtls4jGB-70,1199
|
|
18
17
|
listpick/utils/generate_data.py,sha256=7sv6JRhk0-Gcj4kOlkzx4qPNBJZ-GFWg9vM77GktzpI,3073
|
|
18
|
+
listpick/utils/keycodes.py,sha256=ZGkw1-4szxPnP81wj80r92L6_neIOlBBjQltEieCwnk,2696
|
|
19
19
|
listpick/utils/options_selectors.py,sha256=Vbv4jRkUsSPs7g-EQAv9Q0nhYy6Z4sFsJqMjUIe1oeQ,2814
|
|
20
20
|
listpick/utils/paste_operations.py,sha256=7wDXLPlxUgA3CA99gwsm47juWGO2YQ9EJghW06yo9vI,1242
|
|
21
21
|
listpick/utils/picker_log.py,sha256=SW6GmjxpI7YrSf72fSr4O8Ux0fY_OzaSXUgTFdz6Xo4,805
|
|
@@ -23,10 +23,11 @@ listpick/utils/search_and_filter_utils.py,sha256=XxGfkyDVXO9OAKcftPat8IReMTFIuTH
|
|
|
23
23
|
listpick/utils/searching.py,sha256=Xk5UIqamNHL2L90z3ACB_Giqdpi9iRKoAJ6pKaqaD7Q,3093
|
|
24
24
|
listpick/utils/sorting.py,sha256=WZZiVlVA3Zkcpwji3U5SNFlQ14zVEk3cZJtQirBkecQ,5329
|
|
25
25
|
listpick/utils/table_to_list_of_lists.py,sha256=XBj7eGBDF15BRME-swnoXyOfZWxXCxrXp0pzsBfcJ5g,12224
|
|
26
|
+
listpick/utils/user_input.py,sha256=oyJZPAwA7UGAclPhdPL44tKnPIVNHWhX-tZEnCdBKC0,4318
|
|
26
27
|
listpick/utils/utils.py,sha256=McOl9uT3jh7l4TIWeSd8ZGjK_e7r0YZF0Gl20yI6fl0,13873
|
|
27
|
-
listpick-0.1.14.
|
|
28
|
-
listpick-0.1.14.
|
|
29
|
-
listpick-0.1.14.
|
|
30
|
-
listpick-0.1.14.
|
|
31
|
-
listpick-0.1.14.
|
|
32
|
-
listpick-0.1.14.
|
|
28
|
+
listpick-0.1.14.10.dist-info/licenses/LICENSE.txt,sha256=2mP-MRHJptADDNE9VInMNg1tE-C6Qv93Z4CCQKrpg9w,1061
|
|
29
|
+
listpick-0.1.14.10.dist-info/METADATA,sha256=JBhvFd-3BZN7u_19PRPeNos_bXLzEdpAwp5tbUH0_Q8,8091
|
|
30
|
+
listpick-0.1.14.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
31
|
+
listpick-0.1.14.10.dist-info/entry_points.txt,sha256=-QCf_BKIkUz35Y9nkYpjZWs2Qg0KfRna2PAs5DnF6BE,43
|
|
32
|
+
listpick-0.1.14.10.dist-info/top_level.txt,sha256=5mtsGEz86rz3qQDe0D463gGjAfSp6A3EWg4J4AGYr-Q,9
|
|
33
|
+
listpick-0.1.14.10.dist-info/RECORD,,
|
listpick/ui/keycodes.py
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
# Define constants for alt+a to alt+z
|
|
2
|
-
META_A = 1000
|
|
3
|
-
META_B = 1001
|
|
4
|
-
META_C = 1002
|
|
5
|
-
META_D = 1003
|
|
6
|
-
META_E = 1004
|
|
7
|
-
META_F = 1005
|
|
8
|
-
META_G = 1006
|
|
9
|
-
META_H = 1007
|
|
10
|
-
META_I = 1008
|
|
11
|
-
META_J = 1009
|
|
12
|
-
META_K = 1010
|
|
13
|
-
META_L = 1011
|
|
14
|
-
META_M = 1012
|
|
15
|
-
META_N = 1013
|
|
16
|
-
META_O = 1014
|
|
17
|
-
META_P = 1015
|
|
18
|
-
META_Q = 1016
|
|
19
|
-
META_R = 1017
|
|
20
|
-
META_S = 1018
|
|
21
|
-
META_T = 1019
|
|
22
|
-
META_U = 1020
|
|
23
|
-
META_V = 1021
|
|
24
|
-
META_W = 1022
|
|
25
|
-
META_X = 1023
|
|
26
|
-
META_Y = 1024
|
|
27
|
-
META_Z = 1025
|
|
28
|
-
|
|
29
|
-
# Define constants for alt+A to alt+Z (using uppercase)
|
|
30
|
-
META_a = 1050
|
|
31
|
-
META_b = 1051
|
|
32
|
-
META_c = 1052
|
|
33
|
-
META_d = 1053
|
|
34
|
-
META_e = 1054
|
|
35
|
-
META_f = 1055
|
|
36
|
-
META_g = 1056
|
|
37
|
-
META_h = 1057
|
|
38
|
-
META_i = 1058
|
|
39
|
-
META_j = 1059
|
|
40
|
-
META_k = 1060
|
|
41
|
-
META_l = 1061
|
|
42
|
-
META_m = 1062
|
|
43
|
-
META_n = 1063
|
|
44
|
-
META_o = 1064
|
|
45
|
-
META_p = 1065
|
|
46
|
-
META_q = 1066
|
|
47
|
-
META_r = 1067
|
|
48
|
-
META_s = 1068
|
|
49
|
-
META_t = 1069
|
|
50
|
-
META_u = 1070
|
|
51
|
-
META_v = 1071
|
|
52
|
-
META_w = 1072
|
|
53
|
-
META_x = 1073
|
|
54
|
-
META_y = 1074
|
|
55
|
-
META_z = 1075
|
|
56
|
-
|
|
57
|
-
# Dictionary to map character to its constant value
|
|
58
|
-
META_KEY_MAP = {
|
|
59
|
-
'a': META_a, 'b': META_b, 'c': META_c, 'd': META_d, 'e': META_e,
|
|
60
|
-
'f': META_f, 'g': META_g, 'h': META_h, 'i': META_i, 'j': META_j,
|
|
61
|
-
'k': META_k, 'l': META_l, 'm': META_m, 'n': META_n, 'o': META_o,
|
|
62
|
-
'p': META_p, 'q': META_q, 'r': META_r, 's': META_s, 't': META_t,
|
|
63
|
-
'u': META_u, 'v': META_v, 'w': META_w, 'x': META_x, 'y': META_y,
|
|
64
|
-
'z': META_z, 'A': META_A, 'B': META_B, 'C': META_C, 'D': META_D,
|
|
65
|
-
'E': META_E, 'F': META_F, 'G': META_G, 'H': META_H, 'I': META_I,
|
|
66
|
-
'J': META_J, 'K': META_K, 'L': META_L, 'M': META_M, 'N': META_N,
|
|
67
|
-
'O': META_O, 'P': META_P, 'Q': META_Q, 'R': META_R, 'S': META_S,
|
|
68
|
-
'T': META_T, 'U': META_U, 'V': META_V, 'W': META_W, 'X': META_X,
|
|
69
|
-
'Y': META_Y, 'Z': META_Z
|
|
70
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|