1 ! Copyright (C) 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.c-types alien.strings assocs byte-arrays
4 classes.struct combinators continuations destructors
5 fry io io.encodings.8-bit io.encodings.string io.encodings.utf8
6 io.streams.c kernel libc locals math memoize multiline
7 namespaces prettyprint sequences strings threads ;
10 QUALIFIED-WITH: curses.ffi ffi
12 SYMBOL: current-window
14 CONSTANT: COLOR_BLACK 0
16 CONSTANT: COLOR_GREEN 2
17 CONSTANT: COLOR_YELLO 3
18 CONSTANT: COLOR_BLUE 4
19 CONSTANT: COLOR_MAGEN 5
20 CONSTANT: COLOR_CYAN 6
21 CONSTANT: COLOR_WHITE 7
24 CONSTANT: A_ATTRIBUTES -256
25 CONSTANT: A_CHARTEXT 255
26 CONSTANT: A_COLOR 65280
27 CONSTANT: A_STANDOUT 65536
28 CONSTANT: A_UNDERLINE 131072
29 CONSTANT: A_REVERSE 262144
30 CONSTANT: A_BLINK 524288
31 CONSTANT: A_DIM 1048576
32 CONSTANT: A_BOLD 2097152
33 CONSTANT: A_ALTCHARSET 4194304
34 CONSTANT: A_INVIS 8388608
35 CONSTANT: A_PROTECT 16777216
36 CONSTANT: A_HORIZONTAL 33554432
37 CONSTANT: A_LEFT 67108864
38 CONSTANT: A_LOW 134217728
39 CONSTANT: A_RIGHT 268435456
40 CONSTANT: A_TOP 536870912
41 CONSTANT: A_VERTICAL 1073741824
43 ERROR: curses-failed ;
44 ERROR: unsupported-curses-terminal ;
48 : >BOOLEAN ( ? -- TRUE/FALSE ) ffi:TRUE ffi:FALSE ? ; inline
50 : curses-pointer-error ( ptr/f -- ptr )
51 dup [ curses-failed ] unless ; inline
52 : curses-error ( n -- ) ffi:ERR = [ curses-failed ] when ;
57 { 0 1 2 } [ isatty 0 = not ] all? ;
59 TUPLE: curses-window < disposable
62 { lines integer initial: 0 }
63 { columns integer initial: 0 }
64 { y integer initial: 0 }
65 { x integer initial: 0 }
71 { scrollok initial: t }
72 { leaveok initial: f }
77 { encoding initial: utf8 } ;
79 : <curses-window> ( -- window )
80 curses-window new-disposable ;
82 M: curses-window dispose* ( window -- )
83 ptr>> ffi:delwin curses-error ;
87 : window-params ( window -- lines columns y x )
88 { [ lines>> ] [ columns>> ] [ y>> ] [ x>> ] } cleave ;
90 : set-cbreak/raw ( cbreak raw -- )
92 [ ffi:cbreak ] [ ffi:nocbreak ] if
95 : apply-options ( window -- )
97 [ [ cbreak>> ] [ raw>> ] bi set-cbreak/raw ]
98 [ echo>> [ ffi:echo ] [ ffi:noecho ] if curses-error ]
99 [ [ ptr>> ] [ scrollok>> >BOOLEAN ] bi ffi:scrollok curses-error ]
100 [ [ ptr>> ] [ leaveok>> >BOOLEAN ] bi ffi:leaveok curses-error ]
101 [ [ ptr>> ] [ keypad>> >BOOLEAN ] bi ffi:keypad curses-error ]
104 SYMBOL: n-registered-colors
106 MEMO: register-color ( fg bg -- n )
107 [ n-registered-colors get ] 2dip ffi:init_pair curses-error
108 n-registered-colors [ get ] [ inc ] bi ;
112 1 n-registered-colors set
113 \ register-color reset-memoized
114 ffi:start_color curses-error
119 : setup-window ( window -- window )
122 dup parent-window>> [
123 ptr>> swap window-params ffi:derwin
125 window-params ffi:newwin
126 ] if* [ curses-error ] keep >>ptr &dispose
127 ] [ apply-options ] bi ;
129 : with-window ( window quot -- )
130 [ current-window ] dip with-variable ; inline
132 : with-curses ( window quot -- )
133 curses-ok? [ unsupported-curses-terminal ] unless
136 ffi:initscr curses-pointer-error
137 >>ptr dup apply-options
138 ffi:erase curses-error
141 ] [ ffi:endwin curses-error ] [ ] cleanup
142 ] with-destructors ; inline
144 TUPLE: curses-terminal < disposable
147 : <curses-terminal> ( infd outfd ptr -- curses-terminal )
148 curses-terminal new-disposable
153 M: curses-terminal dispose
154 [ outfd>> fclose ] [ infd>> fclose ]
155 [ ptr>> ffi:delscreen ] tri ;
157 : init-terminal ( terminal -- curses-terminal )
158 "xterm-color" swap [ "rb" fopen ] [ "wb" fopen ] bi
159 [ ffi:newterm curses-pointer-error ] 2keep <curses-terminal> ;
161 : start-remote-curses ( terminal window -- curses-terminal )
164 ffi:initscr curses-pointer-error drop
165 dup ptr>> ffi:set_term curses-pointer-error drop
166 ] dip apply-options ;
170 : (wcrefresh) ( window-ptr -- ) ffi:wrefresh curses-error ; inline
171 : (wcwrite) ( string window-ptr -- ) swap ffi:waddstr curses-error ; inline
173 :: (wcread) ( n encoding window-ptr -- string )
175 n 1 + malloc &free :> str
176 window-ptr str n ffi:wgetnstr curses-error
177 str encoding alien>string
178 ] with-destructors ; inline
180 : (wcmove) ( y x window-ptr -- )
181 -rot ffi:wmove curses-error ; inline
183 : (winsert-blank-line) ( y window-ptr -- )
185 [ ffi:winsertln curses-error ] bi ; inline
187 : (waddch) ( ch window-ptr -- )
188 swap ffi:waddch curses-error ; inline
190 : (wgetch) ( window -- key )
191 ffi:wgetch [ curses-error ] keep ; inline
193 : (wattroff) ( attribute window-ptr -- )
194 swap ffi:wattroff curses-error ; inline
196 : (wattron) ( attribute window-ptr -- )
197 swap ffi:wattron curses-error ; inline
201 : wcrefresh ( window -- ) ptr>> (wcrefresh) ;
202 : crefresh ( -- ) current-window get wcrefresh ;
204 : wcnl ( window -- ) [ "\n" ] dip ptr>> (wcwrite) ;
205 : cnl ( -- ) current-window get wcnl ;
207 : wcwrite ( string window -- ) ptr>> (wcwrite) ;
208 : cwrite ( string -- ) current-window get wcwrite ;
210 : wcprint ( string window -- )
211 ptr>> [ (wcwrite) ] [ "\n" swap (wcwrite) ] bi ;
212 : cprint ( string -- ) current-window get wcprint ;
214 : wcprintf ( string window -- )
215 ptr>> [ (wcwrite) ] [ "\n" swap (wcwrite) ]
216 [ (wcrefresh) ] tri ;
217 : cprintf ( string -- ) current-window get wcprintf ;
219 : wcwritef ( string window -- )
220 ptr>> [ (wcwrite) ] [ (wcrefresh) ] bi ;
221 : cwritef ( string -- ) current-window get wcwritef ;
223 : wcread ( n window -- string )
224 [ encoding>> ] [ ptr>> ] bi (wcread) ;
225 : curses-read ( n -- string ) current-window get wcread ;
227 : wgetch ( window -- key ) ptr>> (wgetch) ;
228 : getch ( -- key ) current-window get wgetch ;
230 : waddch ( ch window -- ) ptr>> (waddch) ;
231 : addch ( ch -- ) current-window get waddch ;
233 : werase ( window -- ) ptr>> ffi:werase curses-error ;
234 : erase ( -- ) current-window get werase ;
236 : wcmove ( y x window -- )
237 ptr>> [ (wcmove) ] [ (wcrefresh) ] bi ;
238 : cmove ( y x -- ) current-window get wcmove ;
240 : wdelete-line ( y window -- )
241 ptr>> [ 0 swap (wcmove) ] [ ffi:wdeleteln curses-error ] bi ;
242 : delete-line ( y -- ) current-window get wdelete-line ;
244 : winsert-blank-line ( y window -- )
245 ptr>> (winsert-blank-line) ;
246 : insert-blank-line ( y -- )
247 current-window get winsert-blank-line ;
249 : winsert-line ( string y window -- )
250 ptr>> [ (winsert-blank-line) ] [ (wcwrite) ] bi ;
251 : insert-line ( string y -- )
252 current-window get winsert-line ;
254 : wattron ( attribute window -- ) ptr>> (wattron) ;
255 : attron ( attribute -- ) current-window get wattron ;
257 : wattroff ( attribute window -- ) ptr>> (wattroff) ;
258 : attroff ( attribute -- ) current-window get wattroff ;
260 : wall-attroff ( window -- ) [ A_NORMAL ] dip wattroff ;
261 : all-attroff ( -- ) current-window get wall-attroff ;
263 : wccolor ( foreground background window -- )
265 2dup [ COLOR_WHITE = ] [ COLOR_BLACK = ] bi* and
266 [ 2drop 0 ] [ register-color ] if ffi:COLOR_PAIR
267 ] dip ptr>> (wattron) ;
269 : ccolor ( foreground background -- )
270 current-window get wccolor ;