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, #q, #r, #s, #space, #t, #u, #v, #w, #z

Constructor Details

#initializeController

:nodoc:



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

def initialize
  @main = MainWindow.new
  @header_l = HeaderLeftWindow.new
  @header_r = HeaderRightWindow.new
  @command_line = CommandLineWindow.new
  @direction, @dir_history, @last_command, @times = nil, [], nil, nil
end

Instance Attribute Details

#command_lineObject (readonly)

Returns the value of attribute command_line.



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

def command_line
  @command_line
end

#current_dirObject (readonly)

Returns the value of attribute current_dir.



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

def current_dir
  @current_dir
end

#current_pageObject (readonly)

Returns the value of attribute current_page.



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

def current_page
  @current_page
end

#current_rowObject (readonly)

Returns the value of attribute current_row.



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

def current_row
  @current_row
end

#current_zipObject (readonly)

Returns the value of attribute current_zip.



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

def current_zip
  @current_zip
end

#displayed_itemsObject (readonly)

Returns the value of attribute displayed_items.



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

def displayed_items
  @displayed_items
end

#header_lObject (readonly)

Returns the value of attribute header_l.



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

def header_l
  @header_l
end

#header_rObject (readonly)

Returns the value of attribute header_r.



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

def header_r
  @header_r
end

#itemsObject (readonly)

Returns the value of attribute items.



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

def items
  @items
end

#mainObject (readonly)

Returns the value of attribute main.



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

def main
  @main
end

Instance Method Details

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

Let the user answer y or n.

Parameters

  • prompt - Prompt message



645
646
647
648
649
650
651
652
653
654
# File 'lib/rfd.rb', line 645

def ask(prompt = '(y/n)')
  command_line.set_prompt prompt
  command_line.wrefresh
  while (c = Curses.getch)
    next unless [78, 89, 110, 121, 3, 27] .include? c  # N, Y, n, y, ^c, esc
    command_line.wclear
    command_line.wrefresh
    break [89, 121].include? c  # Y, y
  end
end

#cd(dir, pushd: true) ⇒ Object

Change the current directory.



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

def cd(dir, pushd: true)
  if dir.is_a?(Item) && dir.zip?
    cd_into_zip dir
  else
    target = expand_path dir
    if File.readable? target
      Dir.chdir target
      @dir_history << current_dir if current_dir && pushd
      @current_dir, @current_page, @current_row, @current_zip = target, 0, nil, nil
      main.activate_pane 0
    end
  end
end

#cd_into_zip(zipfile) ⇒ Object



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

def cd_into_zip(zipfile)
  @current_zip = zipfile
  @dir_history << current_dir if current_dir
  @current_dir, @current_page, @current_row = zipfile.path, 0, nil
  main.activate_pane 0
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)



243
244
245
246
247
248
249
250
251
252
# File 'lib/rfd.rb', line 243

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)



258
259
260
261
262
263
# File 'lib/rfd.rb', line 258

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.



488
489
490
# File 'lib/rfd.rb', line 488

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.



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

def cp(dest)
  unless in_zip?
    src = (m = marked_items).any? ? m.map(&:path) : current_item.path
    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.path) 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.



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

def current_item
  items[current_row]
end

#deleteObject

Delete selected files and directories.



438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# File 'lib/rfd.rb', line 438

def delete
  unless in_zip?
    FileUtils.rm_rf selected_items.map(&:path)
  else
    Zip::File.open(current_zip.path) 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.



312
313
314
315
# File 'lib/rfd.rb', line 312

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

#draw_marked_itemsObject

Update the header information concerning currently marked files or directories.



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

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.



595
596
597
# File 'lib/rfd.rb', line 595

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.



657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
# File 'lib/rfd.rb', line 657

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.path) 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.



266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/rfd.rb', line 266

def fetch_items_from_filesystem_or_zip
  unless in_zip?
    @items = Dir.foreach(current_dir).map {|fn|
      stat = File.lstat File.join(current_dir, fn)
      Item.new dir: current_dir, name: fn, stat: stat, window_width: maxx
    }.to_a
  else
    @items = [Item.new(dir: current_dir, name: '.', stat: File.stat(current_dir), window_width: maxx),
      Item.new(dir: current_dir, name: '..', stat: File.stat(File.dirname(current_dir)), window_width: maxx)]
    zf = Zip::File.new current_dir
    zf.each {|entry|
      next if entry.name_is_directory?
      stat = zf.file.stat entry.name
      @items << Item.new(dir: current_dir, name: entry.name, stat: stat, window_width: maxx)
    }
  end
end

#find(str) ⇒ Object

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



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

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.



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

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)


565
566
567
# File 'lib/rfd.rb', line 565

def first_page?
  current_page == 0
end

#get_charObject

Get a char as a String from user input.



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

def get_char
  c = Curses.getch
  c.chr if (0..255) === c
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



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

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
  switch_page 0
  move_cursor 0

  draw_total_items
end

#last_page?Boolean

Do we have more pages?

Returns:

  • (Boolean)


570
571
572
# File 'lib/rfd.rb', line 570

def last_page?
  current_page == total_pages - 1
end

#lsObject

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



204
205
206
207
208
209
210
211
212
213
214
# File 'lib/rfd.rb', line 204

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
end

