cetus 0.1.21 → 0.1.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/bin/cetus +1040 -711
  3. data/cetus.gemspec +10 -10
  4. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e35fd2792cfb584909c6ddadfaeb6b30e92ff09b4f838585a85f8de977c333e
4
- data.tar.gz: f2b2f7e300a593f9ba2973d8451f4148f9057c5bc4680ad3c9ac77075ae6f19e
3
+ metadata.gz: 040badb6cd9462f5d5a2fe5f5b5e320c03fbbd80984d71e526c500bdd0781822
4
+ data.tar.gz: c48f55c076c32815785341986791e680b990b3fbf3bf1d519835b70331790a52
5
5
  SHA512:
6
- metadata.gz: 6ab765cb054741e0d6951040d7b655d7235d1c583646c96f8bd1b12d74778fd05a735b0a3864e3f87e4b1652316a3bef6b966745bba3d3efe113d46cde306826
7
- data.tar.gz: 1d723a6b666671544a081e426ecf34df28a6fa02bd158fed08f9c89873dbef12a050f66caf286f3231847aa622783abcb41da1285ce0b75104a9fe999658ee1c
6
+ metadata.gz: a7a6655724e7b3e5e46d20d8bf0cc90a3032aacdca0dbbbb4d4348c87c845e8a974574f2530781ff44a7860ed1d3f9eb8e0c5caa952411963106ac3622fc39f9
7
+ data.tar.gz: c61c40989b45d3e4c2ecc04d6a04ceae2722fbf3d0d582e37fb86b4e00b5d78582c16edd18fef1c58ad86e3c20038d4ae3b5455270c7da25dba2bcdb19f27c75
data/bin/cetus CHANGED
@@ -1,19 +1,20 @@
1
1
  #!/usr/bin/env ruby
2
- # ----------------------------------------------------------------------------- #
2
+ # --------------------------------------------------------------------------- #
3
3
  # File: cetus
4
4
  # Description: Fast file navigation, a tiny version of zfm
5
5
  # but with a different indexing mechanism
6
6
  # Author: rkumar http://github.com/rkumar/cetus/
7
7
  # Date: 2013-02-17 - 17:48
8
8
  # License: GPL
9
- # Last update: 2019-03-04 23:50
10
- # ----------------------------------------------------------------------------- #
11
- # cetus.rb Copyright (C) 2012-2013 rahul kumar
9
+ # Last update: 2019-03-10 15:07
10
+ # --------------------------------------------------------------------------- #
11
+ # cetus.rb Copyright (C) 2012-2019 rahul kumar
12
12
  # == CHANGELOG
13
13
  # 2019-02-20 - added smcup and rmcup so alt-screen is used. works a bit
14
14
  # 2019-03-04 - change clear to go to 0,0 and clear down to reduce pollution
15
15
  # 2019-03-04 - changed quit to q (earlier Q)
16
16
  # 2019-03-04 - first dirs then files
17
+ # 2019-03-10 - changing selected_files to have fullpath
17
18
  # == TODO
18
19
  # To dirs add GEMHOME RUBYLIB PYTHONILB or PYTHONPATH,
19
20
  # Make rubygem aware : gemspec or Gemfile the expand lib and bin
@@ -23,10 +24,9 @@ require 'readline'
23
24
  require 'io/wait'
24
25
  # http://www.ruby-doc.org/stdlib-1.9.3/libdoc/shellwords/rdoc/Shellwords.html
25
26
  require 'shellwords'
27
+ # https://docs.ruby-lang.org/en/2.6.0/FileUtils.html
26
28
  require 'fileutils'
27
29
  # -- requires 1.9.3 for io/wait
28
- # -- cannot do with Highline since we need a timeout on wait,
29
- # not sure if HL can do that
30
30
 
31
31
  ## INSTALLATION
32
32
  # copy into PATH
@@ -35,113 +35,119 @@ require 'fileutils'
35
35
 
36
36
  # 2019-02-20 - added so alt-screen is used
37
37
  system 'tput smcup'
38
- VERSION = '0.1.21.0'
38
+ VERSION = '0.1.22.0'.freeze
39
39
  O_CONFIG = true
40
- CONFIG_FILE = '~/.lyrainfo'
40
+ # CONFIG_FILE = '~/.lyrainfo'.freeze
41
+ CONFIG_FILE = '~/.config/cetus/conf.yml'.freeze
41
42
 
42
43
  $bindings = {}
43
44
  $bindings = {
44
- '`' => 'main_menu',
45
- '=' => 'toggle_menu',
46
- '!' => 'command_mode',
47
- '@' => 'selection_mode_toggle',
45
+ '`' => 'main_menu',
46
+ '=' => 'toggle_menu',
47
+ '!' => 'command_mode',
48
+ '@' => 'selection_mode_toggle',
48
49
  'M-a' => 'select_all',
49
50
  'M-A' => 'unselect_all',
50
- ',' => 'goto_parent_dir',
51
- '+' => 'goto_dir',
52
- '.' => 'pop_dir',
53
- ':' => 'subcommand',
54
- "'" => 'goto_bookmark',
55
- '/' => 'enter_regex',
56
- 'M-p' => 'prev_page',
57
- 'M-n' => 'next_page',
58
- 'SPACE' => 'next_page',
59
- 'M-f' => 'select_visited_files',
60
- 'M-d' => 'select_used_dirs',
61
- 'M-b' => 'select_bookmarks',
62
- 'M-m' => 'create_bookmark',
63
- 'M-M' => 'show_marks',
64
- 'C-c' => 'escape',
65
- 'ESCAPE' => 'escape',
66
- 'TAB' => 'views',
67
- 'C-i' => 'views',
68
- '?' => 'dirtree',
69
- 'ENTER' => 'select_current',
70
- 'D' => 'delete_file',
71
- 'M' => 'file_actions most',
72
- 'q' => 'quit_command', # was Q now q 2019-03-04 -
73
- #"RIGHT" => "column_next",
74
- 'RIGHT' => 'select_current', # changed 2018-03-12 - for faster navigation
75
- 'LEFT' => 'goto_parent_dir', # changed on 2018-03-12 - earlier column_next 1
76
- ']' => 'column_next',
77
- '[' => 'column_next 1',
78
- 'C-x' => 'file_actions',
79
- 'M--' => 'columns_incdec -1',
80
- 'M-+' => 'columns_incdec 1',
81
- 'S' => 'command_file list y ls -lh',
82
- 'L' => 'command_file Page n less',
83
- 'C-d' => 'cursor_scroll_dn',
84
- 'C-b' => 'cursor_scroll_up',
85
- 'UP' => 'cursor_up',
86
- 'DOWN' => 'cursor_dn',
51
+ ',' => 'goto_parent_dir',
52
+ '~' => 'goto_home_dir',
53
+ '-' => 'goto_previous_dir', # 2019-03-07 - added. like 'cd ='
54
+ '+' => 'goto_dir', # 2019-03-07 - TODO: change binding
55
+ '.' => 'pop_dir',
56
+ ':' => 'subcommand',
57
+ "'" => 'goto_bookmark',
58
+ '/' => 'enter_regex',
59
+ 'M-p' => 'prev_page',
60
+ 'M-n' => 'next_page',
61
+ 'SPACE' => 'next_page',
62
+ 'M-f' => 'select_visited_files',
63
+ 'M-d' => 'select_used_dirs',
64
+ 'M-b' => 'select_bookmarks',
65
+ 'M-m' => 'create_bookmark',
66
+ 'M-M' => 'show_marks',
67
+ 'C-c' => 'escape',
68
+ 'ESCAPE' => 'escape',
69
+ 'TAB' => 'views',
70
+ 'C-i' => 'views',
71
+ '?' => 'dirtree',
72
+ 'ENTER' => 'select_current',
73
+ 'C-p' => 'page_current',
74
+ 'C-e' => 'edit_current',
75
+ 'C-o' => 'edit_current',
76
+ 'D' => 'delete_file',
77
+ 'M' => 'file_actions most',
78
+ 'q' => 'quit_command', # was Q now q 2019-03-04 -
79
+ # "RIGHT" => "column_next",
80
+ 'RIGHT' => 'select_current', # changed 2018-03-12 - for faster navigation
81
+ 'LEFT' => 'goto_parent_dir', # changed on 2018-03-12 - earlier column_next 1
82
+ ']' => 'column_next',
83
+ '[' => 'column_next 1',
84
+ 'C-x' => 'file_actions',
85
+ 'M--' => 'columns_incdec -1',
86
+ 'M-+' => 'columns_incdec 1',
87
+ 'S' => 'command_file list y ls -lh',
88
+ 'L' => 'command_file Page n less',
89
+ 'C-d' => 'cursor_scroll_dn',
90
+ 'C-b' => 'cursor_scroll_up',
91
+ 'UP' => 'cursor_up',
92
+ 'DOWN' => 'cursor_dn',
87
93
  'C-SPACE' => 'visual_mode_toggle',
88
94
 
89
- 'M-?' => 'print_help',
90
- 'F1' => 'print_help',
91
- 'F2' => 'child_dirs',
92
- 'F3' => 'dirtree',
93
- 'F4' => 'tree',
94
- 'S-F1' => 'dirtree',
95
- 'S-F2' => 'tree'
95
+ 'M-?' => 'print_help',
96
+ 'F1' => 'print_help',
97
+ 'F2' => 'child_dirs',
98
+ 'F3' => 'dirtree',
99
+ 'F4' => 'tree',
100
+ 'S-F1' => 'dirtree',
101
+ 'S-F2' => 'tree'
96
102
 
97
103
  }
98
104
 
99
105
  ## clean this up a bit, copied from shell program and macro'd
100
- $kh=Hash.new
101
- $kh["OP"]="F1"
102
- $kh[""]="UP"
103
- $kh["[5~"]="PGUP"
104
- $kh['']="ESCAPE"
105
- KEY_PGDN="[6~"
106
- KEY_PGUP="[5~"
106
+ $kh = {}
107
+ $kh["\eOP"] = 'F1'
108
+ $kh["\e[A"] = 'UP'
109
+ $kh["\e[5~"] = 'PGUP'
110
+ $kh[''] = 'ESCAPE'
111
+ KEY_PGDN = "\e[6~".freeze
112
+ KEY_PGUP = "\e[5~".freeze
107
113
  ## I needed to replace the O with a [ for this to work
108
114
  # in Vim Home comes as ^[OH whereas on the command line it is correct as ^[[H
109
- KEY_HOME=''
110
- KEY_END=""
111
- KEY_F1="OP"
112
- KEY_UP=""
113
- KEY_DOWN=""
114
-
115
- $kh[KEY_PGDN]="PgDn"
116
- $kh[KEY_PGUP]="PgUp"
117
- $kh[KEY_HOME]="Home"
118
- $kh[KEY_END]="End"
119
- $kh[KEY_F1]="F1"
120
- $kh[KEY_UP]="UP"
121
- $kh[KEY_DOWN]="DOWN"
122
- KEY_LEFT=''
123
- KEY_RIGHT=''
124
- $kh["OQ"]="F2"
125
- $kh["OR"]="F3"
126
- $kh["OS"]="F4"
127
- $kh[KEY_LEFT] = "LEFT"
128
- $kh[KEY_RIGHT]= "RIGHT"
129
- KEY_F5='[15~'
130
- KEY_F6='[17~'
131
- KEY_F7='[18~'
132
- KEY_F8='[19~'
133
- KEY_F9='[20~'
134
- KEY_F10='[21~'
135
- KEY_S_F1=''
136
- $kh[KEY_F5]="F5"
137
- $kh[KEY_F6]="F6"
138
- $kh[KEY_F7]="F7"
139
- $kh[KEY_F8]="F8"
140
- $kh[KEY_F9]="F9"
141
- $kh[KEY_F10]="F10"
115
+ KEY_HOME = ''.freeze
116
+ KEY_END = "\e[F".freeze
117
+ KEY_F1 = "\eOP".freeze
118
+ KEY_UP = "\e[A".freeze
119
+ KEY_DOWN = "\e[B".freeze
120
+
121
+ $kh[KEY_PGDN] = 'PgDn'
122
+ $kh[KEY_PGUP] = 'PgUp'
123
+ $kh[KEY_HOME] = 'Home'
124
+ $kh[KEY_END] = 'End'
125
+ $kh[KEY_F1] = 'F1'
126
+ $kh[KEY_UP] = 'UP'
127
+ $kh[KEY_DOWN] = 'DOWN'
128
+ KEY_LEFT = ''.freeze
129
+ KEY_RIGHT = ''.freeze
130
+ $kh["\eOQ"] = 'F2'
131
+ $kh["\eOR"] = 'F3'
132
+ $kh["\eOS"] = 'F4'
133
+ $kh[KEY_LEFT] = 'LEFT'
134
+ $kh[KEY_RIGHT] = 'RIGHT'
135
+ KEY_F5 = '[15~'.freeze
136
+ KEY_F6 = '[17~'.freeze
137
+ KEY_F7 = '[18~'.freeze
138
+ KEY_F8 = '[19~'.freeze
139
+ KEY_F9 = '[20~'.freeze
140
+ KEY_F10 = '[21~'.freeze
141
+ KEY_S_F1 = ''.freeze
142
+ $kh[KEY_F5] = 'F5'
143
+ $kh[KEY_F6] = 'F6'
144
+ $kh[KEY_F7] = 'F7'
145
+ $kh[KEY_F8] = 'F8'
146
+ $kh[KEY_F9] = 'F9'
147
+ $kh[KEY_F10] = 'F10'
142
148
  # testing out shift+Function. these are the codes my kb generates
143
- $kh[KEY_S_F1]="S-F1"
144
- $kh['']="S-F2"
149
+ $kh[KEY_S_F1] = 'S-F1'
150
+ $kh[''] = 'S-F2'
145
151
 
146
152
  def old_clear_screen
147
153
  system 'clear'
@@ -169,16 +175,16 @@ end
169
175
  # copied from fff
170
176
  # Call before shelling to editor pager and when exiting
171
177
  def reset_terminal
