cetus 0.1.36 → 0.1.38

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/bin/cetus +1292 -1092
  3. data/cetus.gemspec +1 -1
  4. data/scripts/encrypt.sh +1 -0
  5. data/scripts/zip +1 -0
  6. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 273d25acae029a8c12d1e07bd80396c7f6eeb05f6136b112be702a7cebd7a01d
4
- data.tar.gz: 25891b9fc8105132be8cb4325f23767fc2abf79096b98bcee9c11a41f0ffb612
3
+ metadata.gz: 0adbfa483176301769749c1f1756cf6ae616ee572ad5b2ca56c28b2339f0386f
4
+ data.tar.gz: 2506a1e5264337d8648022083d7c37a6616d36e1be12b65d29b5172211cbdc67
5
5
  SHA512:
6
- metadata.gz: 905206ed55286799c28ef2e3c9fee6fc1eedc34730ac4632138c117ce747be62da7ed377c44414ba8499f3cfc2a2b539c4fb2b868522ef9ffc775aa0528b1d43
7
- data.tar.gz: 53e8235558e298e9f08dbaefd5f65fcde07a821e8052ee630db51bc74e340a56ddae0abc430028dfda702700c659686ad449c342250d4cc9a26ef5387eadb98c
6
+ metadata.gz: 7e18775e80ebc7cf5367e4040fb27c73eb2cff2e0cabac603afd1958de18cc1a82055b51c3b13eaaef2b03c0937b9aeff045a29f255b4ab8f7221821e0dc97f0
7
+ data.tar.gz: d7efa83ac9196fc74768e6fad5e87df973ec9ba49a44921310462cfe834cd53bb288be52d76f92d7ca6d45b9363e0545dac584ea5a3e47dad28e2fd0344c0daa
data/bin/cetus CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  # --------------------------------------------------------------------------- #
3
5
  # File: cetus
4
6
  # Description: Fast file navigation, a tiny version of zfm
@@ -6,7 +8,7 @@
6
8
  # Author: rkumar http://github.com/rkumar/cetus/
7
9
  # Date: 2013-02-17 - 17:48
8
10
  # License: GPL
9
- # Last update: 2019-04-14 19:11
11
+ # Last update: 2019-04-19 09:51
10
12
  # --------------------------------------------------------------------------- #
11
13
  # cetus.rb Copyright (C) 2012-2019 rahul kumar
12
14
  # == CHANGELOG
@@ -26,19 +28,19 @@ require 'shellwords'
26
28
  # https://docs.ruby-lang.org/en/2.6.0/FileUtils.html
27
29
  require 'fileutils'
28
30
  require 'logger'
29
- # @log = Logger.new(File.expand_path '~/tmp/log.txt')
30
- @log = Logger.new('log.txt')
31
+ @log = Logger.new(File.expand_path('~/tmp/log.txt'))
32
+ # @log = Logger.new('log.txt')
31
33
 
32
34
  ## INSTALLATION
33
35
  # copy into PATH
34
36
  # alias c=~/bin/cetus.rb
35
37
  # c
36
38
 
37
- VERSION = '0.1.36.0'.freeze
39
+ VERSION = '0.1.38.0'
38
40
  CONFIG_PATH = ENV['XDG_CONFIG_HOME'] || File.join(ENV['HOME'], '.config')
39
- CONFIG_FILE = "#{CONFIG_PATH}/cetus/conf.yml".freeze
41
+ CONFIG_FILE = "#{CONFIG_PATH}/cetus/conf.yml"
40
42
 
