skilleter-thingy 0.0.38__py3-none-any.whl → 0.0.39__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 skilleter-thingy might be problematic. Click here for more details.
- {skilleter_thingy-0.0.38.dist-info → skilleter_thingy-0.0.39.dist-info}/METADATA +1 -1
- skilleter_thingy-0.0.39.dist-info/RECORD +6 -0
- skilleter_thingy-0.0.39.dist-info/entry_points.txt +43 -0
- skilleter_thingy-0.0.39.dist-info/top_level.txt +1 -0
- __init__.py +0 -6
- addpath.py +0 -107
- borger.py +0 -269
- console_colours.py +0 -63
- diskspacecheck.py +0 -67
- docker_purge.py +0 -113
- ffind.py +0 -536
- ggit.py +0 -90
- ggrep.py +0 -154
- git_br.py +0 -180
- git_ca.py +0 -142
- git_cleanup.py +0 -287
- git_co.py +0 -220
- git_common.py +0 -61
- git_hold.py +0 -154
- git_mr.py +0 -92
- git_parent.py +0 -77
- git_review.py +0 -1428
- git_update.py +0 -385
- git_wt.py +0 -96
- gitcmp_helper.py +0 -322
- gitprompt.py +0 -274
- gl.py +0 -174
- gphotosync.py +0 -610
- linecount.py +0 -155
- moviemover.py +0 -133
- photodupe.py +0 -136
- phototidier.py +0 -248
- py_audit.py +0 -131
- readable.py +0 -270
- remdir.py +0 -126
- rmdupe.py +0 -550
- rpylint.py +0 -91
- skilleter_thingy-0.0.38.dist-info/RECORD +0 -66
- skilleter_thingy-0.0.38.dist-info/entry_points.txt +0 -43
- skilleter_thingy-0.0.38.dist-info/top_level.txt +0 -43
- splitpics.py +0 -99
- strreplace.py +0 -82
- sysmon.py +0 -435
- tfm.py +0 -920
- tfparse.py +0 -101
- thingy/__init__.py +0 -0
- thingy/colour.py +0 -213
- thingy/dc_curses.py +0 -278
- thingy/dc_defaults.py +0 -221
- thingy/dc_util.py +0 -50
- thingy/dircolors.py +0 -308
- thingy/docker.py +0 -95
- thingy/files.py +0 -142
- thingy/git.py +0 -1371
- thingy/git2.py +0 -1307
- thingy/gitlab.py +0 -193
- thingy/logger.py +0 -112
- thingy/path.py +0 -156
- thingy/popup.py +0 -87
- thingy/process.py +0 -112
- thingy/run.py +0 -334
- thingy/tfm_pane.py +0 -595
- thingy/tidy.py +0 -160
- trimpath.py +0 -84
- window_rename.py +0 -92
- xchmod.py +0 -125
- yamlcheck.py +0 -89
- {skilleter_thingy-0.0.38.dist-info → skilleter_thingy-0.0.39.dist-info}/LICENSE +0 -0
- {skilleter_thingy-0.0.38.dist-info → skilleter_thingy-0.0.39.dist-info}/WHEEL +0 -0
thingy/tfm_pane.py
DELETED
|
@@ -1,595 +0,0 @@
|
|
|
1
|
-
################################################################################
|
|
2
|
-
""" Pane class for tfm """
|
|
3
|
-
################################################################################
|
|
4
|
-
|
|
5
|
-
import sys
|
|
6
|
-
import os
|
|
7
|
-
import curses
|
|
8
|
-
import fnmatch
|
|
9
|
-
import stat
|
|
10
|
-
import glob
|
|
11
|
-
import time
|
|
12
|
-
import threading
|
|
13
|
-
|
|
14
|
-
from enum import IntEnum
|
|
15
|
-
|
|
16
|
-
if sys.platform == 'linux':
|
|
17
|
-
import inotify.adapters
|
|
18
|
-
|
|
19
|
-
import thingy.dc_curses as dc_curses
|
|
20
|
-
import thingy.path as path
|
|
21
|
-
import thingy.popup as popup
|
|
22
|
-
|
|
23
|
-
################################################################################
|
|
24
|
-
|
|
25
|
-
class SortOrder(IntEnum):
|
|
26
|
-
""" Sort order for filename list """
|
|
27
|
-
|
|
28
|
-
FILENAME = 0
|
|
29
|
-
EXTENSION = 1
|
|
30
|
-
MODIFIED_DATE = 2
|
|
31
|
-
SIZE = 3
|
|
32
|
-
NUM_SORTS = 4
|
|
33
|
-
|
|
34
|
-
SORT_TYPE = ('filename', 'extension', 'modified date', 'size')
|
|
35
|
-
|
|
36
|
-
################################################################################
|
|
37
|
-
|
|
38
|
-
def inotify_wait(self):
|
|
39
|
-
"""Thread to wait for inotify events and post an event to the queue if there
|
|
40
|
-
any create/delete/modify events in the current directory.
|
|
41
|
-
Sends no more than 1 update per second to avoid drowning the recipient."""
|
|
42
|
-
|
|
43
|
-
while True:
|
|
44
|
-
trigger = False
|
|
45
|
-
for event in self.ino.event_gen(yield_nones=False, timeout_s=1):
|
|
46
|
-
(_, events, path, _) = event
|
|
47
|
-
|
|
48
|
-
if path == self.current_dir and ('IN_CREATE' in events or 'IN_DELETE' in events or 'IN_MODIFY' in events):
|
|
49
|
-
trigger = True
|
|
50
|
-
|
|
51
|
-
if trigger:
|
|
52
|
-
self.event_queue.put(('inotify', self.index))
|
|
53
|
-
|
|
54
|
-
################################################################################
|
|
55
|
-
|
|
56
|
-
class Pane():
|
|
57
|
-
""" Class for a file manager pane """
|
|
58
|
-
|
|
59
|
-
def __init__(self, index, num_panes, colours, event_queue):
|
|
60
|
-
# Create window for the pane (dummy size and position initially)
|
|
61
|
-
|
|
62
|
-
self.screen = curses.newwin(1, 1, 0, 0)
|
|
63
|
-
|
|
64
|
-
self.index = index
|
|
65
|
-
|
|
66
|
-
self.current_dir = None
|
|
67
|
-
|
|
68
|
-
self.ino = inotify.adapters.Inotify() if sys.platform == 'linux' else None
|
|
69
|
-
|
|
70
|
-
self.set_current_dir(os.getcwd())
|
|
71
|
-
|
|
72
|
-
self.event_queue = event_queue
|
|
73
|
-
|
|
74
|
-
if sys.platform == 'linux':
|
|
75
|
-
inotify_thread = threading.Thread(target=inotify_wait, args=(self,), daemon=True)
|
|
76
|
-
inotify_thread.start()
|
|
77
|
-
|
|
78
|
-
# Default sort order
|
|
79
|
-
|
|
80
|
-
self.sort_order = SortOrder.FILENAME
|
|
81
|
-
self.reverse_sort = False
|
|
82
|
-
|
|
83
|
-
# Set the attributes of the current review (some are initialised
|
|
84
|
-
# when the screen is drawn)
|
|
85
|
-
|
|
86
|
-
# Index of the current file in the filtered_file_indices
|
|
87
|
-
|
|
88
|
-
self.current = 0
|
|
89
|
-
|
|
90
|
-
self.offset = 0
|
|
91
|
-
self.num_panes = num_panes
|
|
92
|
-
self.colours = colours
|
|
93
|
-
|
|
94
|
-
self.searchstring = None
|
|
95
|
-
|
|
96
|
-
self.height = self.width = -1
|
|
97
|
-
self.file_list_y = 1
|
|
98
|
-
self.file_list_h = -1
|
|
99
|
-
|
|
100
|
-
# File list is a list of the files in the current directory
|
|
101
|
-
|
|
102
|
-
self.file_list = []
|
|
103
|
-
|
|
104
|
-
# Filtered file list is a list of the indices in file_list of the visible files
|
|
105
|
-
# in the current directory
|
|
106
|
-
|
|
107
|
-
self.filtered_file_indices = []
|
|
108
|
-
|
|
109
|
-
# Set of the names of currently-tagged files
|
|
110
|
-
|
|
111
|
-
self.tagged_set = set()
|
|
112
|
-
|
|
113
|
-
self.in_filter = self.out_filter = None
|
|
114
|
-
self.hide_hidden_filter = True
|
|
115
|
-
|
|
116
|
-
self.file_display_fields = ['size', 'mtime']
|
|
117
|
-
|
|
118
|
-
# Set up dircolor highlighting
|
|
119
|
-
|
|
120
|
-
self.dircolours = dc_curses.CursesDircolors(reserved=self.colours['reserved_colours'])
|
|
121
|
-
|
|
122
|
-
# Generate the list of files to be shown (takes filtering into account)
|
|
123
|
-
|
|
124
|
-
self.update_files()
|
|
125
|
-
|
|
126
|
-
################################################################################
|
|
127
|
-
|
|
128
|
-
def sort_file_list(self):
|
|
129
|
-
""" Sort the file list according to the current sort order """
|
|
130
|
-
|
|
131
|
-
if self.sort_order == SortOrder.FILENAME:
|
|
132
|
-
self.file_list.sort(reverse=self.reverse_sort, key=lambda entry: (not entry['isdir'], os.path.basename(entry['name'])))
|
|
133
|
-
elif self.sort_order == SortOrder.EXTENSION:
|
|
134
|
-
self.file_list.sort(reverse=self.reverse_sort, key=lambda entry: (not entry['isdir'], entry['name'].split('.')[-1]))
|
|
135
|
-
elif self.sort_order == SortOrder.MODIFIED_DATE:
|
|
136
|
-
self.file_list.sort(reverse=self.reverse_sort, key=lambda entry: (not entry['isdir'], entry['mtime']))
|
|
137
|
-
elif self.sort_order == SortOrder.SIZE:
|
|
138
|
-
self.file_list.sort(reverse=self.reverse_sort, key=lambda entry: (not entry['isdir'], entry['size']))
|
|
139
|
-
|
|
140
|
-
################################################################################
|
|
141
|
-
|
|
142
|
-
def update_files(self):
|
|
143
|
-
""" Get the list of files
|
|
144
|
-
"""
|
|
145
|
-
|
|
146
|
-
def file_stats(filename):
|
|
147
|
-
""" Get the stats for a file """
|
|
148
|
-
|
|
149
|
-
filestat = os.stat(filename, follow_symlinks=False)
|
|
150
|
-
|
|
151
|
-
info = {'name':filename,
|
|
152
|
-
'mode': filestat.st_mode,
|
|
153
|
-
'uid': filestat.st_uid,
|
|
154
|
-
'gid': filestat.st_gid,
|
|
155
|
-
'size': filestat.st_size,
|
|
156
|
-
'atime': filestat.st_atime,
|
|
157
|
-
'mtime': filestat.st_mtime,
|
|
158
|
-
'ctime': filestat.st_ctime,
|
|
159
|
-
'isdir': stat.S_ISDIR(filestat.st_mode)}
|
|
160
|
-
|
|
161
|
-
return info
|
|
162
|
-
|
|
163
|
-
# Rebuild the file list
|
|
164
|
-
|
|
165
|
-
self.file_list = []
|
|
166
|
-
for filename in glob.glob(os.path.join(self.current_dir, '*')) + glob.glob(os.path.join(self.current_dir, '.*')):
|
|
167
|
-
self.file_list.append(file_stats(filename))
|
|
168
|
-
|
|
169
|
-
# Update the tagged file list to contain only current files
|
|
170
|
-
|
|
171
|
-
self.tagged_set = {entry['name'] for entry in self.file_list if entry['name'] in self.tagged_set}
|
|
172
|
-
|
|
173
|
-
# Optionally add '..' as an entry
|
|
174
|
-
|
|
175
|
-
if self.current_dir != '/':
|
|
176
|
-
self.file_list.append(file_stats('..'))
|
|
177
|
-
|
|
178
|
-
self.sort_file_list()
|
|
179
|
-
self.update_file_list()
|
|
180
|
-
|
|
181
|
-
################################################################################
|
|
182
|
-
|
|
183
|
-
def update_file_list(self):
|
|
184
|
-
""" Generate the file list from the list of current files with filtering
|
|
185
|
-
applied if enabled """
|
|
186
|
-
|
|
187
|
-
self.sort_file_list()
|
|
188
|
-
|
|
189
|
-
if self.active_filters():
|
|
190
|
-
self.filtered_file_indices = [i for i, entry in enumerate(self.file_list) if not self.filtered(entry)]
|
|
191
|
-
else:
|
|
192
|
-
self.filtered_file_indices = range(len(self.file_list))
|
|
193
|
-
|
|
194
|
-
################################################################################
|
|
195
|
-
|
|
196
|
-
def active_filters(self):
|
|
197
|
-
""" Return true if any filters are active """
|
|
198
|
-
|
|
199
|
-
return self.out_filter or \
|
|
200
|
-
self.in_filter or \
|
|
201
|
-
self.hide_hidden_filter
|
|
202
|
-
|
|
203
|
-
################################################################################
|
|
204
|
-
|
|
205
|
-
def filtered(self, entry):
|
|
206
|
-
""" Return True if an entry is hidden by one or more filters """
|
|
207
|
-
|
|
208
|
-
result = False
|
|
209
|
-
|
|
210
|
-
if self.out_filter and fnmatch.fnmatch(entry['name'], self.out_filter):
|
|
211
|
-
result = True
|
|
212
|
-
|
|
213
|
-
elif self.in_filter and not fnmatch.fnmatch(entry['name'], self.in_filter):
|
|
214
|
-
result = True
|
|
215
|
-
|
|
216
|
-
elif self.hide_hidden_filter:
|
|
217
|
-
base_name = os.path.basename(entry['name'])
|
|
218
|
-
if base_name[0] == '.' and base_name != '..':
|
|
219
|
-
result = True
|
|
220
|
-
|
|
221
|
-
return result
|
|
222
|
-
|
|
223
|
-
################################################################################
|
|
224
|
-
|
|
225
|
-
def constrain_display_parameters(self):
|
|
226
|
-
""" Ensure that the current display parameters are within range - easier
|
|
227
|
-
to do it in one place for all of them than check individually whenever we
|
|
228
|
-
change any of them """
|
|
229
|
-
|
|
230
|
-
self.current = max(min(self.current, len(self.filtered_file_indices) - 1), 0)
|
|
231
|
-
self.offset = min(len(self.filtered_file_indices) - 1, max(0, self.offset))
|
|
232
|
-
|
|
233
|
-
# Keep the current entry on-screen
|
|
234
|
-
|
|
235
|
-
if self.current >= self.offset + self.height - 2:
|
|
236
|
-
self.offset = self.current
|
|
237
|
-
elif self.current < self.offset:
|
|
238
|
-
self.offset = self.current
|
|
239
|
-
|
|
240
|
-
################################################################################
|
|
241
|
-
|
|
242
|
-
def file_info_display(self, filename):
|
|
243
|
-
""" Extract the additional file info fields displayed to the right
|
|
244
|
-
of the filename """
|
|
245
|
-
|
|
246
|
-
data = []
|
|
247
|
-
for field in self.file_display_fields:
|
|
248
|
-
if field == 'name':
|
|
249
|
-
data.append(filename['name'])
|
|
250
|
-
elif field in ('atime', 'mtime', 'ctime'):
|
|
251
|
-
data.append(time.strftime('%x %X', time.gmtime(filename[field])))
|
|
252
|
-
elif field == 'uid':
|
|
253
|
-
pass
|
|
254
|
-
elif field == 'gid':
|
|
255
|
-
pass
|
|
256
|
-
elif field == 'mode':
|
|
257
|
-
pass
|
|
258
|
-
elif field == 'size':
|
|
259
|
-
data.append(str(filename[field]))
|
|
260
|
-
|
|
261
|
-
return ' '.join(data)
|
|
262
|
-
|
|
263
|
-
################################################################################
|
|
264
|
-
|
|
265
|
-
def show_file_list(self, current_pane):
|
|
266
|
-
""" Draw the current page of the file list """
|
|
267
|
-
|
|
268
|
-
for ypos in range(0, self.file_list_h):
|
|
269
|
-
|
|
270
|
-
normal_colour = curses.color_pair(self.colours['normal'])
|
|
271
|
-
|
|
272
|
-
if 0 <= self.offset + ypos < len(self.filtered_file_indices):
|
|
273
|
-
# Work out what colour to render the file details in
|
|
274
|
-
|
|
275
|
-
current_file = self.file_list[self.filtered_file_indices[self.offset + ypos]]
|
|
276
|
-
|
|
277
|
-
current = self.offset + ypos == self.current
|
|
278
|
-
|
|
279
|
-
# The text to render
|
|
280
|
-
|
|
281
|
-
filename = os.path.basename(current_file['name'])
|
|
282
|
-
|
|
283
|
-
data = self.file_info_display(current_file)
|
|
284
|
-
|
|
285
|
-
name = f'/{filename}' if current_file['isdir'] else filename
|
|
286
|
-
name = f'* {name}' if current_file['name'] in self.tagged_set else f' {name}'
|
|
287
|
-
|
|
288
|
-
if len(name) > self.width - len(data):
|
|
289
|
-
entry = name[:self.width - 3] + '...'
|
|
290
|
-
else:
|
|
291
|
-
entry = name + ' ' * (self.width - len(name) - len(data)) + data
|
|
292
|
-
|
|
293
|
-
else:
|
|
294
|
-
filename = entry = None
|
|
295
|
-
current = False
|
|
296
|
-
|
|
297
|
-
# Render the current line
|
|
298
|
-
|
|
299
|
-
file_colour = self.dircolours.get_colour_pair(current_file['name'], current_file['mode']) if filename else normal_colour
|
|
300
|
-
|
|
301
|
-
# Reverse the colours if this the cursor line
|
|
302
|
-
|
|
303
|
-
if current and current_pane:
|
|
304
|
-
file_colour |= curses.A_REVERSE
|
|
305
|
-
normal_colour |= curses.A_REVERSE
|
|
306
|
-
|
|
307
|
-
# Write the prefix, filename, and, if necessary, padding
|
|
308
|
-
|
|
309
|
-
self.screen.move(self.file_list_y + ypos, 0)
|
|
310
|
-
if entry:
|
|
311
|
-
self.screen.addstr(entry, file_colour)
|
|
312
|
-
else:
|
|
313
|
-
self.screen.clrtoeol()
|
|
314
|
-
|
|
315
|
-
#if len(filename) < self.width:
|
|
316
|
-
# self.screen.addstr(self.file_list_y + ypos, len(filename), ' ' * (self.width - len(filename)), normal_colour)
|
|
317
|
-
|
|
318
|
-
current_dir = path.trimpath(self.current_dir, self.width)
|
|
319
|
-
|
|
320
|
-
self.screen.move(0, 0)
|
|
321
|
-
self.screen.attron(curses.color_pair(self.colours['status']))
|
|
322
|
-
self.screen.addstr(current_dir + ' '*(self.width-len(current_dir)))
|
|
323
|
-
|
|
324
|
-
self.screen.refresh()
|
|
325
|
-
|
|
326
|
-
if not self.filtered_file_indices:
|
|
327
|
-
with popup.PopUp(self.screen, 'All files are hidden - Press \'c\' to clear filters.', self.colours['status']):
|
|
328
|
-
pass
|
|
329
|
-
|
|
330
|
-
################################################################################
|
|
331
|
-
|
|
332
|
-
def filter_description(self):
|
|
333
|
-
""" Return a textual description of the active filters """
|
|
334
|
-
|
|
335
|
-
filters = []
|
|
336
|
-
|
|
337
|
-
if self.out_filter:
|
|
338
|
-
filters.append('filter-out wildcard')
|
|
339
|
-
|
|
340
|
-
if self.in_filter:
|
|
341
|
-
filters.append('filter-in wildcard')
|
|
342
|
-
|
|
343
|
-
return ', '.join(filters)
|
|
344
|
-
|
|
345
|
-
################################################################################
|
|
346
|
-
|
|
347
|
-
def clear_filters(self):
|
|
348
|
-
""" Clear all filters """
|
|
349
|
-
|
|
350
|
-
if self.out_filter or self.in_filter:
|
|
351
|
-
self.out_filter = self.in_filter = None
|
|
352
|
-
self.update_file_list()
|
|
353
|
-
|
|
354
|
-
################################################################################
|
|
355
|
-
|
|
356
|
-
def reload_changes(self):
|
|
357
|
-
""" Update the list of files in case something external has
|
|
358
|
-
changed it. """
|
|
359
|
-
|
|
360
|
-
self.update_files()
|
|
361
|
-
|
|
362
|
-
################################################################################
|
|
363
|
-
|
|
364
|
-
def get_current_dir(self):
|
|
365
|
-
""" Get the current directory for the pane """
|
|
366
|
-
|
|
367
|
-
return self.current_dir
|
|
368
|
-
|
|
369
|
-
################################################################################
|
|
370
|
-
|
|
371
|
-
def set_current_dir(self, directory):
|
|
372
|
-
""" Set the current directory for the pane """
|
|
373
|
-
|
|
374
|
-
if self.current_dir and self.ino:
|
|
375
|
-
self.ino.remove_watch(self.current_dir)
|
|
376
|
-
|
|
377
|
-
self.current_dir = os.path.normpath(directory)
|
|
378
|
-
|
|
379
|
-
if self.ino:
|
|
380
|
-
self.ino.add_watch(directory)
|
|
381
|
-
|
|
382
|
-
################################################################################
|
|
383
|
-
|
|
384
|
-
def get_current_file(self):
|
|
385
|
-
""" Get the current file for the pane """
|
|
386
|
-
|
|
387
|
-
return self.file_list[self.filtered_file_indices[self.current]]
|
|
388
|
-
|
|
389
|
-
################################################################################
|
|
390
|
-
|
|
391
|
-
def get_tagged_files(self):
|
|
392
|
-
""" Get the list of tagged files, or the current file if none are tagged """
|
|
393
|
-
|
|
394
|
-
if self.tagged_set:
|
|
395
|
-
return [self.file_list[entry] for entry in self.filtered_file_indices if self.file_list[entry]['name'] in self.tagged_set]
|
|
396
|
-
|
|
397
|
-
return [self.get_current_file()]
|
|
398
|
-
|
|
399
|
-
################################################################################
|
|
400
|
-
|
|
401
|
-
def search_entry(self, searchstring):
|
|
402
|
-
""" Search for the next match with the specified search string """
|
|
403
|
-
|
|
404
|
-
for i in list(range(self.current + 1, len(self.filtered_file_indices))) + list(range(0, self.current)):
|
|
405
|
-
if fnmatch.fnmatch(os.path.basename(self.file_list[self.filtered_file_indices[i]]['name']), searchstring):
|
|
406
|
-
self.current = i
|
|
407
|
-
break
|
|
408
|
-
|
|
409
|
-
################################################################################
|
|
410
|
-
|
|
411
|
-
def search_match(self, searchstring):
|
|
412
|
-
""" Search for the first match """
|
|
413
|
-
|
|
414
|
-
self.searchstring = searchstring
|
|
415
|
-
self.search_next_match()
|
|
416
|
-
|
|
417
|
-
################################################################################
|
|
418
|
-
|
|
419
|
-
def search_next_match(self):
|
|
420
|
-
""" Search for the next match with the current search string """
|
|
421
|
-
|
|
422
|
-
self.search_entry(self.searchstring)
|
|
423
|
-
|
|
424
|
-
################################################################################
|
|
425
|
-
|
|
426
|
-
def move_end(self):
|
|
427
|
-
""" Move to the end of the file list """
|
|
428
|
-
|
|
429
|
-
self.current = len(self.filtered_file_indices) - 1
|
|
430
|
-
|
|
431
|
-
################################################################################
|
|
432
|
-
|
|
433
|
-
def move_top(self):
|
|
434
|
-
""" Move to the top of the file list """
|
|
435
|
-
|
|
436
|
-
self.current = self.offset = 0
|
|
437
|
-
|
|
438
|
-
################################################################################
|
|
439
|
-
|
|
440
|
-
def move_to_file(self, filename):
|
|
441
|
-
""" Move to the specified file (if it exists) in the current directory
|
|
442
|
-
or to the top if not """
|
|
443
|
-
|
|
444
|
-
self.current = self.offset = 0
|
|
445
|
-
if filename:
|
|
446
|
-
self.search_entry(filename)
|
|
447
|
-
|
|
448
|
-
################################################################################
|
|
449
|
-
|
|
450
|
-
def move(self, delta):
|
|
451
|
-
""" Move up or down the file list """
|
|
452
|
-
|
|
453
|
-
self.current += delta
|
|
454
|
-
|
|
455
|
-
################################################################################
|
|
456
|
-
|
|
457
|
-
def filter_out(self, filter_out):
|
|
458
|
-
""" Set an exclusion filter """
|
|
459
|
-
|
|
460
|
-
self.out_filter = filter_out
|
|
461
|
-
self.in_filter = None
|
|
462
|
-
self.update_file_list()
|
|
463
|
-
|
|
464
|
-
################################################################################
|
|
465
|
-
|
|
466
|
-
def filter_in(self, filter_in):
|
|
467
|
-
""" Set an inclusion filter """
|
|
468
|
-
|
|
469
|
-
self.in_filter = filter_in
|
|
470
|
-
self.out_filter = None
|
|
471
|
-
self.update_file_list()
|
|
472
|
-
|
|
473
|
-
################################################################################
|
|
474
|
-
|
|
475
|
-
def move_page_down(self):
|
|
476
|
-
""" Page down """
|
|
477
|
-
|
|
478
|
-
pos = self.current - self.offset
|
|
479
|
-
self.offset += self.file_list_h - 1
|
|
480
|
-
self.current = self.offset + pos
|
|
481
|
-
|
|
482
|
-
################################################################################
|
|
483
|
-
|
|
484
|
-
def move_page_up(self):
|
|
485
|
-
""" Page up """
|
|
486
|
-
|
|
487
|
-
pos = self.current - self.offset
|
|
488
|
-
self.offset -= self.file_list_h - 1
|
|
489
|
-
self.current = self.offset + pos
|
|
490
|
-
|
|
491
|
-
################################################################################
|
|
492
|
-
|
|
493
|
-
def set_sort_order(self, value):
|
|
494
|
-
""" Set the sort order """
|
|
495
|
-
|
|
496
|
-
self.sort_order = (self.sort_order + value) % SortOrder.NUM_SORTS
|
|
497
|
-
|
|
498
|
-
self.update_sort()
|
|
499
|
-
|
|
500
|
-
################################################################################
|
|
501
|
-
|
|
502
|
-
def get_sort_order(self):
|
|
503
|
-
""" Get the current sort order """
|
|
504
|
-
|
|
505
|
-
return self.sort_order
|
|
506
|
-
|
|
507
|
-
################################################################################
|
|
508
|
-
|
|
509
|
-
def sort_type_msg(self):
|
|
510
|
-
""" Return a textual explanation of the current sort type """
|
|
511
|
-
|
|
512
|
-
if self.reverse_sort:
|
|
513
|
-
msg = f'Reverse-sorting by {SORT_TYPE[self.sort_order]}'
|
|
514
|
-
else:
|
|
515
|
-
msg = f'Sorting by {SORT_TYPE[self.sort_order]}'
|
|
516
|
-
|
|
517
|
-
return msg
|
|
518
|
-
|
|
519
|
-
################################################################################
|
|
520
|
-
|
|
521
|
-
def reverse_sort_order(self):
|
|
522
|
-
""" Reverse the sort order """
|
|
523
|
-
|
|
524
|
-
self.reverse_sort = not self.reverse_sort
|
|
525
|
-
self.update_sort()
|
|
526
|
-
|
|
527
|
-
################################################################################
|
|
528
|
-
|
|
529
|
-
def update_sort(self):
|
|
530
|
-
""" Update the sort """
|
|
531
|
-
|
|
532
|
-
msg = self.sort_type_msg()
|
|
533
|
-
|
|
534
|
-
with popup.PopUp(self.screen, msg, self.colours['status']):
|
|
535
|
-
self.update_file_list()
|
|
536
|
-
|
|
537
|
-
################################################################################
|
|
538
|
-
|
|
539
|
-
def set_pane_coords(self, y, x, height, width):
|
|
540
|
-
""" Set the pane height given the pane display area """
|
|
541
|
-
|
|
542
|
-
pane_width = width//self.num_panes
|
|
543
|
-
|
|
544
|
-
self.height = height
|
|
545
|
-
self.file_list_h = height-1
|
|
546
|
-
self.width = pane_width-1 # TODO: Why '-1'?
|
|
547
|
-
self.screen.resize(height, pane_width)
|
|
548
|
-
self.screen.mvwin(y, x + pane_width*self.index)
|
|
549
|
-
|
|
550
|
-
################################################################################
|
|
551
|
-
|
|
552
|
-
def tag_current(self):
|
|
553
|
-
""" Tag the current entry (unless it is '..') """
|
|
554
|
-
|
|
555
|
-
current = self.file_list[self.filtered_file_indices[self.current]]['name']
|
|
556
|
-
|
|
557
|
-
if current != '..':
|
|
558
|
-
if current in self.tagged_set:
|
|
559
|
-
self.tagged_set.remove(current)
|
|
560
|
-
else:
|
|
561
|
-
self.tagged_set.add(current)
|
|
562
|
-
|
|
563
|
-
################################################################################
|
|
564
|
-
|
|
565
|
-
def untag(self, wildcard=None):
|
|
566
|
-
""" Tag all, or selected tagged items """
|
|
567
|
-
|
|
568
|
-
if wildcard:
|
|
569
|
-
remove_tags = set()
|
|
570
|
-
for entry in self.tagged_set:
|
|
571
|
-
if fnmatch.fnmatch(self.filtered_file_indices[entry], wildcard):
|
|
572
|
-
remove_tags.add(entry)
|
|
573
|
-
|
|
574
|
-
self.tagged_set -= remove_tags
|
|
575
|
-
else:
|
|
576
|
-
self.tagged_set = set()
|
|
577
|
-
|
|
578
|
-
################################################################################
|
|
579
|
-
|
|
580
|
-
def get_hidden_visibility(self):
|
|
581
|
-
""" Return the current state of hidden file visibility """
|
|
582
|
-
|
|
583
|
-
return not self.hide_hidden_filter
|
|
584
|
-
|
|
585
|
-
################################################################################
|
|
586
|
-
|
|
587
|
-
def set_hidden_visibility(self, state=False):
|
|
588
|
-
""" Set the visibility of hidden files """
|
|
589
|
-
|
|
590
|
-
self.hide_hidden_filter = not state
|
|
591
|
-
|
|
592
|
-
change_txt = 'Hiding' if self.hide_hidden_filter else 'Showing'
|
|
593
|
-
|
|
594
|
-
with popup.PopUp(self.screen, f'{change_txt} hidden files', self.colours['status']):
|
|
595
|
-
self.update_file_list()
|