Class: Rfd::Controller

Inherits:
Object
  • Object
show all
Includes:
Commands
Defined in:
lib/rfd.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Commands

#-, #/, #C, #D, #F, #G, #H, #K, #L, #M, #O, #S, #a, #c, #click, #ctrl_a, #ctrl_b, #ctrl_f, #ctrl_l, #ctrl_n, #ctrl_p, #ctrl_w, #d, #del, #double_click, #e, #enter, #f, #g, #h, #j, #k, #l, #m, #n, #o, #p, #q, #q!, #r, #s, #space, #t, #u, #v, #w, #y, #z

Constructor Details

#initializeController

:nodoc:



50
51
52
53
54
55
56
57
# File 'lib/rfd.rb', line 50

def initialize
  @main = MainWindow.new
  @header_l = HeaderLeftWindow.new
  @header_r = HeaderRightWindow.new
  @command_line = CommandLineWindow.new
  @debug = DebugWindow.new if ENV['DEBUG']
  @direction, @dir_history, @last_command, @times, @yanked_items = nil, [], nil, nil, nil
end

Instance Attribute Details

#command_lineObject (readonly)

Returns the value of attribute command_line.



47
48
49
# File 'lib/rfd.rb', line 47

def command_line
  @command_line
end

#current_dirObject (readonly)

Returns the value of attribute current_dir.



47
48
49
# File 'lib/rfd.rb', line 47

def current_dir
  @current_dir
end

#current_pageObject (readonly)

Returns the value of attribute current_page.



47
48
49
# File 'lib/rfd.rb', line 47

def current_page
  @current_page
end

#current_rowObject (readonly)

Returns the value of attribute current_row.



47
48
49
# File 'lib/rfd.rb', line 47

def current_row
  @current_row
end

#current_zipObject (readonly)

Returns the value of attribute current_zip.



47
48
49
# File 'lib/rfd.rb', line 47

def current_zip
  @current_zip
end

#displayed_itemsObject (readonly)

Returns the value of attribute displayed_items.



47
48
49
# File 'lib/rfd.rb', line 47

def displayed_items
  @displayed_items
end

#header_lObject (readonly)

Returns the value of attribute header_l.



47
48
49
# File 'lib/rfd.rb', line 47

def header_l
  @header_l
end

#header_rObject (readonly)

Returns the value of attribute header_r.



47
48
49
# File 'lib/rfd.rb', line 47

def header_r
  @header_r
end

#itemsObject (readonly)

Returns the value of attribute items.



47
48
49
# File 'lib/rfd.rb', line 47

def items
  @items
end

#mainObject (readonly)

Returns the value of attribute main.



47
48
49
# File 'lib/rfd.rb', line 47

def main
  @main
end

Instance Method Details

#ask(prompt = '(y/n)') ⇒ Object

Let the user answer y or n.

Parameters

  • prompt - Prompt message



663
664
665
666
667
668
669
670
671
672
# File 'lib/rfd.rb', line 663

def ask(prompt = '(y/n)')
  command_line.set_prompt prompt
  command_line.refresh
  while (c = Curses.getch)
    next unless [?N, ?Y, ?n, ?y, 3, 27] .include? c  # N, Y, n, y, ^c, esc
    command_line.clear
    command_line.noutrefresh
    break (c == 'y') || (c == 'Y')
  end
end

#cd(dir = '~', pushd: true) ⇒ Object

Change the current directory.



172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/rfd.rb', line 172

def cd(dir = '~', pushd: true)
  dir = load_item path: expand_path(dir) unless dir.is_a? Item
  unless dir.zip?
    Dir.chdir dir
    @current_zip = nil
  else
    @current_zip = dir
  end
  @dir_history << current_dir if current_dir && pushd
  @current_dir, @current_page, @current_row = dir, 0, nil
  main.activate_pane 0
  ls
  @current_dir
end

#chmod(mode = nil) ⇒ Object