41
- $bindings = {
43
+ @bindings = {
42
44
  '`' => 'main_menu',
43
45
  '=' => 'toggle_menu',
44
46
  'M-s' => 'selection_menu',
@@ -50,14 +52,14 @@ $bindings = {
50
52
  'C-s' => 'toggle_select',
51
53
  'C-r' => 'reduce',
52
54
  'C-g' => 'debug_vars',
53
- '*' => 'toggle_selection_mode',
55
+ '*' => 'toggle_multiple_selection',
54
56
  'M-a' => 'select_all',
55
57
  'M-A' => 'unselect_all',
56
58
  '!' => 'execute',
57
59
  ',' => 'goto_parent_dir',
58
60
  '~' => 'goto_home_dir',
59
61
  '-' => 'goto_previous_dir',
60
- '+' => 'goto_dir', # 2019-03-07 - TODO: change binding
62
+ '+' => 'goto_dir', # 2019-03-07 - TODO: change binding
61
63
  '.' => 'pop_dir',
62
64
  ':' => 'subcommand',
63
65
  "'" => 'goto_bookmark',
@@ -65,6 +67,10 @@ $bindings = {
65
67
  '/' => 'enter_regex',
66
68
  'M-p' => 'prev_page',
67
69
  'M-n' => 'next_page',
70
+ 'PgUp' => 'prev_page',
71
+ 'PgDn' => 'next_page',
72
+ 'Home' => 'goto_top',
73
+ 'End' => 'goto_end',
68
74
  'SPACE' => 'next_page:Page Down',
69
75
  'M-f' => 'select_from_visited_files',
70
76
  'M-d' => 'select_from_used_dirs',
@@ -94,7 +100,7 @@ $bindings = {
94
100
  'C-b' => 'cursor_scroll_up',
95
101
  'UP' => 'cursor_up',
96
102
  'DOWN' => 'cursor_dn',
97
- 'C-SPACE' => 'visual_mode_toggle',
103
+ 'C-SPACE' => 'toggle_visual_mode',
98
104
  '@' => 'scripts',
99
105
  '#' => 'generators',
100
106
 
@@ -109,51 +115,51 @@ $bindings = {
109
115
  }
110
116
 
111
117
  ## clean this up a bit, copied from shell program and macro'd
112
- $kh = {}
113
- $kh["\eOP"] = 'F1'
114
- $kh["\e[A"] = 'UP'
115
- $kh["\e[5~"] = 'PGUP'
116
- $kh[''] = 'ESCAPE'
117
- KEY_PGDN = "\e[6~".freeze
118
- KEY_PGUP = "\e[5~".freeze
118
+ @kh = {}
119
+ @kh["\eOP"] = 'F1'
120
+ @kh["\e[A"] = 'UP'
121
+ @kh["\e[5~"] = 'PGUP'
122
+ @kh[''] = 'ESCAPE'
123
+ KEY_PGDN = "\e[6~"
124
+ KEY_PGUP = "\e[5~"
119
125
  ## I needed to replace the O with a [ for this to work
120
126
  # in Vim Home comes as ^[OH whereas on the command line it is correct as ^[[H
121
- KEY_HOME = ''.freeze
122
- KEY_END = "\e[F".freeze
123
- KEY_F1 = "\eOP".freeze
124
- KEY_UP = "\e[A".freeze
125
- KEY_DOWN = "\e[B".freeze
126
-
127
- $kh[KEY_PGDN] = 'PgDn'
128
- $kh[KEY_PGUP] = 'PgUp'
129
- $kh[KEY_HOME] = 'Home'
130
- $kh[KEY_END] = 'End'
131
- $kh[KEY_F1] = 'F1'
132
- $kh[KEY_UP] = 'UP'
133
- $kh[KEY_DOWN] = 'DOWN'
134
- KEY_LEFT = ''.freeze
135
- KEY_RIGHT = ''.freeze
136
- $kh["\eOQ"] = 'F2'
137
- $kh["\eOR"] = 'F3'
138
- $kh["\eOS"] = 'F4'
139
- $kh[KEY_LEFT] = 'LEFT'
140
- $kh[KEY_RIGHT] = 'RIGHT'
141
- KEY_F5 = '[15~'.freeze
142
- KEY_F6 = '[17~'.freeze
143
- KEY_F7 = '[18~'.freeze
144
- KEY_F8 = '[19~'.freeze
145
- KEY_F9 = '[20~'.freeze
146
- KEY_F10 = '[21~'.freeze
147
- KEY_S_F1 = ''.freeze
148
- $kh[KEY_F5] = 'F5'
149
- $kh[KEY_F6] = 'F6'
150
- $kh[KEY_F7] = 'F7'
151
- $kh[KEY_F8] = 'F8'
152
- $kh[KEY_F9] = 'F9'
153
- $kh[KEY_F10] = 'F10'
127
+ KEY_HOME = ''
128
+ KEY_END = "\e[F"
129
+ KEY_F1 = "\eOP"
130
+ KEY_UP = "\e[A"
131
+ KEY_DOWN = "\e[B"
132
+
133
+ @kh[KEY_PGDN] = 'PgDn'
134
+ @kh[KEY_PGUP] = 'PgUp'
135
+ @kh[KEY_HOME] = 'Home'
136
+ @kh[KEY_END] = 'End'
137
+ @kh[KEY_F1] = 'F1'
138
+ @kh[KEY_UP] = 'UP'
139
+ @kh[KEY_DOWN] = 'DOWN'
140
+ KEY_LEFT = ''
141
+ KEY_RIGHT = ''
142
+ @kh["\eOQ"] = 'F2'
143
+ @kh["\eOR"] = 'F3'
144
+ @kh["\eOS"] = 'F4'
145
+ @kh[KEY_LEFT] = 'LEFT'
146
+ @kh[KEY_RIGHT] = 'RIGHT'
147
+ KEY_F5 = '[15~'
148
+ KEY_F6 = '[17~'
149
+ KEY_F7 = '[18~'
150
+ KEY_F8 = '[19~'
151
+ KEY_F9 = '[20~'
152
+ KEY_F10 = '[21~'
153
+ KEY_S_F1 = ''
154
+ @kh[KEY_F5] = 'F5'
155
+ @kh[KEY_F6] = 'F6'
156
+ @kh[KEY_F7] = 'F7'
157
+ @kh[KEY_F8] = 'F8'
158
+ @kh[KEY_F9] = 'F9'
159
+ @kh[KEY_F10] = 'F10'
154
160
  # testing out shift+Function. these are the codes my kb generates
155
- $kh[KEY_S_F1] = 'S-F1'
156
- $kh[''] = 'S-F2'
161
+ @kh[KEY_S_F1] = 'S-F1'
162
+ @kh[''] = 'S-F2'
157
163
 
158
164
  # copied from fff
159
165
  def clear_screen
@@ -166,8 +172,8 @@ def clear_screen
166
172
  # Also sets cursor to (0,0).
167
173
  # ENV["TMUX:+\e[2J]"],
168
174
  printf("\e[%sH\e[9999C\e[1J\e[1;%sr", \
169
- $glines - 0, # was 2
170
- $glines) # was grows
175
+ @glines - 0, # was 2
176
+ @glines) # was grows
171
177
  end
172
178
 
173
179
  # copied from fff
@@ -196,9 +202,9 @@ def setup_terminal
196
202
  # '\e[2J': Clear the screen.
197
203
  # '\e[1;Nr': Limit scrolling to scrolling area.
198
204
  # Also sets cursor to (0,0).
199
- # printf("\e[?1049h\e[?7l\e[?25l\e[2J\e[1;%sr", $glines)
205
+ # printf("\e[?1049h\e[?7l\e[?25l\e[2J\e[1;%sr", @glines)
200
206
  # 2019-03-29 - XXX temporarily not hiding cursor to see if we can place it.
201
- printf("\e[?1049h\e[?7l\e[?25h\e[2J\e[1;%sr", $glines)
207
+ printf("\e[?1049h\e[?7l\e[?25h\e[2J\e[1;%sr", @glines)
202
208
  # earlier glines was grows
203
209
 
204
210
  # Hide echoing of user input
@@ -214,6 +220,10 @@ def readline prompt='>'
214
220
  print "\e[?25h"
215
221
  system 'stty echo'
216
222
  begin
223
+ if prompt.length > 40
224
+ puts prompt
225
+ prompt = '>'
226
+ end
217
227
  target = Readline.readline(prompt, true)
218
228
  rescue Interrupt
219
229
  return nil
@@ -256,7 +266,7 @@ def get_char
256
266
  # puts "got #{k}"
257
267
  buff += k.chr
258
268
  else
259
- x = $kh[buff]
269
+ x = @kh[buff]
260
270
  return x if x
261
271
 
262
272
  # puts "returning with #{buff}"
@@ -280,36 +290,37 @@ end
280
290
 
281
291
  ## GLOBALS
282
292
  # hints or shortcuts to get to files without moving
283
- $IDX = ('a'..'y').to_a
284
- $IDX.delete 'q'
285
- $IDX.concat ('za'..'zz').to_a
286
- $IDX.concat ('Za'..'Zz').to_a
287
- $IDX.concat ('ZA'..'ZZ').to_a
288
-
289
- $selected_files = []
290
- $bookmarks = {}
291
- $mode = nil
292
- $glines = `tput lines`.to_i
293
- $gcols = `tput cols`.to_i
294
- $grows = $glines - 3 # can be a func
295
- # $pagesize = 60
296
- $gviscols = 3
297
- $pagesize = $grows * $gviscols # can be a func
298
- $stact = 0 # used when panning a folder to next column
299
- # $editor_mode = true
300
- $editor_mode = false # changed 2018-03-12 - so we start in pager mode
301
- $enhanced_mode = true
302
- $visual_block_start = nil
293
+ IDX = ('a'..'y').to_a
294
+ IDX.delete 'q'
295
+ IDX.concat ('za'..'zz').to_a
296
+ IDX.concat ('Za'..'Zz').to_a
297
+ IDX.concat ('ZA'..'ZZ').to_a
298
+ IDX.freeze
299
+
300
+ @selected_files = []
301
+ @bookmarks = {}
302
+ @mode = nil
303
+ @glines = `tput lines`.to_i
304
+ @gcols = `tput cols`.to_i
305
+ @grows = @glines - 3 # can be a func
306
+ # @pagesize = 60
307
+ @gviscols = 3
308
+ @pagesize = @grows * @gviscols # can be a func
309
+ @stact = 0 # used when panning a folder to next column
310
+ # @editor_mode = true
311
+ @editor_mode = false # changed 2018-03-12 - so we start in pager mode
312
+ @enhanced_mode = true
313
+ @visual_block_start = nil
303
314
  PAGER_COMMAND = {
304
315
  text: 'most',
305
316
  image: 'open',
306
317
  zip: 'tar ztvf %% | most',
307
318
  unknown: 'open'
308
- }
309
- $dir_position = {}
310
- @movement = @old_cursor = nil # cursor movement has happened only, don't repaint
311
- $selection_mode = 1 # single select
319
+ }.freeze
320
+ @dir_position = {}
321
+ @movement = @old_cursor = nil # cursor movement has happened only, don't repaint
312
322
  ## FLAGS
323
+ @multiple_selection = true # single select
313
324
  @group_dirs = true
314
325
  # truncate long filenames from :right, :left or :center.
315
326
  @truncate_from = :center
@@ -319,26 +330,56 @@ $selection_mode = 1 # single select
319
330
  @selected_files_escaped_flag = false
320
331
  @keys_to_clear = nil
321
332
 
333
+ # See toggle_value
334
+ # we need to set these on startup
335
+ @toggles = {
336
+ ignore_case: true,
337
+ # group_directories: true,
338
+ long_listing: false,
339
+ enhanced_mode: true,
340
+ visual_mode: false,
341
+ display_file_stats: true,
342
+ toggle_selected_files_fullpath_flag: false,
343
+ toggle_selected_files_escaped_flag: false,
344
+ multiple_selection: true,
345
+ editor_mode: false,
346
+ selection_mode: false, # typing hint adds to selection, does not open
347
+ debug_flag: false,
348
+ toggle_filename_status_line: true
349
+ }
350
+ # @cycles = { truncate_from: :center,
351
+ # show_hidden: nil }
352
+ # @enums = {
353
+ # truncate_from: %i[left right center],
354
+ # show_hidden: [nil, 'D']
355
+ # }
356
+ # var is name of variable to be set
357
+ @options = {
358
+ truncate_from: { current: :center, values: %i[left right center], var: :truncate_from },
359
+ group_directories: { current: :first, values: %i[first none last] },
360
+ show_hidden: { current: nil, values: [nil, 'D'], var: :hidden }
361
+ }
362
+
322
363
  ## ----------------- CONSTANTS ----------------- ##
323
- GMARK = '*'.freeze
324
- CURMARK = '>'.freeze
364
+ GMARK = '*'
365
+ CURMARK = '>'
325
366
  MSCROLL = 10
326
- SPACE = ' '.freeze
327
- SEPARATOR = '-------'.freeze
328
- CLEAR = "\e[0m".freeze
329
- BOLD = "\e[1m".freeze
330
- BOLD_OFF = "\e[22m".freeze
331
- RED = "\e[31m".freeze
332
- ON_RED = "\e[41m".freeze
333
- GREEN = "\e[32m".freeze
334
- YELLOW = "\e[33m".freeze
335
- BLUE = "\e[1;34m".freeze
336
- MAGENTA = "\e[35m".freeze
337
- CYAN = "\e[36m".freeze
338
-
339
- ON_BLUE = "\e[44m".freeze
340
- REVERSE = "\e[7m".freeze
341
- UNDERLINE = "\e[4m".freeze
367
+ SPACE = ' '
368
+ SEPARATOR = '-------'
369
+ CLEAR = "\e[0m"
370
+ BOLD = "\e[1m"
371
+ BOLD_OFF = "\e[22m"
372
+ RED = "\e[31m"
373
+ ON_RED = "\e[41m"
374
+ GREEN = "\e[32m"
375
+ YELLOW = "\e[33m"
376
+ BLUE = "\e[1;34m"
377
+ MAGENTA = "\e[35m"
378
+ CYAN = "\e[36m"
379
+
380
+ ON_BLUE = "\e[44m"
381
+ REVERSE = "\e[7m"
382
+ UNDERLINE = "\e[4m"
342
383
  CURSOR_COLOR = REVERSE
343
384
 
344
385
  # NOTE: that osx uses LSCOLORS which only has colors for filetypes not
@@ -351,45 +392,44 @@ CURSOR_COLOR = REVERSE
351
392
 
352
393
  # This hash contains color codes for extensions. It is updated from
353
394
  # LS_COLORS.
354
- $ls_color = {
395
+ @ls_color = {
355
396
  '.rb' => RED,
356
397
  '.tgz' => MAGENTA,
357
398
  '.zip' => MAGENTA,
358
399
  '.torrent' => GREEN,
359
400
  '.srt' => GREEN,
360
- '.part' => "\e[40;31;01m",
401
+ '.part' => "\e[40;31;01m",
361
402
  '.sh' => CYAN
362
403
  }
363
404
  # This hash contains colors for file patterns, updated from LS_COLORS
364
- $ls_pattern = {}
405
+ @ls_pattern = {}
365
406
  # This hash contains colors for file types, updated from LS_COLORS
366
407
  # Default values in absence of LS_COLORS
367
- $ls_ftype = {
408
+ @ls_ftype = {
368
409
  'directory' => BLUE,
369
- 'link' => "\e[01;36m",
370
- 'mi' => "\e[01;31;7m",
371
- 'or' => "\e[40;31;01m",
372
- 'ex' => "\e[01;32m"
410
+ 'link' => "\e[01;36m",
411
+ 'mi' => "\e[01;31;7m",
412
+ 'or' => "\e[40;31;01m",
413
+ 'ex' => "\e[01;32m"
373
414
  }
374
415
  ## --------------------------------------------- ##
375
416
 
376
- $patt = nil
377
- $ignorecase = true
378
- $quitting = false
379
- $modified = $writing = false
380
- $visited_files = []
417
+ @patt = nil
418
+ @ignorecase = true
419
+ @quitting = false
420
+ @modified = @writing = false
421
+ @visited_files = []
381
422
  ## dir stack for popping
382
- $visited_dirs = []
423
+ @visited_dirs = []
383
424
  ## dirs where some work has been done, for saving and restoring
384
- $used_dirs = []
425
+ @used_dirs = []
385
426
  # zsh o = order m = modified time
386
- $default_sort_order = 'Om'
387
- $sorto = $default_sort_order
388
- $viewctr = 0
389
- $history = []
427
+ @default_sort_order = 'Om'
428
+ @sorto = @default_sort_order
429
+ @viewctr = 0
390
430
  ## sta is where view (viewport) begins, cursor is current row/file
391
- $sta = $cursor = 0
392
- $visual_mode = false
431
+ @sta = @cursor = 0
432
+ @visual_mode = false
393
433
  @status_color = 4 # status line, can be 2 3 4 5 6
394
434
  @status_color_right = 8 # status line right part
395
435
 
@@ -406,20 +446,21 @@ def read_directory
406
446
  # -r Ignore the escape conventions of echo.
407
447
  # zshglob M = MARK_DIRS
408
448
 
409
- $filterstr ||= 'M'
410
- # $files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}#{$filterstr})'`.split("\n")
411
- $files = list_files
412
- $files = group_directories_first($files) if @group_dirs
413
- return unless $enhanced_mode
449
+ @filterstr ||= 'M' # XXX can we remove from here
450
+ # @files = `zsh -c 'print -rl -- *(#{@sorto}#{@hidden}#{@filterstr})'`.split("\n")
451
+ # @files = list_files
452
+ list_files
453
+ # @files = group_directories_first(@files) if @toggles[:group_directories]
454
+ group_directories_first
455
+ return unless cget(:enhanced_mode)
414
456
 
415
457
  enhance_file_list
416
- $files = $files.uniq
458
+ @files = @files.uniq
417
459
  end
418
460
 
419
461
  # return a list of directory contents sorted as per sort order
420
462
  # NOTE: FNM_CASEFOLD does not work with Dir.glob
421
- def list_files dir='*', sorto=$sorto, hidden=$hidden, filter=$filterstr
422
-
463
+ def list_files dir='*', sorto=@sorto, hidden=@hidden, _filter=@filterstr
423
464
  dir += '/*' if File.directory?(dir)
424
465
  dir = dir.gsub('//', '/')
425
466
 
@@ -444,7 +485,7 @@ def list_files dir='*', sorto=$sorto, hidden=$hidden, filter=$filterstr
444
485
 
445
486
  # sort by time and then reverse so latest first.
446
487
  sorted_files = if hidden == 'D'
447
- Dir.glob(dir, File::FNM_DOTMATCH)
488
+ Dir.glob(dir, File::FNM_DOTMATCH) - %w[. ..]
448
489
  else
449
490
  Dir.glob(dir)
450
491
  end
@@ -461,14 +502,15 @@ def list_files dir='*', sorto=$sorto, hidden=$hidden, filter=$filterstr
461
502
  end
462
503
  end
463
504
 
464
- sorted_files.sort! { |w1, w2| w1.casecmp(w2) } if func == :path && $ignorecase
505
+ sorted_files.sort! { |w1, w2| w1.casecmp(w2) } if func == :path && cget(:ignore_case)
465
506
 
466
507
  # zsh gives mtime sort with latest first, ruby gives latest last
467
508
  sorted_files.reverse! if sorto[0] == 'O'
468
509
 
469
510
  # add slash to directories
470
511
  sorted_files = add_slash sorted_files
471
- return sorted_files
512
+ # return sorted_files
513
+ @files = sorted_files
472
514
  end
473
515
  # ------------- end of read_directory --------------------------------#
474
516
 
@@ -484,61 +526,61 @@ end
484
526
 
485
527
  # ------------------- create_viewport ------------------ #
486
528
  def create_viewport
487
- $view = if $patt
488
- if $ignorecase
489
- $files.grep(/#{$patt}/i)
529
+ @view = if @patt
530
+ if cget(:ignore_case)
531
+ @files.grep(/#{@patt}/i)
490
532
  else
491
- $files.grep(/#{$patt}/)
533
+ @files.grep(/#{@patt}/)
492
534
  end
493
535
  else
494
- $files
536
+ @files
495
537
  end
496
538
 
497
- fl = $view.size
498
- $sta = 0 if $sta >= fl || $sta < 0
499
- $cursor = 0 if $cursor >= fl || $cursor < 0
539
+ fl = @view.size
540
+ @sta = 0 if @sta >= fl || @sta < 0
541
+ @cursor = 0 if @cursor >= fl || @cursor < 0
500
542
 
501
543
  # NOTE if we make cursor zero, then it can be < sta so in the next line
502
544
  # it will be made equal to sta which we may not want
503
- $cursor = $sta if $sta > $cursor
545
+ @cursor = @sta if @sta > @cursor
504
546
 
505
547
  # viewport are the files that are visible, subset of view
506
- $viewport = $view[$sta, $pagesize]
548
+ @viewport = @view[@sta, @pagesize]
507
549
  end
508
550
  # ------------- end of create_viewport --------------------------------#
509
551
 
510
552
  # ------------------- print_title ------------------ #
511
553
  def print_title
512
-
513
554
  # print help line and version
514
555
  print "#{GREEN}#{@help} #{BLUE}cetus #{VERSION}#{CLEAR}\n"
515
556
 
516
557
  # print 1 of n files, sort order, filter etc details
517
- $title ||= Dir.pwd.sub(ENV['HOME'], '~')
558
+ @title ||= Dir.pwd.sub(ENV['HOME'], '~')
518
559
 
519
560
  # Add bookmark next to name of dir, if exists
520
- bm = $bookmarks.key(Dir.pwd)
561
+ # FIXME This should not happen in other listings like find selected files etc
562
+ bm = @bookmarks.key(Dir.pwd)
521
563
  bm = " ('#{bm})" if bm
522
564
 
523
- fin = $sta + $viewport.size
524
- fl = $view.size
565
+ fin = @sta + @viewport.size
566
+ fl = @view.size
525
567
 
526
568
  # fix count of entries so separator and enhanced entries don't show up
527
- if $enhanced_mode
528
- ix = $viewport.index SEPARATOR
529
- fin = $sta + ix if ix
569
+ if cget(:enhanced_mode)
570
+ ix = @viewport.index SEPARATOR
571
+ fin = @sta + ix if ix
530
572
 
531
- ix = $view.index SEPARATOR
573
+ ix = @view.index SEPARATOR
532
574
  fl = ix if ix
533
575
  end
534
576
 
535
- t = fl.zero? ? "#{$title}#{bm} No files." : "#{$title}#{bm} #{$sta + 1} to #{fin} of #{fl} #{$sorto} F:#{$filterstr}"
577
+ t = fl.zero? ? "#{@title}#{bm} No files." : "#{@title}#{bm} #{@sta + 1} to #{fin} of #{fl} #{@sorto} F:#{@filterstr}"
536
578
 
537
579
  # don't exceed columns while printing
538
- t = t[t.size - $gcols..-1] if t.size >= $gcols
580
+ t = t[t.size - @gcols..-1] if t.size >= @gcols
539
581
 
540
582
  print "#{BOLD}#{t}#{CLEAR}\n"
541
- print "EMPTY" if fl.zero?
583
+ print 'EMPTY' if fl.zero?
542
584
  end
543
585
  # ------------- end of print_title --------------------------------#
544
586
 
@@ -547,42 +589,41 @@ end
547
589
  # called when page changes, so we only put directory name)
548
590
  # NOTE: called only from draw_directory.
549
591
  def status_line
550
- # prompt
551
- v_mm = $mode ? "[#{$mode}] " : ''
552
- cf = current_file
553
- $message = ' | No matches. Press ESCAPE' if $patt && !cf
592
+ # prompt
593
+ v_mm = @mode ? "[#{@mode}] " : ''
594
+ cf = current_file
595
+ @message = ' | No matches. Press ESCAPE' if @patt && !cf
554
596
 
555
- clear_last_line
597
+ clear_last_line
556
598
 
557
- # Print the filename at the right side of the status line
558
- # sometimes due to search, there is no file
559
- if cf
560
- if @debug_flag
561
- # XXX this will not work on file basis FIXME
562
- print_debug_info cf
563
- else
564
- # print_on_right "#{Dir.pwd}"
565
- print_filename_status_line if @filename_status_line
566
- end
567
- end
568
- # move to beginning of line, reset text mode after printing
569
- # patt and message are together, no gap, why not ? 2019-04-08 -
570
- if $patt && $patt != ''
571
- patt = "[/#{$patt}]"
572
- patt[-1] = '/i]' if $ignorecase
599
+ # Print the filename at the right side of the status line
600
+ # sometimes due to search, there is no file
601
+ if cf
602
+ if cget(:debug_flag)
603
+ # XXX this will not work on file basis FIXME
604
+ print_debug_info cf
605
+ else
606
+ # print_on_right "#{Dir.pwd}"
607
+ print_filename_status_line if @filename_status_line
573
608
  end
574
- # bring cursor to start of line
575
- # add background color
576
- # print mode
577
- # print search pattern if any
578
- # print message if any
579
- # print "\r#{v_mm}#{patt}#{$message}\e[m"
580
- print "\r\e[33;4#{@status_color}m#{v_mm}#{patt}#{$message}\e[m"
581
-
609
+ end
610
+ # move to beginning of line, reset text mode after printing
611
+ # patt and message are together, no gap, why not ? 2019-04-08 -
612
+ if @patt && @patt != ''
613
+ patt = "[/#{@patt}" + ']' # to get unfrozen string
614
+ patt[-1] = '/i]' if cget(:ignore_case)
615
+ end
616
+ # bring cursor to start of line
617
+ # add background color
618
+ # print mode
619
+ # print search pattern if any
620
+ # print message if any
621
+ # print "\r#{v_mm}#{patt}#{@message}\e[m"
622
+ print "\r\e[33;4#{@status_color}m#{v_mm}#{patt}#{@message}\e[m"
582
623
  end
583
624
 
584
- def print_debug_info cf=current_file()
585
- print_on_right "len:#{cf.length}/#{$temp_wid} = #{$sta},#{$cursor},#{$stact},#{$viewport.size},#{$grows} | #{cf}"
625
+ def print_debug_info cf=current_file
626
+ print_on_right "len:#{cf.length}/#{@temp_wid} = #{@sta},#{@cursor},#{@stact},#{@viewport.size},#{@grows} | #{cf}"
586
627
  end
587
628
 
588
629
  def print_filename_status_line cf=current_file
@@ -594,7 +635,7 @@ def print_filename_status_line cf=current_file
594
635
  end
595
636
 
596
637
  mtime = if !File.exist? ff
597
- # take care of dead links lstat TODO
638
+ # take care of dead links lstat
598
639
  date_format(File.lstat(ff).mtime) if File.symlink?(ff)
599
640
  else
600
641
  date_format(File.stat(ff).mtime)
@@ -606,11 +647,11 @@ end
606
647
 
607
648
  # should we do a read of the dir
608
649
  def rescan?
609
- $rescan_required
650
+ @rescan_required
610
651
  end
611
652
 
612
653
  def rescan_required flag=true
613
- $rescan_required = flag
654
+ @rescan_required = flag
614
655
  redraw_required if flag
615
656
  end
616
657
 
@@ -624,7 +665,6 @@ def draw_directory
624
665
  # all this seems to be happening for each keystroke even if
625
666
  # not really required. FIXME maybe reduce and call when required
626
667
 
627
-
628
668
  # view consists of all files (filtered by pattern if necessary)
629
669
  # viewport is only that subset of view that is displayed on screen
630
670
  create_viewport
@@ -632,11 +672,11 @@ def draw_directory
632
672
  print_title
633
673
 
634
674
  # add hint and format the line
635
- buff = format_array $viewport
675
+ buff = format_array @viewport
636
676
 
637
677
  # break viewport into as many columns as required
638
678
  # This is where directories get their blue color
639
- buff = columnate buff, $grows
679
+ buff = columnate buff, @grows
640
680
 
641
681
  # starts printing array on line 3
642
682
  buff.each { |line| print line, "\n" }
@@ -655,18 +695,18 @@ end
655
695
  # FIXME color of original hint lost
656
696
  def place_cursor
657
697
  # clear_cursor
658
- # hint = get_shortcut($cursor)
659
- c = $cursor - $sta
660
- if c < $grows
698
+ # hint = get_shortcut(@cursor)
699
+ c = @cursor - @sta
700
+ if c < @grows
661
701
  # system "tput cup #{c + 2} 0"
662
702
  # print "\e[#{c + 3};0H"
663
703
  tput_cup c, 0
664
704
  # print "#{CURSOR_COLOR}#{hint} >#{CLEAR}"
665
705
  return
666
706
  end
667
- wid = get_width $viewport.size, $grows
668
- rows = c % $grows
669
- cols = (c / $grows) * wid
707
+ wid = get_width @viewport.size, @grows
708
+ rows = c % @grows
709
+ cols = (c / @grows) * wid
670
710
  # system "tput cup #{rows + 2} #{cols}"
671
711
  # print "\e[#{rows + 3};#{cols + 1}H"
672
712
  tput_cup rows, cols
@@ -679,7 +719,7 @@ def clear_cursor
679
719
  return unless @old_cursor
680
720
 
681
721
  hint = get_shortcut(@old_cursor)
682
- if @old_cursor < $grows
722
+ if @old_cursor < @grows
683
723
  # FIXME: faster way of getting here ? see fff
684
724
  # system "tput cup #{@old_cursor + 2} 0"
685
725
  tput_cup @old_cursor, 0
@@ -687,9 +727,9 @@ def clear_cursor
687
727
  print "#{hint} "
688
728
  return
689
729
  end
690
- wid = get_width $viewport.size, $grows
691
- rows = @old_cursor % $grows
692
- cols = (@old_cursor / $grows) * wid
730
+ wid = get_width @viewport.size, @grows
731
+ rows = @old_cursor % @grows
732
+ cols = (@old_cursor / @grows) * wid
693
733
  # system "tput cup #{rows + 2} #{cols}"
694
734
  tput_cup rows, cols
695
735
  # print "#{CURSOR_COLOR}#{hint} >#{CLEAR}"
@@ -702,7 +742,10 @@ def tput_cup row, col
702
742
  print "\e[#{row + 3};#{col + 1}H"
703
743
  end
704
744
 
705
- def redraw_required(flag=true) $redraw_required = flag; end
745
+ # FIXME flag is unused ???? XXX
746
+ def redraw_required flag=true
747
+ @redraw_required = flag
748
+ end
706
749
 
707
750
  def resolve_key key
708
751
  ret = true
@@ -710,11 +753,11 @@ def resolve_key key
710
753
 
711
754
  if key.match?(/^[a-pr-zZ]$/)
712
755
  # hint mode
713
- ret = select_hint $viewport, key
756
+ ret = select_hint @viewport, key
714
757
  elsif key == 'BACKSPACE'
715
758
  # do we really need this TODO
716
- $patt = $patt[0..-2] if $patt && !$patt.empty?
717
- $message = $patt = nil if $patt == ''
759
+ @patt = @patt[0..-2] if @patt && !@patt.empty?
760
+ @message = @patt = nil if @patt == ''
718
761
  elsif '0123456789'.include? key
719
762
  resolve_numeric_key key
720
763
  else
@@ -725,10 +768,10 @@ end
725
768
 
726
769
  def resolve_binding key
727
770
  # fetch binding for key
728
- x = $bindings[key]
771
+ x = @bindings[key]
729
772
 
730
773
  # remove comment string so only binding is left
731
- x, _ = x.split(':') if x
774
+ x, = x.split(':') if x
732
775
 
733
776
  # split into binding and args
734
777
  x = x.split if x
@@ -738,13 +781,14 @@ def resolve_binding key
738
781
  send(binding, *args) if binding
739
782
  else
740
783
  # perror "No binding for #{key}"
784
+ @log.debug "No binding for #{key}"
741
785
  end
742
786
  end
743
787
 
744
788
  # numbers represent quick bookmarks
745
789
  # if bookmark exists, go to else create it.
746
790
  def resolve_numeric_key key
747
- d = $bookmarks[key]
791
+ d = @bookmarks[key]
748
792
  if d
749
793
  change_dir d
750
794
  return
@@ -755,7 +799,7 @@ def resolve_numeric_key key
755
799
  end
756
800
 
757
801
  def set_bookmark key, dir=Dir.pwd
758
- $bookmarks[key] = dir
802
+ @bookmarks[key] = dir
759
803
  end
760
804
 
761
805
  ## write current dir to a file so we can ccd to it when exiting
@@ -775,7 +819,7 @@ KILO_SIZE = 1024.0
775
819
 
776
820
  # Return the file size with a readable style.
777
821
  # NOTE format is a kernel method.
778
- def readable_file_size(size, precision)
822
+ def readable_file_size size, precision
779
823
  if size < KILO_SIZE then format('%d B', size)
780
824
  elsif size < MEGA_SIZE then format("%.#{precision}f K", (size / KILO_SIZE))
781
825
  elsif size < GIGA_SIZE then format("%.#{precision}f M", (size / MEGA_SIZE))
@@ -784,7 +828,7 @@ def readable_file_size(size, precision)
784
828
  end
785
829
 
786
830
  ## format date for file given stat
787
- def date_format(t)
831
+ def date_format t
788
832
  t.strftime '%Y/%m/%d'
789
833
  end
790
834
 
@@ -802,7 +846,7 @@ def columnate ary, siz
802
846
  # if less than sz then 1 col and full width
803
847
  #
804
848
  wid = get_width ary.size, siz
805
- $temp_wid = wid
849
+ @temp_wid = wid
806
850
 
807
851
  # ix refers to the index in the complete file list, wherease we only show 60 at a time
808
852
  ix = 0
@@ -812,19 +856,18 @@ def columnate ary, siz
812
856
  ctr = 0
813
857
  while ctr < siz
814
858
 
815
- f = ary[ix]
859
+ f = ary[ix].dup # 2019-04-14 - frozen_string_literal
816
860
  # f is not just filename but marker and hint
817
861
 
818
862
  # check to see if we need to truncate
819
863
  # 2019-03-18 - truncate from middle of string.
820
864
  # 2019-03-24 - truncate and size to take care of color codes
821
865
  # fsz = f.size
822
- unformatted_len, _ = filename_len(f)
866
+ unformatted_len, = filename_len(f)
823
867
  if unformatted_len > wid
824
868
  # take the excess out from the center on both sides
825
869
  f = truncate_formatted_filename(f, unformatted_len, wid)
826
870
 
827
-
828
871
  elsif unformatted_len < wid
829
872
 
830
873
  # f = f.ljust(wid)
@@ -885,10 +928,10 @@ def truncate_formatted_filename f, unformatted_len, wid
885
928
  # there could be escape codes of varying length
886
929
  sindex = f.index ' '
887
930
  # if f[0] == "\e"
888
- # mindex = f.index('m')
889
- # hintsize = sindex - mindex - 1
931
+ # mindex = f.index('m')
932
+ # hintsize = sindex - mindex - 1
890
933
  # else
891
- # hintsize = sindex - 1
934
+ # hintsize = sindex - 1
892
935
  # end
893
936
  # f[0..sindex + 1] + '<' + f[-wid + hintsize..-1] + ' '
894
937
  # @log.debug "XXX #{excess}: #{f} / #{wid}"
@@ -901,12 +944,12 @@ def truncate_formatted_filename f, unformatted_len, wid
901
944
  end
902
945
 
903
946
  def get_width arysz, siz
904
- ars = [$pagesize, arysz].min
947
+ ars = [@pagesize, arysz].min
905
948
  d = 0
906
- return $gcols - d if ars <= siz
949
+ return @gcols - d if ars <= siz
907
950
 
908
951
  tmp = (ars * 1.000 / siz).ceil
909
- wid = $gcols / tmp - d
952
+ wid = @gcols / tmp - d
910
953
  wid
911
954
  end
912
955
 
@@ -923,7 +966,7 @@ def filename_len name
923
966
  end
924
967
 
925
968
  ## formats the data with number, mark and details
926
- def format_array(ary)
969
+ def format_array ary
927
970
  # buff = Array.new
928
971
  buff = Array.new(ary.size)
929
972
  return buff if ary.nil? || ary.empty?
@@ -941,15 +984,12 @@ def format_array(ary)
941
984
  cur = SPACE
942
985
  ind = get_shortcut(ix)
943
986
 
944
-
945
987
  # Handle separator before enhanced file list.
946
988
  # We do lost a shortcut
947
- if f == SEPARATOR
948
- ind = cur = mark = '-'
949
- end
989
+ ind = cur = mark = '-' if f == SEPARATOR
950
990
 
951
991
  mark = '+' if visited? f
952
- # cur = CURMARK if ix + $sta == $cursor # 2019-03-29 - removed reduced calls
992
+ # cur = CURMARK if ix + @sta == @cursor # 2019-03-29 - removed reduced calls
953
993
  # NOTE seems like f and ary[ix] are the same
954
994
  mark = GMARK if selected?(ary[ix])
955
995
 
@@ -957,37 +997,14 @@ def format_array(ary)
957
997
  fullname = f[0] == '~' ? File.expand_path(f) : f
958
998
  color = color_for fullname
959
999
 
960
- if $long_listing
961
- begin
962
- if File.exist? f
963
- stat = File.stat(f)
964
- else
965
- # dead link
966
- if File.symlink?(f)
967
- stat = File.lstat(f)
968
- else
969
- # remove last character and get stat
970
- last = f[-1]
971
- stat = File.stat(f.chop) if last == ' ' || last == '@' || last == '*'
972
- end
973
- end
974
- # this is for saved directories etc which are shortened
975
- stat ||= File.stat(File.expand_path(f))
976
- f = format('%10s %s %s', readable_file_size(stat.size, 1),
977
- date_format(stat.mtime), f)
978
- rescue StandardError => e
979
- @log.warn "WARN::#{e}: FILE:: #{f}"
980
- f = format('%10s %s %s', '?', '??????????', f)
981
- end
982
- end
1000
+ f = format_long_listing(f) if @long_listing
983
1001
 
984
1002
  # 2019-03-31 - replace unprintable chars with ?
985
1003
  f = f.gsub(/[^[:print:]]/, '?')
986
1004
 
1005
+ # FIXME do in one operation. otherwise creating string 2 times
987
1006
  s = "#{ind}#{mark}#{cur}#{f}"
988
- if color
989
- s = "#{color}#{s}#{CLEAR}"
990
- end
1007
+ s = "#{color}#{s}#{CLEAR}" if color
991
1008
 
992
1009
  buff[ctr] = s
993
1010
 
@@ -997,22 +1014,53 @@ def format_array(ary)
997
1014
  buff
998
1015
  end
999
1016
 
1017
+ def format_long_listing f
1018
+ return unless @long_listing
1019
+ return format('%10s %s %s', '-', '----------', f) if f == SEPARATOR
1020
+
1021
+ begin
1022
+ if File.exist? f
1023
+ stat = File.stat(f)
1024
+ elsif f[0] == '~'
1025
+ stat = File.stat(File.expand_path(f))
1026
+ elsif File.symlink?(f)
1027
+ # dead link
1028
+ stat = File.lstat(f)
1029
+ else
1030
+ # remove last character and get stat
1031
+ last = f[-1]
1032
+ stat = File.stat(f.chop) if last == ' ' || last == '@' || last == '*'
1033
+ end
1034
+
1035
+ f = format('%10s %s %s',
1036
+ readable_file_size(stat.size, 1),
1037
+ date_format(stat.mtime),
1038
+ f)
1039
+
1040
+ rescue StandardError => e
1041
+ @log.warn "WARN::#{e}: FILE:: #{f}"
1042
+ f = format('%10s %s %s', '?', '??????????', f)
1043
+ end
1044
+
1045
+ return f
1046
+ end
1047
+
1000
1048
  # determine color for a filename based on extension, then pattern, then filetype
1001
1049
  def color_for fname
1002
1050
  return nil if fname == SEPARATOR
1003
1051
 
1004
1052
  extension = File.extname(fname)
1005
- color = $ls_color[extension]
1053
+ color = @ls_color[extension]
1006
1054
  return color if color
1007
1055
 
1008
1056
  # check file against patterns
1009
1057
  if File.file?(fname)
1010
- $ls_pattern.each_pair do |k, v|
1058
+ @ls_pattern.each_pair do |k, v|
1011
1059
  # if fname.match?(/k/)
1012
- if fname =~ /#{k}/
1060
+ if /#{k}/.match?(fname)
1013
1061
  # @log.debug "#{fname} matched #{k}. color is #{v[1..-2]}"
1014
1062
  return v
1015
- # else
1063
+ # else
1016
1064
  # @log.debug "#{fname} di not match #{k}. color is #{v[1..-2]}"
1017
1065
  end
1018
1066
  end
@@ -1022,34 +1070,33 @@ def color_for fname
1022
1070
  if File.exist? fname
1023
1071
  # @log.debug "Filetype:#{File.ftype(fname)}"
1024
1072
 
1025
- return $ls_ftype[File.ftype(fname)] if $ls_ftype.key? File.ftype(fname)
1026
- return $ls_ftype['ex'] if File.executable?(fname)
1073
+ return @ls_ftype[File.ftype(fname)] if @ls_ftype.key? File.ftype(fname)
1074
+ return @ls_ftype['ex'] if File.executable?(fname)
1027
1075
  else
1028
1076
  # orphan file, but fff uses mi
1029
- return $ls_ftype['mi'] if File.symlink?(fname)
1077
+ return @ls_ftype['mi'] if File.symlink?(fname)
1030
1078
 
1031
1079
  @log.warn "FILE WRONG: #{fname}"
1032
- return $ls_ftype['or']
1080
+ return @ls_ftype['or']
1033
1081
  end
1034
1082
 
1035
1083
  nil
1036
1084
  end
1037
1085
 
1038
1086
  def parse_ls_colors
1039
-
1040
1087
  colorvar = ENV['LS_COLORS']
1041
1088
  if colorvar.nil?
1042
- $ls_colors_found = nil
1089
+ @ls_colors_found = nil
1043
1090
  return
1044
1091
  end
1045
- $ls_colors_found = true
1092
+ @ls_colors_found = true
1046
1093
  ls = colorvar.split(':')
1047
1094
  ls.each do |e|
1048
1095
  patt, colr = e.split '='
1049
1096
  colr = "\e[" + colr + 'm'
1050
1097
  if e.start_with? '*.'
1051
1098
  # extension, avoid '*' and use the rest as key
1052
- $ls_color[patt[1..-1]] = colr
1099
+ @ls_color[patt[1..-1]] = colr
1053
1100
  # @log.debug "COLOR: Writing extension (#{patt})."
1054
1101
  elsif e[0] == '*'
1055
1102
  # file pattern, this would be a glob pattern not regex
@@ -1057,11 +1104,11 @@ def parse_ls_colors
1057
1104
  patt = patt.gsub('.', '\.')
1058
1105
  patt = patt.sub('+', '\\\+') # if i put a plus it does not go at all
1059
1106
  patt = patt.gsub('-', '\-')
1060
- patt = patt.gsub('?', '.')
1107
+ patt = patt.tr('?', '.')
1061
1108
  patt = patt.gsub('*', '.*')
1062
1109
  patt = "^#{patt}" if patt[0] != '.'
1063
1110
  patt = "#{patt}$" if patt[-1] != '*'
1064
- $ls_pattern[patt] = colr
1111
+ @ls_pattern[patt] = colr
1065
1112
  # @log.debug "COLOR: Writing file (#{patt})."
1066
1113
  elsif patt.length == 2
1067
1114
  # file type, needs to be mapped to what ruby will return
@@ -1078,19 +1125,19 @@ def parse_ls_colors
1078
1125
  # ex = file which is executable (ie. has 'x' set in permissions).
1079
1126
  case patt
1080
1127
  when 'di'
1081
- $ls_ftype['directory'] = colr
1128
+ @ls_ftype['directory'] = colr
1082
1129
  when 'cd'
1083
- $ls_ftype['characterSpecial'] = colr
1130
+ @ls_ftype['characterSpecial'] = colr
1084
1131
  when 'bd'
1085
- $ls_ftype['blockSpecial'] = colr
1132
+ @ls_ftype['blockSpecial'] = colr
1086
1133
  when 'pi'
1087
- $ls_ftype['fifo'] = colr
1134
+ @ls_ftype['fifo'] = colr
1088
1135
  when 'ln'
1089
- $ls_ftype['link'] = colr
1136
+ @ls_ftype['link'] = colr
1090
1137
  when 'so'
1091
- $ls_ftype['socket'] = colr
1138
+ @ls_ftype['socket'] = colr
1092
1139
  else
1093
- $ls_ftype[patt] = colr
1140
+ @ls_ftype[patt] = colr
1094
1141
  end
1095
1142
  # @log.debug "COLOR: ftype #{patt}"
1096
1143
  end
@@ -1099,7 +1146,6 @@ end
1099
1146
 
1100
1147
  ## select file based on key pressed
1101
1148
  def select_hint view, key
1102
-
1103
1149
  ix = get_index(key, view.size)
1104
1150
  return nil unless ix
1105
1151
 
@@ -1107,11 +1153,11 @@ def select_hint view, key
1107
1153
  return nil unless f
1108
1154
  return nil if f == SEPARATOR
1109
1155
 
1110
- $cursor = $sta + ix
1156
+ @cursor = @sta + ix
1111
1157
 
1112
- if $mode == 'SEL'
1158
+ if @mode == 'SEL'
1113
1159
  toggle_select f
1114
- elsif $mode == 'COM'
1160
+ elsif @mode == 'COM'
1115
1161
  # not being called any longer I think
1116
1162
  run_command f
1117
1163
  else
@@ -1125,16 +1171,22 @@ def toggle_select f=current_file
1125
1171
  if selected? f
1126
1172
  remove_from_selection f
1127
1173
  else
1128
- $selected_files.clear if $selection_mode == 1
1174
+ @selected_files.clear unless @multiple_selection
1129
1175
  add_to_selection f
1130
1176
  end
1131
- message "#{$selected_files.count} files selected. "
1177
+ message "#{@selected_files.count} files selected. "
1132
1178
  # XXX is it possible to just redraw this line
1133
1179
  redraw_required
1134
1180
  end
1135
1181
 
1182
+ # allow single or multiple selection with C-s key
1183
+ def toggle_multiple_selection
1184
+ # @multiple_selection = !@multiple_selection
1185
+ toggle_value :multiple_selection
1186
+ end
1187
+
1136
1188
  ## open file or directory
1137
- def open_file(f)
1189
+ def open_file f
1138
1190
  return unless f
1139
1191
 
1140
1192
  f = File.expand_path(f) if f[0] == '~'
@@ -1149,9 +1201,8 @@ def open_file(f)
1149
1201
  f, _nextpos = f.split(':') if f.index(':')
1150
1202
  if File.directory? f
1151
1203
  save_dir_pos
1152
- change_dir f #, nextpos
1204
+ change_dir f # , nextpos
1153
1205
  elsif File.readable? f
1154
- # TODO: looks complex pls simplify !! XXX
1155
1206
  comm = opener_for f
1156
1207
  # '%%' will be substituted with the filename. See zip
1157
1208
  comm = if comm.index('%%')
@@ -1165,7 +1216,7 @@ def open_file(f)
1165
1216
  setup_terminal
1166
1217
  # XXX maybe use absolute_path instead of hardcoding
1167
1218
  f = Dir.pwd + '/' + f if f[0] != '/'
1168
- $visited_files.insert(0, f)
1219
+ @visited_files.insert(0, f)
1169
1220
  push_used_dirs Dir.pwd
1170
1221
  else
1171
1222
  perror "open_file: (#{f}) not found"
@@ -1184,22 +1235,24 @@ end
1184
1235
  def edit_current
1185
1236
  command = ENV['EDITOR'] || ENV['VISUAL'] || 'vim'
1186
1237
  run_on_current command
1187
- $visited_files.insert(0, current_file)
1238
+ @visited_files.insert(0, current_file)
1188
1239
  end
1189
1240
 
1190
1241
  def open_current
1191
- opener = /darwin/ =~ RUBY_PLATFORM ? 'open' : 'xdg-open'
1242
+ opener = /darwin/.match?(RUBY_PLATFORM) ? 'open' : 'xdg-open'
1192
1243
  run_on_current opener
1193
- $visited_files.insert(0, current_file)
1244
+ @visited_files.insert(0, current_file)
1194
1245
  end
1195
1246
 
1196
1247
  # run given command on current file
1197
- def run_on_current(command)
1248
+ def run_on_current command
1198
1249
  f = current_file
1199
1250
  return unless f
1251
+
1200
1252
  f = File.expand_path(f)
1201
1253
  return unless File.readable?(f)
1202
1254
 
1255
+ f = Shellwords.escape(f)
1203
1256
  clear_screen
1204
1257
  reset_terminal
1205
1258
  comm = "#{command} #{f}"
@@ -1213,7 +1266,7 @@ end
1213
1266
  # After putting readline in place of gets, pressing a C-c has a delayed effect.
1214
1267
  # It goes into exception block after executing other commands and still
1215
1268
  # does not do the return !
1216
- def run_command(f)
1269
+ def run_command f
1217
1270
  files = Shellwords.join(f)
1218
1271
  count = f.count
1219
1272
  text = if count > 1
@@ -1234,7 +1287,7 @@ def run_command(f)
1234
1287
  setup_terminal
1235
1288
  rescue StandardError => ex
1236
1289
  perror "Canceled or failed command, (#{ex}) press a key."
1237
- @log.warn "RUNCOMMAND: #{ex.to_s}"
1290
+ @log.warn "RUNCOMMAND: #{ex}"
1238
1291
  return
1239
1292
  end
1240
1293
 
@@ -1252,7 +1305,7 @@ def change_dir f
1252
1305
 
1253
1306
  # before leaving a dir we save it in the list, as well as the cursor
1254
1307
  # position, so we can restore that position when we return
1255
- $visited_dirs.insert(0, Dir.pwd)
1308
+ @visited_dirs.insert(0, Dir.pwd)
1256
1309
  save_dir_pos
1257
1310
 
1258
1311
  f = File.expand_path(f)
@@ -1264,24 +1317,25 @@ def change_dir f
1264
1317
  end
1265
1318
 
1266
1319
  def goto_previous_dir
1267
- prev_dir = $visited_dirs.first
1320
+ prev_dir = @visited_dirs.first
1268
1321
  return unless prev_dir
1322
+
1269
1323
  change_dir prev_dir
1270
1324
  end
1271
1325
 
1272
1326
  def index_of dir
1273
- $files.index(dir)
1327
+ @files.index(dir)
1274
1328
  end
1275
1329
 
1276
1330
  ## clear sort order and refresh listing, used typically if you are in some view
1277
1331
  # such as visited dirs or files
1278
1332
  def escape
1279
- $sorto = nil
1280
- $sorto = $default_sort_order
1281
- $viewctr = 0
1282
- $title = nil
1283
- $filterstr = 'M'
1284
- $message = nil
1333
+ @sorto = nil
1334
+ @sorto = @default_sort_order
1335
+ @viewctr = 0
1336
+ @title = nil
1337
+ @filterstr = 'M'
1338
+ @message = nil
1285
1339
  visual_block_clear
1286
1340
  refresh
1287
1341
  end
@@ -1289,29 +1343,37 @@ end
1289
1343
  ## refresh listing after some change like option change, or toggle
1290
1344
  # Should we check selected_files array also for deleted/renamed files
1291
1345
  def refresh
1292
- $patt = nil
1293
- $title = nil
1346
+ @patt = nil
1347
+ @title = nil
1294
1348
  rescan_required
1295
1349
  end
1296
1350
 
1297
1351
  # put directories first, then files
1298
- def group_directories_first files
1352
+ def group_directories_first
1353
+ return if cget(:group_directories) == :none
1354
+
1355
+ files = @files
1299
1356
  dirs = files.select { |f| File.directory?(f) }
1300
1357
  # earlier I had File? which removed links, esp dead ones
1301
- fi = files.select { |f| !File.directory?(f) }
1302
- dirs + fi
1358
+ fi = files.reject { |f| File.directory?(f) }
1359
+ @files = if cget(:group_directories) == :first
1360
+ dirs + fi
1361
+ else
1362
+ fi + dirs
1363
+ end
1303
1364
  end
1304
1365
 
1305
1366
  ## unselect all files
1306
1367
  def unselect_all
1307
- $selected_files = []
1308
- $visual_mode = nil
1368
+ @selected_files = []
1369
+ @toggles[:visual_mode] = @visual_mode = false
1309
1370
  end
1310
1371
 
1311
1372
  ## select all entries (files and directories)
1312
1373
  def select_all
1313
1374
  dir = Dir.pwd
1314
- $selected_files = $view.map { |file| File.join(dir, file) }
1375
+ @selected_files = @view.map { |file| File.join(dir, file) }
1376
+ message "#{@selected_files.count} files selected."
1315
1377
  end
1316
1378
 
1317
1379
  ## accept dir to goto and change to that ( can be a file too)
@@ -1354,14 +1416,12 @@ end
1354
1416
  # (or deselecting).
1355
1417
  #
1356
1418
  def toggle_selection_mode
1357
- if $mode == 'SEL'
1358
- $selection_mode = 1
1419
+ if @mode == 'SEL'
1359
1420
  unselect_all
1360
- $mode = nil
1421
+ @mode = nil
1361
1422
  message 'Selection mode is single. '
1362
1423
  else
1363
- $selection_mode = 2
1364
- $mode = 'SEL'
1424
+ @mode = 'SEL'
1365
1425
  message 'Typing a hint selects the file. Typing again will clear . '
1366
1426
  end
1367
1427
  end
@@ -1379,16 +1439,15 @@ def goto_parent_dir
1379
1439
  return if curr == Dir.pwd
1380
1440
 
1381
1441
  # get index of child dir in this dir, and set cursor to it.
1382
- index = $files.index(curr + '/')
1442
+ index = @files.index(curr + '/')
1383
1443
  pause "WARNING: Could not find #{curr} in this directory." unless index
1384
- $cursor = index if index
1444
+ @cursor = index if index
1385
1445
  end
1386
1446
 
1387
1447
  def goto_home_dir
1388
1448
  change_dir ENV['HOME']
1389
1449
  end
1390
1450
 
1391
-
1392
1451
  # Goes to directory bookmarked with number or upper case char.
1393
1452
  # If lower case character given, then go to first file starting with char.
1394
1453
  def goto_bookmark key=nil
@@ -1397,7 +1456,7 @@ def goto_bookmark key=nil
1397
1456
  print 'Enter bookmark char: '
1398
1457
  key = get_char
1399
1458
  end
1400
- d = $bookmarks[key]
1459
+ d = @bookmarks[key]
1401
1460
  if d
1402
1461
  change_dir d
1403
1462
  else
@@ -1410,27 +1469,39 @@ def enter_regex
1410
1469
  # print 'Enter (regex) pattern: '
1411
1470
  # move to beginning of line, and clear till EOL
1412
1471
  # print "\r\e[K"
1413
- $patt = readline '/'
1472
+ @patt = readline '/'
1414
1473
  end
1415
1474
 
1416
1475
  # page/scroll down.
1417
1476
  def next_page
1418
- $sta += $pagesize
1419
- $cursor += $pagesize
1420
- $sta = $cursor if $sta > $cursor
1421
- $stact = 0
1477
+ @sta += @pagesize
1478
+ @cursor += @pagesize
1479
+ @sta = @cursor if @sta > @cursor
1480
+ @stact = 0
1422
1481
  @old_cursor = nil
1423
1482
  redraw_required
1424
1483
  end
1425
1484
 
1426
1485
  def prev_page
1427
- $sta -= $pagesize
1428
- $cursor -= $pagesize
1486
+ @sta -= @pagesize
1487
+ @cursor -= @pagesize
1429
1488
  @old_cursor = nil
1430
1489
  # FIXME: check cursor sanity and if not changed then no redraw
1431
1490
  redraw_required
1432
1491
  end
1433
1492
 
1493
+ def goto_top
1494
+ @sta = @cursor = 0
1495
+ @old_cursor = nil
1496
+ end
1497
+
1498
+ # goto end / bottom
1499
+ def goto_end
1500
+ @cursor = @view.size - 1
1501
+ @sta = @view.size - @pagesize
1502
+ @old_cursor = nil
1503
+ end
1504
+
1434
1505
  def print_help
1435
1506
  page_with_tempfile do |file|
1436
1507
  file.puts ' HELP'
@@ -1445,26 +1516,25 @@ def print_help
1445
1516
  file.puts
1446
1517
  ary = []
1447
1518
  # 2019-03-19 - if : then show text after colon
1448
- $bindings.each_pair { |k, v|
1519
+ @bindings.each_pair do |k, v|
1449
1520
  vv = v.tr('_', ' ')
1450
1521
  vv = vv.split(':')[1].strip if vv.include?(':')
1451
1522
  ary.push "#{k.ljust(7)} => #{vv}"
1452
- }
1453
- # FIXME this works but not properly when long_listing is true.
1523
+ end
1524
+ # FIXME: this works but not properly when long_listing is true.
1454
1525
  # We should avoid using columnate as there are several file related things.
1455
- ary = columnate ary, (ary.size/2)+1
1526
+ ary = columnate ary, (ary.size / 2) + 1
1456
1527
  ary.each { |line| file.puts line }
1457
1528
  end
1458
1529
  end
1459
1530
 
1460
1531
  def page_stat_for_file
1461
- stat = %x[ stat #{current_file} ]
1532
+ stat = `stat #{current_file}`
1462
1533
  return unless stat
1463
1534
 
1464
1535
  page_with_tempfile do |file|
1465
1536
  file.puts stat
1466
1537
  end
1467
-
1468
1538
  end
1469
1539
 
1470
1540
  def page_with_tempfile
@@ -1485,20 +1555,20 @@ def debug_vars
1485
1555
  page_with_tempfile do |file|
1486
1556
  file.puts "DEBUG VARIABLES for #{current_file}:"
1487
1557
  file.puts
1488
- file.puts "sta #{$sta}"
1489
- file.puts "cursor #{$cursor}"
1490
- file.puts "stact #{$stact}"
1491
- file.puts "viewport.size #{$viewport.size}"
1492
- file.puts "pagesize #{$pagesize}"
1493
- file.puts "view.size #{$view.size}"
1494
- file.puts "grows #{$grows}"
1558
+ file.puts "sta #{@sta}"
1559
+ file.puts "cursor #{@cursor}"
1560
+ file.puts "stact #{@stact}"
1561
+ file.puts "viewport.size #{@viewport.size}"
1562
+ file.puts "pagesize #{@pagesize}"
1563
+ file.puts "view.size #{@view.size}"
1564
+ file.puts "grows #{@grows}"
1495
1565
  file.puts "File: #{current_file}"
1496
1566
  file.puts
1497
1567
  file.puts "Opener: #{opener_for(current_file)}"
1498
1568
  file.puts
1499
1569
  file.puts `file "#{current_file}"`
1500
1570
  file.puts
1501
- file.puts %x[stat "#{current_file}"]
1571
+ file.puts `stat "#{current_file}"`
1502
1572
  end
1503
1573
  redraw_required
1504
1574
  end
@@ -1506,7 +1576,7 @@ end
1506
1576
  def view_bookmarks
1507
1577
  clear_last_line
1508
1578
  puts 'Bookmarks: '
1509
- $bookmarks.each_pair { |k, v| puts "#{k.ljust(7)} => #{v}" }
1579
+ @bookmarks.each_pair { |k, v| puts "#{k.ljust(7)} => #{v}" }
1510
1580
  puts
1511
1581
  print 'Enter bookmark to goto: '
1512
1582
  key = get_char
@@ -1517,16 +1587,17 @@ end
1517
1587
  def main_menu
1518
1588
  h = {
1519
1589
  :a => :ag,
1520
- '/' => :ffind,
1590
+ '/' => :ffind,
1521
1591
  :l => :locate,
1522
1592
  :v => :vidir,
1523
1593
  :z => :z_interface,
1524
1594
  :d => :child_dirs,
1525
1595
  :r => :recent_files,
1526
- '1' => :select_from_visited_files,
1527
- '2' => :select_from_used_dirs,
1596
+ '1' => :select_from_visited_files,
1597
+ '2' => :select_from_used_dirs,
1598
+ '3' => :list_selected_files,
1528
1599
  :t => :dirtree,
1529
- '4' => :tree,
1600
+ '4' => :tree,
1530
1601
  :o => :order_menu,
1531
1602
  :F => :filter_menu,
1532
1603
  :c => :create_menu,
@@ -1537,13 +1608,15 @@ def main_menu
1537
1608
  menu 'Main Menu', h
1538
1609
  end
1539
1610
 
1611
+ # copy and move here ?
1540
1612
  def selection_menu
1541
1613
  h = {
1542
1614
  :a => :select_all,
1543
1615
  :u => :unselect_all,
1544
1616
  :s => :toggle_select,
1545
- '*' => 'toggle_selection_mode',
1546
- 'x' => 'visual_mode_toggle',
1617
+ '*' => 'toggle_multiple_selection',
1618
+ 'x' => 'toggle_visual_mode',
1619
+ 'm' => 'toggle_selection_mode',
1547
1620
  :v => :view_selected_files
1548
1621
  }
1549
1622
  menu 'Selection Menu', h
@@ -1568,18 +1641,17 @@ def menu title, h
1568
1641
  # 2019-03-09 - trying out using `column` to print in cols
1569
1642
  ary = []
1570
1643
 
1571
- # 2019-04-07 - check $bindings for shortcut and get key, add global
1644
+ # 2019-04-07 - check @bindings for shortcut and get key, add global
1572
1645
  # binding in brackets
1573
1646
  h.each_pair do |k, v|
1574
-
1575
1647
  # get global binding
1576
- scut = $bindings.key(v.to_s)
1648
+ scut = @bindings.key(v.to_s)
1577
1649
  scut = " (#{scut})" if scut
1578
1650
 
1579
1651
  ary << " #{k}: #{v} #{scut}"
1580
1652
  end
1581
1653
  x = ary.join("\n")
1582
- puts %x{echo "#{x}" | column}
1654
+ puts `echo "#{x}" | column`
1583
1655
 
1584
1656
  key = get_char
1585
1657
  binding = h[key]
@@ -1587,109 +1659,154 @@ def menu title, h
1587
1659
  # TODO: 2019-03-21 - menu's do not have comments, they are symbols
1588
1660
  # binding, _ = binding.split(':')
1589
1661
  if binding
1662
+ # 2019-04-18 - true removed, else 'open' binds to ruby open not OS open
1663
+ # without true, many methods here don't get triggered
1590
1664
  send(binding) if respond_to?(binding, true)
1665
+ # send(binding) if respond_to?(binding)
1591
1666
  end
1592
1667
  redraw_required
1593
1668
  [key, binding]
1594
1669
  end
1595
1670
 
1671
+ # some toggles can be invoked directly on a key, or through another menu.
1672
+ # Some go to methods like multiple_selection from a key
1673
+ # WARNING: method and toggle should not have same name, else flag will toggle twice.
1596
1674
  def toggle_menu
1597
- h = { h: :toggle_hidden,
1598
- c: :toggle_case,
1599
- l: :toggle_long_list,
1675
+ h = { h: :show_hidden,
1676
+ c: :ignore_case,
1677
+ l: :long_listing,
1600
1678
  '1' => :toggle_columns,
1601
- d: :toggle_group_dirs,
1602
- :p => :toggle_pager_mode,
1603
- :D => :toggle_debug_flag,
1604
- '8' => :toggle_selection_mode,
1605
- '*' => :toggle_selection_mode,
1606
- v: :visual_mode_toggle,
1607
- t: :toggle_truncate_from,
1608
- e: :toggle_enhanced_list
1609
- }
1679
+ d: :group_directories,
1680
+ :e => :editor_mode,
1681
+ :D => :debug_flag,
1682
+ '8' => :multiple_selection,
1683
+ '*' => :multiple_selection,
1684
+ 'S' => :selection_mode,
1685
+ v: :visual_mode,
1686
+ t: :truncate_from,
1687
+ n: :enhanced_mode }
1688
+ # TODO: add other values at end, what key ?
1610
1689
 
1611
1690
  _, menu_text = menu 'Toggle Menu', h
1612
1691
  return unless menu_text
1613
1692
 
1614
- case menu_text
1615
- when :toggle_hidden
1616
- # NOTE: now that I am shifting queries to ruby not sure this will continue
1617
- # FNM_DOTMATCH
1618
- # working everywhere
1619
- # zsh D - dot files should show
1620
- $hidden = $hidden ? nil : 'D'
1621
- message "Show hidden is now #{!$hidden.nil?}"
1622
- rescan_required
1623
- when :toggle_case
1624
- $ignorecase = !$ignorecase
1625
- message "Ignore Case is now #{$ignorecase}"
1626
- rescan_required
1627
- when :toggle_group_dirs
1628
- @group_dirs = !@group_dirs
1629
- message "Group Dirs First is now #{@group_dirs}"
1630
- rescan_required
1631
- when :toggle_columns
1632
- if $gviscols == 1
1633
- $gviscols = 3
1634
- else
1635
- $gviscols = 1
1636
- end
1637
- # $long_listing = false if $gviscols > 1
1638
- x = $grows * $gviscols
1639
- $pagesize = $pagesize == x ? $grows : x
1640
- message "Visible columns now set to #{$gviscols}"
1641
- rescan_required
1642
- when :toggle_pager_mode
1643
- $editor_mode = !$editor_mode
1644
- $default_command = if $editor_mode
1645
- ENV['EDITOR'] # earlier nil # 2019-03-10 -
1646
- # it was nil so we could set a default command
1647
- else
1648
- ENV['MANPAGER'] || ENV['PAGER']
1649
- end
1650
- message "Default command is #{$default_command}"
1651
- when :toggle_enhanced_list
1652
- $enhanced_mode = !$enhanced_mode
1653
- message "Enhanced mode is #{$enhanced_mode}"
1654
- rescan_required
1693
+ # menu would have called if symbol only responds so return.
1694
+ return if respond_to?(menu_text, true) # already handled
1655
1695
 
1656
- when :toggle_long_list
1657
- $long_listing = !$long_listing
1658
- if $long_listing
1659
- $saved_gviscols = $gviscols
1660
- $gviscols = 1
1661
- $pagesize = $grows
1662
- else
1663
- $gviscols = $saved_gviscols || 3
1664
- x = $grows * $gviscols
1665
- $pagesize = $pagesize == x ? $grows : x
1666
- end
1667
- if $stact > 0
1668
- $sta = $stact
1669
- $stact = 0 # in case user was panned 2019-03-20 -
1670
- end
1671
- message "Long listing is #{$long_listing}, vis cols is #{$gviscols}"
1672
- rescan_required
1673
- when :toggle_debug_flag
1674
- @debug_flag = !@debug_flag
1675
- message "Debug flag is #{@debug_flag}"
1676
-
1677
- when :toggle_truncate_from
1678
- # if filename exceeds width cut from which direction
1679
- @truncate_from = case @truncate_from
1680
- when :center
1681
- :left
1682
- when :left
1683
- :right
1684
- when :right
1685
- :center
1696
+ # for visual and selection mode
1697
+ # check if respond_to? symbol or toggle + symbol then call and return.
1698
+ symb = "toggle_#{menu_text}".to_sym
1699
+ @log.debug "trying #{symb}."
1700
+ if respond_to?(symb, true)
1701
+ @log.debug "calling #{symb}."
1702
+ send(symb)
1703
+ return
1704
+ end
1705
+
1706
+ cset menu_text
1707
+ end
1708
+
1709
+ def toggle_columns
1710
+ @gviscols = if @gviscols == 1
1711
+ 3
1712
+ else
1713
+ 1
1714
+ end
1715
+ x = @grows * @gviscols
1716
+ @pagesize = @pagesize == x ? @grows : x
1717
+ message "Visible columns now set to #{@gviscols}"
1718
+ rescan_required
1719
+
1720
+ end
1721
+
1722
+ def toggle_editor_mode
1723
+ toggle_value :editor_mode
1724
+ @default_command = if @editor_mode
1725
+ ENV['EDITOR'] # earlier nil # 2019-03-10 -
1726
+ # it was nil so we could set a default command
1686
1727
  else
1687
- :center
1728
+ ENV['MANPAGER'] || ENV['PAGER']
1688
1729
  end
1689
- message "Truncate long filenames from: #{@truncate_from}"
1730
+ message "Default command is #{@default_command}"
1731
+ end
1732
+
1733
+ def toggle_long_listing
1734
+ toggle_value :long_listing
1735
+ @long_listing = cget(:long_listing)
1736
+ if @long_listing
1737
+ @saved_gviscols = @gviscols
1738
+ @gviscols = 1
1739
+ @pagesize = @grows
1740
+ else
1741
+ @gviscols = @saved_gviscols || 3
1742
+ x = @grows * @gviscols
1743
+ @pagesize = @pagesize == x ? @grows : x
1744
+ end
1745
+ if @stact > 0
1746
+ @sta = @stact
1747
+ @stact = 0 # in case user was panned 2019-03-20 -
1690
1748
  end
1749
+ message "Long listing is #{@long_listing}, visible columns is #{@gviscols}."
1750
+ rescan_required
1691
1751
  end
1692
1752
 
1753
+ # ----------------- flag related functions -----------------------------------#
1754
+ # toggles the value of a toggle flag, also setting the variable if defined
1755
+ # WARN: be careful of variable being set directly. Replace such vars one by one.
1756
+ # NOTE: please use cset
1757
+ def toggle_value flag
1758
+ @toggles[flag] = !@toggles[flag]
1759
+ # TODO: 2019-04-16 - can we set a variable so we don't have to check
1760
+ # against a hash everywhere. variable name can be in hash too
1761
+ if instance_variable_defined? "@#{flag}"
1762
+ instance_variable_set "@#{flag}", @toggles[flag]
1763
+ @log.debug "instance_variable_set #{flag}, #{@toggles[flag]}"
1764
+ end
1765
+ message "#{flag} is set to #{@toggles[flag]}"
1766
+ end
1767
+
1768
+ # rotates the value of an option that has multiple values
1769
+ # NOTE: please use cset
1770
+ def rotate_value symb
1771
+ curr = cget(symb) # get current value
1772
+ index = @options[symb][:values].index(curr) || 0
1773
+ index += 1
1774
+ index = 0 if index >= @options[symb][:values].count
1775
+ x = @options[symb][:current] = @options[symb][:values][index]
1776
+ var = @options[symb][:var]
1777
+ instance_variable_set "@#{var}", x if var
1778
+ message "#{symb} is set to #{@options[symb][:current]}. "
1779
+ end
1780
+
1781
+ # get the value of a flag given the symbol.
1782
+ # NOTE: use this rather than access the hashes directly, since changes in structure
1783
+ # may happen
1784
+ def cget symb
1785
+ return @toggles[symb] if @toggles.key? symb
1786
+ return @options[symb][:current] if @options.key? symb
1787
+
1788
+ @log.warn "CGET: #{symb} does not exist. Please check code."
1789
+ raise ArgumentError, "CGET: #{symb} does not exist. Please check code."
1790
+ end
1791
+
1792
+ # toggles or rotates the value of a flag
1793
+ def cset symb
1794
+ if @toggles.key? symb
1795
+ toggle_value symb
1796
+ rescan_required
1797
+ return true
1798
+ end
1799
+ if @options.key? symb
1800
+ rotate_value symb
1801
+ rescan_required
1802
+ return true
1803
+ end
1804
+
1805
+ @log.warn "CSET: #{symb} does not exist. Please check code."
1806
+ raise ArgumentError, "CSET: #{symb} does not exist. Please check code."
1807
+ end
1808
+ # ----------------- end of flag related functions ----------------------------#
1809
+
1693
1810
  def order_menu
1694
1811
  # zsh o = order, O = reverse order
1695
1812
  # ruby mtime/atime/ctime come reversed so we have to change o to O
@@ -1726,16 +1843,17 @@ def order_menu
1726
1843
  lo = ''
1727
1844
  end
1728
1845
  ## This needs to persist and be a part of all listings, put in change_dir.
1729
- $sorto = lo
1846
+ @sorto = lo
1730
1847
  message "Sorted on #{menu_text}"
1731
1848
  rescan_required
1732
1849
  end
1733
1850
 
1851
+ # TODO: create a link
1734
1852
  def create_menu
1735
1853
  h = { f: :create_a_file,
1736
1854
  d: :create_a_dir,
1737
- b: :create_bookmark
1738
- }
1855
+ s: :create_dir_with_selection,
1856
+ b: :create_bookmark }
1739
1857
  _, menu_text = menu 'Create Menu', h
1740
1858
  end
1741
1859
 
@@ -1751,7 +1869,7 @@ def command_menu
1751
1869
  #
1752
1870
  h = { t: :today, D: :default_command, R: :remove_from_list,
1753
1871
  v: :view_selected_files }
1754
- h[:e] = if $editor_mode
1872
+ h[:e] = if @editor_mode
1755
1873
  :pager_mode
1756
1874
  else
1757
1875
  :editor_mode
@@ -1759,11 +1877,11 @@ def command_menu
1759
1877
  _, menu_text = menu 'Command Menu', h
1760
1878
  case menu_text
1761
1879
  when :pager_mode
1762
- $editor_mode = false
1763
- $default_command = ENV['MANPAGER'] || ENV['PAGER']
1880
+ @editor_mode = false
1881
+ @default_command = ENV['MANPAGER'] || ENV['PAGER']
1764
1882
  when :editor_mode
1765
- $editor_mode = true
1766
- $default_command = nil
1883
+ @editor_mode = true
1884
+ @default_command = nil
1767
1885
  when :ffind
1768
1886
  ffind
1769
1887
  when :locate
@@ -1771,20 +1889,20 @@ def command_menu
1771
1889
  when :today
1772
1890
  # zshglob: M = MARK_DIRS with slash
1773
1891
  # zshglob: 'm0' 'm' = modified time, '0' = 0 days ago
1774
- $files = `zsh -c 'print -rl -- *(#{$hidden}Mm0)'`.split("\n")
1775
- $title = "Today's files"
1892
+ @files = `zsh -c 'print -rl -- *(#{@hidden}Mm0)'`.split("\n")
1893
+ @title = "Today's files"
1776
1894
  when :default_command
1777
1895
  puts ' This no longer works'
1778
1896
  puts 'Selecting a file usually invokes $EDITOR'
1779
1897
  puts 'What command do you want to use repeatedly on selected files: '
1780
- $default_command = gets.chomp
1781
- if $default_command != ''
1898
+ @default_command = gets.chomp
1899
+ if @default_command != ''
1782
1900
  print 'Second part of command (maybe blank): '
1783
- $default_command2 = gets.chomp
1901
+ @default_command2 = gets.chomp
1784
1902
  else
1785
1903
  print 'Cleared default command, will default to $EDITOR'
1786
- $default_command2 = nil
1787
- $default_command = nil
1904
+ @default_command2 = nil
1905
+ @default_command = nil
1788
1906
  end
1789
1907
  end
1790
1908
  # redraw
@@ -1799,65 +1917,64 @@ def extras
1799
1917
  g: :generators,
1800
1918
  :B => :bindkey_ext_command,
1801
1919
  :r => :config_read,
1802
- :w => :config_write
1803
- }
1920
+ :w => :config_write }
1804
1921
  key, menu_text = menu 'Extras Menu', h
1805
1922
  case menu_text
1806
1923
  when :one_column
1807
- $pagesize = $grows
1924
+ @pagesize = @grows
1808
1925
  when :multi_column
1809
- # $pagesize = 60
1810
- $pagesize = $grows * $gviscols
1926
+ # @pagesize = 60
1927
+ @pagesize = @grows * @gviscols
1811
1928
  when :columns
1812
- print "How many columns to show: 1-6 [current #{$gviscols}]? "
1929
+ print "How many columns to show: 1-6 [current #{@gviscols}]? "
1813
1930
  key = get_char
1814
1931
  key = key.to_i
1815
1932
  if key > 0 && key < 7
1816
- $gviscols = key.to_i
1817
- $pagesize = $grows * $gviscols
1933
+ @gviscols = key.to_i
1934
+ @pagesize = @grows * @gviscols
1818
1935
  end
1819
1936
  end
1820
1937
  end
1821
1938
 
1822
1939
  def filter_menu
1823
1940
  h = { :d => :dirs, :f => :files, :e => :emptydirs, '0' => :emptyfiles,
1824
- :r => :reduce_list, :x => :extension}
1941
+ :r => :reduce_list, :x => :extension }
1825
1942
  _, menu_text = menu 'Filter Menu', h
1826
1943
  files = nil
1827
1944
  case menu_text
1828
1945
  when :dirs
1829
- $filterstr = '/M'
1946
+ @filterstr = '/M'
1830
1947
  # zsh /M MARK_DIRS appends trailing '/' to directories
1831
- files = `zsh -c 'print -rl -- *(#{$sorto}/M)'`.split("\n")
1832
- $title = 'Filter: directories only'
1948
+ files = `zsh -c 'print -rl -- *(#{@sorto}/M)'`.split("\n")
1949
+ @title = 'Filter: directories only'
1833
1950
  when :files
1834
- $filterstr = '.'
1951
+ @filterstr = '.'
1835
1952
  # zsh '.' for files, '/' for dirs
1836
- files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}.)'`.split("\n")
1837
- $title = 'Filter: files only'
1953
+ files = `zsh -c 'print -rl -- *(#{@sorto}#{@hidden}.)'`.split("\n")
1954
+ @title = 'Filter: files only'
1838
1955
  when :emptydirs
1839
- $filterstr = '/D^F'
1956
+ @filterstr = '/D^F'
1840
1957
  # zsh F = full dirs, ^F empty dirs
1841
- files = `zsh -c 'print -rl -- *(#{$sorto}/D^F)'`.split("\n")
1842
- $title = 'Filter: empty directories'
1958
+ files = `zsh -c 'print -rl -- *(#{@sorto}/D^F)'`.split("\n")
1959
+ @title = 'Filter: empty directories'
1843
1960
  when :emptyfiles
1844
- $filterstr = '.L0'
1961
+ @filterstr = '.L0'
1845
1962
  # zsh .L size in bytes
1846
- files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}.L0)'`.split("\n")
1847
- $title = 'Filter: empty files'
1963
+ files = `zsh -c 'print -rl -- *(#{@sorto}#{@hidden}.L0)'`.split("\n")
1964
+ @title = 'Filter: empty files'
1848
1965
  when :reduce_list
1849
1966
  files = reduce
1850
1967
  when :extension
1851
1968
  files = filter_for_current_extension
1852
1969
  end
1853
1970
  if files && files.count > 0
1854
- $files = files
1855
- $stact = 0
1856
- $message = "Filtered on #{menu_text}. Press ESC to return."
1971
+ @files = files
1972
+ @stact = 0
1973
+ @message = "Filtered on #{menu_text}. Press ESC to return."
1857
1974
  # redraw
1858
1975
  else
1859
1976
  perror 'Sorry, No files. '
1860
- $title = nil
1977
+ @title = nil
1861
1978
  end
1862
1979
  end
1863
1980
 
@@ -1866,47 +1983,47 @@ def reduce pattern=nil
1866
1983
  last_line 'Enter a pattern to reduce current list: '
1867
1984
  pattern = gets.chomp
1868
1985
  end
1869
- $title = "Filter: pattern #{pattern}"
1870
- $files = $files.select { |f| f.match(pattern) }
1986
+ @title = "Filter: pattern #{pattern}"
1987
+ @files = @files.select { |f| f.match(pattern) }
1871
1988
  end
1872
1989
 
1873
1990
  def filter_for_current_extension
1874
1991
  extn = File.extname(current_file)
1875
1992
  return unless extn
1876
1993
 
1877
- $files = $files.select { |f| !File.directory?(f) && extn == File.extname(f) }
1994
+ @files = @files.select { |f| !File.directory?(f) && extn == File.extname(f) }
1878
1995
  end
1879
1996
 
1880
1997
  def select_from_used_dirs
1881
- $title = 'Used Directories'
1998
+ @title = 'Used Directories'
1882
1999
  home = File.expand_path '~'
1883
- $files = $used_dirs.uniq.map { |path| path.sub("#{home}", '~') }
2000
+ @files = @used_dirs.uniq.map { |path| path.sub(home.to_s, '~') }
1884
2001
  # redraw
1885
2002
  end
1886
2003
 
1887
2004
  def select_from_visited_files
1888
2005
  # not yet a unique list, needs to be unique and have latest pushed to top
1889
- $title = 'Visited Files'
2006
+ @title = 'Visited Files'
1890
2007
  home = File.expand_path '~'
1891
- $files = $visited_files.uniq.map { |path| path.sub("#{home}", '~') }
2008
+ @files = @visited_files.uniq.map { |path| path.sub(home.to_s, '~') }
1892
2009
  # redraw
1893
2010
  end
1894
2011
 
1895
2012
  # maybe unused ??? XXX
1896
2013
  def select_bookmarks
1897
- $title = 'Bookmarks'
1898
- $files = $bookmarks.values
2014
+ @title = 'Bookmarks'
2015
+ @files = @bookmarks.values
1899
2016
  end
1900
2017
 
1901
2018
  ## part copied and changed from change_dir since we don't dir going back on top
1902
2019
  # or we'll be stuck in a cycle
1903
2020
  def pop_dir
1904
2021
  # the first time we pop, we need to put the current on stack
1905
- $visited_dirs.push Dir.pwd unless $visited_dirs.index(Dir.pwd)
2022
+ @visited_dirs.push Dir.pwd unless @visited_dirs.index(Dir.pwd)
1906
2023
  ## XXX make sure thre is something to pop
1907
- d = $visited_dirs.delete_at 0
2024
+ d = @visited_dirs.delete_at 0
1908
2025
  ## XXX make sure the dir exists, cuold have been deleted. can be an error or crash otherwise
1909
- $visited_dirs.push d
2026
+ @visited_dirs.push d
1910
2027
  Dir.chdir d
1911
2028
  post_cd
1912
2029
  rescan_required
@@ -1914,10 +2031,10 @@ end
1914
2031
 
1915
2032
  # after changing directory
1916
2033
  def post_cd
1917
- $title = $patt = $message = nil
1918
- $sta = $cursor = $stact = 0
1919
- $visual_block_start = nil
1920
- $current_dir = Dir.pwd
2034
+ @title = @patt = @message = nil
2035
+ @sta = @cursor = @stact = 0
2036
+ @visual_block_start = nil
2037
+ @current_dir = Dir.pwd
1921
2038
  screen_settings
1922
2039
 
1923
2040
  # goto last position cursor was in this dir
@@ -1930,10 +2047,10 @@ def config_read
1930
2047
  return unless File.readable? f
1931
2048
 
1932
2049
  hash = loadYML(f)
1933
- $used_dirs = hash['DIRS']
1934
- $visited_files = hash['FILES']
1935
- $bookmarks = hash['BOOKMARKS']
1936
- $used_dirs.concat get_env_paths
2050
+ @used_dirs = hash['DIRS']
2051
+ @visited_files = hash['FILES']
2052
+ @bookmarks = hash['BOOKMARKS']
2053
+ @used_dirs.concat get_env_paths
1937
2054
  end
1938
2055
 
1939
2056
  def get_env_paths
@@ -1955,44 +2072,40 @@ def config_write
1955
2072
  # Putting it in a format that zfm can also read and write
1956
2073
  f1 = File.expand_path(CONFIG_FILE)
1957
2074
  hash = {}
1958
- hash['DIRS'] = $used_dirs.select {|dir| File.exist? dir}
1959
- hash['FILES'] = $visited_files.select {|file| File.exist? file}
2075
+ hash['DIRS'] = @used_dirs.select { |dir| File.exist? dir }
2076
+ hash['FILES'] = @visited_files.select { |file| File.exist? file }
1960
2077
  # NOTE bookmarks is a hash and contains FILE:cursor_pos
1961
- hash['BOOKMARKS'] = $bookmarks #.select {|file| File.exist? file}
2078
+ hash['BOOKMARKS'] = @bookmarks # .select {|file| File.exist? file}
1962
2079
  writeYML hash, f1
1963
- $writing = $modified = false
2080
+ @writing = @modified = false
1964
2081
  message "Saved #{f1}"
1965
2082
  end
1966
2083
 
1967
2084
  # {{{ YML
1968
2085
  require 'yaml'
1969
- def loadYML( filename)
1970
- hash = YAML::load( File.open( filename ) )
1971
- if $opt_debug
1972
- $stderr.puts hash.keys.size
1973
- end
2086
+ def loadYML filename
2087
+ hash = YAML.safe_load(File.open(filename))
2088
+ warn hash.keys.size if @opt_debug
1974
2089
  return hash
1975
2090
  end
2091
+
1976
2092
  def writeYML obj, filename
1977
- File.open(filename, 'w') {|f| f.write obj.to_yaml }
1978
- if $opt_debug
1979
- $stderr.puts "Written to file #{filename}"
1980
- end
2093
+ File.open(filename, 'w') { |f| f.write obj.to_yaml }
2094
+ warn "Written to file #{filename}" if @opt_debug
1981
2095
  end
1982
2096
  # }}}
1983
2097
 
1984
2098
  ## accept a character to save this dir as a bookmark
1985
2099
  def create_bookmark
1986
-
1987
2100
  clear_last_line
1988
2101
  print 'Enter A-Z, a-z or 0-9 to create a bookmark: '
1989
2102
  # print "\e[?25h" # unhide cursor
1990
2103
  key = get_char
1991
2104
  # print "\e[?25l" # hide cursor
1992
- if key =~ /^[0-9A-Za-z]$/
1993
- # $bookmarks[key] = "#{Dir.pwd}:#{$cursor}"
2105
+ if /^[0-9A-Za-z]$/.match?(key)
2106
+ # @bookmarks[key] = "#{Dir.pwd}:#{@cursor}"
1994
2107
  set_bookmark key
1995
- $modified = true
2108
+ @modified = true
1996
2109
  message "Created bookmark #{key} for #{File.basename(Dir.pwd)}."
1997
2110
  else
1998
2111
  perror 'Bookmark must be alpha character or number.'
@@ -2014,35 +2127,35 @@ def subcommand
2014
2127
  end
2015
2128
  if command == 'q'
2016
2129
  # FIXME: 2019-03-22 - should this not call quit_command ?
2017
- if $modified
2130
+ if @modified
2018
2131
  last_line
2019
2132
  print 'Do you want to save bookmarks? (y/n): '
2020
2133
  key = get_char
2021
2134
  if key == 'y'
2022
- $writing = true
2023
- $quitting = true
2135
+ @writing = true
2136
+ @quitting = true
2024
2137
  elsif key == 'n'
2025
- $quitting = true
2138
+ @quitting = true
2026
2139
  print 'Quitting without saving bookmarks'
2027
2140
  else
2028
2141
  perror 'No action taken.'
2029
2142
  end
2030
2143
  else
2031
- $quitting = true
2144
+ @quitting = true
2032
2145
  end
2033
2146
  elsif command == 'wq'
2034
- $quitting = true
2035
- $writing = true
2147
+ @quitting = true
2148
+ @writing = true
2036
2149
  elsif command == 'w'
2037
2150
  config_write
2038
2151
  elsif command == 'x'
2039
- $quitting = true
2040
- $writing = true if $modified
2152
+ @quitting = true
2153
+ @writing = true if @modified
2041
2154
  elsif command == 'e'
2042
2155
  edit_current
2043
2156
  elsif command == 'o'
2044
2157
  open_current
2045
- elsif command == 'h' or command == 'help' or command == '?'
2158
+ elsif (command == 'h') || (command == 'help') || (command == '?')
2046
2159
  print_help
2047
2160
  elsif command == 'p'
2048
2161
  system 'echo $PWD | pbcopy'
@@ -2054,41 +2167,41 @@ def subcommand
2054
2167
  end
2055
2168
 
2056
2169
  def quit_command
2057
- if $modified
2170
+ if @modified
2058
2171
  last_line
2059
- puts 'Press y to save bookmarks before quitting ' if $modified
2172
+ puts 'Press y to save bookmarks before quitting ' if @modified
2060
2173
  print 'Press n to quit without saving'
2061
2174
  key = get_char
2062
2175
  else
2063
- $quitting = true
2176
+ @quitting = true
2064
2177
  end
2065
- $quitting = true if key == 'n'
2066
- $quitting = $writing = true if key == 'y'
2178
+ @quitting = true if key == 'n'
2179
+ @quitting = @writing = true if key == 'y'
2067
2180
  end
2068
2181
 
2069
2182
  def views
2070
2183
  views = %w[/ om oa Om OL oL On on]
2071
2184
  viewlabels = %w[Dirs Newest Accessed Oldest Largest Smallest Reverse Name]
2072
- $sorto = views[$viewctr]
2073
- $title = viewlabels[$viewctr]
2074
- $viewctr += 1
2075
- $viewctr = 0 if $viewctr > views.size
2185
+ @sorto = views[@viewctr]
2186
+ @title = viewlabels[@viewctr]
2187
+ @viewctr += 1
2188
+ @viewctr = 0 if @viewctr > views.size
2076
2189
 
2077
- $files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}M)'`.split("\n")
2190
+ @files = `zsh -c 'print -rl -- *(#{@sorto}#{@hidden}M)'`.split("\n")
2078
2191
  # redraw
2079
2192
  end
2080
2193
 
2081
2194
  def child_dirs
2082
- $title = 'Directories in current directory'
2195
+ @title = 'Directories in current directory'
2083
2196
  # M is MARK_DIRS option for putting trailing slash after dir
2084
- # $files = `zsh -c 'print -rl -- *(/#{$sorto}#{$hidden}M)'`.split("\n")
2085
- $files = dirs
2086
- message "#{$files.size} directories."
2197
+ # @files = `zsh -c 'print -rl -- *(/#{@sorto}#{@hidden}M)'`.split("\n")
2198
+ @files = dirs
2199
+ message "#{@files.size} directories."
2087
2200
  # redraw
2088
2201
  end
2089
2202
 
2090
2203
  def dirs dir='*'
2091
- files = Dir.glob(dir, File::FNM_DOTMATCH).select {|f| File.directory?(f)} - %w[ . ..]
2204
+ files = Dir.glob(dir, File::FNM_DOTMATCH).select { |f| File.directory?(f) } - %w[. ..]
2092
2205
  files = add_slash files
2093
2206
  files
2094
2207
  end
@@ -2100,12 +2213,11 @@ def add_slash files
2100
2213
  end
2101
2214
 
2102
2215
  def dirtree
2103
- $title = 'Child directories recursive'
2216
+ @title = 'Child directories recursive'
2104
2217
  # zsh **/ is recursive
2105
- files1 = `zsh -c 'print -rl -- **/*(/#{$sorto}#{$hidden}M)'`.split("\n")
2106
- $files = Dir['**/']
2107
- @log.debug "zsh #{files1} != rb #{$files}" if files1 != $files
2108
- message "#{$files.size} files."
2218
+ # files1 = `zsh -c 'print -rl -- **/*(/#{@sorto}#{@hidden}M)'`.split("\n")
2219
+ @files = Dir['**/']
2220
+ message "#{@files.size} files."
2109
2221
  # redraw
2110
2222
  end
2111
2223
 
@@ -2114,10 +2226,10 @@ end
2114
2226
  # structure than files.
2115
2227
  def tree
2116
2228
  # Caution: use only for small projects, don't use in root.
2117
- $title = 'Full Tree'
2118
- # $files = `zsh -c 'print -rl -- **/*(#{$sorto}#{$hidden}M)'`.split("\n")
2119
- $files = Dir['**/*']
2120
- message "#{$files.size} files."
2229
+ @title = 'Full Tree'
2230
+ # @files = `zsh -c 'print -rl -- **/*(#{@sorto}#{@hidden}M)'`.split("\n")
2231
+ @files = Dir['**/*']
2232
+ message "#{@files.size} files."
2121
2233
  # redraw
2122
2234
  end
2123
2235
 
@@ -2125,25 +2237,26 @@ end
2125
2237
  # In some cases it shows mostly .git files, we need to prune those
2126
2238
  def recent_files
2127
2239
  # print -rl -- **/*(Dom[1,10])
2128
- $title = 'Recent files'
2240
+ @title = 'Recent files'
2129
2241
  # zsh D DOT_GLOB, show dot files
2130
2242
  # zsh om order on modification time
2131
- $files = `zsh -c 'print -rl -- **/*(Dom[1,15])'`.split("\n").reject {|f| f[0] == '.'}
2243
+ @files = `zsh -c 'print -rl -- **/*(Dom[1,15])'`.split("\n").reject { |f| f[0] == '.' }
2132
2244
  # redraw
2133
2245
  end
2134
2246
 
2135
2247
  def select_current
2136
- ## vp is local there, so i can do $vp[0]
2137
- # open_file $view[$sta] if $view[$sta]
2138
- open_file $view[$cursor] if $view[$cursor]
2248
+ ## vp is local there, so i can do @vp[0]
2249
+ # open_file @view[@sta] if @view[@sta]
2250
+ open_file @view[@cursor] if @view[@cursor]
2139
2251
  end
2140
2252
 
2141
2253
  ## create a list of dirs in which some action has happened, for saving
2142
- def push_used_dirs(d = Dir.pwd)
2143
- # $used_dirs.index(d) || $used_dirs.push(d)
2144
- return if $used_dirs[0] == d
2145
- $used_dirs.delete(d) if $used_dirs.index(d)
2146
- $used_dirs.insert(0, d)
2254
+ def push_used_dirs d=Dir.pwd
2255
+ # @used_dirs.index(d) || @used_dirs.push(d)
2256
+ return if @used_dirs[0] == d
2257
+
2258
+ @used_dirs.delete(d) if @used_dirs.index(d)
2259
+ @used_dirs.insert(0, d)
2147
2260
  end
2148
2261
 
2149
2262
  def pbold text
@@ -2167,22 +2280,21 @@ end
2167
2280
  ## return shortcut/hint for an index (offset in file array)
2168
2281
  # ix is the index of a file in the complete array (view)
2169
2282
  def get_shortcut index
2170
-
2171
2283
  # Case where user has panned to the right columns:
2172
2284
  # Earlier, we showed '<' in left columns, if user has panned right.
2173
2285
  # Now we show unused shortcuts after exhausting them.
2174
- # return '<' if index < $stact
2175
- if index < $stact
2176
- index = $viewport.size - $stact + index
2177
- i = $IDX[index]
2286
+ # return '<' if index < @stact
2287
+ if index < @stact
2288
+ index = @viewport.size - @stact + index
2289
+ i = IDX[index]
2178
2290
  return i if i
2179
2291
 
2180
2292
  return '['
2181
2293
  end
2182
2294
 
2183
2295
  # Normal case (user has not panned columns)
2184
- index -= $stact
2185
- i = $IDX[index]
2296
+ index -= @stact
2297
+ i = IDX[index]
2186
2298
  return i if i
2187
2299
 
2188
2300
  '->'
@@ -2192,7 +2304,7 @@ end
2192
2304
  # Called when user types a key
2193
2305
  # should we even ask for a second key if there are not enough rows
2194
2306
  # What if we want to also trap z with numbers for other purposes
2195
- def get_index(key, vsz = 999)
2307
+ def get_index key, vsz=999
2196
2308
  # @log.debug "Etners get_index with #{key}"
2197
2309
  i = convert_key_to_index key
2198
2310
  return i if i
@@ -2206,8 +2318,8 @@ def get_index(key, vsz = 999)
2206
2318
  i = convert_key_to_index("#{key}#{zch}")
2207
2319
  # @log.debug "convert returned #{i} for #{key}#{zch}"
2208
2320
  return i if i
2209
- # i = $IDX.index
2210
- # return i + $stact if i
2321
+ # i = IDX.index
2322
+ # return i + @stact if i
2211
2323
  end
2212
2324
  end
2213
2325
  nil
@@ -2217,72 +2329,272 @@ end
2217
2329
  # Earlier this was simple, but now that we put hints/shortcuts
2218
2330
  # in rows on the left after panning, we need to account for cycled hints.
2219
2331
  def convert_key_to_index key
2220
- i = $IDX.index(key)
2221
- if i
2222
- # @log.debug "get_index with #{key}: #{i}. #{$stact}. #{$viewport.size}"
2223
- vps = $viewport.size
2224
- # TODO: if very high key given, consider going to last file ?
2225
- # that way one can press zz or ZZ to go to last file.
2226
- # 2019-04-11 - XXX actually this doesnt place the cursor on last file
2227
- # it opens it, which may not be what we want
2228
- retnil = nil # vps - 1 # nil
2229
- return retnil if $stact == 0 && i + $stact >= vps
2230
- # return nil if $stact > 0 && i + $stact >= vps && i + $stact - vps >= $stact
2231
- return retnil if $stact > 0 && i + $stact >= vps && i - vps >= 0
2232
-
2233
- if i + $stact >= vps
2234
- # panning case, hints are recycled
2235
- return (i + $stact) - vps
2332
+ i = IDX.index(key)
2333
+ return nil unless i
2334
+
2335
+ # @log.debug "get_index with #{key}: #{i}. #{@stact}. #{@viewport.size}"
2336
+ vps = @viewport.size
2337
+ # TODO: if very high key given, consider going to last file ?
2338
+ # that way one can press zz or ZZ to go to last file.
2339
+ # 2019-04-11 - XXX actually this doesnt place the cursor on last file
2340
+ # it opens it, which may not be what we want
2341
+ retnil = nil # vps - 1 # nil
2342
+ # user has entered a key that is outside of range, return nil
2343
+ return retnil if @stact == 0 && i + @stact >= vps
2344
+
2345
+ # again, key out of range
2346
+ # return nil if @stact > 0 && i + @stact >= vps && i + @stact - vps >= @stact
2347
+ return retnil if @stact > 0 && i + @stact >= vps && i - vps >= 0
2348
+
2349
+ # panning case, hints are recycled
2350
+ return (i + @stact) - vps if i + @stact >= vps
2351
+
2352
+ # regular hint
2353
+ return i + @stact # if i
2354
+
2355
+ end
2356
+
2357
+ def delete_file
2358
+ # file_actions :delete
2359
+ rbfiles = current_or_selected_files
2360
+ return if rbfiles.nil? || rbfiles.empty?
2361
+
2362
+ count = rbfiles.count
2363
+ first = rbfiles.first
2364
+ text = count == 1 ? File.basename(first) : "#{count} files"
2365
+ shfiles = Shellwords.join(rbfiles)
2366
+
2367
+ delcommand = 'rmtrash'
2368
+ clear_last_line
2369
+ print "#{delcommand} #{text[0..40]} ? [yn?]: "
2370
+ key = get_char
2371
+ view_selected_files if key == '?'
2372
+ return if key != 'y'
2373
+
2374
+ clear_last_line
2375
+ print "\r deleting ..."
2376
+ system "#{delcommand} #{shfiles}"
2377
+ @log.info "trashed #{shfiles}."
2378
+ message "Deleted #{text[0..40]}."
2379
+ refresh
2380
+ end
2381
+
2382
+ def move_file
2383
+ rbfiles = current_or_selected_files
2384
+ return if rbfiles.nil? || rbfiles.empty?
2385
+
2386
+ count = rbfiles.count
2387
+ first = rbfiles.first
2388
+ text = count == 1 ? File.basename(first) : "#{count} files"
2389
+
2390
+ # multiple files can only be moved to a directory
2391
+ default = @move_target.nil? ? '.' : @move_target
2392
+ target = readline "Move #{text[0..40]} to (#{default}): "
2393
+ return unless target
2394
+
2395
+ target = default if target == ''
2396
+ target = File.expand_path(target)
2397
+ return if target == ''
2398
+
2399
+ if count > 1 && !File.directory?(target)
2400
+ perror 'Move target must be a directory for multiple files.'
2401
+ return
2402
+ end
2403
+
2404
+ if count == 1 && !File.directory?(target) && File.exist?(target)
2405
+ perror "Target #{target} exists."
2406
+ return
2407
+ end
2408
+
2409
+ begin
2410
+ FileUtils.mv rbfiles, target
2411
+ message "Moved #{text} to #{target}."
2412
+ rescue StandardError => exc
2413
+ @log.warn "move_file: #{exc}."
2414
+ @log.warn "MOVE: files: #{rbfiles}, target:#{target}"
2415
+ perror exc.to_s
2416
+ end
2417
+ refresh
2418
+ end
2419
+
2420
+ def copy_file
2421
+ rbfiles = current_or_selected_files
2422
+ return if rbfiles.nil? || rbfiles.empty?
2423
+
2424
+ count = rbfiles.count
2425
+ first = rbfiles.first
2426
+ text = "#{count} files"
2427
+
2428
+ # Target must be directory for multiple files.
2429
+ # NOTE: target should not be same as source dir but there can be files
2430
+ # from multiple directories
2431
+ if count == 1
2432
+ if File.exist? File.basename(first)
2433
+ default = get_unique_file_name File.basename(first)
2434
+ Readline::HISTORY.push default
2236
2435
  else
2237
- # regular hint
2238
- return i + $stact #if i
2436
+ default = '.'
2239
2437
  end
2438
+ # default : if file exists here, then add suffix
2439
+ # if no file here, then directory is default.
2440
+ else
2441
+ default = if File.exist? File.basename(first)
2442
+ ''
2443
+ else
2444
+ '.'
2445
+ end
2446
+ # current directory is default if first file does not exist
2447
+ # if first file exists here, then no default
2448
+ end
2449
+ target = readline "Copy to (#{default}): "
2450
+ return unless target # C-c
2451
+
2452
+ target = default if target == ''
2453
+ target = File.expand_path(target)
2454
+ return if target == ''
2455
+
2456
+ if count > 1 && !File.directory?(target)
2457
+ perror 'Copy target must be a directory for multiple files.'
2458
+ return
2240
2459
  end
2241
- nil
2460
+
2461
+ if count == 1 && !File.directory?(target) && File.exist?(target)
2462
+ perror "Target #{target} exists."
2463
+ return
2464
+ end
2465
+
2466
+ # if rbfiles is array, then dest must be a directory.
2467
+ rbfiles = rbfiles.first if rbfiles.count == 1
2468
+
2469
+ begin
2470
+ FileUtils.cp rbfiles, target
2471
+ message "Copied #{text} to #{target}."
2472
+ rescue StandardError => exc
2473
+ @log.warn exc.to_s
2474
+ @log.warn "Target: #{target}, files:#{rbfiles}"
2475
+ perror exc.to_s
2476
+ end
2477
+ refresh
2242
2478
  end
2243
2479
 
2244
- def delete_file
2245
- file_actions :delete
2480
+ # generate a unique filename by adding a zero padded number prior to the extension.
2481
+ # This is used only during copy operation.
2482
+ def get_unique_file_name fname
2483
+ 100.times do |i|
2484
+ suffix = "%03d" % i
2485
+ extn = File.extname(fname)
2486
+ base = File.basename(fname, extn)
2487
+ # f = fname + '.' + suffix
2488
+ f = base + suffix + extn
2489
+ return f unless File.exist?(f)
2490
+ end
2491
+
2492
+ timestamp = Time.now.strftime("%Y%m%d-%H%M%S")
2493
+ return fname + '.' + timestamp
2246
2494
  end
2247
2495
 
2248
- def move_instant
2249
- # FIXME: cannot be in target directory and do auto update
2496
+ def rename_file
2497
+ rbfiles = current_or_selected_files
2498
+ return if rbfiles.nil? || rbfiles.empty?
2250
2499
 
2251
- if $selected_files.empty?
2252
- target = readline "Enter target directory for moving files (#{@move_target}):"
2253
- return unless target
2254
- return if target == '' && @move_target.nil?
2500
+ count = rbfiles.count
2501
+ first = rbfiles.first
2502
+ text = count == 1 ? File.basename(first) : "#{count} files"
2255
2503
 
2256
- # take default value if user presses Enter
2257
- target = @move_target if target == ''
2258
- return unless target
2504
+ if count > 1
2505
+ perror 'Select only one file for rename.'
2506
+ return
2507
+ end
2259
2508
 
2260
- # current dir if dot pressed FIXME you cannot move to current dir !!!
2509
+ Readline::HISTORY.push File.basename(first)
2510
+ target = readline "Rename #{text[0..40]} to : "
2511
+ return if target == '' || target == '.' || target == '..'
2512
+
2513
+ if File.exist? target
2514
+ perror "Target (#{target}) exists."
2515
+ return
2516
+ end
2517
+
2518
+ begin
2519
+ FileUtils.mv first, target
2520
+ message "Renamed to #{target}."
2521
+ @log.info "Renamed #{first} to #{target}."
2522
+ rescue StandardError => exc
2523
+ @log.warn exc.to_s
2524
+ @log.warn "RENAME: files: #{first}, target:#{target}"
2525
+ pause exc.to_s
2526
+ end
2527
+ refresh
2528
+ end
2529
+
2530
+ # remove spaces and brackets from file name
2531
+ # replace space with underscore, removes square and round brackets
2532
+ def remove_spaces_from_name
2533
+ execute_script 'remove_brackets'
2534
+ end
2535
+
2536
+ def zip_file
2537
+ rbfiles = current_or_selected_files
2538
+ return if rbfiles.nil? || rbfiles.empty?
2539
+
2540
+ # count = rbfiles.count
2541
+ # first = rbfiles.first
2542
+ # text = count == 1 ? File.basename(first) : "#{count} files"
2543
+
2544
+ extn = '.tgz'
2545
+ default = "archive#{extn}"
2546
+ Readline::HISTORY.push default # check for exist before pushing
2547
+ target = readline "Archive name (#{default}): "
2548
+ return unless target
2549
+ return if target == ''
2550
+
2551
+ if target && target.size < 4
2552
+ perror 'Use target of more than 4 characters.'
2553
+ return
2554
+ end
2555
+ target += extn if File.extname(target) == ''
2556
+
2557
+ if File.exist? target
2558
+ perror "Target (#{target}) exists."
2559
+ return
2560
+ end
2561
+
2562
+ # convert absolute paths to relative ones in this zip
2563
+ # the problem with zip is that we have full paths
2564
+ # so the zip file has full paths and extraction sucks
2565
+ require 'pathname'
2566
+ base = Pathname.new Dir.pwd
2567
+ relfiles = rbfiles.map { |f| p = Pathname.new(f); p.relative_path_from(base) }
2568
+ zfiles = Shellwords.join relfiles
2569
+
2570
+ system "tar zcvf #{target} #{zfiles}"
2571
+ message "Created #{target} with #{relfiles.count} files."
2572
+ setup_terminal
2573
+ refresh
2574
+ end
2575
+
2576
+ # instantly move to move target. Use during bulk operations so you don't have to
2577
+ # enter or goto target dir and come back.
2578
+ def move_instant
2579
+ # FIXME: cannot be in target directory and do auto update
2580
+ # should we have a key for specifying move_target ?
2581
+
2582
+ # for the mo, lets not move if nothing selected
2583
+ if @selected_files.empty?
2584
+ target = readline "Set Move target #{@move_target}:"
2261
2585
  target = Dir.pwd if target == '.'
2262
2586
  target = File.expand_path(target)
2263
- unless File.directory? target
2264
- perror "#{target} not a directory."
2265
- return
2266
- end
2267
- begin
2268
- f = current_file
2269
- FileUtils.mv f, target
2270
- @move_target = target
2271
- message "#{f} moved to #{File.basename(target)}. Target set."
2272
- @log.info "1.#{f} moved to #{target}."
2273
- rescue StandardError => exc
2274
- @log.warn "Case 1:"
2275
- @log.warn "Target is #{target}, file was #{f}"
2276
- @log.warn exc.to_s
2277
- end
2278
- refresh
2587
+ @move_target = target
2588
+ message "Move target is #{@move_target}. Select files and press this key."
2279
2589
  return
2280
2590
  end
2281
2591
 
2282
2592
  # files selected. Use earlier target if there, else ask
2593
+ # XXX how do we change it once set
2283
2594
  target = @move_target
2284
2595
  if target.nil? || target == ''
2285
- target = readline "Enter directory for moving files #{@move_target}:"
2596
+ count = @selected_files.count
2597
+ target = readline "Move #{count} files to :"
2286
2598
  return unless target
2287
2599
  end
2288
2600
  target = File.expand_path(target)
@@ -2291,15 +2603,14 @@ def move_instant
2291
2603
  return
2292
2604
  end
2293
2605
 
2294
- files = $selected_files
2295
- # todo: shellwords
2606
+ files = @selected_files
2296
2607
  ccount = 0
2297
2608
  files.each do |f|
2298
2609
  FileUtils.mv f, target
2299
2610
  @log.info "2.#{f} moved to #{target}."
2300
2611
  ccount += 1
2301
2612
  rescue StandardError => exc
2302
- @log.warn "Case 2:"
2613
+ @log.warn 'Case 2:'
2303
2614
  @log.warn "Target is #{target}, file was #{f}"
2304
2615
  @log.warn exc.to_s
2305
2616
  perror exc.to_s
@@ -2314,11 +2625,12 @@ end
2314
2625
  # prompt is the user friendly text of command such as list for ls, or extract for dtrx, page for less
2315
2626
  # pauseyn is whether to pause after command as in file or ls
2316
2627
  #
2317
- def command_file(prompt, *command)
2628
+ def command_file prompt, *command
2318
2629
  pauseyn = command.shift
2319
2630
  command = command.join ' '
2320
- print "[#{prompt}] Choose a file [#{$view[$cursor]}]: "
2321
- file = ask_hint $view[$cursor]
2631
+ clear_last_line
2632
+ print "[#{prompt}] Choose a file [#{@view[@cursor]}]: "
2633
+ file = ask_hint @view[@cursor]
2322
2634
  # print "#{prompt} :: Enter file shortcut: "
2323
2635
  # file = ask_hint
2324
2636
  perror 'Command Cancelled' unless file
@@ -2344,8 +2656,8 @@ def ask_hint deflt=nil
2344
2656
  key = get_char
2345
2657
  return deflt if key == 'ENTER'
2346
2658
 
2347
- ix = get_index(key, $viewport.size)
2348
- f = $viewport[ix] if ix
2659
+ ix = get_index(key, @viewport.size)
2660
+ f = @viewport[ix] if ix
2349
2661
  f
2350
2662
  end
2351
2663
 
@@ -2353,13 +2665,13 @@ end
2353
2665
  # NOTE: tput is ncurses dependent, so use stty
2354
2666
  #
2355
2667
  def screen_settings
2356
- $glines, $gcols = `stty size`.split.map{|e| e.to_i}
2357
- # $glines = `tput lines`.to_i
2358
- # $gcols = `tput cols`.to_i
2359
- $grows = $glines - 3
2360
- # $pagesize = 60
2361
- # $gviscols = 3
2362
- $pagesize = $grows * $gviscols
2668
+ @glines, @gcols = `stty size`.split.map(&:to_i)
2669
+ # @glines = `tput lines`.to_i
2670
+ # @gcols = `tput cols`.to_i
2671
+ @grows = @glines - 3
2672
+ # @pagesize = 60
2673
+ # @gviscols = 3
2674
+ @pagesize = @grows * @gviscols
2363
2675
  end
2364
2676
 
2365
2677
  ## Tabs to next column in multi-column displays.
@@ -2371,24 +2683,24 @@ def column_next direction=0
2371
2683
  # right movement or panning cycles back to first column
2372
2684
  # leftward movement stops at first column.
2373
2685
  if direction == 0
2374
- $stact += $grows
2375
- $stact = 0 if $stact >= $viewport.size
2376
- $cursor += $grows
2686
+ @stact += @grows
2687
+ @stact = 0 if @stact >= @viewport.size
2688
+ @cursor += @grows
2377
2689
  # 2019-03-18 - zero loses offset. we need to maintain it
2378
- # $cursor = 0 if $cursor >= $viewport.size
2379
- if $cursor - $sta >= $viewport.size
2380
- $cursor -= $grows while $cursor > $sta
2381
- $stact -= $grows while $stact > 0
2382
- $cursor += $grows if $cursor < $sta
2383
- $stact += $grows if $stact < 0
2690
+ # @cursor = 0 if @cursor >= @viewport.size
2691
+ if @cursor - @sta >= @viewport.size
2692
+ @cursor -= @grows while @cursor > @sta
2693
+ @stact -= @grows while @stact > 0
2694
+ @cursor += @grows if @cursor < @sta
2695
+ @stact += @grows if @stact < 0
2384
2696
  end
2385
2697
  else
2386
- $stact -= $grows
2387
- $cursor -= $grows
2388
- $stact = 0 if $stact < 0
2698
+ @stact -= @grows
2699
+ @cursor -= @grows
2700
+ @stact = 0 if @stact < 0
2389
2701
  # setting cursor as zero loses the position or offset
2390
2702
  # We are trying to maintain offset
2391
- $cursor += $grows if $cursor < 0
2703
+ @cursor += @grows if @cursor < 0
2392
2704
  end
2393
2705
  # redraw
2394
2706
  end
@@ -2397,10 +2709,11 @@ end
2397
2709
  # I should be able to pass in new actions that are external commands
2398
2710
  # 2019-03-08 - TODO when a file name changes or moves it must be removed
2399
2711
  # from selection
2400
- def file_actions(action = nil)
2712
+ def file_actions action=nil
2401
2713
  h = { d: :delete, D: '/bin/rm', m: :move, v: ENV['EDITOR'] || :vim,
2402
2714
  c: :copy, e: :execute,
2403
- l: :less, p: :most, o: :open }
2715
+ l: :less, p: :most,
2716
+ o: :open_current }
2404
2717
 
