cetus 0.1.34 → 0.1.36

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 443d16e21b148f67cc9f5e946cd30c208849851d3f00d61654f9397608d9efc2
4
- data.tar.gz: e313ebd0039f87472eff95115a56484bb2fa298e2a94783ea52bdeb804fcaeed
3
+ metadata.gz: 273d25acae029a8c12d1e07bd80396c7f6eeb05f6136b112be702a7cebd7a01d
4
+ data.tar.gz: 25891b9fc8105132be8cb4325f23767fc2abf79096b98bcee9c11a41f0ffb612
5
5
  SHA512:
6
- metadata.gz: fc89827c004339856387fa481fd88ae15bf5a0d0eb0ae75fc4a7837ea055adc9f19e96b6ac128897c2655beeaedc0bdbbc72b023155b0dbd1ee9322f0ae818c1
7
- data.tar.gz: b72d9d557dba6c150720362053ba247df1745c018a53c387ef857f63d2b6937931f59668b2fa2b518456a6972353f228cc975e8c760ebecf00f4a07faf1ecd8e
6
+ metadata.gz: 905206ed55286799c28ef2e3c9fee6fc1eedc34730ac4632138c117ce747be62da7ed377c44414ba8499f3cfc2a2b539c4fb2b868522ef9ffc775aa0528b1d43
7
+ data.tar.gz: 53e8235558e298e9f08dbaefd5f65fcde07a821e8052ee630db51bc74e340a56ddae0abc430028dfda702700c659686ad449c342250d4cc9a26ef5387eadb98c
data/bin/cetus CHANGED
@@ -6,7 +6,7 @@
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-04-10 11:18
9
+ # Last update: 2019-04-14 19:11
10
10
  # --------------------------------------------------------------------------- #
11
11
  # cetus.rb Copyright (C) 2012-2019 rahul kumar
12
12
  # == CHANGELOG
@@ -16,13 +16,8 @@
16
16
  # 2019-03-04 - change clear to go to 0,0 and clear down to reduce pollution
17
17
  # 2019-03-04 - changed quit to q (earlier Q)
18
18
  # 2019-03-04 - first dirs then files
19
- # 2019-03-10 - changing selected_files to have fullpath
20
19
  # 2019-03-22 - refactoring the code, esp run()
21
20
  # == TODO
22
- # a method is called from. a menu or direct from key. e.g help
23
- # To dirs add GEMHOME RUBYLIB PYTHONILB or PYTHONPATH,
24
- # Make rubygem aware : gemspec or Gemfile the expand lib and bin
25
- # fpath if existing
26
21
 
27
22
  require 'readline'
28
23
  require 'io/wait'
@@ -39,11 +34,10 @@ require 'logger'
39
34
  # alias c=~/bin/cetus.rb
40
35
  # c
41
36
 
42
- VERSION = '0.1.34.0'.freeze
37
+ VERSION = '0.1.36.0'.freeze
43
38
  CONFIG_PATH = ENV['XDG_CONFIG_HOME'] || File.join(ENV['HOME'], '.config')
44
39
  CONFIG_FILE = "#{CONFIG_PATH}/cetus/conf.yml".freeze
45
40
 
