ffi-ncurses 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/COPYING +22 -0
  2. data/Gemfile +5 -0
  3. data/Gemfile.lock +13 -0
  4. data/History.txt +32 -3
  5. data/README.rdoc +118 -58
  6. data/Rakefile +30 -0
  7. data/examples/acs_chars.rb +53 -0
  8. data/examples/acs_chars.rbc +1502 -0
  9. data/examples/{example-attributes.rb → attributes.rb} +0 -0
  10. data/examples/color.rb +63 -0
  11. data/examples/cursor.rb +27 -0
  12. data/examples/example.rb +17 -17
  13. data/examples/getkey.rb +212 -0
  14. data/examples/{example-getsetsyx.rb → getsetsyx.rb} +2 -2
  15. data/examples/globals.rb +38 -0
  16. data/examples/hello.rb +34 -0
  17. data/examples/hello.rbc +638 -0
  18. data/examples/hellowide.rb +59 -0
  19. data/examples/keys.rb +27 -0
  20. data/examples/{example-mouse.rb → mouse.rb} +2 -2
  21. data/examples/multiterm.rb +120 -0
  22. data/examples/ncurses/LICENSES_for_examples +26 -0
  23. data/examples/{ncurses-example.rb → ncurses/example.rb} +13 -80
  24. data/examples/ncurses/hello_ncurses.rb +57 -0
  25. data/examples/ncurses/rain.rb +220 -0
  26. data/examples/ncurses/read_line.rb +67 -0
  27. data/examples/ncurses/subwin.rb +71 -0
  28. data/examples/ncurses/tclock.rb +227 -0
  29. data/examples/newterm.rb +65 -0
  30. data/examples/panel_simple.rb +82 -0
  31. data/examples/{example-printw-variadic.rb → printw-variadic.rb} +1 -1
  32. data/examples/ripoffline.rb +86 -0
  33. data/examples/run-all.sh +14 -0
  34. data/examples/{example-softkeys.rb → softkeys.rb} +0 -0
  35. data/examples/{example-stdscr.rb → stdscr.rb} +2 -1
  36. data/examples/temp_leave.rb +99 -0
  37. data/examples/viewer.rb +350 -0
  38. data/examples/wacs_chars.rb +64 -0
  39. data/examples/windows.rb +73 -0
  40. data/ffi-ncurses.gemspec +39 -52
  41. data/lib/ffi-ncurses.rb +214 -474
  42. data/lib/ffi-ncurses/acs.rb +150 -0
  43. data/lib/ffi-ncurses/bool_wrappers.rb +66 -0
  44. data/lib/ffi-ncurses/functions.rb +450 -0
  45. data/lib/ffi-ncurses/keydefs.rb +136 -99
  46. data/lib/ffi-ncurses/mouse.rb +106 -106
  47. data/lib/ffi-ncurses/ncurses.rb +176 -0
  48. data/lib/ffi-ncurses/{ord-shim.rb → ord_shim.rb} +0 -0
  49. data/lib/ffi-ncurses/panel.rb +21 -0
  50. data/lib/ffi-ncurses/typedefs.rb +35 -0
  51. data/lib/ffi-ncurses/version.rb +7 -0
  52. data/lib/ffi-ncurses/widechars.rb +137 -0
  53. data/lib/ffi-ncurses/winstruct.rb +55 -33
  54. data/spec/attached_functions_spec.rb +42 -0
  55. metadata +95 -85
  56. data/examples/example-colour.rb +0 -63
  57. data/examples/example-cursor.rb +0 -22
  58. data/examples/example-hello.rb +0 -24
  59. data/examples/example-jruby.rb +0 -14
  60. data/examples/example-keys.rb +0 -25
  61. data/examples/example-windows.rb +0 -24
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ require 'ffi-ncurses'
3
+
4
+ # newterm - how to read STDIN and do ncurses at the same time
5
+ # See ncurses FAQ http://invisible-island.net/ncurses/ncurses.faq.html "Problems with output buffering"
6
+
7
+ # Call like this:
8
+ #
9
+ # $ echo hello|ruby newterm.rb
10
+ #
11
+ # or
12
+ #
13
+ # $ ruby newterm.rb < input.txt
14
+ #
15
+ # otherwise the program will stall.
16
+
17
+ def log(*a)
18
+ File.open("ncurses.log", "a") do |file|
19
+ file.puts(a.inspect)
20
+ end
21
+ end
22
+
23
+ module CLib
24
+ extend FFI::Library
25
+ ffi_lib FFI::Library::LIBC
26
+ # FILE* open and close
27
+ typedef :pointer, :FILEP
28
+ attach_function :fopen, [:string, :string], :FILEP
29
+ attach_function :fclose, [:FILEP], :int
30
+ end
31
+
32
+ begin
33
+ term = CLib.fopen("/dev/tty", "rb+")
34
+ screen = FFI::NCurses.newterm(nil, term, term)
35
+ old_screen = FFI::NCurses.set_term(screen)
36
+ FFI::NCurses.noecho
37
+ FFI::NCurses.clear
38
+ FFI::NCurses.move 1, 1
39
+ FFI::NCurses.addstr("Press any key to continue")
40
+ FFI::NCurses.move 3, 1
41
+ FFI::NCurses.addstr(STDIN.read(3))
42
+ FFI::NCurses.refresh
43
+ FFI::NCurses.flushinp
44
+ FFI::NCurses.getch
45
+ FFI::NCurses.addstr(STDIN.read)
46
+ FFI::NCurses.move 5, 1
47
+ FFI::NCurses.addstr("Press any key to continue")
48
+ FFI::NCurses.refresh
49
+ FFI::NCurses.flushinp
50
+ FFI::NCurses.getch
51
+ rescue => e
52
+ log :e1, e
53
+ ensure
54
+ begin
55
+ # Watch the ordering of these calls, i.e. do not call delscreen
56
+ # before endwin
57
+ FFI::NCurses.flushinp
58
+ FFI::NCurses.echo
59
+ FFI::NCurses.endwin
60
+ FFI::NCurses.delscreen(screen)
61
+ CLib.fclose(term)
62
+ rescue => e
63
+ log :e2, e
64
+ end
65
+ end
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby; coding: utf-8; -*-
3
+ require 'ffi-ncurses'
4
+
5
+ include FFI::NCurses
6
+
7
+ def main
8
+ my_wins = []
9
+ my_panels = []
10
+ lines = 10
11
+ cols = 40
12
+ y = 2
13
+ x = 4
14
+
15
+ begin
16
+ initscr
17
+ cbreak
18
+ noecho
19
+
20
+ # Create windows for the panels
21
+ my_wins[0] = newwin(lines, cols, y, x)
22
+ my_wins[1] = newwin(lines, cols, y + 1, x + 5)
23
+ my_wins[2] = newwin(lines, cols, y + 2, x + 10)
24
+
25
+
26
+ # Create borders around the windows so that you can see the effect
27
+ # of panels
28
+ my_wins.each_with_index do |win, i|
29
+ box(win, 0, 0)
30
+ mvwaddstr(win, 2, 2, "Window #{i}")
31
+ end
32
+
33
+ # Attach a panel to each window Order is bottom up #
34
+ my_panels[0] = new_panel(my_wins[0]) # Push 0, order: stdscr-0
35
+ my_panels[1] = new_panel(my_wins[2]) # Push 1, order: stdscr-0-1
36
+ my_panels[2] = new_panel(my_wins[1]) # Push 2, order: stdscr-0-1-2
37
+
38
+ # Update the stacking order. panel 2 will be on top
39
+ update_panels
40
+
41
+ # Show it on the screen
42
+ doupdate
43
+
44
+ getch
45
+
46
+ # bring panel 1 to top
47
+ top_panel(my_panels[1])
48
+ update_panels
49
+ doupdate
50
+
51
+ getch
52
+
53
+ # hide panel 0
54
+ hide_panel(my_panels[0])
55
+ update_panels
56
+ doupdate
57
+
58
+ getch
59
+
60
+ # show panel 0 again (on top)
61
+ show_panel(my_panels[0])
62
+ update_panels
63
+ doupdate
64
+
65
+ getch
66
+
67
+ # put panel 0 back to bottom of stack
68
+ bottom_panel(my_panels[0])
69
+ update_panels
70
+ doupdate
71
+
72
+ getch
73
+
74
+ rescue => e
75
+ endwin
76
+ raise
77
+ ensure
78
+ endwin
79
+ end
80
+ end
81
+
82
+ main
@@ -4,7 +4,7 @@
4
4
  # Sean O'Halpin, 2009-02-15