2405
2718
  rbfiles = current_or_selected_files # use with ruby FileUtils
2406
2719
  return if rbfiles.nil? || rbfiles.empty?
@@ -2448,7 +2761,7 @@ def file_actions(action = nil)
2448
2761
  if action
2449
2762
  menu_text = action
2450
2763
  else
2451
- key, menu_text = menu "File Menu for #{text}", h
2764
+ key, menu_text = menu "File Menu for #{text[0..@gcols-20]}", h
2452
2765
  menu_text = :quit if key == 'q'
2453
2766
  end
2454
2767
  return unless menu_text # pressed some wrong key
@@ -2456,150 +2769,32 @@ def file_actions(action = nil)
2456
2769
  case menu_text.to_sym
2457
2770
 
2458
2771
  when :quit
2459
-
2772
+ 1
2460
2773
  when :delete
2461
- delcommand = 'rmtrash'
2462
- clear_last_line
2463
- print "#{delcommand} #{text} ? [yn?]: "
2464
- key = get_char
2465
- view_selected_files if key == '?'
2466
- return if key != 'y'
2467
-
2468
- clear_last_line
2469
- print "\r deleting ..."
2470
- system "#{delcommand} #{shfiles}"
2471
- message "Deleted #{text}."
2472
- refresh
2774
+ delete_file
2473
2775
 
