relative distance lobster script - TreeSheets

Slug: 3shits-dist

4437 characters 507 words

#StrikethruDistancesToNotes.lobster

// StrikethruDistancesToNotes.lobster // Implements: // (01) iterate current selection rectangle // (02) recursively assess stylebits in selected cells' subtrees // (03) collect (x,y) for strikethru cells (bit 16) // (04) compute pairwise parent/child tree distance // (05) append distance lines into each cell's NOTE (not cell text) // (06) end import std let STRIKETHRU = 16 // Collected marked nodes: let node_paths = [] // each is an array of child indices from selection-parent root let node_texts = [] // ts.get_text() captured for each marked node let node_xs = [] // x coordinate within its parent grid let node_ys = [] // y coordinate within its parent grid // Reusable traversal stacks: var path_stack = [] var col_stack = [] // columns count of parent grid at each depth var depth = 0 def ensure_stack_capacity() -> void: if path_stack.length == depth: path_stack.push(0) col_stack.push(0) def copy_prefix(p, n): let out = [] for(n) i: out.push(p[i]) return out def record_if_strikethru() -> void: // depth==0 means "no path" (should not happen once we're inside a selected cell) if depth == 0: return if ts.get_style_bits() & STRIKETHRU: node_paths.push(copy_prefix(path_stack, depth)) node_texts.push(ts.get_text()) // Coordinate of this node within its parent grid: let idx = path_stack[depth - 1] let cols = col_stack[depth - 1] node_xs.push(idx % cols) node_ys.push(idx / cols) def walk_subtree() -> void: record_if_strikethru() if ts.num_children(): let g = ts.num_columns_rows() // g[0]=cols, g[1]=rows for(ts.num_children()) i: ensure_stack_capacity() path_stack[depth] = i col_stack[depth] = g[0] depth++ ts.goto_child(i) walk_subtree() ts.goto_parent() depth-- def lcp(a, b): let m = if a.length < b.length: a.length else: b.length var k = 0 for(m) i: if a[i] == b[i]: k++ else: break return k def dist(a, b): let k = lcp(a, b) return (a.length - k) + (b.length - k) def goto_selection_parent() -> void: ts.goto_selection() ts.goto_parent() def goto_node(p) -> void: goto_selection_parent() for(p.length) i: ts.goto_child(p[i]) def build_lines(i): let parts = [] for(node_paths.length) j: if i != j: let d = dist(node_paths[i], node_paths[j]) // Required format: (<number> , <text of related cell compared to> ) parts.push("({d} , {node_texts[j]})\n") return concat_string(parts, "") def write_lines_into_note(lines) -> void: let old = ts.get_note() // Assumption: "has related note of its own" ≈ old note non-empty. // If non-empty: append at end. If empty: set note to new lines (effectively at beginning). if old.length: ts.set_note(old + "\n" + lines) else: ts.set_note(lines) // -------------------- main -------------------- if not ts.has_selection(): ts.set_status_message("No selection rectangle; please select a region first.") else: ts.goto_selection() let size, start = ts.selection() // selection() -> (size:int2, start:int2) ts.goto_parent() let g = ts.num_columns_rows() // g[0]=cols, g[1]=rows // Enumerate selected cells in this grid (same pattern as Statistics.lobster). for(ts.num_children()) j: let x = j % g[0] let y = j / g[0] if x >= start[0] and x < start[0] + size[0] and y >= start[1] and y < start[1] + size[1]: // Start path at this selected cell index j. ensure_stack_capacity() path_stack[0] = j col_stack[0] = g[0] depth = 1 ts.goto_child(j) walk_subtree() ts.goto_parent() depth = 0 // Write per-node distance info into notes. for(node_paths.length) i: let lines = build_lines(i) if lines.length: goto_node(node_paths[i]) write_lines_into_note(lines) ts.set_status_message("Updated notes for {node_paths.length} strikethru cell(s).")
URL: https://ib.bsb.br/3shits-dist