46
- # $bindings = {}
47
41
  $bindings = {
48
42
  '`' => 'main_menu',
49
43
  '=' => 'toggle_menu',
@@ -52,7 +46,7 @@ $bindings = {
52
46
  'ENTER' => 'select_current',
53
47
  'C-p' => 'page_current',
54
48
  'C-e' => 'edit_current',
55
- 'C-o' => 'edit_current',
49
+ 'C-o' => 'open_current',
56
50
  'C-s' => 'toggle_select',
57
51
  'C-r' => 'reduce',
58
52
  'C-g' => 'debug_vars',
@@ -83,7 +77,8 @@ $bindings = {
83
77
  'C-i' => 'views',
84
78
  # '?' => 'dirtree',
85
79
  'D' => 'delete_file',
86
- 'M' => 'file_actions most',
80
+ # 'M' => 'file_actions most',
81
+ 'M' => 'move_instant',
87
82
  'q' => 'quit_command', # was Q now q 2019-03-04 -
88
83
  # "RIGHT" => "column_next",
89
84
  'RIGHT' => 'select_current', # changed 2018-03-12 - for faster navigation
@@ -305,24 +300,31 @@ $stact = 0 # used when panning a folder to next column
305
300
  $editor_mode = false # changed 2018-03-12 - so we start in pager mode
306
301
  $enhanced_mode = true
307
302
  $visual_block_start = nil
308
- $pager_command = {
303
+ PAGER_COMMAND = {
309
304
  text: 'most',
310
305
  image: 'open',
311
306
  zip: 'tar ztvf %% | most',
312
307
  unknown: 'open'
313
308
  }
314
309
  $dir_position = {}
315
- $movement = $old_cursor = nil # cursor movement has happened only, don't repaint
310
+ @movement = @old_cursor = nil # cursor movement has happened only, don't repaint
316
311
  $selection_mode = 1 # single select
312
+ ## FLAGS
317
313
  @group_dirs = true
318
314
  # truncate long filenames from :right, :left or :center.
319
315
  @truncate_from = :center
316
+ @filename_status_line = true
317
+ @display_file_stats = true
318
+ @selected_files_fullpath_flag = false
319
+ @selected_files_escaped_flag = false
320
+ @keys_to_clear = nil
320
321
 
321
322
  ## ----------------- CONSTANTS ----------------- ##
322
323
  GMARK = '*'.freeze
323
324
  CURMARK = '>'.freeze
324
325
  MSCROLL = 10
325
326
  SPACE = ' '.freeze
327
+ SEPARATOR = '-------'.freeze
326
328
  CLEAR = "\e[0m".freeze
327
329
  BOLD = "\e[1m".freeze
328
330
  BOLD_OFF = "\e[22m".freeze
@@ -355,6 +357,7 @@ $ls_color = {
355
357
  '.zip' => MAGENTA,
356
358
  '.torrent' => GREEN,
357
359
  '.srt' => GREEN,
360
+ '.part' => "\e[40;31;01m",
358
361
  '.sh' => CYAN
359
362
  }
360
363
  # This hash contains colors for file patterns, updated from LS_COLORS
@@ -387,7 +390,8 @@ $history = []
387
390
  ## sta is where view (viewport) begins, cursor is current row/file
388
391
  $sta = $cursor = 0
389
392
  $visual_mode = false
390
- $status_color = 4 # status line, can be 2 3 4 5 6
393
+ @status_color = 4 # status line, can be 2 3 4 5 6
394
+ @status_color_right = 8 # status line right part
391
395
 
392
396
  # Menubar on top of screen
393
397
  @help = "#{BOLD}?#{BOLD_OFF} Help #{BOLD}`#{BOLD_OFF} Menu #{BOLD}!#{BOLD_OFF} Execute #{BOLD}=#{BOLD_OFF} Toggle #{BOLD}C-x#{BOLD_OFF} File Actions #{BOLD}q#{BOLD_OFF} Quit "
@@ -511,14 +515,25 @@ def print_title
511
515
 
512
516
  # print 1 of n files, sort order, filter etc details
513
517
  $title ||= Dir.pwd.sub(ENV['HOME'], '~')
518
+
519
+ # Add bookmark next to name of dir, if exists
520
+ bm = $bookmarks.key(Dir.pwd)
521
+ bm = " ('#{bm})" if bm
522
+
514
523
  fin = $sta + $viewport.size
515
524
  fl = $view.size
516
- if fl.zero?
517
- t = "#{$title} No files."
518
- else
519
- t = "#{$title} #{$sta + 1} to #{fin} of #{fl} #{$sorto} F:#{$filterstr}"
525
+
526
+ # 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
530
+
531
+ ix = $view.index SEPARATOR
532
+ fl = ix if ix
520
533
  end
521
534
 
535
+ t = fl.zero? ? "#{$title}#{bm} No files." : "#{$title}#{bm} #{$sta + 1} to #{fin} of #{fl} #{$sorto} F:#{$filterstr}"
536
+
522
537
  # don't exceed columns while printing
523
538
  t = t[t.size - $gcols..-1] if t.size >= $gcols
524
539
 
@@ -530,6 +545,7 @@ end
530
545
  # TODO: clean this up and simplify it
531
546
  # NOTE: earlier this was called on every key (up-arow down arrow, now only
532
547
  # called when page changes, so we only put directory name)
548
+ # NOTE: called only from draw_directory.
533
549
  def status_line
534
550
  # prompt
535
551
  v_mm = $mode ? "[#{$mode}] " : ''
@@ -538,14 +554,15 @@ def status_line
538
554
 
539
555
  clear_last_line
540
556
 
541
- # Print the filename at the right side of the status_line
557
+ # Print the filename at the right side of the status line
542
558
  # sometimes due to search, there is no file
543
559
  if cf
544
560
  if @debug_flag
545
561
  # XXX this will not work on file basis FIXME
546
562
  print_debug_info cf
547
563
  else
548
- print_on_right "#{Dir.pwd}"
564
+ # print_on_right "#{Dir.pwd}"
565
+ print_filename_status_line if @filename_status_line
549
566
  end
550
567
  end
551
568
  # move to beginning of line, reset text mode after printing
@@ -560,7 +577,7 @@ def status_line
560
577
  # print search pattern if any
561
578
  # print message if any
562
579
  # print "\r#{v_mm}#{patt}#{$message}\e[m"
563
- print "\r\e[33;4#{$status_color}m#{v_mm}#{patt}#{$message}\e[m"
580
+ print "\r\e[33;4#{@status_color}m#{v_mm}#{patt}#{$message}\e[m"
564
581
 
565
582
  end
566
583
 
@@ -568,6 +585,25 @@ def print_debug_info cf=current_file()
568
585
  print_on_right "len:#{cf.length}/#{$temp_wid} = #{$sta},#{$cursor},#{$stact},#{$viewport.size},#{$grows} | #{cf}"
569
586
  end
570
587
 
588
+ def print_filename_status_line cf=current_file
589
+ if @display_file_stats
590
+ ff = if cf[0] == '~'
591
+ File.expand_path(cf)
592
+ else
593
+ cf
594
+ end
595
+
596
+ mtime = if !File.exist? ff
597
+ # take care of dead links lstat TODO
598
+ date_format(File.lstat(ff).mtime) if File.symlink?(ff)
599
+ else
600
+ date_format(File.stat(ff).mtime)
601
+ end
602
+ end
603
+ # print size and mtime only if more data requested.
604
+ print_on_right "| #{mtime} | #{cf}".rjust(40)
605
+ end
606
+
571
607
  # should we do a read of the dir
572
608
  def rescan?
573
609
  $rescan_required
@@ -640,26 +676,27 @@ end
640
676
  # clear the earlier position when we move.
641
677
  # Currently not using until I can implement chgat here.
642
678
  def clear_cursor
643
- return unless $old_cursor
679
+ return unless @old_cursor
644
680
 
645
- hint = get_shortcut($old_cursor)
646
- if $old_cursor < $grows
681
+ hint = get_shortcut(@old_cursor)
682
+ if @old_cursor < $grows
647
683
  # FIXME: faster way of getting here ? see fff
648
- # system "tput cup #{$old_cursor + 2} 0"
649
- tput_cup $old_cursor, 0
684
+ # system "tput cup #{@old_cursor + 2} 0"
685
+ tput_cup @old_cursor, 0
650
686
  # print "#{CURSOR_COLOR}#{hint} >#{CLEAR}"
651
687
  print "#{hint} "
652
688
  return
653
689
  end
654
690
  wid = get_width $viewport.size, $grows
655
- rows = $old_cursor % $grows
656
- cols = ($old_cursor / $grows) * wid
691
+ rows = @old_cursor % $grows
692
+ cols = (@old_cursor / $grows) * wid
657
693
  # system "tput cup #{rows + 2} #{cols}"
658
694
  tput_cup rows, cols
659
695
  # print "#{CURSOR_COLOR}#{hint} >#{CLEAR}"
660
696
  print "#{hint} "
661
697
  end
662
698
 
699
+ # place cursor on row and col taking first two rows into account
663
700
  def tput_cup row, col
664
701
  # we add 3: 2 is for the help and directory line. 1 is since tput is 1 based
665
702
  print "\e[#{row + 3};#{col + 1}H"
@@ -669,6 +706,8 @@ def redraw_required(flag=true) $redraw_required = flag; end
669
706
 
670
707
  def resolve_key key
671
708
  ret = true
709
+ clear_message
710
+
672
711
  if key.match?(/^[a-pr-zZ]$/)
673
712
  # hint mode
674
713
  ret = select_hint $viewport, key
@@ -852,7 +891,7 @@ def truncate_formatted_filename f, unformatted_len, wid
852
891
  # hintsize = sindex - 1
853
892
  # end
854
893
  # f[0..sindex + 1] + '<' + f[-wid + hintsize..-1] + ' '
855
- @log.debug "XXX #{excess}: #{f} / #{wid}"
894
+ # @log.debug "XXX #{excess}: #{f} / #{wid}"
856
895
  # 4 = 2 for literals, 2 to get ahead of sindex+1
857
896
  f[0..sindex + 1] + '<' + f[sindex + 4 + excess..-1] + ' '
858
897
  # in some cases 29/32 we are actually overlapping 2 parts above
@@ -898,10 +937,18 @@ def format_array(ary)
898
937
  ctr = 0
899
938
  ary.each do |f|
900
939
  ## ctr refers to the index in the column
901
- ind = get_shortcut(ix)
902
940
  mark = SPACE
903
- mark = '+' if visited? f
904
941
  cur = SPACE
942
+ ind = get_shortcut(ix)
943
+
944
+
945
+ # Handle separator before enhanced file list.
946
+ # We do lost a shortcut
947
+ if f == SEPARATOR
948
+ ind = cur = mark = '-'
949
+ end
950
+
951
+ mark = '+' if visited? f
905
952
  # cur = CURMARK if ix + $sta == $cursor # 2019-03-29 - removed reduced calls
906
953
  # NOTE seems like f and ary[ix] are the same
907
954
  mark = GMARK if selected?(ary[ix])
@@ -952,6 +999,8 @@ end
952
999
 
953
1000
  # determine color for a filename based on extension, then pattern, then filetype
954
1001
  def color_for fname
1002
+ return nil if fname == SEPARATOR
1003
+
955
1004
  extension = File.extname(fname)
956
1005
  color = $ls_color[extension]
957
1006
  return color if color
@@ -1050,20 +1099,20 @@ end
1050
1099
 
1051
1100
  ## select file based on key pressed
1052
1101
  def select_hint view, key
1053
- # a to y is direct
1054
- # if x or z take a key IF there are those many
1055
- #
1102
+
1056
1103
  ix = get_index(key, view.size)
1057
1104
  return nil unless ix
1058
1105
 
1059
1106
  f = view[ix]
1060
1107
  return nil unless f
1108
+ return nil if f == SEPARATOR
1061
1109
 
1062
1110
  $cursor = $sta + ix
1063
1111
 
1064
1112
  if $mode == 'SEL'
1065
1113
  toggle_select f
1066
1114
  elsif $mode == 'COM'
1115
+ # not being called any longer I think
1067
1116
  run_command f
1068
1117
  else
1069
1118
  open_file f
@@ -1103,19 +1152,8 @@ def open_file(f)
1103
1152
  change_dir f #, nextpos
1104
1153
  elsif File.readable? f
1105
1154
  # TODO: looks complex pls simplify !! XXX
1106
- $default_command ||= '$PAGER'
1107
- if !$editor_mode
1108
- ft = filetype f
1109
- if ft
1110
- comm = $pager_command[ft]
1111
- else
1112
- comm = $pager_command[File.extname(f)]
1113
- comm ||= $pager_command['unknown']
1114
- end
1115
- else
1116
- comm = $default_command
1117
- end
1118
- comm ||= $default_command
1155
+ comm = opener_for f
1156
+ # '%%' will be substituted with the filename. See zip
1119
1157
  comm = if comm.index('%%')
1120
1158
  comm.gsub('%%', Shellwords.escape(f))
1121
1159
  else
@@ -1125,6 +1163,7 @@ def open_file(f)
1125
1163
  reset_terminal
1126
1164
  system(comm.to_s)
1127
1165
  setup_terminal
1166
+ # XXX maybe use absolute_path instead of hardcoding
1128
1167
  f = Dir.pwd + '/' + f if f[0] != '/'
1129
1168
  $visited_files.insert(0, f)
1130
1169
  push_used_dirs Dir.pwd
@@ -1148,9 +1187,15 @@ def edit_current
1148
1187
  $visited_files.insert(0, current_file)
1149
1188
  end
1150
1189
 
1190
+ def open_current
1191
+ opener = /darwin/ =~ RUBY_PLATFORM ? 'open' : 'xdg-open'
1192
+ run_on_current opener
1193
+ $visited_files.insert(0, current_file)
1194
+ end
1195
+
1151
1196
  # run given command on current file
1152
1197
  def run_on_current(command)
1153
- f = $view[$cursor]
1198
+ f = current_file
1154
1199
  return unless f
1155
1200
  f = File.expand_path(f)
1156
1201
  return unless File.readable?(f)
@@ -1163,40 +1208,39 @@ def run_on_current(command)
1163
1208
  setup_terminal
1164
1209
  end
1165
1210
 
1166
- ## run command on given file/s
1167
- # Accepts command from user
1211
+ ## run system command on given file/s
1212
+ # Accepts external command from user
1168
1213
  # After putting readline in place of gets, pressing a C-c has a delayed effect.
1169
1214
  # It goes into exception block after executing other commands and still
1170
1215
  # does not do the return !
1171
1216
  def run_command(f)
1172
- files = nil
1173
- case f
1174
- when Array
1175
- # escape the contents and create a string
1176
- files = Shellwords.join(f)
1177
- when String
1178
- files = Shellwords.escape(f)
1179
- end
1217
+ files = Shellwords.join(f)
1218
+ count = f.count
1219
+ text = if count > 1
1220
+ "#{count} files"
1221
+ else
1222
+ files[0..40]
1223
+ end
1180
1224
  begin
1181
- # Readline::HISTORY.push(*values)
1182
- command = readline "Run a command on #{files}: "
1183
- # command = gets().chomp
1225
+ command = readline "Run a command on #{text}: "
1184
1226
  return if command.empty?
1185
1227
 
1186
1228
  # command2 = gets().chomp
1187
1229
  command2 = readline 'Second part of command: '
1188
- puts "#{command} #{files} #{command2}"
1230
+ pause "#{command} #{files} #{command2}"
1231
+
1232
+ reset_terminal
1189
1233
  system "#{command} #{files} #{command2}"
1190
1234
  setup_terminal
1191
1235
  rescue StandardError => ex
1192
- perror "Canceled command, (#{ex}) press a key"
1236
+ perror "Canceled or failed command, (#{ex}) press a key."
1237
+ @log.warn "RUNCOMMAND: #{ex.to_s}"
1193
1238
  return
1194
1239
  end
1195
1240
 
1196
1241
  refresh
1197
- puts 'Press a key ...'
1198
1242
  push_used_dirs Dir.pwd
1199
- get_char
1243
+ # should we clear selection also ?
1200
1244
  end
1201
1245
 
1202
1246
  ## cd to a dir.
@@ -1243,6 +1287,7 @@ def escape
1243
1287
  end
1244
1288
 
1245
1289
  ## refresh listing after some change like option change, or toggle
1290
+ # Should we check selected_files array also for deleted/renamed files
1246
1291
  def refresh
1247
1292
  $patt = nil
1248
1293
  $title = nil
@@ -1263,7 +1308,7 @@ def unselect_all
1263
1308
  $visual_mode = nil
1264
1309
  end
1265
1310
 
1266
- ## select all files
1311
+ ## select all entries (files and directories)
1267
1312
  def select_all
1268
1313
  dir = Dir.pwd
1269
1314
  $selected_files = $view.map { |file| File.join(dir, file) }
@@ -1340,7 +1385,7 @@ def goto_parent_dir
1340
1385
  end
1341
1386
 
1342
1387
  def goto_home_dir
1343
- change_dir '~'
1388
+ change_dir ENV['HOME']
1344
1389
  end
1345
1390
 
1346
1391
 
@@ -1374,14 +1419,14 @@ def next_page
1374
1419
  $cursor += $pagesize
1375
1420
  $sta = $cursor if $sta > $cursor
1376
1421
  $stact = 0
1377
- $old_cursor = nil
1422
+ @old_cursor = nil
1378
1423
  redraw_required
1379
1424
  end
1380
1425
 
1381
1426
  def prev_page
1382
1427
  $sta -= $pagesize
1383
1428
  $cursor -= $pagesize
1384
- $old_cursor = nil
1429
+ @old_cursor = nil
1385
1430
  # FIXME: check cursor sanity and if not changed then no redraw
1386
1431
  redraw_required
1387
1432
  end
@@ -1447,7 +1492,9 @@ def debug_vars
1447
1492
  file.puts "pagesize #{$pagesize}"
1448
1493
  file.puts "view.size #{$view.size}"
1449
1494
  file.puts "grows #{$grows}"
1450
- file.puts "file #{current_file}"
1495
+ file.puts "File: #{current_file}"
1496
+ file.puts
1497
+ file.puts "Opener: #{opener_for(current_file)}"
1451
1498
  file.puts
1452
1499
  file.puts `file "#{current_file}"`
1453
1500
  file.puts
@@ -1457,7 +1504,7 @@ def debug_vars
1457
1504
  end
1458
1505
 
1459
1506
  def view_bookmarks
1460
- puts
1507
+ clear_last_line
1461
1508
  puts 'Bookmarks: '
1462
1509
  $bookmarks.each_pair { |k, v| puts "#{k.ljust(7)} => #{v}" }
1463
1510
  puts
@@ -1515,7 +1562,7 @@ end
1515
1562
  def menu title, h
1516
1563
  return unless h
1517
1564
 
1518
- last_line # 2019-03-30 - required since cursor is not longer at bottom
1565
+ clear_last_line # 2019-03-30 - required since cursor is not longer at bottom
1519
1566
  pbold title.to_s
1520
1567
  # h.each_pair { |k, v| puts " #{k}: #{v}" }
1521
1568
  # 2019-03-09 - trying out using `column` to print in cols
@@ -1993,6 +2040,8 @@ def subcommand
1993
2040
  $writing = true if $modified
1994
2041
  elsif command == 'e'
1995
2042
  edit_current
2043
+ elsif command == 'o'
2044
+ open_current
1996
2045
  elsif command == 'h' or command == 'help' or command == '?'
1997
2046
  print_help
1998
2047
  elsif command == 'p'
@@ -2105,7 +2154,7 @@ end
2105
2154
  # but prints on next line.FIXME 2019-03-24 - 00:08
2106
2155
  def perror text
2107
2156
  clear_last_line
2108
- print "\r#{RED}#{text}. Press a key.#{CLEAR}"
2157
+ puts "\r#{RED}#{text}. Press a key.#{CLEAR}"
2109
2158
  get_char
2110
2159
  end
2111
2160
 
@@ -2155,7 +2204,7 @@ def get_index(key, vsz = 999)
2155
2204
  zch = get_char
2156
2205
  print zch
2157
2206
  i = convert_key_to_index("#{key}#{zch}")
2158
- @log.debug "convert returned #{i} for #{key}#{zch}"
2207
+ # @log.debug "convert returned #{i} for #{key}#{zch}"
2159
2208
  return i if i
2160
2209
  # i = $IDX.index
2161
2210
  # return i + $stact if i
@@ -2172,9 +2221,14 @@ def convert_key_to_index key
2172
2221
  if i
2173
2222
  # @log.debug "get_index with #{key}: #{i}. #{$stact}. #{$viewport.size}"
2174
2223
  vps = $viewport.size
2175
- return nil if $stact == 0 && i + $stact >= vps
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
2176
2230
  # return nil if $stact > 0 && i + $stact >= vps && i + $stact - vps >= $stact
2177
- return nil if $stact > 0 && i + $stact >= vps && i - vps >= 0
2231
+ return retnil if $stact > 0 && i + $stact >= vps && i - vps >= 0
2178
2232
 
2179
2233
  if i + $stact >= vps
2180
2234
  # panning case, hints are recycled
@@ -2191,6 +2245,71 @@ def delete_file
2191
2245
  file_actions :delete
2192
2246
  end
2193
2247
 
2248
+ def move_instant
2249
+ # FIXME: cannot be in target directory and do auto update
2250
+
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?
2255
+
2256
+ # take default value if user presses Enter
2257
+ target = @move_target if target == ''
2258
+ return unless target
2259
+
2260
+ # current dir if dot pressed FIXME you cannot move to current dir !!!
2261
+ target = Dir.pwd if target == '.'
2262
+ 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
2279
+ return
2280
+ end
2281
+
2282
+ # files selected. Use earlier target if there, else ask
2283
+ target = @move_target
2284
+ if target.nil? || target == ''
2285
+ target = readline "Enter directory for moving files #{@move_target}:"
2286
+ return unless target
2287
+ end
2288
+ target = File.expand_path(target)
2289
+ unless File.directory? target
2290
+ perror "#{target} not a directory."
2291
+ return
2292
+ end
2293
+
2294
+ files = $selected_files
2295
+ # todo: shellwords
2296
+ ccount = 0
2297
+ files.each do |f|
2298
+ FileUtils.mv f, target
2299
+ @log.info "2.#{f} moved to #{target}."
2300
+ ccount += 1
2301
+ rescue StandardError => exc
2302
+ @log.warn "Case 2:"
2303
+ @log.warn "Target is #{target}, file was #{f}"
2304
+ @log.warn exc.to_s
2305
+ perror exc.to_s
2306
+ end
2307
+ @move_target = target
2308
+ clean_selected_files
2309
+ message "#{ccount} files moved to #{target}."
2310
+ refresh
2311
+ end
2312
+
2194
2313
  ## generic external command program
2195
2314
  # prompt is the user friendly text of command such as list for ls, or extract for dtrx, page for less
2196
2315
  # pauseyn is whether to pause after command as in file or ls
@@ -2220,7 +2339,7 @@ end
2220
2339
 
2221
2340
  ## prompt user for file shortcut and return file or nil
2222
2341
  #
2223
- def ask_hint(deflt = nil)
2342
+ def ask_hint deflt=nil
2224
2343
  f = nil
2225
2344
  key = get_char
2226
2345
  return deflt if key == 'ENTER'
@@ -2279,43 +2398,53 @@ end
2279
2398
  # 2019-03-08 - TODO when a file name changes or moves it must be removed
2280
2399
  # from selection
2281
2400
  def file_actions(action = nil)
2282
- # only add dtrx for gz
2283
- h = { d: :delete, D: '/bin/rm', m: :move, r: :rename, v: ENV['EDITOR'] || :vim,
2284
- c: :copy, C: :chdir, W: :remspace, e: :execute, s: :page_stat_for_file,
2285
- l: :less, p: :most, f: :file, o: :open, x: :dtrx, z: :zip }
2286
- # acttext = h[action.to_sym] || action
2287
- acttext = action || ''
2288
- file = nil
2289
-
2290
- sct = $selected_files.size
2291
- if sct > 0
2292
- text = "#{sct} files"
2293
- file = $selected_files
2294
- else
2295
- # 2019-03-07 - trying out direct deletes
2296
- # why were we aksing to select a file when user is on a file
2297
- # print "[#{acttext}] Choose a file [#{$view[$cursor]}]: "
2298
- # file = ask_hint $view[$cursor]
2299
- file = $view[$cursor]
2300
- unless file
2301
- file = ask_hint $view[$cursor]
2401
+ h = { d: :delete, D: '/bin/rm', m: :move, v: ENV['EDITOR'] || :vim,
2402
+ c: :copy, e: :execute,
2403
+ l: :less, p: :most, o: :open }
2404
+
2405
+ rbfiles = current_or_selected_files # use with ruby FileUtils
2406
+ return if rbfiles.nil? || rbfiles.empty?
2407
+
2408
+ count = rbfiles.count
2409
+ first = rbfiles.first
2410
+ if count == 1
2411
+ h[:r] = :rename
2412
+
2413
+ # add chdir if dir of file under cursor is not same as current dir
2414
+ h[:C] = :chdir if File.dirname(File.expand_path(first)) != Dir.pwd
2415
+
2416
+ h[:s] = :page_stat_for_file
2417
+ h[:f] = :file
2418
+ if filetype(first) == :zip
2419
+ h[:x] = :dtrx
2420
+ h[:u] = :unzip
2302
2421
  end
2303
- return unless file
2422
+ h[:g] = if File.extname(first) == '.gz'
2423
+ :gunzip
2424
+ else
2425
+ :gzip
2426
+ end
2304
2427
 
2305
- text = file
2306
2428
  end
2307
- # 2019-03-07 - NOTE at this point file can be one or more files.
2308
- # 2019-03-07 - text can be a file or count of files, so unreliable !!! FIXME
2429
+ h[:M] = :set_move_target if File.directory?(current_file)
2430
+ h[:z] = :zip unless filetype(first) == :zip
2309
2431
 
2310
- case file
2311
- when Array
2312
- # escape the contents and create a string
2313
- files = Shellwords.join(file)
2314
- when String
2315
- files = Shellwords.escape(file)
2316
- end
2432
+ # if first file has spaces then add remspace method
2433
+ # TODO: put this in scripts
2434
+ # take care that directories can have spaces
2435
+ h[:W] = :remspace if File.basename(first).index ' '
2436
+
2437
+ text = count == 1 ? File.basename(first) : "#{count} files"
2438
+ shfiles = Shellwords.join(rbfiles)
2439
+
2440
+ # --------------------------------------------------------------
2441
+ # Use 'text' for display
2442
+ # Use 'shfiles' for system actions, these are escaped
2443
+ # Use 'rbfiles' for looping and ruby FileUtils, system commands can bork on unescaped names
2444
+ # Use 'count' for how many files, in case of single file operation.
2445
+ # --------------------------------------------------------------
2317
2446
 
2318
- key = nil
2447
+ # if no action passed, then ask for action
2319
2448
  if action
2320
2449
  menu_text = action
2321
2450
  else
@@ -2330,7 +2459,7 @@ def file_actions(action = nil)
2330
2459
 
2331
2460
  when :delete
2332
2461
  delcommand = 'rmtrash'
2333
- last_line
2462
+ clear_last_line
2334
2463
  print "#{delcommand} #{text} ? [yn?]: "
2335
2464
  key = get_char
2336
2465
  view_selected_files if key == '?'
@@ -2338,119 +2467,176 @@ def file_actions(action = nil)
2338
2467
 
2339
2468
  clear_last_line
2340
2469
  print "\r deleting ..."
2341
- system "#{delcommand} #{files}"
2470
+ system "#{delcommand} #{shfiles}"
2471
+ message "Deleted #{text}."
2342
2472
  refresh
2343
2473
 
2344
2474
  when :move
2345
- # 2019-03-07 - NOTE this will only work with single file selection
2346
- # target = gets().chomp
2347
- # target = Readline.readline('>', true)
2348
- target = readline "Move #{text} to : "
2475
+ # multiple files can only be moved to a directory
2476
+ default = @move_target.nil? ? '.' : @move_target
2477
+ target = readline "Move #{text} to (#{default}): "
2349
2478
  return unless target
2350
2479
 
2351
- target = '.' if target == ''
2352
- # 2019-03-07 - NOTE cannot use text if multiple files
2353
- # text = File.expand_path(text)
2480
+ target = default if target == ''
2354
2481
  target = File.expand_path(target)
2355
2482
  return if target == ''
2356
2483
 
2357
- if File.directory? target
2358
- begin
2359
- FileUtils.mv file, target
2360
- message "Moved #{text} to #{target}"
2361
- rescue StandardError => exc
2362
- perror exc.to_s
2363
- end
2364
- # 2019-03-08 - TODO if success remove from selection
2365
- refresh
2366
- else
2367
- perror 'Target not a dir'
2484
+ if count > 1 && !File.directory?(target)
2485
+ perror 'Move target must be a directory for multiple files.'
2486
+ return
2368
2487
  end
2369
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
2504
+
2370
2505
  when :copy
2371
- # Target must be directory
2372
- target = readline "Copy #{text} to : "
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}): "
2373
2511
  return unless target # C-c
2374
2512
 
2375
- target = '.' if target == ''
2513
+ target = default if target == ''
2376
2514
  target = File.expand_path(target)
2377
2515
  return if target == ''
2378
2516
 
2379
- if File.directory? target
2380
- begin
2381
- FileUtils.cp file, target
2382
- message "Copied #{text} to #{target}"
2383
- rescue StandardError => exc
2384
- perror exc.to_s
2385
- end
2386
- refresh
2387
- else
2388
- perror 'Copy target must be a dir'
2517
+ if count > 1 && !File.directory?(target)
2518
+ perror 'Copy target must be a directory for multiple files.'
2519
+ return
2389
2520
  end
2390
2521
 
2522
+ if count == 1 && !File.directory?(target) && File.exist?(target)
2523
+ perror "Target #{target} exists."
2524
+ return
2525
+ end
2526
+
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
2534
+
2391
2535
  when :chdir
2392
- change_dir File.dirname(text)
2536
+ # will only work if one selected. Check this out
2537
+ # This works if you have searched for files and got a list
2538
+ # with different paths.
2539
+ # 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
2543
+
2544
+ when :set_move_target
2545
+ set_move_target current_file
2393
2546
 
2394
2547
  when :zip
2395
- # target = gets().chomp
2548
+
2396
2549
  target = readline 'Archive name: '
2397
2550
  return unless target
2398
2551
  return if target == ''
2399
2552
 
2400
- # don't want a blank space or something screwing up
2401
- if target && target.size > 3
2402
- if File.exist? target
2403
- perror "Target (#{target}) exists"
2404
- else
2405
- system "tar zcvf #{target} #{files}"
2406
- setup_terminal
2407
- refresh
2408
- end
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
2409
2560
  end
2410
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
+
2411
2577
  when :rename
2412
- # 2019-03-07 NOTE works for single file FIXME
2413
- # 2019-03-07 - TODO for n files replace pattern with string
2578
+ if count > 1
2579
+ perror 'Select only one file for rename.'
2580
+ return
2581
+ end
2582
+
2414
2583
  target = readline "Rename #{text} to : "
2415
- return if target == ''
2584
+ return if target == '' || target == '.' || target == '..'
2416
2585
 
2417
- text = File.expand_path(text)
2418
- target = File.basename(text) if target == '.'
2586
+ # file = File.expand_path(files)
2587
+ # target = File.basename(file) if target == '.'
2419
2588
  if File.exist? target
2420
- perror "Target (#{target}) exists"
2421
- else
2422
- FileUtils.mv text, target
2423
- refresh
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
2424
2600
  end
2601
+ refresh
2602
+
2425
2603
  when :most, :less, :vim
2426
- system "#{menu_text} #{files}"
2604
+
2605
+ system "#{menu_text} #{shfiles}"
2427
2606
  setup_terminal
2428
2607
  # should we remove from selection ?
2429
2608
 
2430
2609
  when :remspace
2431
- # 2019-03-08 - 00:07 added replace space with underscore in filename
2432
- print "Remove spaces from #{file}"
2433
- pause
2434
- farray = nil
2435
-
2436
- # stupidly using one variable for scalar and array DUH !
2437
- case file
2438
- when String
2439
- farray = [file]
2440
- when Array
2441
- farray = file
2442
- end
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}."
2443
2616
 
2444
- farray.each do |f|
2445
- if f.index ' '
2446
- nname = f.tr(' ', '_')
2447
- FileUtils.mv f, nname unless File.exist? nname
2448
- # if success then remove from selection
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
2449
2632
  end
2450
2633
  end
2634
+ message "Renamed #{ccount} files."
2451
2635
  refresh
2636
+
2452
2637
  when :execute
2453
2638
  execute
2639
+
2454
2640
  when :page_stat_for_file
2455
2641
  1
2456
2642
  # already been executed by menu
@@ -2458,21 +2644,38 @@ def file_actions(action = nil)
2458
2644
  else
2459
2645
  return unless menu_text
2460
2646
 
2461
- @log.debug "#{menu_text} #{files}"
2462
- last_line
2463
- pause "#{menu_text} #{files}"
2464
- system "#{menu_text} #{files}"
2647
+ clear_last_line
2648
+ pause "#{menu_text} #{shfiles} "
2649
+ system "#{menu_text} #{shfiles}"
2650
+ pause # putting this back 2019-04-13 - file doesn't show anything
2651
+ message "Ran #{menu_text}."
2465
2652
  setup_terminal
2466
2653
  refresh
2467
2654
  end
2468
2655
 
2469
- # remove non-existent files from select list due to move or delete
2470
- # or rename or whatever
2471
- if sct > 0
2472
- $selected_files.select! { |x| x = File.expand_path(x); File.exist?(x) }
2473
- end
2656
+ return if count == 0
2657
+
2658
+ clean_selected_files
2659
+
2660
+ end
2661
+
2662
+ # remove non-existent files from select list due to move or delete
2663
+ # or rename or whatever
2664
+ def clean_selected_files
2665
+ $selected_files.select! { |x| x = File.expand_path(x); File.exist?(x) }
2666
+ end
2667
+
2668
+ # set the default target for further moves
2669
+ # We need to also be able to set it to current dir in which user is. TODO
2670
+ def set_move_target cf=current_file
2671
+ ff = File.expand_path(cf)
2672
+ return unless File.directory? ff
2673
+
2674
+ @move_target = ff
2675
+ message "Move target set to #{cf}."
2474
2676
  end
2475
2677
 
2678
+
2476
2679
  # increase or decrease column
2477
2680
  def columns_incdec(howmany)
2478
2681
  $gviscols += howmany.to_i
@@ -2505,11 +2708,7 @@ end
2505
2708
 
2506
2709
  # execute a command on selected or current file
2507
2710
  def execute
2508
- if $selected_files.empty?
2509
- run_command current_file
2510
- return
2511
- end
2512
- run_command $selected_files
2711
+ run_command current_or_selected_files
2513
2712
  end
2514
2713
 
2515
2714
  def ag
@@ -2593,23 +2792,25 @@ end
2593
2792
 
2594
2793
  ## scroll cursor down
2595
2794
  def cursor_scroll_dn
2795
+ @movement = :down
2596
2796
  moveto(pos + MSCROLL)
2597
2797
  end
2598
2798
 
2599
2799
  def cursor_scroll_up
2800
+ @movement = :up
2600
2801
  moveto(pos - MSCROLL)
2601
2802
  end
2602
2803
 
2603
2804
  # move cursor down a line
2604
2805
  def cursor_dn
2605
- $movement = true
2606
- $old_cursor = $cursor
2806
+ @movement = :down
2807
+ @old_cursor = $cursor
2607
2808
  moveto(pos + 1)
2608
2809
  end
2609
2810
 
2610
2811
  def cursor_up
2611
- $old_cursor = $cursor
2612
- $movement = true
2812
+ @old_cursor = $cursor
2813
+ @movement = :up
2613
2814
  moveto(pos - 1)
2614
2815
  end
2615
2816
 
@@ -2619,11 +2820,19 @@ def pos
2619
2820
  end
2620
2821
 
2621
2822
  # move cursor to given position/line
2622
- def moveto(position)
2823
+ def moveto position
2623
2824
  orig = $cursor
2624
2825
  $cursor = position
2625
2826
  $cursor = [$cursor, $view.size - 1].min
2626
2827
  $cursor = [$cursor, 0].max
2828
+
2829
+ # try to stop it from landing on separator
2830
+ if current_file == SEPARATOR
2831
+ $cursor += 1 if @movement == :down
2832
+ $cursor -= 1 if @movement == :up
2833
+ return
2834
+ end
2835
+
2627
2836
  # 2019-03-18 - adding sta
2628
2837
  # $sta = position - only when page flips and file not visible
2629
2838
  # FIXME not correct, it must stop at end or correctly cycle
@@ -2639,13 +2848,13 @@ def moveto(position)
2639
2848
  # $sta = $cursor
2640
2849
  end
2641
2850
 
2642
- $movement = nil if oldsta != $sta # we need to redraw
2851
+ @movement = nil if oldsta != $sta # we need to redraw
2643
2852
 
2644
2853
  star = [orig, $cursor].min
2645
2854
  fin = [orig, $cursor].max
2646
2855
  return unless $visual_mode
2647
2856
 
2648
- $movement = nil # visual mode needs to redraw page
2857
+ @movement = nil # visual mode needs to redraw page
2649
2858
 
2650
2859
  # PWD has to be there in selction
2651
2860
  if selected? current_file
@@ -2658,6 +2867,7 @@ def moveto(position)
2658
2867
  # $selected_files.concat $view[star..fin]
2659
2868
  add_to_selection $view[star..fin]
2660
2869
  end
2870
+ message "#{$selected_files.count} files selected. "
2661
2871
  # ensure
2662
2872
  # redraw
2663
2873
  end
@@ -2715,9 +2925,10 @@ def visual_mode_toggle
2715
2925
  $visual_block_start = $cursor
2716
2926
  add_to_selection current_file
2717
2927
  end
2718
- message "Visual mode is #{$visual_mode}"
2928
+ message "Visual mode is #{$visual_mode}."
2719
2929
  end
2720
2930
 
2931
+ # Called from Escape key only. Clears selection.
2721
2932
  def visual_block_clear
2722
2933
  if $visual_block_start
2723
2934
  star = [$visual_block_start, $cursor].min
@@ -2726,6 +2937,7 @@ def visual_block_clear
2726
2937
  end
2727
2938
  $visual_block_start = nil
2728
2939
  $visual_mode = nil
2940
+ $mode = nil if $mode == 'VIS'
2729
2941
  end
2730
2942
 
2731
2943
  # ------------- file matching methods --------------------------------#
@@ -2771,27 +2983,44 @@ def goto_line pos
2771
2983
  $cursor = pos
2772
2984
  end
2773
2985
 
2774
- # ---
2775
- def filetype(f)
2986
+ # return filetype of file using `file` external command.
2987
+ # NOTE: Should we send back executable as separate type or allow
2988
+ # it to be nil, so it will be paged.
2989
+ def filetype f
2776
2990
  return nil unless f
2777
2991
 
2778
2992
  f = Shellwords.escape(f)
2779
2993
  s = `file #{f}`
2780
- if s.index 'text'
2781
- return :text
2782
- elsif s.index(/[Zz]ip/)
2783
- return :zip
2784
- elsif s.index('archive')
2785
- return :zip
2786
- elsif s.index 'image'
2787
- return :image
2788
- elsif s.index 'data'
2789
- return :text
2790
- end
2994
+ return :text if s.index 'text'
2995
+ return :zip if s.index(/[Zz]ip/)
2996
+ return :zip if s.index('archive')
2997
+ return :image if s.index 'image'
2998
+ return :text if s.index 'data'
2791
2999
 
2792
3000
  nil
2793
3001
  end
2794
3002
 
3003
+ def opener_for f
3004
+ # by default, default command is nil. Changed in toggle_pager_mode
3005
+ $default_command ||= '$PAGER'
3006
+ # by default mode, is false, changed in toggle_pager_mode
3007
+ # Get filetype, and check for command for type, else extn else unknown
3008
+ if !$editor_mode
3009
+ ft = filetype f
3010
+ comm = PAGER_COMMAND[ft] if ft
3011
+ comm ||= PAGER_COMMAND[File.extname(f)]
3012
+ comm ||= PAGER_COMMAND[:unknown]
3013
+ else
3014
+ # 2019-04-10 - what does this mean, that in editor_mode, editor
3015
+ # opens everything? what of images etc
3016
+ # TODO use editor only for text, otherwise use filetype or another hash
3017
+ # like editor_command
3018
+ comm = $default_command
3019
+ end
3020
+ comm ||= $default_command
3021
+ comm
3022
+ end
3023
+
2795
3024
  # save offset in directory so we can revert to it when we return
2796
3025
  def save_dir_pos
2797
3026
  # the next line meant that it would not save first directory.
@@ -2846,7 +3075,7 @@ def current_file
2846
3075
  end
2847
3076
 
2848
3077
  def current_or_selected_files
2849
- return $selected_files if $selected_files.size > 0
3078
+ return $selected_files if !$selected_files.empty?
2850
3079
 
2851
3080
  return [current_file]
2852
3081
  end
@@ -2874,11 +3103,13 @@ def scripts
2874
3103
 
2875
3104
  # 2019-04-08 - to avoid confusion, we pass name of file under cursor
2876
3105
  # script may ignore this and use selected_files
3106
+ reset_terminal
2877
3107
  system %( #{binding} "#{current_file}" )
2878
3108
 
2879
3109
  # system %(echo "#{cf}" | xargs #{binding})
2880
3110
  pause
2881
- redraw_required
3111
+ setup_terminal
3112
+ refresh
2882
3113
  end
2883
3114
 
2884
3115
  # allow user to select a script that generates filenames which
@@ -2917,17 +3148,32 @@ end
2917
3148
  # script could use old selection again.
2918
3149
  def write_selected_files
2919
3150
 
2920
- fname = File.join(File.dirname(CONFIG_FILE), 'selected_files')
3151
+ require 'pathname'
3152
+ # fname = File.join(File.dirname(CONFIG_FILE), 'selected_files')
3153
+ # 2019-04-10 - changed to ~/tmp otherwise confusion about location
3154
+ fname = File.join('~/tmp/', 'selected_files')
2921
3155
  fname = File.expand_path(fname)
2922
3156
 
2923
3157
  # remove file if no selection
2924
- unless $selected_files
2925
- File.unlink(fname)
3158
+ if $selected_files.empty?
3159
+ File.unlink(fname) if File.exist?(fname)
2926
3160
  return nil
2927
3161
  end
2928
3162
 
3163
+ # TODO : what if user does not want full path e,g zip
3164
+ # TODO: what if unix commands need escaped files ?
3165
+ base = Pathname.new Dir.pwd
2929
3166
  File.open(fname, 'w') do |file|
2930
- $selected_files.each { |row| file.puts row }
3167
+ $selected_files.each do |row|
3168
+
3169
+ # use relative filename. Otherwise things like zip and tar run into issues
3170
+ unless @selected_files_fullpath_flag
3171
+ p = Pathname.new(row)
3172
+ row = p.relative_path_from(base)
3173
+ end
3174
+ row = Shellwords.escape(row) if @selected_files_escaped_flag
3175
+ file.puts row
3176
+ end
2931
3177
  end
2932
3178
 
2933
3179
  return fname
@@ -2979,36 +3225,40 @@ end
2979
3225
  # include files.
2980
3226
  def enhance_file_list
2981
3227
  return unless $enhanced_mode
3228
+ begin
3229
+ actr = $files.size
2982
3230
 
2983
3231
  # zshglob: M = MARK_DIRS with slash
2984
3232
  # zshglob: N = NULL_GLOB no error if no result, this is causing space to split
2985
3233
  # file sometimes for single file.
2986
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
+
2987
3240
  # if only one entry and its a dir
2988
3241
  # get its children and maybe the recent mod files a few
2989
3242
  # FIXME: simplify condition into one
2990
3243
  if $files.size == 1
2991
3244
  # its a dir, let give the next level at least
2992
- if $files.first[-1] == '/'
2993
- d = $files.first
2994
- # zshglob: 'om' = ordered on modification time
2995
- # f1 = `zsh -c 'print -rl -- #{d}*(omM)'`.split("\n")
2996
- f = get_files_by_mtime(d)
3245
+ return unless $files.first[-1] == '/'
2997
3246
 
2998
- # @log.warn "f1:#{f1} != f:#{f} in #{d}" if f1 != f
2999
- # order returned by zsh and ruby are different since the time is the same
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)
3000
3251
 
3001
- # TODO: use ruby this throws errors if not files
3002
- if f && !f.empty?
3003
- # @log.debug "CONCAT: #{f}" if @debug_flag
3004
- $files.concat f
3005
- $files.concat get_important_files(d)
3006
- return
3007
- end
3008
- else
3009
- # just a file, not dirs here
3010
- return
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)
3011
3260
  end