2474
2776
  when :move
2475
- # multiple files can only be moved to a directory
2476
- default = @move_target.nil? ? '.' : @move_target
2477
- target = readline "Move #{text} to (#{default}): "
2478
- return unless target
2479
-
2480
- target = default if target == ''
2481
- target = File.expand_path(target)
2482
- return if target == ''
2483
-
2484
- if count > 1 && !File.directory?(target)
2485
- perror 'Move target must be a directory for multiple files.'
2486
- return
2487
- end
2488
-
2489
- if count == 1 && !File.directory?(target) && File.exist?(target)
2490
- perror "Target #{target} exists."
2491
- return
2492
- end
2493
-
2494
- begin
2495
- FileUtils.mv rbfiles, target
2496
- message "Moved #{text} to #{target}."
2497
- rescue StandardError => exc
2498
- @log.warn "C-x move: #{exc.to_s}."
2499
- @log.warn "MOVE: files: #{rbfiles}, target:#{target}"
2500
- perror exc.to_s
2501
- end
2502
- # 2019-03-08 - TODO if success remove from selection
2503
- refresh
2777
+ move_file
2504
2778
 
2505
2779
  when :copy
2506
- # Target must be directory for multiple files.
2507
- # NOTE: target should not be same as source dir but there can be files
2508
- # from multiple directories
2509
- default = @move_target.nil? ? '.' : @move_target
2510
- target = readline "Copy #{text} to (#{default}): "
2511
- return unless target # C-c
2512
-
2513
- target = default if target == ''
2514
- target = File.expand_path(target)
2515
- return if target == ''
2516
-
2517
- if count > 1 && !File.directory?(target)
2518
- perror 'Copy target must be a directory for multiple files.'
2519
- return
2520
- end
2780
+ copy_file
2521
2781
 
