ffi-ncurses 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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