Change the file permission of the selected files and directories.

Parameters

  • mode - Unix chmod string (e.g. +w, g-r, 755, 0644)



234
235
236
237
238
239
240
241
242
243
# File 'lib/rfd.rb', line 234

def chmod(mode = nil)
  return unless mode
  begin
    Integer mode
    mode = Integer mode.size == 3 ? "0#{mode}" : mode
  rescue ArgumentError
  end
  FileUtils.chmod mode, selected_items.map(&:path)
  ls
end

#chown(user_and_group) ⇒ Object

Change the file owner of the selected files and directories.

Parameters

  • user_and_group - user name and group name separated by : (e.g. alice, nobody:nobody, :admin)



249
250
251
252
253
254
# File 'lib/rfd.rb', line 249

def chown(user_and_group)
  return unless user_and_group
  user, group = user_and_group.split(':').map {|s| s == '' ? nil : s}
  FileUtils.chown user, group, selected_items.map(&:path)
  ls
end

#clipboardObject

Copy selected files and directories’ path into clipboard on OSX.



504
505
506
# File 'lib/rfd.rb', line 504

def clipboard
  IO.popen('pbcopy', 'w') {|f| f << selected_items.map(&:path).join(' ')} if osx?
end

#cp(dest) ⇒ Object

Copy selected files and directories to the destination.



356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/rfd.rb', line 356

def cp(dest)
  unless in_zip?
    src = (m = marked_items).any? ? m.map(&:path) : current_item
    FileUtils.cp_r src, expand_path(dest)
  else
    raise 'cping multiple items in .zip is not supported.' if selected_items.size > 1
    Zip::File.open(current_zip) do |zip|
      entry = zip.find_entry(selected_items.first.name).dup
      entry.name, entry.name_length = dest, dest.size
      zip.instance_variable_get(:@entry_set) << entry
    end
  end
  ls
end

#current_itemObject

The file or directory on which the cursor is on.



130
131
132
# File 'lib/rfd.rb', line 130

def current_item
  items[current_row]
end

#deleteObject

Delete selected files and directories.



426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/rfd.rb', line 426

def delete
  unless in_zip?
    FileUtils.rm_rf selected_items.map(&:path)
  else
    Zip::File.open(current_zip) do |zip|
      zip.select {|e| selected_items.map(&:name).include? e.to_s}.each do |entry|
        if entry.name_is_directory?
          zip.dir.delete entry.to_s
        else
          zip.file.delete entry.to_s
        end
      end
    end
  end
  @current_row -= selected_items.count {|i| i.index <= current_row}
  ls
end

#draw_itemsObject

Update the main window with the loaded files and directories. Also update the header.



297
298
299
300
301
302
# File 'lib/rfd.rb', line 297

def draw_items
  main.newpad items
  @displayed_items = items[current_page * max_items, max_items]
  main.display current_page
  header_l.draw_path_and_page_number path: current_dir.path, current: current_page + 1, total: total_pages
end

#draw_marked_itemsObject

Update the header information concerning currently marked files or directories.



606
607
608
609
# File 'lib/rfd.rb', line 606

def draw_marked_items
  items = marked_items
  header_r.draw_marked_items count: items.size, size: items.inject(0) {|sum, i| sum += i.size}
end

#draw_total_itemsObject

Update the header information concerning total files and directories in the current directory.



612
613
614
# File 'lib/rfd.rb', line 612

def draw_total_items
  header_r.draw_total_items count: items.size, size: items.inject(0) {|sum, i| sum += i.size}
end

#editObject

Open current file or directory with the editor.



675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
# File 'lib/rfd.rb', line 675