5
5
  #
6
6
  require 'ffi-ncurses'
7
- begin
7
+ begin
8
8
  FFI::NCurses.initscr
9
9
  FFI::NCurses.clear
10
10
  FFI::NCurses.printw("Hello %s! There are %d arguments to this variadic function!", :string, "world", :int, 2)
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env ruby
2
+ require 'ffi-ncurses'
3
+
4
+ # how to use ripoffline
5
+
6
+ def log(*a)
7
+ File.open("ncurses.log", "a") do |file|
8
+ file.puts(a.inspect)
9
+ end
10
+ end
11
+
12
+ # this works
13
+ # module FFI
14
+ # module NCurses
15
+ # callback :ripoffline_callback, [:pointer, :int], :int
16
+ # attach_function :ripoffline, [:int, :ripoffline_callback], :int
17
+ # end
18
+ # end
19
+
20
+ # works
21
+ $ripoffwin = nil
22
+ ripoffCallback = Proc.new do |win, cols|
23
+ $ripoffwin = win
24
+ FFI::NCurses.wbkgd(win, FFI::NCurses::A_REVERSE)
25
+ FFI::NCurses.werase(win)
26
+
27
+ FFI::NCurses.wmove(win, 0, 0)
28
+ FFI::NCurses.waddstr(win, "ripoff: window %s, %d columns %s" % [win.to_s, cols, Time.now])
29
+ FFI::NCurses.wnoutrefresh(win)
30
+ Thread.start do
31
+ # FFI::NCurses.immedok(win)
32
+ loop do
33
+ FFI::NCurses.wmove(win, 0, 0)
34
+ FFI::NCurses.waddstr(win, "ripoff: window %s, %d columns %s" % [win.to_s, cols, Time.now])
35
+ FFI::NCurses.wnoutrefresh(win)
36
+ sleep 1
37
+ end
38
+ end
39
+ FFI::NCurses::OK
40
+ end
41
+
42
+ callback = FFI::Function.new(:int, [:pointer, :int], &ripoffCallback)
43
+
44
+ def get_cmd
45
+ while (ch = FFI::NCurses.getch) == FFI::NCurses::ERR
46
+ sleep(0.1) # this has better performance than using halfdelay
47
+ FFI::NCurses.wrefresh($ripoffwin)
48
+ end
49
+ ch
50
+ end
51
+
52
+ begin
53
+ #FFI::NCurses.ripoffline(-1, RipoffCallback) # works
54
+ FFI::NCurses.ripoffline(1, callback) # rip line off top
55
+ FFI::NCurses.ripoffline(-1, callback) # rip line off bottom
56
+ FFI::NCurses.initscr
57
+ # FFI::NCurses.halfdelay(1)
58
+ FFI::NCurses.nodelay(FFI::NCurses.stdscr, true) # v. expensive in CPU (unless we sleep as above)
59
+ FFI::NCurses.noecho
60
+ FFI::NCurses.clear
61
+ FFI::NCurses.border(*([0]*8))
62
+ FFI::NCurses.move(4, 4)
63
+ FFI::NCurses.addstr("Hello")
64
+ FFI::NCurses.refresh
65
+ # FFI::NCurses.getch
66
+ get_cmd
67
+ FFI::NCurses.flushinp
68
+ FFI::NCurses.addstr("World")
69
+ FFI::NCurses.refresh
70
+ get_cmd
71
+ #FFI::NCurses.getch
72
+ rescue => e
73
+ FFI::NCurses.flushinp
74
+ FFI::NCurses.echo
75
+ FFI::NCurses.endwin
76
+ log :e1, e
77
+ raise
78
+ ensure
79
+ begin
80
+ FFI::NCurses.flushinp
81
+ FFI::NCurses.echo
82
+ FFI::NCurses.endwin
83
+ rescue => e
84
+ log :e2, e
85
+ end
86
+ end
@@ -0,0 +1,14 @@
1
+ #!/bin/sh
2
+ for p in *.rb; do
3
+ if [ "$p" = "newterm.rb" ]; then
4
+ echo Not running $p
5
+ elif [ "$p" = "multiterm.rb" ]; then
6
+ echo Not running $p
7
+ elif [ "$p" = "viewer.rb" ]; then
8
+ echo $p
9
+ ruby $p $p
10
+ else
11
+ echo $p
12
+ ruby $p
13
+ fi
14
+ done
@@ -6,7 +6,8 @@ require 'ffi-ncurses'
6
6
  begin
