LOIPDREBCMPSZ4SFPPQ5VFT7VRRB46DOKPZAWKZUDZWRMJI3ARBAC /-- Cached terminal size to avoid spawning `stty` every frame. -/initialize terminalSizeCache : IO.Ref (Option (Nat × Nat)) ← IO.mkRef noneprivate def parseEnvSize : IO (Option (Nat × Nat)) := dolet rows? ← IO.getEnv "LINES"let cols? ← IO.getEnv "COLUMNS"match (rows?.bind String.toNat?, cols?.bind String.toNat?) with| (some r, some c) =>if r > 0 && c > 0 thenreturn some (r, c)elsereturn none| _ => return none
let out ← IO.Process.run { cmd := "stty", args := #["-F", "/dev/tty", "size"] }let parts := out.trimAscii.toString.splitOn " "match parts with| [rows, cols] => pure (rows.toNat!, cols.toNat!)| _ => pure (24, 80)
if let some sz ← terminalSizeCache.get thenreturn szif let some sz ← parseEnvSize thenterminalSizeCache.set (some sz)return sztrylet out ← IO.Process.run { cmd := "stty", args := #["-F", "/dev/tty", "size"] }let parts := out.trimAscii.toString.splitOn " "let sz := match parts with| [rows, cols] =>match (rows.toNat?, cols.toNat?) with| (some r, some c) =>if r > 0 && c > 0 then (r, c) else (24, 80)| _ => (24, 80)| _ => (24, 80)terminalSizeCache.set (some sz)return szcatch _ =>return (24, 80)
namespace Bliku.Tui.Tabs/-- Generic tab state. -/structure State whereactive : Nat := 0total : Nat := 0deriving Inhabited, Reprdef State.clamp (s : State) : State :=let maxIdx := if s.total == 0 then 0 else s.total - 1{ s with active := min s.active maxIdx }def State.next (s : State) : State :=let maxIdx := if s.total == 0 then 0 else s.total - 1{ s with active := min (s.active + 1) maxIdx } |>.clampdef State.prev (s : State) : State :={ s with active := if s.active > 0 then s.active - 1 else 0 } |>.clampend Bliku.Tui.Tabs
namespace Bliku.Tui.Cursor/-- Scroll/selection state for list-like UIs. -/structure State whereselected : Nat := 0scroll : Nat := 0totalRows : Nat := 0viewportRows : Nat := 20margin : Nat := 3deriving Inhabited, Reprdef autoScrollRow(selectedRow scrollRow totalRows : Nat)(viewportRows : Nat := 20)(margin : Nat := 3) : Nat :=if totalRows == 0 || viewportRows == 0 then0elselet maxScroll := totalRows - 1let lowBound := scrollRow + marginlet highBound := scrollRow + (viewportRows - 1 - min margin (viewportRows - 1))if selectedRow < lowBound thenmin (selectedRow - margin) maxScrollelse if selectedRow > highBound thenlet wanted := selectedRow - (viewportRows - 1 - min margin (viewportRows - 1))min wanted maxScrollelsemin scrollRow maxScrolldef State.clamp (s : State) : State :=let maxIdx := if s.totalRows == 0 then 0 else s.totalRows - 1let selected := min s.selected maxIdxlet scroll := autoScrollRow selected s.scroll s.totalRows s.viewportRows s.margin{ s with selected := selected, scroll := scroll }def State.moveDown (s : State) : State :=let maxIdx := if s.totalRows == 0 then 0 else s.totalRows - 1{ s with selected := min (s.selected + 1) maxIdx } |>.clampdef State.moveUp (s : State) : State :={ s with selected := if s.selected > 0 then s.selected - 1 else 0 } |>.clampdef State.moveTop (s : State) : State :={ s with selected := 0 } |>.clampdef State.moveBottom (s : State) : State :=let maxIdx := if s.totalRows == 0 then 0 else s.totalRows - 1{ s with selected := maxIdx } |>.clampend Bliku.Tui.Cursor
namespace Bliku.Tui.Collapsible/-- Collapsible section state indexed by Nat key. -/structure State wherecollapsed : Array Nat := #[]deriving Inhabited, Reprdef State.isCollapsed (s : State) (k : Nat) : Bool :=s.collapsed.contains kdef State.toggle (s : State) (k : Nat) : State :=match s.collapsed.findIdx? (fun x => x == k) with| some _ => { s with collapsed := s.collapsed.filter (fun x => x != k) }| none => { s with collapsed := s.collapsed.push k }end Bliku.Tui.Collapsible