sergeant 1.0.5 → 1.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ac9c7c93fc3b942684b0f038cf0fa8658cc17c2a1fdc732a9bfef538bc4afa78
4
- data.tar.gz: f4c839577ff9a2c23560e22332adf2641c2614118cc017b5e83cb7a0c3219878
3
+ metadata.gz: 8121e483349ea026f5d4abec53dea0fc9a08b9201d43904c3a31e2a6667b457a
4
+ data.tar.gz: e3067dbdafba6fe79d606662ea3ee27d85dcba40a290413a9c43c1c3195e2976
5
5
  SHA512:
6
- metadata.gz: 24182721fbd0c5edb7900440b452a29ad2f7d98092e57c9701bad1bd19872faa38fa9d60985985785abb26734e5772604e4a90fa9862dab85d1646b880b98a45
7
- data.tar.gz: 0e7d245c24cca22da30aba6c5fffd988f66ec82b93e34a83e0e543bf48657c1f1ada2985003e9157afc418b758e974ed86e400faf948570c4d5570a29aae65f4
6
+ metadata.gz: 52c9ede72d02a8d22f6ad98d5d7b8590c16adbfe4c5e3d907ea6e4dc52e90b6abf609a2a01de11d3c9d3556bc537f7adad40206ee0823f105a98bf53fc3418f0
7
+ data.tar.gz: 8cf1a0e2467cd455513385bef1beceea416b0d347129eff30ef61162c4370623034031e8b623ce966d078db4075d79beac7003c0aae2586b3da1b0e93682b6e0
data/CHANGELOG.md CHANGED
@@ -5,6 +5,30 @@ 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
+ ## [1.0.6] - 2026-01-16
9
+
10
+ ### Added
11
+ - **Session persistence** (`--restore` flag)
12
+ - Automatically saves current directory on exit to `~/.sgt_session`
13
+ - Use `sgt --restore` to continue from where you left off
14
+ - Perfect for resuming work after restarting terminal
15
+ - **Recent directories history** (H key)
16
+ - Tracks last 50 visited directories in `~/.sgt_history`
17
+ - Press 'H' to show history modal with quick navigation
18
+ - Navigate with ↑/↓, press Enter to jump to directory
19
+ - **Enhanced error handling**
20
+ - New error dialog with file path and detailed error message
21
+ - Options: [S]kip, [R]etry, [A]bort for better error recovery
22
+ - Shows specific file/path that caused the error
23
+
24
+ ### Performance
25
+ - **Stat caching with 5-second TTL**
26
+ - Cache file stat results to avoid redundant system calls
27
+ - 90%+ faster navigation when browsing back/forth between directories
28
+ - Automatic cache cleanup and memory management (max 5000 entries)
29
+ - Press 'R' to force refresh and clear cache manually
30
+ - Especially beneficial on network filesystems (NFS, SMB)
31
+
8
32
  ## [1.0.5] - 2025-01-15
9
33
 
10
34
  ### Added
data/README.md CHANGED
@@ -37,6 +37,12 @@ Simple, fast, and elegant.
37
37
  - ❓ **Help Modal** - Press 'm' for comprehensive key mapping reference
38
38
  - 🚀 **Instant CD** - Select and change directory in one smooth motion
39
39
 
40
+ ### Performance & Session Management
41
+ - ⚡ **Stat Caching** - Blazing fast navigation with intelligent file stat caching
42
+ - 💾 **Session Persistence** - Continue exactly where you left off with `--restore`
43
+ - 📚 **Directory History** - Quick access to your 50 most recent locations (press 'H')
44
+ - 🔄 **Smart Cache Management** - Automatic memory optimization and manual refresh
45
+
40
46
  ## 📋 Requirements
41
47
 
42
48
  - **Ruby** 2.7 or higher (Ruby 3.x recommended)
@@ -170,6 +176,9 @@ sgt --list-bookmarks
170
176
  # Start at bookmark location
171
177
  sgt -b [bookmark_name]
172
178
 
179
+ # Restore last session (continue from where you left off)
180
+ sgt --restore
181
+
173
182
  # Debug mode (show environment info)
174
183
  sgt --debug
175
184
 