3261
+ return
3012
3262
  end
3013
3263
  #
3014
3264
  # check if a ruby project dir, although it could be a backup file too,
@@ -3114,18 +3364,22 @@ def enhance_file_list
3114
3364
  # If you access the latest mod dir, then come back you get only one, since mod and accessed
3115
3365
  # are the same dir, so we need to find the second modified dir
3116
3366
  end
3367
+ ensure
3368
+ # if any files were added, then add a separator
3369
+ bctr = $files.size
3370
+ if actr < bctr
3371
+ $files.insert actr, SEPARATOR
3372
+ end
3373
+ end
3117
3374
  end
3118
3375
 
3119
3376
  # insert important files to end of $files
3120
3377
  def insert_into_list _dir, file
3121
- # ix = $files.index(dir)
3122
- # raise "something wrong can find #{dir}." unless ix
3123
- # $files.insert ix, *file
3124
- # 2013-03-19 - 19:42 adding at end to avoid confusion
3125
- # $files.concat file
3126
3378
  $files.push(*file)
3127
3379
  end
3128
3380
 
3381
+ # Get visited files and bookmarks that are inside this directory
3382
+ # at a lower level.
3129
3383
  # 2019-03-23 - not exactly clear what is happening XXX
3130
3384
  # this gets a directory (containing '/' at end)