2522
- if count == 1 && !File.directory?(target) && File.exist?(target)
2523
- perror "Target #{target} exists."
2524
- return
2525
- end
2782
+ when :zip
2783
+ zip_file
2526
2784
 
2527
- begin
2528
- FileUtils.cp rbfiles, target
2529
- message "Copied #{text} to #{target}."
2530
- rescue StandardError => exc
2531
- perror exc.to_s
2532
- end
2533
- refresh
2785
+ when :rename
2786
+ rename_file
2534
2787
 
2535
2788
  when :chdir
2536
2789
  # will only work if one selected. Check this out
2537
2790
  # This works if you have searched for files and got a list
2538
2791
  # with different paths.
2539
2792
  # This should not be shown in regular listings XXX
2540
- if count == 1
2541
- change_dir File.dirname(File.expand_path(rbfiles.first))
2542
- end
2793
+ change_dir File.dirname(File.expand_path(rbfiles.first)) if count == 1
2543
2794
 
2544
2795
  when :set_move_target
2545
2796
  set_move_target current_file
2546
2797
 
2547
- when :zip
2548
-
2549
- target = readline 'Archive name: '
2550
- return unless target
2551
- return if target == ''
2552
-
2553
- if File.exist? target
2554
- perror "Target (#{target}) exists"
2555
- return
2556
- end
2557
- if target && target.size < 4
2558
- perror 'Use target of more than 4 characters.'
2559
- return
2560
- end
2561
-
2562
- # convert absolute paths to relative ones in this zip
2563
- require 'pathname'
2564
- base = Pathname.new Dir.pwd
2565
- relfiles = rbfiles.map {|f| p = Pathname.new(f); p.relative_path_from(base) }
2566
- zfiles = Shellwords.join relfiles
2567
-
2568
- # the problem with zip is that we have full paths
2569
- # so the zip file has full paths and extraction sucks
2570
-
2571
- # pause "(#{target}).zipping #{relfiles.count}: #{zfiles}"
2572
- system "tar zcvf #{target} #{zfiles}"
2573
- message "Created #{target} with #{relfiles.count} files."
2574
- setup_terminal
2575
- refresh
2576
-
2577
- when :rename
2578
- if count > 1
2579
- perror 'Select only one file for rename.'
2580
- return
2581
- end
2582
-
2583
- target = readline "Rename #{text} to : "
2584
- return if target == '' || target == '.' || target == '..'
2585
-
2586
- # file = File.expand_path(files)
2587
- # target = File.basename(file) if target == '.'
2588
- if File.exist? target
2589
- perror "Target (#{target}) exists."
2590
- return
2591
- end
2592
-
2593
- begin
2594
- FileUtils.mv first, target
2595
- message "Renamed #{first} to #{target}."
2596
- rescue StandardError => exc
2597
- @log.warn exc.to_s
2598
- @log.warn "RENAME: files: #{first}, target:#{target}"
2599
- pause exc.to_s
2600
- end
2601
- refresh
2602
-
2603
2798
  when :most, :less, :vim
