code wiki / _hdl_build / nx_wiki_page_lib.nx
nx_wiki_page_lib.nx source
↩ module page · 165 lines · 9359 B
1// nx_wiki_page_lib.nx -- the reusable page emitter for the autonomous wiki. wp_emit_page() turns ONE
2// workstream record (a memory project-*.md = our real work) into an S-class anatomy page (Lead ->
3// Infobox -> Body[md render w/ [[wikilinks]]] -> See also -> Category) on the shared skin, per the
4// Wikipedia MoS/Layout the Nishi researcher fetched. Used by nx_wiki_workstream_page (one page) AND
5// nx_wiki_build (all of them). Sovereign: nx_syscalls + nx_wiki_skin_lib. license_tier: ORIGINAL
6import "nx_syscalls.nx"
7import "nx_wiki_skin_lib.nx"
8const K_MAGIC_2048: i64 = 2048
9
10func wp_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
11func wp_slurp(path: *u8, buf: *u8, cap: i64) -> i64 {
12 let fd: i64 = sys_openat_rd(path)
13 if fd < 0 { return 0 }
14 var total: i64 = 0
15 var nrd: i64 = sys_read(fd, buf, cap)
16 while nrd > 0 { total = total + nrd; if total >= cap { nrd = 0 } else { nrd = sys_read(fd, ((buf as i64) + total) as *u8, cap - total) } }
17 sys_close(fd)
18 return total
19}
20func wp_find_from(buf: *u8, len: i64, from: i64, pat: *u8) -> i64 {
21 var pl: i64 = 0; while pat[pl] != (0 as u8) { pl = pl + 1 }
22 if pl == 0 { return 0 - 1 }
23 var i: i64 = from
24 while i + pl <= len { var j: i64 = 0; var ok: i64 = 1; while j < pl { if buf[i + j] != pat[j] { ok = 0; j = pl } else { j = j + 1 } } if ok == 1 { return i } i = i + 1 }
25 return 0 - 1
26}
27func wp_line_end(buf: *u8, len: i64, s: i64) -> i64 { var e: i64 = s; while e < len { if buf[e] == (10 as u8) { return e } e = e + 1 } return len }
28func wp_fm_field(buf: *u8, len: i64, key: *u8, out: *u8, cap: i64) -> i64 {
29 let p: i64 = wp_find_from(buf, len, 0, key)
30 if p < 0 { out[0] = 0 as u8; return 0 }
31 var s: i64 = p
32 while s < len {
33 if buf[s] == (58 as u8) {
34 s = s + 1
35 if s < len { if buf[s] == (32 as u8) { s = s + 1 } }
36 var o: i64 = 0
37 while s < len { if buf[s] == (10 as u8) { s = len } else { if buf[s] == (13 as u8) { s = len } else { if o < cap - 1 { out[o] = buf[s]; o = o + 1 } s = s + 1 } } }
38 out[o] = 0 as u8
39 return o
40 }
41 s = s + 1
42 }
43 out[0] = 0 as u8
44 return 0
45}
46func wp_esc1(dst: *u8, o: i64, c: i64) -> i64 {
47 if c == 60 { return sk_cat(dst, o, "<" as *u8) }
48 if c == 62 { return sk_cat(dst, o, ">" as *u8) }
49 if c == 38 { return sk_cat(dst, o, "&" as *u8) }
50 dst[o] = c as u8; return o + 1
51}
52func wp_esc(dst: *u8, o: i64, buf: *u8, a: i64, b: i64) -> i64 { var oo: i64 = o; var i: i64 = a; while i < b { oo = wp_esc1(dst, oo, buf[i] as i64); i = i + 1 } return oo }
53func wp_find2(buf: *u8, i: i64, end: i64, a: u8, b: u8) -> i64 { var k: i64 = i; while k + 1 < end { if buf[k] == a { if buf[k + 1] == b { return k } } k = k + 1 } return end }
54func wp_find1(buf: *u8, i: i64, end: i64, a: u8) -> i64 { var k: i64 = i; while k < end { if buf[k] == a { return k } k = k + 1 } return end }
55func wp_inline(dst: *u8, off: i64, buf: *u8, a: i64, b: i64) -> i64 {
56 var o: i64 = off; var i: i64 = a
57 while i < b {
58 let c: i64 = buf[i] as i64
59 if c == 91 { if i + 1 < b { if buf[i + 1] == (91 as u8) {
60 let k: i64 = wp_find2(buf, i + 2, b, 93 as u8, 93 as u8)
61 o = sk_cat(dst, o, "<a href=\"" as *u8)
62 var t: i64 = i + 2; while t < k { dst[o] = buf[t]; o = o + 1; t = t + 1 }
63 o = sk_cat(dst, o, ".html\">" as *u8)
64 o = wp_esc(dst, o, buf, i + 2, k)
65 o = sk_cat(dst, o, "</a>" as *u8)
66 i = k + 2
67 } else { o = wp_esc1(dst, o, 91); i = i + 1 } } else { o = wp_esc1(dst, o, 91); i = i + 1 } }
68 else { if c == 42 { if i + 1 < b { if buf[i + 1] == (42 as u8) {
69 let k: i64 = wp_find2(buf, i + 2, b, 42 as u8, 42 as u8)
70 o = sk_cat(dst, o, "<strong>" as *u8); o = wp_esc(dst, o, buf, i + 2, k); o = sk_cat(dst, o, "</strong>" as *u8)
71 i = k + 2
72 } else { o = wp_esc1(dst, o, 42); i = i + 1 } } else { o = wp_esc1(dst, o, 42); i = i + 1 } }
73 else { if c == 96 {
74 let k: i64 = wp_find1(buf, i + 1, b, 96 as u8)
75 o = sk_cat(dst, o, "<code>" as *u8); o = wp_esc(dst, o, buf, i + 1, k); o = sk_cat(dst, o, "</code>" as *u8)
76 i = k + 1
77 }
78 else { o = wp_esc1(dst, o, c); i = i + 1 } } }
79 }
80 return o
81}
82func wp_body(dst: *u8, off: i64, buf: *u8, start: i64, len: i64) -> i64 {
83 var o: i64 = off; var in_list: i64 = 0; var ls: i64 = start
84 while ls < len {
85 let le: i64 = wp_line_end(buf, len, ls)
86 var blank: i64 = 1; var j: i64 = ls
87 while j < le { if buf[j] != (32 as u8) { blank = 0; j = le } else { j = j + 1 } }
88 if blank == 1 { if in_list == 1 { o = sk_cat(dst, o, "</ul>\n" as *u8); in_list = 0 } }
89 else {
90 if buf[ls] == (35 as u8) {
91 if in_list == 1 { o = sk_cat(dst, o, "</ul>\n" as *u8); in_list = 0 }
92 var h: i64 = 0; var p: i64 = ls
93 while p < le { if buf[p] == (35 as u8) { h = h + 1; p = p + 1 } else { p = le } }
94 var cs: i64 = ls + h
95 if cs < le { if buf[cs] == (32 as u8) { cs = cs + 1 } }
96 var tag: *u8 = "h2" as *u8
97 if h == 3 { tag = "h3" as *u8 }
98 if h >= 4 { tag = "h4" as *u8 }
99 o = sk_cat(dst, o, "<" as *u8); o = sk_cat(dst, o, tag); o = sk_cat(dst, o, ">" as *u8)
100 o = wp_inline(dst, o, buf, cs, le)
101 o = sk_cat(dst, o, "</" as *u8); o = sk_cat(dst, o, tag); o = sk_cat(dst, o, ">\n" as *u8)
102 }
103 else { var islist: i64 = 0
104 if buf[ls] == (45 as u8) { if ls + 1 < le { if buf[ls + 1] == (32 as u8) { islist = 1 } } }
105 if islist == 1 {
106 if in_list == 0 { o = sk_cat(dst, o, "<ul>\n" as *u8); in_list = 1 }
107 o = sk_cat(dst, o, "<li>" as *u8); o = wp_inline(dst, o, buf, ls + 2, le); o = sk_cat(dst, o, "</li>\n" as *u8)
108 } else {
109 if in_list == 1 { o = sk_cat(dst, o, "</ul>\n" as *u8); in_list = 0 }
110 o = sk_cat(dst, o, "<p>" as *u8); o = wp_inline(dst, o, buf, ls, le); o = sk_cat(dst, o, "</p>\n" as *u8)
111 }
112 }
113 }
114 ls = le + 1
115 }
116 if in_list == 1 { o = sk_cat(dst, o, "</ul>\n" as *u8) }
117 return o
118}
119func wp_seealso(dst: *u8, off: i64, buf: *u8, start: i64, len: i64) -> i64 {
120 var o: i64 = off; var count: i64 = 0
121 o = sk_cat(dst, o, "<ul>\n" as *u8)
122 var i: i64 = start
123 while i + 1 < len {
124 if buf[i] == (91 as u8) { if buf[i + 1] == (91 as u8) {
125 let k: i64 = wp_find2(buf, i + 2, len, 93 as u8, 93 as u8)
126 o = sk_cat(dst, o, "<li><a href=\"" as *u8)
127 var t: i64 = i + 2; while t < k { dst[o] = buf[t]; o = o + 1; t = t + 1 }
128 o = sk_cat(dst, o, ".html\">" as *u8); o = wp_esc(dst, o, buf, i + 2, k); o = sk_cat(dst, o, "</a></li>\n" as *u8)
129 count = count + 1
130 i = k + 2
131 } else { i = i + 1 } } else { i = i + 1 }
132 }
133 if count == 0 { o = sk_cat(dst, o, "<li class=\"sub\">no linked workstreams</li>\n" as *u8) }
134 o = sk_cat(dst, o, "</ul>\n" as *u8)
135 return o
136}
137
138// THE PAGE: render record `rec[0..slen)` into `out`, return HTML length. Skips records with no name.
139func wp_emit_page(out: *u8, rec: *u8, slen: i64) -> i64 {
140 let name: *u8 = sys_mmap(256); wp_fm_field(rec, slen, "name:" as *u8, name, 256)
141 if name[0] == (0 as u8) { return 0 }
142 let desc: *u8 = sys_mmap(K_MAGIC_2048); wp_fm_field(rec, slen, "description:" as *u8, desc, K_MAGIC_2048)
143 let typ: *u8 = sys_mmap(64); wp_fm_field(rec, slen, "\n type:" as *u8, typ, 64)
144 if typ[0] == (0 as u8) { wp_fm_field(rec, slen, "type:" as *u8, typ, 64) }
145
146 var body_start: i64 = 0
147 let close: i64 = wp_find_from(rec, slen, 3, "\n---" as *u8)
148 if close >= 0 { var bs: i64 = close + 4; while bs < slen { if rec[bs] == (10 as u8) { bs = bs + 1; body_start = bs; bs = slen } else { bs = bs + 1 } } }
149
150 var w: i64 = 0
151 w = skin_open(out, w, name, "ws" as *u8)
152 w = sk_cat(out, w, "<h1>" as *u8); w = wp_esc(out, w, name, 0, wp_slen(name)); w = sk_cat(out, w, "</h1>\n" as *u8)
153 w = sk_cat(out, w, "<p class=\"sub\">" as *u8); w = wp_inline(out, w, desc, 0, wp_slen(desc)); w = sk_cat(out, w, "</p>\n" as *u8)
154 w = sk_cat(out, w, "<table><thead><tr><th colspan=2>Workstream</th></tr></thead><tbody>" as *u8)
155 w = sk_cat(out, w, "<tr><td>Name</td><td><code>" as *u8); w = wp_esc(out, w, name, 0, wp_slen(name)); w = sk_cat(out, w, "</code></td></tr>" as *u8)
156 w = sk_cat(out, w, "<tr><td>Type</td><td>" as *u8); w = wp_esc(out, w, typ, 0, wp_slen(typ)); w = sk_cat(out, w, "</td></tr>" as *u8)
157 w = sk_cat(out, w, "<tr><td>Source</td><td class=\"sub\">live work record (not a TSV)</td></tr></tbody></table>\n" as *u8)
158 w = sk_cat(out, w, "<h2>Detail</h2>\n" as *u8)
159 w = wp_body(out, w, rec, body_start, slen)
160 w = sk_cat(out, w, "<h2>See also</h2>\n" as *u8)
161 w = wp_seealso(out, w, rec, body_start, slen)
162 w = sk_cat(out, w, "<h2>Category</h2>\n<p><a href=\"index.html\">" as *u8); w = wp_esc(out, w, typ, 0, wp_slen(typ)); w = sk_cat(out, w, "</a></p>\n" as *u8)
163 w = skin_close(out, w, sys_now_realtime_sec())
164 return w
165}