listpick 0.1.15.19__py3-none-any.whl → 0.1.16.17__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.
listpick/pane/get_data.py CHANGED
@@ -8,6 +8,8 @@ Author: GrimAndGreedy
8
8
  License: MIT
9
9
  """
10
10
 
11
+ from listpick.pane.pane_utils import get_file_attributes
12
+
11
13
  def data_refresh_randint_by_row(data, state):
12
14
  """
13
15
  Add a random number to the data if row id is the same.
@@ -93,3 +95,21 @@ def get_dl(data, state):
93
95
  data[0].append(data[0][-1]+1)
94
96
  data[1].append(dl)
95
97
  return data
98
+
99
+
100
+ def update_file_attributes(data, state):
101
+ """
102
+ Get file attributes
103
+
104
+ data[0]: ["size: {}", filetype: {}, last modified: {}]
105
+ ]
106
+ data[1]: id
107
+ """
108
+ if state["indexed_items"]:
109
+ # id = state["indexed_items"][state["cursor_pos"]][1][state["id_column"]]
110
+ id = state["indexed_items"][state["cursor_pos"]][1][0]
111
+ else:
112
+ return [[], -1]
113
+ return [get_file_attributes(id), id]
114
+
115
+
@@ -0,0 +1,198 @@
1
+ #!/bin/python
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ pane_functions.py
5
+ Functions which are run by a listpick Picker to display data in a pane.
6
+
7
+ Author: GrimAndGreedy
8
+ License: MIT
9
+ """
10
+
11
+ import curses
12
+ import os
13
+ from listpick.pane.pane_utils import get_file_attributes, get_graph_string, escape_ansi
14
+ from listpick.pane.get_data import update_file_attributes
15
+
16
+ def left_start_pane(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
17
+ """
18
+ Display file attributes in right pane.
19
+ """
20
+ if test: return True
21
+
22
+ # Title
23
+ for i in range(h):
24
+ s = '*'*w
25
+ stdscr.addstr(y+i, x, s)
26
+
27
+
28
+ stdscr.addstr(y, x, "+")
29
+ stdscr.addstr(y+h-1, x, "+")
30
+ stdscr.addstr(y, x+w-1, "+")
31
+ stdscr.addstr(y+h-1, x+w-1, "+")
32
+
33
+
34
+ stdscr.addstr(y+1, x, f"{w},{h}")
35
+
36
+ return []
37
+
38
+
39
+ def left_split_file_attributes(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
40
+ """
41
+ Display file attributes in right pane.
42
+ """
43
+ if test: return True
44
+
45
+ # Title
46
+ title = "File attributes"
47
+ if len(title) < w: title = f"{title:^{w}}"
48
+ stdscr.addstr(y, x,title[:w], curses.color_pair(state["colours_start"]+4) | curses.A_BOLD)
49
+
50
+ # Separator
51
+ for j in range(h):
52
+ stdscr.addstr(j+y, x+w-1, ' ', curses.color_pair(state["colours_start"]+16))
53
+
54
+ # Display pane count
55
+ pane_count = len(state["right_panes"])
56
+ pane_index = state["right_pane_index"]
57
+ if pane_count > 1:
58
+ s = f" {pane_index+1}/{pane_count} "
59
+ stdscr.addstr(y+h-1, x, s, curses.color_pair(state["colours_start"]+20))
60
+
61
+ # Filename/cursor cell value
62
+ stdscr.addstr(y+2, x+2, cell[:w-3])
63
+
64
+ attributes = get_file_attributes(cell)
65
+ for i, attr in enumerate(attributes):
66
+ stdscr.addstr(y+3+i, x+4, attr[:w-5])
67
+
68
+ return []
69
+
70
+
71
+ def left_split_file_attributes_dynamic(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
72
+ """
73
+ Display file attributes in right pane.
74
+ """
75
+ if test: return True
76
+
77
+ # Title
78
+ title = "File attributes"
79
+ if len(title) < w: title = f"{title:^{w}}"
80
+ stdscr.addstr(y, x,title[:w], curses.color_pair(state["colours_start"]+4) | curses.A_BOLD)
81
+
82
+ # Separator
83
+ for j in range(h):
84
+ stdscr.addstr(j+y, x+w-1, ' ', curses.color_pair(state["colours_start"]+16))
85
+
86
+ # Display pane count
87
+ pane_count = len(state["right_panes"])
88
+ pane_index = state["right_pane_index"]
89
+ if pane_count > 1:
90
+ s = f" {pane_index+1}/{pane_count} "
91
+ stdscr.addstr(y+h-1, x, s, curses.color_pair(state["colours_start"]+20))
92
+
93
+ if len(state["indexed_items"]) == 0:
94
+ return []
95
+
96
+ # Filename/cursor cell value
97
+ stdscr.addstr(y+2, x+2, cell[:w-3])
98
+
99
+ # If the cursor-hovered file is different then reload the data
100
+ if data[1] != cell:
101
+ data[:] = update_file_attributes(data, state)
102
+
103
+ # attributes = get_file_attributes(cell)
104
+ if len(data) == 0: return []
105
+ attributes = data[0]
106
+ for i, attr in enumerate(attributes):
107
+ stdscr.addstr(y+3+i, x+4, attr[:w-5])
108
+
109
+ return []
110
+
111
+ def left_split_graph(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
112
+ """
113
+ Display a graph of the data in right pane.
114
+
115
+ data[0] = x_vals
116
+ data[1] = y_vals
117
+ data[2] = id
118
+ """
119
+ if test: return True
120
+
121
+ # Title
122
+ title = "Graph"
123
+ if len(title) < w: title = f"{title:^{w}}"
124
+ stdscr.addstr(y, x,title[:w], curses.color_pair(state["colours_start"]+4) | curses.A_BOLD)
125
+
126
+ # Separator
127
+ for j in range(h):
128
+ stdscr.addstr(j+y, x+w-1, ' ', curses.color_pair(state["colours_start"]+16))
129
+
130
+
131
+ # Display pane count
132
+ pane_count = len(state["right_panes"])
133
+ pane_index = state["right_pane_index"]
134
+ if pane_count > 1:
135
+ s = f" {pane_index+1}/{pane_count} "
136
+ stdscr.addstr(y+h-1, x, s, curses.color_pair(state["colours_start"]+20))
137
+
138
+ try:
139
+ import plotille as plt
140
+ except:
141
+ s = f"No module named 'plotille'"
142
+ stdscr.addstr(y+2, x+1, s[:w-2])
143
+ return None
144
+
145
+
146
+
147
+ # x_vals, y_vals = list(range(100)), [x**2 for x in range(100)]
148
+ if data in [[], {}, None]:
149
+ return None
150
+ x_vals, y_vals = data[0], data[1]
151
+ graph_str = get_graph_string(x_vals, y_vals, width=w-3-10, height=h-3)
152
+ for i, s in enumerate(graph_str.split("\n")):
153
+ s = escape_ansi(s)
154
+ stdscr.addstr(y+2+i, x+1, s[:w-2])
155
+
156
+ return []
157
+
158
+
159
+
160
+
161
+ def left_split_display_list(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
162
+ """
163
+ data[0]:str = title
164
+ data[1]:list[str] = list of strings to display
165
+ """
166
+ if test: return True
167
+
168
+ # Title
169
+ title = data[0]
170
+ if len(title) < w: title = f"{title:^{w}}"
171
+ stdscr.addstr(y, x,title[:w], curses.color_pair(state["colours_start"]+4) | curses.A_BOLD)
172
+
173
+ # Separator
174
+ for j in range(h):
175
+ stdscr.addstr(j+y, x+w-1, ' ', curses.color_pair(state["colours_start"]+16))
176
+
177
+
178
+ # Display pane count
179
+ pane_count = len(state["right_panes"])
180
+ pane_index = state["right_pane_index"]
181
+ if pane_count > 1:
182
+ s = f" {pane_index+1}/{pane_count} "
183
+ stdscr.addstr(y+h-1, x, s, curses.color_pair(state["colours_start"]+20))
184
+
185
+ if data in [[], {}, None]:
186
+ return None
187
+
188
+ items = data[1]
189
+ number_to_display = min(len(items), h-3)
190
+ for i in range(number_to_display):
191
+ s = items[i]
192
+ stdscr.addstr(y+1+i, x+2, s[:w-2])
193
+
194
+ if number_to_display < len(items):
195
+ stdscr.addstr(y+1+number_to_display, x+2, f" ... {len(items)-number_to_display} more"[:w-2])
196
+
197
+
198
+ return []
@@ -11,15 +11,14 @@ License: MIT
11
11
  import curses
12
12
  import os
13
13
  from listpick.pane.pane_utils import get_file_attributes, get_graph_string, escape_ansi
14
+ from listpick.pane.get_data import update_file_attributes
14
15
 
15
- def right_split_file_attributes(stdscr, x, y, w, h, state, row, cell, past_data: list = [], data: list = [], test: bool = False):
16
+ def right_split_file_attributes(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
16
17
  """