172
- # Reset the terminal to a useable state (undo all changes).
173
- # '\e[?7h': Re-enable line wrapping.
174
- # '\e[?25h': Unhide the cursor.
175
- # '\e[2J': Clear the terminal.
176
- # '\e[;r': Set the scroll region to its default value.
177
- # Also sets cursor to (0,0).
178
- print "\e[?7h\e[?25h\e[2J\e[;r"
178
+ # Reset the terminal to a useable state (undo all changes).
179
+ # '\e[?7h': Re-enable line wrapping.
180
+ # '\e[?25h': Unhide the cursor.
181
+ # '\e[2J': Clear the terminal.
182
+ # '\e[;r': Set the scroll region to its default value.
183
+ # Also sets cursor to (0,0).
184
+ print "\e[?7h\e[?25h\e[2J\e[;r"
179
185
 
180
- # Show user input.
181
- system 'stty echo'
186
+ # Show user input.
187
+ system 'stty echo'
182
188
  end
183
189
 
184
190
  # copied from fff
@@ -197,107 +203,115 @@ def setup_terminal
197
203
  system 'stty -echo'
198
204
  end
199
205
 
206
+ # wrap readline so C-c can be ignored, but blank is taken as default
207
+ def readline
208
+ begin
209
+ target = Readline.readline('>', true)
210
+ rescue Interrupt
211
+ return nil
212
+ end
213
+ target
214
+ end
215
+
200
216
  ## get a character from user and return as a string
201
217
  # Adapted from:
202
- #http://stackoverflow.com/questions/174933/how-to-get-a-single-character-without-pressing-enter/8274275#8274275
218
+ # http://stackoverflow.com/questions/174933/how-to-get-a-single-character-without-pressing-enter/8274275#8274275
203
219
  # Need to take complex keys and matc against a hash.
204
220
  def get_char
205
- begin
206
- system('stty raw -echo 2>/dev/null') # turn raw input on
207
- c = nil
208
- #if $stdin.ready?
209
- c = $stdin.getc
210
- cn = c.ord
211
- return 'ENTER' if cn == 10 || cn == 13
212
- return 'BACKSPACE' if cn == 127
213
- return 'C-SPACE' if cn == 0
214
- return 'SPACE' if cn == 32
215
- # next does not seem to work, you need to bind C-i
216
- return 'TAB' if cn == 8
217
-
218
- if cn >= 0 && cn < 27
219
- x = cn + 96
220
- return "C-#{x.chr}"
221
- end
222
- if c == ''
223
- buff=c.chr
224
- while true
225
- k = nil
226
- if $stdin.ready?
227
- k = $stdin.getc
228
- #puts "got #{k}"
229
- buff += k.chr
230
- else
231
- x = $kh[buff]
232
- return x if x
233
-
234
- # puts "returning with #{buff}"
235
- if buff.size == 2
236
- ## possibly a meta/alt char
237
- k = buff[-1]
238
- return "M-#{k.chr}"
239
- end
240
- return buff
221
+ system('stty raw -echo 2>/dev/null') # turn raw input on
222
+ c = nil
223
+ # if $stdin.ready?
224
+ c = $stdin.getc
225
+ cn = c.ord
226
+ return 'ENTER' if cn == 10 || cn == 13
227
+ return 'BACKSPACE' if cn == 127
228
+ return 'C-SPACE' if cn == 0
229
+ return 'SPACE' if cn == 32
230
+ # next does not seem to work, you need to bind C-i
231
+ return 'TAB' if cn == 8
232
+
233
+ if cn >= 0 && cn < 27
234
+ x = cn + 96
235
+ return "C-#{x.chr}"
236
+ end
237
+ if c == ''
238
+ buff = c.chr
239
+ loop do
240
+ k = nil
241
+ if $stdin.ready?
242
+ k = $stdin.getc
243
+ # puts "got #{k}"
244
+ buff += k.chr
245
+ else
246
+ x = $kh[buff]
247
+ return x if x
248
+
249
+ # puts "returning with #{buff}"
250
+ if buff.size == 2
251
+ ## possibly a meta/alt char
252
+ k = buff[-1]
253
+ return "M-#{k.chr}"
241
254
  end
255
+ return buff
242
256
  end
243
257
  end
244
- #end
245
- return c.chr if c
246
- ensure
247
- #system "stty -raw echo" # turn raw input off
248
- system('stty -raw echo 2>/dev/null') # turn raw input on
249
258
  end
259
+ # end
260
+ return c.chr if c
261
+ ensure
262
+ # system "stty -raw echo" # turn raw input off
263
+ system('stty -raw echo 2>/dev/null') # turn raw input on
250
264
  end
251
265
 
252
266
  ## GLOBALS
253
- #$IDX="123456789abcdefghijklmnoprstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
254
- #$IDX="abcdefghijklmnopqrstuvwxy"
255
- $IDX=('a'..'y').to_a
267
+ # $IDX="123456789abcdefghijklmnoprstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
268
+ # $IDX="abcdefghijklmnopqrstuvwxy"
269
+ $IDX = ('a'..'y').to_a
256
270
  $IDX.delete 'q'
257
271
  $IDX.concat ('za'..'zz').to_a
258
272
  $IDX.concat ('Za'..'Zz').to_a
259
273
  $IDX.concat ('ZA'..'ZZ').to_a
260
274
 
261
- $selected_files = Array.new
275
+ $selected_files = []
262
276
  $bookmarks = {}
263
277
  $mode = nil
264
- $glines=%x(tput lines).to_i
265
- $gcols=%x(tput cols).to_i
278
+ $glines = `tput lines`.to_i
279
+ $gcols = `tput cols`.to_i
266
280
  $grows = $glines - 3
267
281
  $pagesize = 60
268
282
  $gviscols = 3
269
283
  $pagesize = $grows * $gviscols
270
284
  $stact = 0
271
- #$editor_mode = true
285
+ # $editor_mode = true
272
286
  $editor_mode = false # changed 2018-03-12 - so we start in pager mode
273
287
  $enhanced_mode = true
274
288
  $visual_block_start = nil
275
289
  $pager_command = {
276
- :text => 'most',
277
- :image => 'open',
278
- :zip => 'tar ztvf %% | most',
279
- :unknown => 'open'
290
+ text: 'most',
291
+ image: 'open',
292
+ zip: 'tar ztvf %% | most',
293
+ unknown: 'open'
280
294
  }
281
295
  $dir_position = {}
282
296
  ## CONSTANTS
283
- GMARK='*'
284
- CURMARK='>'
297
+ GMARK = '*'.freeze
298
+ CURMARK = '>'.freeze
285
299
  MSCROLL = 10
286
- SPACE=" "
287
- CLEAR = "\e[0m"
288
- BOLD = "\e[1m"
289
- BOLD_OFF = "\e[22m"
290
- RED = "\e[31m"
291
- ON_RED = "\e[41m"
292
- GREEN = "\e[32m"
293
- YELLOW = "\e[33m"
294
- BLUE = "\e[1;34m"
295
-
296
- ON_BLUE = "\e[44m"
297
- REVERSE = "\e[7m"
298
- UNDERLINE = "\e[4m"
300
+ SPACE = ' '.freeze
301
+ CLEAR = "\e[0m".freeze
302
+ BOLD = "\e[1m".freeze
303
+ BOLD_OFF = "\e[22m".freeze
304
+ RED = "\e[31m".freeze
305
+ ON_RED = "\e[41m".freeze
306
+ GREEN = "\e[32m".freeze
307
+ YELLOW = "\e[33m".freeze
308
+ BLUE = "\e[1;34m".freeze
309
+
310
+ ON_BLUE = "\e[44m".freeze
311
+ REVERSE = "\e[7m".freeze
312
+ UNDERLINE = "\e[4m".freeze
299
313
  CURSOR_COLOR = ON_BLUE
300
- $patt=nil
314
+ $patt = nil
301
315
  $ignorecase = true
302
316
  $quitting = false
303
317
  $modified = $writing = false
@@ -306,20 +320,20 @@ $visited_files = []
306
320
  $visited_dirs = []
307
321
  ## dirs where some work has been done, for saving and restoring
308
322
  $used_dirs = []
309
- $default_sort_order = "om"
323
+ $default_sort_order = 'om'
310
324
  $sorto = $default_sort_order
311
325
  $viewctr = 0
312
326
  $history = []
313
327
  $sta = $cursor = 0
314
328
  $visual_mode = false
315
- #$help = "#{BOLD}1-9a-zA-Z#{BOLD_OFF} Select #{BOLD}/#{BOLD_OFF} Grep #{BOLD}'#{BOLD_OFF} First char #{BOLD}M-n/p#{BOLD_OFF} Paging #{BOLD}!#{BOLD_OFF} Command Mode #{BOLD}@#{BOLD_OFF} Selection Mode #{BOLD}q#{BOLD_OFF} Quit"
329
+ # $help = "#{BOLD}1-9a-zA-Z#{BOLD_OFF} Select #{BOLD}/#{BOLD_OFF} Grep #{BOLD}'#{BOLD_OFF} First char #{BOLD}M-n/p#{BOLD_OFF} Paging #{BOLD}!#{BOLD_OFF} Command Mode #{BOLD}@#{BOLD_OFF} Selection Mode #{BOLD}q#{BOLD_OFF} Quit"
316
330
 
317
331
  $help = "#{BOLD}M-?#{BOLD_OFF} Help #{BOLD}`#{BOLD_OFF} Menu #{BOLD}!#{BOLD_OFF} Command #{BOLD}=#{BOLD_OFF} Toggle #{BOLD}@#{BOLD_OFF} Selection Mode #{BOLD}q#{BOLD_OFF} Quit "
318
332
 
319
- ## main loop which calls all other programs
333
+ ## main loop which calls all other programs
320
334
  def run
321
- home=ENV['HOME']
322
- ctr=0
335
+ home = ENV['HOME']
336
+ ctr = 0
323
337
  config_read
324
338
  $files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}M)'`.split("\n")
325
339
  $files = sort_file_list $files
@@ -327,27 +341,27 @@ def run
327
341
  ## added by RK 2014-03-31 - 00:29 since too many duplicates
328
342
  $files = $files.uniq if $enhanced_mode
329
343
 
330
- fl=$files.size
344
+ fl = $files.size
331
345
 
332
346
  selectedix = nil
333
- $patt=""
334
- $sta=0
335
- while true
347
+ $patt = ''
348
+ $sta = 0
349
+ loop do
336
350
  i = 0
