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



637
638
639
640
641
642
643
644
645
646
# File 'lib/rfd.rb', line 637

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
# File 'lib/rfd.rb', line 173

def cd(dir, pushd: true)
  dir = load_item 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
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)



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

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)



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

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.



480
481
482
# File 'lib/rfd.rb', line 480

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.



360
361
362
363
364
365
366
367
368
369
370
371
372
373
# File 'lib/rfd.rb', line 360

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.



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

def current_item
  items[current_row]
end

#deleteObject

Delete selected files and directories.



430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# File 'lib/rfd.rb', line 430

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.



304
305
306
307
# File 'lib/rfd.rb', line 304

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.path, current: current_page + 1, total: total_pages
end

#draw_marked_itemsObject

Update the header information concerning currently marked files or directories.



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

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.



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

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.



649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
# File 'lib/rfd.rb', line 649

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.



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

def fetch_items_from_filesystem_or_zip
  unless in_zip?
    @items = Dir.foreach(current_dir).map {|fn|
      stat = File.lstat current_dir.join(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.



277
278
279
280
# File 'lib/rfd.rb', line 277

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.



283
284
285
286
# File 'lib/rfd.rb', line 283

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)


557
558
559
# File 'lib/rfd.rb', line 557

def first_page?
  current_page == 0
end

#get_charObject

Get a char as a String from user input.



597
598
599
600
# File 'lib/rfd.rb', line 597

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



348
349
350
351
352
353
354
355
356
357
# File 'lib/rfd.rb', line 348

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)


562
563
564
# File 'lib/rfd.rb', line 562

def last_page?
  current_page == total_pages - 1
end

#lsObject

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



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

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.



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

def max_items
  main.max_items
end

#maxxObject

Width of the currently active pane.



289
290
291
# File 'lib/rfd.rb', line 289

def maxx
  main.maxx
end

#maxyObject

Height of the currently active pane.



294
295
296
# File 'lib/rfd.rb', line 294

def maxy
  main.maxy
end

#mkdir(dir) ⇒ Object

Create a new directory.



449
450
451
452
453
454
455
456
457
458
# File 'lib/rfd.rb', line 449

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.



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



696
697
698
699
700
701
# File 'lib/rfd.rb', line 696

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.



376
377
378
379
380
381
382
383
384
385
# File 'lib/rfd.rb', line 376

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

#popdObject

cd to the previous directory.



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

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.



606
607
608
609
610
611
612
613
614
615
616
617
618
# File 'lib/rfd.rb', line 606

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.



621
622
623
624
625
626
627
628
629
630
631
# File 'lib/rfd.rb', line 621

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



391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
# File 'lib/rfd.rb', line 391

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
# 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
    


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

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.



310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/rfd.rb', line 310

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



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

def switch_page(page)
  @current_page = page
  draw_items
end

Create a symlink to the current file or directory.



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

def symlink(name)
  FileUtils.ln_s current_item, 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.



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

def toggle_mark
  main.toggle_mark current_item
end

#total_pagesObject

Number of pages in the current directory.



567
568
569
# File 'lib/rfd.rb', line 567

def total_pages
  items.size / max_items + 1
end

#touch(filename) ⇒ Object

Create a new empty file.



461
462
463
464
465
466
467
468
469
470
471
# File 'lib/rfd.rb', line 461

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.



413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/rfd.rb', line 413

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.



505
506
507
508
509
510
511
512
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
# File 'lib/rfd.rb', line 505

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.



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

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

#zip(zipfile_name) ⇒ Object

Archive selected files and directories into a .zip file.



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

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