2604
2799
 
2605
2800
  system "#{menu_text} #{shfiles}"
@@ -2607,32 +2802,7 @@ def file_actions(action = nil)
2607
2802
  # should we remove from selection ?
2608
2803
 
2609
2804
  when :remspace
2610
- # replace space with underscore in filename
2611
- # Issue. in many cases directory may have spaces,
2612
- # so we are using basename only. So use in one directory.
2613
- # TODO: move to script
2614
- clear_last_line
2615
- pause "Remove spaces from #{text}."
2616
-
2617
- ccount = 0
2618
- rbfiles.each do |name|
2619
- f = File.basename(name)
2620
- next unless File.exist?(f)
2621
- next unless f.index ' '
2622
-
2623
- target = f.tr(' ', '_')
2624
- next if File.exist? target
2625
-
2626
- begin
2627
- FileUtils.mv f, target
2628
- ccount += 1
2629
- rescue StandardError => exc
2630
- @log.warn "REMSPACE: #{exc.to_s}"
2631
- perror exc.to_s
2632
- end
2633
- end
2634
- message "Renamed #{ccount} files."
2635
- refresh
2805
+ remove_spaces_from_name
2636
2806
 
2637
2807
  when :execute
2638
2808
  execute
@@ -2649,6 +2819,7 @@ def file_actions(action = nil)
2649
2819
  system "#{menu_text} #{shfiles}"
2650
2820
  pause # putting this back 2019-04-13 - file doesn't show anything
2651
2821
  message "Ran #{menu_text}."
2822
+ @log.info "#{menu_text} #{shfiles}"
2652
2823
  setup_terminal
2653
2824
  refresh
2654
2825
  end
@@ -2656,13 +2827,13 @@ def file_actions(action = nil)
2656
2827
  return if count == 0
2657
2828
 
2658
2829
  clean_selected_files
2659
-
2830
+ visual_block_clear # 2019-04-15 - get out of mode after operation over.
2660
2831
  end
2661
2832
 
2662
2833
  # remove non-existent files from select list due to move or delete
2663
2834
  # or rename or whatever
2664
2835
  def clean_selected_files
2665
- $selected_files.select! { |x| x = File.expand_path(x); File.exist?(x) }
2836
+ @selected_files.select! { |x| x = File.expand_path(x); File.exist?(x) }
2666
2837
  end
2667
2838
 
2668
2839
  # set the default target for further moves
@@ -2675,13 +2846,12 @@ def set_move_target cf=current_file
2675
2846
  message "Move target set to #{cf}."
2676
2847
  end
2677
2848
 
2678
-
2679
2849
  # increase or decrease column
2680
- def columns_incdec(howmany)
2681
- $gviscols += howmany.to_i
2682
- $gviscols = 1 if $gviscols < 1
2683
- $gviscols = 6 if $gviscols > 6
2684
- $pagesize = $grows * $gviscols
2850
+ def columns_incdec howmany
2851
+ @gviscols += howmany.to_i
2852
+ @gviscols = 1 if @gviscols < 1
2853
+ @gviscols = 6 if @gviscols > 6
2854
+ @pagesize = @grows * @gviscols
2685
2855
  end
2686
2856
 
2687
2857
  # bind a key to an external command wich can be then be used for files
@@ -2692,7 +2862,7 @@ def bindkey_ext_command
2692
2862
  key = get_char
2693
2863
  return if key == 'Q'
2694
2864
 
2695
- if key =~ /^[A-Z]$/
2865
+ if /^[A-Z]$/.match?(key)
2696
2866
  print "Enter an external command to bind to #{key}: "
2697
2867
  com = gets.chomp
2698
2868
  if com != ''
@@ -2702,7 +2872,7 @@ def bindkey_ext_command
2702
2872
  end
2703
2873
  print 'Pause after output [y/n]: '
2704
2874
  yn = get_char
2705
- $bindings[key] = "command_file #{pro} #{yn} #{com}"
2875
+ @bindings[key] = "command_file #{pro} #{yn} #{com}"
2706
2876
  end
2707
2877
  end
2708
2878
 
@@ -2715,22 +2885,22 @@ def ag
2715
2885
  pattern = readline 'Enter a pattern to search (ag): '
2716
2886
  return if pattern == ''
2717
2887
 
2718
- $title = "Files found using 'ag -t: ' #{pattern}"
2888
+ @title = "Files found using 'ag -t: ' #{pattern}"
2719
2889
 
2720
2890
  ## ag options :
2721
2891
  # -t : all text files
2722
2892
  # -l : print only file names
2723
2893
  # -a : print all files, even ignored
2724
- system %[ag -t "#{pattern}"]
2894
+ system %(ag -t "#{pattern}" | less)
2725
2895
 
2726
2896
  pause
2727
2897
  files = `ag -lt "#{pattern}"`.split("\n")
2728
2898
  if files.empty?
2729
2899
  perror "No files found for #{pattern}."
2730
- $title = nil
2900
+ @title = nil
2731
2901
  return
2732
2902
  end
2733
- $files = files
2903
+ @files = files
2734
2904
  # redraw
2735
2905
  end
2736
2906
 
@@ -2740,12 +2910,12 @@ def ffind
2740
2910
  pattern = readline '! find . -iname :'
2741
2911
  return if pattern == ''
2742
2912
 
2743
- $title = "Files found using 'find' #{pattern}"
2913
+ @title = "Files found using 'find' #{pattern}"
2744
2914
  files = `find . -iname "#{pattern}"`.split("\n")
2745
2915
  if files.empty?