337
- if $patt
338
- if $ignorecase
339
- $view = $files.grep(/#{$patt}/i)
340
- else
341
- $view = $files.grep(/#{$patt}/)
342
- end
343
- else
344
- $view = $files
345
- end
346
- fl=$view.size
351
+ $view = if $patt
352
+ if $ignorecase
353
+ $files.grep(/#{$patt}/i)
354
+ else
355
+ $files.grep(/#{$patt}/)
356
+ end
357
+ else
358
+ $files
359
+ end
360
+ fl = $view.size
347
361
  $sta = 0 if $sta >= fl || $sta < 0
348
362
  $viewport = $view[$sta, $pagesize]
349
363
  fin = $sta + $viewport.size
350
- $title ||= Dir.pwd.sub(home, "~")
364
+ $title ||= Dir.pwd.sub(home, '~')
351
365
  clear_screen
352
366
  # title
353
367
  print "#{GREEN}#{$help} #{BLUE}cetus #{VERSION}#{CLEAR}\n"
@@ -355,36 +369,34 @@ def run
355
369
  t = t[t.size - $gcols..-1] if t.size >= $gcols
356
370
  print "#{BOLD}#{t}#{CLEAR}\n"
357
371
  ## nilling the title means a superimposed one gets cleared.
358
- #$title = nil
372
+ # $title = nil
359
373
  # split into 2 procedures so columnate can e clean and reused.
360
- buff = format $viewport
374
+ buff = _format $viewport
361
375
  buff = columnate buff, $grows
362
376
  # needed the next line to see how much extra we were going in padding
363
- #buff.each {|line| print "#{REVERSE}#{line}#{CLEAR}\n" }
364
- buff.each {|line| print line, "\n" }
377
+ # buff.each {|line| print "#{REVERSE}#{line}#{CLEAR}\n" }
378
+ buff.each { |line| print line, "\n" }
365
379
  print
366
380
  # prompt
367
- #print "#{$files.size}, #{view.size} sta=#{sta} (#{patt}): "
368
- _mm = ""
381
+ # print "#{$files.size}, #{view.size} sta=#{sta} (#{patt}): "
382
+ _mm = ''
369
383
  _mm = "[#{$mode}] " if $mode
370
384
  print "\r#{_mm}#{$patt} >"
371
385
  ch = get_char
372
- #puts
373
- #break if ch == "q"
374
- #elsif ch =~ /^[1-9a-zA-Z]$/
386
+ # puts
387
+ # break if ch == "q"
388
+ # elsif ch =~ /^[1-9a-zA-Z]$/
375
389
  # 2019-03-04 - ignore q since that is quit key now
376
- #if ch =~ /^[a-zZ]$/
390
+ # if ch =~ /^[a-zZ]$/
377
391
  if ch =~ /^[a-pr-zZ]$/
378
392
  # hint mode
379
393
  select_hint $viewport, ch
380
394
  ctr = 0
381
- elsif ch == "BACKSPACE"
382
- if $patt && $patt.size > 0
383
- $patt = $patt[0..-2]
384
- end
395
+ elsif ch == 'BACKSPACE'
396
+ $patt = $patt[0..-2] if $patt && !$patt.empty?
385
397
  ctr = 0
386
398
  else
387
- #binding = $bindings[ch]
399
+ # binding = $bindings[ch]
388
400
  x = $bindings[ch]
389
401
  x = x.split if x
390
402
  if x
@@ -392,57 +404,56 @@ def run
392
404
  args = x
393
405
  send(binding, *args) if binding
394
406
  else
395
- #perror "No binding for #{ch}"
407
+ perror "No binding for #{ch}"
396
408
  end
397
- #p ch
409
+ # p ch
398
410
  end
399
411
  break if $quitting
400
412
  end
401
413
  write_curdir
402
- puts "bye"
414
+ puts 'bye'
403
415
  config_write if $writing
404
416
  end
405
417
 
406
418
  ## write current dir to a file so we can ccd to it when exiting
407
419
  def write_curdir
408
-
409
- f = File.expand_path("~/.fff_d")
420
+ f = File.expand_path('~/.fff_d')
410
421
  s = Dir.pwd
411
- File.open(f, "w") do |f2|
422
+ File.open(f, 'w') do |f2|
412
423
  f2.puts s
413
424
  end
414
- #puts "Written #{s} to #{f}"
425
+ # puts "Written #{s} to #{f}"
415
426
  end
416
427
 
417
-
418
428
  ## code related to long listing of files
419
- GIGA_SIZE = 1073741824.0
420
- MEGA_SIZE = 1048576.0
429
+ GIGA_SIZE = 1_073_741_824.0
430
+ MEGA_SIZE = 1_048_576.0
421
431
  KILO_SIZE = 1024.0
422
432
 
423
433
  # Return the file size with a readable style.
434
+ # NOTE format is a kernel method.
424
435
  def readable_file_size(size, precision)
425
- case
426
- #when size == 1 : "1 B"
427
- when size < KILO_SIZE then "%d B" % size
428
- when size < MEGA_SIZE then "%.#{precision}f K" % (size / KILO_SIZE)
429
- when size < GIGA_SIZE then "%.#{precision}f M" % (size / MEGA_SIZE)
430
- else "%.#{precision}f G" % (size / GIGA_SIZE)
436
+ if size < KILO_SIZE then format('%d B', size)
437
+ elsif size < MEGA_SIZE then format("%.#{precision}f K", (size / KILO_SIZE))
438
+ elsif size < GIGA_SIZE then format("%.#{precision}f M", (size / MEGA_SIZE))
439
+ else format("%.#{precision}f G", (size / GIGA_SIZE))
431
440
  end
432
441
  end
442
+
433
443
  ## format date for file given stat
434
- def date_format t
435
- t.strftime "%Y/%m/%d"
444
+ def date_format(t)
445
+ t.strftime '%Y/%m/%d'
436
446
  end
447
+
437
448
  ##
438
449
  #
439
450
  # print in columns
440
451
  # ary - array of data
441
452
  # sz - lines in one column
442
453
  #
443
- def columnate ary, sz
444
- buff=Array.new
445
- return buff if ary.nil? || ary.size == 0
454
+ def columnate(ary, sz)
455
+ buff = []
456
+ return buff if ary.nil? || ary.empty?
446
457
 
447
458
  # determine width based on number of files to show
448
459
  # if less than sz then 1 col and full width
@@ -454,39 +465,35 @@ def columnate ary, sz
454
465
  if ars <= sz
455
466
  wid = $gcols - d
456
467
  else
457
- tmp = (ars * 1.000/ sz).ceil
468
+ tmp = (ars * 1.000 / sz).ceil
458
469
  wid = $gcols / tmp - d
459
470
  end
460
- #elsif ars < sz * 2
461
- #wid = $gcols/2 - d
462
- #elsif ars < sz * 3
463
- #wid = $gcols/3 - d
464
- #else
465
- #wid = $gcols/$gviscols - d
466
- #end
471
+ # elsif ars < sz * 2
472
+ # wid = $gcols/2 - d
473
+ # elsif ars < sz * 3
474
+ # wid = $gcols/3 - d
475
+ # else
476
+ # wid = $gcols/$gviscols - d
477
+ # end
467
478
 
468
479
  # ix refers to the index in the complete file list, wherease we only show 60 at a time
469
- ix=0
470
- while true
480
+ ix = 0
481
+ loop do
471
482
  ## ctr refers to the index in the column
472
- ctr=0
483
+ ctr = 0
473
484
  while ctr < sz
474
485
 
475
486
  f = ary[ix]
476
487
  fsz = f.size
477
488
  if fsz > wid
478
- f = f[0, wid-2]+"$ "
489
+ f = f[0, wid - 2] + '$ '
479
490
  ## we do the coloring after trunc so ANSI escpe seq does not get get
480
- if ix + $sta == $cursor
481
- f = "#{CURSOR_COLOR}#{f}#{CLEAR}"
482
- end
491
+ f = "#{CURSOR_COLOR}#{f}#{CLEAR}" if ix + $sta == $cursor
483
492
  else
484
493
  ## we do the coloring before padding so the entire line does not get padded, only file name
485
- if ix + $sta == $cursor
486
- f = "#{CURSOR_COLOR}#{f}#{CLEAR}"
487
- end
488
- #f = f.ljust(wid)
489
- f << " " * (wid-fsz)
494
+ f = "#{CURSOR_COLOR}#{f}#{CLEAR}" if ix + $sta == $cursor
495
+ # f = f.ljust(wid)
496
+ f << ' ' * (wid - fsz)
490
497
  end
491
498
 
492
499
  if buff[ctr]
@@ -495,156 +502,188 @@ def columnate ary, sz
495
502
  buff[ctr] = f
496
503
  end
497
504
 
498
- ctr+=1
499
- ix+=1
505
+ ctr += 1
506
+ ix += 1
500
507
  break if ix >= ary.size
501
508
  end
502
509
  break if ix >= ary.size
503
510
  end
504
- return buff
511
+ buff
505
512
  end
513
+
506
514
  ## formats the data with number, mark and details
507
- def format ary
508
- #buff = Array.new
515
+ # 2019-03-09 - at some time this got renamed to `format` which is a kernel
516
+ # method and this overshadowed that method.
517
+ def _format(ary)
518
+ # buff = Array.new
509
519
  buff = Array.new(ary.size)
510
- return buff if ary.nil? || ary.size == 0
520
+ return buff if ary.nil? || ary.empty?
511
521
 
512
522
  # determine width based on number of files to show
513
523
  # if less than sz then 1 col and full width
514
524
  #
515
525
  # ix refers to the index in the complete file list, wherease we only show 60 at a time
516
- ix=0
517
- ctr=0
526
+ ix = 0
527
+ ctr = 0
518
528
  ary.each do |f|
519
529
  ## ctr refers to the index in the column
520
530
  ind = get_shortcut(ix)
521
- mark=SPACE
522
- cur=SPACE
531
+ mark = SPACE
532
+ cur = SPACE
523
533
  cur = CURMARK if ix + $sta == $cursor
524
- mark=GMARK if $selected_files.index(ary[ix])
534
+ # TODO: add full path TESTME
535
+ # mark = GMARK if $selected_files.index(ary[ix])
536
+ mark = GMARK if selected?(ary[ix])
525
537
 
526
538
  if $long_listing
527
539
  begin
528
- unless File.exist? f
529
- last = f[-1]
530
- if last == " " || last == "@" || last == '*'
531
- stat = File.stat(f.chop)
532
- end
533
- else
540
+ if File.exist? f
534
541
  stat = File.stat(f)
542
+ else
543
+ last = f[-1]
544
+ stat = File.stat(f.chop) if last == ' ' || last == '@' || last == '*'
535
545
  end
536
- f = "%10s %s %s" % [readable_file_size(stat.size,1), date_format(stat.mtime), f]
546
+ f = format('%10s %s %s', readable_file_size(stat.size, 1),
547
+ date_format(stat.mtime), f)
537
548
  rescue Exception => e
538
- f = "%10s %s %s" % ["?", "??????????", f]
549
+ f = format('%10s %s %s', '?', '??????????', f)
539
550
  end
540
551
  end
541
552
 
542
553
  s = "#{ind}#{mark}#{cur}#{f}"
543
554
  # I cannot color the current line since format does the chopping
544
- # so not only does the next lines alignment get skeweed, but also if the line is truncated
555
+ # so not only does the next lines alignment get skewed,
556
+ # but also if the line is truncated
545
557
  # then the color overflows.
546
- #if ix + $sta == $cursor
547
- #s = "#{RED}#{s}#{CLEAR}"
548
- #end
558
+ # if ix + $sta == $cursor
559
+ # s = "#{RED}#{s}#{CLEAR}"
560
+ # end
549
561
 
550
562
  buff[ctr] = s
551
563
 
552
- ctr+=1
553
- ix+=1
564
+ ctr += 1
565
+ ix += 1
554
566
  end
555
- return buff
567
+ buff
556
568
  end
569
+
557
570
  ## select file based on key pressed
558
- def select_hint view, ch
571
+ def select_hint(view, ch)
559
572
  # a to y is direct
560
573
  # if x or z take a key IF there are those many
561
574
  #
562
575
  ix = get_index(ch, view.size)
563
- if ix
564
- f = view[ix]
565
- return unless f
566
- $cursor = $sta + ix
567
-
568
- if $mode == 'SEL'
569
- toggle_select f
570
- elsif $mode == 'COM'
571
- run_command f
572
- else
573
- open_file f
574
- end
575
- #selectedix=ix
576
+ return unless ix
577
+
578
+ f = view[ix]
579
+ return unless f
580
+
581
+ $cursor = $sta + ix
582
+
583
+ if $mode == 'SEL'
584
+ toggle_select f
585
+ elsif $mode == 'COM'
586
+ run_command f
587
+ else
588
+ open_file f
576
589
  end
590
+ # selectedix=ix
577
591
  end
592
+
578
593
  ## toggle selection state of file
579
- def toggle_select f
580
- if $selected_files.index f
581
- $selected_files.delete f
594
+ def toggle_select(f)
595
+ # dir = Dir.pwd
596
+ # file = File.join(dir, f)
597
+ if selected? f
598
+ remove_from_selection f
582
599
  else
583
- $selected_files.push f
600
+ add_to_selection f
584
601
  end
585
602
  end
586
603
 
587
604
  ## open file or directory
588
- def open_file f
605
+ def open_file(f)
589
606
  return unless f
590
- if f[0] == "~"
591
- f = File.expand_path(f)
592
- end
607
+
608
+ f = File.expand_path(f) if f[0] == '~'
593
609
  unless File.exist? f
594
610
  # this happens if we use (T) in place of (M)
595
611
  # it places a space after normal files and @ and * which borks commands
596
612
  last = f[-1]
597
- if last == " " || last == "@" || last == '*'
598
- f = f.chop
599
- end
613
+ f = f.chop if last == ' ' || last == '@' || last == '*'
600
614
  end
601
615
  nextpos = nil
602
616
 
603
617
  # could be a bookmark with position attached to it
604
- if f.index(":")
605
- f, nextpos = f.split(":")
606
- end
618
+ f, nextpos = f.split(':') if f.index(':')
607
619
  if File.directory? f
608
620
  save_dir_pos
609
621
  change_dir f, nextpos
610
622
  elsif File.readable? f
611
- $default_command ||= "$EDITOR"
623
+ $default_command ||= '$PAGER'
612
624
  if !$editor_mode
613
625
  ft = filetype f
614
626
  if ft
615
627
  comm = $pager_command[ft]
616
628
  else
617
629
  comm = $pager_command[File.extname(f)]
618
- comm = $pager_command["unknown"] unless comm
630
+ comm ||= $pager_command['unknown']
619
631
  end
620
632
  else
621
633
  comm = $default_command
622
634
  end
623
635
  comm ||= $default_command
624
- if comm.index("%%")
625
- comm = comm.gsub("%%", Shellwords.escape(f))
626
- else
627
- comm = comm + " #{Shellwords.escape(f)}"
628
- end
636
+ comm = if comm.index('%%')
637
+ comm.gsub('%%', Shellwords.escape(f))
638
+ else
639
+ comm + " #{Shellwords.escape(f)}"
640
+ end
629
641
  clear_screen
630
642
  reset_terminal
631
- system("#{comm}")
643
+ system(comm.to_s)
632
644
  setup_terminal
633
- f = Dir.pwd + "/" + f if f[0] != '/'
645
+ f = Dir.pwd + '/' + f if f[0] != '/'
634
646
  $visited_files.insert(0, f)
635
647
  push_used_dirs Dir.pwd
636
648
  else
637
649
  perror "open_file: (#{f}) not found"
638
- # could check home dir or CDPATH env variable DO
650
+ # could check home dir or CDPATH env variable DO
639
651
  end
640
652
  end
641
653
 
654
+ # regardless of mode, view the current file using pager
655
+ def page_current
656
+ command = ENV['MANPAGER'] || ENV['PAGER'] || 'less'
657
+ run_on_current command
658
+ end
659
+
660
+ # regardless of mode, edit the current file using editor
661
+ def edit_current
662
+ command = ENV['EDITOR'] || ENV['VISUAL'] || 'vim'
663
+ run_on_current command
664
+ $visited_files.insert(0, current_file)
665
+ end
666
+
667
+ # run given command on current file
668
+ def run_on_current(command)
669
+ f = $view[$cursor]
670
+ return unless f
671
+ f = File.expand_path(f)
672
+ return unless File.readable?(f)
673
+
674
+ clear_screen
675
+ reset_terminal
676
+ comm = "#{command} #{f}"
677
+ system(comm.to_s)
678
+ setup_terminal
679
+ end
680
+
642
681
  ## run command on given file/s
643
682
  # Accepts command from user
644
683
  # After putting readline in place of gets, pressing a C-c has a delayed effect. It goes intot
645
684
  # exception bloack after executing other commands and still does not do the return !
646
- def run_command f
647
- files=nil
685
+ def run_command(f)
686
+ files = nil
648
687
  case f
649
688
  when Array
650
689
  # escape the contents and create a string
@@ -654,13 +693,14 @@ def run_command f
654
693
  end
655
694
  print "Run a command on #{files}: "
656
695
  begin
657
- #Readline::HISTORY.push(*values)
658
- command = Readline::readline('>', true)
659
- #command = gets().chomp
660
- return if command.size == 0
661
- print "Second part of command: "
662
- #command2 = gets().chomp
663
- command2 = Readline::readline('>', true)
696
+ # Readline::HISTORY.push(*values)
697
+ command = Readline.readline('>', true)
698
+ # command = gets().chomp
699
+ return if command.empty?
700
+
701
+ print 'Second part of command: '
702
+ # command2 = gets().chomp
703
+ command2 = Readline.readline('>', true)
664
704
  puts "#{command} #{files} #{command2}"
665
705
  system "#{command} #{files} #{command2}"
666
706
  rescue Exception => ex
@@ -672,27 +712,33 @@ def run_command f
672
712
  end
673
713
 
674
714
  refresh
675
- puts "Press a key ..."
715
+ puts 'Press a key ...'
676
716
  push_used_dirs Dir.pwd
677
717
  get_char
678
718
  end
679
719
 
680
720
  ## cd to a dir
681
- def change_dir f, pos = nil
721
+ def change_dir(f, pos = nil)
682
722
  $visited_dirs.insert(0, Dir.pwd)
683
723
  f = File.expand_path(f)
684
724
  Dir.chdir f
685
- $filterstr ||= "M"
725
+ $filterstr ||= 'M'
686
726
  $files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}#{$filterstr})'`.split("\n")
687
727
  $files = sort_file_list $files
688
728
  post_cd
689
729
  if pos
690
730
  # convert curpos to sta also
691
- #$cursor = pos.to_i
731
+ # $cursor = pos.to_i
692
732
  goto_line pos.to_i
693
733
  end
694
734
  end
695
735
 
736
+ def goto_previous_dir
737
+ prev_dir = $visited_dirs.first
738
+ return unless prev_dir
739
+ change_dir prev_dir
740
+ end
741
+
696
742
  ## clear sort order and refresh listing, used typically if you are in some view
697
743
  # such as visited dirs or files
698
744
  def escape
@@ -700,25 +746,25 @@ def escape
700
746
  $sorto = $default_sort_order
701
747
  $viewctr = 0
702
748
  $title = nil
703
- $filterstr = "M"
749
+ $filterstr = 'M'
704
750
  visual_block_clear
705
751
  refresh
706
752
  end
707
753
 
708
754
  ## refresh listing after some change like option change, or toggle
709
755
  def refresh
710
- $filterstr ||= "M"
711
- $files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}#{$filterstr})'`.split("\n")
712
- # first put dirs then files
713
- $files = sort_file_list $files
714
- $patt = nil
715
- $title = nil
756
+ $filterstr ||= 'M'
757
+ $files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}#{$filterstr})'`.split("\n")
758
+ # first put dirs then files
759
+ $files = sort_file_list $files
760
+ $patt = nil
761
+ $title = nil
716
762
  end
717
763
 
718
- def sort_file_list files
719
- _dirs = $files.select { |f| File.directory?(f) }
720
- _files = $files.select { |f| File.file?(f) }
721
- return _dirs + _files
764
+ def sort_file_list(_files)
765
+ _dirs = $files.select { |f| File.directory?(f) }
766
+ _files = $files.select { |f| File.file?(f) }
767
+ _dirs + _files
722
768
  end
723
769
 
724
770
  ## unselect all files
@@ -729,31 +775,31 @@ end
729
775
 
730
776
  ## select all files
731
777
  def select_all
732
- $selected_files = $view.dup
778
+ # TODO: add path TESTME
779
+ dir = Dir.pwd
780
+ $selected_files = $view.map { |file| File.join(dir, file) }
733
781
  end
734
782
 
735
783
  ## accept dir to goto and change to that ( can be a file too)
736
784
  def goto_dir
737
- print "Enter path: "
785
+ print 'Enter path: '
738
786
  begin
739
- #path = gets.chomp
740
- path = Readline::readline('>', true)
741
- return if path == ""
742
- #rescue => ex
787
+ # path = gets.chomp
788
+ path = Readline.readline('>', true)
789
+ return if path == ''
790
+ # rescue => ex
743
791
  rescue Exception => ex
744
- perror "Cancelled cd, press a key"
792
+ perror 'Cancelled cd, press a key'
745
793
  return
746
794
  end
747
795
  f = File.expand_path(path)
748
796
  unless File.directory? f
749
797
  ## check for env variable
750
798
  tmp = ENV[path]
751
- if tmp.nil? || !File.directory?( tmp )
799
+ if tmp.nil? || !File.directory?(tmp)
752
800
  ## check for dir in home
753
801
  tmp = File.expand_path("~/#{path}")
754
- if File.directory? tmp
755
- f = tmp
756
- end
802
+ f = tmp if File.directory? tmp
757
803
  else
758
804
  f = tmp
759
805
  end
@@ -769,15 +815,14 @@ end
769
815
  def selection_mode_toggle
770
816
  if $mode == 'SEL'
771
817
  # we seem to be coming out of select mode with some files
772
- if $selected_files.size > 0
773
- run_command $selected_files
774
- end
818
+ run_command $selected_files unless $selected_files.empty?
775
819
  $mode = nil
776
820
  else
777
- #$selection_mode = !$selection_mode
821
+ # $selection_mode = !$selection_mode
778
822
  $mode = 'SEL'
779
823
  end
780
824
  end
825
+
781
826
  ## toggle command mode
782
827
  def command_mode
783
828
  if $mode == 'COM'
@@ -786,24 +831,32 @@ def command_mode
786
831
  end
787
832
  $mode = 'COM'
788
833
  end
834
+
789
835
  def goto_parent_dir
790
836
  change_dir '..'
791
837
  end
838
+
839
+ def goto_home_dir
840
+ change_dir '~'
841
+ end
842
+
792
843
  ## This actually filters, in zfm it goes to that entry since we have a cursor there
793
844
  #
794
- def goto_entry_starting_with fc=nil
845
+ def goto_entry_starting_with(fc = nil)
795
846
  unless fc
796
- print "Entries starting with: "
847
+ print 'Entries starting with: '
797
848
  fc = get_char
798
849
  end
799
850
  return if fc.size != 1
851
+
800
852
  ## this is wrong and duplicates the functionality of /
801
853
  # It shoud go to cursor of item starting with fc
802
854
  $patt = "^#{fc}"
803
855
  end
804
- def goto_bookmark ch=nil
856
+
857
+ def goto_bookmark(ch = nil)
805
858
  unless ch
806
- print "Enter bookmark char: "
859
+ print 'Enter bookmark char: '
807
860
  ch = get_char
808
861
  end
809
862
  if ch =~ /^[0-9A-Z]$/
@@ -812,122 +865,173 @@ def goto_bookmark ch=nil
812
865
  # this way we leave the position as is, so it gets written back
813
866
  nextpos = nil
814
867
  if d
815
- if d.index(":")
816
- ix = d.index(":")
817
- nextpos = d[ix+1..-1]
818
- d = d[0,ix]
868
+ if d.index(':')
869
+ ix = d.index(':')
870
+ nextpos = d[ix + 1..-1]
871
+ d = d[0, ix]
819
872
  end
820
873
  change_dir d, nextpos
821
874
  else
822
875
  perror "#{ch} not a bookmark"
823
876
  end
824
877
  else
825
- #goto_entry_starting_with ch
878
+ # goto_entry_starting_with ch
826
879
  file_starting_with ch
827
880
  end
828
881
  end
829
882
 
830
-
831
883
  ## take regex from user, to run on files on screen, user can filter file names
832
884
  def enter_regex
833
- print "Enter (regex) pattern: "
834
- #$patt = gets().chomp
835
- $patt = Readline::readline('>', true)
885
+ print 'Enter (regex) pattern: '
886
+ # $patt = gets().chomp
887
+ $patt = Readline.readline('>', true)
836
888
  ctr = 0
837
889
  end
890
+
838
891
  def next_page
839
892
  $sta += $pagesize
840
893
  end
894
+
841
895
  def prev_page
842
896
  $sta -= $pagesize
843
897
  end
844
898
 
899
+ # print help on key-bindings
900
+ # 2019-03-08 - write to temp file and user PAGER
845
901
  def print_help
846
- clear_screen
847
- puts "HELP"
848
- puts
849
- puts "To open a file or dir press 1-9 a-z A-Z "
850
- puts "Command Mode: Will prompt for a command to run on a file, after selecting using hotkey"
851
- puts "Selection Mode: Each selection adds to selection list (toggles)"
852
- puts " Upon exiting mode, user is prompted for a command to run on selected files"
853
- puts
854
- ary = []
855
- $bindings.each_pair { |k, v| ary.push "#{k.ljust(7)} => #{v}" }
856
- ary = columnate ary, $grows - 7
857
- ary.each {|line| print line, "\n" }
858
- get_char
902
+ require 'tempfile'
903
+ file = Tempfile.new('help')
904
+ begin
905
+ file.puts ' HELP'
906
+
907
+ file.puts
908
+ file.puts 'To open a file or dir press 1-9 a-z A-Z '
909
+ file.puts 'Command Mode: Will prompt for a command to run on a file, after selecting using hotkey'
910
+ file.puts 'Selection Mode: Each selection adds to selection list (toggles)'
911
+ file.puts ' Execute commands on selected files. e.g D '
912
+ file.puts ' Upon exiting mode, user is prompted for a command to run on selected files'
913
+ file.puts
914
+ ary = []
915
+ $bindings.each_pair { |k, v| ary.push "#{k.ljust(7)} => #{v}" }
916
+ ary = columnate ary, (ary.size/2)+1
917
+ ary.each { |line| file.puts line }
918
+ file.flush
919
+ system "$PAGER #{file.path}"
920
+ rescue
921
+ file.close
922
+ file.unlink
923
+ end
924
+ end #
859
925
 
860
- end
861
926
  def show_marks
862
927
  puts
863
- puts "Bookmarks: "
928
+ puts 'Bookmarks: '
864
929
  $bookmarks.each_pair { |k, v| puts "#{k.ljust(7)} => #{v}" }
865
930
  puts
866
- print "Enter bookmark to goto: "
931
+ print 'Enter bookmark to goto: '
867
932
  ch = get_char
868
933
  goto_bookmark(ch) if ch =~ /^[0-9A-Z]$/
869
934
  end
935
+
870
936
  # MENU MAIN -- keep consistent with zfm
871
937
  def main_menu
872
938
  h = {
873
- :a => :ack,
874
- "/" => :ffind,
939
+ :a => :ag,
940
+ '/' => :ffind,
875
941
  :l => :locate,
876
- :v => :viminfo,
942
+ :V => :viminfo,
943
+ :v => :vidir,
877
944
  :z => :z_interface,
878
945
  :d => :child_dirs,
879
946
  :r => :recent_files,
947
+ '1' => :select_visited_files,
948
+ '2' => :select_used_dirs,
880
949
  :t => :dirtree,
881
- "4" => :tree,
950
+ '4' => :tree,
882
951
  :s => :sort_menu,
883
952
  :F => :filter_menu,
884
- :c => :command_menu ,
953
+ :c => :command_menu,
885
954
  :B => :bindkey_ext_command,
886
955
  :M => :newdir,
887
- "%" => :newfile,
956
+ '%' => :newfile,
957
+ 'S' => :scripts,
888
958
  :x => :extras
889
959
  }
890
- menu "Main Menu", h
960
+ menu 'Main Menu', h
961
+ end
962
+
963
+ # trying out fzf instead
964
+ # 2019-03-08 - 23:46
965
+ # FIXME returns a String not symbol, so some callers can fail
966
+ def fzfmenu(title, h)
967
+ return unless h
968
+
969
+ pbold title.to_s
970
+ values = h.values.join("\n")
971
+ binding = `echo "#{values}" | fzf --prompt="#{title.to_s} :"`
972
+ # h.each_pair { |k, v| puts " #{k}: #{v}" }
973
+ # ch = get_char
974
+ # binding = h[ch]
975
+ # binding ||= h[ch.to_sym]
976
+ # FIXME we have converted symbol to string
977
+ ch = nil
978
+ if binding
979
+ binding = binding.chomp
980
+ send(binding) if respond_to?(binding, true)
981
+ ch = h.key(binding)
982
+ end
983
+ [ch, binding]
891
984
  end
892
- def menu title, h
985
+
986
+ # this style used hotkeys which I remember. But it can get long.
987
+ # and I have to fix a hotkey for each new entry
988
+ def menu(title, h)
893
989
  return unless h
894
990
 
895
- pbold "#{title}"
896
- h.each_pair { |k, v| puts " #{k}: #{v}" }
991
+ pbold title.to_s
992
+ # h.each_pair { |k, v| puts " #{k}: #{v}" }
993
+ # 2019-03-09 - trying out using `column` to print in cols
994
+ ary = []
995
+ h.each_pair { |k, v| ary << " #{k}: #{v}" }
996
+ x = ary.join("\n")
997
+ puts %x{echo "#{x}" | column}
998
+
897
999
  ch = get_char
898
1000
  binding = h[ch]
899
- binding = h[ch.to_sym] unless binding
1001
+ binding ||= h[ch.to_sym]
900
1002
  if binding
901
- if respond_to?(binding, true)
902
- send(binding)
903
- end
1003
+ send(binding) if respond_to?(binding, true)
904
1004
  end
905
- return ch, binding
1005
+ [ch, binding]
906
1006
  end
1007
+
907
1008
  def toggle_menu
908
- h = { :h => :toggle_hidden, :c => :toggle_case, :l => :toggle_long_list , "1" => :toggle_columns,
909
- :p => :toggle_pager_mode, :e => :toggle_enhanced_list}
910
- ch, menu_text = menu "Toggle Menu", h
1009
+ h = { :h => :toggle_hidden, :c => :toggle_case, :l => :toggle_long_list, '1' => :toggle_columns,
1010
+ :p => :toggle_pager_mode, :e => :toggle_enhanced_list }
1011
+ ch, menu_text = menu 'Toggle Menu', h
1012
+ # NOTE fzfmenu returns string not symbol
1013
+ return unless menu_text
1014
+
911
1015
  case menu_text
912
1016
  when :toggle_hidden
913
- $hidden = $hidden ? nil : "D"
1017
+ $hidden = $hidden ? nil : 'D'
914
1018
  refresh
915
1019
  when :toggle_case
916
- #$ignorecase = $ignorecase ? "" : "i"
1020
+ # $ignorecase = $ignorecase ? "" : "i"
917
1021
  $ignorecase = !$ignorecase
918
1022
  refresh
919
1023
  when :toggle_columns
920
1024
  $gviscols = 3 if $gviscols == 1
921
- #$long_listing = false if $gviscols > 1
1025
+ # $long_listing = false if $gviscols > 1
922
1026
  x = $grows * $gviscols
923
- $pagesize = $pagesize==x ? $grows : x
1027
+ $pagesize = $pagesize == x ? $grows : x
924
1028
  when :toggle_pager_mode
925
1029
  $editor_mode = !$editor_mode
926
- if $editor_mode
927
- $default_command = nil
928
- else
929
- $default_command = ENV['MANPAGER'] || ENV['PAGER']
930
- end
1030
+ $default_command = if $editor_mode
1031
+ ENV['EDITOR'] # earlier nil # 2019-03-10 -
1032
+ else
1033
+ ENV['MANPAGER'] || ENV['PAGER']
1034
+ end
931
1035
  when :toggle_enhanced_list
932
1036
  $enhanced_mode = !$enhanced_mode
933
1037
 
@@ -938,7 +1042,7 @@ def toggle_menu
938
1042
  $pagesize = $grows
939
1043
  else
940
1044
  x = $grows * $gviscols
941
- $pagesize = $pagesize==x ? $grows : x
1045
+ $pagesize = $pagesize == x ? $grows : x
942
1046
  end
943
1047
  refresh
944
1048
  end
@@ -946,34 +1050,34 @@ end
946
1050
 
947
1051
  def sort_menu
948
1052
  lo = nil
949
- h = { :n => :newest, :a => :accessed, :o => :oldest,
950
- :l => :largest, :s => :smallest , :m => :name , :r => :rname, :d => :dirs, :c => :clear }
951
- ch, menu_text = menu "Sort Menu", h
1053
+ h = { n: :newest, a: :accessed, o: :oldest,
1054
+ l: :largest, s: :smallest, m: :name, r: :rname, d: :dirs, c: :clear }
1055
+ ch, menu_text = menu 'Sort Menu', h
952
1056
  case menu_text
953
1057
  when :newest
954
- lo="om"
1058
+ lo = 'om'
955
1059
  when :accessed
956
- lo="oa"
1060
+ lo = 'oa'
957
1061
  when :oldest
958
- lo="Om"
1062
+ lo = 'Om'
959
1063
  when :largest
960
- lo="OL"
1064
+ lo = 'OL'
961
1065
  when :smallest
962
- lo="oL"
1066
+ lo = 'oL'
963
1067
  when :name
964
- lo="on"
1068
+ lo = 'on'
965
1069
  when :rname
966
- lo="On"
1070
+ lo = 'On'
967
1071
  when :dirs
968
- lo="/"
1072
+ lo = '/'
969
1073
  when :clear
970
- lo=""
1074
+ lo = ''
971
1075
  end
972
1076
  ## This needs to persist and be a part of all listings, put in change_dir.
973
1077
  $sorto = lo
974
1078
  $files = `zsh -c 'print -rl -- *(#{lo}#{$hidden}M)'`.split("\n") if lo
975
1079
  $title = nil
976
- #$files =$(eval "print -rl -- ${pattern}(${MFM_LISTORDER}$filterstr)")
1080
+ # $files =$(eval "print -rl -- ${pattern}(${MFM_LISTORDER}$filterstr)")
977
1081
  end
978
1082
 
979
1083
  def command_menu
@@ -986,13 +1090,14 @@ def command_menu
986
1090
  # should be able to sort THIS listing and not rerun command. But for that I'd need to use
987
1091
  # xargs ls -t etc rather than the zsh sort order. But we can run a filter using |.
988
1092
  #
989
- h = { :t => :today, :D => :default_command , :R => :remove_from_list}
990
- if $editor_mode
991
- h[:e] = :pager_mode
992
- else
993
- h[:e] = :editor_mode
994
- end
995
- ch, menu_text = menu "Command Menu", h
1093
+ h = { t: :today, D: :default_command, R: :remove_from_list,
1094
+ v: :page_selection }
1095
+ h[:e] = if $editor_mode
1096
+ :pager_mode
1097
+ else
1098
+ :editor_mode
1099
+ end
1100
+ _, menu_text = menu 'Command Menu', h
996
1101
  case menu_text
997
1102
  when :pager_mode
998
1103
  $editor_mode = false
@@ -1008,26 +1113,27 @@ def command_menu
1008
1113
  $files = `zsh -c 'print -rl -- *(#{$hidden}Mm0)'`.split("\n")
1009
1114
  $title = "Today's files"
1010
1115
  when :default_command
1011
- print "Selecting a file usually invokes $EDITOR, what command do you want to use repeatedly on selected files: "
1012
- $default_command = gets().chomp
1013
- if $default_command != ""
1014
- print "Second part of command (maybe blank): "
1015
- $default_command2 = gets().chomp
1116
+ print 'Selecting a file usually invokes $EDITOR, what command do you want to use repeatedly on selected files: '
1117
+ $default_command = gets.chomp
1118
+ if $default_command != ''
1119
+ print 'Second part of command (maybe blank): '
1120
+ $default_command2 = gets.chomp
1016
1121
  else
1017
- print "Cleared default command, will default to $EDITOR"
1122
+ print 'Cleared default command, will default to $EDITOR'
1018
1123
  $default_command2 = nil
1019
1124
  $default_command = nil
1020
1125
  end
1021
1126
  end
1022
1127
  end
1128
+
1023
1129
  def extras
1024
- h = { "1" => :one_column, "2" => :multi_column, :c => :columns, :r => :config_read , :w => :config_write}
1025
- ch, menu_text = menu "Extras Menu", h
1130
+ h = { '1' => :one_column, '2' => :multi_column, :c => :columns, :r => :config_read, :w => :config_write }
1131
+ ch, menu_text = menu 'Extras Menu', h
1026
1132
  case menu_text
1027
1133
  when :one_column
1028
1134
  $pagesize = $grows
1029
1135
  when :multi_column
1030
- #$pagesize = 60
1136
+ # $pagesize = 60
1031
1137
  $pagesize = $grows * $gviscols
1032
1138
  when :columns
1033
1139
  print "How many columns to show: 1-6 [current #{$gviscols}]? "
@@ -1039,44 +1145,50 @@ def extras
1039
1145
  end
1040
1146
  end
1041
1147
  end
1148
+
1042
1149
  def filter_menu
1043
- h = { :d => :dirs, :f => :files, :e => :emptydirs , "0" => :emptyfiles}
1044
- ch, menu_text = menu "Filter Menu", h
1150
+ h = { :d => :dirs, :f => :files, :e => :emptydirs, '0' => :emptyfiles }
1151
+ ch, menu_text = menu 'Filter Menu', h
1045
1152
  files = nil
1046
1153
  case menu_text
1047
1154
  when :dirs
1048
- $filterstr = "/M"
1155
+ $filterstr = '/M'
1049
1156
  files = `zsh -c 'print -rl -- *(#{$sorto}/M)'`.split("\n")
1050
- $title = "Filter: directories only"
1157
+ $title = 'Filter: directories only'
1051
1158
  when :files
1052
- $filterstr = "."
1159
+ $filterstr = '.'
1053
1160
  files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}.)'`.split("\n")
