6 std.fput(2, "Error: {}\n", e)
8 regurgitate(digest(ingest(s)), 72)
12 type paragraph = struct
13 first_line_prefix : char[:]
14 gen_line_prefix : char[:]
23 `Reading_line_last_was_ws
29 Read each line, and strip off the prefix (the whitespace, markers
30 like -/•/·/#/45:/_1_/) from the content. Each line becomes its own
31 paragraph. If the content is all whitespace, the paragraph is
34 Now collapse all paragraphs. Empty paragraphs with equivalent
35 prefixes (that is, up to whitespace) collapse together. Non-empty
36 paragraphs with equivalent prefixes collapse together. If two
37 adjacent, non-empty paragraphs A, B have non-equivalent prefixes, A
38 is preceded by an empty paragraph (or nothing), B is anteceded by an
39 empty paragraph (or nothing), AND A itself was not collapsed, then
40 merge A and B, with A governing the first_line_prefix and B the
43 Now output. That's easy, you made Ori take your stupid Unicode tables
44 so you know what the cell width is.
47 /* Turn input slop into paragraphs */
48 const ingest = { str : byte[:]
49 var s : state = `Reading_prefix
50 var p : paragraph[:] = [][:]
51 var p_cur : paragraph = [
52 .first_line_prefix = [][:],
53 .gen_line_prefix = [][:],
58 for c : std.bychar(str)
65 .first_line_prefix = [][:],
66 .gen_line_prefix = [][:],
79 std.slpush(&p_cur.content, c)
81 std.slpush(&p_cur.first_line_prefix, c)
84 std.slpush(&p_cur.content, c)
86 s = `Reading_line_last_was_ws
88 | `Reading_line_last_was_ws:
90 std.slpush(&p_cur.content, c)
96 if p_cur.first_line_prefix.len > 0 || p_cur.content.len > 0
103 /* Do the paragraph joining thing */
106 for var j = 0; j < p.len; ++j
107 p[j].empty = (p[j].content.len == 0)
111 for var j = 0; j + 1 < p.len; ++j
112 if p[j].empty == p[j + 1].empty && equiv_prefixes(p[j].first_line_prefix, p[j + 1].first_line_prefix)
114 p[j].gen_line_prefix = std.sldup(p[j + 1].first_line_prefix)
116 merge_para(&p, j, j + 1)
123 for var j = 0; j + 1 < p.len; ++j
124 if j > 0 && !p[j - 1].empty
128 if j + 2 < p.len && !p[j + 2].empty
132 if p[j].empty || p[j + 1].empty || p[j].merged
136 p[j].gen_line_prefix = std.sldup(p[j + 1].first_line_prefix)
137 merge_para(&p, j, j + 1)
140 /* The unmerged give no distinction to the first */
141 for var j = 0; j < p.len; ++j
143 p[j].gen_line_prefix = std.sldup(p[j].first_line_prefix)
147 /* Finally, strip whitespace from the end of content */
148 for var j = 0; j < p.len; ++j
149 var c = &p[j].content
150 while c#.len > 0 && std.isblank(c#[c#.len - 1])
151 std.sldel(c, c#.len - 1)
158 const regurgitate = {p, max
159 var sb : std.strbuf# = std.mksb()
163 /* maybe we can get away with dropping the prefix? */
164 var need_prefix = false
165 for c : a.first_line_prefix
176 /* Oh well, just handle it normally */
180 for c : a.first_line_prefix
182 cur_pos += std.cellwidth(c)
185 /* precalculate this */
186 var gen_prefix_len = 0
187 for c : a.gen_line_prefix
188 gen_prefix_len += std.cellwidth(c)
191 var st, sn, e, wt, wn
193 while j < a.content.len
194 (st, sn, e, wt, wn) = hypothetical_forward(a.content, j)
195 if cur_pos + wt > max && gen_prefix_len + wn <= max
197 for c : a.gen_line_prefix
200 for var k = sn; k < e; ++k
201 std.sbputc(sb, a.content[k])
203 cur_pos = gen_prefix_len + wn
205 for var k = st; k < e; ++k
206 std.sbputc(sb, a.content[k])
214 std.sbputc(sb, ('\n' : char))
217 std.writeall(1, std.sbfin(sb))
220 const equiv_prefixes = {a, b
224 while ak < a.len && std.isblank(a[ak])
228 while bk < b.len && std.isblank(b[bk])
232 if (ak < a.len) != (bk < b.len)
250 std.slfree(p.first_line_prefix)
251 std.slfree(p.gen_line_prefix)
252 std.slfree(p.content)
255 const merge_para = {p, j, k
256 if (p#[j].content.len > 0 && !std.isblank(p#[j].content[p#[j].content.len - 1]))
257 /* TODO: what if you use U+3000 instead of ' '? Huh? */
258 std.slpush(&(p#[j].content), (' ' : char))
260 std.sljoin(&(p#[j].content), p#[k].content)
266 const hypothetical_forward = {c, j
267 var start_if_this_line = j
268 var start_if_next_line = j
270 var width_if_this_line = 0
271 var width_if_next_line = 0
272 var past_first_blanks = false
276 By the normalization in ingest() we should only have
277 one blank separating non-blanks. Still, let's be damn
280 if !past_first_blanks
281 if!std.isblank(c[end])
282 past_first_blanks = true
283 start_if_next_line = end
285 width_if_this_line += std.cellwidth(c[end])
290 if std.isblank(c[end])
293 width_if_this_line += std.cellwidth(c[end])
294 width_if_next_line += std.cellwidth(c[end])
300 -> (start_if_this_line, start_if_next_line, end, width_if_this_line, width_if_next_line)