"""Border merging post-pass — fix junction characters where borders meet. Scans the CharGrid for adjacent border cells and replaces with the correct junction character (T-junctions, crosses, corners) from the Unicode box-drawing set. """ from __future__ import annotations from uframe.grid import CharGrid from uframe.ir import BorderWeight # --------------------------------------------------------------------------- # Connection detection # --------------------------------------------------------------------------- # For each border cell, check which directions have adjacent borders. # Direction flags: UP = 1 DOWN = 2 LEFT = 4 RIGHT = 8 # Junction lookup: connections bitmask → character # Only light weight for now (most common case) _LIGHT_JUNCTIONS: dict[int, str] = { UP | DOWN: "│", LEFT | RIGHT: "─", DOWN | RIGHT: "┌", DOWN | LEFT: "┐", UP | RIGHT: "└", UP | LEFT: "┘", UP | DOWN | RIGHT: "├", UP | DOWN | LEFT: "┤", LEFT | RIGHT | DOWN: "┬", LEFT | RIGHT | UP: "┴", UP | DOWN | LEFT | RIGHT: "┼", RIGHT: "─", LEFT: "─", UP: "│", DOWN: "│", } _HEAVY_JUNCTIONS: dict[int, str] = { UP | DOWN: "┃", LEFT | RIGHT: "━", DOWN | RIGHT: "┏", DOWN | LEFT: "┓", UP | RIGHT: "┗", UP | LEFT: "┛", UP | DOWN | RIGHT: "┣", UP | DOWN | LEFT: "┫", LEFT | RIGHT | DOWN: "┳", LEFT | RIGHT | UP: "┻", UP | DOWN | LEFT | RIGHT: "╋", RIGHT: "━", LEFT: "━", UP: "┃", DOWN: "┃", } _DOUBLE_JUNCTIONS: dict[int, str] = { UP | DOWN: "║", LEFT | RIGHT: "═", DOWN | RIGHT: "╔", DOWN | LEFT: "╗", UP | RIGHT: "╚", UP | LEFT: "╝", UP | DOWN | RIGHT: "╠", UP | DOWN | LEFT: "╣", LEFT | RIGHT | DOWN: "╦", LEFT | RIGHT | UP: "╩", UP | DOWN | LEFT | RIGHT: "╬", RIGHT: "═", LEFT: "═", UP: "║", DOWN: "║", } _JUNCTION_TABLES = { BorderWeight.LIGHT: _LIGHT_JUNCTIONS, BorderWeight.HEAVY: _HEAVY_JUNCTIONS, BorderWeight.DOUBLE: _DOUBLE_JUNCTIONS, BorderWeight.ROUNDED: _LIGHT_JUNCTIONS, # rounded uses light junctions } # Weight priority for mixed-weight junctions _WEIGHT_PRIORITY = { BorderWeight.DOUBLE: 3, BorderWeight.HEAVY: 2, BorderWeight.LIGHT: 1, BorderWeight.ROUNDED: 0, } def merge_borders(grid: CharGrid) -> None: """Scan the grid for adjacent border cells and fix junction characters. This pass resolves cases where two boxes share an edge or corner, replacing the overlapping border characters with proper junctions. """ for row in range(grid.height): for col in range(grid.width): cell = grid.cells[row][col] if not cell.is_border: continue # Detect connections in 4 directions connections = 0 max_weight = cell.border_weight or BorderWeight.LIGHT # Check each neighbor if row > 0 and grid.cells[row - 1][col].is_border: connections |= UP nw = grid.cells[row - 1][col].border_weight or BorderWeight.LIGHT if _WEIGHT_PRIORITY.get(nw, 0) > _WEIGHT_PRIORITY.get(max_weight, 0): max_weight = nw if row < grid.height - 1 and grid.cells[row + 1][col].is_border: connections |= DOWN nw = grid.cells[row + 1][col].border_weight or BorderWeight.LIGHT if _WEIGHT_PRIORITY.get(nw, 0) > _WEIGHT_PRIORITY.get(max_weight, 0): max_weight = nw if col > 0 and grid.cells[row][col - 1].is_border: connections |= LEFT nw = grid.cells[row][col - 1].border_weight or BorderWeight.LIGHT if _WEIGHT_PRIORITY.get(nw, 0) > _WEIGHT_PRIORITY.get(max_weight, 0): max_weight = nw if col < grid.width - 1 and grid.cells[row][col + 1].is_border: connections |= RIGHT nw = grid.cells[row][col + 1].border_weight or BorderWeight.LIGHT if _WEIGHT_PRIORITY.get(nw, 0) > _WEIGHT_PRIORITY.get(max_weight, 0): max_weight = nw # Skip rounded corners — they should preserve ╭╮╰╯ if cell.border_weight == BorderWeight.ROUNDED and connections in ( DOWN | RIGHT, DOWN | LEFT, UP | RIGHT, UP | LEFT ): continue # Look up the junction character if connections: table = _JUNCTION_TABLES.get(max_weight, _LIGHT_JUNCTIONS) junction = table.get(connections) if junction: cell.char = junction