1054
- $title = "Filter: files only"
1161
+ $title = 'Filter: files only'
1055
1162
  when :emptydirs
1056
- $filterstr = "/D^F"
1163
+ $filterstr = '/D^F'
1057
1164
  files = `zsh -c 'print -rl -- *(#{$sorto}/D^F)'`.split("\n")
1058
- $title = "Filter: empty directories"
1165
+ $title = 'Filter: empty directories'
1059
1166
  when :emptyfiles
1060
- $filterstr = ".L0"
1167
+ $filterstr = '.L0'
1061
1168
  files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}.L0)'`.split("\n")
1062
- $title = "Filter: empty files"
1169
+ $title = 'Filter: empty files'
1063
1170
  end
1064
1171
  if files
1065
1172
  $files = files
1066
1173
  $stact = 0
1067
1174
  end
1068
1175
  end
1176
+
1069
1177
  def select_used_dirs
1070
- $title = "Used Directories"
1071
- $files = $used_dirs.uniq
1178
+ $title = 'Used Directories'
1179
+ home = File.expand_path '~'
1180
+ $files = $used_dirs.uniq.map { |path| path.sub("#{home}", '~') }
1072
1181
  end
1182
+
1073
1183
  def select_visited_files
1074
1184
  # not yet a unique list, needs to be unique and have latest pushed to top