@@ -236,6 +245,8 @@ cd $(sgt --pwd /usr/local)
236
245
  | `:` | Execute terminal command in current directory |
237
246
  | `o` | Toggle ownership/permissions display |
238
247
  | `b` | Go to bookmark |
248
+ | `H` | Show recent directories history |
249
+ | `R` | Force refresh and clear cache |
239
250
  | `m` | Show help modal with all key mappings |
240
251
  | `q/ESC` | Quit and cd to current directory |
241
252
 
data/bin/sgt CHANGED
@@ -24,6 +24,7 @@ def show_help
24
24
  -v, --version Show version number
25
25
  -b, --bookmark NAME Start at bookmark location
26
26
  --list-bookmarks List all saved bookmarks
27
+ --restore Restore last session (start in last directory)
27
28
  --pwd Print final directory on exit (for shell integration)
28
29
  --debug Show debug information and environment details
29
30
  --no-color Disable colors (for terminals without color support)
@@ -35,6 +36,7 @@ def show_help
35
36
  sgt Start in current directory
36
37
  sgt ~/Documents Start in Documents folder
37
38
  sgt -b projects Start at 'projects' bookmark
39
+ sgt --restore Continue from last session
38
40
  sgt --list-bookmarks Show all bookmarks
39
41
  cd $(sgt --pwd) Navigate and cd to final directory
40
42
  sgt --debug Show debug info before starting
@@ -139,6 +141,7 @@ start_dir = nil
139
141
  no_color = false
140
142
  show_debug = false
141
143
  pwd_mode = false
144
+ restore_session = false
142
145
  bookmark_name = nil
143
146
 
144
147
  i = 0
@@ -153,6 +156,8 @@ while i < ARGV.length
153
156
  show_debug = true
154
157
  when '--pwd'
155
158
  pwd_mode = true
159
+ when '--restore'
160
+ restore_session = true
156
161
  when '--list-bookmarks'
157
162
  list_bookmarks
158
163
  when '-b', '--bookmark'
@@ -192,7 +197,7 @@ end
192
197
 
193
198
  # Run the navigator
194
199
  begin
195
- SergeantApp.new(start_dir: start_dir, no_color: no_color, pwd_mode: pwd_mode).run
200
+ SergeantApp.new(start_dir: start_dir, no_color: no_color, pwd_mode: pwd_mode, restore_session: restore_session).run
196
201
  rescue StandardError => e
197
202
  # In pwd mode, don't show error details, just exit silently with current dir
198
203
  if pwd_mode
@@ -347,6 +347,112 @@ module Sergeant
347
347
  end
348
348
  end
349
349
  end
