From f3fb27f6ac00d0815489cf780f318c8f76d22ced Mon Sep 17 00:00:00 2001 From: Thomas Walker Lynch Date: Tue, 4 Aug 2026 07:45:27 +0000 Subject: [PATCH] updates setup script to open subshell --- .../Manuscript.copy/Element/endnote.js | 442 +++++++++++++----- .../authored/Manuscript.copy/Element/grid.js | 217 +++++---- setup | 131 +++--- 3 files changed, 540 insertions(+), 250 deletions(-) mode change 100644 => 100755 setup diff --git a/developer/authored/Manuscript.copy/Element/endnote.js b/developer/authored/Manuscript.copy/Element/endnote.js index 3151a34..53e84c7 100644 --- a/developer/authored/Manuscript.copy/Element/endnote.js +++ b/developer/authored/Manuscript.copy/Element/endnote.js @@ -1,136 +1,362 @@ /* - Element/endnote.js - Processes tags inline and dumps them when is encountered. + Element/grid.js + Compiles semantic tabular structures into a Cartesian GridState. */ -(function(){ +(function() { + if (!window.RT) return; - if(!window.RT) return; - - const apply_style = function(link, config) { - link.style.cursor = 'pointer'; - link.style.color = config.brand_link || '#0056b3'; - link.style.textDecoration = 'none'; - }; - - const apply_list_style = function(list_container, config) { - list_container.style.marginTop = '1rem'; - list_container.style.borderTop = '1px solid ' + (config.surface_3 || '#ccc'); - list_container.style.paddingTop = '1rem'; - list_container.style.listStyle = 'none'; - list_container.style.paddingLeft = '0'; - list_container.style.margin = '0'; - }; - - function process_endnotes(){ - const config = window.RT.layout_config || {}; - const article = document.querySelector('RT·article, rt·article, RT·memo, rt·memo'); - - if(!article) return; - - const initial_make = document.createElement('RT·counter·make'); - initial_make.setAttribute('counter', 'EndNoteCounter'); - initial_make.setAttribute('style', 'CountingNumber'); - initial_make.setAttribute('on-first-step', '0'); - article.insertBefore(initial_make, article.firstChild); - - const nodes = document.querySelectorAll('RT·endnote, rt·endnote, RT-endnote, rt-endnote, RT·endnotes, rt·endnotes, RT-endnotes, rt-endnotes'); - - let endnote_buffer = []; - let anchor_id_counter = 1; - - for(let i = 0; i < nodes.length; i++){ - const node = nodes[i]; - const tag = node.tagName.toLowerCase(); - - if(tag === 'rt·endnote' || tag === 'rt-endnote'){ - const snap_name = 'endnote_cite_' + anchor_id_counter; - const ref_text = node.innerHTML; - - const step = document.createElement('RT·counter·step'); - step.setAttribute('counter', 'EndNoteCounter'); + class GridState { + constructor() { + this.cells = []; + this.max_x = 0; + this.max_y = 0; + } - const snapshot = document.createElement('RT·counter·snapshot'); - snapshot.setAttribute('counter', 'EndNoteCounter'); - snapshot.setAttribute('snapshot', snap_name); + insert(cell_data) { + this.cells.push(cell_data); + if (cell_data.x_extent > this.max_x) this.max_x = cell_data.x_extent; + if (cell_data.y_extent > this.max_y) this.max_y = cell_data.y_extent; + } + } - const link = document.createElement('a'); - link.href = '#note_' + anchor_id_counter; - link.id = 'cite_' + anchor_id_counter; - link.innerHTML = '[]'; - - apply_style(link, config); + function pad_headers(grid_state) { + const max_x = grid_state.max_x; + const max_y = grid_state.max_y; + + // Pad horizontal headers (x-label) + const x_labels = grid_state.cells.filter(c => c.type === 'x-label'); + if (x_labels.length > 0) { + const header_y = x_labels[0].y; + const existing_xs = new Set(x_labels.map(c => c.x)); + for (let i = 0; i <= max_x; i++) { + if (!existing_xs.has(i)) { + const empty_el = document.createElement('RT·e'); + empty_el.textContent = ''; + grid_state.insert({ + element: empty_el, type: 'x-label', + x: i, y: header_y, x_extent: i, y_extent: header_y + }); + } + } + } - step.appendChild(snapshot); - step.appendChild(link); + // Pad vertical headers (y-label) + const y_labels = grid_state.cells.filter(c => c.type === 'y-label'); + if (y_labels.length > 0) { + const header_x = y_labels[0].x; + const existing_ys = new Set(y_labels.map(c => c.y)); + for (let i = 0; i <= max_y; i++) { + if (!existing_ys.has(i)) { + const empty_el = document.createElement('RT·e'); + empty_el.textContent = ''; + grid_state.insert({ + element: empty_el, type: 'y-label', + x: header_x, y: i, x_extent: header_x, y_extent: i + }); + } + } + } - node.parentNode.replaceChild(step, node); + // Pad tuple names (name) + const names = grid_state.cells.filter(c => c.type === 'name'); + if (names.length > 0) { + const name_x = names[0].x; + const existing_ys = new Set(names.map(c => c.y)); + for (let i = 0; i <= max_y; i++) { + if (!existing_ys.has(i)) { + const empty_el = document.createElement('RT·e'); + empty_el.textContent = ''; + grid_state.insert({ + element: empty_el, type: 'name', + x: name_x, y: i, x_extent: name_x, y_extent: i + }); + } + } + } + } - endnote_buffer.push({ id: anchor_id_counter, text: ref_text, snap: snap_name }); - anchor_id_counter++; + const apply_style = function(el, cell, is_transposed, options, config) { + el.style.padding = '0.25rem 0.5rem'; + el.style.margin = '0'; + el.style.lineHeight = '1.3'; - } else if(tag === 'rt·endnotes' || tag === 'rt-endnotes'){ - if(endnote_buffer.length === 0){ - node.parentNode.removeChild(node); - continue; - } + if (cell.type === 'x-label' || cell.type === 'y-label' || cell.type === 'name') { + el.style.fontWeight = '600'; + } - const frag = document.createDocumentFragment(); + // Direct cell boundary mapping handles continuous lines if cells are padded + if (cell.type === 'x-label') { + if (is_transposed) el.style.borderRight = '2px solid ' + (config.border_strong || '#000'); + else el.style.borderBottom = '2px solid ' + (config.border_strong || '#000'); + } + if (cell.type === 'y-label') { + if (is_transposed) el.style.borderBottom = '2px solid ' + (config.border_strong || '#000'); + else el.style.borderRight = '2px solid ' + (config.border_strong || '#000'); + } + if (cell.type === 'name') { + if (is_transposed) el.style.borderBottom = '1px solid ' + (config.border_faint || '#ccc'); + else el.style.borderRight = '1px solid ' + (config.border_faint || '#ccc'); + } - const pb = document.createElement('RT·page-break'); - frag.appendChild(pb); + if (cell.type === 'data') el.style.textAlign = 'center'; + if (cell.type === 'x-label') el.style.textAlign = 'center'; + + if (cell.type === (is_transposed ? 'x-label' : 'y-label') || cell.type === 'name') { + el.style.textAlign = 'right'; + el.style.paddingRight = '0.5rem'; + } - const header = document.createElement('h1'); - header.innerText = 'Endnotes'; - frag.appendChild(header); + if (options && options.no_wrap) { + el.style.whiteSpace = 'nowrap'; + el.style.padding = '0.15rem 0.5rem'; + } + }; - const list_container = document.createElement('ul'); - list_container.className = 'RT_endnote_list'; - apply_list_style(list_container, config); + function project_grid(container_node, grid_state, model, options = {}) { + const config = window.RT.layout_config || {}; + switch (model) { + case 'html-grid-direct': + return render_model_html_standard(container_node, grid_state, options, false, config); + case 'html-grid-transpose': + return render_model_html_standard(container_node, grid_state, options, true, config); + case 'html-grid-dictionary': + return render_model_html_dictionary(container_node, grid_state, options, config); + } + } - for(let j = 0; j < endnote_buffer.length; j++){ - const item = endnote_buffer[j]; + function render_model_html_standard(container_node, grid_state, options, is_transposed, config) { + const wrapper = document.createElement('div'); + wrapper.style.display = 'grid'; + wrapper.style.justifyContent = 'start'; + wrapper.className = `RT_grid_container ${options.css_class || ''}`; + + if (options.delimiters) { + wrapper.style.borderLeft = '2px solid ' + (config.content_main || '#000'); + wrapper.style.borderRight = '2px solid ' + (config.content_main || '#000'); + wrapper.style.borderRadius = '5px'; + wrapper.style.padding = '0.2rem'; + wrapper.style.margin = '1rem 0'; + } else { + wrapper.style.margin = '1.5rem 0'; + } - const li = document.createElement('li'); - li.id = 'note_' + item.id; - li.style.display = 'flex'; - li.style.marginBottom = '0.5rem'; + grid_state.cells.forEach(cell => { + let render_x = is_transposed ? cell.y : cell.x; + let render_y = is_transposed ? cell.x : cell.y; + let render_x_extent = is_transposed ? cell.y_extent : cell.x_extent; + let render_y_extent = is_transposed ? cell.x_extent : cell.y_extent; + + const el = cell.element; + el.style.gridColumn = `${render_x + 1} / ${render_x_extent + 2}`; + el.style.gridRow = `${render_y + 1} / ${render_y_extent + 2}`; + el.className = `RT_grid_${cell.type}`; + + apply_style(el, cell, is_transposed, options, config); + wrapper.appendChild(el); + }); + + container_node.replaceWith(wrapper); + execute_two_pass_measurement(wrapper, options); + } - const left_div = document.createElement('div'); - left_div.style.marginRight = '0.5rem'; - left_div.innerHTML = '[]'; + function render_model_html_dictionary(container_node, grid_state, options, config) { + const wrapper = document.createElement('div'); + wrapper.style.display = 'grid'; + wrapper.style.gridAutoColumns = 'max-content'; + wrapper.style.justifyContent = 'start'; + wrapper.className = `RT_grid_container ${options.css_class || ''}`; + wrapper.style.margin = '1.5rem 0'; + + grid_state.cells.forEach(cell => { + const el = cell.element; + el.style.gridColumn = `${cell.x + 1} / ${cell.x_extent + 2}`; + el.style.gridRow = `${cell.y + 1} / ${cell.y_extent + 2}`; + el.className = `RT_grid_${cell.type}`; + + apply_style(el, cell, false, options, config); + if (cell.type === 'data') el.style.textAlign = 'left'; + + wrapper.appendChild(el); + }); + + container_node.replaceWith(wrapper); + execute_two_pass_measurement(wrapper, options); + } - const right_div = document.createElement('div'); - const return_link = document.createElement('a'); - return_link.href = '#cite_' + item.id; - return_link.style.textDecoration = 'none'; - return_link.innerHTML = '↩'; - return_link.style.marginLeft = '0.5em'; + function execute_two_pass_measurement(wrapper, options) { + requestAnimationFrame(() => { + if (options.wrap_check) { + const data_cells = wrapper.querySelectorAll('.RT_grid_data, .RT_grid_name'); + data_cells.forEach(cell => { + const computed = window.getComputedStyle(cell); + const line_height = parseFloat(computed.lineHeight) || (parseFloat(computed.fontSize) * 1.2); + const pTop = parseFloat(computed.paddingTop) || 0; + const pBot = parseFloat(computed.paddingBottom) || 0; + const content_height = cell.scrollHeight - pTop - pBot; + + if (content_height > line_height * 1.5) { + cell.style.paddingBottom = '1.25rem'; + } + }); + } + }); + } - right_div.innerHTML = item.text + ' '; - right_div.appendChild(return_link); + function parse_coordinate(attr_value, current_val) { + if (!attr_value) return { start: current_val, extent: current_val }; + const parts = attr_value.split('-'); + const start = parseInt(parts[0], 10); + const extent = parts.length > 1 ? parseInt(parts[1], 10) : start; + return { start, extent }; + } - li.appendChild(left_div); - li.appendChild(right_div); - list_container.appendChild(li); + RT.Element.add(function process_grids() { + document.querySelectorAll('RT·grid, rt·grid').forEach(node => { + const state = new GridState(); + const model = node.getAttribute('model') || 'html-grid-direct'; + const major_axis = node.getAttribute('major') || 'x'; + + let cursor_x = 0; + let cursor_y = 0; + + node.querySelectorAll('RT·e, rt·e').forEach(e => { + const attr_x = e.getAttribute('x'); + const attr_y = e.getAttribute('y'); + + if (major_axis === 'x') { + if (attr_y && !attr_x && attr_y !== String(cursor_y)) cursor_x = 0; + } else { + if (attr_x && !attr_y && attr_x !== String(cursor_x)) cursor_y = 0; } - frag.appendChild(list_container); - - const counter_reset = document.createElement('RT·counter·make'); - counter_reset.setAttribute('counter', 'EndNoteCounter'); - counter_reset.setAttribute('style', 'CountingNumber'); - counter_reset.setAttribute('on-first-step', '0'); - frag.appendChild(counter_reset); + const parsed_x = parse_coordinate(attr_x, cursor_x); + const parsed_y = parse_coordinate(attr_y, cursor_y); + + cursor_x = parsed_x.start; + cursor_y = parsed_y.start; + + const type = e.getAttribute('type') || 'data'; + state.insert({ + element: e.cloneNode(true), type: type, + x: cursor_x, y: cursor_y, + x_extent: parsed_x.extent, y_extent: parsed_y.extent + }); + + if (major_axis === 'x') cursor_x = parsed_x.extent + 1; + else cursor_y = parsed_y.extent + 1; + }); + + pad_headers(state); + project_grid(node, state, model, { wrap_check: true }); + }); + + document.querySelectorAll('RT·dictionary, rt·dictionary').forEach(node => { + const state = new GridState(); + const key_label = node.getAttribute('key'); + const def_label = node.getAttribute('definition'); + + let y = 0; + + if (key_label || def_label) { + const h1 = document.createElement('RT·e'); h1.textContent = key_label || ''; + const h2 = document.createElement('RT·e'); h2.textContent = def_label || ''; + state.insert({ element: h1, type: 'x-label', x: 0, y: y, x_extent: 0, y_extent: y }); + state.insert({ element: h2, type: 'x-label', x: 1, y: y, x_extent: 1, y_extent: y }); + y++; + } - // Unpack fragment directly into the article context to enable native UL splitting - node.parentNode.replaceChild(frag, node); + node.querySelectorAll('RT·entry, rt·entry').forEach(entry => { + const k = document.createElement('RT·e'); + k.textContent = entry.getAttribute('key') || ''; + + const v = document.createElement('RT·e'); + v.innerHTML = entry.innerHTML; + + state.insert({ element: k, type: 'name', x: 0, y: y, x_extent: 0, y_extent: y }); + state.insert({ element: v, type: 'data', x: 1, y: y, x_extent: 1, y_extent: y }); + y++; + }); + + pad_headers(state); + project_grid(node, state, 'html-grid-dictionary', { wrap_check: true }); + }); + + document.querySelectorAll('RT·relation, rt·relation').forEach(node => { + const state = new GridState(); + const layout_intent = node.getAttribute('layout-intention') || 'row-tuple'; + const model = layout_intent === 'column-tuple' ? 'html-grid-transpose' : 'html-grid-direct'; + + let offset_x = 0; + let offset_y = 0; + + const col_head = node.querySelector('RT·tuple-meta, rt·tuple-meta'); + if (col_head) { + offset_y = 1; + let cx = node.querySelector('RT·name, rt·name') ? 1 : 0; + col_head.querySelectorAll('RT·e, rt·e').forEach(e => { + state.insert({ element: e.cloneNode(true), type: 'x-label', x: cx, y: 0, x_extent: cx, y_extent: 0 }); + cx++; + }); + } - endnote_buffer = []; + let y = offset_y; + node.querySelectorAll('RT·tuple, rt·tuple').forEach(tuple => { + let x = 0; + const name = tuple.querySelector('RT·name, rt·name'); + if (name) { + offset_x = 1; + state.insert({ element: name.cloneNode(true), type: 'name', x: 0, y: y, x_extent: 0, y_extent: y }); + } + x = offset_x; + tuple.querySelectorAll('RT·e, rt·e').forEach(e => { + state.insert({ element: e.cloneNode(true), type: 'data', x: x, y: y, x_extent: x, y_extent: y }); + x++; + }); + y++; + }); + + pad_headers(state); + project_grid(node, state, model, { wrap_check: true }); + }); + + document.querySelectorAll('RT·matrix, rt·matrix').forEach(node => { + const state = new GridState(); + const layout_intent = node.getAttribute('layout-intention') || 'row-vector'; + const model = layout_intent === 'column-vector' ? 'html-grid-transpose' : 'html-grid-direct'; + + let offset_j = 0; + let offset_i = 0; + + const vector_meta = node.querySelector('RT·vector-meta, rt·vector-meta'); + if (vector_meta) { + offset_i = 1; + let cj = node.querySelector('RT·name, rt·name') ? 1 : 0; + vector_meta.querySelectorAll('RT·label, rt·label').forEach(e => { + state.insert({ element: e.cloneNode(true), type: 'x-label', x: cj, y: 0, x_extent: cj, y_extent: 0 }); + cj++; + }); } - } - } - window.RT.Element.add(process_endnotes); + let i = offset_i; + node.querySelectorAll('RT·vector, rt·vector').forEach(vec => { + let j = 0; + const name = vec.querySelector('RT·name, rt·name'); + if (name) { + offset_j = 1; + state.insert({ element: name.cloneNode(true), type: 'name', x: 0, y: i, x_extent: 0, y_extent: i }); + } + j = offset_j; + vec.querySelectorAll('RT·e, rt·e').forEach(e => { + state.insert({ element: e.cloneNode(true), type: 'data', x: j, y: i, x_extent: j, y_extent: i }); + j++; + }); + i++; + }); + + pad_headers(state); + project_grid(node, state, model, { wrap_check: false, no_wrap: true, delimiters: true }); + }); + }); })(); diff --git a/developer/authored/Manuscript.copy/Element/grid.js b/developer/authored/Manuscript.copy/Element/grid.js index 6859bac..7b16278 100644 --- a/developer/authored/Manuscript.copy/Element/grid.js +++ b/developer/authored/Manuscript.copy/Element/grid.js @@ -1,11 +1,14 @@ /* Element/grid.js Compiles semantic tabular structures into a Cartesian GridState. + [INSTRUMENTED DIAGNOSTIC BUILD] */ (function() { if (!window.RT) return; + console.warn(">>> [RT GRID DIAGNOSTIC] grid.js parsed by browser at: " + new Date().toISOString() + " <<<"); + class GridState { constructor() { this.cells = []; @@ -20,55 +23,49 @@ } } - function pad_headers(grid_state) { - const headers = grid_state.cells.filter(c => c.type === 'x-label'); - if (headers.length === 0) return; - - const max_x = Math.max(...grid_state.cells.map(c => c.x_extent)); - const min_header_x = Math.min(...headers.map(c => c.x)); - const existing_xs = new Set(headers.map(c => c.x)); - - for (let i = min_header_x; i <= max_x; i++) { - if (!existing_xs.has(i)) { - const empty_el = document.createElement('RT·e'); - empty_el.innerHTML = ' '; - grid_state.insert({ - element: empty_el, - type: 'x-label', - x: i, - y: 0, - x_extent: i, - y_extent: 0 - }); - } - } - } - const apply_style = function(el, cell, is_transposed, options, config) { el.style.padding = '0.25rem 0.5rem'; el.style.margin = '0'; el.style.lineHeight = '1.3'; - if (cell.type === 'x-label' || cell.type === 'y-label' || cell.type === 'name') { + const type = cell.type; + const border_strong = '2px solid ' + (config.border_strong || '#000'); + const border_faint = '1px solid ' + (config.border_faint || '#ccc'); + + if (type === 'x-label' || type === 'y-label' || type === 'name' || type === 'corner') { el.style.fontWeight = '600'; } - if (cell.type === 'x-label') { + if (type === 'x-label') { + if (is_transposed) el.style.borderRight = border_strong; + else el.style.borderBottom = border_strong; + } + + if (type === 'y-label') { + if (is_transposed) el.style.borderBottom = border_strong; + else el.style.borderRight = border_strong; + } + + if (type === 'name') { + if (is_transposed) el.style.borderBottom = border_faint; + else el.style.borderRight = border_faint; + } + + if (type === 'corner') { if (is_transposed) { - el.style.borderRight = '2px solid ' + (config.border_strong || '#000'); + el.style.borderRight = border_strong; + el.style.borderBottom = border_faint; } else { - el.style.borderBottom = '2px solid ' + (config.border_strong || '#000'); + el.style.borderBottom = border_strong; + el.style.borderRight = border_faint; } } - - if (cell.type === 'name') { - el.style.borderRight = '1px solid ' + (config.border_faint || '#ccc'); - } - if (cell.type === 'data') el.style.textAlign = 'center'; - if (cell.type === 'x-label') el.style.textAlign = 'center'; + if (type === 'data' || type === 'x-label') { + el.style.textAlign = 'center'; + } - if (cell.type === (is_transposed ? 'x-label' : 'y-label') || cell.type === 'name') { + if ((is_transposed ? type === 'x-label' : type === 'y-label') || type === 'name' || type === 'corner') { el.style.textAlign = 'right'; el.style.paddingRight = '0.5rem'; } @@ -178,7 +175,10 @@ } RT.Element.add(function process_grids() { - document.querySelectorAll('RT·grid, rt·grid').forEach(node => { + console.error(">>> [RT GRID DIAGNOSTIC] process_grids() triggered by stage_manager <<<"); + + // 1. Native Grid + document.querySelectorAll('RT·grid, rt·grid, RT-grid, rt-grid').forEach(node => { const state = new GridState(); const model = node.getAttribute('model') || 'html-grid-direct'; const major_axis = node.getAttribute('major') || 'x'; @@ -186,7 +186,7 @@ let cursor_x = 0; let cursor_y = 0; - node.querySelectorAll('RT·e, rt·e').forEach(e => { + node.querySelectorAll('RT·e, rt·e, RT-e, rt-e').forEach(e => { const attr_x = e.getAttribute('x'); const attr_y = e.getAttribute('y'); @@ -213,11 +213,11 @@ else cursor_y = parsed_y.extent + 1; }); - pad_headers(state); project_grid(node, state, model, { wrap_check: true }); }); - document.querySelectorAll('RT·dictionary, rt·dictionary').forEach(node => { + // 2. Dictionary + document.querySelectorAll('RT·dictionary, rt·dictionary, RT-dictionary, rt-dictionary').forEach(node => { const state = new GridState(); const key_label = node.getAttribute('key'); const def_label = node.getAttribute('definition'); @@ -225,16 +225,16 @@ let y = 0; if (key_label || def_label) { - const h1 = document.createElement('RT·e'); h1.textContent = key_label || ''; - const h2 = document.createElement('RT·e'); h2.textContent = def_label || ''; + const h1 = document.createElement('RT·e'); h1.textContent = key_label || 'X'; + const h2 = document.createElement('RT·e'); h2.textContent = def_label || 'X'; state.insert({ element: h1, type: 'x-label', x: 0, y: y, x_extent: 0, y_extent: y }); state.insert({ element: h2, type: 'x-label', x: 1, y: y, x_extent: 1, y_extent: y }); y++; } - node.querySelectorAll('RT·entry, rt·entry').forEach(entry => { + node.querySelectorAll('RT·entry, rt·entry, RT-entry, rt-entry').forEach(entry => { const k = document.createElement('RT·e'); - k.textContent = entry.getAttribute('key') || ''; + k.textContent = entry.getAttribute('key') || 'X'; const v = document.createElement('RT·e'); v.innerHTML = entry.innerHTML; @@ -244,83 +244,140 @@ y++; }); - pad_headers(state); project_grid(node, state, 'html-grid-dictionary', { wrap_check: true }); }); - document.querySelectorAll('RT·relation, rt·relation').forEach(node => { + // 3. Relation + document.querySelectorAll('RT·relation, rt·relation, RT-relation, rt-relation').forEach(node => { + console.warn(">>> [RT GRID DIAGNOSTIC] node found <<<"); + const state = new GridState(); const layout_intent = node.getAttribute('layout-intention') || 'row-tuple'; const model = layout_intent === 'column-tuple' ? 'html-grid-transpose' : 'html-grid-direct'; + const tuples = node.querySelectorAll('RT·tuple, rt·tuple, RT-tuple, rt-tuple'); + + let row_labels_debug = []; + let has_any_name = false; + + tuples.forEach(tuple => { + const names = tuple.querySelectorAll('RT·name, rt·name, RT-name, rt-name'); + if (names.length > 0) { + has_any_name = true; + let sublist = []; + names.forEach(n => sublist.push(n.textContent.trim())); + row_labels_debug.push(sublist); + } else { + row_labels_debug.push(['X']); + } + }); - let offset_x = 0; + console.error(`>>> [RT GRID DIAGNOSTIC] Relation row labels: ${JSON.stringify(row_labels_debug)} <<<`); + + let offset_x = has_any_name ? 1 : 0; let offset_y = 0; - const col_head = node.querySelector('RT·tuple-meta, rt·tuple-meta'); + const col_head = node.querySelector('RT·tuple-meta, rt·tuple-meta, RT-tuple-meta, rt-tuple-meta'); if (col_head) { offset_y = 1; - let cx = node.querySelector('RT·name, rt·name') ? 1 : 0; - col_head.querySelectorAll('RT·e, rt·e').forEach(e => { + let cx = offset_x; + col_head.querySelectorAll('RT·e, rt·e, RT-e, rt-e').forEach(e => { state.insert({ element: e.cloneNode(true), type: 'x-label', x: cx, y: 0, x_extent: cx, y_extent: 0 }); cx++; }); + + if (has_any_name) { + const corner_el = document.createElement('RT·e'); + corner_el.textContent = 'X'; + state.insert({ element: corner_el, type: 'corner', x: 0, y: 0, x_extent: 0, y_extent: 0 }); + } } let y = offset_y; - node.querySelectorAll('RT·tuple, rt·tuple').forEach(tuple => { - let x = 0; - const name = tuple.querySelector('RT·name, rt·name'); - if (name) { - offset_x = 1; - state.insert({ element: name.cloneNode(true), type: 'name', x: 0, y: y, x_extent: 0, y_extent: y }); + tuples.forEach(tuple => { + if (has_any_name) { + const names = tuple.querySelectorAll('RT·name, rt·name, RT-name, rt-name'); + const name_container = document.createElement('RT·e'); + if (names.length > 0) { + names.forEach(n => name_container.appendChild(n.cloneNode(true))); + } else { + name_container.textContent = 'X'; + } + state.insert({ element: name_container, type: 'name', x: 0, y: y, x_extent: 0, y_extent: y }); } - x = offset_x; - tuple.querySelectorAll('RT·e, rt·e').forEach(e => { + + let x = offset_x; + tuple.querySelectorAll('RT·e, rt·e, RT-e, rt-e').forEach(e => { state.insert({ element: e.cloneNode(true), type: 'data', x: x, y: y, x_extent: x, y_extent: y }); x++; }); y++; }); - pad_headers(state); project_grid(node, state, model, { wrap_check: true }); }); - document.querySelectorAll('RT·matrix, rt·matrix').forEach(node => { + // 4. Matrix + document.querySelectorAll('RT·matrix, rt·matrix, RT-matrix, rt-matrix').forEach(node => { const state = new GridState(); const layout_intent = node.getAttribute('layout-intention') || 'row-vector'; const model = layout_intent === 'column-vector' ? 'html-grid-transpose' : 'html-grid-direct'; + const vectors = node.querySelectorAll('RT·vector, rt·vector, RT-vector, rt-vector'); + + let row_labels_debug = []; + let has_any_name = false; + + vectors.forEach(vec => { + const names = vec.querySelectorAll('RT·name, rt·name, RT-name, rt-name'); + if (names.length > 0) { + has_any_name = true; + let sublist = []; + names.forEach(n => sublist.push(n.textContent.trim())); + row_labels_debug.push(sublist); + } else { + row_labels_debug.push(['X']); + } + }); - let offset_j = 0; - let offset_i = 0; + let offset_x = has_any_name ? 1 : 0; + let offset_y = 0; - const vector_meta = node.querySelector('RT·vector-meta, rt·vector-meta'); + const vector_meta = node.querySelector('RT·vector-meta, rt·vector-meta, RT-vector-meta, rt-vector-meta'); if (vector_meta) { - offset_i = 1; - let cj = node.querySelector('RT·name, rt·name') ? 1 : 0; - vector_meta.querySelectorAll('RT·label, rt·label').forEach(e => { - state.insert({ element: e.cloneNode(true), type: 'x-label', x: cj, y: 0, x_extent: cj, y_extent: 0 }); - cj++; + offset_y = 1; + let cx = offset_x; + vector_meta.querySelectorAll('RT·label, rt·label, RT-label, rt-label').forEach(e => { + state.insert({ element: e.cloneNode(true), type: 'x-label', x: cx, y: 0, x_extent: cx, y_extent: 0 }); + cx++; }); + + if (has_any_name) { + const corner_el = document.createElement('RT·e'); + corner_el.textContent = 'X'; + state.insert({ element: corner_el, type: 'corner', x: 0, y: 0, x_extent: 0, y_extent: 0 }); + } } - let i = offset_i; - node.querySelectorAll('RT·vector, rt·vector').forEach(vec => { - let j = 0; - const name = vec.querySelector('RT·name, rt·name'); - if (name) { - offset_j = 1; - state.insert({ element: name.cloneNode(true), type: 'name', x: 0, y: i, x_extent: 0, y_extent: i }); + let y = offset_y; + vectors.forEach(vec => { + if (has_any_name) { + const names = vec.querySelectorAll('RT·name, rt·name, RT-name, rt-name'); + const name_container = document.createElement('RT·e'); + if (names.length > 0) { + names.forEach(n => name_container.appendChild(n.cloneNode(true))); + } else { + name_container.textContent = 'X'; + } + state.insert({ element: name_container, type: 'name', x: 0, y: y, x_extent: 0, y_extent: y }); } - j = offset_j; - vec.querySelectorAll('RT·e, rt·e').forEach(e => { - state.insert({ element: e.cloneNode(true), type: 'data', x: j, y: i, x_extent: j, y_extent: i }); - j++; + + let x = offset_x; + vec.querySelectorAll('RT·e, rt·e, RT-e, rt-e').forEach(e => { + state.insert({ element: e.cloneNode(true), type: 'data', x: x, y: y, x_extent: x, y_extent: y }); + x++; }); - i++; + y++; }); - pad_headers(state); project_grid(node, state, model, { wrap_check: false, no_wrap: true, delimiters: true }); }); }); diff --git a/setup b/setup old mode 100644 new mode 100755 index a249e2e..f750f1d --- a/setup +++ b/setup @@ -1,63 +1,70 @@ -#!/usr/bin/env bash +#!/usr/bin/env python3 # setup - enter a project role environment -# (must be sourced) - -script_afp=$(realpath "${BASH_SOURCE[0]}") -if [ "${BASH_SOURCE[0]}" == "${0}" ]; then - echo "${script_afp}:: This script must be sourced, not executed." - exit 1 -fi - -project_roles="administrator consumer developer tester" - -print_usage(){ - echo "usage: . setup " - echo "known roles: ${project_roles}" -} - -if [ -z "${1:-}" ] || [ "${1}" == "-h" ] || [ "${1}" == "--help" ]; then - print_usage - return 0 -fi - -role_is_valid=false -for r in ${project_roles}; do - if [ "${1}" == "${r}" ]; then - role_is_valid=true - break - fi -done - -if [ "${role_is_valid}" == "false" ]; then - echo "setup: unrecognized role or option '${1}'" - print_usage - return 1 -fi - -# setup the project -# - source shared/tool/setup - if [[ -f "shared/authored/setup" ]]; then - source shared/authored/setup - fi - -# setup the role -# - export ROLE="${1}" - export ROLE_HOME="$REPO_HOME/$ROLE" - echo ROLE_HOME "$ROLE_HOME" - - tool="${ROLE_HOME}/tool" - if [[ ":${PATH}:" != *":${tool}:"* ]]; then - export PATH="${tool}:${PATH}" - fi - - export SETUP="${ROLE}/tool/setup" - - cd "${ROLE}" || return 1 - if [ -f "tool/setup" ]; then - source "tool/setup" - echo "in environment: ${SETUP}" - else - echo "not found: ${SETUP}" - fi + +import os +import sys +import argparse +import tempfile + +PROJECT_ROLES = ["administrator", "consumer", "developer", "tester"] + +def main(): + parser = argparse.ArgumentParser( + description="Enter a project role environment by spawning an isolated subshell." + ) + parser.add_argument("role", choices=PROJECT_ROLES, help="The project role to assume.") + args = parser.parse_args() + + env = os.environ.copy() + + # Python-domain logic: Variables and Paths + repo_home = env.get("REPO_HOME", os.getcwd()) + role = args.role + role_home = os.path.join(repo_home, role) + tool_dir = os.path.join(role_home, "tool") + setup_file = os.path.join(role, "tool", "setup") + + env["ROLE"] = role + env["ROLE_HOME"] = role_home + env["SETUP"] = setup_file + + print(f"ROLE_HOME {role_home}") + + # Python-domain logic: PATH injection + path_parts = env.get("PATH", "").split(os.pathsep) + if tool_dir not in path_parts: + env["PATH"] = f"{tool_dir}{os.pathsep}{env.get('PATH', '')}" + + # Python-domain logic: Directory validation + if not os.path.isdir(role): + print(f"setup: failed to locate directory for role '{role}'") + sys.exit(1) + + # Bash-domain logic: The rcfile only handles operations Python cannot inherit + # (sourcing bash functions) and performs the directory change internally to + # guarantee the shared scripts are sourced from the project root. + bash_logic = [ + 'if [[ -f ~/.bashrc ]]; then source ~/.bashrc; fi', + 'if [[ -f "shared/tool/setup" ]]; then source "shared/tool/setup"; fi', + 'if [[ -f "shared/authored/setup" ]]; then source "shared/authored/setup"; fi', + f'cd "{role}"', + 'if [[ -f "tool/setup" ]]; then', + ' source "tool/setup"', + f' echo "in environment: {setup_file}"', + 'else', + f' echo "not found: {setup_file}"', + 'fi', + 'if [[ -n "${INSIDE_EMACS}" ]] && command -v env_to_emacs >/dev/null 2>&1; then', + ' env_to_emacs', + 'fi', + 'rm -f "${BASH_SOURCE[0]}"' + ] + + fd, rcfile_path = tempfile.mkstemp(suffix="-rt-setup.sh") + with os.fdopen(fd, "w") as f: + f.write("\n".join(bash_logic) + "\n") + + os.execvpe("bash", ["bash", "--rcfile", rcfile_path], env) + +if __name__ == "__main__": + main() -- 2.20.1