--- /dev/null
+#!/usr/bin/env ruby
+
+require "time"
+require "ncurses"
+require "inifile"
+require "open3"
+
+class IO
+ def readline_nonblock
+ buffer = ""
+ buffer << read_nonblock(1) while buffer[-1] != "\n"
+ buffer
+ rescue IO::WaitReadable => blocking
+ if (not buffer.empty?)
+ ungetc(buffer)
+ end
+ raise blocking
+ end
+end
+
+class List_Win
+ def initialize(inifile)
+ @params = inifile
+ @win = Ncurses::WINDOW.new(0, Ncurses.COLS()/4, 0, 0)
+ @win.border(*([0]*8))
+ @win.keypad(true)
+ @win.timeout(1000)
+ @win.refresh()
+ @entry = 0
+ end
+
+ def getch()
+ @win.getch()
+ end
+ def clear()
+ @win.clear()
+ end
+ def resize(x,y)
+ @win.resize(x,y)
+ end
+ def move(x,y)
+ @win.move(x,y)
+ end
+ def refresh()
+ @win.refresh()
+ end
+
+ def print_list(entry=nil)
+ if(not entry.nil?)
+ @entry = entry
+ end
+ i = 0
+ @params.each_section do |section|
+ if(@entry == i)
+ @win.attron(Ncurses::A_REVERSE)
+ end
+ @win.move(i+1,1)
+ print_line(@win,@params[section]['Name'])
+ if(@entry == i)
+ @win.attroff(Ncurses::A_REVERSE)
+ end
+ i = i+1
+ end
+ @win.border(*([0]*8))
+ @win.move(0,3)
+ @win.addstr("Menu")
+ @win.refresh()
+ end
+end
+
+class Buff_Win
+ def initialize(winsize,winpos,params)
+ @params = params
+ @win = Ncurses::WINDOW.new(0, winsize, 0, winpos)
+ @panel = Ncurses::Panel::PANEL.new(@win)
+ if(@params['Type'] == 'oneshot')
+ @buffer = Buffer.new(0)
+ else
+ @buffer = Buffer.new(@params['Buffer'].to_i)
+ end
+ @proc = nil
+ @curr_offset = 0
+ @hscroll = 0
+ update_date()
+
+ spawn_proc()
+ print_buffer()
+ end
+
+ def move_resize(winsize,winpos)
+ newwin = Ncurses::WINDOW.new(0, winsize, 0, winpos)
+ Ncurses::Panel.replace_panel(@panel, newwin)
+ Ncurses.delwin(@win)
+ @win = newwin
+ print_buffer()
+ end
+ def update_date()
+ @last_update = Time.now
+ @date = @last_update.strftime("%F %R:%S")
+ end
+
+ def win_border()
+ @win.border(*([0]*8))
+ win_header()
+ end
+ def win_header()
+ @win.move(0,3)
+ @win.addnstr(@params['Name'],@win.getmaxx-@date.length-10)
+ @win.move(0,@win.getmaxx-@date.length-2)
+ @win.addstr(@date)
+ end
+ def refresh()
+ @win.refresh()
+ end
+ def clear()
+ @win.clear()
+ end
+
+ def show_win()
+ Ncurses::Panel.top_panel(@panel)
+ Ncurses::Panel.update_panels
+ end
+
+ def hscroll(scroll=0)
+ @hscroll += scroll
+ if(@hscroll < 0)
+ @hscroll = 0
+ end
+ if(@hscroll > @buffer.maxlen()-@win.getmaxx+3)
+ @hscroll = @buffer.maxlen()-@win.getmaxx+3
+ end
+ print_buffer()
+ refresh()
+ end
+ def scroll(scroll=0,goto=nil,fact=nil)
+ if (not fact.nil?)
+ scroll = (fact * @win.getmaxy.to_f).to_i
+ elsif (not goto.nil?)
+ @curr_offset = (goto * @buffer.size()).to_i
+ scroll = 0
+ end
+ #@curr_offset -= @win.getmaxy/2
+ @curr_offset += scroll
+ if(@curr_offset < 0)
+ @curr_offset = 0
+ end
+ if(@curr_offset > @buffer.size()-@win.getmaxy+2)
+ @curr_offset = @buffer.size()-@win.getmaxy+2
+ end
+ print_buffer()
+ refresh()
+ end
+
+ def print_buffer()
+ win_border()
+ j = 1
+ @buffer.yield(@win.getmaxy-2,@curr_offset) { |l,type|
+ @win.move(j,1)
+ if(type == 1) then @win.attron(Ncurses.COLOR_PAIR(1)) end
+ print_line(@win,l,hscroll=@hscroll)
+ if(type == 1) then @win.attroff(Ncurses.COLOR_PAIR(1)) end
+ j = j+1
+ }
+ if(@buffer.has_before?)
+ @win.move(2,@win.getmaxx-1)
+ @win.attron(Ncurses::A_REVERSE)
+ @win.addstr("↑")
+ @win.attroff(Ncurses::A_REVERSE)
+ end
+ if(@buffer.has_after?)
+ @win.move(@win.getmaxy-2,@win.getmaxx-1)
+ @win.attron(Ncurses::A_REVERSE)
+ @win.addstr("↓")
+ @win.attroff(Ncurses::A_REVERSE)
+ end
+ end
+
+ def proc_readlines()
+ begin
+ while true
+ @buffer.push(@proc.readline_nonblock)
+ update_date()
+ end
+ rescue IO::WaitReadable
+ end
+ end
+
+ def update()
+ if(@params['Type'] == 'continuous')
+ proc_readlines()
+ end
+ if(@params['Type'] == 'oneshot')
+ if(Time.now - @last_update > @params['Periodic'].to_i)
+ @buffer.clear()
+ spawn_proc()
+ end
+ end
+ print_buffer()
+ end
+
+ def spawn_proc()
+ if(@params['Type'] == 'oneshot')
+ update_date()
+ Open3.popen3(@params["Command"]) { |i,o,e,t|
+ while ((not o.eof?) or (not e.eof?))
+ rs = IO.select([o,e],nil)[0]
+ r = (rs[0].eof?)? rs[1] : rs[0]
+
+ if r.fileno == o.fileno
+ @buffer.push(r.readline)
+ elsif r.fileno == e.fileno
+ @buffer.push(r.readline,type=1)
+ end
+ end
+ }
+ elsif(@params['Type'] == 'continuous')
+ @proc = IO.popen(@params["Command"])
+ proc_readlines()
+ end
+ end
+end
+
+class Buffer
+ def initialize(size)
+ @size = size
+ @buff = []
+ @buff_type = []
+ @current = 0
+ @wrap = false
+ @before = false
+ @after = false
+ end
+ def size()
+ return @buff.length
+ end
+ def maxlen()
+ maxlen = 0
+ @buff.each do |string|
+ if string.length > maxlen
+ maxlen = string.length
+ end
+ end
+ return maxlen
+ end
+
+ def push(string,type=0)
+ if(string.chomp.empty?) then string = " " end
+ string.split( /\r?\n/ ).each do |line|
+ @buff[@current] = line
+ @buff_type[@current] = type
+ if(@size > 0)
+ @current = (1+@current) % @size
+ else
+ @current = 1+@current
+ end
+ if(@current == 0) then @wrap = true end
+ end
+ end
+ def yield(size,offset=0,&block)
+ range = Range.new(0,@current-1).to_a
+ if(@wrap)
+ range = Range.new(@current,@size-1).to_a + range
+ end
+ range = range.last(size+offset)[0,size]
+ @before = (size+offset < @buff.length)
+ @after = (offset != 0 and size < @buff.length)
+ if(block)
+ range.each do |i|
+ yield [@buff[i],@buff_type[i]]
+ end
+ else
+ return range.collect{|r| [@buff[r],@buff_type[r]]}
+ end
+ end
+ def has_after?()
+ return @after
+ end
+ def has_before?()
+ return @before
+ end
+ def clear()
+ @current = 0
+ @buff = []
+ @buff_type = []
+ end
+end
+
+def read_ini()
+ inifile = IniFile.load('monitorrc')
+ return inifile
+end
+
+def print_line(win, str, hscroll=0)
+ if(hscroll > 0)
+ strcut = str[hscroll,str.length]
+ if(strcut.nil? or strcut.empty?)
+ str = ""
+ else
+ str = "…"+strcut
+ end
+ end
+ strlen = str.length
+ winlen = win.getmaxx-win.getcurx-1
+ if(strlen <= winlen)
+ win.addstr(str + " "*(winlen-strlen))
+ else
+ win.addstr(str[0,winlen-1]+"…")
+ end
+end
+
+def make_bufwins(inifile)
+ bufwins = []
+ inifile.each_section do |section|
+ bufwin = Buff_Win.new(Ncurses.COLS()-Ncurses.COLS()/4,
+ Ncurses.COLS()/4,
+ inifile[section])
+ bufwins.push(bufwin)
+ end
+ return bufwins
+end
+
+def update_buffers(bufwins)
+ bufwins.each do |bufwin|
+ bufwin.update()
+ end
+end
+
+def redraw_all(list,bufwins,curr_bufwin)
+ bufwins.each do |bufwin|
+ bufwin.move_resize(Ncurses.COLS()-Ncurses.COLS()/4,Ncurses.COLS()/4)
+ end
+ list.resize(Ncurses.LINES(), Ncurses.COLS()/4)
+ list.clear()
+ list.print_list()
+ list.refresh()
+ curr_bufwin.refresh()
+end
+begin
+ # initialize ncurses
+ Ncurses.initscr
+ Ncurses.start_color
+ Ncurses.cbreak # provide unbuffered input
+ Ncurses.noecho # turn off input echoing
+ #Ncurses.nonl # turn off newline translation
+ #Ncurses.stdscr.intrflush(false) # turn off flush-on-interrupt
+ Ncurses.stdscr.keypad(true) # turn on keypad mode
+ Ncurses.init_pair(1, Ncurses::COLOR_RED, Ncurses::COLOR_BLACK)
+
+
+ inifile = read_ini()
+
+ list = List_Win.new(inifile)
+ bufwins = make_bufwins(inifile)
+ entry = 0
+ cur_bufwin = bufwins[entry]
+ cur_bufwin.show_win()
+ list.print_list()
+ while(ch = list.getch()) do
+ case(ch)
+ when "n".ord
+ entry = (entry +1) % bufwins.length
+ cur_bufwin = bufwins[entry]
+ cur_bufwin.show_win()
+ list.print_list(entry=entry)
+ when "p".ord
+ entry = (entry -1) % bufwins.length
+ cur_bufwin = bufwins[entry]
+ cur_bufwin.show_win()
+ list.print_list(entry=entry)
+ when 12 #ctrl+L
+ redraw_all(list,bufwins,cur_bufwin)
+ when Ncurses::KEY_RESIZE
+ redraw_all(list,bufwins,cur_bufwin)
+ when Ncurses::KEY_LEFT
+ cur_bufwin.hscroll(scroll=-1)
+ when Ncurses::KEY_RIGHT
+ cur_bufwin.hscroll(scroll=1)
+ when Ncurses::KEY_DOWN
+ cur_bufwin.scroll(scroll=-1)
+ when Ncurses::KEY_UP
+ cur_bufwin.scroll(scroll=1)
+ when Ncurses::KEY_NPAGE
+ cur_bufwin.scroll(scroll=0,goto=nil,fact=-0.75)
+ when Ncurses::KEY_PPAGE
+ cur_bufwin.scroll(scroll=0,goto=nil,fact=0.75)
+ when Ncurses::KEY_HOME
+ cur_bufwin.scroll(scroll=0,goto=1.0)
+ when Ncurses::KEY_END
+ cur_bufwin.scroll(scroll=0,goto=0.0)
+ when Ncurses::ERR
+ update_buffers(bufwins)
+ cur_bufwin.show_win()
+ when "q".ord
+ break
+ else
+ next
+ end
+ end
+
+ensure
+ Ncurses.echo
+ Ncurses.nocbreak
+ Ncurses.nl
+ Ncurses.endwin
+end