cetus 0.1.36 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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