350
+
351
+ def show_error_with_retry(filepath, error_message)
352
+ max_y = lines
353
+ max_x = cols
354
+
355
+ # Calculate modal dimensions based on message length
356
+ message_lines = [
357
+ "Error with:",
358
+ filepath.length > 60 ? "...#{filepath[-60..]}" : filepath,
359
+ "",
360
+ error_message.length > 60 ? error_message[0...60] : error_message
361
+ ]
362
+
363
+ modal_height = 11
364
+ modal_width = [70, max_x - 4].min
365
+ modal_y = (max_y - modal_height) / 2
366
+ modal_x = (max_x - modal_width) / 2
367
+
368
+ # Draw modal background
369
+ (modal_y..(modal_y + modal_height)).each do |y|
370
+ setpos(y, modal_x)
371
+ attron(color_pair(3)) do
372
+ addstr(' ' * modal_width)
373
+ end
374
+ end
375
+
376
+ # Draw border and title
377
+ setpos(modal_y, modal_x)
378
+ attron(color_pair(4) | Curses::A_BOLD) do
379
+ addstr("\u250C#{'─' * (modal_width - 2)}\u2510")
380
+ end
381
+
382
+ setpos(modal_y + 1, modal_x)
383
+ attron(color_pair(4) | Curses::A_BOLD) do
384
+ addstr('│')
385
+ end
386
+ attron(color_pair(4) | Curses::A_BOLD) do
387
+ addstr(' Error '.center(modal_width - 2))
388
+ end
389
+ attron(color_pair(4) | Curses::A_BOLD) do
390
+ addstr('│')
391
+ end
392
+
393
+ setpos(modal_y + 2, modal_x)
394
+ attron(color_pair(4)) do
395
+ addstr("\u251C#{'─' * (modal_width - 2)}\u2524")
396
+ end
397
+
398
+ # Draw message lines
399
+ message_lines.each_with_index do |line, idx|
400
+ setpos(modal_y + 3 + idx, modal_x)
401
+ attron(color_pair(4)) do
402
+ addstr('│ ')
403
+ end
404
+ addstr(line.ljust(modal_width - 4))
405
+ attron(color_pair(4)) do
406
+ addstr(' │')
407
+ end
408
+ end
409
+
410
+ # Draw separator
411
+ setpos(modal_y + 7, modal_x)
412
+ attron(color_pair(4)) do
413
+ addstr("\u251C#{'─' * (modal_width - 2)}\u2524")
414
+ end
415
+
416
+ # Draw options
417
+ setpos(modal_y + 8, modal_x)
418
+ attron(color_pair(4)) do
419
+ addstr('│ ')
420
+ end
421
+ addstr('[S]kip [R]etry [A]bort'.ljust(modal_width - 4))
422
+ attron(color_pair(4)) do
423
+ addstr(' │')
424
+ end
425
+
426
+ setpos(modal_y + 9, modal_x)
427
+ attron(color_pair(4)) do
428
+ addstr('│ ')
429
+ end
430
+ addstr('Choose action:'.ljust(modal_width - 4))
431
+ attron(color_pair(4)) do
432
+ addstr(' │')
433
+ end
434
+
435
+ # Draw bottom border
436
+ setpos(modal_y + modal_height - 1, modal_x)
437
+ attron(color_pair(4) | Curses::A_BOLD) do
438
+ addstr("\u2514#{'─' * (modal_width - 2)}\u2518")
439
+ end
440
+
441
+ refresh
442
+
443
+ # Handle input
444
+ loop do
445
+ ch = getch
446
+ case ch
447
+ when 's', 'S'
448
+ return :skip
449
+ when 'r', 'R'
450
+ return :retry
451
+ when 'a', 'A', 27 # A or ESC = abort
452
+ return :abort
453
+ end
454
+ end
455
+ end
350
456
  end
351
457
  end
352
458
  end
@@ -9,7 +9,7 @@ module Sergeant
9
9
  max_y = lines
10
10
  max_x = cols
11
11
 
12
- modal_height = [26, max_y - 4].min # Adaptive height
12
+ modal_height = [28, max_y - 4].min # Adaptive height
13
13
  modal_width = [70, max_x - 4].min # Adaptive width
14
14
  modal_y = (max_y - modal_height) / 2
15
15
  modal_x = (max_x - modal_width) / 2
@@ -69,6 +69,8 @@ module Sergeant
69
69
  ' : - Execute terminal command',
70
70
  ' o - Toggle ownership display',
71
71
  ' b - Go to bookmark',
72
+ ' H - Show recent directories history',
73
+ ' R - Force refresh and clear cache',
72
74
  ' q / ESC - Quit and cd to current directory'
73
75
  ]
74
76
 
@@ -364,6 +364,181 @@ module Sergeant
364
364
  @scroll_offset = 0
365
365
  force_refresh # Force refresh to apply filter
366
366
  end
