nx_html_emit.nx source
↩ module page · 218 lines · 6967 B
1// nx_html_emit.nx -- minimal substrate-native HTML5 writer.
2//
3// Layer 5 of the sovereign-log roadmap: dashboard visibility. Renders
4// query-layer projections to a tail-able HTML page. Pure NishiLang,
5// fd-write based, no template engine.
6//
7// Per the user's "live fire testing + see how its testing, innovating,
8// improving" directive: this primitive is what makes the substrate's
9// audit data VISIBLE without leaving NishiLang. Caller composes a
10// page from these primitives like Lego bricks:
11//
12// nx_html_doc_open(fd, "Batch 42 audit")
13// nx_html_h1(fd, "Pool utilization")
14// nx_html_table_open(fd, "n_scenes | n_violations | outfit_band")
15// nx_html_tr3_int(fd, n_scenes, n_violations, outfit_band)
16// nx_html_table_close(fd)
17// nx_html_doc_close(fd)
18//
19// HTML5 minimal: <!doctype html> + <meta charset="utf-8">, no CSS
20// dependency (inline classes only). Output is human-readable and
21// browser-renderable end-to-end.
22//
23// genealogy_id: html5_w3c_2014 + tufte_dashboards
24// lineage_id: substrate_html_emit_v1
25
26// nx_safety_envelope:
27// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
28// sil_target: SIL1
29// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
30// verdict: NOT_YET_EVALUATED
31
32import "nx_syscalls.nx"
33import "nx_runtime.nx"
34import "nx_tier.nx"
35
36// ===== Raw byte writes ============================================
37//
38// Direct sys_write helpers. No buffering; caller can wrap in a
39// nx_io buffered writer if they want batching.
40
41func _html_write_z(fd: nx_int, s: *u8) -> nx_int {
42 return sys_write(fd, s, strlen(s))
43}
44
45func _html_write_byte(fd: nx_int, b: nx_int) -> nx_int {
46 let buf: *u8 = sys_mmap(8)
47 buf[0] = b
48 return sys_write(fd, buf, 1)
49}
50
51func _html_write_i64(fd: nx_int, n: nx_int) -> nx_int {
52 let buf: *u8 = sys_mmap(32)
53 let len: nx_int = itoa(n, buf)
54 return sys_write(fd, buf, len)
55}
56
57// ===== Escape text for HTML body context ==========================
58//
59// Replaces &, <, >, " with their entity references. Single quotes
60// not escaped (HTML5 attribute values quoted with double quotes by
61// our convention).
62
63func _html_write_escaped_z(fd: nx_int, s: *u8) -> nx_int {
64 let n: nx_int = strlen(s)
65 var i: nx_int = 0
66 let one: *u8 = sys_mmap(8)
67 while i < n {
68 let c: nx_int = s[i]
69 if c == 0x26 { _html_write_z(fd, "&" as *u8) }
70 if c == 0x3C { _html_write_z(fd, "<" as *u8) }
71 if c == 0x3E { _html_write_z(fd, ">" as *u8) }
72 if c == 0x22 { _html_write_z(fd, """ as *u8) }
73 if c != 0x26 {
74 if c != 0x3C {
75 if c != 0x3E {
76 if c != 0x22 {
77 one[0] = c
78 sys_write(fd, one, 1)
79 }
80 }
81 }
82 }
83 i = i + 1
84 }
85 return n
86}
87
88// ===== Document open/close ========================================
89
90func nx_html_doc_open(fd: nx_int, title: *u8) -> nx_int {
91 _html_write_z(fd, "<!doctype html>\n" as *u8)
92 _html_write_z(fd, "<html lang=\"en\"><head>" as *u8)
93 _html_write_z(fd, "<meta charset=\"utf-8\">" as *u8)
94 _html_write_z(fd, "<title>" as *u8)
95 _html_write_escaped_z(fd, title)
96 _html_write_z(fd, "</title></head><body>\n" as *u8)
97 return 0
98}
99
100func nx_html_doc_close(fd: nx_int) -> nx_int {
101 _html_write_z(fd, "</body></html>\n" as *u8)
102 return 0
103}
104
105// ===== Headings ===================================================
106
107func nx_html_h1(fd: nx_int, text: *u8) -> nx_int {
108 _html_write_z(fd, "<h1>" as *u8)
109 _html_write_escaped_z(fd, text)
110 _html_write_z(fd, "</h1>\n" as *u8)
111 return 0
112}
113
114func nx_html_h2(fd: nx_int, text: *u8) -> nx_int {
115 _html_write_z(fd, "<h2>" as *u8)
116 _html_write_escaped_z(fd, text)
117 _html_write_z(fd, "</h2>\n" as *u8)
118 return 0
119}
120
121// ===== Paragraph ==================================================
122
123func nx_html_p(fd: nx_int, text: *u8) -> nx_int {
124 _html_write_z(fd, "<p>" as *u8)
125 _html_write_escaped_z(fd, text)
126 _html_write_z(fd, "</p>\n" as *u8)
127 return 0
128}
129
130// ===== Table primitives ===========================================
131//
132// We emit minimal <table> with a single header row built from a
133// pipe-delimited header string. Cells take an int or string.
134// No CSS dependency; the dashboard renders fine in any browser.
135
136func nx_html_table_open(fd: nx_int) -> nx_int {
137 return _html_write_z(fd, "<table border=\"1\" cellpadding=\"4\">\n" as *u8)
138}
139
140func nx_html_table_close(fd: nx_int) -> nx_int {
141 return _html_write_z(fd, "</table>\n" as *u8)
142}
143
144// Header row: caller passes individual column labels.
145func nx_html_thead_open(fd: nx_int) -> nx_int {
146 return _html_write_z(fd, "<thead><tr>" as *u8)
147}
148
149func nx_html_thead_close(fd: nx_int) -> nx_int {
150 return _html_write_z(fd, "</tr></thead>\n" as *u8)
151}
152
153func nx_html_th(fd: nx_int, label: *u8) -> nx_int {
154 _html_write_z(fd, "<th>" as *u8)
155 _html_write_escaped_z(fd, label)
156 _html_write_z(fd, "</th>" as *u8)
157 return 0
158}
159
160// Body row: open / cells / close
161func nx_html_tr_open(fd: nx_int) -> nx_int {
162 return _html_write_z(fd, "<tr>" as *u8)
163}
164
165func nx_html_tr_close(fd: nx_int) -> nx_int {
166 return _html_write_z(fd, "</tr>\n" as *u8)
167}
168
169func nx_html_td_int(fd: nx_int, n: nx_int) -> nx_int {
170 _html_write_z(fd, "<td>" as *u8)
171 _html_write_i64(fd, n)
172 _html_write_z(fd, "</td>" as *u8)
173 return 0
174}
175
176func nx_html_td_text(fd: nx_int, s: *u8) -> nx_int {
177 _html_write_z(fd, "<td>" as *u8)
178 _html_write_escaped_z(fd, s)
179 _html_write_z(fd, "</td>" as *u8)
180 return 0
181}
182
183// ===== Bands as colored badges (no CSS framework) ================
184//
185// Maps a utilization or continuity band code to a coloured inline
186// <span>. Caller passes the band int + a label table. This is
187// where the dashboard becomes scannable: green = GOOD, yellow =
188// DRIFT, red = BROKEN.
189
190const NX_HTML_BADGE_GOOD: nx_int = 0
191const NX_HTML_BADGE_DRIFT: nx_int = 1
192const NX_HTML_BADGE_BROKEN: nx_int = 2
193const NX_HTML_BADGE_NEUTRAL: nx_int = 3
194const NX_HTML_BADGE_N_KINDS: nx_int = 4
195
196func nx_html_badge(fd: nx_int, kind: nx_int, label: *u8) -> nx_int {
197 var color: *u8 = "#888" as *u8
198 if kind == NX_HTML_BADGE_GOOD { color = "#3a3" as *u8 }
199 if kind == NX_HTML_BADGE_DRIFT { color = "#cc6" as *u8 }
200 if kind == NX_HTML_BADGE_BROKEN { color = "#d33" as *u8 }
201
202 _html_write_z(fd, "<span style=\"background:" as *u8)
203 _html_write_z(fd, color)
204 _html_write_z(fd, ";color:#fff;padding:2px 6px;border-radius:3px;\">" as *u8)
205 _html_write_escaped_z(fd, label)
206 _html_write_z(fd, "</span>" as *u8)
207 return 0
208}
209
210// ===== Pre-formatted code block (for raw JSON / span dumps) =======
211
212func nx_html_pre_open(fd: nx_int) -> nx_int {
213 return _html_write_z(fd, "<pre>" as *u8)
214}
215
216func nx_html_pre_close(fd: nx_int) -> nx_int {
217 return _html_write_z(fd, "</pre>\n" as *u8)
218}