]>
Commit | Line | Data |
---|---|---|
8b6154e9 I |
1 | #!/usr/bin/env ruby |
2 | ||
3 | require "time" | |
4 | require "ncurses" | |
5 | require "inifile" | |
6 | require "open3" | |
7 | ||
8 | class IO | |
9 | def readline_nonblock | |
10 | buffer = "" | |
11 | buffer << read_nonblock(1) while buffer[-1] != "\n" | |
12 | buffer | |
13 | rescue IO::WaitReadable => blocking | |
14 | if (not buffer.empty?) | |
15 | ungetc(buffer) | |
16 | end | |
17 | raise blocking | |
18 | end | |
19 | end | |
20 | ||
21 | class List_Win | |
22 | def initialize(inifile) | |
23 | @params = inifile | |
24 | @win = Ncurses::WINDOW.new(0, Ncurses.COLS()/4, 0, 0) | |
25 | @win.border(*([0]*8)) | |
26 | @win.keypad(true) | |
27 | @win.timeout(1000) | |
28 | @win.refresh() | |
29 | @entry = 0 | |
30 | end | |
31 | ||
32 | def getch() | |
33 | @win.getch() | |
34 | end | |
35 | def clear() | |
36 | @win.clear() | |
37 | end | |
38 | def resize(x,y) | |
39 | @win.resize(x,y) | |
40 | end | |
41 | def move(x,y) | |
42 | @win.move(x,y) | |
43 | end | |
44 | def refresh() | |
45 | @win.refresh() | |
46 | end | |
47 | ||
48 | def print_list(entry=nil) | |
49 | if(not entry.nil?) | |
50 | @entry = entry | |
51 | end | |
52 | i = 0 | |
53 | @params.each_section do |section| | |
54 | if(@entry == i) | |
55 | @win.attron(Ncurses::A_REVERSE) | |
56 | end | |
57 | @win.move(i+1,1) | |
58 | print_line(@win,@params[section]['Name']) | |
59 | if(@entry == i) | |
60 | @win.attroff(Ncurses::A_REVERSE) | |
61 | end | |
62 | i = i+1 | |
63 | end | |
64 | @win.border(*([0]*8)) | |
65 | @win.move(0,3) | |
66 | @win.addstr("Menu") | |
67 | @win.refresh() | |
68 | end | |
69 | end | |
70 | ||
71 | class Buff_Win | |
72 | def initialize(winsize,winpos,params) | |
73 | @params = params | |
74 | @win = Ncurses::WINDOW.new(0, winsize, 0, winpos) | |
75 | @panel = Ncurses::Panel::PANEL.new(@win) | |
76 | if(@params['Type'] == 'oneshot') | |
77 | @buffer = Buffer.new(0) | |
78 | else | |
79 | @buffer = Buffer.new(@params['Buffer'].to_i) | |
80 | end | |
81 | @proc = nil | |
82 | @curr_offset = 0 | |
83 | @hscroll = 0 | |
84 | update_date() | |
85 | ||
86 | spawn_proc() | |
87 | print_buffer() | |
88 | end | |
89 | ||
90 | def move_resize(winsize,winpos) | |
91 | newwin = Ncurses::WINDOW.new(0, winsize, 0, winpos) | |
92 | Ncurses::Panel.replace_panel(@panel, newwin) | |
93 | Ncurses.delwin(@win) | |
94 | @win = newwin | |
95 | print_buffer() | |
96 | end | |
97 | def update_date() | |
98 | @last_update = Time.now | |
99 | @date = @last_update.strftime("%F %R:%S") | |
100 | end | |
101 | ||
102 | def win_border() | |
103 | @win.border(*([0]*8)) | |
104 | win_header() | |
105 | end | |
106 | def win_header() | |
107 | @win.move(0,3) | |
108 | @win.addnstr(@params['Name'],@win.getmaxx-@date.length-10) | |
109 | @win.move(0,@win.getmaxx-@date.length-2) | |
110 | @win.addstr(@date) | |
111 | end | |
112 | def refresh() | |
113 | @win.refresh() | |
114 | end | |
115 | def clear() | |
116 | @win.clear() | |
117 | end | |
118 | ||
119 | def show_win() | |
120 | Ncurses::Panel.top_panel(@panel) | |
121 | Ncurses::Panel.update_panels | |
122 | end | |
123 | ||
124 | def hscroll(scroll=0) | |
125 | @hscroll += scroll | |
126 | if(@hscroll < 0) | |
127 | @hscroll = 0 | |
128 | end | |
129 | if(@hscroll > @buffer.maxlen()-@win.getmaxx+3) | |
130 | @hscroll = @buffer.maxlen()-@win.getmaxx+3 | |
131 | end | |
132 | print_buffer() | |
133 | refresh() | |
134 | end | |
135 | def scroll(scroll=0,goto=nil,fact=nil) | |
136 | if (not fact.nil?) | |
137 | scroll = (fact * @win.getmaxy.to_f).to_i | |
138 | elsif (not goto.nil?) | |
139 | @curr_offset = (goto * @buffer.size()).to_i | |
140 | scroll = 0 | |
141 | end | |
142 | #@curr_offset -= @win.getmaxy/2 | |
143 | @curr_offset += scroll | |
144 | if(@curr_offset < 0) | |
145 | @curr_offset = 0 | |
146 | end | |
147 | if(@curr_offset > @buffer.size()-@win.getmaxy+2) | |
148 | @curr_offset = @buffer.size()-@win.getmaxy+2 | |
149 | end | |
150 | print_buffer() | |
151 | refresh() | |
152 | end | |
153 | ||
154 | def print_buffer() | |
155 | win_border() | |
156 | j = 1 | |
157 | @buffer.yield(@win.getmaxy-2,@curr_offset) { |l,type| | |
158 | @win.move(j,1) | |
159 | if(type == 1) then @win.attron(Ncurses.COLOR_PAIR(1)) end | |
160 | print_line(@win,l,hscroll=@hscroll) | |
161 | if(type == 1) then @win.attroff(Ncurses.COLOR_PAIR(1)) end | |
162 | j = j+1 | |
163 | } | |
164 | if(@buffer.has_before?) | |
165 | @win.move(2,@win.getmaxx-1) | |
166 | @win.attron(Ncurses::A_REVERSE) | |
167 | @win.addstr("↑") | |
168 | @win.attroff(Ncurses::A_REVERSE) | |
169 | end | |
170 | if(@buffer.has_after?) | |
171 | @win.move(@win.getmaxy-2,@win.getmaxx-1) | |
172 | @win.attron(Ncurses::A_REVERSE) | |
173 | @win.addstr("↓") | |
174 | @win.attroff(Ncurses::A_REVERSE) | |
175 | end | |
176 | end | |
177 | ||
178 | def proc_readlines() | |
179 | begin | |
180 | while true | |
181 | @buffer.push(@proc.readline_nonblock) | |
182 | update_date() | |
183 | end | |
184 | rescue IO::WaitReadable | |
185 | end | |
186 | end | |
187 | ||
188 | def update() | |
189 | if(@params['Type'] == 'continuous') | |
190 | proc_readlines() | |
191 | end | |
192 | if(@params['Type'] == 'oneshot') | |
193 | if(Time.now - @last_update > @params['Periodic'].to_i) | |
194 | @buffer.clear() | |
195 | spawn_proc() | |
196 | end | |
197 | end | |
198 | print_buffer() | |
199 | end | |
200 | ||
201 | def spawn_proc() | |
202 | if(@params['Type'] == 'oneshot') | |
203 | update_date() | |
204 | Open3.popen3(@params["Command"]) { |i,o,e,t| | |
205 | while ((not o.eof?) or (not e.eof?)) | |
206 | rs = IO.select([o,e],nil)[0] | |
207 | r = (rs[0].eof?)? rs[1] : rs[0] | |
208 | ||
209 | if r.fileno == o.fileno | |
210 | @buffer.push(r.readline) | |
211 | elsif r.fileno == e.fileno | |
212 | @buffer.push(r.readline,type=1) | |
213 | end | |
214 | end | |
215 | } | |
216 | elsif(@params['Type'] == 'continuous') | |
217 | @proc = IO.popen(@params["Command"]) | |
218 | proc_readlines() | |
219 | end | |
220 | end | |
221 | end | |
222 | ||
223 | class Buffer | |
224 | def initialize(size) | |
225 | @size = size | |
226 | @buff = [] | |
227 | @buff_type = [] | |
228 | @current = 0 | |
229 | @wrap = false | |
230 | @before = false | |
231 | @after = false | |
232 | end | |
233 | def size() | |
234 | return @buff.length | |
235 | end | |
236 | def maxlen() | |
237 | maxlen = 0 | |
238 | @buff.each do |string| | |
239 | if string.length > maxlen | |
240 | maxlen = string.length | |
241 | end | |
242 | end | |
243 | return maxlen | |
244 | end | |
245 | ||
246 | def push(string,type=0) | |
247 | if(string.chomp.empty?) then string = " " end | |
248 | string.split( /\r?\n/ ).each do |line| | |
249 | @buff[@current] = line | |
250 | @buff_type[@current] = type | |
251 | if(@size > 0) | |
252 | @current = (1+@current) % @size | |
253 | else | |
254 | @current = 1+@current | |
255 | end | |
256 | if(@current == 0) then @wrap = true end | |
257 | end | |
258 | end | |
259 | def yield(size,offset=0,&block) | |
260 | range = Range.new(0,@current-1).to_a | |
261 | if(@wrap) | |
262 | range = Range.new(@current,@size-1).to_a + range | |
263 | end | |
264 | range = range.last(size+offset)[0,size] | |
265 | @before = (size+offset < @buff.length) | |
266 | @after = (offset != 0 and size < @buff.length) | |
267 | if(block) | |
268 | range.each do |i| | |
269 | yield [@buff[i],@buff_type[i]] | |
270 | end | |
271 | else | |
272 | return range.collect{|r| [@buff[r],@buff_type[r]]} | |
273 | end | |
274 | end | |
275 | def has_after?() | |
276 | return @after | |
277 | end | |
278 | def has_before?() | |
279 | return @before | |
280 | end | |
281 | def clear() | |
282 | @current = 0 | |
283 | @buff = [] | |
284 | @buff_type = [] | |
285 | end | |
286 | end | |
287 | ||
288 | def read_ini() | |
289 | inifile = IniFile.load('monitorrc') | |
290 | return inifile | |
291 | end | |
292 | ||
293 | def print_line(win, str, hscroll=0) | |
294 | if(hscroll > 0) | |
295 | strcut = str[hscroll,str.length] | |
296 | if(strcut.nil? or strcut.empty?) | |
297 | str = "" | |
298 | else | |
299 | str = "…"+strcut | |
300 | end | |
301 | end | |
302 | strlen = str.length | |
303 | winlen = win.getmaxx-win.getcurx-1 | |
304 | if(strlen <= winlen) | |
305 | win.addstr(str + " "*(winlen-strlen)) | |
306 | else | |
307 | win.addstr(str[0,winlen-1]+"…") | |
308 | end | |
309 | end | |
310 | ||
311 | def make_bufwins(inifile) | |
312 | bufwins = [] | |
313 | inifile.each_section do |section| | |
314 | bufwin = Buff_Win.new(Ncurses.COLS()-Ncurses.COLS()/4, | |
315 | Ncurses.COLS()/4, | |
316 | inifile[section]) | |
317 | bufwins.push(bufwin) | |
318 | end | |
319 | return bufwins | |
320 | end | |
321 | ||
322 | def update_buffers(bufwins) | |
323 | bufwins.each do |bufwin| | |
324 | bufwin.update() | |
325 | end | |
326 | end | |
327 | ||
328 | def redraw_all(list,bufwins,curr_bufwin) | |
329 | bufwins.each do |bufwin| | |
330 | bufwin.move_resize(Ncurses.COLS()-Ncurses.COLS()/4,Ncurses.COLS()/4) | |
331 | end | |
332 | list.resize(Ncurses.LINES(), Ncurses.COLS()/4) | |
333 | list.clear() | |
334 | list.print_list() | |
335 | list.refresh() | |
336 | curr_bufwin.refresh() | |
337 | end | |
338 | begin | |
339 | # initialize ncurses | |
340 | Ncurses.initscr | |
341 | Ncurses.start_color | |
342 | Ncurses.cbreak # provide unbuffered input | |
343 | Ncurses.noecho # turn off input echoing | |
344 | #Ncurses.nonl # turn off newline translation | |
345 | #Ncurses.stdscr.intrflush(false) # turn off flush-on-interrupt | |
346 | Ncurses.stdscr.keypad(true) # turn on keypad mode | |
347 | Ncurses.init_pair(1, Ncurses::COLOR_RED, Ncurses::COLOR_BLACK) | |
348 | ||
349 | ||
350 | inifile = read_ini() | |
351 | ||
352 | list = List_Win.new(inifile) | |
353 | bufwins = make_bufwins(inifile) | |
354 | entry = 0 | |
355 | cur_bufwin = bufwins[entry] | |
356 | cur_bufwin.show_win() | |
357 | list.print_list() | |
358 | while(ch = list.getch()) do | |
359 | case(ch) | |
360 | when "n".ord | |
361 | entry = (entry +1) % bufwins.length | |
362 | cur_bufwin = bufwins[entry] | |
363 | cur_bufwin.show_win() | |
364 | list.print_list(entry=entry) | |
365 | when "p".ord | |
366 | entry = (entry -1) % bufwins.length | |
367 | cur_bufwin = bufwins[entry] | |
368 | cur_bufwin.show_win() | |
369 | list.print_list(entry=entry) | |
370 | when 12 #ctrl+L | |
371 | redraw_all(list,bufwins,cur_bufwin) | |
372 | when Ncurses::KEY_RESIZE | |
373 | redraw_all(list,bufwins,cur_bufwin) | |
374 | when Ncurses::KEY_LEFT | |
375 | cur_bufwin.hscroll(scroll=-1) | |
376 | when Ncurses::KEY_RIGHT | |
377 | cur_bufwin.hscroll(scroll=1) | |
378 | when Ncurses::KEY_DOWN | |
379 | cur_bufwin.scroll(scroll=-1) | |
380 | when Ncurses::KEY_UP | |
381 | cur_bufwin.scroll(scroll=1) | |
382 | when Ncurses::KEY_NPAGE | |
383 | cur_bufwin.scroll(scroll=0,goto=nil,fact=-0.75) | |
384 | when Ncurses::KEY_PPAGE | |
385 | cur_bufwin.scroll(scroll=0,goto=nil,fact=0.75) | |
386 | when Ncurses::KEY_HOME | |
387 | cur_bufwin.scroll(scroll=0,goto=1.0) | |
388 | when Ncurses::KEY_END | |
389 | cur_bufwin.scroll(scroll=0,goto=0.0) | |
390 | when Ncurses::ERR | |
391 | update_buffers(bufwins) | |
392 | cur_bufwin.show_win() | |
393 | when "q".ord | |
394 | break | |
395 | else | |
396 | next | |
397 | end | |
398 | end | |
399 | ||
400 | ensure | |
401 | Ncurses.echo | |
402 | Ncurses.nocbreak | |
403 | Ncurses.nl | |
404 | Ncurses.endwin | |
405 | end |