| #!/usr/local/bin/ruby |
| |
| require "curses" |
| |
| |
| # A curses based file viewer |
| class FileViewer |
| |
| # Create a new fileviewer, and view the file. |
| def initialize(filename) |
| @data_lines = [] |
| @screen = nil |
| @top = nil |
| init_curses |
| load_file(filename) |
| interact |
| end |
| |
| # Perform the curses setup |
| def init_curses |
| # signal(SIGINT, finish) |
| |
| Curses.init_screen |
| Curses.nonl |
| Curses.cbreak |
| Curses.noecho |
| |
| @screen = Curses.stdscr |
| |
| @screen.scrollok(true) |
| #$screen.keypad(true) |
| end |
| |
| # Load the file into memory, and put |
| # the first part on the curses display. |
| def load_file(filename) |
| fp = open(filename, "r") do |fp| |
| # slurp the file |
| fp.each_line { |l| |
| @data_lines.push(l.chop) |
| } |
| end |
| @top = 0 |
| @data_lines[0..@screen.maxy-1].each_with_index{|line, idx| |
| @screen.setpos(idx, 0) |
| @screen.addstr(line) |
| } |
| @screen.setpos(0,0) |
| @screen.refresh |
| rescue |
| raise "cannot open file '#{filename}' for reading" |
| end |
| |
| |
| # Scroll the display up by one line |
| def scroll_up |
| if( @top > 0 ) |
| @screen.scrl(-1) |
| @top -= 1 |
| str = @data_lines[@top] |
| if( str ) |
| @screen.setpos(0, 0) |
| @screen.addstr(str) |
| end |
| return true |
| else |
| return false |
| end |
| end |
| |
| # Scroll the display down by one line |
| def scroll_down |
| if( @top + @screen.maxy < @data_lines.length ) |
| @screen.scrl(1) |
| @top += 1 |
| str = @data_lines[@top + @screen.maxy - 1] |
| if( str ) |
| @screen.setpos(@screen.maxy - 1, 0) |
| @screen.addstr(str) |
| end |
| return true |
| else |
| return false |
| end |
| end |
| |
| # Allow the user to interact with the display. |
| # This uses EMACS-like keybindings, and also |
| # vi-like keybindings as well, except that left |
| # and right move to the beginning and end of the |
| # file, respectively. |
| def interact |
| while true |
| result = true |
| c = Curses.getch |
| case c |
| when Curses::KEY_DOWN, Curses::KEY_CTRL_N, ?j |
| result = scroll_down |
| when Curses::KEY_UP, Curses::KEY_CTRL_P, ?k |
| result = scroll_up |
| when Curses::KEY_NPAGE, ?\s # white space |
| for i in 0..(@screen.maxy - 2) |
| if( ! scroll_down ) |
| if( i == 0 ) |
| result = false |
| end |
| break |
| end |
| end |
| when Curses::KEY_PPAGE |
| for i in 0..(@screen.maxy - 2) |
| if( ! scroll_up ) |
| if( i == 0 ) |
| result = false |
| end |
| break |
| end |
| end |
| when Curses::KEY_LEFT, Curses::KEY_CTRL_T, ?h |
| while( scroll_up ) |
| end |
| when Curses::KEY_RIGHT, Curses::KEY_CTRL_B, ?l |
| while( scroll_down ) |
| end |
| when ?q |
| break |
| else |
| @screen.setpos(0,0) |
| @screen.addstr("[unknown key `#{Curses.keyname(c)}'=#{c}] ") |
| end |
| if( !result ) |
| Curses.beep |
| end |
| @screen.setpos(0,0) |
| end |
| Curses.close_screen |
| end |
| end |
| |
| |
| # If we are being run as a main program... |
| if __FILE__ == $0 |
| if ARGV.size != 1 then |
| printf("usage: #{$0} file\n"); |
| exit |
| end |
| |
| viewer = FileViewer.new(ARGV[0]) |
| end |