1075
- $title = "Visited Files"
1076
- $files = $visited_files.uniq
1185
+ $title = 'Visited Files'
1186
+ home = File.expand_path '~'
1187
+ $files = $visited_files.uniq.map { |path| path.sub("#{home}", '~') }
1077
1188
  end
1189
+
1078
1190
  def select_bookmarks
1079
- $title = "Bookmarks"
1191
+ $title = 'Bookmarks'
1080
1192
  $files = $bookmarks.values
1081
1193
  end
1082
1194
 
@@ -1084,15 +1196,13 @@ end
1084
1196
  # or we'll be stuck in a cycle
1085
1197
  def pop_dir
1086
1198
  # the first time we pop, we need to put the current on stack
1087
- if !$visited_dirs.index(Dir.pwd)
1088
- $visited_dirs.push Dir.pwd
1089
- end
1199
+ $visited_dirs.push Dir.pwd unless $visited_dirs.index(Dir.pwd)
1090
1200
  ## XXX make sure thre is something to pop
1091
1201
  d = $visited_dirs.delete_at 0
1092
1202
  ## XXX make sure the dir exists, cuold have been deleted. can be an error or crash otherwise
1093
1203
  $visited_dirs.push d
1094
1204
  Dir.chdir d
1095
- $filterstr ||= "M"
1205
+ $filterstr ||= 'M'
1096
1206
  $files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}#{$filterstr})'`.split("\n")
1097
1207
  $files = sort_file_list $files
1098
1208
  post_cd
@@ -1100,14 +1210,14 @@ end
1100
1210
 
1101
1211
  # after changing directory
1102
1212
  def post_cd
1103
- $patt=nil
1213
+ $patt = nil
1104
1214
  $sta = $cursor = 0
1105
1215
  $title = nil
1106
- if $selected_files.size > 0
1107
- $selected_files = []
1108
- end
1216
+ # 2019-03-10 - why am I clearing selected when dir changed !!! FIXME
1217
+ # $selected_files = [] unless $selected_files.empty?
1109
1218
  $visual_block_start = nil
1110
1219
  $stact = 0
1220
+ $current_dir = Dir.pwd # 2019-03-10 - so i don't keep doing in functions
1111
1221
  screen_settings
1112
1222
  # i think this will screw with the dir_pos since it is not filename based.
1113
1223
  enhance_file_list
@@ -1118,103 +1228,108 @@ end
1118
1228
 
1119
1229
  ## read dirs and files and bookmarks from file
1120
1230
  def config_read
1121
- #f = File.expand_path("~/.zfminfo")
1122
- f = File.expand_path(CONFIG_FILE)
1123
- if File.readable? f
1124
- load f
1125
- # maybe we should check for these existing else crash will happen.
1126
- $used_dirs.push(*(DIRS.split ":"))
1127
- $used_dirs.concat get_env_paths
1128
- $visited_files.push(*(FILES.split ":"))
1129
- #$bookmarks.push(*bookmarks) if bookmarks
1130
- chars = ('A'..'Z').to_a
1131
- chars.concat( ('0'..'9').to_a )
1132
- chars.each do |ch|
1133
- if Kernel.const_defined? "BM_#{ch}"
1134
- $bookmarks[ch] = Kernel.const_get "BM_#{ch}"
1135
- end
1136
- end
1137
- end
1231
+ # f = File.expand_path("~/.zfminfo")
1232
+ f = File.expand_path(CONFIG_FILE)
1233
+ return unless File.readable? f
1234
+
1235
+ hash = loadYML(f)
1236
+ $used_dirs = hash['DIRS']
1237
+ $visited_files = hash['FILES']
1238
+ $bookmarks = hash['BOOKMARKS']
1239
+ $used_dirs.concat get_env_paths
1138
1240
  end
1241
+
1139
1242
  def get_env_paths
1140
1243
  files = []
1141
- %w{ GEM_HOME PYTHONHOME}.each do |p|
1244
+ %w[GEM_HOME PYTHONHOME].each do |p|
1142
1245
  d = ENV[p]
1143
1246
  files.push d if d
1144
1247
  end
1145
- %w{ RUBYLIB RUBYPATH GEM_PATH PYTHONPATH }.each do |p|
1248
+ %w[RUBYLIB RUBYPATH GEM_PATH PYTHONPATH].each do |p|
1146
1249
  d = ENV[p]
1147
- files.concat d.split(":") if d
1250
+ files.concat d.split(':') if d
1148
1251
  end
1149
- return files
1252
+ files
1150
1253
  end
1151
1254
 
1152
1255
  ## save dirs and files and bookmarks to a file
1256
+ # - moved to yml 2019-03-09
1153
1257
  def config_write
1154
1258
  # Putting it in a format that zfm can also read and write
1155
- #f1 = File.expand_path("~/.zfminfo")
1156
- f1 = File.expand_path(CONFIG_FILE)
1157
- d = $used_dirs.join ":"
1158
- f = $visited_files.join ":"
1159
- File.open(f1, 'w+') do |f2|
1160
- # use "\n" for two lines of text
1161
- f2.puts "DIRS=\"#{d}\""
1162
- f2.puts "FILES=\"#{f}\""
1163
- $bookmarks.each_pair { |k, val|
1164
- f2.puts "BM_#{k}=\"#{val}\""
1165
- #f2.puts "BOOKMARKS[\"#{k}\"]=\"#{val}\""
1166
- }
1167
- end
1259
+ f1 = File.expand_path(CONFIG_FILE)
1260
+ hash = {}
1261
+ hash['DIRS'] = $used_dirs.select {|dir| File.exist? dir}
1262
+ hash['FILES'] = $visited_files.select {|file| File.exist? file}
1263
+ hash['BOOKMARKS'] = $bookmarks
1264
+ writeYML hash, f1
1168
1265
  $writing = $modified = false
1169
1266
  end
1170
1267
 
1268
+ # {{{ YML
1269
+ require 'yaml'
1270
+ def loadYML( filename)
1271
+ hash = YAML::load( File.open( filename ) )
1272
+ if $opt_debug
1273
+ $stderr.puts hash.keys.size
1274
+ end
1275
+ return hash
1276
+ end
1277
+ def writeYML obj, filename
1278
+ File.open(filename, 'w') {|f| f.write obj.to_yaml }
1279
+ if $opt_debug
1280
+ $stderr.puts "Written to file #{filename}"
1281
+ end
1282
+ end
1283
+ # }}}
1171
1284
  ## accept a character to save this dir as a bookmark
1172
1285
  def create_bookmark
1173
- print "Enter A to Z or 0-9 for bookmark: "
1286
+ print 'Enter A to Z or 0-9 for bookmark: '
1174
1287
  ch = get_char
1175
1288
  if ch =~ /^[0-9A-Z]$/
1176
1289
  $bookmarks[ch] = "#{Dir.pwd}:#{$cursor}"
1177
1290
  $modified = true
1178
1291
  else
1179
- perror "Bookmark must be upper-case character or number."
1292
+ perror 'Bookmark must be upper-case character or number.'
1180
1293
  end
1181
1294
  end
1295
+
1182
1296
  def subcommand
1183
- print "Enter command: "
1297
+ print 'Enter command: '
1184
1298
  begin