7
7
  scr = FFI::NCurses.initscr
8
8
  FFI::NCurses.box(FFI::NCurses.stdscr, 0, 0)
9
- FFI::NCurses.mvaddstr 1, 1, "#{[scr, FFI::NCurses.stdscr].inspect}"
9
+ FFI::NCurses.mvaddstr 1, 1, "initscr: #{scr.inspect}"
10
+ FFI::NCurses.mvaddstr 2, 1, "stdscr: #{FFI::NCurses.stdscr.inspect}"
10
11
  FFI::NCurses.refresh
11
12
  FFI::NCurses.getch
12
13
 
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env ruby
2
+ require 'ffi-ncurses'
3
+
4
+ include FFI::NCurses
5
+
6
+ module CLib
7
+ extend FFI::Library
8
+ ffi_lib FFI::Library::LIBC
9
+ # FILE* open and close
10
+ typedef :pointer, :FILEP
11
+ attach_function :fdopen, [:int, :string], :FILEP
12
+ attach_function :fopen, [:string, :string], :FILEP
13
+ attach_function :fclose, [:FILEP], :int
14
+ end
15
+
16
+ # This is the version from NCURSES HOWTO
17
+ def do_cmd(cmd)
18
+ def_prog_mode # Save the tty modes
19
+ endwin # End curses mode temporarily
20
+ system(cmd) # Do whatever you like in cooked mode
21
+ reset_prog_mode # Return to the previous tty mode
22
+ refresh # Do refresh() to restore the
23
+ # Screen contents
24
+ # stored by def_prog_mode()
25
+ end
26
+
27
+ # This is the version from ncurses examples filter.c
28
+ def do_cmdx(cmd)
29
+ reset_shell_mode # Restore terminal mode
30
+ STDOUT.flush
31
+ system(cmd) # Do whatever you like in cooked mode
32
+ reset_prog_mode # Return to the previous tty mode
33
+ touchwin(stdscr)
34
+ # erase
35
+ refresh
36
+ end
37
+
38
+ def show_text_window(win, title, text)
39
+ text_width = text.lines.map{ |x| x.size }.max
40
+ text_height = text.lines.to_a.size
41
+
42
+ width = text_width + 4
43
+ height = text_height + 4
44
+
45
+ rows, cols = getmaxyx(win)
46
+
47
+ col = (cols - width)/2
48
+ row = (rows - height)/2
49
+
50
+ frame = newwin(height, width, row, col)
51
+ keypad frame, true
52
+ box(frame, 0, 0)
53
+
54
+ title = "[ #{title} ]"
55
+ wmove(frame, 0, (width - title.size)/2)
56
+ waddstr(frame, title)
57
+
58
+ win = derwin(frame, text_height, text_width, 2, 2)
59
+ wmove(win, 0, 0)
60
+ waddstr(win, text)
61
+ wnoutrefresh(win)
62
+ wgetch(frame)
63
+ flushinp
64
+ delwin(win)
65
+ delwin(frame)
66
+ end
67
+
68
+ def main
69
+ begin
70
+ # input = CLib.fdopen(STDIN.fileno, "rb+")
71
+ # output = CLib.fdopen(STDOUT.fileno, "rb+")
72
+ # screen = newterm(nil, output, input)
73
+ # set_term(screen)
74
+
75
+ initscr
76
+ keypad stdscr, true
77
+ noecho
78
+
79
+ addstr("Hello from ncurses\n")
80
+ refresh
81
+ addstr("Press any key to enter shell\n")
82
+ getch
83
+ addstr("Now entering shell - enter 'exit' or press Ctrl-D to exit\n")
84
+ refresh
85
+ sleep 0.2
86
+
87
+ cmd = ARGV[0] || "/bin/sh"
88
+ do_cmd(cmd)
89
+ flushinp
90
+ show_text_window(stdscr, "Message", "Back to ncurses\nPress any key to quit")
91
+ refresh
92
+ ensure
93
+ flushinp
94
+ endwin
95
+ # delscreen(screen)
96
+ end
97
+ end
98
+
99
+ main
@@ -0,0 +1,350 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby; coding: utf-8 -*-
3
+ #
4
+ # A simple file viewer.
5
+ #
6
+ # Sean O'Halpin, 2011-09-16
7
+ #
8
+ # Possible features to add:
9
+ # - search
10
+ # - hex view
11
+ #
12
+ require 'ffi-ncurses'
13
+
14
+ include FFI::NCurses
15
+
16
+ # some helper methods for working with stdlib FILE pointers
17
+ module CLib
18
+ extend FFI::Library
19
+ ffi_lib FFI::Library::LIBC
20
+ typedef :pointer, :FILEP
21
+ # FILE* open, close and eof
22
+ attach_function :fopen, [:string, :string], :FILEP
23
+ attach_function :fclose, [:FILEP], :int
24
+ attach_function :feof, [:FILEP], :int
25
+ attach_function :fflush, [:FILEP], :int
26
+ attach_function :fputs, [:string, :FILEP], :int
27
+ end
28
+
29
+ $APP_DEBUG = ARGV.delete("--debug")
30
+ def log(*a)
31
+ STDERR.puts a.inspect if $APP_DEBUG
32
+ end
33
+
34
+ def redraw_background_frame
35
+ clear
36
+ touchwin(stdscr)
37
+ box(stdscr, 0, 0)
38
+ title = "[ F1 or ? for help ]"
39
+ wmove(stdscr, 0, (COLS() - title.size)/2)
40
+ waddstr(stdscr, title)
41
+ wnoutrefresh(stdscr)
42
+ end
43
+
44
+ def std_colors
45
+ init_pair(0, Color::BLACK, Color::BLACK)
46
+ init_pair(1, Color::RED, Color::BLACK)
47
+ init_pair(2, Color::GREEN, Color::BLACK)
48
+ init_pair(3, Color::YELLOW, Color::BLACK)
49
+ init_pair(4, Color::BLUE, Color::BLACK)
50
+ init_pair(5, Color::MAGENTA, Color::BLACK)
51
+ init_pair(6, Color::CYAN, Color::BLACK)
52
+ init_pair(7, Color::WHITE, Color::BLACK)
53
+
54
+ init_pair(8, Color::BLACK, Color::BLACK)
55
+ init_pair(9, Color::BLACK, Color::RED)
56
+ init_pair(10, Color::BLACK, Color::GREEN)
57
+ init_pair(11, Color::BLACK, Color::YELLOW)
58
+ init_pair(12, Color::BLACK, Color::BLUE)
59
+ init_pair(13, Color::BLACK, Color::MAGENTA)
60
+ init_pair(14, Color::BLACK, Color::CYAN)
61
+ init_pair(15, Color::BLACK, Color::WHITE)
62
+ end
63
+
64
+ def show_text_window(win, title, text)
65
+ text_width = text.lines.map{ |x| x.size }.max
66
+ text_height = text.lines.to_a.size
67
+
68
+ width = text_width + 4
69
+ height = text_height + 4
70
+
71
+ rows, cols = getmaxyx(win)
72
+
73
+ col = (cols - width)/2
74
+ row = (rows - height)/2
75
+
76
+ frame = newwin(height, width, row, col)
77
+ keypad frame, true
78
+ box(frame, 0, 0)
79
+
80
+ title = "[ #{title} ]"
81
+ wmove(frame, 0, (width - title.size)/2)
82
+ waddstr(frame, title)
83
+
84
+ win = derwin(frame, text_height, text_width, 2, 2)
85
+ wmove(win, 0, 0)
86
+ waddstr(win, text)
87
+ wnoutrefresh(win)
88
+ wgetch(frame)
89
+ flushinp
90
+ delwin(win)
91
+ delwin(frame)
92
+ end
93
+
94
+ def update_row_col(left_border, row, col)
95
+ move(0, left_border)
96
+ addstr("%03d:%003d" % [row + 1, col + 1])
97
+ wnoutrefresh(stdscr)
98
+ end
99
+
100
+ @maximized = false
101
+ def toggle_maximize(term)
102
+ # Maximize terminal window (xterm only).
103
+ #
104
+ # You can do the same with Alt-F10 in Gnome (and it seems more
105
+ # reliable).
106
+ CLib.fflush(term)
107
+
108
+ # maximize
109
+ CLib.fputs("\e[9;#{@maximized ? 0 : 1}t", term)
110
+ CLib.fflush(term)
111
+
112
+ @maximized = !@maximized
113
+ end
114
+
115
+ # Helper function to match charcodes or (single character) strings
116
+ # against keycodes returned by ncursesw.
117
+ #
118
+ # Note that this won't work for characters outside Latin-1 as they overlap numerically with
119
+ # ncurses's KEY_ codes. Should return new class for KEY_ codes.
120
+ #
121
+ def KEY(s)
122
+ case s
123
+ when String
124
+ s.unpack("U")[0]
125
+ else
126
+ s
127
+ end
128
+ end
129
+
130
+ def resize_terminal_window(rows, cols)
131
+ print("\e[8;#{rows};#{cols};t") # set window size to rows x cols
132
+ resizeterm(rows, cols) # note: you need to tell ncurses that you've resized the terminal
133
+ end
134
+
135
+ def page_height
136
+ LINES() - total_tb_border
137
+ end
138
+
139
+ def page_width
140
+ COLS() - total_lr_border
141
+ end
142
+
143
+ def total_lr_border
144
+ @left_border + @right_border
145
+ end
146
+
147
+ def total_tb_border
148
+ @top_border + @bottom_border
149
+ end
150
+
151
+ def view(text, arg_rows = nil, arg_cols = nil)
152
+ @top_border = @bottom_border = 1
153
+ @left_border = @right_border = 1
154
+ # set_escdelay(10) if respond_to?(:set_escdelay) # Centos 5.1 :S
155
+ lines = text.lines.to_a
156
+ maxx = lines.map{|x| x.size }.max + total_lr_border
157
+ maxy = lines.size + total_tb_border
158
+
159
+ # We need to open /dev/tty so we can read from STDIN without borking
160
+ # ncurses
161
+ term = CLib.fopen("/dev/tty", "rb+")
162
+ screen = newterm(nil, term, term)
163
+ old_screen = set_term(screen)
164
+
165
+ # save original window size
166
+ orig_rows, orig_cols = getmaxyx(stdscr)
167
+ if arg_rows.nil?
168
+ arg_rows = orig_rows
169
+ end
170
+ if arg_cols.nil?
171
+ arg_cols = orig_cols
172
+ end
173
+ if arg_rows != orig_rows || arg_cols != orig_cols
174
+ resize_terminal_window(arg_rows, arg_cols)
175
+ end
176
+
177
+ help_text = <<EOT
178
+ F1, ? - Help
179
+ Home - Beginning of file
180
+ End - End of file
181
+ PgDn, space - Scroll down one page
182
+ PgUp - Scroll up one page
183
+ Down arrow - Scroll down one line
184
+ Up arrow - Scroll up one line
185
+ Right arrow - Scroll right one column
186
+ Left arrow - Scroll left one column
187
+ +/- - Increase/decrease window size
188
+ ^q, q, Esc - Quit
189
+ EOT
190
+
191
+ saved_exception = nil
192
+ begin
193
+ raw
194
+ noecho
195
+ curs_set 0
196
+ pad = newpad(maxy, maxx)
197
+ if has_colors
198
+ start_color
199
+ std_colors
200
+ end
201
+ keypad pad, true
202
+
203
+ # just a bit of fun - format RDoc headers, comments and org-mode
204
+ # header lines
205
+ flag = false
206
+ bg_flag = false
207
+ attribute = 0
208
+ lines.each do |line|
209
+ if line =~ /^\s*[=*#]+/
210
+ case line
211
+ when /^\s*#/
212
+ attribute = COLOR_PAIR(4)
213
+ when /^\s*=+/
214
+ # attribute = A_UNDERLINE
215
+ wbkgdset(pad, A_REVERSE)
216
+ wclrtoeol(pad)
217
+ bg_flag = true
218
+ when /^\s*\*/
219
+ attribute = COLOR_PAIR(1)
220
+ end
221
+ # wchgat(pad, -1, A_REVERSE, COLOR_WHITE, nil)
222
+ flag = true
223
+ # wattron(pad, A_BOLD)
224
+ wattron(pad, attribute)
225
+ end
226
+ rv = waddstr(pad, line)
227
+ if flag
228
+ flag = false
229
+ wattroff(pad, attribute)
230
+ if bg_flag
231
+ wbkgdset(pad, A_NORMAL)
232
+ wattroff(pad, A_BOLD)
233
+ end
234
+ end
235
+ log :adding, line, :rv, rv
236
+ end
237
+
238
+ current_line = 0
239
+ current_col = 0
240
+
241
+ redraw_background_frame
242
+ update_row_col(@left_border, current_line, current_col)
243
+
244
+ rv = pnoutrefresh(pad, current_line, current_col, @top_border, @left_border, page_height, page_width)
245
+ log :prefresh1, :rv, rv
246
+ doupdate
247
+
248
+ # main loop
249
+ while ch = wgetch(pad)
250
+ log :ch, ch
251
+ case ch
252
+ when KEY_HOME
253
+ current_line = 0
254
+ current_col = 0
255
+ when KEY_END
256
+ current_line = maxy - LINES() + total_lr_border
257
+ current_col = 0
258
+ when KEY_NPAGE, KEY(' ')
259
+ current_line = [current_line + page_height, [maxy - page_height, 0].max].min
260
+ when KEY_PPAGE
261
+ current_line = [current_line - page_height, 0].max
262
+ when KEY_DOWN
263
+ current_line = [current_line + 1, [maxy - page_height, 0].max].min
264
+ when KEY_UP
265
+ current_line = [current_line - 1, 0].max
266
+ when KEY_RIGHT
267
+ current_col = [current_col + 1, [maxx - page_width, 0].max].min
268
+ when KEY_LEFT
269
+ current_col = [current_col - 1, 0].max
270
+ when KEY_F1, KEY('?')
271
+ # Help
272
+ show_text_window stdscr, "Help", help_text
273
+ redraw_background_frame
274
+ when KEY('f')
275
+ toggle_maximize(term)
276
+ when KEY('+')
277
+ rows, cols = getmaxyx(stdscr)
278
+ rows += 1
279
+ cols += 1
280
+ resize_terminal_window(rows, cols)
281
+ redraw_background_frame
282
+ when KEY('-')
283
+ rows, cols = getmaxyx(stdscr)
284
+ rows -= 1
285
+ cols -= 1
286
+ resize_terminal_window(rows, cols)
287
+ redraw_background_frame
288
+ when KEY_CTRL_Q, 'q'[0].ord, 27 # 27 == Esc
289
+ # Quit
290
+ delwin(pad)
291
+ break
292
+ when KEY_CTRL_C
293
+ # for JRuby - Ctrl-C in cbreak mode is not trapped in rescue
294
+ # below for some reason and so leaves the terminal in raw mode
295
+ raise Interrupt
296
+ when KEY_RESIZE, KEY_CTRL_L
297
+ log :redraw2
298
+ redraw_background_frame
299
+ end
300
+
301
+ update_row_col(@left_border, current_line, current_col)
302
+ rv = pnoutrefresh(pad, current_line, current_col, @top_border, @left_border, page_height, page_width)
303
+ log :prefresh2, :rv, rv, :line, current_line, :col, current_col
304
+ doupdate
305
+ flushinp
306
+ end
307
+ rescue Object => saved_exception
308
+ ensure
309
+ CLib.fclose(term) if !CLib.feof(term)
310
+ flushinp
311
+ end_rows, end_cols = getmaxyx(stdscr)
312
+ endwin
313
+ delscreen(screen)
314
+
315
+ # restore terminal size at launch
316
+ if end_rows != orig_rows || end_cols != orig_cols
317
+ resizeterm(orig_rows, orig_cols)
318
+ File.open("/dev/tty", "wb+") do |file|
319
+ file.print("\e[8;#{orig_rows};#{orig_cols};t") # restore window
320
+ end
321
+ end
322
+ end
323
+ if saved_exception
324
+ raise saved_exception
325
+ end
326
+ end
327
+
328
+ def main
329
+ require 'ostruct'
330
+ require 'optparse'
331
+
332
+ options = OpenStruct.new
333
+
334
+ xopts = OptionParser.new do |opts|
335
+ opts.on("-c", "--c COLS", Integer, "Resize screen to COLS width") do |cols|
336
+ options.columns = cols
337
+ end
338
+ opts.on("-r", "--r ROWS", Integer, "Resize screen to ROWS height") do |rows|
339
+ options.rows = rows
340
+ end
341
+ end
342
+
343
+ xopts.parse!(ARGV)
344
+ view(ARGF.read, options.rows, options.columns) # simplistic but works for demo
345
+
346
+ end
347
+
348
+ if __FILE__ == $0
349
+ main
350
+ end