class Object

Constants

LScolors

Public Instance Methods

ansifix(text) click to toggle source
# File bin/rtfm, line 789
def ansifix(text) # Format [[fg, attr, text]]
  output = ""
  text.each do |e|
    ansi    = "\e[38;5;#{e[0]}"
    ansi   += ";1" if e[1] == 1
    ansi   += "m"
    output += ansi + e[2].gsub(/\n/, "\n#{ansi}")
  end
  return output
end
cmd?(command) click to toggle source
# File bin/rtfm, line 136
def cmd?(command)
  system("which #{command} > /dev/null 2>&1")
end
color_parse(input) click to toggle source
# File bin/rtfm, line 253
def color_parse(input) # PARSE ANSI COLOR SEQUENCES
  input.gsub!( /\e\[\d;38;5;(\d+);*(\d*)m/, '¤¤\1¤¤\2¤¤')
  input.gsub!( /\e\[38;5;(\d+);*(\d*)m/, '¤¤\1¤¤\2¤¤')
  input.gsub!( /\e\[\d;38;2;(\d+);*(\d*);\d*m/, '¤¤\1¤¤\2¤¤')
  input.gsub!( /\e\[38;2;(\d+);*(\d*);\d*m/, '¤¤\1¤¤\2¤¤')
  input.gsub!( /\e\[0m/, "\t")
  color_array = input.split("¤¤")
  color_array = color_array.drop(1)
  output = color_array.each_slice(3).to_a
  return output
end
conf_write() click to toggle source
# File bin/rtfm, line 748
def conf_write
  if File.exist?(Dir.home+'/.rtfm.conf')
    conf = File.read(Dir.home+'/.rtfm.conf')
  else
    conf = ""
  end
  conf.sub!(/^@marks.*{.*}\n/, "") 
  conf += "@marks = #{@marks}\n"
  conf.sub!(/^@hash.*{.*}\n/, "") 
  conf += "@hash = #{@hash}\n"
  conf.sub!(/^@tagged.*\[.*\]\n/, "")
  conf += "@tagged = #{@tagged}\n"
  if @write_conf_all
    conf.sub!(/^@lslong.*\n/, "") 
    conf += "@lslong = #{@lslong}\n"
    conf.sub!(/^@lsall.*\n/, "") 
    conf += "@lsall = \"#{@lsall}\"\n"
    conf.sub!(/^@lsorder.*\n/, "") 
    conf += "@lsorder = \"#{@lsorder}\"\n"
    conf.sub!(/^@lsinvert.*\n/, "") 
    conf += "@lsinvert = \"#{@lsinvert}\"\n"
    conf.sub!(/^@width.*\n/, "") 
    conf += "@width = #{@width}\n"
    conf.sub!(/^@border.*\n/, "") 
    conf += "@border = #{@border}\n"
    conf.sub!(/^@preview.*\n/, "") 
    conf += "@preview = #{@preview}\n"
    conf.sub!(/^@showimage.*\n/, "") 
    conf += "@showimage = #{@showimage}\n"
    w_r_info("Press W again to write this to .rtfm.conf:\n\n" + conf)
    if getchr == 'W'
      w_b_info(" Parameters written to .rtfm.conf")
      @w_r.update = true
    else
      w_b_info(" Config NOT updated")
      @w_r.update = true
      return
    end
  end
  File.write(Dir.home+'/.rtfm.conf', conf)
end
get_ls_color(type) click to toggle source

GENERIC FUNCTIONS

# File bin/rtfm, line 228
def get_ls_color(type) # GET THE COLOR FOR THE FILETYPE FROM IMPORTED LS_COLORS
  bold    = 0
  begin
    color = LScolors.match(/#{type}=\d*;\d*;(\d*)/)[1]
    bold  = 1 if LScolors.match(/#{type}=\d*;\d*;\d*;1/)
  rescue
    color = 7 # Default color
  end
  return color.to_i, bold
end
getchr() click to toggle source
# File bin/rtfm, line 264
def getchr # PROCESS KEY PRESSES
  # Note: Curses.getch blanks out @w_t
  # @w_l.getch makes Curses::KEY_DOWN etc not work
  # Therefore resorting to the generic method
  c = STDIN.getch(min: 0, time: 3)
  case c
  when "\e"    # ANSI escape sequences
    case $stdin.getc
    when '['   # CSI
      case $stdin.getc
      when 'A' then chr = "UP"
      when 'B' then chr = "DOWN"
      when 'C' then chr = "RIGHT"
      when 'D' then chr = "LEFT"
      when 'Z' then chr = "S-TAB"
      when '2' then chr = "INS"    ; chr = "C-INS"    if STDIN.getc == "^"
      when '3' then chr = "DEL"    ; chr = "C-DEL"    if STDIN.getc == "^"
      when '5' then chr = "PgUP"   ; chr = "C-PgUP"   if STDIN.getc == "^"
      when '6' then chr = "PgDOWN" ; chr = "C-PgDOWN" if STDIN.getc == "^"
      when '7' then chr = "HOME"   ; chr = "C-HOME"   if STDIN.getc == "^"
      when '8' then chr = "END"    ; chr = "C-END"    if STDIN.getc == "^"
      end
    when 'O'   # Set Ctrl+ArrowKey equal to ArrowKey; May be used for other purposes in the future
      case $stdin.getc
      when 'a' then chr = "C-UP"
      when 'b' then chr = "C-DOWN"
      when 'c' then chr = "C-RIGHT"
      when 'd' then chr = "C-LEFT"
      end
    end
  when "", "" then chr = "BACK"
  when "" then chr = "WBACK"
  when "" then chr = "LDEL"
  when "" then chr = "C-T"
  when "" then chr = "C-G"
  when "\r" then chr = "ENTER"
  when "\t" then chr = "TAB"
  when /./  then chr = c
  end
  return chr
end
image_show(image) click to toggle source
# File bin/rtfm, line 1094
def image_show(image)# SHOW THE SELECTED IMAGE IN THE RIGHT WINDOW
  # Pass "clear" to clear the window for previous image
  return unless @showimage
  begin
    terminfo    = `xwininfo -id $(xdotool getactivewindow 2>/dev/null) 2>/dev/null`
    term_w      = terminfo.match(/Width: (\d+)/)[1].to_i
    term_h      = terminfo.match(/Height: (\d+)/)[1].to_i
    char_w      = term_w / Curses.cols
    char_h      = term_h / Curses.lines
    img_x       = char_w * (Curses.cols/@width + 1)
    img_y       = char_h * 2
    img_max_w   = char_w * (Curses.cols - Curses.cols/@width - 2)
    img_max_h   = char_h * (Curses.lines - 4)
    if image == "clear"
      `clear`
      img_x     -= char_w
      img_max_w += char_w + 2
      img_max_h += 2
      `echo "6;#{img_x};#{img_y};#{img_max_w};#{img_max_h};\n4;\n3;" | #{@imgdisplay} 2>/dev/null`
    else
      img_w,img_h = `identify -format "%[fx:w]x%[fx:h]" #{image} 2>/dev/null`.split('x')
      img_w       = img_w.to_i
      img_h       = img_h.to_i
      if img_w > img_max_w
        img_h = img_h * img_max_w / img_w 
        img_w = img_max_w
      end
      if img_h > img_max_h
        img_w = img_w * img_max_h / img_h
        img_h = img_max_h
      end
      `echo "0;1;#{img_x};#{img_y};#{img_w};#{img_h};;;;;\"#{image}\"\n4;\n3;" | #{@imgdisplay} 2>/dev/null`
    end
  rescue
    @w_r.clr
    @w_r << "Error showing image"
  end
end
list_dir(active) click to toggle source

LEFT WINDOW FUNCTIONS

# File bin/rtfm, line 842
def list_dir(active) # LIST CONTENT OF A DIRECTORY (BOTH active AND RIGHT WINDOWS)
  ix = 0; t = 0
  if active 
    win = @w_l
    ix = @index - @w_l.maxy/2 if @index > @w_l.maxy/2 and @files.size > @w_l.maxy - 1
  else
    win = @w_r
  end
  while ix < @files.size and t < win.maxy do
    str = @files[ix]
    active ? str_path = str : str_path = "#{@selected}/#{str}" 
    begin # Add items matching @tag to @tagged
      if str.match(/#{@tag}/) and @tag != false
        @tagged.push("\"#{Dir.pwd}/#{str}\"")
        @tagged.uniq!
      end
    rescue
    end
    # Determine the filetype of the item
    ftype = ""
    ftype = str.match(/\.([^.]*$)/)[1] if str.match?(/\.([^.]*$)/)
    # Set special filetypes (sequence matters)
    ftype = "bd" if File.blockdev?(str_path)
    ftype = "cd" if File.chardev?(str_path)
    ftype = "pi" if File.pipe?(str_path)
    ftype = "st" if File.sticky?(str_path)
    ftype = "so" if File.socket?(str_path)
    ftype = "ex" if File.executable?(str_path)
    ftype = "di" if File.directory?(str_path)
    ftype = "ln" if File.symlink?(str_path) 
    begin
      File.stat(str_path) # Checking if not an orphaned link
    rescue
      ftype = "or"        # Set to orphant if no link target
    end
    fg = 7; bold = 0; bg = 0 # Set default color
    fg, bold = get_ls_color(ftype) unless ftype == "" # Color from LS_COLORS
    init_pair(fg, fg, bg)
    file_marker = color_pair(fg)
    file_marker = file_marker | Curses::A_BOLD if bold == 1
    if ix == @index and active
      str = "∶" + str
      file_marker = file_marker | Curses::A_UNDERLINE 
      wixy = win.cury
    else
      str = " " + str
    end
    file_marker = file_marker | Curses::A_REVERSE if @tagged.include?("\"#{Dir.pwd}/#{str_path}\"")
    file_marker = file_marker | Curses::A_BLINK if str.match(/#{@searched}/) and @searched != ""
    File.directory?(str_path) ? dir = "/" : dir = ""
    File.symlink?(str_path) ? link = "@" : link = ""
    str = @fspes[ix] + "  " + str if @lslong
    if str.length > win.maxx - 4
      base_name   = File.basename(str, ".*")
      base_length = base_name.length
      ext_name    = File.extname(str)
      ext_length  = ext_name.length
      nbl = win.maxx - 5 - ext_length # nbl: new_base_length
      str = base_name[0..nbl] + "…" + ext_name
    end
    if !active and ix == win.maxy - 1 # Add indicator of more at bottom @w_r list
      win << " ..."
      return
    end
    str += link + dir
    win.attron(file_marker) { win << str } # Implement color/bold to the item
    win.clrtoeol
    win << "\n"
    ix += 1; t  += 1
  end
  (win.maxy - win.cury).times {win.deleteln()} # Clear to bottom of window
  if active
    init_pair(242, 242, 0)
    if @index > @w_l.maxy/2
      @w_l.setpos(0, @w_l.maxx - 1)
      @w_l.attron(color_pair(242) | Curses::A_DIM) { @w_l << "∆" }
    end
    if @files.length > @w_l.maxy - 1 and @files.length > @index + @w_l.maxy/2 - 1
      @w_l.setpos(@w_l.maxy - 2, @w_l.maxx - 1)
      @w_l.attron(color_pair(242) | Curses::A_DIM) { @w_l << "∇" }
    end
  end
end
main_getkey() click to toggle source
# File bin/rtfm, line 305
def main_getkey # GET KEY FROM USER
  dir = Dir.pwd
  chr = getchr
  case chr
  # BASIC KEYS
  when '?' # Show helptext in right window
    @w_r.fg = 249
    w_r_info(@help)
    @w_b.update = true
  when 'r' # Refresh all windows
    @break = true
  when 'R' # Reload .rtfm.conf
    if File.exist?(Dir.home+'/.rtfm.conf')
      load(Dir.home+'/.rtfm.conf')
    end
    w_b_info(" Config reloaded")
  when 'W' # Write all parameters to .rtfm.conf
    @write_conf_all = true
    conf_write
    @w_b.update = true
  when 'q' # Exit
    @write_conf = true
    exit 0
  when 'Q' # Exit without writing to .rtfm.conf
    system("printf \"\033]0;#{Dir.pwd}\007\"")
    @write_conf = false
    exit 0
  # MOTION
  when 'DOWN', 'j', 'C-DOWN'
    var_resets
    @index = @index >= @max_index ? @min_index : @index + 1
    @w_r.update = true
    @w_b.update = true
  when 'UP', 'k', 'C-UP'
    var_resets
    @index = @index <= @min_index ? @max_index : @index - 1
    @w_r.update = true
    @w_b.update = true
  when 'LEFT', 'h', 'C-LEFT'
    var_resets
    cur_dir = Dir.pwd
    @directory[Dir.pwd] = @selected # Store this directory before leaving
    mark_latest
    Dir.chdir("..")
    @directory[Dir.pwd] = File.basename(cur_dir) unless @directory.key?(Dir.pwd)
    @w_r.update = true
    @w_b.update = true
  when 'RIGHT', 'l', 'C-RIGHT'
    var_resets
    @directory[Dir.pwd] = @selected # Store this directory before leaving
    mark_latest
    open_selected()
    @w_r.update = true
    @w_b.update = true
  when 'x'   # Force open with file opener (used to open HTML files in browser)
    var_resets
    @directory[Dir.pwd] = @selected # Store this directory before leaving
    mark_latest
    open_selected(true)
    @w_r.update = true
    @w_b.update = true
  when 'PgDOWN'
    var_resets
    @index += @w_l.maxy - 2
    @index = @max_index if @index > @max_index
    @w_r.update = true
    @w_b.update = true
  when 'PgUP'
    var_resets
    @index -= @w_l.maxy - 2
    @index = @min_index if @index < @min_index
    @w_r.update = true
    @w_b.update = true
  when 'END'
    var_resets
    @index = @max_index
    @w_r.update = true
    @w_b.update = true
  when 'HOME'
    var_resets
    @index = @min_index
    @w_r.update = true
    @w_b.update = true
  # JUMPING AND MARKS
  when 'm' # Set mark
    marks_info
    m = STDIN.getc
    if m.match(/[\w']/)
      @marks[m] = Dir.pwd
    elsif m == "-"
      r = STDIN.getc
      @marks.delete(r)
    end
    marks_info
    @w_r.update = false
    @w_b.update = true
  when 'M' # Show marks
    marks_info
    @w_r.update = false
    @w_b.update = true
  when "'" # Jump to mark
    marks_info
    m = stdscr.getch.to_s
    if m.match(/[\w']/) and @marks[m]
      var_resets
      @directory[Dir.pwd] = @selected # Store this directory before leaving
      dir_before  = Dir.pwd
      begin
        Dir.chdir(@marks[m]) 
      rescue
        w_b_info(" No such directory")
      end
      mark_latest
      @marks["'"] = dir_before
    end
    @w_r.update = true
    @w_b.update = true
  when '~' # Go to home dir
    var_resets
    @directory[Dir.pwd] = @selected # Store this directory before leaving
    mark_latest
    Dir.chdir
    @w_r.update = true
    @w_b.update = true
  when 'f' # Follow symlink
    @directory[Dir.pwd] = @selected # Store this directory before leaving
    mark_latest
    if File.symlink?(@selected) 
      begin
        Dir.chdir(File.dirname(File.readlink(@selected)))
      rescue
      end
    end
    @w_b.update = true
  when 'g' # Run 'grep' in the current directory
    cmd = w_b_getstr(": ", "grep -s MATCH *")
    w_b_exec(cmd)
  when 'L' # Run 'locate' and let user jump to a result (by '#')
    cmd = w_b_getstr(": ", "locate ")
    w_b_exec(cmd)
    @w_r.locate = true
    @w_b.update = true
  when '#' # Jump to the line number in list of matches to 'locate'
    if @w_r.locate
      jumpnr   = w_b_getstr("# ", "").to_i
      jumpline = @w_r.text.lines[jumpnr - 1]
      jumpdir  = jumpline[/\/[^\e]*/]
      unless Dir.exist?(jumpdir) 
        @searched = File.basename(jumpdir)
        jumpdir = File.dirname(jumpdir)
      end
      @directory[Dir.pwd] = @selected # Store this directory before leaving
      mark_latest
      Dir.chdir(jumpdir)
      @w_r.pager = 0
    end
    @w_b.update = true
  # TAGGING
  when 't' # Add item to tagged list
    item = "\"#{Dir.pwd}/#{@selected}\""
    if @tagged.include?(item)
      @tagged.delete(item)
    else
      @tagged.push(item)
    end
    @index += 1
    @w_r.update = true
    @w_b.update = true
  when 'C-T' # Tag items matching a pettern
    @w_b.nohistory = true
    @tag = w_b_getstr("~ ", "")
    @w_r.update = true
    @w_b.update = true
  when 'T' # Show tagged list
    @w_r.fg = 196
    tagged_info
    @w_r.update = false
    @w_b.update = true
  when 'u' # Clear tagged list
    @tagged = []
    tagged_info
    @w_r.update = false
    @w_b.update = true
  # MANIPULATE ITEMS
  when 'p' # Copy tagged items here
    copy_move_link("copy")
    @w_r.update = true
  when 'P' # Move tagged items here
    copy_move_link("move")
    @w_r.update = true
  when 's' # Create symlink to tagged items here
    copy_move_link("link")
    @w_r.update = true
  when 'd' # Delete items tagged and @selected
    tagged_info
    w_b_info(" Delete selected and tagged? (press 'd' again to delete)")
    begin
      @tagged.push("\"#{Dir.pwd}/#{@selected}\"")
      @tagged.uniq!
      deletes = @tagged.join(" ")
      `rm -rf #{deletes} 2>/dev/null` if STDIN.getc == 'd'
      items_number = @tagged.length
      @tagged = []
      w_b_info("Deleted #{items_number} items: #{deletes}")
      @w_r.update = true
    rescue StandardError => err
      w_b_info(err.to_s)
    end
  when 'c' # Change/rename selected @selected
    cmd = w_b_getstr(": ", "mv \"#{@selected}\" \"#{@selected}\"")
    begin
      w_b_exec(cmd + " 2>/dev/null")
    rescue StandardError => err
      w_b_info(err.to_s)
    end
    @w_r.update = true
  # DIRECTORY VIEWS
  when 'a' # Show all items
    @lsall == "" ? @lsall = "-a" : @lsall = ""
    @w_r.update = true
    @w_b.update = true
  when 'A' # Show all info for all items
    @lslong = !@lslong
    @w_r.update = true
    @w_b.update = true
  when 'o' # Circular toggle the order/sorting of directory views
    case @lsorder
    when ""
      @lsorder = "-S"
      w_b_info(" Sorting by size, largest first")
    when "-S"
      @lsorder = "-t"
      w_b_info(" Sorting by modification time")
    when "-t"
      @lsorder = "-X"
      w_b_info(" Sorting by extension (alphabetically)")
    when "-X"
      @lsorder = ""
      w_b_info(" Normal sorting")
    end
    @w_r.update  = true
    @orderchange = true
  when 'i' # Invert the order/sorting of directory views
    case @lsinvert
    when ""
      @lsinvert = "-r"
      w_b_info(" Sorting inverted")
    when "-r"
      @lsinvert = ""
      w_b_info(" Sorting NOT inverted")
    end
    @w_r.update  = true
    @orderchange = true
  when 'O' # Show the Ordering in the bottom window (the full ls command)
    w_b_info(" Full 'ls' command: ls <@s> #{@lsbase} #{@lsall} #{@lsorder} #{@lsinvert} #{@lsuser}")
  when 'G' # Git status for selected item or current dir
    @w_r.fg = 214
    if File.exist?(".git")
      w_r_info(`git status 2>/dev/null`)
    else
      w_r_info("This is not a git repository.")
    end
    @w_r.update = false
    @w_b.update = true
  when 'H' # Compare with previous hash status or write hash status if no existing hash
    @w_r.fg = 213
    hashcmd = "\(find #{Dir.pwd} -type f -print0  | sort -z | xargs -0 sha1sum; find #{Dir.pwd}"\
              " \\( -type f -o -type d \\) -print0 | sort -z | xargs -0 stat -c '%n %a'\) | sha1sum | cut -c -40"
    begin
      hashdir = `#{hashcmd}`.chomp
    rescue StandardError => e
      w_r_info("Error: #{e.inspect}")
    end
    hashtime = DateTime.now.strftime "%Y-%m-%d %H:%M"
    if @hash.include?(Dir.pwd)
      if @hash[Dir.pwd][1] == hashdir
        w_b_info(" Hash for #{Dir.pwd} has NOT changed since #{hashtime} (#{hashdir})")
      else
        w_b_info(" Hash for #{Dir.pwd} has CHANGED since #{hashtime} (#{@hash[Dir.pwd][1]} -> #{hashdir})")
        @hash[Dir.pwd] = [hashtime, hashdir]
      end
    else
      hashtime = DateTime.now.strftime "%Y-%m-%d %H:%M"
      @hash[Dir.pwd] = [hashtime, hashdir]
      w_b_info(" New hash for #{Dir.pwd}: #{hashtime}: #{hashdir}")
    end
    @w_r.update = true
    @w_b.update = false
  when 'S' # Show comprehensive system info
    begin
      @w_r.clr
      @w_r.pager_cmd = ""
      uname    = `uname -o`.chomp + "  "
      uname   += `uname -r`.chomp + "  "
      uname   += `uname -v`.chomp + "  "
      uname   += `uname -p`.chomp + "  "
      uname   += `awk -F '"' '/PRETTY/ {print $2}' /etc/os-release` + "\n"
      text     = [[253, 1, uname]]
      system   = "Shell & Terminal: " + `echo $SHELL`.sub(/.*\//, '').chomp + ", " + `echo $TERM`.chomp + "   "
      packages = `pacman -Q 2>/dev/null | wc -l`.chomp
      packages = `dpkg-query -l 2>/dev/null | grep -c '^.i'`.chomp if packages == "0"
      packages = "Unrecognized" if packages == "0"
      system  += "Packages: " + packages + "\n"
      system  += "Desktop: " + `awk '/^DesktopNames/' /usr/share/xsessions/* | sed 's/DesktopNames=//g' | \\
                  sed 's/\\;/\\n/g' | sed '/^$/d' | sort -u | sed ':a;N;$!ba;s/\\n/, /g'`.chomp + "/"
      system  += `grep 'gtk-theme-name' ~/.config/gtk-3.0/* | sed 's/gtk-theme-name=//g' | \\
                  sed 's/-/ /g'`.sub(/.*:/, '') + "\n"
      text    += [[251, 0, system]]
      cpu      = "CPUs = " + `nproc`.chop + "  "
      cpuinfo  = `lscpu`
      cpu     += cpuinfo[/^.*Model name:\s*(.*)/, 1] + "  "
      cpu     += "Max: " + cpuinfo[/^.*CPU max MHz:\s*(.*)/, 1][/(.*),.*/, 1] + "MHz  "
      cpu     += "Min: " + cpuinfo[/^.*CPU min MHz:\s*(.*)/, 1][/(.*),.*/, 1] + "MHz\n\n"
      text    += [[154, 0, cpu]]
      mem      = `free -h`  + "\n"
      text    += [[229, 0, mem]]
      ps       = `ps -eo comm,pid,user,pcpu,pmem,stat --sort -pcpu,-pmem | head` + "\n"
      text    += [[195, 0, ps]]
      disk     = `df -H | head -8`
      text    += [[172, 0, disk]]
      dmesg    = "\nDMESG (latest first):\n"
      dmesg   += `dmesg | tail -6`.split("\n").sort.reverse.join("\n")
      text    += [[219, 0, dmesg]]
      w_r_info(ansifix(text))
    rescue
      w_r_info("Unable to show system info")
    end
  # RIGHT PANE
  when 'ENTER' # Refresh right pane
    @w_r.fill # First clear the window, then clear any previously showing image
    image_show("clear") if @image; @image = false
    @w_r.update = true
    @w_b.update = true
  when 'TAB' # Start paging/Down one page
    if @w_r.pager == 1 and @w_r.pager_cmd != ""
      @w_r.text = `#{@w_r.pager_cmd} 2>/dev/null` 
    end
    if @w_r.pager_more
      @w_r.pager += 1
      pager_show 
    end
    @w_b.update = true
  when 'S-TAB' # Up one page
    if @w_r.pager > 1
      @w_r.pager -= 1
      pager_show
    end
    @w_b.update = true
  when 'w' # Change width of left/right panes
    @width += 1
    @width  = 2 if @width == 7
    @break = true
    @w_b.update = true
  when '-'
    @preview = !@preview
    @preview ? p = "On" : p = "Off"
    w_b_info("Preview = " + p)
    getch
    @break = true
  when '_'
    @showimage = !@showimage
    @showimage ? i = "On" : i = "Off"
    w_b_info("Image preview = " + i)
    getch
    @break = true
  # ADDITIONAL COMMANDS
  when '/' # Get search string to mark items that match the input
    @w_b.nohistory = true
    @searched = w_b_getstr("/ ", "")
    l = `ls #{@lsbase} #{@lsall} #{@lsorder} #{@lsinvert} #{@lsuser}`.split
    m = l.each_index.select{|n| l[n] =~ /#{@searched}/}
    @index = m[0] unless m == []
    @index = 0 if @searched == ""
    @w_r.update = true
  when '\\'
    @searched = ""
  when 'n' # Jump to next occurence of search (after '/')
    l = `ls #{@lsbase} #{@lsall} #{@lsorder} #{@lsinvert} #{@lsuser}`.split
    m = l.each_index.select{|n| l[n] =~ /#{@searched}/}
    i = m.find { |n| n > @index }
    if i == nil
      @index = m.first
    else
      @index = i
    end
    @w_r.update = true
  when 'N' # Jump to previous occurence of search (after '/')
    l = `ls #{@lsbase} #{@lsall} #{@lsorder} #{@lsinvert} #{@lsuser}`.split
    m = l.each_index.select{|n| l[n] =~ /#{@searched}/}.reverse
    i = m.find { |n| n < @index }
    if i == nil
      @index = m.first
    else
      @index = i
    end
    @w_r.update = true
  when ':' # Enter "command mode" in the bottom window - tries to execute the given command
    @w_r.nohistory = false
    cmd = w_b_getstr(": ", "")
    w_b_exec(cmd)
  when ';' # Show command history
    w_r_info("Command history (latest on top):\n\n" + @history.join("\n"))
    @w_b.update = true
  when 'y', 'Y' # Copy path of selected item
    if @selected == nil
      w_b_info(" No selected item path to copy")
    else
      path = Dir.pwd + "/" + @selected
      if chr == 'Y'
        clip = "xclip -selection clipboard" 
        w_b_info(" Path copied to clipboard")
      else
        clip = "xclip"
        w_b_info(" Path copied to primary selection (paste with middle mouse button)")
      end
      system("echo -n '#{path}' | #{clip}")
    end
  when '@' # Enter "Ruby debug"
    @w_b.nohistory = true
    cmd = w_b_getstr("◆ ", "")
    @w_b.clr
    @w_b.refresh
    @w_b.update = true
    @w_r.clr
    info = "Command: #{cmd}\n\n"
    begin
      info += eval(cmd).to_s
    rescue StandardError => e
      info += "Error: #{e.inspect}"
    end
    w_r_info(info)
    @w_r.update = false
  end
  if @w_r.update == true
    @w_r.locate     = false
    @w_r.pager      = 0
    @w_r.pager_more = false
  end
  begin
    @w_r.update = true if dir != Dir.pwd
  rescue
  end
end
mark_latest() click to toggle source
# File bin/rtfm, line 799
def mark_latest
  @marks["5"] = @marks["4"]
  @marks["4"] = @marks["3"]
  @marks["3"] = @marks["2"]
  @marks["2"] = @marks["1"]
  @marks["1"] = @marks["'"]
  @marks["'"] = Dir.pwd
end
marks_info() click to toggle source
# File bin/rtfm, line 1076
def marks_info # SHOW MARKS IN RIGHT WINDOW
  @w_r.fg = 183
  @marks = @marks.sort.to_h
  info = "MARKS:\n"
  unless @marks.empty?
    @marks.each do |mark, dir|
      info += "#{mark} = #{dir}\n"
    end
  else
    info += "(none)"
  end
  w_r_info(info)
end
open_selected(html = nil) click to toggle source
# File bin/rtfm, line 925
def open_selected(html = nil) # OPEN SELECTED ITEM (when pressing RIGHT)
  if File.directory?(@selected) # Rescue for permission error
    begin
      mark_latest
      Dir.chdir(@selected)
    rescue
    end
  else
    begin
      if File.read(@selected).force_encoding("UTF-8").valid_encoding? and not html
        system("exec $EDITOR #{@selected_safe}")
      else
          if @runmailcap
            Thread.new { system("run-mailcap #{@selected_safe} 2>/dev/null") }
          else
            Thread.new { system("xdg-open #{@selected_safe} 2>/dev/null") }
          end
        end
      @break = true
    rescue
    end
  end
end
pager_add_markers() click to toggle source
# File bin/rtfm, line 1160
def pager_add_markers # ADD MARKERS TOP/RIGHT & BOTTOM/RIGHT TO SHOW PAGING AS RELEVANT
  if @w_r.pager > 1
    @w_r.setpos(0, @w_r.maxx - 2)
    @w_r << " ∆"
  end
  if @w_r.pager_more
    @w_r.setpos(@w_r.maxy - 1, @w_r.maxx - 2)
    @w_r << " ∇"
  end
end
pager_show() click to toggle source
# File bin/rtfm, line 1138
def pager_show # SHOW THE CURRENT PAGE CONTENT
  @w_r.setpos(0,0)
  beg_l = (@w_r.pager - 1) * (@w_r.maxy - 5)
  end_l = beg_l + @w_r.maxy - 2
  input = @w_r.text.lines[beg_l..end_l].join() + "\n"
  input.lines.count > @w_r.maxy - 2 ? @w_r.pager_more = true : @w_r.pager_more = false
  if @w_r.text.match(/^\e\[/)
    syntax_highlight(input)
  else
    if @w_r.fg == nil
      init_pair(255, 255, 0)
      @w_r.fg = 255
    else 
      init_pair(@w_r.fg, @w_r.fg, 0)
    end
    @w_r.attr = 0 if @w_r.attr == nil
    @w_r.attron(color_pair(@w_r.fg) | @w_r.attr) { @w_r << input }
  end
  (@w_r.maxy - @w_r.cury).times {@w_r.deleteln()} # Clear to bottom of window
  pager_add_markers
  @w_r.refresh
end
pager_start() click to toggle source
# File bin/rtfm, line 1132
def pager_start # START PAGING
  @w_r.pager = 1
  if @w_r.text.lines.count > @w_r.maxy - 2
    @w_r.pager_more = true
  end
end
syntax_highlight(input) click to toggle source
# File bin/rtfm, line 238
def syntax_highlight(input) # SYNTAX HIGHLIGHTING FROM ANSI COLOR CODES
  color_ary  = color_parse(input)
  color_ary.each do | pair |
    begin
      fg   = pair[0].to_i
      atr  = pair[1].to_i
      atr == 1 ? atr = Curses::A_BOLD : atr = 0
      text = pair[2]
      text.gsub!(/\t/, '')
      init_pair(fg, fg, 0)
      @w_r.attron(color_pair(fg) | atr) { @w_r << text }
    rescue
    end
  end
end
tagged_info() click to toggle source
# File bin/rtfm, line 1089
def tagged_info # SHOW THE LIST OF TAGGED ITEMS IN @w_r
  info = "TAGGED:\n"
  @tagged.empty? ? info += "(None)" : info += @tagged.join("\n")
  w_r_info(info)
end
var_resets() click to toggle source
# File bin/rtfm, line 1170
def var_resets # RESET PAGER VARIABLES
    @pager      = 0
    @pager_more = false
    @pager_cmd  = ""
    @info       = false
end
w_b_exec(cmd) click to toggle source
# File bin/rtfm, line 1307
def w_b_exec(cmd) # EXECUTE COMMAND FROM @W_B
  # Subsitute any '@s' with the selected item, @t with tagged items
  # 'rm @s' deletes the selected item, 'rm @t' deletes tagged items
  return if cmd == ""
  @s = "\"#{Dir.pwd}/#{@selected}\""
  cmd.gsub!(/@s/, @s)
  @t = @tagged.join(" ")
  cmd.gsub!(/@t/, @t)
  if cmd.match(/^cd /)
    cmd.sub!(/^cd (\S*).*/, '\1')
    Dir.chdir(cmd) if Dir.exist?(cmd)
    return
  end
  begin
    status = Timeout::timeout(15) {
      @w_r.clr
      begin
        @w_r.pager_cmd = "#{cmd} | #{@bat} -n --color=always 2>/dev/null"
        @w_r.text = `#{@w_r.pager_cmd} 2>/dev/null`
      rescue
        @w_r.pager_cmd = "#{cmd} 2>/dev/null"
        @w_r.text = `#{@w_r.pager_cmd} 2>/dev/null`
      end
      unless @w_r.text == "" or @w_r.text == nil
        pager_start
        pager_show
        @w_r.update = false
      else
        @w_r.update = true
      end
    }
  rescue
    w_b_info(" Failed to execute command (#{cmd})")
  end
end
w_b_getstr(pretext, text) click to toggle source
# File bin/rtfm, line 1186
def w_b_getstr(pretext, text) # A SIMPLE READLINE-LIKE ROUTINE
  Curses.curs_set(1)
  Curses.echo
  stk = 0
  @history.insert(stk, text)
  pos = @history[stk].length
  chr = ""
  while chr != "ENTER"
    @w_b.setpos(0,0)
    init_pair(250, 250, 238)
    text = pretext + @history[stk]
    text += " " * (@w_b.maxx - text.length) if text.length < @w_b.maxx
    @w_b.attron(color_pair(250)) { @w_b << text }
    @w_b.setpos(0,pretext.length + pos)
    @w_b.refresh
    chr = getchr
    if chr == "C-G"
      Curses.curs_set(0)
      Curses.noecho
      @w_b.update = true
      return "" 
    end
    case chr
    when 'UP'
      unless @w_b.nohistory
        unless stk == @history.length - 1
          stk += 1 
          pos = @history[stk].length
        end
      end
    when 'DOWN'
      unless @w_b.nohistory
        unless stk == 0
          stk -= 1 
          pos = @history[stk].length
        end
      end
    when 'RIGHT'
      pos += 1 unless pos > @history[stk].length
    when 'LEFT'
      pos -= 1 unless pos == 0
    when 'HOME'
      pos = 0
    when 'END'
      pos = @history[stk].length
    when 'DEL'
      @history[stk][pos] = ""
    when 'BACK'
      unless pos == 0
        pos -= 1
        @history[stk][pos] = ""
      end
    when 'WBACK'
      unless pos == 0
        until @history[stk][pos - 1] == " " or pos == 0
          pos -= 1
          @history[stk][pos] = ""
        end
        if @history[stk][pos - 1] == " "
          pos -= 1
          @history[stk][pos] = ""
        end
      end
    when 'LDEL'
      @history[stk] = ""
      pos = 0
    when 'TAB' # Tab completion of dirs and files
      p1 = pos - 1
      c  = @history[stk][0..(p1)].sub(/^.* /, '')
      p0 = p1 - c.length
      compl = File.expand_path(c)
      compl += "/" if Dir.exist?(compl)
      clist = Dir.glob(compl + "*")
      unless compl == clist[0].to_s and clist.length == 1
        if clist.length == 1
          compl = clist[0].to_s
        else
          ix = clist.find_index(compl)
          ix = 0 if ix == nil
          sel_item = ""
          begin
            Curses.curs_set(0)
            Curses.noecho
            @w_r.clr
            @w_r << "Completion list:\n\n"
            clist.each.with_index do |item, index|
              if index == ix
                @w_r.attron(Curses::A_BLINK) { @w_r << item }
                sel_item = item
              else
                @w_r << item
              end
              @w_r << "\n"
            end
            @w_r.refresh
            ix == clist.length ? ix = 0 : ix += 1
          end while getchr == 'TAB'
          compl = sel_item
          @w_r.clr
          Curses.curs_set(1)
          Curses.echo
        end
      end
      @history[stk].sub!(c,compl)
      pos = pos - c.length + compl.length
    when /^.$/
      @history[stk].insert(pos,chr)
      pos += 1
    end
  end
  curstr = @history[stk]
  @history.shift if @w_b.nohistory
  unless @w_b.nohistory
    @history.uniq!
    @history.compact!
    @history.delete("")
  end
  Curses.curs_set(0)
  Curses.noecho
  return curstr
end
w_b_info(info) click to toggle source

BOTTOM WINDOW FUNCTIONS

# File bin/rtfm, line 1177
def w_b_info(info) # SHOW INFO IN @W_B
  @w_b.clr
  info      = ": for command (use @s for selected item, @t for tagged items)" if info == nil
  info      = info[1..(@w_b.maxx - 3)] + "…" if info.length + 3 > @w_b.maxx 
  info     += " " * (@w_b.maxx - info.length) if info.length < @w_b.maxx
  @w_b.text = info
  @w_b.write
  @w_b.update = false
end
w_r_doc() click to toggle source
# File bin/rtfm, line 1056
def w_r_doc # GET FULL CONTENT TO PAGE
  @w_r.text = `#{@w_r.pager_cmd} 2>/dev/null`
  pager_start 
  @w_r << @w_r.text
end
w_r_info(info) click to toggle source
# File bin/rtfm, line 1061
def w_r_info(info) # SHOW INFO IN THE RIGHT WINDOW
  image_show("clear") if @image; @image = false
  @w_r.clr
  @w_r. refresh
  w_r_width = Curses.cols - (Curses.cols/@width) - 1
  info = info.split("\n")
  l = []
  info.each{ |e| l << e.scan(/.{,#{w_r_width}}/)[0..-2] }
  info = l.join("\n")
  @w_r.text      = info
  @w_r.pager_cmd = ""
  pager_start
  pager_show
  @w_r.update = false
end
w_r_show() click to toggle source

RIGHT WINDOW FUNCTIONS

# File bin/rtfm, line 977
def w_r_show # SHOW CONTENTS IN THE RIGHT WINDOW
  if @w_r.update
    @w_r.clr # First clear the window, then clear any previously showing image
    image_show("clear") if @image; @image = false
  end
  begin # Determine the specific programs to open/show content
    if @w_r.pager > 0
      pager_show 
    elsif File.directory?(@selected)
      ls_cmd  = "ls #{@selected_safe} #{@lsbase} #{@lsall} #{@lsorder} #{@lsinvert} #{@lsuser}"
      @files  = `#{ls_cmd} 2>/dev/null`.split("\n")
      ls_cmd += %q[ -lhgGH --time-style="long-iso" | awk '{printf "%s%12s%6s%6s%5s", $1,$4,$5,$3,$2 "\n"}']
      @fspes  = `#{ls_cmd} 2>/dev/null`.split("\n").drop(1)
      list_dir(false)
    # TEXT
    elsif File.read(@selected).force_encoding("UTF-8").valid_encoding? and @w_r.pager == 0
      begin # View the file as text if it is utf-8
        @w_r.pager_cmd = "#{@bat} -n --color=always #{@selected_safe} 2>/dev/null"
        @w_r.text      = `#{@bat} -n --color=always --line-range :#{@w_r.maxy} #{@selected_safe} 2>/dev/null`
        pager_start
        syntax_highlight(@w_r.text)
      rescue
        @w_r.pager_cmd  = "cat #{@selected_safe} 2>/dev/null"
        w_r_doc
      end
    # PDF
    elsif @selected.match(@pdffile) and @w_r.pager == 0
      @w_r.pager_cmd  = "pdftotext #{@selected_safe} - 2>/dev/null | less"
      @w_r.text       = `pdftotext -f 1 -l 4 #{@selected_safe} - 2>/dev/null`
      pager_start 
      @w_r << @w_r.text
    # OPEN/LIBREOFFICE
    elsif @selected.match(@oolofile) and @w_r.pager == 0
      @w_r.pager_cmd  = "odt2txt #{@selected_safe} 2>/dev/null"
      w_r_doc
    # MS DOCX
    elsif @selected.match(@docxfile) and @w_r.pager == 0
      @w_r.pager_cmd  = "docx2txt #{@selected_safe} - 2>/dev/null"
      w_r_doc
    # MS XLSX
    elsif @selected.match(@xlsxfile) and @w_r.pager == 0
      @w_r.pager_cmd  = "ssconvert -O 'separator=   ' -T Gnumeric_stf:stf_assistant #{@selected_safe} fd://1 2>/dev/null"
      w_r_doc
    # MS PPTX
    elsif @selected.match(@pptxfile) and @w_r.pager == 0
      @w_r.pager_cmd  = %Q[unzip -qc #{@selected_safe} | ruby -e '$stdin.each_line { |i| i.force_encoding("ISO-8859-1").scan(/<a:t>(.+?)<\\/a:t>/).each { |j| puts(j) } }' 2>/dev/null]
      w_r_doc
    # MS DOC
    elsif @selected.match(@docfile) and @w_r.pager == 0
      @w_r.pager_cmd  = "catdoc #{@selected_safe} 2>/dev/null"
      w_r_doc
    # MS XLS
    elsif @selected.match(@xlsfile) and @w_r.pager == 0
      @w_r.pager_cmd  = "xls2csv #{@selected_safe} 2>/dev/null"
      w_r_doc
    # MS PPT
    elsif @selected.match(@pptfile) and @w_r.pager == 0
      @w_r.pager_cmd  = "catppt #{@selected_safe} 2>/dev/null"
      w_r_doc
    # IMAGES
    elsif @selected.match(@imagefile)
      image_show(@selected_safe)
      @image = true
    # VIDEOS (THUMBNAILS)
    elsif @selected.match(/\.mpg$|\.mpeg$|\.avi$|\.mov$|\.mkv$|\.mp4$/)
      begin
        tmpfile = "/tmp/" + File.basename(@selected_safe,".*")
        `ffmpegthumbnailer -s 1200 -i #{@selected_safe} -o /tmp/rtfm_video_tn.jpg 2>/dev/null`
        image_show("/tmp/rtfm_video_tn.jpg")
        @image = true
      rescue
      end
    end
  rescue
  end
  pager_add_markers # Add page markers, up and/or down
  @w_r.update = false
  @w_r.refresh
end
w_t_info() click to toggle source

TOP WINDOW FUNCTIONS

# File bin/rtfm, line 808
def w_t_info # SHOW INFO IN @w_t
  text  = " " + ENV['USER'].to_s + "@" + `hostname 2>/dev/null`.to_s.chop + ": " + Dir.pwd + "/"
  unless @selected == nil
    text += @selected
    text += " → #{File.readlink(@selected)}" if File.symlink?(@selected) 
  end
  begin
    text += " (#{@fspes[@index]})" 
  rescue
  end
  begin
    if @selected.match(@imagefile)
      text += `identify #{@selected_safe} | awk '{printf " [%s %s %s %s] ", $3,$2,$5,$6}' 2>/dev/null` if cmd?('identify')
    elsif @selected.match(@pdffile)
      info  = `pdfinfo #{@selected_safe} 2>/dev/null`
      text += " [" + info.match(/Pages:.*?(\d+)/)[1] 
      text += " "  + info.match(/Page size:.*\((.*)\)/)[1] + " pages] "
    end
  rescue
  end
  if Dir.exist?(@selected.to_s)
    begin
      text += " [" + Dir.glob(@selected+"/*").count.to_s + " " + Dir.children(@selected).count.to_s + "]"
    rescue
      text += " [Denied]"
    end
  end
  text  = text[1..(@w_t.maxx - 3)] + "…" if text.length + 3 > @w_t.maxx 
  text += " " * (@w_t.maxx - text.length) if text.length < @w_t.maxx
  @w_t.clr
  @w_t.text = text
  @w_t.write
end