17
18
  Display file attributes in right pane.
18
19
  """
19
20
  if test: return True
20
21
 
21
- os.chdir(os.path.expanduser("~/Downloads/new"))
22
-
23
22
  # Title
24
23
  title = "File attributes"
25
24
  if len(title) < w: title = f"{title:^{w}}"
@@ -45,7 +44,48 @@ def right_split_file_attributes(stdscr, x, y, w, h, state, row, cell, past_data:
45
44
 
46
45
  return []
47
46
 
48
- def right_split_graph(stdscr, x, y, w, h, state, row, cell, past_data: list = [], data: list = [], test: bool = False):
47
+
48
+ def right_split_file_attributes_dynamic(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
49
+ """
50
+ Display file attributes in right pane.
51
+ """
52
+ if test: return True
53
+
54
+ # Title
55
+ title = "File attributes"
56
+ if len(title) < w: title = f"{title:^{w}}"
57
+ stdscr.addstr(y, x,title[:w], curses.color_pair(state["colours_start"]+4) | curses.A_BOLD)
58
+
59
+ # Separator
60
+ for j in range(h):
61
+ stdscr.addstr(j+y, x, ' ', curses.color_pair(state["colours_start"]+16))
62
+
63
+ # Display pane count
64
+ pane_count = len(state["right_panes"])
65
+ pane_index = state["right_pane_index"]
66
+ if pane_count > 1:
67
+ s = f" {pane_index+1}/{pane_count} "
68
+ stdscr.addstr(y+h-1, x+w-len(s)-1, s, curses.color_pair(state["colours_start"]+20))
69
+
70
+ if len(state["indexed_items"]) == 0:
71
+ return []
72
+
73
+ # Filename/cursor cell value
74
+ stdscr.addstr(y+2, x+2, cell[:w-3])
75
+
76
+ # If the cursor-hovered file is different then reload the data
77
+ if data[1] != cell:
78
+ data[:] = update_file_attributes(data, state)
79
+
80
+ # attributes = get_file_attributes(cell)
81
+ if len(data) == 0: return []
82
+ attributes = data[0]
83
+ for i, attr in enumerate(attributes):
84
+ stdscr.addstr(y+3+i, x+4, attr[:w-5])
85
+
86
+ return []
87
+
88
+ def right_split_graph(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
49
89
  """