#marked_itemsObject

  • marked files and directories.



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

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

#max_itemsObject

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



307
308
309
# File 'lib/rfd.rb', line 307

def max_items
  main.max_items
end

#maxxObject

Width of the currently active pane.



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

def maxx
  main.maxx
end

#maxyObject

Height of the currently active pane.



302
303
304
# File 'lib/rfd.rb', line 302

def maxy
  main.maxy
end

#mkdir(dir) ⇒ Object

Create a new directory.



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

def mkdir(dir)
  unless in_zip?
    FileUtils.mkdir_p File.join(current_dir, dir)
  else
    Zip::File.open(current_zip.path) 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.



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

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

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

  header_l.draw_current_file_info item
  header_l.wrefresh
end

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



704
705
706
707
708
709
# File 'lib/rfd.rb', line 704

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.



384
385
386
387
388
389
390
391
392
393
# File 'lib/rfd.rb', line 384

def mv(dest)
  unless in_zip?
    src = (m = marked_items).any? ? m.map(&:path) : current_item.path
    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

#popdObject

cd to the previous directory.



195
196
197
198
199
200
# File 'lib/rfd.rb', line 195

def popd
  if @dir_history.any?
    cd @dir_history.pop, pushd: false
    ls
  end
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.



614
615
616
617
618
619
620
621
622
623
624
625
626
# File 'lib/rfd.rb', line 614

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)
    self.public_send cmd, *args
    command_line.wclear
    command_line.wrefresh
  end
rescue Interrupt
  command_line.wclear
  command_line.wrefresh
end

#process_shell_commandObject

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



629
630
631
632
633
634
635
636
637
638
639
# File 'lib/rfd.rb', line 629

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.wclear
  command_line.wrefresh
end

#rename(pattern) ⇒ Object

Rename selected files and directories.

Parameters

  • pattern - / separated Regexp like string



399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# File 'lib/rfd.rb', line 399

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.path, File.join(current_dir, name)
    end
  else
    Zip::File.open(current_zip.path) 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
# File 'lib/rfd.rb', line 60

def run
  mouse_event = Curses::MEVENT.new
  loop do
    begin
      number_pressed = false
      case (c = Curses.getch)
      when Curses::KEY_RETURN
        enter
      when Curses::KEY_ESCAPE
        q
      when 32  # 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 48..57  # ?0..?9
        public_send c.chr
        number_pressed = true
      when 0..255
        if respond_to? c.chr
          public_send c.chr
        else
          debug "key: #{c}" if ENV['DEBUG']
        end
      when Curses::KEY_MOUSE
        if Curses.getmouse(mouse_event) == Curses::OK
          if Curses.BUTTON_CLICK(mouse_event[:bstate], 1) > 0
            click y: mouse_event[:y], x: mouse_event[:x]
          elsif Curses.BUTTON_DOUBLE_CLICK(mouse_event[:bstate], 1) > 0
            double_click y: mouse_event[:y], x: mouse_event[:x]
          end
        end
      else
        debug "key: #{c}" if ENV['DEBUG']
      end
      @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.endwin
end

#selected_itemsObject

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

. and .. will not be included.



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

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
    


232
233
234
235
236
237
# File 'lib/rfd.rb', line 232

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.



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'lib/rfd.rb', line 318

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.



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

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

#switch_page(page) ⇒ Object

Move to the given page number.

Parameters

  • page - Target page number



583
584
585
586
# File 'lib/rfd.rb', line 583

def switch_page(page)
  @current_page = page
  draw_items
end

Create a symlink to the current file or directory.



482
483
484
485
# File 'lib/rfd.rb', line 482

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

#timesObject

Number of times to repeat the next command.



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

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

#toggle_markObject

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



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

def toggle_mark
  main.toggle_mark current_item
end

#total_pagesObject

Number of pages in the current directory.



575
576
577
# File 'lib/rfd.rb', line 575

def total_pages
  items.size / max_items + 1
end

#touch(filename) ⇒ Object

Create a new empty file.



469
470
471
472
473
474
475
476
477
478
479
# File 'lib/rfd.rb', line 469

def touch(filename)
  unless in_zip?
    FileUtils.touch File.join(current_dir, filename)
  else
    Zip::File.open(current_zip.path) 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.path, filename)
    end
  end
  ls
end

#trashObject

Soft delete selected files and directories.

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



421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
# File 'lib/rfd.rb', line 421

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.



513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
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
# File 'lib/rfd.rb', line 513

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 File.join(current_dir, item.basename)
      Zip::File.open(item.path) do |zip|
        zip.each do |entry|
          FileUtils.mkdir_p File.join(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.path) do |gz|
        Gem::Package::TarReader.new(gz) do |tar|
          dest_dir = File.join current_dir, (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.path) 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.



682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
# File 'lib/rfd.rb', line 682

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.path) 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

#zip(zipfile_name) ⇒ Object

Archive selected files and directories into a .zip file.



493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
# File 'lib/rfd.rb', line 493

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[File.join(item.path, '**/**')].each do |file|
          zipfile.add file.sub("#{current_dir}/", ''), file
        end
      else
        zipfile.add item.name, item.path
      end
    end
  end
  ls
end