1185
- #command = gets().chomp
1186
- command = Readline::readline('>', true)
1187
- return if command == ""
1299
+ # command = gets().chomp
1300
+ command = Readline.readline('>', true)
1301
+ return if command == ''
1188
1302
  rescue Exception => ex
1189
1303
  return
1190
1304
  end
1191
- if command == "q"
1305
+ if command == 'q'
1192
1306
  if $modified
1193
- print "Do you want to save bookmarks? (y/n): "
1307
+ print 'Do you want to save bookmarks? (y/n): '
1194
1308
  ch = get_char
1195
- if ch == "y"
1309
+ if ch == 'y'
1196
1310
  $writing = true
1197
1311
  $quitting = true
1198
- elsif ch == "n"
1312
+ elsif ch == 'n'
1199
1313
  $quitting = true
1200
- print "Quitting without saving bookmarks"
1314
+ print 'Quitting without saving bookmarks'
1201
1315
  else
1202
- perror "No action taken."
1316
+ perror 'No action taken.'
1203
1317
  end
1204
1318
  else
1205
1319
  $quitting = true
1206
1320
  end
1207
- elsif command == "wq"
1321
+ elsif command == 'wq'
1208
1322
  $quitting = true
1209
1323
  $writing = true
1210
- elsif command == "x"
1324
+ elsif command == 'x'
1211
1325
  $quitting = true
1212
1326
  $writing = true if $modified
1213
- elsif command == "p"
1327
+ elsif command == 'p'
1214
1328
  system 'echo $PWD | pbcopy'
1215
1329
  puts 'Stored PWD in clipboard (using pbcopy)'
1216
1330
  end
1217
1331
  end
1332
+
1218
1333
  def quit_command
1219
1334
  if $modified
1220
1335
  puts 'Press w to save bookmarks before quitting ' if $modified
@@ -1228,91 +1343,102 @@ def quit_command
1228
1343
  end
1229
1344
 
1230
1345
  def views
1231
- views=%w[/ om oa Om OL oL On on]
1232
- viewlabels=%w[Dirs Newest Accessed Oldest Largest Smallest Reverse Name]
1346
+ views = %w[/ om oa Om OL oL On on]
1347
+ viewlabels = %w[Dirs Newest Accessed Oldest Largest Smallest Reverse Name]
1233
1348
  $sorto = views[$viewctr]
1234
1349
  $title = viewlabels[$viewctr]
1235
1350
  $viewctr += 1
1236
1351
  $viewctr = 0 if $viewctr > views.size
1237
1352
 
1238
1353
  $files = `zsh -c 'print -rl -- *(#{$sorto}#{$hidden}M)'`.split("\n")
1239
-
1240
1354
  end
1355
+
1241
1356
  def child_dirs
1242
- $title = "Child directories"
1357
+ $title = 'Child directories'
1243
1358
  $files = `zsh -c 'print -rl -- *(/#{$sorto}#{$hidden}M)'`.split("\n")
1244
1359
  end
1360
+
1245
1361
  def dirtree
1246
- $title = "Child directories"
1362
+ $title = 'Child directories'
1247
1363
  $files = `zsh -c 'print -rl -- **/*(/#{$sorto}#{$hidden}M)'`.split("\n")
1248
1364
  end
1365
+
1249
1366
  #
1250
1367
  # Get a full recursive listing of what's in this dir - useful for small projects with more
1251
1368
  # structure than files.
1252
1369
  def tree
1253
1370
  # Caution: use only for small projects, don't use in root.
1254
- $title = "Full Tree"
1371
+ $title = 'Full Tree'
1255
1372
  $files = `zsh -c 'print -rl -- **/*(#{$sorto}#{$hidden}M)'`.split("\n")
1256
1373
  end
1374
+
1257
1375
  # lists recent files in current dir
1258
- # TODO in some cases it shows mostly .git files, we need to prune those
1376
+ # In some cases it shows mostly .git files, we need to prune those
1259
1377
  def recent_files
1260
1378
  # print -rl -- **/*(Dom[1,10])
1261
- $title = "Recent files"
1262
- $files = `zsh -c 'print -rl -- **/*(Dom[1,15])'`.split("\n")
1379
+ $title = 'Recent files'
1380
+ $files = `zsh -c 'print -rl -- **/*(Dom[1,15])'`.split("\n").reject {|f| f[0] == '.'}
1263
1381
  end
1264
1382
 
1265
1383
  def select_current
1266
1384
  ## vp is local there, so i can do $vp[0]
1267
- #open_file $view[$sta] if $view[$sta]
1385
+ # open_file $view[$sta] if $view[$sta]
1268
1386
  open_file $view[$cursor] if $view[$cursor]
1269
1387
  end
1270
1388
 
1271
1389
  ## create a list of dirs in which some action has happened, for saving
1272
- def push_used_dirs d=Dir.pwd
1390
+ def push_used_dirs(d = Dir.pwd)
1273
1391
  $used_dirs.index(d) || $used_dirs.push(d)
1274
1392
  end
1275
- def pbold text
1393
+
1394
+ def pbold(text)
1276
1395
  puts "#{BOLD}#{text}#{BOLD_OFF}"
1277
1396
  end
1278
- def perror text
1397
+
1398
+ def perror(text)
1279
1399
  puts "#{RED}#{text}#{CLEAR}"
1280
1400
  get_char
1281
1401
  end
1282
- def pause text=" Press a key ..."
1402
+
1403
+ def pause(text = ' Press a key ...')
1283
1404
  print text
1284
1405
  get_char
1285
1406
  end
1407
+
1286
1408
  ## return shortcut for an index (offset in file array)
1287
1409
  # use 2 more arrays to make this faster
1288
1410
  # if z or Z take another key if there are those many in view
1289
1411
  # Also, display ROWS * COLS so now we are not limited to 60.
1290
- def get_shortcut ix
1291
- return "<" if ix < $stact
1412
+ def get_shortcut(ix)
1413
+ return '<' if ix < $stact
1414
+
1292
1415
  ix -= $stact
1293
1416
  i = $IDX[ix]
1294
1417
  return i if i
1295
- return "->"
1418
+
1419
+ '->'
1296
1420
  end
1421
+
1297
1422
  ## returns the integer offset in view (file array based on a-y za-zz and Za - Zz
1298
1423
  # Called when user types a key
1299
1424
  # should we even ask for a second key if there are not enough rows
1300
1425
  # What if we want to also trap z with numbers for other purposes
1301
- def get_index key, vsz=999
1426
+ def get_index(key, vsz = 999)
1302
1427
  i = $IDX.index(key)
1303
- return i+$stact if i
1304
- #sz = $IDX.size
1428
+ return i + $stact if i
1429
+
1430
+ # sz = $IDX.size
1305
1431
  zch = nil
1306
1432
  if vsz > 25
1307
- if key == "z" || key == "Z"
1433
+ if key == 'z' || key == 'Z'
1308
1434
  print key
1309
1435
  zch = get_char
1310
1436
  print zch
1311
1437
  i = $IDX.index("#{key}#{zch}")
1312
- return i+$stact if i
1438
+ return i + $stact if i
1313
1439
  end
1314
1440
  end
1315
- return nil
1441
+ nil
1316
1442
  end
1317
1443
 
1318
1444
  def delete_file
@@ -1323,21 +1449,22 @@ end
1323
1449
  # prompt is the user friendly text of command such as list for ls, or extract for dtrx, page for less
1324
1450
  # pauseyn is whether to pause after command as in file or ls
1325
1451
  #
1326
- def command_file prompt, *command
1452
+ def command_file(prompt, *command)
1327
1453
  pauseyn = command.shift
1328
- command = command.join " "
1329
- print "[#{prompt}] Choose a file [#{$view[$cursor]}]: "
1330
- file = ask_hint $view[$cursor]
1331
- #print "#{prompt} :: Enter file shortcut: "
1332
- #file = ask_hint
1333
- perror "Command Cancelled" unless file
1454
+ command = command.join ' '
1455
+ print "[#{prompt}] Choose a file [#{$view[$cursor]}]: "
1456
+ file = ask_hint $view[$cursor]
1457
+ # print "#{prompt} :: Enter file shortcut: "
1458
+ # file = ask_hint
1459
+ perror 'Command Cancelled' unless file
1334
1460
  return unless file
1461
+
1335
1462
  file = File.expand_path(file)
1336
- if File.exists? file
1463
+ if File.exist? file
1337
1464
  file = Shellwords.escape(file)
1338
1465
  pbold "#{command} #{file} (#{pauseyn})"
1339
1466
  system "#{command} #{file}"
1340
- pause if pauseyn == "y"
1467
+ pause if pauseyn == 'y'
1341
1468
  refresh
1342
1469
  else
1343
1470
  perror "File #{file} not found"
@@ -1346,31 +1473,30 @@ end
1346
1473
 
1347
1474
  ## prompt user for file shortcut and return file or nil
1348
1475
  #
1349
- def ask_hint deflt=nil
1476
+ def ask_hint(deflt = nil)
1350
1477
  f = nil
1351
1478
  ch = get_char
1352
- if ch == "ENTER"
1353
- return deflt
1354
- end
1479
+ return deflt if ch == 'ENTER'
1480
+
1355
1481
  ix = get_index(ch, $viewport.size)
1356
1482
  f = $viewport[ix] if ix
1357
- return f
1483
+ f
1358
1484
  end
1359
1485
 
1360
1486
  ## check screen size and accordingly adjust some variables
1361
1487
  #
1362
1488
  def screen_settings
1363
- $glines = %x(tput lines).to_i
1364
- $gcols = %x(tput cols).to_i
1489
+ $glines = `tput lines`.to_i
1490
+ $gcols = `tput cols`.to_i
1365
1491
  $grows = $glines - 3
1366
1492
  $pagesize = 60
1367
- #$gviscols = 3
1493
+ # $gviscols = 3
1368
1494
  $pagesize = $grows * $gviscols
1369
1495
  end
1370
1496
 
1371
1497
  ## moves column offset so we can reach unindexed columns or entries
1372
1498
  # 0 forward and any other back/prev
1373
- def column_next dir = 0
1499
+ def column_next(dir = 0)
1374
1500
  if dir == 0
1375
1501
  $stact += $grows
1376
1502
  $stact = 0 if $stact >= $viewport.size
@@ -1382,12 +1508,14 @@ end
1382
1508
 
1383
1509
  # currently i am only passing the action in from the list there as a key
1384
1510
  # I should be able to pass in new actions that are external commands
1385
- def file_actions(action=nil)
1386
- h = { :d => :delete, :m => :move, :r => :rename, :v => ENV["EDITOR"] || :vim,
1387
- :c => :copy, :C => :chdir,
1388
- :l => :less, :s => :most , :f => :file , :o => :open, :x => :dtrx, :z => :zip }
1389
- #acttext = h[action.to_sym] || action
1390
- acttext = action || ""
1511
+ # 2019-03-08 - TODO when a file name changes or moves it must be removed
1512
+ # from selection
1513
+ def file_actions(action = nil)
1514
+ h = { d: :delete, m: :move, r: :rename, v: ENV['EDITOR'] || :vim,
1515
+ c: :copy, C: :chdir, W: :remspace,
1516
+ l: :less, s: :most, f: :file, o: :open, x: :dtrx, z: :zip }
1517
+ # acttext = h[action.to_sym] || action
1518
+ acttext = action || ''
1391
1519
  file = nil
1392
1520
 
1393
1521
  sct = $selected_files.size
@@ -1395,11 +1523,20 @@ def file_actions(action=nil)
1395
1523
  text = "#{sct} files"
1396
1524
  file = $selected_files
1397
1525
  else
1398
- print "[#{acttext}] Choose a file [#{$view[$cursor]}]: "
1399
- file = ask_hint $view[$cursor]
1526
+ # 2019-03-07 - trying out direct deletes
1527
+ # why were we aksing to select a file when user is on a file
1528
+ # print "[#{acttext}] Choose a file [#{$view[$cursor]}]: "
1529
+ # file = ask_hint $view[$cursor]
1530
+ file = $view[$cursor]
1531
+ unless file
1532
+ file = ask_hint $view[$cursor]
1533
+ end
1400
1534
  return unless file
1535
+
1401
1536
  text = file
1402
1537
  end
1538
+ # 2019-03-07 - NOTE at this point file can be one or more files.
1539
+ # 2019-03-07 - text can be a file or count of files, so unreliable !!! FIXME
1403
1540
 
1404
1541
  case file
1405
1542
  when Array
@@ -1409,67 +1546,138 @@ def file_actions(action=nil)
1409
1546
  files = Shellwords.escape(file)
1410
1547
  end
1411
1548
 
1412
-
1413
1549
  ch = nil
1414
1550
  if action
1415
- menu_text = action
1551
+ menu_text = action
1416
1552
  else
1417
1553
  ch, menu_text = menu "File Menu for #{text}", h
1418
1554
  menu_text = :quit if ch == 'q'
1419
1555
  end
1556
+ return unless menu_text # pressed some wrong key
1557
+
1420
1558
  case menu_text.to_sym
1559
+
1421
1560
  when :quit
1561
+
1422
1562
  when :delete
1423
- print "rmtrash #{files} ?[yn]: "
1563
+ delcommand = 'rmtrash'
1564
+ print "#{delcommand} #{files} ?[yn]: "
1424
1565
  ch = get_char
1425
- return if ch != "y"
1426
- system "rmtrash #{files}"
1566
+ return if ch != 'y'
1567
+
1568
+ system "#{delcommand} #{files}"
1427
1569
  refresh
1570
+
1428
1571
  when :move
1572
+ # 2019-03-07 - NOTE this will only work with single file selection
1429
1573
  print "move #{text} to : "
1430
- #target = gets().chomp
1431
- target = Readline::readline('>', true)
1432
- text=File.expand_path(text)
1433
- return if target == ""
1574
+ # target = gets().chomp
1575
+ # target = Readline.readline('>', true)
1576
+ target = readline
1577
+ return unless target
1578
+
1579
+ target = '.' if target == ''
1580
+ # 2019-03-07 - NOTE cannot use text if multiple files
1581
+ # text = File.expand_path(text)
1582
+ target = File.expand_path(target)
1583
+ return if target == ''
1584
+
1434
1585
  if File.directory? target