50
90
  Display a graph of the data in right pane.
51
91
 
@@ -95,7 +135,7 @@ def right_split_graph(stdscr, x, y, w, h, state, row, cell, past_data: list = []
95
135
 
96
136
 
97
137
 
98
- def right_split_display_list(stdscr, x, y, w, h, state, row, cell, past_data: list = [], data: list = [], test: bool = False):
138
+ def right_split_display_list(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
99
139
  """
100
140
  data[0]:str = title
101
141
  data[1]:list[str] = list of strings to display
@@ -0,0 +1,175 @@
1
+ #!/bin/python
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ pane_functions.py
5
+ Functions which are run by a listpick Picker to display data in a pane.
6
+
7
+ Author: GrimAndGreedy
8
+ License: MIT
9
+ """
10
+
11
+ import curses
12
+ import os
13
+ from listpick.pane.pane_utils import get_file_attributes, get_graph_string, escape_ansi
14
+ from listpick.pane.get_data import update_file_attributes
15
+
16
+ def right_split_file_attributes(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
17
+ """
18
+ Display file attributes in right pane.
19
+ """
20
+ if test: return True
21
+
22
+ # Title
23
+ title = "File attributes"
24
+ if len(title) < w: title = f"{title:^{w}}"
25
+ stdscr.addstr(y, x,title[:w], curses.color_pair(state["colours_start"]+4) | curses.A_BOLD)
26
+
27
+ # Separator
28
+ for j in range(h):
29
+ stdscr.addstr(j+y, x, ' ', curses.color_pair(state["colours_start"]+16))
30
+
31
+ # Display pane count
32
+ pane_count = len(state["right_panes"])
33
+ pane_index = state["right_pane_index"]
34
+ if pane_count > 1:
35
+ s = f" {pane_index+1}/{pane_count} "
36
+ stdscr.addstr(y+h-1, x+w-len(s)-1, s, curses.color_pair(state["colours_start"]+20))
37
+
38
+ # Filename/cursor cell value
39
+ stdscr.addstr(y+2, x+2, cell[:w-3])
40
+
41
+ attributes = get_file_attributes(cell)
42
+ for i, attr in enumerate(attributes):
43
+ stdscr.addstr(y+3+i, x+4, attr[:w-5])
44
+
45
+ return []
46
+
47
+
48
+ def right_split_file_attributes_dynamic(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
49
+ """
50
+ Display file attributes in right pane.
51
+ """
52
+ if test: return True
53
+
54
+ # Title
55
+ title = "File attributes"
56
+ if len(title) < w: title = f"{title:^{w}}"
57
+ stdscr.addstr(y, x,title[:w], curses.color_pair(state["colours_start"]+4) | curses.A_BOLD)
58
+
59
+ # Separator
60
+ for j in range(h):
61
+ stdscr.addstr(j+y, x, ' ', curses.color_pair(state["colours_start"]+16))
62
+
63
+ # Display pane count
64
+ pane_count = len(state["right_panes"])
65
+ pane_index = state["right_pane_index"]
66
+ if pane_count > 1:
67
+ s = f" {pane_index+1}/{pane_count} "
68
+ stdscr.addstr(y+h-1, x+w-len(s)-1, s, curses.color_pair(state["colours_start"]+20))
69
+
70
+ if len(state["indexed_items"]) == 0:
71
+ return []
72
+
73
+ # Filename/cursor cell value
74
+ stdscr.addstr(y+2, x+2, cell[:w-3])
75
+
76
+ # If the cursor-hovered file is different then reload the data
77
+ if data[1] != cell:
78
+ data[:] = update_file_attributes(data, state)
79
+
80
+ # attributes = get_file_attributes(cell)
81
+ if len(data) == 0: return []
82
+ attributes = data[0]
83
+ for i, attr in enumerate(attributes):
84
+ stdscr.addstr(y+3+i, x+4, attr[:w-5])
85
+
86
+ return []
87
+
88
+ def right_split_graph(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
89
+ """
90
+ Display a graph of the data in right pane.
91
+
92
+ data[0] = x_vals
93
+ data[1] = y_vals
94
+ data[2] = id
95
+ """
96
+ if test: return True
97
+
98
+ # Title
99
+ title = "Graph"
100
+ if len(title) < w: title = f"{title:^{w}}"
101
+ stdscr.addstr(y, x,title[:w], curses.color_pair(state["colours_start"]+4) | curses.A_BOLD)
102
+
103
+ # Separator
104
+ for j in range(h):
105
+ stdscr.addstr(j+y, x, ' ', curses.color_pair(state["colours_start"]+16))
106
+
107
+
108
+ # Display pane count
109
+ pane_count = len(state["right_panes"])
110
+ pane_index = state["right_pane_index"]
111
+ if pane_count > 1:
112
+ s = f" {pane_index+1}/{pane_count} "
113
+ stdscr.addstr(y+h-1, x+w-len(s)-1, s, curses.color_pair(state["colours_start"]+20))
114
+
115
+ try:
116
+ import plotille as plt
117
+ except:
118
+ s = f"No module named 'plotille'"
119
+ stdscr.addstr(y+2, x+2, s[:w-2])
120
+ return None
121
+
122
+
123
+
124
+ # x_vals, y_vals = list(range(100)), [x**2 for x in range(100)]
125
+ if data in [[], {}, None]:
126
+ return None
127
+ x_vals, y_vals = data[0], data[1]
128
+ graph_str = get_graph_string(x_vals, y_vals, width=w-3-10, height=h-3)
129
+ for i, s in enumerate(graph_str.split("\n")):
130
+ s = escape_ansi(s)
131
+ stdscr.addstr(y+2+i, x+2, s[:w-2])
132
+
133
+ return []
134
+
135
+
136
+
137
+
138
+ def right_split_display_list(stdscr, x, y, w, h, state, row, cell, data: list = [], test: bool = False):
139
+ """
140
+ data[0]:str = title
141
+ data[1]:list[str] = list of strings to display
142
+ """
143
+ if test: return True
144
+
145
+ # Title
146
+ title = data[0]
147
+ if len(title) < w: title = f"{title:^{w}}"
148
+ stdscr.addstr(y, x,title[:w], curses.color_pair(state["colours_start"]+4) | curses.A_BOLD)
149
+
150
+ # Separator
151
+ for j in range(h):
152
+ stdscr.addstr(j+y, x, ' ', curses.color_pair(state["colours_start"]+16))
153
+
154
+
155
+ # Display pane count
156
+ pane_count = len(state["right_panes"])
157
+ pane_index = state["right_pane_index"]
158
+ if pane_count > 1:
159
+ s = f" {pane_index+1}/{pane_count} "
160
+ stdscr.addstr(y+h-1, x+w-len(s)-1, s, curses.color_pair(state["colours_start"]+20))
161
+
162
+ if data in [[], {}, None]:
163
+ return None
164
+
165
+ items = data[1]
166
+ number_to_display = min(len(items), h-3)
167
+ for i in range(number_to_display):
168
+ s = items[i]
169
+ stdscr.addstr(y+1+i, x+2, s[:w-2])
170
+
171
+ if number_to_display < len(items):
172
+ stdscr.addstr(y+1+number_to_display, x+2, f" ... {len(items)-number_to_display} more"[:w-2])
173
+
174
+
175
+ return []
@@ -41,9 +41,9 @@ def get_graph_string(x_vals, y_vals, width=50, height=20, title=None, x_label=No
41
41
  fig.ylabel = y_label
42
42
 
43
43
  # Generate the ASCII art of the graph
44
- ascii_art = str(fig.show())
44
+ graph_str = str(fig.show())
45
45
 
46
- return ascii_art
46
+ return graph_str
47
47
 
48
48
 
49
49
  def get_file_attributes(filename):
@@ -83,6 +83,6 @@ def get_file_attributes(filename):
83
83
  return attributes
84
84
 
85
85
  except Exception as e:
86
- print(f"An error occurred: {e}")
86
+ # print(f"An error occurred: {e}")
87
87
  return []
88
88
 
listpick/ui/build_help.py CHANGED
@@ -14,7 +14,7 @@ from listpick.utils import keycodes
14
14
 
15
15
  logger = logging.getLogger('picker_log')
16
16
 
17
- def build_help_rows(keys_dict: dict, debug: bool = False) -> list[list[str]]:
17
+ def build_help_rows(keys_dict: dict, macros: list, debug: bool = False) -> list[list[str]]:
18
18
  """ Build help rows based on the keys_dict. """
19
19
 
20
20
  logger.info(f"function: build_help_rows() (build_help.py)")
@@ -68,7 +68,7 @@ def build_help_rows(keys_dict: dict, debug: bool = False) -> list[list[str]]:
68
68
 
69
69
  ## Key descriptions
70
70
  help_descriptions = {
71
- "refresh": "Refresh the screen.",
71
+ "refresh": "Refresh data.",
72
72
  "help": "Open help.",
73
73
  "exit": "Exit picker instance.",
74
74
  "full_exit": "Immediate exit to terminal.",
@@ -117,9 +117,10 @@ def build_help_rows(keys_dict: dict, debug: bool = False) -> list[list[str]]:
117
117
  "col_select_next": "Select next column.",
118
118
  "col_select_prev": "Select previous column.",
119
119
  "col_hide": "Hide column.",
120
- "edit": "Edit cell.",
121
- "edit_picker": "Edit cell from options dialogue.",
122
- "edit_ipython": "Edit current data with ipython.",
120
+ "edit": "Edit (editable) cell.",
121
+ "edit_nvim": "Edit (editable) cell(s) in nvim.",
122
+ "edit_picker": "Edit (editable) cell from options dialogue.",
123
+ "edit_ipython": "Drop to ipython shell with environment as `self`",
123
124
  "copy": "Copy selections.",
124
125
  "paste": "Paste into picker.",
125
126
  "save": "Save selections.",
@@ -131,8 +132,8 @@ def build_help_rows(keys_dict: dict, debug: bool = False) -> list[list[str]]:
131
132
  "undo": "Undo.",
132
133
  "scroll_right": "Scroll right (5 chars).",
133
134
  "scroll_left": "Scroll left (5 chars).",
134
- "scroll_right_25": "Scroll right (25 chars).",
135
- "scroll_left_25": "Scroll left (25 chars).",
135
+ "scroll_right_25": "Scroll right (25 chars).",
136
+ "scroll_left_25": "Scroll left (25 chars).",
136
137
  "scroll_far_right": "Scroll to the end of the column set.",
137
138
  "scroll_far_left": "Scroll to the left home.",
138
139
  "add_column_before": "Insert column before cursor.",
@@ -145,17 +146,19 @@ def build_help_rows(keys_dict: dict, debug: bool = False) -> list[list[str]]:
145
146
  "sheet_next": "Go to the next sheet.",
146
147
  "sheet_prev": "Go to the previous sheet.",
147
148
  "toggle_right_pane": "Toggle the right pane",
148
- "cycle_right_pane": "Cycle through right panes",
149
+ "cycle_right_pane": "Cycle through right pane views",
150
+ "toggle_left_pane": "Toggle the left pane",
151
+ "cycle_left_pane": "Cycle through left pane views",
149
152
  }
150
153
  sections = {
151
154
  "Navigation:": [ "cursor_down", "cursor_up", "half_page_up", "half_page_down", "page_up", "page_down", "cursor_bottom", "cursor_top", "five_up", "five_down", "scroll_right", "scroll_left", "scroll_right_25", "scroll_left_25", "scroll_far_right", "scroll_far_left" ],
152
155
  "Selection:": [ "toggle_select", "select_all", "select_none", "visual_selection_toggle", "visual_deselection_toggle", "enter" ],
153
- "UI:": [ "toggle_footer", "redraw_screen", "decrease_lines_per_page", "increase_lines_per_page", "increase_column_width", "decrease_column_width", "notification_toggle", "toggle_right_pane", "cycle_right_pane"],
156
+ "UI:": [ "toggle_footer", "redraw_screen", "decrease_lines_per_page", "increase_lines_per_page", "increase_column_width", "decrease_column_width", "notification_toggle", "toggle_right_pane", "cycle_right_pane", "toggle_left_pane", "cycle_left_pane"],
154
157
  "Sort:": [ "cycle_sort_method", "cycle_sort_method_reverse", "cycle_sort_order", ] ,
155
- "Data manipulation:": [ "delete", "delete_column", "edit", "edit_picker", "edit_ipython", "add_column_before", "add_column_after", "add_row_before", "add_row_after"],
156
- "Filter and sort:": [ "filter_input", "search_input", "continue_search_forward", "continue_search_backward", ] ,
158
+ "Data manipulation:": [ "delete", "delete_column", "edit", "edit_nvim", "edit_picker", "edit_ipython", "add_column_before", "add_column_after", "add_row_before", "add_row_after"],
159
+ "Filter and search:": [ "filter_input", "search_input", "continue_search_forward", "continue_search_backward", ] ,
157
160
  "Settings:": [ "settings_input", "settings_options" ],
158
- "Cancel:": [ "opts_input", "opts_select", "mode_next", "mode_prev", "pipe_input", "reset_opts", "col_select", "col_select_next", "col_select_prev", "col_hide" ],
161
+ "Options and modes:": [ "opts_input", "opts_select", "mode_next", "mode_prev", "pipe_input", "reset_opts", "col_select", "col_select_next", "col_select_prev", "col_hide" ],
159
162
  "Save, load, copy and paste:": [ "save", "load", "open", "copy", "paste" ],
160
163
  "Misc:": [ "redo", "undo", "refresh", "help", "exit", "full_exit", "move_column_left", "move_column_right" ],
161
164
  }
@@ -170,6 +173,8 @@ def build_help_rows(keys_dict: dict, debug: bool = False) -> list[list[str]]:
170
173
  if not found:
171
174
  sections["Misc:"].append(key)
172
175
 
176
+
177
+
173
178
  items = []
174
179
  for section_name, section_operations in sections.items():
175
180
  section_rows = []
@@ -205,6 +210,26 @@ def build_help_rows(keys_dict: dict, debug: bool = False) -> list[list[str]]:
205
210
  items += section_rows
206
211
  items.append(["",""])
207
212
 
213
+ if macros:
214
+ items.append([f" Macros:", ""])
215
+ for macro in macros:
216
+ keys = []
217
+ for key in macro["keys"]:
218
+ if key in special_keys:
219
+ keys.append(special_keys[key])
220
+ else:
221
+ try:
222
+ keys.append(chr(int(key)))
223
+ except Exception as e:
224
+ keys.append(f"keycode={key}")
225
+ if debug: print(f"Error chr({key}): {e}")
226
+
227
+ row = [f" {str(keys)[1:-1]}", macro["description"]]
228
+ items.append(row)
229
+ items.append(["",""])
230
+
231
+
232
+
208
233
  if debug:
209
234
  for operation in keys_dict:
210
235
  if operation not in help_descriptions:
File without changes
listpick/ui/footer.py CHANGED
@@ -160,7 +160,7 @@ class StandardFooter(Footer):
160
160
  if state["footer_string"]:
161
161
  footer_string_width = min(w-1, len(state["footer_string"])+2)
162
162
 
163
- disp_string = f"{state["footer_string"][:footer_string_width]}"
163
+ disp_string = f"{state['footer_string'][:footer_string_width]}"
164
164
  disp_string = f" {disp_string:>{footer_string_width-2}} "
165
165
  self.stdscr.addstr(self.footer_string_y, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
166
166
  self.stdscr.addstr(self.footer_string_y, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
@@ -259,7 +259,7 @@ class CompactFooter(Footer):
259
259
  if state["footer_string"]:
260
260
  footer_string_width = min(w-1, len(state["footer_string"])+2)
261
261
 
262
- disp_string = f"{state["footer_string"][:footer_string_width]}"
262
+ disp_string = f"{state['footer_string'][:footer_string_width]}"
263
263
  disp_string = f" {disp_string:>{footer_string_width-2}} "
264
264
  self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
265
265
  self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
@@ -318,7 +318,7 @@ class NoFooter(Footer):
318
318
 
319
319
  if state["footer_string"]:
320
320
  footer_string_width = min(w-1, len(state["footer_string"])+2)
321
- disp_string = f"{state["footer_string"][:footer_string_width]}"
321
+ disp_string = f"{state['footer_string'][:footer_string_width]}"
322
322
  disp_string = f" {disp_string:>{footer_string_width-2}} "
323
323
  self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
324
324
  self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
@@ -16,27 +16,9 @@ from datetime import datetime
16
16
  import logging
17
17
 
18
18
  logger = logging.getLogger('picker_log')
19
- import select
20
- import tty
21
19
  from listpick.utils.user_input import get_char, open_tty
22
20
  from listpick.utils import keycodes
23
21
 
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
39
-
40
22
  def input_field(
41
23
  stdscr: curses.window,
42
24
  usrtxt:str="",
@@ -126,7 +108,7 @@ def input_field(
126
108
  offscreen_x, offscreen_y = False, False
127
109
  orig_x, orig_y = x, y
128
110
 
129
- tty_fd = open_tty()
111
+ tty_fd, saved_terminal_state = open_tty()
130
112
 
131
113
  # Input field loop
132
114
  while True:
@@ -211,7 +193,6 @@ def input_field(
211
193
  match_word, left_ptr, right_ptr = get_partially_complete_word(usrtxt, cursor, [" ", "/", "="])
212
194
 
213
195
  if match_word in completions:
214
- # os.system(f"notify-send '{completions[0]}'")
215
196
  index = completions.index(match_word)
216
197
  if index == len(completions) - 1: index = -1
217
198
  completions_disp_str = str(completions[index:])[:max_field_length]