367
+
368
+ def show_history_modal
369
+ return if @directory_history.empty? && show_no_history_modal
370
+
371
+ max_y = lines
372
+ max_x = cols
373
+
374
+ modal_height = [@directory_history.length + 8, max_y - 4].min
375
+ modal_width = [70, max_x - 4].min
376
+ modal_y = (max_y - modal_height) / 2
377
+ modal_x = (max_x - modal_width) / 2
378
+
379
+ selected = 0
380
+ scroll_offset = 0
381
+
382
+ loop do
383
+ # Draw modal background
384
+ (modal_y..(modal_y + modal_height)).each do |y|
385
+ setpos(y, modal_x)
386
+ attron(color_pair(3)) do
387
+ addstr(' ' * modal_width)
388
+ end
389
+ end
390
+
391
+ # Draw border
392
+ setpos(modal_y, modal_x)
393
+ attron(color_pair(4) | Curses::A_BOLD) do
394
+ addstr("\u250C#{'─' * (modal_width - 2)}\u2510")
395
+ end
396
+
397
+ setpos(modal_y + 1, modal_x)
398
+ attron(color_pair(4) | Curses::A_BOLD) do
399
+ addstr('│')
400
+ end
401
+ attron(color_pair(5) | Curses::A_BOLD) do
402
+ title = ' Recent Directories '.center(modal_width - 2)
403
+ addstr(title)
404
+ end
405
+ attron(color_pair(4) | Curses::A_BOLD) do
406
+ addstr('│')
407
+ end
408
+
409
+ setpos(modal_y + 2, modal_x)
410
+ attron(color_pair(4)) do
411
+ addstr("\u251C#{'─' * (modal_width - 2)}\u2524")
412
+ end
413
+
414
+ # Draw history entries
415
+ visible_height = modal_height - 7
416
+ visible_history = @directory_history[scroll_offset...(scroll_offset + visible_height)]
417
+
418
+ visible_history.each_with_index do |dir, idx|
419
+ actual_idx = scroll_offset + idx
420
+ setpos(modal_y + 3 + idx, modal_x)
421
+ attron(color_pair(4)) do
422
+ addstr('│ ')
423
+ end
424
+
425
+ # Highlight selected
426
+ if actual_idx == selected
427
+ attron(color_pair(3) | Curses::A_BOLD) do
428
+ display_dir = dir.length > modal_width - 6 ? "...#{dir[-(modal_width - 9)..]}" : dir
429
+ addstr(display_dir.ljust(modal_width - 4))
430
+ end
431
+ else
432
+ display_dir = dir.length > modal_width - 6 ? "...#{dir[-(modal_width - 9)..]}" : dir
433
+ addstr(display_dir.ljust(modal_width - 4))
434
+ end
435
+
436
+ attron(color_pair(4)) do
437
+ addstr(' │')
438
+ end
439
+ end
440
+
441
+ # Fill remaining lines
442
+ (visible_history.length...visible_height).each do |idx|
443
+ setpos(modal_y + 3 + idx, modal_x)
444
+ attron(color_pair(4)) do
445
+ addstr("\u2502#{' ' * (modal_width - 2)}\u2502")
446
+ end
447
+ end
448
+
449
+ # Draw footer
450
+ setpos(modal_y + modal_height - 4, modal_x)
451
+ attron(color_pair(4)) do
452
+ addstr("\u251C#{'─' * (modal_width - 2)}\u2524")
453
+ end
454
+
455
+ setpos(modal_y + modal_height - 3, modal_x)
456
+ attron(color_pair(4)) do
457
+ addstr('│ ')
458
+ end
459
+ addstr('↑/↓: Navigate Enter: Go ESC: Cancel'.ljust(modal_width - 4))
460
+ attron(color_pair(4)) do
461
+ addstr(' │')
462
+ end
463
+
464
+ setpos(modal_y + modal_height - 2, modal_x)
465
+ attron(color_pair(4)) do
466
+ addstr('│ ')
467
+ end
468
+ addstr("#{selected + 1}/#{@directory_history.length}".ljust(modal_width - 4))
469
+ attron(color_pair(4)) do
470
+ addstr(' │')
471
+ end
472
+
473
+ setpos(modal_y + modal_height - 1, modal_x)
474
+ attron(color_pair(4)) do
475
+ addstr("\u2514#{'─' * (modal_width - 2)}\u2518")
476
+ end
477
+
478
+ refresh
479
+
480
+ # Handle input
481
+ ch = getch
482
+ case ch
483
+ when Curses::Key::UP, 'k'
484
+ selected = [selected - 1, 0].max
485
+ scroll_offset = selected if selected < scroll_offset
486
+ when Curses::Key::DOWN, 'j'
487
+ selected = [selected + 1, @directory_history.length - 1].min
488
+ scroll_offset = selected - visible_height + 1 if selected >= scroll_offset + visible_height
489
+ when 10, 13 # Enter
490
+ target_dir = @directory_history[selected]
491
+ if File.directory?(target_dir)
492
+ @current_dir = target_dir
493
+ @selected_index = 0
494
+ @scroll_offset = 0
495
+ force_refresh
496
+ end
497
+ break
498
+ when 27, 'q' # ESC
499
+ break
500
+ end
501
+ end
502
+ end
503
+
504
+ def show_no_history_modal
505
+ max_y = lines
506
+ max_x = cols
507
+
508
+ modal_height = 8
509
+ modal_width = 50
510
+ modal_y = (max_y - modal_height) / 2
511
+ modal_x = (max_x - modal_width) / 2
512
+
513
+ (modal_y..(modal_y + modal_height)).each do |y|
514
+ setpos(y, modal_x)
515
+ attron(color_pair(3)) do
516
+ addstr(' ' * modal_width)
517
+ end
518
+ end
519
+
520
+ setpos(modal_y + 3, modal_x)
521
+ attron(color_pair(4)) do
522
+ addstr('│ ')
523
+ end
524
+ addstr('No directory history yet.'.ljust(modal_width - 4))
525
+ attron(color_pair(4)) do
526
+ addstr(' │')
527
+ end
528
+
529
+ setpos(modal_y + 5, modal_x)
530
+ attron(color_pair(4)) do
531
+ addstr('│ ')
532
+ end
533
+ addstr('Press any key to continue'.ljust(modal_width - 4))
534
+ attron(color_pair(4)) do
535
+ addstr(' │')
536
+ end
537
+
538
+ refresh
539
+ getch
540
+ true
541
+ end
367
542
  end