2746
2916
  perror 'No files found. Try adding *'
2747
2917
  else
2748
- $files = files
2918
+ @files = files
2749
2919
  end
2750
2920
  # redraw
2751
2921
  end
@@ -2755,13 +2925,13 @@ def locate
2755
2925
  pattern = readline
2756
2926
  return if pattern == ''
2757
2927
 
2758
- $title = "Files found using 'locate' #{pattern}"
2928
+ @title = "Files found using 'locate' #{pattern}"
2759
2929
  files = `locate #{pattern}`.split("\n")
2760
2930
  files.select! { |x| x = File.expand_path(x); File.exist?(x) }
2761
2931
  if files.empty?
2762
2932
  perror 'No files found.'
2763
2933
  else
2764
- $files = files
2934
+ @files = files
2765
2935
  end
2766
2936
  # redraw
2767
2937
  end
@@ -2773,11 +2943,11 @@ def z_interface
2773
2943
  file = File.expand_path('~/.z')
2774
2944
  return unless File.exist? file
2775
2945
 
2776
- $title = 'Directories from ~/.z'
2777
- $files = `sort -rn -k2 -t '|' ~/.z | cut -f1 -d '|'`.split("\n")
2946
+ @title = 'Directories from ~/.z'
2947
+ @files = `sort -rn -k2 -t '|' ~/.z | cut -f1 -d '|'`.split("\n")
2778
2948
  home = ENV['HOME']
2779
2949
  # shorten file names
