require "time" 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 Ncurses::WINDOW def print_line(str, hscroll=0) revert_color = false str[0,5].match(/\033\[3(.)m/) { |c| #Line starts with an escape sequence. We handle that `a la xterm` Ncurses.init_pair(10, c[1].to_i, Ncurses::COLOR_BLACK) self.attron(Ncurses.COLOR_PAIR(10)) revert_color = true str = str[5,str.length] } str = str.gsub("\011"," ") #Any other control char is ignored and escaped str = str.gsub(/[[:cntrl:]]/) { |m| "^"+(m.ord + 64).chr } if(hscroll > 0) strcut = str[hscroll,str.length] if(strcut.nil? or strcut.empty?) str = "" else str = "…"+strcut end end strlen = str.length winlen = self.getmaxx-self.getcurx-1 if(strlen <= winlen) self.addstr(str + " "*(winlen-strlen)) else self.addstr(str[0,winlen-1]+"…") end if(revert_color) self.attroff(Ncurses.COLOR_PAIR(10)) end end end class List_Win def initialize(sections, size) @params = sections @win = Ncurses::WINDOW.new(0, size*Ncurses.COLS()/100, 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_name,section| if(@entry == i) @win.attron(Ncurses::A_REVERSE) end @win.move(i+1,1) @win.print_line(section['Name']) if(@entry == i) @win.attroff(Ncurses::A_REVERSE) end i = i+1 } @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() #clear() 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 @win.print_line(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(force=false) if(@params['Type'] == 'continuous') proc_readlines() end if(@params['Type'] == 'oneshot') if(force or (Time.now - @last_update > @params['Periodic'].to_i)) @buffer.clear() spawn_proc() clear() 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