sergeant 1.0.6 → 1.0.7
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/lib/sergeant/modals/dialogs.rb +87 -0
- data/lib/sergeant/modals/file_operations.rb +19 -1
- data/lib/sergeant/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c874d9cc43e11d9c891bf372f1324f188c7a1b5aebe5ee4ddcb71bb5db68c66
|
|
4
|
+
data.tar.gz: 2a47b52f0ae9fe27c7e02b13a74338b34c0db9a768bf36216048e838445843e3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d9b9b02b04e41563f2a623f64228b07f2de2a551480d1547a731e4d09d577033c2bb29ceb1c8c5b0b56d22000d6c8bb51c267fc6e415f07190badcde85b631fc
|
|
7
|
+
data.tar.gz: 7a23e6671b4e1c77231060e3dde2cde017d859ce8cfacff23c449166cc7b62b1c3df0bcec53f3243ab5c193d6c82de7b5c73dfe684f671c3db1f3679aeed32b6
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,15 @@ All notable changes to Sergeant will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
|
|
9
|
+
## [1.0.7] - 2026-03-09
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Progress bar for file operations**
|
|
13
|
+
- Copy, move, and delete now show a live progress modal
|
|
14
|
+
- Displays current filename, filled bar (█░), and X/N (%) counter
|
|
15
|
+
- Prevents UI from appearing frozen during large or multi-file operations
|
|
16
|
+
|
|
8
17
|
## [1.0.6] - 2026-01-16
|
|
9
18
|
|
|
10
19
|
### Added
|
|
@@ -348,6 +348,93 @@ module Sergeant
|
|
|
348
348
|
end
|
|
349
349
|
end
|
|
350
350
|
|
|
351
|
+
def draw_progress_modal(title, total)
|
|
352
|
+
max_y = lines
|
|
353
|
+
max_x = cols
|
|
354
|
+
|
|
355
|
+
modal_width = [60, max_x - 4].min
|
|
356
|
+
modal_height = 7
|
|
357
|
+
modal_y = (max_y - modal_height) / 2
|
|
358
|
+
modal_x = (max_x - modal_width) / 2
|
|
359
|
+
|
|
360
|
+
@progress_modal = { y: modal_y, x: modal_x, width: modal_width, total: total }
|
|
361
|
+
|
|
362
|
+
# Draw background
|
|
363
|
+
(modal_y..(modal_y + modal_height)).each do |y|
|
|
364
|
+
setpos(y, modal_x)
|
|
365
|
+
attron(color_pair(3)) { addstr(' ' * modal_width) }
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# Top border
|
|
369
|
+
setpos(modal_y, modal_x)
|
|
370
|
+
attron(color_pair(4) | Curses::A_BOLD) do
|
|
371
|
+
addstr("\u250C#{'─' * (modal_width - 2)}\u2510")
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# Title row
|
|
375
|
+
setpos(modal_y + 1, modal_x)
|
|
376
|
+
attron(color_pair(4) | Curses::A_BOLD) { addstr('│') }
|
|
377
|
+
attron(color_pair(5) | Curses::A_BOLD) { addstr(" #{title} ".center(modal_width - 2)) }
|
|
378
|
+
attron(color_pair(4) | Curses::A_BOLD) { addstr('│') }
|
|
379
|
+
|
|
380
|
+
# Separator
|
|
381
|
+
setpos(modal_y + 2, modal_x)
|
|
382
|
+
attron(color_pair(4)) { addstr("\u251C#{'─' * (modal_width - 2)}\u2524") }
|
|
383
|
+
|
|
384
|
+
# Filename row (blank initially)
|
|
385
|
+
setpos(modal_y + 3, modal_x)
|
|
386
|
+
attron(color_pair(4)) { addstr('│ ') }
|
|
387
|
+
addstr(' ' * (modal_width - 4))
|
|
388
|
+
attron(color_pair(4)) { addstr(' │') }
|
|
389
|
+
|
|
390
|
+
# Spacer row
|
|
391
|
+
setpos(modal_y + 4, modal_x)
|
|
392
|
+
attron(color_pair(4)) { addstr("\u2502#{' ' * (modal_width - 2)}\u2502") }
|
|
393
|
+
|
|
394
|
+
# Progress bar row (blank initially)
|
|
395
|
+
setpos(modal_y + 5, modal_x)
|
|
396
|
+
attron(color_pair(4)) { addstr('│ ') }
|
|
397
|
+
addstr(' ' * (modal_width - 4))
|
|
398
|
+
attron(color_pair(4)) { addstr(' │') }
|
|
399
|
+
|
|
400
|
+
# Bottom border
|
|
401
|
+
setpos(modal_y + 6, modal_x)
|
|
402
|
+
attron(color_pair(4) | Curses::A_BOLD) do
|
|
403
|
+
addstr("\u2514#{'─' * (modal_width - 2)}\u2518")
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
refresh
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def update_progress_modal(current, total, filename)
|
|
410
|
+
return unless @progress_modal
|
|
411
|
+
|
|
412
|
+
modal_y = @progress_modal[:y]
|
|
413
|
+
modal_x = @progress_modal[:x]
|
|
414
|
+
modal_width = @progress_modal[:width]
|
|
415
|
+
inner_width = modal_width - 4 # between '│ ' and ' │'
|
|
416
|
+
|
|
417
|
+
# Update filename line
|
|
418
|
+
setpos(modal_y + 3, modal_x + 2)
|
|
419
|
+
display_name = filename.to_s
|
|
420
|
+
display_name = "...#{display_name[-(inner_width - 3)..]}" if display_name.length > inner_width
|
|
421
|
+
addstr(display_name.ljust(inner_width))
|
|
422
|
+
|
|
423
|
+
# Build progress bar
|
|
424
|
+
percent = total > 0 ? (current.to_f / total * 100).round : 0
|
|
425
|
+
count_str = "#{current}/#{total} (#{percent}%)"
|
|
426
|
+
bar_outer = [inner_width - count_str.length - 1, 3].max # 1 space between bar and count
|
|
427
|
+
bar_inner = bar_outer - 2 # subtract [ and ]
|
|
428
|
+
filled = total > 0 ? (current.to_f / total * bar_inner).round : 0
|
|
429
|
+
empty = bar_inner - filled
|
|
430
|
+
|
|
431
|
+
bar = "[#{'█' * filled}#{'░' * empty}] #{count_str}"
|
|
432
|
+
setpos(modal_y + 5, modal_x + 2)
|
|
433
|
+
addstr(bar.ljust(inner_width))
|
|
434
|
+
|
|
435
|
+
refresh
|
|
436
|
+
end
|
|
437
|
+
|
|
351
438
|
def show_error_with_retry(filepath, error_message)
|
|
352
439
|
max_y = lines
|
|
353
440
|
max_x = cols
|
|
@@ -131,11 +131,18 @@ module Sergeant
|
|
|
131
131
|
error_count = 0
|
|
132
132
|
errors = []
|
|
133
133
|
|
|
134
|
+
total = @copied_items.count { |p| File.exist?(p) }
|
|
135
|
+
operation = @cut_mode ? 'Moving' : 'Copying'
|
|
136
|
+
draw_progress_modal("#{operation} Files", total)
|
|
137
|
+
current = 0
|
|
138
|
+
|
|
134
139
|
@copied_items.each do |source_path|
|
|
135
140
|
next unless File.exist?(source_path)
|
|
136
141
|
|
|
137
142
|
filename = File.basename(source_path)
|
|
138
143
|
dest_path = File.join(@current_dir, filename)
|
|
144
|
+
current += 1
|
|
145
|
+
update_progress_modal(current, total, filename)
|
|
139
146
|
|
|
140
147
|
begin
|
|
141
148
|
if File.exist?(dest_path)
|
|
@@ -167,6 +174,8 @@ module Sergeant
|
|
|
167
174
|
end
|
|
168
175
|
end
|
|
169
176
|
|
|
177
|
+
@progress_modal = nil
|
|
178
|
+
|
|
170
179
|
# Clean up after operation
|
|
171
180
|
@marked_items.clear
|
|
172
181
|
@copied_items.clear
|
|
@@ -204,19 +213,28 @@ module Sergeant
|
|
|
204
213
|
error_count = 0
|
|
205
214
|
errors = []
|
|
206
215
|
|
|
216
|
+
total = @marked_items.count { |p| File.exist?(p) }
|
|
217
|
+
draw_progress_modal('Deleting Files', total)
|
|
218
|
+
current = 0
|
|
219
|
+
|
|
207
220
|
@marked_items.each do |item_path|
|
|
208
221
|
next unless File.exist?(item_path)
|
|
209
222
|
|
|
223
|
+
filename = File.basename(item_path)
|
|
224
|
+
current += 1
|
|
225
|
+
update_progress_modal(current, total, filename)
|
|
226
|
+
|
|
210
227
|
begin
|
|
211
228
|
FileUtils.rm_rf(item_path)
|
|
212
229
|
success_count += 1
|
|
213
230
|
rescue StandardError => e
|
|
214
231
|
error_count += 1
|
|
215
|
-
filename = File.basename(item_path)
|
|
216
232
|
errors << "#{filename}: #{e.message}"
|
|
217
233
|
end
|
|
218
234
|
end
|
|
219
235
|
|
|
236
|
+
@progress_modal = nil
|
|
237
|
+
|
|
220
238
|
# Clear marked items after deletion
|
|
221
239
|
@marked_items.clear
|
|
222
240
|
|
data/lib/sergeant/version.rb
CHANGED