2780
- $files.collect! do |f|
2950
+ @files.collect! do |f|
2781
2951
  f.sub(/#{home}/, '~')
2782
2952
  end
2783
2953
  # redraw
@@ -2785,6 +2955,7 @@ end
2785
2955
 
2786
2956
  def vidir
2787
2957
  system 'vidir'
2958
+ refresh
2788
2959
  setup_terminal
2789
2960
  end
2790
2961
 
@@ -2804,140 +2975,142 @@ end
2804
2975
  # move cursor down a line
2805
2976
  def cursor_dn
2806
2977
  @movement = :down
2807
- @old_cursor = $cursor
2978
+ @old_cursor = @cursor
2808
2979
  moveto(pos + 1)
2809
2980
  end
2810
2981
 
2811
2982
  def cursor_up
2812
- @old_cursor = $cursor
2983
+ @old_cursor = @cursor
2813
2984
  @movement = :up
2814
2985
  moveto(pos - 1)
2815
2986
  end
2816
2987
 
2817
2988
  # return cursor position
2818
2989
  def pos
2819
- $cursor
2990
+ @cursor
2820
2991
  end
2821
2992
 
2822
2993
  # move cursor to given position/line
2823
2994
  def moveto position
2824
- orig = $cursor
2825
- $cursor = position
2826
- $cursor = [$cursor, $view.size - 1].min
2827
- $cursor = [$cursor, 0].max
2995
+ orig = @cursor
2996
+ @cursor = position
2997
+ @cursor = [@cursor, @view.size - 1].min
2998
+ @cursor = [@cursor, 0].max
2828
2999
 
2829
3000
  # try to stop it from landing on separator
2830
3001
  if current_file == SEPARATOR
2831
- $cursor += 1 if @movement == :down
2832
- $cursor -= 1 if @movement == :up
3002
+ @cursor += 1 if @movement == :down
3003
+ @cursor -= 1 if @movement == :up
2833
3004
  return
2834
3005
  end
2835
3006
 
2836
3007
  # 2019-03-18 - adding sta
2837
- # $sta = position - only when page flips and file not visible
3008
+ # @sta = position - only when page flips and file not visible
2838
3009
  # FIXME not correct, it must stop at end or correctly cycle
2839
3010
  # sta goes to 0 but cursor remains at 70
2840
3011
  # viewport.size may be wrong here, maybe should be pagesize only
2841
- oldsta = $sta
2842
- if $cursor - $sta >= $pagesize
2843
- $sta += $pagesize
2844
- # elsif $sta - $cursor >= $viewport.size
3012
+ oldsta = @sta
3013
+ if @cursor - @sta >= @pagesize
3014
+ @sta += @pagesize
3015
+ # elsif @sta - @cursor >= @viewport.size
2845
3016
  end
2846
- if $sta > $cursor
2847
- $sta -= $pagesize
2848
- # $sta = $cursor
3017
+ if @sta > @cursor
3018
+ @sta -= @pagesize
3019
+ # @sta = @cursor
2849
3020
  end
2850
3021
 
2851
- @movement = nil if oldsta != $sta # we need to redraw
3022
+ @movement = nil if oldsta != @sta # we need to redraw
2852
3023
 
2853
- star = [orig, $cursor].min
2854
- fin = [orig, $cursor].max
2855
- return unless $visual_mode
3024
+ star = [orig, @cursor].min
3025
+ fin = [orig, @cursor].max
3026
+ return unless @visual_mode
2856
3027
 
2857
3028
  @movement = nil # visual mode needs to redraw page
2858
3029
 
2859
3030
  # PWD has to be there in selction
2860
3031
  if selected? current_file
2861
3032
  # this depends on the direction
2862
- # $selected_files = $selected_files - $view[star..fin]
2863
- remove_from_selection $view[star..fin]
3033
+ # @selected_files = @selected_files - @view[star..fin]
3034
+ remove_from_selection @view[star..fin]
2864
3035
  ## current row remains in selection always.
2865
3036
  add_to_selection current_file
2866
3037
  else
2867
- # $selected_files.concat $view[star..fin]
2868
- add_to_selection $view[star..fin]
3038
+ # @selected_files.concat @view[star..fin]
3039
+ add_to_selection @view[star..fin]
2869
3040
  end
2870
- message "#{$selected_files.count} files selected. "
2871
- # ensure
3041
+ message "#{@selected_files.count} files selected. "
3042
+ # ensure
2872
3043
  # redraw
2873
3044
  end
2874
3045
  # --
2875
3046
 
2876
3047
  # is given file in selected array
2877
- def visited?(file)
2878
- $current_dir ||= Dir.pwd
2879
- file = File.join($current_dir, file)
2880
- return $visited_files.index file
3048
+ def visited? file
3049
+ @current_dir ||= Dir.pwd
3050
+ file = File.join(@current_dir, file)
3051
+ return @visited_files.index file
2881
3052
  end
2882
3053
 
2883
3054
  # ------------- selection related methods --------------------------------#
2884
3055
 
2885
3056
  # is given file in selected array
2886
- def selected?(file)
2887
- $current_dir ||= Dir.pwd
2888
- file = File.join($current_dir, file)
2889
- return $selected_files.index file
3057
+ def selected? file
3058
+ @current_dir ||= Dir.pwd
3059
+ file = File.join(@current_dir, file)
3060
+ return @selected_files.index file
2890
3061
  end
2891
3062
 
2892
3063
  # add given file/s to selected file list
2893
- def add_to_selection(file)
3064
+ def add_to_selection file
2894
3065
  ff = file
2895
3066
  case file
2896
3067
  when String
2897
3068
  ff = [file]
2898
3069
  end
2899
- $current_dir ||= Dir.pwd
3070
+ @current_dir ||= Dir.pwd
2900
3071
  ff.each do |f|
2901
- full = File.join($current_dir, f)
2902
- $selected_files.push(full) unless $selected_files.include?(full)
3072
+ full = File.join(@current_dir, f)
3073
+ @selected_files.push(full) unless @selected_files.include?(full)
2903
3074
  end
2904
3075
  end
2905
3076
 
2906
- def remove_from_selection(file)
3077
+ def remove_from_selection file
2907
3078
  ff = file
2908
3079
  case file
2909
3080
  when String
2910
3081
  ff = [file]
2911
3082
  end
2912
- $current_dir ||= Dir.pwd
3083
+ @current_dir ||= Dir.pwd
2913
3084
  ff.each do |f|
2914
- full = File.join($current_dir, f)
2915
- $selected_files.delete full
3085
+ full = File.join(@current_dir, f)
3086
+ @selected_files.delete full
2916
3087
  end
2917
3088
  end
2918
3089
 
2919
3090
  # ------------- visual mode methods --------------------------------#
2920
- def visual_mode_toggle
2921
- $mode = nil
2922
- $visual_mode = !$visual_mode
2923
- if $visual_mode
2924
- $mode = 'VIS'
2925
- $visual_block_start = $cursor
2926
- add_to_selection current_file
2927
- end
2928
- message "Visual mode is #{$visual_mode}."
3091
+ def toggle_visual_mode
3092
+ @mode = nil
3093
+ # @visual_mode = !@visual_mode
3094
+ toggle_value :visual_mode
3095
+ return unless @visual_mode
3096
+
3097
+ @mode = 'VIS'
3098
+ @visual_block_start = @cursor
3099
+ add_to_selection current_file
2929
3100
  end
2930
3101
 
2931
- # Called from Escape key only. Clears selection.
3102
+ # Called from Escape key and scripts and file actions. Clears selection.
2932
3103
  def visual_block_clear
2933
- if $visual_block_start
2934
- star = [$visual_block_start, $cursor].min
2935
- fin = [$visual_block_start, $cursor].max
2936
- remove_from_selection $view[star..fin]
2937
- end
2938
- $visual_block_start = nil
2939
- $visual_mode = nil
2940
- $mode = nil if $mode == 'VIS'
3104
+ if @visual_block_start
3105
+ star = [@visual_block_start, @cursor].min
3106
+ fin = [@visual_block_start, @cursor].max
3107
+ remove_from_selection @view[star..fin]
3108
+ end
3109
+ @visual_block_start = nil
3110
+ @toggles[:visual_mode] = @visual_mode = false
3111
+ @mode = nil if @mode == 'VIS'
3112
+ # is this the right place to put this ??? 2019-04-16 -
3113
+ clean_selected_files
2941
3114
  end
2942
3115
 
2943
3116
  # ------------- file matching methods --------------------------------#
@@ -2951,19 +3124,19 @@ def file_starting_with first_char=nil
2951
3124
  goto_line ix if ix
2952
3125
  end
2953
3126
 
2954
- def file_matching?(file, patt)
3127
+ def file_matching? file, patt
2955
3128
  file =~ /#{patt}/
2956
3129
  end
2957
3130
 
2958
3131
  ## generic method to take cursor to next position for a given condition
2959
- def return_next_match(binding, *args)
3132
+ def return_next_match binding, *args
2960
3133
  first = nil
2961
3134
  ix = 0
2962
- $view.each_with_index do |elem, ii|
3135
+ @view.each_with_index do |elem, ii|
2963
3136
  next unless binding.call(elem, *args)
2964
3137
 
2965
3138
  first ||= ii
2966
- if ii > $cursor
3139
+ if ii > @cursor
2967
3140
  ix = ii
2968
3141
  break
2969
3142
  end
@@ -2977,10 +3150,10 @@ end
2977
3150
  # position cursor on a specific line which could be on a nother page
2978
3151
  # therefore calculate the correct start offset of the display also.
2979
3152
  def goto_line pos
2980
- pages = ((pos * 1.00) / $pagesize).ceil
3153
+ pages = ((pos * 1.00) / @pagesize).ceil
2981
3154
  pages -= 1
2982
- $sta = pages * $pagesize + 1
2983
- $cursor = pos
3155
+ @sta = pages * @pagesize + 1
3156
+ @cursor = pos
2984
3157
  end
2985
3158
 
2986
3159
  # return filetype of file using `file` external command.
@@ -3002,10 +3175,10 @@ end
3002
3175
 
3003
3176
  def opener_for f
3004
3177
  # by default, default command is nil. Changed in toggle_pager_mode
3005
- $default_command ||= '$PAGER'
3178
+ @default_command ||= '$PAGER'
3006
3179
  # by default mode, is false, changed in toggle_pager_mode
3007
3180
  # Get filetype, and check for command for type, else extn else unknown
3008
- if !$editor_mode
3181
+ if !@editor_mode
3009
3182
  ft = filetype f
3010
3183
  comm = PAGER_COMMAND[ft] if ft
3011
3184
  comm ||= PAGER_COMMAND[File.extname(f)]
@@ -3015,30 +3188,30 @@ def opener_for f
3015
3188
  # opens everything? what of images etc
3016
3189
  # TODO use editor only for text, otherwise use filetype or another hash
3017
3190
  # like editor_command
3018
- comm = $default_command
3191
+ comm = @default_command
3019
3192
  end
3020
- comm ||= $default_command
3193
+ comm ||= @default_command
3021
3194
  comm
3022
3195
  end
3023
3196
 
3024
3197
  # save offset in directory so we can revert to it when we return
3025
3198
  def save_dir_pos
3026
3199
  # the next line meant that it would not save first directory.
3027
- # return if $sta == 0 && $cursor == 0
3200
+ # return if @sta == 0 && @cursor == 0
3028
3201
 
3029
- $dir_position[Dir.pwd] = [$sta, $cursor]
3202
+ @dir_position[Dir.pwd] = [@sta, @cursor]
3030
3203
  end
3031
3204
 
3032
3205
  # revert to the position we were at in this directory
3033
3206
  def revert_dir_pos
3034
- $sta = 0
3035
- $cursor = 0
3036
- a = $dir_position[Dir.pwd]
3207
+ @sta = 0
3208
+ @cursor = 0
3209
+ a = @dir_position[Dir.pwd]
3037
3210
  if a
3038
- $sta = a.first
3039
- $cursor = a[1]
3040
- raise "sta is nil for #{Dir.pwd} : #{$dir_position[Dir.pwd]}" unless $sta
3041
- raise 'cursor is nil' unless $cursor
3211
+ @sta = a.first
3212
+ @cursor = a[1]
3213
+ raise "sta is nil for #{Dir.pwd} : #{@dir_position[Dir.pwd]}" unless @sta
3214
+ raise 'cursor is nil' unless @cursor
3042
3215
  end
3043
3216
  end
3044
3217
 
@@ -3052,7 +3225,7 @@ def create_a_dir
3052
3225
  end
3053
3226
  begin
3054
3227
  FileUtils.mkdir str
3055
- $used_dirs.insert(0, str) if File.exist?(str)
3228
+ @used_dirs.insert(0, str) if File.exist?(str)
3056
3229
  refresh
3057
3230
  rescue StandardError => ex
3058
3231
  perror "Error in newdir: #{ex}"
@@ -3065,32 +3238,38 @@ def create_a_file
3065
3238
 
3066
3239
  system %($EDITOR "#{str}")
3067
3240
  setup_terminal
3068
- $visited_files.insert(0, str) if File.exist?(str)
3241
+ @visited_files.insert(0, str) if File.exist?(str)
3069
3242
  refresh
3070
3243
  end
3071
3244
 
3072
3245
  # convenience method to return file under cursor
3073
3246
  def current_file
3074
- $view[$cursor]
3247
+ @view[@cursor]
3075
3248
  end
3076
3249
 
3077
3250
  def current_or_selected_files
3078
- return $selected_files if !$selected_files.empty?
3251
+ return @selected_files unless @selected_files.empty?
3079
3252
 
3080
3253
  return [current_file]
3081
3254
  end
3082
3255
 
3083
3256
  # ------------------- scripts ------------------ #
3084
3257
  # prompt for scripts to execute, giving file name under cursor
3085
- def scripts
3258
+ def scripts binding=nil
3086
3259
  # some scripts may work with the selected_files and not want to be called
3087
3260
  # with filenames.
3088
3261
  write_selected_files
3089
3262
 
3090
- title = 'Select a script'
3091
- script_path = '~/.config/cetus/scripts'
3092
- binding = `find #{script_path} -type f | fzf --prompt="#{title} :"`.chomp
3093
- return if binding.nil? || binding == ''
3263
+ unless binding
3264
+ title = 'Select a script'
3265
+ script_path = '~/.config/cetus/scripts'
3266
+ binding = `find #{script_path} -type f | fzf --prompt="#{title} :"`.chomp
3267
+ return if binding.nil? || binding == ''
3268
+ end
3269
+ unless File.exist? binding
3270
+ @log.warn "Unable to find #{binding}"
3271
+ return
3272
+ end
3094
3273
 
3095
3274
  # TODO: check if binding is a file and executable
3096
3275
  # xargs only seems to take the first file
@@ -3098,20 +3277,38 @@ def scripts
3098
3277
  # cf = Shellwords.join(current_or_selected_files)
3099
3278
  # This was getting called repeatedly even if script used selected_files
3100
3279
  # current_or_selected_files.each do |file|
3101
- # system %( #{binding} "#{file}" )
3280
+ # system %( #{binding} "#{file}" )
3102
3281
  # end
3103
3282
 
3104
3283
  # 2019-04-08 - to avoid confusion, we pass name of file under cursor
3105
3284
  # script may ignore this and use selected_files
3285
+
3286
+ # reset clears the screen, we don't want that. just unhide cursor and echo keys TODO
3106
3287
  reset_terminal
3107
3288
  system %( #{binding} "#{current_file}" )
3108
3289
 
3109
3290
  # system %(echo "#{cf}" | xargs #{binding})
3110
3291
  pause
3111
3292
  setup_terminal
3293
+ visual_block_clear
3112
3294
  refresh
3113
3295
  end
3114
3296
 
3297
+ # this is quite important and should not be left to a script
3298
+ # example of calling a script from somewhere directly without selection
3299
+ def execute_script filename
3300
+ script_path = '~/.config/cetus/scripts'
3301
+ script = File.expand_path(File.join(script_path, 'filename'))
3302
+ return unless File.exist? script
3303
+
3304
+ scripts script
3305
+ end
3306
+
3307
+ # maybe do this internally
3308
+ def create_dir_with_selection
3309
+ execute_script 'create_dir_with_selection'
3310
+ end
3311
+
3115
3312
  # allow user to select a script that generates filenames which
3116
3313
  # will be displayed for selection or action.
3117
3314
  def generators
@@ -3123,9 +3320,8 @@ def generators
3123
3320
  return if binding.nil? || binding == ''
3124
3321
 
3125
3322
  # call generator and accept list of files
3126
- $title = "Files from #{File.basename(binding)}"
3127
- $files = `#{binding} "#{current_file}"`.split("\n")
3128
-
3323
+ @title = "Files from #{File.basename(binding)}"
3324
+ @files = `#{binding} "#{current_file}"`.split("\n")
3129
3325
  end
3130
3326
  # ------------- end of scripts --------------------------------#
3131
3327
 
@@ -3134,7 +3330,7 @@ def view_selected_files
3134
3330
  fname = write_selected_files
3135
3331
 
3136
3332
  unless fname
3137
- message "No file selected. "
3333
+ message 'No file selected. '
3138
3334
  return
3139
3335
  end
3140
3336
 
@@ -3143,11 +3339,15 @@ def view_selected_files
3143
3339
  end
3144
3340
  # ------------- end of view_selected_files --------------------------------#
3145
3341
 
3342
+ def list_selected_files
3343
+ @title = 'Selected Files'
3344
+ @files = @selected_files
3345
+ end
3346
+
3146
3347
  # write selected files to a file and return path
3147
3348
  # if no selected files then blank out the file, or else
3148
3349
  # script could use old selection again.
3149
3350
  def write_selected_files
3150
-
3151
3351
  require 'pathname'
3152
3352
  # fname = File.join(File.dirname(CONFIG_FILE), 'selected_files')
3153
3353
  # 2019-04-10 - changed to ~/tmp otherwise confusion about location
@@ -3155,7 +3355,7 @@ def write_selected_files
3155
3355
  fname = File.expand_path(fname)
3156
3356
 
3157
3357
  # remove file if no selection
3158
- if $selected_files.empty?
3358
+ if @selected_files.empty?
3159
3359
  File.unlink(fname) if File.exist?(fname)
3160
3360
  return nil
3161
3361
  end
@@ -3164,8 +3364,7 @@ def write_selected_files
3164
3364
  # TODO: what if unix commands need escaped files ?
3165
3365
  base = Pathname.new Dir.pwd
3166
3366
  File.open(fname, 'w') do |file|
3167
- $selected_files.each do |row|
3168
-
3367
+ @selected_files.each do |row|
3169
3368
  # use relative filename. Otherwise things like zip and tar run into issues
3170
3369
  unless @selected_files_fullpath_flag
3171
3370
  p = Pathname.new(row)
@@ -3178,23 +3377,24 @@ def write_selected_files
3178
3377
 
3179
3378
  return fname
3180
3379
  end
3380
+
3181
3381
  ##
3182
3382
  # Editing of the User Dir List.
3183
3383
  # remove current entry from used dirs list, since we may not want some entries being there
3184
3384
  #
3185
3385
  def remove_from_list
3186
- unless $selected_files.empty?
3187
- sz = $selected_files.size
3386
+ unless @selected_files.empty?
3387
+ sz = @selected_files.size
3188
3388
  print "Remove #{sz} files from used list (y)?: "
3189
3389
  key = get_char
3190
3390
  return if key != 'y'
3191
3391
 
3192
- arr = $selected_files.map { |path| File.expand_path(path) }
3392
+ arr = @selected_files.map { |path| File.expand_path(path) }
3193
3393
 
3194
- $used_dirs = $used_dirs - arr
3195
- $visited_files = $visited_files - arr
3394
+ @used_dirs = @used_dirs - arr
3395
+ @visited_files = @visited_files - arr
3196
3396
  unselect_all
3197
- $modified = true
3397
+ @modified = true
3198
3398
  refresh
3199
3399
  return
3200
3400
  end
@@ -3202,19 +3402,19 @@ def remove_from_list
3202
3402
  # no file selected, use file under cursor
3203
3403
  print
3204
3404
  ## what if selected some rows
3205
- file = $view[$cursor]
3405
+ file = @view[@cursor]
3206
3406
  print "Remove #{file} from used list (y)?: "
3207
3407
  key = get_char
3208
3408
  return if key != 'y'
3209
3409
 
3210
3410
  file = File.expand_path(file)
3211
3411
  if File.directory? file
3212
- $used_dirs.delete(file)
3412
+ @used_dirs.delete(file)
3213
3413
  else
3214
- $visited_files.delete(file)
3414
+ @visited_files.delete(file)
3215
3415
  end
3216
3416
  refresh
3217
- $modified = true
3417
+ @modified = true
3218
3418
  end
3219
3419
 
3220
3420
  #
@@ -3224,158 +3424,152 @@ end
3224
3424
  # latest source, but in some cases even this can be misleading since running a program accesses
3225
3425
  # include files.
3226
3426
  def enhance_file_list
3227
- return unless $enhanced_mode
3427
+ return unless cget(:enhanced_mode)
3428
+
3228
3429
  begin
3229
- actr = $files.size
3230
-
3231
- # zshglob: M = MARK_DIRS with slash
3232
- # zshglob: N = NULL_GLOB no error if no result, this is causing space to split
3233
- # file sometimes for single file.
3234
-
3235
- # FIXME: append only if we are adding.
3236
- # FIXME: this makes it possible to select this row,
3237
- # FIXME: and count it as a file !!
3238
- # $files.append SEPARATOR
3239
-
3240
- # if only one entry and its a dir
3241
- # get its children and maybe the recent mod files a few
3242
- # FIXME: simplify condition into one
3243
- if $files.size == 1
3244
- # its a dir, let give the next level at least
3245
- return unless $files.first[-1] == '/'
3246
-
3247
- d = $files.first
3248
- # zshglob: 'om' = ordered on modification time
3249
- # f1 = `zsh -c 'print -rl -- #{d}*(omM)'`.split("\n")
3250
- f = get_files_by_mtime(d)
3251
-
3252
- # @log.warn "f1:#{f1} != f:#{f} in #{d}" if f1 != f
3253
- # order returned by zsh and ruby are different since the time is the same
3254
-
3255
- # TODO: use ruby this throws errors if not files
3256
- if f && !f.empty?
3257
- # @log.debug "CONCAT: #{f}" if @debug_flag
3258
- $files.concat f
3259
- $files.concat get_important_files(d)
3260
- end
3261
- return
3262
- end
3263
- #
3264
- # check if a ruby project dir, although it could be a backup file too,
3265
- # if so , expand lib and maybe bin, put a couple recent files
3266
- # FIXME: gemspec file will be same as current folder
3267
- if $files.index('Gemfile') || !$files.grep(/\.gemspec/).empty?
3268
- # usually the lib dir has only one file and one dir
3269
- flg = false
3270
- $files.concat get_important_files(Dir.pwd)
3271
- if $files.index('lib/')
3272
- # get first five entries by modification time
3273
- # f1 = `zsh -c 'print -rl -- lib/*(om[1,5]MN)'`.split("\n")
3274
- f = get_files_by_mtime('lib')&.first(5)
3275
- # @log.warn "f1 #{f1} != #{f} in lib" if f1 != f
3430
+ actr = @files.size
3431
+
3432
+ # zshglob: M = MARK_DIRS with slash
3433
+ # zshglob: N = NULL_GLOB no error if no result, this is causing space to split
3434
+ # file sometimes for single file.
3435
+
3436
+ # FIXME: append only if we are adding.
3437
+ # FIXME: this makes it possible to select this row,
3438
+ # FIXME: and count it as a file !!
3439
+ # @files.append SEPARATOR
3440
+
3441
+ # if only one entry and its a dir
3442
+ # get its children and maybe the recent mod files a few
3443
+ # FIXME: simplify condition into one
3444
+ if @files.size == 1
3445
+ # its a dir, let give the next level at least
3446
+ return unless @files.first[-1] == '/'
3447
+
3448
+ d = @files.first
3449
+ # zshglob: 'om' = ordered on modification time
3450
+ # f1 = `zsh -c 'print -rl -- #{d}*(omM)'`.split("\n")
3451
+ f = get_files_by_mtime(d)
3452
+
3276
3453
  if f && !f.empty?
3277
- insert_into_list('lib/', f)
3278
- flg = true
3454
+ @files.concat f
3455
+ @files.concat get_important_files(d)
3279
3456
  end
3280
-
3281
- # look into lib file for that project
3282
- dd = File.basename(Dir.pwd)
3283
- if f.index("lib/#{dd}/")
3284
- # f1 = `zsh -c 'print -rl -- lib/#{dd}/*(om[1,5]MN)'`.split("\n")
3285
- f = get_files_by_mtime("lib/#{dd}")&.first(5)
3286
- # @log.warn "2756 f1 #{f1} != #{f} in lib/#{dd}" if f1 != f
3457
+ return
3458
+ end
3459
+ #
3460
+ # check if a ruby project dir, although it could be a backup file too,
3461
+ # if so , expand lib and maybe bin, put a couple recent files
3462
+ # FIXME: gemspec file will be same as current folder
3463
+ if @files.index('Gemfile') || !@files.grep(/\.gemspec/).empty?
3464
+ # usually the lib dir has only one file and one dir
3465
+ flg = false
3466
+ @files.concat get_important_files(Dir.pwd)
3467
+ if @files.index('lib/')
3468
+ # get first five entries by modification time
3469
+ # f1 = `zsh -c 'print -rl -- lib/*(om[1,5]MN)'`.split("\n")
3470
+ f = get_files_by_mtime('lib')&.first(5)
3471
+ # @log.warn "f1 #{f1} != #{f} in lib" if f1 != f
3287
3472
  if f && !f.empty?
3288
- insert_into_list("lib/#{dd}/", f)
3473
+ insert_into_list('lib/', f)
3289
3474
  flg = true
3290
3475
  end
3291
- end
3292
- end
3293
-
3294
- # look into bin directory and get first five modified files
3295
- if $files.index('bin/')
3296
- # f1 = `zsh -c 'print -rl -- bin/*(om[1,5]MN)'`.split("\n")
3297
- f = get_files_by_mtime("bin")&.first(5)
3298
- # @log.warn "2768 f1 #{f1} != #{f} in bin/" if f1 != f
3299
- insert_into_list('bin/', f) if f && !f.empty?
3300
- flg = true
3301
- end
3302
- return if flg
3303
-
3304
- # lib has a dir in it with the gem name
3305
-
3306
- end
3307
- return if $files.size > 15
3308
3476
 
3309
- # Get most recently accessed directory
3310
- ## NOTE: first check accessed else modified will change accessed
3311
- # 2019-03-28 - adding NULL_GLOB breaks file name on spaces
3312
- # print -n : don't add newline
3313
- # zzmoda = `zsh -c 'print -rn -- *(/oa[1]MN)'`
3314
- # zzmoda = nil if zzmoda == ''
3315
- moda = get_most_recently_accessed_dir
3316
- # @log.warn "Error 2663 #{zzmoda} != #{moda}" if zzmoda != moda
3317
- if moda && moda != ''
3477
+ # look into lib file for that project
3478
+ dd = File.basename(Dir.pwd)
3479
+ if f.index("lib/#{dd}/")
3480
+ # f1 = `zsh -c 'print -rl -- lib/#{dd}/*(om[1,5]MN)'`.split("\n")
3481
+ f = get_files_by_mtime("lib/#{dd}")&.first(5)
3482
+ # @log.warn "2756 f1 #{f1} != #{f} in lib/#{dd}" if f1 != f
3483
+ if f && !f.empty?
3484
+ insert_into_list("lib/#{dd}/", f)
3485
+ flg = true
3486
+ end
3487
+ end
3488
+ end
3318
3489
 
3319
- # get most recently accessed file in that directory
3320
- # NOTE: adding NULL_GLOB splits files on spaces
3321
- # FIXME: this zsh one gave a dir instead of file.
3322
- # zzmodf = `zsh -c 'print -rl -- #{moda}*(oa[1]M)'`.chomp
3323
- # zzmodf = nil if zzmodf == ''
3324
- modf = get_most_recently_accessed_file moda
3325
- # @log.warn "Error 2670 (#{zzmodf}) != (#{modf}) gmra in #{moda} #{zzmodf.class}, #{modf.class} : Loc: #{Dir.pwd}" if zzmodf != modf
3490
+ # look into bin directory and get first five modified files
3491
+ if @files.index('bin/')
3492
+ # f1 = `zsh -c 'print -rl -- bin/*(om[1,5]MN)'`.split("\n")
3493
+ f = get_files_by_mtime('bin')&.first(5)
3494
+ # @log.warn "2768 f1 #{f1} != #{f} in bin/" if f1 != f
3495
+ insert_into_list('bin/', f) if f && !f.empty?
3496
+ flg = true
3497
+ end
3498
+ return if flg
3326
3499
 
3327
- raise "2784: #{modf}" if modf && !File.exist?(modf)
3500
+ # lib has a dir in it with the gem name
3328
3501
 
3329
- insert_into_list moda, modf if modf && modf != ''
3502
+ end
3503
+ return if @files.size > 15
3504
+
3505
+ # Get most recently accessed directory
3506
+ ## NOTE: first check accessed else modified will change accessed
3507
+ # 2019-03-28 - adding NULL_GLOB breaks file name on spaces
3508
+ # print -n : don't add newline
3509
+ # zzmoda = `zsh -c 'print -rn -- *(/oa[1]MN)'`
3510
+ # zzmoda = nil if zzmoda == ''
3511
+ moda = get_most_recently_accessed_dir
3512
+ # @log.warn "Error 2663 #{zzmoda} != #{moda}" if zzmoda != moda
3513
+ if moda && moda != ''
3514
+
3515
+ # get most recently accessed file in that directory
3516
+ # NOTE: adding NULL_GLOB splits files on spaces
3517
+ # FIXME: this zsh one gave a dir instead of file.
3518
+ # zzmodf = `zsh -c 'print -rl -- #{moda}*(oa[1]M)'`.chomp
3519
+ # zzmodf = nil if zzmodf == ''
3520
+ modf = get_most_recently_accessed_file moda
3521
+ # @log.warn "Error 2670 (#{zzmodf}) != (#{modf}) gmra in #{moda} #{zzmodf.class}, #{modf.class} : Loc: #{Dir.pwd}" if zzmodf != modf
3522
+
3523
+ raise "2784: #{modf}" if modf && !File.exist?(modf)
3524
+
3525
+ insert_into_list moda, modf if modf && modf != ''
3526
+
3527
+ # get most recently modified file in that directory
3528
+ # zzmodm = `zsh -c 'print -rn -- #{moda}*(om[1]M)'`.chomp
3529
+ modm = get_most_recently_modified_file moda
3530
+ # zzmodm = nil if zzmodm == ''
3531
+ # @log.debug "Error 2678 (gmrmf) #{zzmodm} != #{modm} in #{moda}" if zzmodm != modm
3532
+ raise "2792: #{modm}" if modm && !File.exist?(modm)
3533
+
3534
+ insert_into_list moda, modm if modm && modm != '' && modm != modf
3535
+ end
3330
3536
 
3331
- # get most recently modified file in that directory
3332
- # zzmodm = `zsh -c 'print -rn -- #{moda}*(om[1]M)'`.chomp
3333
- modm = get_most_recently_modified_file moda
3537
+ ## get most recently modified dir
3538
+ # zzmodm = `zsh -c 'print -rn -- *(/om[1]M)'`
3334
3539
  # zzmodm = nil if zzmodm == ''
3335
- # @log.debug "Error 2678 (gmrmf) #{zzmodm} != #{modm} in #{moda}" if zzmodm != modm
3336
- raise "2792: #{modm}" if modm && !File.exist?(modm)
3337
-
3338
- insert_into_list moda, modm if modm && modm != '' && modm != modf
3339
- end
3340
-
3341
- ## get most recently modified dir
3342
- # zzmodm = `zsh -c 'print -rn -- *(/om[1]M)'`
3343
- # zzmodm = nil if zzmodm == ''
3344
- modm = get_most_recently_modified_dir
3345
- # @log.debug "Error 2686 rmd #{zzmodm} != #{modm}" if zzmodm != modm
3540
+ modm = get_most_recently_modified_dir
3541
+ # @log.debug "Error 2686 rmd #{zzmodm} != #{modm}" if zzmodm != modm
3346
3542
 
3347
- if modm != moda
3543
+ if modm != moda
3348
3544
 
3349
- # get most recently accessed file in that directory
3350
- # modmf = `zsh -c 'print -rn -- #{modm}*(oa[1]M)'`
3351
- modmf = get_most_recently_accessed_file modm
3352
- raise "2806: #{modmf}" if modmf && !File.exist?(modmf)
3545
+ # get most recently accessed file in that directory
3546
+ # modmf = `zsh -c 'print -rn -- #{modm}*(oa[1]M)'`
3547
+ modmf = get_most_recently_accessed_file modm
3548
+ raise "2806: #{modmf}" if modmf && !File.exist?(modmf)
3353
3549
 
3354
- insert_into_list modm, modmf
3550
+ insert_into_list modm, modmf
3355
3551
 
3356
- # get most recently modified file in that directory
3357
- # modmf11 = `zsh -c 'print -rn -- #{modm}*(om[1]M)'`
3358
- modmf1 = get_most_recently_modified_file modm
3359
- raise "2812: #{modmf1}" if modmf1 && !File.exist?(modmf1)
3552
+ # get most recently modified file in that directory
3553
+ # modmf11 = `zsh -c 'print -rn -- #{modm}*(om[1]M)'`
3554
+ modmf1 = get_most_recently_modified_file modm
3555
+ raise "2812: #{modmf1}" if modmf1 && !File.exist?(modmf1)
3360
3556
 
3361
- insert_into_list(modm, modmf1) if modmf1 != modmf
3362
- else
3363
- # if both are same then our options get reduced so we need to get something more
3364
- # If you access the latest mod dir, then come back you get only one, since mod and accessed
3365
- # are the same dir, so we need to find the second modified dir
3366
- end
3557
+ insert_into_list(modm, modmf1) if modmf1 != modmf
3558
+ else
3559
+ # if both are same then our options get reduced so we need to get something more
3560
+ # If you access the latest mod dir, then come back you get only one, since mod and accessed
3561
+ # are the same dir, so we need to find the second modified dir
3562
+ end
3367
3563
  ensure
3368
3564
  # if any files were added, then add a separator
3369
- bctr = $files.size
3370
- if actr < bctr
3371
- $files.insert actr, SEPARATOR
3372
- end
3565
+ bctr = @files.size
3566
+ @files.insert actr, SEPARATOR if actr < bctr
3373
3567
  end
3374
3568
  end
3375
3569
 
3376
- # insert important files to end of $files
3570
+ # insert important files to end of @files
3377
3571
  def insert_into_list _dir, file
3378
- $files.push(*file)
3572
+ @files.push(*file)
3379
3573
  end
3380
3574
 
3381
3575
  # Get visited files and bookmarks that are inside this directory
@@ -3383,7 +3577,6 @@ end
3383
3577
  # 2019-03-23 - not exactly clear what is happening XXX
3384
3578
  # this gets a directory (containing '/' at end)
3385
3579
  def get_important_files dir
3386
-
3387
3580
  # checks various lists like visited_files and bookmarks
3388
3581
  # to see if files from this dir or below are in it.
3389
3582
  # More to be used in a dir with few files.
@@ -3392,14 +3585,14 @@ def get_important_files dir
3392
3585
 
3393
3586
  # 2019-03-23 - i think we are getting the basename of the file
3394
3587
  # if it is present in the given directory XXX
3395
- $visited_files.each do |e|
3588
+ @visited_files.each do |e|
3396
3589
  list << e[l..-1] if e.index(dir) == 0
3397
3590
  end
3398
3591
 
3399
3592
  # bookmarks if it starts with this directory then add it
3400
3593
  # FIXME it puts same directory cetus into the list with full path
3401
3594
  # We need to remove the base until this dir. get relative part
3402
- list1 = $bookmarks.values.select do |e|
3595
+ list1 = @bookmarks.values.select do |e|
3403
3596
  e.index(dir) == 0 && e != dir
3404
3597
  end
3405
3598
 
@@ -3429,8 +3622,8 @@ end
3429
3622
  # func can be :mtime or :atime or :ctime or :birthtime
3430
3623
  def gmr dir, type, func
3431
3624
  file = Dir.glob(dir + '/*')
3432
- .select { |f| File.send(type, f) }
3433
- .max_by { |f| File.send(func, f) }
3625
+ .select { |f| File.send(type, f) }
3626
+ .max_by { |f| File.send(func, f) }
3434
3627
  file = File.basename(file) + '/' if file && type == :directory?
3435
3628
  return file.gsub('//', '/') if file
3436
3629
 
@@ -3465,14 +3658,14 @@ end
3465
3658
  # set message which will be displayed in status line
3466
3659
  # TODO: maybe we should pad it 2019-04-08 -
3467
3660
  def message mess
3468
- $message = mess
3661
+ @message = mess
3469
3662
  @keys_to_clear = 2 if mess
3470
3663
  end
3471
3664
 
3472
3665
  def last_line
3473
- # system "tput cup #{$glines} 0"
3474
- # print "\e[#{$glines};0H"
3475
- tput_cup $glines, 0
3666
+ # system "tput cup #{@glines} 0"
3667
+ # print "\e[#{@glines};0H"
3668
+ tput_cup @glines, 0
3476
3669
  end
3477
3670
 
3478
3671
  def clear_last_line
@@ -3482,7 +3675,7 @@ def clear_last_line
3482
3675
  # %*s - set blank spaces for entire line
3483
3676
  # \e[m - reset text mode
3484
3677
  # \r - bring to start of line since callers will print.
3485
- print "\e[33;4%sm%*s\e[m\r" % [@status_color || '1', $gcols, ' ']
3678
+ print format("\e[33;4%sm%*s\e[m\r", @status_color || '1', @gcols, ' ')
3486
3679
  end
3487
3680
 
3488
3681
  # print right aligned
@@ -3491,14 +3684,12 @@ end
3491
3684
  # should clear and reprint mode, message, patt and right text
3492
3685
  def print_on_right text
3493
3686
  sz = text.size
3494
- col = $gcols - sz - 1
3687
+ col = @gcols - sz - 1
3495
3688
  col = 2 if col < 2
3496
- if sz > $gcols - 2
3497
- text = text[0..$gcols-3]
3498
- end
3499
- # system "tput cup #{$glines} #{$gcols - sz - 1}"
3500
- system "tput cup #{$glines} #{col}"
3501
- # tput_cup $glines, $gcols - sz - 1
3689
+ text = text[0..@gcols - 3] if sz > @gcols - 2
3690
+ # system "tput cup #{@glines} #{@gcols - sz - 1}"
3691
+ system "tput cup #{@glines} #{col}"
3692
+ # tput_cup @glines, @gcols - sz - 1
3502
3693
  # print text
3503
3694
  print "\e[33;4#{@status_color_right}m#{text}\e[m"
3504
3695
  end
@@ -3519,9 +3710,34 @@ def clear_message
3519
3710
  end
3520
3711
  end
3521
3712
  end
3713
+
3714
+ # returns true if only cursor moved and redrawing not required
3715
+ def only_cursor_moved?
3716
+ # only movement has happened within this page, don't redraw
3717
+ return unless @movement && @old_cursor
3718
+
3719
+ # if cursor has not moved (first or last item on screen)
3720
+ # keep testing this out 2019-04-14 -
3721
+ if @old_cursor == @cursor
3722
+ @movement = false
3723
+ return true # next in the loop
3724
+ end
3725
+
3726
+ # we may want to print debug info if flag is on
3727
+ if cget(:debug_flag)
3728
+ clear_last_line
3729
+ print_debug_info
3730
+ else
3731
+ status_line
3732
+ end
3733
+
3734
+ place_cursor
3735
+ @movement = false
3736
+ return true # next in the loop
3737
+ end
3738
+
3522
3739
  # main loop which calls all other programs
3523
3740
  def run
3524
-
3525
3741
  Signal.trap('EXIT') do
3526
3742
  reset_terminal
3527
3743
  exit
@@ -3536,44 +3752,28 @@ def run
3536
3752
  place_cursor
3537
3753
 
3538
3754
  # do we need this, have they changed after redraw
3539
- $patt = nil
3540
- $sta = 0
3755
+ @patt = nil
3756
+ @sta = 0
3541
3757
 
3542
3758
  # forever loop that prints dir and takes a key
3543
3759
  loop do
3544
-
3545
3760
  key = get_char
3546
3761
 
3547
-
3548
3762
  unless resolve_key key # key did not map to file name, so don't redraw
3549
3763
  place_cursor
3550
3764
  next
3551
3765
  end
3552
3766
 
3553
- # only movement has happened within this page, don't redraw
3554
- if @movement && @old_cursor
3555
-
3556
- # we may want to print debug info if flag is on
3557
- if @debug_flag
3558
- clear_last_line
3559
- print_debug_info
3560
- else
3561
- status_line
3562
- end
3563
-
3564
- place_cursor
3565
- @movement = false
3566
- next
3567
- end
3767
+ next if only_cursor_moved?
3568
3768
 
3569
3769
  redraw rescan?
3570
3770
  place_cursor
3571
3771
 
3572
- break if $quitting
3772
+ break if @quitting
3573
3773
  end
3574
3774
  write_curdir
3575
3775
  puts 'bye'
3576
- config_write if $writing
3776
+ config_write if @writing
3577
3777
  @log&.close
3578
3778
  end
3579
3779