3131
3385
  def get_important_files dir
@@ -3206,15 +3460,13 @@ def gfb dir, func
3206
3460
  # add slash to directories
3207
3461
  sorted_files = add_slash sorted_files
3208
3462
  return sorted_files
3209
- # sorted_files.map do |f|
3210
- # File.directory?(f) ? f + '/' : f
3211
- # end
3212
3463
  end
3213
3464
 
3214
3465
  # set message which will be displayed in status line
3215
3466
  # TODO: maybe we should pad it 2019-04-08 -
3216
3467
  def message mess
3217
3468
  $message = mess
3469
+ @keys_to_clear = 2 if mess
3218
3470
  end
3219
3471
 
3220
3472
  def last_line
@@ -3230,11 +3482,13 @@ def clear_last_line
3230
3482
  # %*s - set blank spaces for entire line
3231
3483
  # \e[m - reset text mode
3232
3484
  # \r - bring to start of line since callers will print.
3233
- print "\e[33;4%sm%*s\e[m\r" % [$status_color || '1', $gcols, " "]
3485
+ print "\e[33;4%sm%*s\e[m\r" % [@status_color || '1', $gcols, ' ']
3234
3486
  end
3235
3487
 
3236
3488
  # print right aligned
3237
- # FIXME: if text longer then width then does not print
3489
+ # XXX does not clear are, if earlier text was longer then that remains.
3490
+ # TODO: 2019-04-10 - this should update a variable, and status_line
3491
+ # should clear and reprint mode, message, patt and right text
3238
3492
  def print_on_right text
