code wiki / _hdl_build / nx_wiki_shell.nx

nx_wiki_shell.nx source

↩ module page · 545 lines · 29420 B

1// nx_wiki_shell.nx -- THE AUTOMATIC PAGE BUILDER: the standard wiki-page furniture as reusable 2// emitters, so EVERY Nishi wiki page clears the MediaWiki/Wikipedia feature bar measured by 3// nx_wiki_exceed. Each function appends to a caller buffer and returns the new offset. 4// 5// Features emitted (the census signals): responsive-viewport, print-css (media="print"), 6// lang-links (hreflang=), permalink (rel="bookmark") [sh_head]; navbar (<nav), search (type="search"), 7// wikilinks (href="/wiki/) [sh_nav]; toc (class="toc") [sh_toc_*]; section-anchors (<h2 id=) 8// [sh_section]; infobox (class="infobox") [sh_infobox_*]; references (class="references") [sh_refs_*]; 9// categories (class="catlinks"), seealso (id="seealso"), edit-affordance (class="wiki-edit") [sh_footer]. 10// The page supplies its own <h1> + freshness chip + body. Sovereign: nx_syscalls. license_tier: ORIGINAL 11 12import "nx_syscalls.nx" 13import "nx_wiki_backlinks.nx" 14import "nx_native_config.nx" 15 16func sh_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != 0 as u8 { n = n + 1 } return n } 17func sh_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != 0 as u8 { dst[off + i] = s[i]; i = i + 1 } return off + i } 18func sh_catn(dst: *u8, off: i64, v: i64) -> i64 { 19 var m: i64 = v; var o: i64 = off 20 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m } 21 let t: *u8 = sys_mmap(28); var k: i64 = 0 22 if m == 0 { t[0] = 48 as u8; k = 1 } 23 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 24 var i: i64 = 0 25 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 } 26 return o + k 27} 28 29// HEAD: charset + responsive viewport + title + permalink + interlanguage link + main CSS + PRINT CSS. 30func sh_head(buf: *u8, off: i64, title: *u8, slug: *u8) -> i64 { 31 var w: i64 = off 32 w = sh_cat(buf, w, "<!DOCTYPE html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n" as *u8) 33 w = sh_cat(buf, w, "<title>" as *u8); w = sh_cat(buf, w, title); w = sh_cat(buf, w, " &mdash; Nishi Wiki</title>\n" as *u8) 34 w = sh_cat(buf, w, "<link rel=\"bookmark\" href=\"/wiki/" as *u8); w = sh_cat(buf, w, slug); w = sh_cat(buf, w, ".html\">\n" as *u8) 35 w = sh_cat(buf, w, "<link rel=\"alternate\" hreflang=\"en\" href=\"/wiki/" as *u8); w = sh_cat(buf, w, slug); w = sh_cat(buf, w, ".html\">\n" as *u8) 36 w = sh_cat(buf, w, "<style>" as *u8) 37 w = sh_cat(buf, w, "body{font-family:-apple-system,Segoe UI,Roboto,sans-serif;max-width:920px;margin:0 auto;padding:0 24px 4vh;color:#14141e;line-height:1.6}" as *u8) 38 w = sh_cat(buf, w, "h1{font-size:2.2rem;margin:.6rem 0 .1rem}h2{color:#2a4d8f;margin-top:2rem;font-size:1.25rem;border-bottom:2px solid #eef2fb;padding-bottom:.2rem}h2 a{color:inherit;text-decoration:none}h3{font-size:1rem;margin:1rem 0 .3rem}" as *u8) 39 w = sh_cat(buf, w, ".fresh{display:inline-block;background:#eef7ee;border:1px solid #bcdcbc;color:#225522;border-radius:6px;padding:6px 12px;font-size:.85rem;margin:.4rem 0}" as *u8) 40 w = sh_cat(buf, w, ".lede{background:#1b1b26;color:#e8eef8;border-radius:8px;padding:16px 20px;font-size:1rem}.lede strong{color:#9ecbff}" as *u8) 41 w = sh_cat(buf, w, ".why{background:#eef2fb;border-left:4px solid #2a4d8f;border-radius:4px;padding:12px 16px;font-size:.92rem;margin:1rem 0}" as *u8) 42 w = sh_cat(buf, w, "table{border-collapse:collapse;width:100%;margin:.8rem 0;font-size:.9rem}th,td{border:1px solid #dcdce4;padding:5px 8px;text-align:left}th{background:#f4f4f8}" as *u8) 43 w = sh_cat(buf, w, "code{background:#f0f0f4;padding:1px 5px;border-radius:3px;font-size:.9em}pre{background:#1b1b26;color:#d8e8d8;padding:10px 13px;border-radius:6px;overflow-x:auto;font-size:.85rem}" as *u8) 44 w = sh_cat(buf, w, ".ev{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:.85rem;background:#1b1b26;color:#d8e8d8;padding:7px 10px;border-radius:5px;white-space:pre-wrap}" as *u8) 45 w = sh_cat(buf, w, "ul{padding-left:1.2rem}li{margin:.25rem 0}.foot{margin-top:3rem;font-size:.8rem;color:#888;border-top:1px solid #eee;padding-top:1rem}a{color:#2a4d8f}" as *u8) 46 w = sh_cat(buf, w, "nav.wiki-nav{position:sticky;top:0;background:#fff;border-bottom:1px solid #e4e4ee;display:flex;gap:14px;align-items:center;padding:10px 0;margin-bottom:1rem;flex-wrap:wrap;z-index:9}.wiki-nav a{font-weight:600;text-decoration:none}.wiki-nav form{margin-left:auto}.wiki-nav input{border:1px solid #ccd;border-radius:6px;padding:5px 9px;font-size:.9rem}" as *u8) 47 w = sh_cat(buf, w, "nav.toc{background:#fafaff;border:1px solid #e4e4ee;border-radius:8px;padding:10px 16px;margin:1rem 0;font-size:.9rem}nav.toc b{display:block;margin-bottom:.3rem;color:#555}nav.toc ol{margin:0;padding-left:1.3rem}" as *u8) 48 w = sh_cat(buf, w, "aside.infobox{float:right;width:280px;margin:0 0 1rem 1.2rem;border:1px solid #dcdce4;border-radius:8px;background:#fbfbfe;font-size:.85rem}aside.infobox .ib-h{background:#2a4d8f;color:#fff;padding:7px 11px;border-radius:8px 8px 0 0;font-weight:700}aside.infobox table{margin:0}aside.infobox td{border:none;border-top:1px solid #eee}" as *u8) 49 w = sh_cat(buf, w, "section.references{font-size:.9rem}section.references ol{padding-left:1.3rem}#seealso ul{columns:2}.catlinks{margin-top:1.4rem;padding:8px 12px;background:#f4f4f8;border-radius:6px;font-size:.85rem}.catlinks a{margin-right:10px}.wiki-edit{float:right;font-size:.8rem;border:1px solid #ccd;border-radius:6px;padding:2px 9px;text-decoration:none}" as *u8) 50 w = sh_cat(buf, w, "@media (max-width:680px){aside.infobox{float:none;width:auto;margin:0 0 1rem}#seealso ul{columns:1}}" as *u8) 51 w = sh_cat(buf, w, "</style>\n" as *u8) 52 w = sh_cat(buf, w, "<style media=\"print\">nav.wiki-nav,.wiki-edit,.wiki-nav form{display:none}body{max-width:none}a{color:#000;text-decoration:none}aside.infobox{float:none}</style>\n" as *u8) 53 w = sh_cat(buf, w, "</head><body>\n" as *u8) 54 return w 55} 56 57// NAV bar: internal wikilinks + an on-page search box + an edit affordance. 58func sh_nav(buf: *u8, off: i64, slug: *u8) -> i64 { 59 var w: i64 = off 60 w = sh_cat(buf, w, "<nav class=\"wiki-nav\"><a href=\"/wiki/start.html\">&#9750; AI Start</a> <a href=\"/wiki/charter.html\">Charter</a> <a href=\"/wiki/start.html#tasks\">Task streams</a> <a href=\"/wiki/start.html#docs\">Docs</a>" as *u8) 61 w = sh_cat(buf, w, "<a class=\"wiki-edit\" href=\"/wiki/edit?p=" as *u8); w = sh_cat(buf, w, slug); w = sh_cat(buf, w, "\">&#9998; edit</a>" as *u8) 62 w = sh_cat(buf, w, "<form action=\"/wiki/search.html\" method=\"get\"><input type=\"search\" name=\"q\" placeholder=\"Search the wiki\" aria-label=\"Search\"></form></nav>\n" as *u8) 63 return w 64} 65 66// TABLE OF CONTENTS (page lists its own sections). 67func sh_toc_open(buf: *u8, off: i64) -> i64 { return sh_cat(buf, off, "<nav class=\"toc\" aria-label=\"Contents\"><b>Contents</b><ol>\n" as *u8) } 68func sh_toc_item(buf: *u8, off: i64, id: *u8, title: *u8) -> i64 { 69 var w: i64 = off 70 w = sh_cat(buf, w, "<li><a href=\"#" as *u8); w = sh_cat(buf, w, id); w = sh_cat(buf, w, "\">" as *u8); w = sh_cat(buf, w, title); w = sh_cat(buf, w, "</a></li>\n" as *u8) 71 return w 72} 73func sh_toc_close(buf: *u8, off: i64) -> i64 { return sh_cat(buf, off, "</ol></nav>\n" as *u8) } 74 75// ANCHORED section heading (deep-linkable). 76func sh_section(buf: *u8, off: i64, id: *u8, title: *u8) -> i64 { 77 var w: i64 = off 78 w = sh_cat(buf, w, "<h2 id=\"" as *u8); w = sh_cat(buf, w, id); w = sh_cat(buf, w, "\"><a href=\"#" as *u8); w = sh_cat(buf, w, id); w = sh_cat(buf, w, "\">" as *u8); w = sh_cat(buf, w, title); w = sh_cat(buf, w, "</a></h2>\n" as *u8) 79 return w 80} 81 82// INFOBOX (structured summary). 83func sh_infobox_open(buf: *u8, off: i64, title: *u8) -> i64 { 84 var w: i64 = off 85 w = sh_cat(buf, w, "<aside class=\"infobox\"><div class=\"ib-h\">" as *u8); w = sh_cat(buf, w, title); w = sh_cat(buf, w, "</div><table>\n" as *u8) 86 return w 87} 88func sh_infobox_row(buf: *u8, off: i64, k: *u8, v: *u8) -> i64 { 89 var w: i64 = off 90 w = sh_cat(buf, w, "<tr><td><strong>" as *u8); w = sh_cat(buf, w, k); w = sh_cat(buf, w, "</strong></td><td>" as *u8); w = sh_cat(buf, w, v); w = sh_cat(buf, w, "</td></tr>\n" as *u8) 91 return w 92} 93func sh_infobox_close(buf: *u8, off: i64) -> i64 { return sh_cat(buf, off, "</table></aside>\n" as *u8) } 94 95// REFERENCES section (the page appends <li> items between open/close). 96func sh_refs_open(buf: *u8, off: i64) -> i64 { return sh_cat(buf, off, "<section class=\"references\"><h2 id=\"refs\"><a href=\"#refs\">References &amp; evidence</a></h2><ol>\n" as *u8) } 97func sh_refs_close(buf: *u8, off: i64) -> i64 { return sh_cat(buf, off, "</ol></section>\n" as *u8) } 98 99// ============================================================================= 100// WALKABILITY FURNITURE (wiki nav-tree arc): dense bidirectional link-tree + 101// learning paths, the S-class fix for the flat/dead-end F-class nav. The curated 102// tree/path/see-also/tags come from knowledge/registry/wiki_links.tsv (loaded by 103// sh_links_load below); forward+back links stay COMPUTED from page bodies. 104// ============================================================================= 105 106// ---- wiki_links.tsv reader (curated tree/path/related/tags) ----------------- 107// Loaded ONCE per page into an NxWikiLinks; every furniture emitter reads it. 108// Columns: slug<TAB>parent<TAB>prev<TAB>next<TAB>related<TAB>tags<TAB>diataxis 109const SH_WL_MAXROWS: i64 = 64 110const SH_WL_MAXBYTES: i64 = 65536 111const SH_WL_NCOLS: i64 = 7 112 113struct NxWikiLinks { 114 raw: *u8 // mutable copy of the file (TABs/NLs overwritten with NUL) 115 nrows: i64 116 // per-row, per-col: pointer (as i64) to a NUL-terminated field inside raw ('-'/empty => 0) 117 cells: *i64 // SH_WL_MAXROWS * SH_WL_NCOLS i64s 118 valid: i64 119} 120 121func sh_wl_field(wl: *NxWikiLinks, row: i64, col: i64) -> *u8 { 122 if wl.valid != 1 { return 0 as *u8 } 123 if row < 0 { return 0 as *u8 } 124 if row >= wl.nrows { return 0 as *u8 } 125 if col < 0 { return 0 as *u8 } 126 if col >= SH_WL_NCOLS { return 0 as *u8 } 127 return wl.cells[row * SH_WL_NCOLS + col] as *u8 128} 129 130// streq for NUL-terminated strings (one may be 0 => not equal unless both 0-len). 131func sh_streq(a: *u8, b: *u8) -> i64 { 132 if (a as i64) == 0 { return 0 } 133 if (b as i64) == 0 { return 0 } 134 var i: i64 = 0 135 while a[i] != 0 as u8 { 136 if a[i] != b[i] { return 0 } 137 i = i + 1 138 } 139 if b[i] != 0 as u8 { return 0 } 140 return 1 141} 142 143// find the row index for a slug; -1 if absent. 144func sh_wl_row_of(wl: *NxWikiLinks, slug: *u8) -> i64 { 145 var r: i64 = 0 146 while r < wl.nrows { 147 let s: *u8 = sh_wl_field(wl, r, 0) 148 if sh_streq(s, slug) == 1 { return r } 149 r = r + 1 150 } 151 return 0 - 1 152} 153 154// the native nav-tree store prefix (no TSV; authored by nx_wiki_links_seed). 155func sh_wikilinks_prefix() -> *u8 { return "knowledge/store/wiki-links-\x00" as *u8 } 156// map a named field of a decoded row to a cell pointer; "-"/empty/absent -> 0 (the old '-'=>empty rule). 157func sh_wl_cell(keys: *i64, vals: *i64, nf: i64, name: *u8) -> i64 { 158 let v: *u8 = ncfg_field(keys, vals, nf, name) 159 if (v as i64) == 0 { return 0 } 160 if v[0] == 0 as u8 { return 0 } 161 if v[0] == 45 as u8 { if v[1] == 0 as u8 { return 0 } } 162 return v as i64 163} 164// Load the curated wiki nav tree into wl from the NATIVE seg_store (no TSV). `path` is vestigial 165// (kept for source-compat with the existing callers); the tree lives in knowledge/store/wiki-links- 166// via nx_native_config (tag "wl"). Columns are looked up BY NAME and stored in wl.cells in the same 167// fixed order (slug/parent/prev/next/related/tags/diataxis), so every furniture emitter 168// (sh_wl_field / sh_wl_row_of / sh_breadcrumb / sh_tree / sh_related / sh_footer_wl) is UNCHANGED. 169// A "-"/empty field maps to 0 (root / endpoint / none). Returns nrows (>=0), or -1 if the native 170// store is absent (fail-closed: emit no nav rather than read a stale TSV). 171func sh_links_load(wl: *NxWikiLinks, path: *u8) -> i64 { 172 wl.valid = 0 173 wl.nrows = 0 174 wl.cells = sys_mmap(SH_WL_MAXROWS * SH_WL_NCOLS * 8) as *i64 175 wl.raw = 0 as *u8 176 let hh: *i64 = ncfg_open(sh_wikilinks_prefix()) 177 if (hh as i64) == 0 { return 0 - 1 } 178 let cnt: i64 = ncfg_count(hh, "wl\x00" as *u8) 179 let rk: *i64 = sys_mmap(8 * 8) as *i64 180 let rv: *i64 = sys_mmap(8 * 8) as *i64 181 var rows: i64 = 0 182 var i: i64 = 0 183 while i < cnt { 184 if rows < SH_WL_MAXROWS { 185 let rf: i64 = ncfg_row(hh, "wl\x00" as *u8, i, rk, rv, 8) 186 if rf > 0 { 187 wl.cells[rows * SH_WL_NCOLS + 0] = sh_wl_cell(rk, rv, rf, "slug\x00" as *u8) 188 wl.cells[rows * SH_WL_NCOLS + 1] = sh_wl_cell(rk, rv, rf, "parent\x00" as *u8) 189 wl.cells[rows * SH_WL_NCOLS + 2] = sh_wl_cell(rk, rv, rf, "prev\x00" as *u8) 190 wl.cells[rows * SH_WL_NCOLS + 3] = sh_wl_cell(rk, rv, rf, "next\x00" as *u8) 191 wl.cells[rows * SH_WL_NCOLS + 4] = sh_wl_cell(rk, rv, rf, "related\x00" as *u8) 192 wl.cells[rows * SH_WL_NCOLS + 5] = sh_wl_cell(rk, rv, rf, "tags\x00" as *u8) 193 wl.cells[rows * SH_WL_NCOLS + 6] = sh_wl_cell(rk, rv, rf, "diataxis\x00" as *u8) 194 rows = rows + 1 195 } 196 } 197 i = i + 1 198 } 199 wl.nrows = rows 200 wl.valid = 1 201 return rows 202} 203 204// pretty title from a slug: capitalize first letter, '_' -> ' '. Falls back to 205// the raw slug if absent. Writes into dst at off; returns new off. 206func sh_title_of(dst: *u8, off: i64, slug: *u8) -> i64 { 207 var o: i64 = off 208 if (slug as i64) == 0 { return o } 209 var i: i64 = 0 210 while slug[i] != 0 as u8 { 211 var ch: u8 = slug[i] 212 if ch == 95 as u8 { ch = 32 as u8 } // '_' -> ' ' 213 if i == 0 { if ch >= 97 as u8 { if ch <= 122 as u8 { ch = (ch - 32) as u8 } } } 214 dst[o] = ch; o = o + 1 215 i = i + 1 216 } 217 return o 218} 219 220// ---- A. BREADCRUMB: Home > parent-chain > current --------------------------- 221// Walks parent edges from slug up to the root, emitting a reversed trail. Cycle- 222// guarded by SH_WL_MAXROWS hops. Marker class="nx-breadcrumb". 223func sh_breadcrumb(buf: *u8, off: i64, wl: *NxWikiLinks, slug: *u8) -> i64 { 224 var w: i64 = off 225 w = sh_cat(buf, w, "<nav class=\"nx-breadcrumb\" aria-label=\"Breadcrumb\"><a href=\"/wiki/start.html\">&#127968; Home</a>" as *u8) 226 // collect the parent chain (slug -> parent -> ...root), bounded 227 let chain: *i64 = sys_mmap(SH_WL_MAXROWS * 8) as *i64 228 var depth: i64 = 0 229 var cur: *u8 = slug 230 var hops: i64 = 0 231 while hops < SH_WL_MAXROWS { 232 let r: i64 = sh_wl_row_of(wl, cur) 233 if r < 0 { hops = SH_WL_MAXROWS } else { 234 chain[depth] = r 235 depth = depth + 1 236 let par: *u8 = sh_wl_field(wl, r, 1) 237 if (par as i64) == 0 { hops = SH_WL_MAXROWS } else { cur = par } 238 } 239 hops = hops + 1 240 } 241 // emit from root (chain[depth-1]) down to current (chain[0]); current is plain text 242 var k: i64 = depth - 1 243 while k >= 0 { 244 let rr: i64 = chain[k] 245 let sg: *u8 = sh_wl_field(wl, rr, 0) 246 w = sh_cat(buf, w, " &rsaquo; " as *u8) 247 if k == 0 { 248 w = sh_cat(buf, w, "<span aria-current=\"page\">" as *u8) 249 w = sh_title_of(buf, w, sg) 250 w = sh_cat(buf, w, "</span>" as *u8) 251 } else { 252 w = sh_cat(buf, w, "<a href=\"/wiki/" as *u8); w = sh_cat(buf, w, sg); w = sh_cat(buf, w, ".html\">" as *u8) 253 w = sh_title_of(buf, w, sg) 254 w = sh_cat(buf, w, "</a>" as *u8) 255 } 256 k = k - 1 257 } 258 w = sh_cat(buf, w, "</nav>\n" as *u8) 259 return w 260} 261 262// ---- B. PREV / NEXT learning-path pager ------------------------------------- 263// Reads the prev/next columns for slug. Marker class="nx-prevnext". 264func sh_prevnext(buf: *u8, off: i64, wl: *NxWikiLinks, slug: *u8) -> i64 { 265 let r: i64 = sh_wl_row_of(wl, slug) 266 if r < 0 { return off } 267 let prev: *u8 = sh_wl_field(wl, r, 2) 268 let next: *u8 = sh_wl_field(wl, r, 3) 269 var w: i64 = off 270 w = sh_cat(buf, w, "<nav class=\"nx-prevnext\" aria-label=\"Learning path\">" as *u8) 271 if (prev as i64) != 0 { 272 w = sh_cat(buf, w, "<a class=\"nx-pn-prev\" rel=\"prev\" href=\"/wiki/" as *u8); w = sh_cat(buf, w, prev) 273 w = sh_cat(buf, w, ".html\">&larr; " as *u8); w = sh_title_of(buf, w, prev); w = sh_cat(buf, w, "</a>" as *u8) 274 } else { 275 w = sh_cat(buf, w, "<span class=\"nx-pn-prev nx-pn-none\"></span>" as *u8) 276 } 277 if (next as i64) != 0 { 278 w = sh_cat(buf, w, "<a class=\"nx-pn-next\" rel=\"next\" href=\"/wiki/" as *u8); w = sh_cat(buf, w, next) 279 w = sh_cat(buf, w, ".html\">" as *u8); w = sh_title_of(buf, w, next); w = sh_cat(buf, w, " &rarr;</a>" as *u8) 280 } else { 281 w = sh_cat(buf, w, "<span class=\"nx-pn-next nx-pn-none\"></span>" as *u8) 282 } 283 w = sh_cat(buf, w, "</nav>\n" as *u8) 284 return w 285} 286 287// ---- C. RELATED (curated see-also) ------------------------------------------ 288// Reads the comma-separated related column for slug. Marker class="nx-related". 289func sh_related(buf: *u8, off: i64, wl: *NxWikiLinks, slug: *u8) -> i64 { 290 let r: i64 = sh_wl_row_of(wl, slug) 291 if r < 0 { return off } 292 let rel: *u8 = sh_wl_field(wl, r, 4) 293 if (rel as i64) == 0 { return off } 294 var w: i64 = off 295 w = sh_cat(buf, w, "<aside class=\"nx-related\"><h2>Related pages</h2><ul>\n" as *u8) 296 // split rel on ',' 297 var i: i64 = 0 298 var seg_start: i64 = 0 299 var done: i64 = 0 300 while done == 0 { 301 let ch: u8 = rel[i] 302 var boundary: i64 = 0 303 if ch == 0 as u8 { boundary = 1; done = 1 } 304 if ch == 44 as u8 { boundary = 1 } // ',' 305 if boundary == 1 { 306 let seglen: i64 = i - seg_start 307 if seglen > 0 { 308 // emit a temp NUL-terminated slug 309 let t: *u8 = sys_mmap(seglen + 1) 310 var j: i64 = 0 311 while j < seglen { t[j] = rel[seg_start + j]; j = j + 1 } 312 t[seglen] = 0 as u8 313 w = sh_cat(buf, w, "<li><a href=\"/wiki/" as *u8); w = sh_cat(buf, w, t) 314 w = sh_cat(buf, w, ".html\">" as *u8); w = sh_title_of(buf, w, t); w = sh_cat(buf, w, "</a></li>\n" as *u8) 315 } 316 seg_start = i + 1 317 } 318 i = i + 1 319 if i > SH_WL_MAXBYTES { done = 1 } 320 } 321 w = sh_cat(buf, w, "</ul></aside>\n" as *u8) 322 return w 323} 324 325// ---- D. TREE (this page's siblings/children from parent edges) -------------- 326// Emits the parent's child list (or, if slug is root, the root's children), 327// highlighting the current page. Marker class="nx-tree". Pure read of wl. 328func sh_tree(buf: *u8, off: i64, wl: *NxWikiLinks, slug: *u8) -> i64 { 329 let r: i64 = sh_wl_row_of(wl, slug) 330 if r < 0 { return off } 331 let par: *u8 = sh_wl_field(wl, r, 1) 332 // the "branch parent" is this page's parent, or this page itself if it is root 333 var branch: *u8 = par 334 if (branch as i64) == 0 { branch = slug } // root: show its own children 335 var w: i64 = off 336 w = sh_cat(buf, w, "<nav class=\"nx-tree\" aria-label=\"Section\"><b>" as *u8) 337 w = sh_title_of(buf, w, branch) 338 w = sh_cat(buf, w, "</b><ul>\n" as *u8) 339 // root link of the branch first 340 w = sh_cat(buf, w, "<li><a href=\"/wiki/" as *u8); w = sh_cat(buf, w, branch) 341 w = sh_cat(buf, w, ".html\">" as *u8); w = sh_title_of(buf, w, branch); w = sh_cat(buf, w, "</a><ul>\n" as *u8) 342 // every page whose parent == branch 343 var c: i64 = 0 344 while c < wl.nrows { 345 let cp: *u8 = sh_wl_field(wl, c, 1) 346 if sh_streq(cp, branch) == 1 { 347 let cs: *u8 = sh_wl_field(wl, c, 0) 348 if sh_streq(cs, slug) == 1 { 349 w = sh_cat(buf, w, "<li class=\"nx-tree-cur\"><strong>" as *u8); w = sh_title_of(buf, w, cs); w = sh_cat(buf, w, "</strong></li>\n" as *u8) 350 } else { 351 w = sh_cat(buf, w, "<li><a href=\"/wiki/" as *u8); w = sh_cat(buf, w, cs) 352 w = sh_cat(buf, w, ".html\">" as *u8); w = sh_title_of(buf, w, cs); w = sh_cat(buf, w, "</a></li>\n" as *u8) 353 } 354 } 355 c = c + 1 356 } 357 w = sh_cat(buf, w, "</ul></li>\n</ul></nav>\n" as *u8) 358 return w 359} 360 361// ---- E. BACKLINKS ("what links here"): THIN wrapper over the existing engine - 362// nx_wiki_backlinks_panel computes the reverse-link set from page bodies (ground 363// truth, never hand-maintained) and emits an <aside class="nx-backlinks">. This 364// wrapper just splices its NUL-terminated output into the caller buffer at off. 365const SH_BL_CAP: i64 = 32768 366func sh_backlinks(buf: *u8, off: i64, store: *NxWikiDocStore, slug: *u8) -> i64 { 367 if (store as i64) == 0 { return off } 368 let scratch: *u8 = sys_mmap(SH_BL_CAP) 369 let used: *i64 = sys_mmap(8) as *i64 370 let rc: i64 = nx_wiki_backlinks_panel(store, slug, sh_slen(slug), scratch, SH_BL_CAP, used) 371 if rc != NX_WBL_OK { return off } 372 var w: i64 = off 373 var i: i64 = 0 374 while i < used[0] { buf[w] = scratch[i]; w = w + 1; i = i + 1 } 375 return w 376} 377 378// ---- live-corpus store loader (so a page emitter can feed sh_backlinks) ------ 379// Ingests the framed corpus snapshot (###PAGE <url> <blen>\n<body>) -- the SAME 380// transport nx_wiki_walkability/nx_ims_monitor read -- into a doc store. Returns 381// the store (valid) or 0 on failure. Read-only. 382const SH_CORPUS_PATH: *u8 = "knowledge/status/ims_live_corpus.txt" 383const SH_CORPUS_CAP: i64 = 4194304 384const SH_CORPUS_MARKN: i64 = 8 // len("###PAGE ") 385func sh_corpus_store() -> *NxWikiDocStore { 386 let nbox: *i64 = sys_mmap(16) as *i64 387 nbox[0] = 0 388 let buf: *u8 = sys_read_file(SH_CORPUS_PATH, nbox) 389 if (buf as i64) == 0 { return 0 as *NxWikiDocStore } 390 let total: i64 = nbox[0] 391 if total < 1 { return 0 as *NxWikiDocStore } 392 if total > SH_CORPUS_CAP { return 0 as *NxWikiDocStore } 393 let store: *NxWikiDocStore = sys_mmap(512) as *NxWikiDocStore 394 nx_wiki_doc_store_init(store, 64, 16384, 16384, SH_CORPUS_CAP) 395 let mk: *u8 = "###PAGE \x00" as *u8 396 var i: i64 = 0 397 while i < total { 398 var ismark: i64 = 0 399 if i + SH_CORPUS_MARKN <= total { 400 var mi: i64 = 0 401 var ok: i64 = 1 402 while mi < SH_CORPUS_MARKN { if buf[i + mi] != mk[mi] { ok = 0 } mi = mi + 1 } 403 ismark = ok 404 } 405 if ismark == 1 { 406 let url_off: i64 = i + SH_CORPUS_MARKN 407 var u: i64 = url_off 408 var du: i64 = 0 409 while du == 0 { if u >= total { du = 1 } else { if buf[u] == 0x20 as u8 { du = 1 } else { u = u + 1 } } } 410 let url_n: i64 = u - url_off 411 var bi: i64 = u + 1 412 var blen: i64 = 0 413 var db: i64 = 0 414 while db == 0 { 415 if bi >= total { db = 1 } else { 416 let c: i64 = buf[bi] as i64 417 if c < 0x30 { db = 1 } else { if c > 0x39 { db = 1 } else { blen = blen * 10 + (c - 0x30); bi = bi + 1 } } 418 } 419 } 420 var he: i64 = bi 421 var dh: i64 = 0 422 while dh == 0 { if he >= total { dh = 1 } else { if buf[he] == 0x0A as u8 { dh = 1 } else { he = he + 1 } } } 423 let body_off: i64 = he + 1 424 var body_n: i64 = blen 425 if body_off + body_n > total { body_n = total - body_off } 426 let url_p: *u8 = (buf as i64 + url_off) as *u8 427 let body_p: *u8 = (buf as i64 + body_off) as *u8 428 nx_wiki_doc_store_add(store, url_p, url_n, url_p, url_n, body_p, body_n) 429 i = body_off + body_n 430 } else { 431 i = i + 1 432 } 433 } 434 return store 435} 436 437// ---- COMBINED walk furniture: one call emits the whole walkable nav block ---- 438// breadcrumb + tree + prev/next + related + backlinks, in reading order. store 439// may be 0 (backlinks skipped). Wrapped in <div class="nx-walk"> for styling. 440func sh_walk_furniture(buf: *u8, off: i64, wl: *NxWikiLinks, store: *NxWikiDocStore, slug: *u8) -> i64 { 441 var w: i64 = off 442 w = sh_cat(buf, w, "<div class=\"nx-walk\">\n" as *u8) 443 w = sh_breadcrumb(buf, w, wl, slug) 444 w = sh_tree(buf, w, wl, slug) 445 w = sh_prevnext(buf, w, wl, slug) 446 w = sh_related(buf, w, wl, slug) 447 w = sh_backlinks(buf, w, store, slug) 448 w = sh_cat(buf, w, "</div>\n" as *u8) 449 return w 450} 451 452// ---- FOOTER (refactored): see-also + categories READ from wiki_links.tsv ---- 453// see-also = the curated related[] for this slug; categories = the curated tags[]. 454// Falls back to the slug itself if the page is absent from the registry. 455func sh_footer_wl(buf: *u8, off: i64, wl: *NxWikiLinks, slug: *u8, epoch: i64) -> i64 { 456 var w: i64 = off 457 let r: i64 = sh_wl_row_of(wl, slug) 458 // SEE ALSO from related[] 459 w = sh_cat(buf, w, "<section id=\"seealso\"><h2><a href=\"#seealso\">See also</a></h2><ul>" as *u8) 460 var any_rel: i64 = 0 461 if r >= 0 { 462 let rel: *u8 = sh_wl_field(wl, r, 4) 463 if (rel as i64) != 0 { 464 var i: i64 = 0 465 var seg_start: i64 = 0 466 var done: i64 = 0 467 while done == 0 { 468 let ch: u8 = rel[i] 469 var boundary: i64 = 0 470 if ch == 0 as u8 { boundary = 1; done = 1 } 471 if ch == 44 as u8 { boundary = 1 } 472 if boundary == 1 { 473 let seglen: i64 = i - seg_start 474 if seglen > 0 { 475 let t: *u8 = sys_mmap(seglen + 1) 476 var j: i64 = 0 477 while j < seglen { t[j] = rel[seg_start + j]; j = j + 1 } 478 t[seglen] = 0 as u8 479 w = sh_cat(buf, w, "<li><a href=\"/wiki/" as *u8); w = sh_cat(buf, w, t) 480 w = sh_cat(buf, w, ".html\">" as *u8); w = sh_title_of(buf, w, t); w = sh_cat(buf, w, "</a></li>" as *u8) 481 any_rel = 1 482 } 483 seg_start = i + 1 484 } 485 i = i + 1 486 if i > SH_WL_MAXBYTES { done = 1 } 487 } 488 } 489 } 490 if any_rel == 0 { 491 w = sh_cat(buf, w, "<li><a href=\"/wiki/start.html\">AI Start Here (capstone)</a></li>" as *u8) 492 } 493 w = sh_cat(buf, w, "</ul></section>\n" as *u8) 494 // CATEGORIES from tags[] 495 w = sh_cat(buf, w, "<div class=\"catlinks\"><strong>Categories:</strong> " as *u8) 496 var any_tag: i64 = 0 497 if r >= 0 { 498 let tg: *u8 = sh_wl_field(wl, r, 5) 499 if (tg as i64) != 0 { 500 var i2: i64 = 0 501 var seg2: i64 = 0 502 var d2: i64 = 0 503 while d2 == 0 { 504 let ch2: u8 = tg[i2] 505 var b2: i64 = 0 506 if ch2 == 0 as u8 { b2 = 1; d2 = 1 } 507 if ch2 == 44 as u8 { b2 = 1 } 508 if b2 == 1 { 509 let sl2: i64 = i2 - seg2 510 if sl2 > 0 { 511 let t2: *u8 = sys_mmap(sl2 + 1) 512 var j2: i64 = 0 513 while j2 < sl2 { t2[j2] = tg[seg2 + j2]; j2 = j2 + 1 } 514 t2[sl2] = 0 as u8 515 w = sh_cat(buf, w, "<a href=\"/wiki/start.html\">" as *u8); w = sh_cat(buf, w, t2); w = sh_cat(buf, w, "</a> " as *u8) 516 any_tag = 1 517 } 518 seg2 = i2 + 1 519 } 520 i2 = i2 + 1 521 if i2 > SH_WL_MAXBYTES { d2 = 1 } 522 } 523 } 524 } 525 if any_tag == 0 { w = sh_cat(buf, w, "<a href=\"/wiki/start.html\">Nishi ecosystem</a>" as *u8) } 526 w = sh_cat(buf, w, "</div>\n" as *u8) 527 // PROVENANCE (unchanged) 528 w = sh_cat(buf, w, "<p class=\"foot\">Built by the sovereign Nishi page builder (<code>nx_wiki_shell</code>) &mdash; no nginx, no OpenSSL, no libc. Permalink <a rel=\"bookmark\" href=\"/wiki/" as *u8) 529 w = sh_cat(buf, w, slug); w = sh_cat(buf, w, ".html\">/wiki/" as *u8); w = sh_cat(buf, w, slug) 530 w = sh_cat(buf, w, ".html</a> &middot; regenerate to refresh (epoch=" as *u8); w = sh_catn(buf, w, epoch) 531 w = sh_cat(buf, w, ").</p>\n</body></html>\n" as *u8) 532 return w 533} 534 535// FOOTER: see-also + categories + provenance. (permalink + edit live in head/nav.) 536func sh_footer(buf: *u8, off: i64, slug: *u8, epoch: i64) -> i64 { 537 var w: i64 = off 538 w = sh_cat(buf, w, "<section id=\"seealso\"><h2><a href=\"#seealso\">See also</a></h2><ul><li><a href=\"/wiki/start.html\">AI Start Here (capstone)</a></li><li><a href=\"/wiki/charter.html\">Graceful Evolution Charter</a></li><li><a href=\"/wiki/start.html#tasks\">Task streams (resume any work)</a></li></ul></section>\n" as *u8) 539 w = sh_cat(buf, w, "<div class=\"catlinks\"><strong>Categories:</strong> <a href=\"/wiki/start.html\">Nishi ecosystem</a> <a href=\"/wiki/start.html#docs\">Documentation</a> <a href=\"/wiki/charter.html\">Doctrine</a></div>\n" as *u8) 540 w = sh_cat(buf, w, "<p class=\"foot\">Built by the sovereign Nishi page builder (<code>nx_wiki_shell</code>) &mdash; no nginx, no OpenSSL, no libc. Permalink <a rel=\"bookmark\" href=\"/wiki/" as *u8) 541 w = sh_cat(buf, w, slug); w = sh_cat(buf, w, ".html\">/wiki/" as *u8); w = sh_cat(buf, w, slug) 542 w = sh_cat(buf, w, ".html</a> &middot; regenerate to refresh (epoch=" as *u8); w = sh_catn(buf, w, epoch) 543 w = sh_cat(buf, w, ").</p>\n</body></html>\n" as *u8) 544 return w 545}