1435
- FileUtils.mv text, target
1586
+ begin
1587
+ FileUtils.mv file, target
1588
+ rescue StandardError => exc
1589
+ perror exc.to_s
1590
+ end
1591
+ # 2019-03-08 - TODO if success remove from selection
1436
1592
  refresh
1437
1593
  else
1438
- perror "Target not a dir"
1594
+ perror 'Target not a dir'
1439
1595
  end
1596
+
1440
1597
  when :copy
1598
+ # Target must be directory
1441
1599
  print "copy #{text} to : "
1442
- target = Readline::readline('>', true)
1443
- return if target == ""
1444
- text=File.expand_path(text)
1445
- target = File.basename(text) if target == "."
1446
- if File.exists? target
1447
- perror "Target (#{target}) exists"
1448
- else
1449
- FileUtils.cp text, target
1600
+ target = readline
1601
+ return unless target # C-c
1602
+
1603
+ target = '.' if target == ''
1604
+ target = File.expand_path(target)
1605
+ return if target == ''
1606
+
1607
+ if File.directory? target
1608
+ begin
1609
+ FileUtils.cp file, target
1610
+ rescue StandardError => exc
1611
+ perror exc.to_s
1612
+ end
1450
1613
  refresh
1614
+ else
1615
+ perror 'Copy target must be a dir'
1451
1616
  end
1617
+
1452
1618
  when :chdir
1453
1619
  change_dir File.dirname(text)
1620
+
1454
1621
  when :zip
1455
- print "Archive name: "
1456
- #target = gets().chomp
1457
- target = Readline::readline('>', true)
1458
- return if target == ""
1622
+ print 'Archive name: '
1623
+ # target = gets().chomp
1624
+ target = Readline.readline('>', true)
1625
+ return if target == ''
1626
+
1459
1627
  # don't want a blank space or something screwing up
1460
1628
  if target && target.size > 3
1461
- if File.exists? target
1629
+ if File.exist? target
1462
1630
  perror "Target (#{target}) exists"
1463
1631
  else
1464
1632
  system "tar zcvf #{target} #{files}"
1465
1633
  refresh
1466
1634
  end
1467
1635
  end
1636
+
1468
1637
  when :rename
1638
+ # 2019-03-07 NOTE works for single file FIXME
1639
+ # 2019-03-07 - TODO for n files replace pattern with string
1640
+ print "rename #{text} to : "
1641
+ target = Readline.readline('>', true)
1642
+ return if target == ''
1643
+
1644
+ text = File.expand_path(text)
1645
+ target = File.basename(text) if target == '.'
1646
+ if File.exist? target
1647
+ perror "Target (#{target}) exists"
1648
+ else
1649
+ FileUtils.mv text, target
1650
+ refresh
1651
+ end
1469
1652
  when :most, :less, :vim
1470
1653
  system "#{menu_text} #{files}"
1654
+ # should we remove from selection ?
1655
+
1656
+ when :remspace
1657
+ # 2019-03-08 - 00:07 added replace space with underscore in filename
1658
+ print "Remove spaces from #{file}"
1659
+ pause
1660
+ farray = nil
1661
+
1662
+ # stupidly using one variable for scalar and array DUH !
1663
+ case file
1664
+ when String
1665
+ farray = [file]
1666
+ when Array
1667
+ farray = file
1668
+ end
1669
+
1670
+ farray.each do |f|
1671
+ if f.index ' '
1672
+ nname = f.tr(' ', '_')
1673
+ FileUtils.mv f, nname unless File.exist? nname
1674
+ # if success then remove from selection
1675
+ end
1676
+ end
1677
+ refresh
1471
1678
  else
1472
1679
  return unless menu_text
1680
+
1473
1681
  print "#{menu_text} #{files}"
1474
1682
  pause
1475
1683
  print
@@ -1477,13 +1685,16 @@ def file_actions(action=nil)
1477
1685
  refresh
1478
1686
  pause
1479
1687
  end
1480
- # remove non-existent files from select list due to move or delete or rename or whatever
1688
+
1689
+ # remove non-existent files from select list due to move or delete
1690
+ # or rename or whatever
1481
1691
  if sct > 0
1482
- $selected_files.reject! {|x| x = File.expand_path(x); !File.exists?(x) }
1692
+ $selected_files.select! { |x| x = File.expand_path(x); File.exist?(x) }
1483
1693
  end
1484
1694
  end
1485
1695
 
1486
- def columns_incdec howmany
1696
+ # increase or decrease column
1697
+ def columns_incdec(howmany)
1487
1698
  $gviscols += howmany.to_i
1488
1699
  $gviscols = 1 if $gviscols < 1
1489
1700
  $gviscols = 6 if $gviscols > 6
@@ -1493,59 +1704,65 @@ end
1493
1704
  # bind a key to an external command wich can be then be used for files
1494
1705
  def bindkey_ext_command
1495
1706
  print
1496
- pbold "Bind a capital letter to an external command"
1497
- print "Enter a capital letter to bind: "
1707
+ pbold 'Bind a capital letter to an external command'
1708
+ print 'Enter a capital letter to bind: '
1498
1709
  ch = get_char
1499
- return if ch == "Q"
1710
+ return if ch == 'Q'
1711
+
1500
1712
  if ch =~ /^[A-Z]$/
1501
1713
  print "Enter an external command to bind to #{ch}: "
1502
- com = gets().chomp
1503
- if com != ""
1504
- print "Enter prompt for command (blank if same as command): "
1505
- pro = gets().chomp
1506
- pro = com if pro == ""
1714
+ com = gets.chomp
1715
+ if com != ''
1716
+ print 'Enter prompt for command (blank if same as command): '
1717
+ pro = gets.chomp
1718
+ pro = com if pro == ''
1507
1719
  end
1508
- print "Pause after output [y/n]: "
1720
+ print 'Pause after output [y/n]: '
1509
1721
  yn = get_char
1510
1722
  $bindings[ch] = "command_file #{pro} #{yn} #{com}"
1511
1723
  end
1512
1724
  end
1513
- def ack
1514
- print "Enter a pattern to search (ack): "
1515
- #pattern = gets.chomp
1516
- pattern = Readline::readline('>', true)
1517
- return if pattern == ""
1518
- $title = "Files found using 'ack' #{pattern}"
1519
- system("ack #{pattern}")
1725
+
1726
+ def ag
1727
+ print 'Enter a pattern to search (ag): '
1728
+ pattern = Readline.readline('>', true)
1729
+ return if pattern == ''
1730
+
1731
+ $title = "Files found using 'ag' #{pattern}"
1732
+ system("ag #{pattern}")
1520
1733
  pause
1521
- files = `ack -l #{pattern}`.split("\n")
1522
- if files.size == 0
1523
- perror "No files found."
1734
+ files = `ag -l #{pattern}`.split("\n")
1735
+ if files.empty?
1736
+ perror 'No files found.'
1524
1737
  else
1525
1738
  $files = files
1526
1739
  end
1527
1740
  end
1741
+
1528
1742
  def ffind
1529
- print "Enter a file name pattern to find: "
1530
- pattern = Readline::readline('>', true)
1531
- return if pattern == ""
1743
+ print 'Enter a file name pattern to find: '
1744
+ pattern = Readline.readline('>', true)
1745
+ return if pattern == ''
1746
+
1532
1747
  $title = "Files found using 'find' #{pattern}"
1533
1748
  files = `find . -name '#{pattern}'`.split("\n")
1534
- if files.size == 0
1535
- perror "No files found."
1749
+ if files.empty?
1750
+ perror 'No files found.'
1536
1751
  else
1537
1752
  $files = files
1538
1753
  end
1539
1754
  end
1755
+
1540
1756
  def locate
1541
- print "Enter a file name pattern to locate: "
1542
- pattern = Readline::readline('>', true)
1543
- return if pattern == ""
1757
+ print 'Enter a file name pattern to locate: '
1758
+ pattern = Readline.readline('>', true)
1759
+ return if pattern == ''
1760
+
1544
1761
  $title = "Files found using 'locate' #{pattern}"
1545
1762
  files = `locate #{pattern}`.split("\n")
1546
- files.reject! {|x| x = File.expand_path(x); !File.exists?(x) }
1547
- if files.size == 0
1548
- perror "No files found."
1763
+ files.select! { |x| x = File.expand_path(x); File.exist?(x) }
1764
+ if files.empty?
1765
+ perror 'No files found.'
1549
1766
  else
1550
1767
  $files = files
1551
1768
  end
@@ -1555,12 +1772,12 @@ end
1555
1772
  # then you can modify this accordingly.
1556
1773
  #
1557
1774
  def viminfo
1558
- file = File.expand_path("~/.viminfo")
1559
- if File.exists? file
1560
- $title = "Files from ~/.viminfo"
1561
- #$files = `grep '^>' ~/.viminfo | cut -d ' ' -f 2- | sed "s#~#$HOME#g"`.split("\n")
1775
+ file = File.expand_path('~/.viminfo')
1776
+ if File.exist? file
1777
+ $title = 'Files from ~/.viminfo'
1778
+ # $files = `grep '^>' ~/.viminfo | cut -d ' ' -f 2- | sed "s#~#$HOME#g"`.split("\n")
1562
1779
  $files = `grep '^>' ~/.viminfo | cut -d ' ' -f 2- `.split("\n")
1563
- $files.reject! {|x| x = File.expand_path(x); !File.exists?(x) }
1780
+ $files.select! { |x| x = File.expand_path(x); File.exist?(x) }
1564
1781
  end
1565
1782
  end
1566
1783
 
@@ -1568,43 +1785,49 @@ end
1568
1785
  # modify this accordingly
1569
1786
  #
1570
1787
  def z_interface
1571
- file = File.expand_path("~/.z")
1572
- if File.exists? file
1573
- $title = "Directories from ~/.z"
1788
+ file = File.expand_path('~/.z')
1789
+ if File.exist? file
1790
+ $title = 'Directories from ~/.z'
1574
1791
  $files = `sort -rn -k2 -t '|' ~/.z | cut -f1 -d '|'`.split("\n")
1575
1792
  home = ENV['HOME']
1576
1793
  $files.collect! do |f|
