-
Notifications
You must be signed in to change notification settings - Fork 5
/
rich-text.red
160 lines (149 loc) · 3.16 KB
/
rich-text.red
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
Red [
Title: "Rich Text Dialect"
Author: "Boleslav Březovský"
File: %rich-text.red
Rights: "Copyright (C) 2019 Boleslav Březovský. All rights reserved."
License: 'BSD
Date: "23-10-2016"
Note: {
Rich Text Dialect takes Lest source and converts it to Draw dialect
that can be supplied to Red/View.
}
To-Do: {
Links should be part of Rich Text Dialect.
}
]
whitespace?: function [char][find " ^/" char]
; ----------------
rich-text: function [
"Return Draw block created from Rich Text Dialect"
dialect "Rich Text Dialect input"
width "Width to wrap text at"
/info "Return block! with output as first item and info as others (currently SIZE)"
] [
emit-text: func [/local text area] [
unless empty? line [
text: copy line
append out reduce ['text as-pair start-pos char-size/y text]
area: make map! compose [
type: (area-type)
offset: (as-pair start-pos y-pos)
size: (size-text/with face text)
text: (text)
]
if equal? 'link area-type [
area/link: take/last stack
]
append areas area
blocks: blocks + 1
]
]
fix-height: does [
; --- place blocks on Y-axis
out: tail out
while [not zero? blocks] [
if pair? out/1 [
out/1/y: y-pos + line-height - out/1/y ;+ font-offset
blocks: blocks - 1
]
out: back out
]
out: head out
; ---
]
process-text: func [
text
] [
start-pos: x-pos
char-size: 0x0
; print ["Process:" start-pos mold text]
clear line
clear word
foreach char text [
char-size: size-text/with face form char
if char-size/y > line-height [line-height: char-size/y]
x-pos: x-pos + char-size/x
case [
whitespace? char (
append word char
either any [
x-pos > width
equal? newline char
] [
if equal? newline char [append line head remove back tail copy word]
emit-text
fix-height
clear line
start-pos: x-pos: 0
y-pos: y-pos + line-height
line-height: 0
] [
append line copy word
]
clear word
)
equal? #"^-" char (
append word " " ;tab-size
)
true (
append word char
)
]
]
append line word
emit-text
fix-height
]
out: make block! 2000
font: none
value: none
stack: make block! 20
line-width: 0
start-pos: 0
x-pos: 0
y-pos: 0
blocks: 0
font-offset: 0
line-height: 0
line-spacing: 3 ; FIXME: Hardcoded height
line: make string! 200
word: make string! 50
areas: make block! 50
area-type: none
face: make face! [
font: fonts/text
]
set-font: func [
font
] [
repend out ['font font]
face/font: font
font-offset: line-height - line-spacing - second size-text/with face "M"
]
font-rule: [
'font set value [word! | path!]
(set-font get value)
]
text-rule: [
set value string!
(
area-type: 'area
process-text value
)
]
link-rule: [
'link
set value string!
(append stack value)
set value url!
(
append stack value
set-font fonts/link
area-type: 'link
; TODO: penultimate: func [series] [skip tail series -2]
process-text take skip tail stack -2
)
]
parse dialect [some [font-rule | link-rule | text-rule]]
either info [reduce [out as-pair width y-pos + line-height areas]] [out]
]