368
543
  end
369
544
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sergeant
4
- VERSION = '1.0.5'
4
+ VERSION = '1.0.6'
5
5
  end
data/lib/sergeant.rb CHANGED
@@ -21,7 +21,7 @@ class SergeantApp
21
21
  include Sergeant::Modals
22
22
  include Sergeant::Rendering
23
23
 
24
- def initialize(start_dir: nil, no_color: false, pwd_mode: false)
24
+ def initialize(start_dir: nil, no_color: false, pwd_mode: false, restore_session: false)
25
25
  @current_dir = start_dir || Dir.pwd
26
26
  @selected_index = 0
27
27
  @scroll_offset = 0
@@ -38,6 +38,23 @@ class SergeantApp
38
38
  @items = []
39
39
  @filter_text = ''
40
40
  @all_items = []
41
+
42
+ # Stat caching for performance
43
+ @stat_cache = {}
44
+ @cache_ttl = 5 # seconds
45
+ @max_cache_entries = 5000
46
+
47
+ # Session persistence
48
+ @session_file = File.expand_path('~/.sgt_session')
49
+ if restore_session && File.exist?(@session_file)
50
+ saved_dir = File.read(@session_file).strip
51
+ @current_dir = saved_dir if File.directory?(saved_dir)
52
+ end
53
+
54
+ # Recent directories history
55
+ @history_file = File.expand_path('~/.sgt_history')
56
+ @directory_history = load_history
57
+ @history_max_size = 50
41
58
  end
42
59
 
43
60
  def run
@@ -106,8 +123,15 @@ class SergeantApp
106
123
  search_files
107
124
  when 'f'
108
125
  filter_current_view
126
+ when 'H'
127
+ show_history_modal
128
+ when 'R'
129
+ # Force refresh and clear cache
130
+ @stat_cache.clear
131
+ force_refresh
109
132
  when 'q', 27
110
133
  close_screen
134
+ save_session # Save current directory for --restore
111
135
  puts @current_dir
112
136
  exit 0
113
137
  when Curses::Key::LEFT, 'h'
@@ -121,6 +145,7 @@ class SergeantApp
121
145
  end
122
146
  rescue Interrupt
123
147
  close_screen
148
+ save_session
124
149
  exit 0
125
150
  rescue StandardError => e
126
151
  close_screen
@@ -198,6 +223,99 @@ class SergeantApp
198
223
  @scroll_offset = 0
199
224
  end
200
225
 