def edit
  execute_external_command do
    editor = ENV['EDITOR'] || 'vim'
    unless in_zip?
      system %Q[#{editor} "#{current_item.path}"]
    else
      begin
        tmpdir, tmpfile_name = nil
        Zip::File.open(current_zip) do |zip|
          tmpdir = Dir.mktmpdir
          FileUtils.mkdir_p File.join(tmpdir, File.dirname(current_item.name))
          tmpfile_name = File.join(tmpdir, current_item.name)
          File.open(tmpfile_name, 'w') {|f| f.puts zip.file.read(current_item.name)}
          system %Q[#{editor} "#{tmpfile_name}"]
          zip.add(current_item.name, tmpfile_name) { true }
        end
        ls
      ensure
        FileUtils.remove_entry_secure tmpdir if tmpdir
      end
    end
  end
end

#fetch_items_from_filesystem_or_zipObject

Fetch files from current directory or current .zip file.



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/rfd.rb', line 257

def fetch_items_from_filesystem_or_zip
  unless in_zip?
    @items = Dir.foreach(current_dir).map {|fn|
      load_item dir: current_dir, name: fn
    }.to_a.partition {|i| %w(. ..).include? i.name}.flatten
  else
    @items = [load_item(dir: current_dir, name: '.', stat: File.stat(current_dir)),
      load_item(dir: current_dir, name: '..', stat: File.stat(File.dirname(current_dir)))]
    zf = Zip::File.new current_dir
    zf.each {|entry|
      next if entry.name_is_directory?
      stat = zf.file.stat entry.name
      @items << load_item(dir: current_dir, name: entry.name, stat: stat)
    }
  end
end

#find(str) ⇒ Object

Focus at the first file or directory of which name starts with the given String.



275
276
277
278
# File 'lib/rfd.rb', line 275

def find(str)
  index = items.index {|i| i.index > current_row && i.name.start_with?(str)} || items.index {|i| i.name.start_with? str}
  move_cursor index if index
end

#find_reverse(str) ⇒ Object

Focus at the last file or directory of which name starts with the given String.



281
282
283
284
# File 'lib/rfd.rb', line 281

def find_reverse(str)
  index = items.reverse.index {|i| i.index < current_row && i.name.start_with?(str)} || items.reverse.index {|i| i.name.start_with? str}
  move_cursor items.size - index - 1 if index
end

#first_page?Boolean

Current page is the first page?

Returns:

  • (Boolean)


581
582
583
# File 'lib/rfd.rb', line 581

def first_page?
  current_page == 0
end

#get_charObject

Get a char as a String from user input.



622
623
624
625
# File 'lib/rfd.rb', line 622

def get_char
  c = Curses.getch
  c if (0..255) === c.ord
end

#grep(pattern = '.*') ⇒ Object

Search files and directories from the current directory, and update the screen.

  • pattern - Search pattern against file names in Ruby Regexp string.

Example

a : Search files that contains the letter “a” in their file name .*.pdf$ : Search PDF files



343
344
345
346
347
348
349
350
351
352
353
# File 'lib/rfd.rb', line 343

def grep(pattern = '.*')
  regexp = Regexp.new(pattern)
  fetch_items_from_filesystem_or_zip
  @items = items.shift(2) + items.select {|i| i.name =~ regexp}
  sort_items_according_to_current_direction
  draw_items
  switch_page 0
  move_cursor 0

  draw_total_items
end

#last_page?Boolean

Do we have more pages?

Returns:

  • (Boolean)


586
587
588
# File 'lib/rfd.rb', line 586

def last_page?
  current_page == total_pages - 1
end

#lsObject

Fetch files from current directory. Then update each windows reflecting the newest information.



194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/rfd.rb', line 194

def ls
  fetch_items_from_filesystem_or_zip
  sort_items_according_to_current_direction

  @current_page ||= 0
  draw_items
  move_cursor (current_row ? [current_row, items.size - 1].min : nil)

  draw_marked_items
  draw_total_items
  true
end

#marked_itemsObject

  • marked files and directories.



135
136
137
# File 'lib/rfd.rb', line 135

def marked_items
  items.select(&:marked?)
end

#max_itemsObject

Number of files or directories that the current main window can show in a page.



292
293
294
# File 'lib/rfd.rb', line 292

def max_items
  main.max_items
end

#maxyObject

Height of the currently active pane.



287
288
289
# File 'lib/rfd.rb', line 287

def maxy
  main.maxy
end

#mkdir(dir) ⇒ Object

Create a new directory.



445
446
447
448
449
450
451
452
453
454
# File 'lib/rfd.rb', line 445

def mkdir(dir)
  unless in_zip?
    FileUtils.mkdir_p current_dir.join(dir)
  else
    Zip::File.open(current_zip) do |zip|
      zip.dir.mkdir dir
    end
  end
  ls
end

#move_cursor(row = nil) ⇒ Object

Move the cursor to specified row.

The main window and the headers will be updated reflecting the displayed files and directories. The row number can be out of range of the current page.



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/rfd.rb', line 150

def move_cursor(row = nil)
  if row
    if (prev_item = items[current_row])
      main.draw_item prev_item
    end
    page = row / max_items
    switch_page page if page != current_page
    main.activate_pane row / maxy
    @current_row = row
  else
    @current_row = 0
  end

  item = items[current_row]
  main.draw_item item, current: true
  main.display current_page

  header_l.draw_current_file_info item
  @current_row
end

#move_cursor_by_click(y: nil, x: nil) ⇒ Object



722
723
724
725
726
727
# File 'lib/rfd.rb', line 722

def move_cursor_by_click(y: nil, x: nil)
  if (idx = main.pane_index_at(y: y, x: x))
    row = current_page * max_items + main.maxy * idx + y - main.begy
    move_cursor row if (row >= 0) && (row < items.size)
  end
end

#mv(dest) ⇒ Object

Move selected files and directories to the destination.



372
373
374
375
376
377
378
379
380
381
# File 'lib/rfd.rb', line 372

def mv(dest)
  unless in_zip?
    src = (m = marked_items).any? ? m.map(&:path) : current_item
    FileUtils.mv src, expand_path(dest)
  else
    raise 'mving multiple items in .zip is not supported.' if selected_items.size > 1
    rename "#{selected_items.first.name}/#{dest}"
  end
  ls
end

#pasteObject

Paste yanked files / directories here.



481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
# File 'lib/rfd.rb', line 481

def paste
  if @yanked_items
    if current_item.directory?
      FileUtils.cp_r @yanked_items.map(&:path), current_item
    else
      @yanked_items.each do |item|
        if items.include? item
          i = 1
          while i += 1
            new_item = load_item dir: current_dir, name: "#{item.basename}_#{i}#{item.extname}", stat: item.stat
            break unless File.exist? new_item.path
          end
          FileUtils.cp_r item, new_item
        else
          FileUtils.cp_r item, current_dir
        end
      end
    end
    ls
  end
end

#popdObject

cd to the previous directory.



188
189
190
# File 'lib/rfd.rb', line 188

def popd
  cd @dir_history.pop, pushd: false if @dir_history.any?
end

#process_command_line(preset_command: nil) ⇒ Object

Accept user input, and directly execute it as a Ruby method call to the controller.

Parameters

  • preset_command - A command that would be displayed at the command line before user input.



631
632
633
634
635
636
637
638
639
640
641
642
643
644
# File 'lib/rfd.rb', line 631

def process_command_line(preset_command: nil)
  prompt = preset_command ? ":#{preset_command} " : ':'
  command_line.set_prompt prompt
  cmd, *args = command_line.get_command(prompt: prompt).split(' ')
  if cmd && !cmd.empty? && respond_to?(cmd)
    ret = self.public_send cmd, *args
    command_line.clear
    command_line.noutrefresh
    ret
  end
rescue Interrupt
  command_line.clear
  command_line.noutrefresh
end

#process_shell_commandObject

Accept user input, and directly execute it in an external shell.



647
648
649
650
651
652
653
654
655
656
657
# File 'lib/rfd.rb', line 647

def process_shell_command
  command_line.set_prompt ':!'
  cmd = command_line.get_command(prompt: ':!')[1..-1]
  execute_external_command pause: true do
    system cmd
  end
rescue Interrupt
ensure
  command_line.clear
  command_line.noutrefresh
end

#rename(pattern) ⇒ Object

Rename selected files and directories.

Parameters

  • pattern - / separated Regexp like string



387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'lib/rfd.rb', line 387

def rename(pattern)
  from, to = pattern.split '/'
  from = Regexp.new from
  unless in_zip?
    selected_items.each do |item|
      name = item.name.gsub from, to
      FileUtils.mv item, current_dir.join(name) if item.name != name
    end
  else
    Zip::File.open(current_zip) do |zip|
      selected_items.each do |item|
        name = item.name.gsub from, to
        zip.rename item.name, name
      end
    end
  end
  ls
end

#runObject

The main loop.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/rfd.rb', line 60

def run
  loop do
    begin
      number_pressed = false
      ret = case (c = Curses.getch)
      when 10, 13  # enter, return
        enter
      when 27  # ESC
        q
      when ' '  # space
        space
      when 127  # DEL
        del
      when Curses::KEY_DOWN
        j
      when Curses::KEY_UP
        k
      when Curses::KEY_LEFT
        h
      when Curses::KEY_RIGHT
        l
      when Curses::KEY_CTRL_A..Curses::KEY_CTRL_Z
        chr = ((c - 1 + 65) ^ 0b0100000).chr
        public_send "ctrl_#{chr}" if respond_to?("ctrl_#{chr}")
      when ?0..?9
        public_send c
        number_pressed = true
      when ?!..?~
        if respond_to? c
          public_send c
        else
          debug "key: #{c}" if ENV['DEBUG']
        end
      when Curses::KEY_MOUSE
        if (mouse_event = Curses.getmouse)
          case mouse_event.bstate
          when Curses::BUTTON1_CLICKED
            click y: mouse_event.y, x: mouse_event.x
          when Curses::BUTTON1_DOUBLE_CLICKED
            double_click y: mouse_event.y, x: mouse_event.x
          end
        end
      else
        debug "key: #{c}" if ENV['DEBUG']
      end
      Curses.doupdate if ret
      @times = nil unless number_pressed
    rescue StopIteration
      raise
    rescue => e
      command_line.show_error e.to_s
      raise if ENV['DEBUG']
    end
  end
ensure
  Curses.close_screen
end

#selected_itemsObject

Marked files and directories or Array(the current file or directory).

. and .. will not be included.



142
143
144
# File 'lib/rfd.rb', line 142

def selected_items
  ((m = marked_items).any? ? m : Array(current_item)).reject {|i| %w(. ..).include? i.name}
end

#sort(direction = nil) ⇒ Object

Sort the whole files and directories in the current directory, then refresh the screen.

Parameters

  • direction - Sort order in a String.

    nil   : order by name
    r     : reverse order by name
    s, S  : order by file size
    sr, Sr: reverse order by file size
    t     : order by mtime
    tr    : reverse order by mtime
    c     : order by ctime
    cr    : reverse order by ctime
    u     : order by atime
    ur    : reverse order by atime
    e     : order by extname
    er    : reverse order by extname
    


223
224
225
226
227
228
# File 'lib/rfd.rb', line 223

def sort(direction = nil)
  @direction, @current_page = direction, 0
  sort_items_according_to_current_direction
  switch_page 0
  move_cursor 0
end

#sort_items_according_to_current_directionObject

Sort the loaded files and directories in already given sort order.



305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/rfd.rb', line 305

def sort_items_according_to_current_direction
  case @direction
  when nil
    @items = items.shift(2) + items.partition(&:directory?).flat_map(&:sort)
  when 'r'
    @items = items.shift(2) + items.partition(&:directory?).flat_map {|arr| arr.sort.reverse}
  when 'S', 's'
    @items = items.shift(2) + items.partition(&:directory?).flat_map {|arr| arr.sort_by {|i| -i.size}}
  when 'Sr', 'sr'
    @items = items.shift(2) + items.partition(&:directory?).flat_map {|arr| arr.sort_by(&:size)}
  when 't'
    @items = items.shift(2) + items.partition(&:directory?).flat_map {|arr| arr.sort {|x, y| y.mtime <=> x.mtime}}
  when 'tr'
    @items = items.shift(2) + items.partition(&:directory?).flat_map {|arr| arr.sort_by(&:mtime)}
  when 'c'
    @items = items.shift(2) + items.partition(&:directory?).flat_map {|arr| arr.sort {|x, y| y.ctime <=> x.ctime}}
  when 'cr'
    @items = items.shift(2) + items.partition(&:directory?).flat_map {|arr| arr.sort_by(&:ctime)}
  when 'u'
    @items = items.shift(2) + items.partition(&:directory?).flat_map {|arr| arr.sort {|x, y| y.atime <=> x.atime}}
  when 'ur'
    @items = items.shift(2) + items.partition(&:directory?).flat_map {|arr| arr.sort_by(&:atime)}
  when 'e'
    @items = items.shift(2) + items.partition(&:directory?).flat_map {|arr| arr.sort {|x, y| y.extname <=> x.extname}}
  when 'er'
    @items = items.shift(2) + items.partition(&:directory?).flat_map {|arr| arr.sort_by(&:extname)}
  end
  items.each.with_index {|item, index| item.index = index}
end

#spawn_panes(num) ⇒ Object

Change the number of columns in the main window.



119
120
121
122
# File 'lib/rfd.rb', line 119

def spawn_panes(num)
  main.number_of_panes = num
  @current_row = @current_page = 0
end

#switch_page(page) ⇒ Object

Move to the given page number.

Parameters

  • page - Target page number



599
600
601
602
603
# File 'lib/rfd.rb', line 599

def switch_page(page)
  main.display (@current_page = page)
  @displayed_items = items[current_page * max_items, max_items]
  header_l.draw_path_and_page_number path: current_dir.path, current: current_page + 1, total: total_pages
end

Create a symlink to the current file or directory.



470
471
472
473
# File 'lib/rfd.rb', line 470

def symlink(name)
  FileUtils.ln_s current_item, name
  ls
end

#timesObject

Number of times to repeat the next command.



125
126
127
# File 'lib/rfd.rb', line 125

def times
  (@times || 1).to_i
end

#toggle_markObject

Swktch on / off marking on the current file or directory.



617
618
619
# File 'lib/rfd.rb', line 617

def toggle_mark
  main.toggle_mark current_item
end

#total_pagesObject

Number of pages in the current directory.



591
592
593
# File 'lib/rfd.rb', line 591

def total_pages
  (items.size - 1) / max_items + 1
end

#touch(filename) ⇒ Object

Create a new empty file.



457
458
459
460
461
462
463
464
465
466
467
# File 'lib/rfd.rb', line 457

def touch(filename)
  unless in_zip?
    FileUtils.touch current_dir.join(filename)
  else
    Zip::File.open(current_zip) do |zip|
      # zip.file.open(filename, 'w') {|_f| }  #HAXX this code creates an unneeded temporary file
      zip.instance_variable_get(:@entry_set) << Zip::Entry.new(current_zip, filename)
    end
  end
  ls
end

#trashObject

Soft delete selected files and directories.

If the OS is not OSX, performs the same as delete command.



409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
# File 'lib/rfd.rb', line 409

def trash
  unless in_zip?
    if osx?
      FileUtils.mv selected_items.map(&:path), File.expand_path('~/.Trash/')
    else
      #TODO support other OS
      FileUtils.rm_rf selected_items.map(&:path)
    end
  else
    return unless ask %Q[Trashing zip entries is not supported. Actually the files will be deleted. Are you sure want to proceed? (y/n)]
    delete
  end
  @current_row -= selected_items.count {|i| i.index <= current_row}
  ls
end

#unarchiveObject

Unarchive .zip and .tar.gz files within selected files and directories into current_directory.



529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
# File 'lib/rfd.rb', line 529

def unarchive
  unless in_zip?
    zips, gzs = selected_items.partition(&:zip?).tap {|z, others| break [z, *others.partition(&:gz?)]}
    zips.each do |item|
      FileUtils.mkdir_p current_dir.join(item.basename)
      Zip::File.open(item) do |zip|
        zip.each do |entry|
          FileUtils.mkdir_p File.join(item.basename, File.dirname(entry.to_s))
          zip.extract(entry, File.join(item.basename, entry.to_s)) { true }
        end
      end
    end
    gzs.each do |item|
      Zlib::GzipReader.open(item) do |gz|
        Gem::Package::TarReader.new(gz) do |tar|
          dest_dir = current_dir.join (gz.orig_name || item.basename).sub(/\.tar$/, '')
          tar.each do |entry|
            dest = nil
            if entry.full_name == '././@LongLink'
              dest = File.join dest_dir, entry.read.strip
              next
            end
            dest ||= File.join dest_dir, entry.full_name
            if entry.directory?
              FileUtils.mkdir_p dest, :mode => entry.header.mode
            elsif entry.file?
              FileUtils.mkdir_p dest_dir
              File.open(dest, 'wb') {|f| f.print entry.read}
              FileUtils.chmod entry.header.mode, dest
            elsif entry.header.typeflag == '2'  # symlink
              File.symlink entry.header.linkname, dest
            end
            unless Dir.exist? dest_dir
              FileUtils.mkdir_p dest_dir
              File.open(File.join(dest_dir, gz.orig_name || item.basename), 'wb') {|f| f.print gz.read}
            end
          end
        end
      end
    end
  else
    Zip::File.open(current_zip) do |zip|
      zip.select {|e| selected_items.map(&:name).include? e.to_s}.each do |entry|
        FileUtils.mkdir_p File.join(current_zip.dir, current_zip.basename, File.dirname(entry.to_s))
        zip.extract(entry, File.join(current_zip.dir, current_zip.basename, entry.to_s)) { true }
      end
    end
  end
  ls
end

#viewObject

Open current file or directory with the viewer.



700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
# File 'lib/rfd.rb', line 700

def view
  pager = ENV['PAGER'] || 'less'
  execute_external_command do
    unless in_zip?
      system %Q[#{pager} "#{current_item.path}"]
    else
      begin
        tmpdir, tmpfile_name = nil
        Zip::File.open(current_zip) do |zip|
          tmpdir = Dir.mktmpdir
          FileUtils.mkdir_p File.join(tmpdir, File.dirname(current_item.name))
          tmpfile_name = File.join(tmpdir, current_item.name)
          File.open(tmpfile_name, 'w') {|f| f.puts zip.file.read(current_item.name)}
        end
        system %Q[#{pager} "#{tmpfile_name}"]
      ensure
        FileUtils.remove_entry_secure tmpdir if tmpdir
      end
    end
  end
end

#yankObject

Yank selected file / directory names.



476
477
478
# File 'lib/rfd.rb', line 476

def yank
  @yanked_items = selected_items
end

#zip(zipfile_name) ⇒ Object

Archive selected files and directories into a .zip file.



509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
# File 'lib/rfd.rb', line 509

def zip(zipfile_name)
  return unless zipfile_name
  zipfile_name << '.zip' unless zipfile_name.end_with? '.zip'

  Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
    selected_items.each do |item|
      next if item.symlink?
      if item.directory?
        Dir[item.join('**/**')].each do |file|
          zipfile.add file.sub("#{current_dir}/", ''), file
        end
      else
        zipfile.add item.name, item
      end
    end
  end
  ls
end