3239
3493
  sz = text.size
3240
3494
  col = $gcols - sz - 1
@@ -3246,7 +3500,7 @@ def print_on_right text
3246
3500
  system "tput cup #{$glines} #{col}"
3247
3501
  # tput_cup $glines, $gcols - sz - 1
3248
3502
  # print text
3249
- print "\e[33;4#{$status_color}m#{text}\e[m"
3503
+ print "\e[33;4#{@status_color_right}m#{text}\e[m"
3250
3504
  end
3251
3505
 
3252
3506
  # unused, should set bgcolor before printing
@@ -3256,6 +3510,15 @@ def print_last_line text
3256
3510
  print text
3257
3511
  end
3258
3512
 
3513
+ def clear_message
3514
+ if @keys_to_clear
3515
+ @keys_to_clear -= 1
3516
+ if @keys_to_clear == 0
3517
+ message nil
3518
+ @keys_to_clear = nil
3519
+ end
3520
+ end
3521
+ end
3259
3522
  # main loop which calls all other programs
3260
3523
  def run
3261
3524
 
@@ -3281,22 +3544,25 @@ def run
3281
3544
 
3282
3545
  key = get_char
3283
3546
 
3547
+
3284
3548
  unless resolve_key key # key did not map to file name, so don't redraw
3285
3549
  place_cursor
3286
3550
  next
3287
3551
  end
3288
3552
 
3289
3553
  # only movement has happened within this page, don't redraw
3290
- if $movement && $old_cursor
3554
+ if @movement && @old_cursor
3291
3555
 
3292
3556
  # we may want to print debug info if flag is on
3293
3557
  if @debug_flag
3294
3558
  clear_last_line
3295
3559
  print_debug_info
3560
+ else
3561
+ status_line
3296
3562
  end
3297
3563
 
3298
3564
  place_cursor
3299
- $movement = false
3565
+ @movement = false
3300
3566
  next
3301
3567
  end
3302
3568