(ns tui.simple "Simplified TUI runtime - no core.async, works with Babashka. Synchronous event loop, no timers/async commands." (:require [tui.terminal :as term] [tui.input :as input] [tui.render :as render] [tui.ansi :as ansi])) ;; === Commands === (def quit [:quit]) ;; === Key Matching === (defn key= "Check if message is a specific key." [msg key-pattern] (input/key-match? msg key-pattern)) (defn key-str "Get string representation of key." [msg] (input/key->str msg)) ;; === Simple Run Loop === (defn run "Run a TUI application (synchronous, no async commands). Options: - :init - Initial model (required) - :update - (fn [model msg] [new-model cmd]) (required) - :view - (fn [model] hiccup) (required) - :alt-screen - Use alternate screen buffer (default false) Returns the final model." [{:keys [init update view alt-screen] :or {alt-screen false}}] ;; Setup terminal (term/init-input!) (term/raw-mode!) (when alt-screen (term/alt-screen!)) (term/clear!) (try ;; Initial render (term/render! (render/render (view init))) ;; Main loop - simple synchronous (loop [model init] (if-let [key-msg (input/read-key)] (let [[new-model cmd] (update model key-msg)] ;; Render (term/render! (render/render (view new-model))) ;; Check for quit (if (= cmd [:quit]) new-model (recur new-model))) (recur model))) (finally ;; Cleanup (when alt-screen (term/exit-alt-screen!)) (term/restore!) (term/close-input!) (println)))) ;; Re-export render (def render render/render)