1577
- f.sub(/#{home}/,"~")
1794
+ f.sub(/#{home}/, '~')
1578
1795
  end
1579
1796
  end
1580
1797
  end
1581
1798
 
1799
+ def vidir
1800
+ system "vidir"
1801
+ end
1582
1802
  ## there is no one consisten way i am getting.
1583
1803
  # i need to do a shell join if I am to pipe ffiles to say: xargs ls -t
1584
1804
  # but if i want to pipe names to grep xxx then i need to join with newlines
1585
- def pipe
1586
- end
1805
+ def pipe; end
1587
1806
 
1588
1807
  ## some cursor movement functions
1589
1808
  ##
1590
1809
  #
1591
1810
  def cursor_scroll_dn
1592
- moveto(pos() + MSCROLL)
1811
+ moveto(pos + MSCROLL)
1593
1812
  end
1813
+
1594
1814
  def cursor_scroll_up
1595
- moveto(pos() - MSCROLL)
1815
+ moveto(pos - MSCROLL)
1596
1816
  end
1817
+
1597
1818
  def cursor_dn
1598
- moveto(pos() + 1)
1819
+ moveto(pos + 1)
1599
1820
  end
1821
+
1600
1822
  def cursor_up
1601
- moveto(pos() - 1)
1823
+ moveto(pos - 1)
1602
1824
  end
1825
+
1603
1826
  def pos
1604
1827
  $cursor
1605
1828
  end
1606
1829
 
1607
- def moveto pos
1830
+ def moveto(pos)
1608
1831
  orig = $cursor
1609
1832
  $cursor = pos
1610
1833
  $cursor = [$cursor, $view.size - 1].min
@@ -1613,21 +1836,62 @@ def moveto pos
1613
1836
  fin = [orig, $cursor].max
1614
1837
  if $visual_mode
1615
1838
  # PWD has to be there in selction
1616
- if $selected_files.index $view[$cursor]
1839
+ # TODO: add full path TESTME
1840
+ if selected? current_file
1617
1841
  # this depends on the direction
1618
- $selected_files = $selected_files - $view[star..fin]
1842
+ # $selected_files = $selected_files - $view[star..fin]
1843
+ remove_from_selection $view[star..fin]
1619
1844
  ## current row remains in selection always.
1620
- $selected_files.push $view[$cursor]
1845
+ add_to_selection current_file
1621
1846
  else
1622
- $selected_files.concat $view[star..fin]
1847
+ # $selected_files.concat $view[star..fin]
1848
+ add_to_selection $view[star..fin]
1623
1849
  end
1624
1850
  end
1625
1851
  end
1852
+
1853
+ # is given file in selected array
1854
+ def selected?(file)
1855
+ $current_dir ||= Dir.pwd
1856
+ file = File.join($current_dir, file)
1857
+ return $selected_files.index file
1858
+ end
1859
+
1860
+ # TODO: can be array
1861
+ def add_to_selection(file)
1862
+ ff = file
1863
+ case file
1864
+ when String
1865
+ ff = [file]
1866
+ end
1867
+ $current_dir ||= Dir.pwd
1868
+ ff.each do |f|
1869
+ full = File.join($current_dir, f)
1870
+ $selected_files.push full
1871
+ end
1872
+ end
1873
+
1874
+ # TODO: can be array
1875
+ def remove_from_selection(file)
1876
+ ff = file
1877
+ case file
1878
+ when String
1879
+ ff = [file]
1880
+ end
1881
+ $current_dir ||= Dir.pwd
1882
+ ff.each do |f|
1883
+ full = File.join($current_dir, f)
1884
+ $selected_files.delete full
1885
+ end
1886
+ end
1887
+
1626
1888
  def visual_mode_toggle
1627
1889
  $visual_mode = !$visual_mode
1628
1890
  if $visual_mode
1629
1891
  $visual_block_start = $cursor
1630
- $selected_files.push $view[$cursor]
1892
+ # TODO: add full path TESTME
1893
+ # $selected_files.push $view[$cursor]
1894
+ add_to_selection current_file
1631
1895
  end
1632
1896
  end
1633
1897
 
@@ -1635,69 +1899,77 @@ def visual_block_clear
1635
1899
  if $visual_block_start
1636
1900
  star = [$visual_block_start, $cursor].min
1637
1901
  fin = [$visual_block_start, $cursor].max
1638
- $selected_files = $selected_files - $view[star..fin]
1902
+ # TODO: add full path TESTME
1903
+ # $selected_files = $selected_files - $view[star..fin]
1904
+ remove_from_selection $view[star..fin]
1639
1905
  end
1640
1906
  $visual_block_start = nil
1641
1907
  $visual_mode = nil
1642
1908
  end
1643
1909
 
1644
- def file_starting_with fc
1645
- ix = return_next_match(method(:file_matching?), "^#{fc}")
1646
- if ix
1647
- goto_line ix
1648
- end
1910
+ def file_starting_with(first_char)
1911
+ ix = return_next_match(method(:file_matching?), "^#{first_char}")
1912
+ goto_line ix if ix
1649
1913
  end
1650
- def file_matching? file, patt
1914
+
1915
+ def file_matching?(file, patt)
1651
1916
  file =~ /#{patt}/
1652
1917
  end
1653
1918
 
1654
1919
  ## generic method to take cursor to next position for a given condition
1655
- def return_next_match binding, *args
1920
+ def return_next_match(binding, *args)
1656
1921
  first = nil
1657
1922
  ix = 0
1658
- $view.each_with_index do |elem,ii|
1659
- if binding.call(elem, *args)
1660
- first ||= ii
1661
- if ii > $cursor
1662
- ix = ii
1663
- break
1664
- end
1923
+ $view.each_with_index do |elem, ii|
1924
+ next unless binding.call(elem, *args)
1925
+
1926
+ first ||= ii
1927
+ if ii > $cursor
1928
+ ix = ii
1929
+ break
1665
1930
  end
1666
1931
  end
1667
1932
  return first if ix == 0
1668
- return ix
1933
+
1934
+ ix
1669
1935
  end
1936
+
1670
1937
  ##
1671
1938
  # position cursor on a specific line which could be on a nother page
1672
1939
  # therefore calculate the correct start offset of the display also.
1673
- def goto_line pos
1674
- pages = ((pos * 1.00)/$pagesize).ceil
1940
+ def goto_line(pos)
1941
+ pages = ((pos * 1.00) / $pagesize).ceil
1675
1942
  pages -= 1
1676
1943
  $sta = pages * $pagesize + 1
1677
1944
  $cursor = pos
1678
1945
  end
1679
- def filetype f
1946
+
1947
+ def filetype(f)
1680
1948
  return nil unless f
1949
+
1681
1950
  f = Shellwords.escape(f)
1682
1951
  s = `file #{f}`
1683
- if s.index "text"
1952
+ if s.index 'text'
1684
1953
  return :text
1685
1954
  elsif s.index(/[Zz]ip/)
1686
1955
  return :zip
1687
- elsif s.index("archive")
1956
+ elsif s.index('archive')
1688
1957
  return :zip
1689
- elsif s.index "image"
1958
+ elsif s.index 'image'
1690
1959
  return :image
1691
- elsif s.index "data"
1960
+ elsif s.index 'data'
1692
1961
  return :text
1693
1962
  end
1963
+
1694
1964
  nil
1695
1965
  end
1696
1966
 
1697
1967
  def save_dir_pos
1698
1968
  return if $sta == 0 && $cursor == 0
1969
+
1699
1970
  $dir_position[Dir.pwd] = [$sta, $cursor]
1700
1971
  end
1972
+
1701
1973
  def revert_dir_pos
1702
1974
  $sta = 0
1703
1975
  $cursor = 0
@@ -1706,50 +1978,108 @@ def revert_dir_pos
1706
1978
  $sta = a.first
1707
1979
  $cursor = a[1]
1708
1980
  raise "sta is nil for #{Dir.pwd} : #{$dir_position[Dir.pwd]}" unless $sta
1709
- raise "cursor is nil" unless $cursor
1981
+ raise 'cursor is nil' unless $cursor
1710
1982
  end
1711
1983
  end
1984
+
1712
1985
  def newdir
1713
1986
  print
1714
- print "Enter directory name: "
1715
- str = Readline::readline('>', true)
1716
- return if str == ""
1717
- if File.exists? str
1987
+ print 'Enter directory name: '
1988
+ str = Readline.readline('>', true)
1989
+ return if str == ''
1990
+
1991
+ if File.exist? str
1718
1992
  perror "#{str} exists."
1719
1993
  return
1720
1994
  end
1721
1995
  begin
1722
1996
  FileUtils.mkdir str
1723
- $used_dirs.insert(0, str) if File.exists?(str)
1997
+ $used_dirs.insert(0, str) if File.exist?(str)
1724
1998
  refresh
1725
1999
  rescue Exception => ex
1726
2000
  perror "Error in newdir: #{ex}"
1727
2001
  end
1728
2002
  end
2003
+
1729
2004
  def newfile
1730
2005
  print
1731
- print "Enter file name: "
1732
- str = Readline::readline('>', true)
1733
- return if str == ""
1734
- system "$EDITOR #{str}"
1735
- $visited_files.insert(0, str) if File.exists?(str)
2006
+ print 'Enter file name: '
2007
+ str = Readline.readline('>', true)
2008
+ return if str == ''
2009
+
2010
+ # FIXME a file with space will not create single file
2011
+ # 2019-03-10 - maybe touch a file
2012
+
2013
+ system %($EDITOR "#{str}")
2014
+ $visited_files.insert(0, str) if File.exist?(str)
1736
2015
  refresh
1737
2016
  end
1738
2017
 
2018
+
2019
+
2020
+ def current_file
2021
+ $view[$cursor]
2022
+ end
2023
+
2024
+ def current_or_selected_files
2025
+ return $selected_files if $selected_files.size > 0
2026
+
2027
+ return [current_file]
2028
+ end
2029
+
2030
+ # ------------------- scripts ------------------ #
2031
+ # prompt for scripts to execute, giving selected file names
2032
+ def scripts
2033
+ title = 'Select a script'
2034
+ script_path = '~/.config/cetus/scripts'
2035
+ binding = `find #{script_path} -type f | fzf --prompt="#{title.to_s} :"`
2036
+ return unless binding
2037
+
2038
+ binding = binding.chomp if binding
2039
+ # TODO: check if binding is a file and executable
2040
+ # xargs only seems to take the first file
2041
+ # cf = current_or_selected_files.join('\0')
2042
+ # cf = Shellwords.join(current_or_selected_files)
2043
+ current_or_selected_files.each do |file|
2044
+ system %( #{binding} "#{file}" )
2045
+ end
2046
+ # system %(echo "#{cf}" | xargs #{binding})
2047
+ pause
2048
+ end
2049
+ # ------------- end of scripts --------------------------------#
2050
+
2051
+ # ------------------- page_selection ------------------ #
2052
+ def page_selection
2053
+ require 'tempfile'
2054
+ file = Tempfile.new('selected_files')
2055
+ begin
2056
+ $selected_files.each { |row| file.puts row }
2057
+ file.flush
2058
+ system "$PAGER #{file.path}"
2059
+ rescue
2060
+ file.close
2061
+ file.unlink
2062
+ end
2063
+ end
2064
+ # ------------- end of page_selection --------------------------------#
1739
2065
  ##
1740
2066
  # Editing of the User Dir List.
1741
2067
  # remove current entry from used dirs list, since we may not want some entries being there
1742
2068
  #
1743
2069
  def remove_from_list
1744
- if $selected_files.size > 0
2070
+ unless $selected_files.empty?
1745
2071
  sz = $selected_files.size
1746
2072
  print "Remove #{sz} files from used list (y)?: "
1747
2073
  ch = get_char
1748
- return if ch != "y"
1749
- $used_dirs = $used_dirs - $selected_files
1750
- $visited_files = $visited_files - $selected_files
2074
+ return if ch != 'y'
2075
+
2076
+ arr = $selected_files.map { |path| File.expand_path(path) }
2077
+
2078
+ $used_dirs = $used_dirs - arr
2079
+ $visited_files = $visited_files - arr
1751
2080
  unselect_all
1752
2081
  $modified = true
2082
+ refresh
1753
2083
  return
1754
2084
  end
1755
2085
  print
@@ -1757,7 +2087,8 @@ def remove_from_list
1757
2087
  file = $view[$cursor]
1758
2088
  print "Remove #{file} from used list (y)?: "
1759
2089
  ch = get_char
1760
- return if ch != "y"
2090
+ return if ch != 'y'
2091
+
1761
2092
  file = File.expand_path(file)
1762
2093
  if File.directory? file
1763
2094
  $used_dirs.delete(file)
@@ -1767,6 +2098,7 @@ def remove_from_list
1767
2098
  refresh
1768
2099
  $modified = true
1769
2100
  end
2101
+
1770
2102
  #
1771
2103
  # If there's a short file list, take recently mod and accessed folders and put latest
1772
2104
  # files from there and insert it here. I take both since recent mod can be binaries / object
@@ -1775,15 +2107,16 @@ end
1775
2107
  # include files.
1776
2108
  def enhance_file_list
1777
2109
  return unless $enhanced_mode
2110
+
1778
2111
  # if only one entry and its a dir
1779
2112
  # get its children and maybe the recent mod files a few
1780
2113
 
1781
2114
  if $files.size == 1
1782
2115
  # its a dir, let give the next level at least
1783
- if $files.first[-1] == "/"
2116
+ if $files.first[-1] == '/'
1784
2117
  d = $files.first
1785
2118
  f = `zsh -c 'print -rl -- #{d}*(omM)'`.split("\n")
1786
- if f && f.size > 0
2119
+ if f && !f.empty?
1787
2120
  $files.concat f
1788
2121
  $files.concat get_important_files(d)
1789
2122
  return
@@ -1797,28 +2130,28 @@ def enhance_file_list
1797
2130
  # check if a ruby project dir, although it could be a backup file too,
1798
2131
  # if so , expand lib and maby bin, put a couple recent files
1799
2132
  #
1800
- if $files.index("Gemfile") || $files.grep(/\.gemspec/).size > 0
2133
+ if $files.index('Gemfile') || !$files.grep(/\.gemspec/).empty?
1801
2134
  # usually the lib dir has only one file and one dir
1802
2135
  flg = false
1803
2136
  $files.concat get_important_files(Dir.pwd)
1804
- if $files.index("lib/")
2137
+ if $files.index('lib/')
1805
2138
  f = `zsh -c 'print -rl -- lib/*(om[1,5]M)'`.split("\n")
1806
- if f && f.size() > 0
1807
- insert_into_list("lib/", f)
2139
+ if f && !f.empty?
2140
+ insert_into_list('lib/', f)
1808
2141
  flg = true
1809
2142
  end
1810
2143
  dd = File.basename(Dir.pwd)
1811
2144
  if f.index("lib/#{dd}/")
1812
2145
  f = `zsh -c 'print -rl -- lib/#{dd}/*(om[1,5]M)'`.split("\n")
1813
- if f && f.size() > 0
2146
+ if f && !f.empty?
1814
2147
  insert_into_list("lib/#{dd}/", f)
1815
2148
  flg = true
1816
2149
  end
1817
2150
  end
1818
2151
  end
1819
- if $files.index("bin/")
2152
+ if $files.index('bin/')
1820
2153
  f = `zsh -c 'print -rl -- bin/*(om[1,5]M)'`.split("\n")
1821
- insert_into_list("bin/", f) if f && f.size() > 0
2154
+ insert_into_list('bin/', f) if f && !f.empty?
1822
2155
  flg = true
1823
2156
  end
1824
2157
  return if flg
@@ -1830,15 +2163,11 @@ def enhance_file_list
1830
2163
 
1831
2164
  ## first check accessed else modified will change accessed
1832
2165
  moda = `zsh -c 'print -rn -- *(/oa[1]M)'`
1833
- if moda && moda != ""
2166
+ if moda && moda != ''
1834
2167
  modf = `zsh -c 'print -rn -- #{moda}*(oa[1]M)'`
1835
- if modf && modf != ""
1836
- insert_into_list moda, modf
1837
- end
2168
+ insert_into_list moda, modf if modf && modf != ''
1838
2169
  modm = `zsh -c 'print -rn -- #{moda}*(om[1]M)'`
1839
- if modm && modm != "" && modm != modf
1840
- insert_into_list moda, modm
1841
- end
2170
+ insert_into_list moda, modm if modm && modm != '' && modm != modf
1842
2171
  end
1843
2172
  ## get last modified dir
1844
2173
  modm = `zsh -c 'print -rn -- *(/om[1]M)'`
@@ -1853,38 +2182,38 @@ def enhance_file_list
1853
2182
  # are the same dir, so we need to find the second modified dir
1854
2183
  end
1855
2184
  end
1856
- def insert_into_list dir, file
1857
- #ix = $files.index(dir)
1858
- #raise "something wrong can find #{dir}." unless ix
1859
- #$files.insert ix, *file
2185
+
2186
+ def insert_into_list(_dir, file)
2187
+ # ix = $files.index(dir)
2188
+ # raise "something wrong can find #{dir}." unless ix
2189
+ # $files.insert ix, *file
1860
2190
  # 2013-03-19 - 19:42 adding at end to avoid confusion
1861
- #$files.concat file
2191
+ # $files.concat file
1862
2192
  $files.push *file
1863
2193
  end
1864
- def get_important_files dir
2194
+
2195
+ def get_important_files(dir)
1865
2196
  # checks various lists like visited_files and bookmarks
1866
2197
  # to see if files from this dir or below are in it.
1867
2198
  # More to be used in a dir with few files.
1868
2199
  list = []
1869
2200
  l = dir.size + 1
1870
2201
  $visited_files.each do |e|
1871
- if e.index(dir) == 0
1872
- list << e[l..-1]
1873
- end
2202
+ list << e[l..-1] if e.index(dir) == 0
1874
2203
  end
1875
2204
  # bookmarks have : which needs to be removed
1876
- #list1 = $bookmarks.values.select do |e|
1877
- #e.index(dir) == 0
1878
- #end
1879
- #list.concat list1
1880
- return list
2205
+ # list1 = $bookmarks.values.select do |e|
2206
+ # e.index(dir) == 0
2207
+ # end
2208
+ # list.concat list1
2209
+ list
1881
2210
  end
1882
2211
 
1883
- Signal.trap('EXIT') {
2212
+ Signal.trap('EXIT') do
1884
2213
  reset_terminal
1885
2214
  # system 'tput rmcup'
1886
2215
  exit
1887
- }
2216
+ end
1888
2217
  run
1889
2218
  # 2019-02-20 - added so alt-screen is used
1890
2219
  system 'tput rmcup'