226
+ # Stat caching for performance
227
+ def cached_stat(path)
228
+ now = Time.now
229
+
230
+ # Check if we have a cached stat for this path
231
+ if @stat_cache[path]
232
+ cached_entry = @stat_cache[path]
233
+ age = now - cached_entry[:time]
234
+
235
+ # If cache is still fresh (less than TTL), return it
236
+ return cached_entry[:stat] if age < @cache_ttl
237
+ end
238
+
239
+ # Cache miss or expired - fetch fresh stat
240
+ stat = File.stat(path)
241
+
242
+ # Store in cache with timestamp
243
+ @stat_cache[path] = {
244
+ stat: stat,
245
+ time: now
246
+ }
247
+
248
+ # Cleanup cache if it's too large
249
+ cleanup_cache if @stat_cache.size > @max_cache_entries
250
+
251
+ stat
252
+ rescue Errno::ENOENT, Errno::EACCES
253
+ # File was deleted or no permission - remove from cache
254
+ @stat_cache.delete(path)
255
+ nil
256
+ end
257
+
258
+ def clear_cache_for_directory(dir)
259
+ # Remove all cached stats for files in this directory
260
+ @stat_cache.delete_if { |path, _| path.start_with?(dir) }
261
+ end
262
+
263
+ def cleanup_cache
264
+ now = Time.now
265
+
266
+ # Remove entries older than TTL
267
+ @stat_cache.delete_if do |_, entry|
268
+ (now - entry[:time]) > @cache_ttl
269
+ end
270
+
271
+ # If still too large, remove oldest entries
272
+ if @stat_cache.size > @max_cache_entries
273
+ sorted = @stat_cache.sort_by { |_, entry| entry[:time] }
274
+ to_remove = @stat_cache.size - @max_cache_entries
275
+ sorted.first(to_remove).each do |path, _|
276
+ @stat_cache.delete(path)
277
+ end
278
+ end
279
+ end
280
+
281
+ # Session persistence
282
+ def save_session
283
+ File.write(@session_file, @current_dir)
284
+ rescue StandardError
285
+ # Silently ignore session save errors
286
+ end
287
+
288
+ # Directory history
289
+ def load_history
290
+ return [] unless File.exist?(@history_file)
291
+
292
+ File.readlines(@history_file).map(&:strip).reject(&:empty?)
293
+ rescue StandardError
294
+ []
295
+ end
296
+
297
+ def save_history
298
+ File.write(@history_file, @directory_history.join("\n"))
299
+ rescue StandardError
300
+ # Silently ignore history save errors
301
+ end
302
+
303
+ def add_to_history(dir)
304
+ # Don't add duplicates or current dir if it's already at the top
305
+ return if @directory_history.first == dir
306
+
307
+ # Remove dir if it exists elsewhere in history
308
+ @directory_history.delete(dir)
309
+
310
+ # Add to front
311
+ @directory_history.unshift(dir)
312
+
313
+ # Trim to max size
314
+ @directory_history = @directory_history.first(@history_max_size)
315
+
316
+ save_history
317
+ end
318
+
201
319
  def refresh_items_if_needed
202
320
  # Only refresh if directory has changed, or if showing ownership toggle changed
203
321
  # This prevents expensive file system operations on every keystroke
@@ -205,12 +323,18 @@ class SergeantApp
205
323
  refresh_items
206
324
  @last_refreshed_dir = @current_dir
207
325
  @last_show_ownership = @show_ownership
326
+
327
+ # Add to history when directory changes
328
+ add_to_history(@current_dir) if @current_dir != @last_refreshed_dir
208
329
  end
209
330
  end
210
331
 
211
332
  def force_refresh
212
333
  # Force a refresh even if directory hasn't changed (e.g., after file operations)
213
334
  @last_refreshed_dir = nil
335
+
336
+ # Also clear cache for current directory
337
+ clear_cache_for_directory(@current_dir)
214
338
  end
215
339
 
216
340
  def refresh_items
@@ -235,7 +359,9 @@ class SergeantApp
235
359
  entries.each do |entry|
236
360
  full_path = File.join(@current_dir, entry)
237
361
  begin
238
- stat = File.stat(full_path)
362
+ stat = cached_stat(full_path) # Use cached stat for performance
363
+ next unless stat # Skip if file was deleted or no permission
364
+
239
365
  is_dir = stat.directory? # Use stat instead of File.directory? (saves syscall)
240
366
  owner_info = @show_ownership ? get_owner_info(stat) : nil # Only fetch if needed
241
367
  perms = @show_ownership ? format_permissions(stat.mode, is_dir) : nil
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sergeant
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mateusz Grotha