-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathraart.scrbl
319 lines (238 loc) · 13.5 KB
/
raart.scrbl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
#lang scribble/manual
@(require (for-syntax racket/base)
(for-label raart
lux/chaos
ansi
racket/format
racket/contract
racket/base)
racket/sandbox
scribble/example)
@(define ev
(parameterize ([sandbox-output 'string]
[sandbox-error-output 'string]
[sandbox-memory-limit 50]
;; Need to load the tty-raw extension and we don't
;; know where it is.
[sandbox-path-permissions '((execute #rx#""))])
(make-evaluator 'racket/base)))
@(ev '(require raart/draw))
@(define-syntax-rule (ex r ...) (examples #:eval ev r ...))
@title{raart: Racket ASCII Art and Interfaces}
@author{Jay McCarthy}
@defmodule[raart]
The @racketmodname[raart] module provides an algebraic model of ASCII
that can be used for art, user interfaces, and diagrams. It is
comparable to @racketmodname[2htdp/image].
Check out some examples in the
@link["https://github.com/jeapostrophe/raart/tree/master/t"]{test}
directory in the source.
@local-table-of-contents[]
@section{Buffers}
@defmodule[raart/buffer]
When drawing, @racketmodname[raart] renders to a @deftech{buffer}. In
almost all circumstances, you should use @racket[make-cached-buffer].
@defproc[(buffer? [x any/c]) boolean?]{Identifiers @tech{buffer}s.}
@defproc[(make-output-buffer [#:output output output-port? (current-output-port)])
buffer?]{
A @tech{buffer} that displays to @racket[output].
}
@defproc[(make-terminal-buffer [rows exact-nonnegative-integer?]
[cols exact-nonnegative-integer?]
[#:clear? clear? boolean? #t]
[#:output output output-port? (current-output-port)])
buffer?]{
A @tech{buffer} that displays to a terminal of @racket[rows] rows and
@racket[cols] columns via the port @racket[output]. If @racket[clear?]
is non-false, then the terminal will be cleared before display.
}
@defproc[(make-cached-buffer [rows exact-nonnegative-integer?]
[cols exact-nonnegative-integer?]
[#:output output output-port? (current-output-port)])
buffer?]{
A @tech{buffer} that displays to a terminal of @racket[rows] rows and
@racket[cols] columns via the port @racket[output], with minimal
output to the terminal implemented via client-side caching of the
screen content so only updates are output. }
@defthing[color/c contract?]{
A contract that recognizes the ASCII colors from the list
@racket['(black red green yellow blue magenta cyan white brblack brred
brgreen bryellow brblue brmagenta brcyan brwhite)], as well as any
@racket[byte?] value. The actual color display depends on the terminal
configuration. }
@defthing[style/c contract?]{
A contract that recognizes the ASCII styles from the list
@racket['(normal bold inverse underline)]. The actual font displayed
may depend on the terminal configuration. }
@section{Drawing}
@defmodule[raart/draw]
@racketmodname[raart] represents ASCII art algebraically as an
abstract @racket[raart?] object.
@defproc[(raart? [x any/c]) boolean?]{Identifies ASCII art.}
@defproc[(raart-w [x raart?]) exact-nonnegative-integer?]{Returns the
width of the art.}
@defproc[(raart-h [x raart?]) exact-nonnegative-integer?]{Returns the
height of the art.}
@defproc[(draw [b buffer?] [r raart?]) void?]{Displays @racket[r] to
the @racket[b] buffer.}
@defproc[(draw-here [r raart?]) void?]{Displays @racket[r] with a
freshly created buffer made with @racket[make-output-buffer].}
@defproc[(style [s style/c] [r raart?]) raart?]{@racket[r], except
with the style given by @racket[s].}
@defproc[(fg [c color/c] [r raart?]) raart?]{@racket[r], except with
the foreground color given by @racket[c].}
@defproc[(bg [c color/c] [r raart?]) raart?]{@racket[r], except with
the background color given by @racket[c].}
@defproc[(with-drawing [s (or/c style/c #f)] [fc (or/c color/c #f)]
[bc (or/c color/c #f)] [r raart?]) raart?]{Wraps @racket[r] in calls
to @racket[style], @racket[fg], and @racket[bg] if @racket[s],
@racket[fc], or @racket[bc] (respectively) are provided as non-false.}
@defproc[(blank [w exact-nonnegative-integer? 0] [h
exact-nonnegative-integer? 0]) raart?]{A blank art of width @racket[w]
and height @racket[h].
@ex[(draw-here (blank 2 2))
(draw-here (blank 5 5))]
}
@defproc[(char [c (and/c char? (not/c char-iso-control?))]) raart?]{An
art displaying @racket[c].
@ex[(draw-here (char #\a)) (draw-here (char #\b))]}
@defproc[(text [s string?]) raart?]{An art displaying @racket[s],
which must not contain any @racket[char-iso-control?] characters.
@ex[(draw-here (text "Hello World!"))]}
@defproc[(hline [w exact-nonnegative-integer?]) raart?]{A horizontal
line of @litchar{-} characters of width @racket[w].
@ex[(draw-here (hline 5))]}
@defproc[(vline [h exact-nonnegative-integer?]) raart?]{A vertical
line of @litchar{|} characters of height @racket[h].
@ex[(draw-here (vline 3))]}
@defthing[halign/c contract?]{A contract for the horizontal alignment modes @racket['(left center right)]. @racket['left] means that the art will be extended with blanks to the right@";" @racket['center] places the blanks equally on both sides@";" and @racket['right] places the blanks to the left.}
@defthing[valign/c contract?]{A contract for the vertical alignment modes @racket['(top center bottom)]. @racket['top] means that the art will be extended with blanks below";" @racket['center] places the blanks equally on both sides@";" and @racket['bottom] places the blanks above.}
@defproc[(vappend2 [y raart?] [x raart?] [#:halign halign (or/c
halign/c #f) #f] [#:reverse? reverse? boolean? #f]) raart?]{ Renders
@racket[y] vertically above @racket[x]. (If @racket[reverse?] is true,
then the effects are evaluated in the opposite order.) Uses
@racket[halign] to determine the horizontal alignment. If
@racket[halign] is @racket[#f], then the arts must have the same
width.
@ex[(draw-here (vappend2 (text "Hello") (text "World")))
(eval:error
(draw-here (vappend2 (text "Short") (text "Very Very Long"))))
(draw-here (vappend2 (text "Short") (text "Very Very Long") #:halign 'left))
(draw-here (vappend2 (text "Short") (text "Very Very Long") #:halign 'right))
(draw-here (vappend2 (text "Short") (text "Very Very Long") #:halign 'center))]}
@defproc[(vappend [y raart?] [x raart?] ... [#:halign halign (or/c
halign/c #f) #f] [#:reverse? reverse? boolean? #f]) raart?]{Like
@racket[vappend2], but for many arguments.
@ex[(draw-here (vappend (text "Short") (text "A Little Medium") (text "Very Very Long") #:halign 'right))]}
@defproc[(vappend* [y-and-xs (non-empty-listof raart?)] [#:halign
halign (or/c halign/c #f) #f] [#:reverse? reverse? boolean? #f])
raart?]{Like @racket[vappend], but accepts arguments as a list.
@ex[(draw-here (vappend* (list (text "Short") (text "A Little Medium") (text "Very Very Long")) #:halign 'right))]}
@defproc[(happend2 [y raart?] [x raart?] [#:valign valign (or/c
valign/c #f) #f] [#:reverse? reverse? boolean? #f]) raart?]{ Renders
@racket[y] horizontally to the left of @racket[x]. (If
@racket[reverse?] is true, then the effects are evaluated in the
opposite order.) Uses @racket[valign] to determine the vertical
alignment. If @racket[valign] is @racket[#f], then the arts must have
the same height.
@ex[(draw-here (happend2 (vline 2) (vline 2)))
(eval:error
(draw-here (happend2 (vline 2) (vline 4))))
(draw-here (happend2 (vline 2) (vline 4) #:valign 'top))
(draw-here (happend2 (vline 2) (vline 4) #:valign 'center))
(draw-here (happend2 (vline 2) (vline 4) #:valign 'bottom))]}
@defproc[(happend [y raart?] [x raart?] ... [#:valign valign (or/c
valign/c #f) #f] [#:reverse? reverse? boolean? #f]) raart?]{Like
@racket[happend2], but for many arguments.
@ex[(draw-here (happend (vline 2) (vline 3) (vline 4) #:valign 'top))]}
@defproc[(happend* [y-and-xs (non-empty-listof raart?)] [#:valign
valign (or/c valign/c #f) #f] [#:reverse? reverse? boolean? #f])
raart?]{Like @racket[happend], but accepts arguments as a list.
@ex[(draw-here (happend* (list (vline 2) (vline 3) (vline 4)) #:valign 'top))]}
@defproc[(para [max-width exact-nonnegative-integer?] [s string?] [#:halign halign halign/c 'left]) raart?]{An art displaying @racket[s], that is at most @racket[max-width] wide, taking multiple lines if necessary.
@ex[(draw-here (para 45 "And it came to pass that I, Nephi, said unto my father: I will go and do the things which the Lord hath commanded, for I know that the Lord giveth no commandments unto the children of men, save he shall prepare a way for them that they may accomplish the thing which he commandeth them."))]}
@defproc[(para* [max-width exact-nonnegative-integer?] [rs (listof raart?)] [#:halign halign halign/c 'left] [#:gap gap raart? (blank)]) raart?]{Like @racket[happend*], but limits the total width and uses @racket[vappend] when things get too long. @racket[para] uses this after splitting the input string into words and supplies @racket[(text " ")] as the @racket[gap].}
@defproc[(place-at [back raart?] [dr exact-nonnegative-integer?] [dh
exact-nonnegative-integer?] [front raart?]) raart?]{Renders
@racket[front] on top of @racket[back] offset by @racket[dr] rows and
@racket[dh] columns.}
@defform[(place-at* back [dr dc fore] ...) #:contracts ([back raart?]
[dr exact-nonnegative-integer?] [dc exact-nonnegative-integer?] [fore
raart?])]{Calls @racket[place-at] on a sequence of art objects from
back on the left to front on the right.}
@defproc[(frame [#:style s (or/c style/c #f) #f] [#:fg fc (or/c
color/c #f)] [#:bg bc (or/c color/c #f)] [x raart?]) raart?]{Renders
@racket[x] with a frame where the frame character's style is
controlled by @racket[s], @racket[fc], and @racket[bc].}
@defproc[(matte-at [mw exact-nonnegative-integer?] [mh
exact-nonnegative-integer?] [c exact-nonnegative-integer?] [r
exact-nonnegative-integer?] [x raart?]) raart?]{Mattes @racket[x]
inside a blank of size @racket[mw] columns and @racket[mh] rows at row
@racket[r] and column @racket[c].}
@defproc[(translate [dr exact-nonnegative-integer?] [dc
exact-nonnegative-integer?] [x raart?]) raart?]{Translates @racket[x]
by @racket[dr] rows and @racket[dc] columns.}
@defproc[(matte [w exact-nonnegative-integer?] [h
exact-nonnegative-integer?] [#:halign halign halign/c 'center]
[#:valign valign valign/c 'center] [x raart?]) raart?]{Mattes
@racket[x] inside a blank of size @racket[w]x@racket[h] with the given
alignment.}
@defproc[(inset [dw exact-nonnegative-integer?] [dh
exact-nonnegative-integer?] [x raart?]) raart?]{Insets @racket[x] with
@racket[dw] columns and @racket[dh] rows of blanks.}
@defproc[(mask [mc exact-nonnegative-integer?] [mw
exact-nonnegative-integer?] [mr exact-nonnegative-integer?] [mh
exact-nonnegative-integer?] [x raart?]) raart?]{Renders the portion of
@racket[x] inside the rectangle (@racket[mc],@racket[mr])
to (@racket[(+ mc mw)],@racket[(+ mr mh)]).}
@defproc[(crop [cc exact-nonnegative-integer?] [cw
exact-nonnegative-integer?] [cr exact-nonnegative-integer?] [ch
exact-nonnegative-integer?] [x raart?]) raart?]{Renders the portion of
@racket[x] inside the rectangle (@racket[cc],@racket[cr])
to (@racket[(+ cc cw)],@racket[(+ cr ch)]) and removes the surrounding
blanks.}
@defproc[(table [cells (listof (listof raart?))] [#:frames? frames?
boolean? #t] [#:style s (or/c style/c #f) #f] [#:fg f (or/c color/c
#f) #f] [#:bg b (or/c color/c #f) #f] [#:inset-dw dw
exact-nonnegative-integer? 0] [#:inset-dh dh
exact-nonnegative-integer? 0] [#:valign row-valign valign/c 'top]
[#:halign halign (or/c halign/c (list*of halign/c (or/c halign/c
'()))) 'left]) raart?]{Renders a table of cells where frames are added
if @racket[frames?] is non-false with style and color given by the
arguments. Cells are inset by @racket[inset-dh] rows and
@racket[inset-dw] columns. Cells are horizontally aligned with
@racket[halign]. Rows are vertically aligned with
@racket[row-valign].}
@defproc[(text-rows [cells (listof (listof any/c))]) (listof (listof
raart?))]{Transforms a matrix of content into a matrix of art objects,
using @racket[~a] composed with @racket[text] if they are not already
art objects.}
@defproc[(if-drawn [f (-> exact-nonnegative-integer?
exact-nonnegative-integer? exact-nonnegative-integer?
exact-nonnegative-integer? any)] [x raart?]) raart?]{Renders
@racket[x] and if it ends up being displayed, then calls @racket[f]
with the actual bounding box, given as a row, column, width, and
height.}
@defproc[(place-cursor-after [x raart?] [cr
exact-nonnegative-integer?] [ch exact-nonnegative-integer?])
raart?]{Renders @racket[x] but places the cursor at row @racket[cr]
and column @racket[ch] afterwards.}
@defproc[(without-cursor [x raart?]) raart?]{Renders @racket[x], but
signals to @racket[draw] to not display the cursor, if this is the art
object given to it. (That is, this has no effect if composed with
other drawing operations.)}
@section{lux integration}
@defmodule[raart/lux-chaos]
@racketmodname[raart] provides integration with @racketmodname[lux]
via the @racketmodname[ansi] module.
@defproc[(make-raart [#:mouse? mouse? boolean? #f]) chaos?]{
Returns a @tech[#:doc '(lib "lux/scribblings/lux.scrbl")]{chaos} that
manages the terminal.
The values that @racket[word-event] is called with are characters or
@racket[screen-size-report] structures. If @racket[mouse?] is
non-false, then @racket[any-mouse-event], @racket[mouse-focus-event],
or @racket[mouse-event] structures may also be provided.
The values that @racket[word-output] should return are @racket[raart?]
objects. The drawing will use @racket[make-cached-buffer] to optimize
the display process.
}