diff --git a/README.md b/README.md index de5788e..4e6db33 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ ![Status](https://img.shields.io/badge/status-beta-blue) [![Clojars Project](https://img.shields.io/clojars/v/de.timokramer/charm.clj.svg)](https://clojars.org/de.timokramer/charm.clj) [![GitHub tag](https://img.shields.io/github/v/tag/TimoKramer/charm.clj?label=git%20tag)](https://github.com/TimoKramer/charm.clj/tags) +[![bb compatible](https://raw.githubusercontent.com/babashka/babashka/master/logo/badge.svg)](https://book.babashka.org#badges) A Clojure TUI (Terminal User Interface) library inspired by [Bubble Tea](https://github.com/charmbracelet/bubbletea). diff --git a/deps.edn b/deps.edn index 60f4a1e..579baa3 100644 --- a/deps.edn +++ b/deps.edn @@ -1,9 +1,9 @@ {:paths ["src"] :deps {org.clojure/clojure {:mvn/version "1.12.4"} org.clojure/core.async {:mvn/version "1.8.741"} - org.jline/jline-terminal-ffm {:mvn/version "4.0.10" + org.jline/jline-terminal-ffm {:mvn/version "4.0.12" :exclusions [org.jline/jline-native]} - org.jline/jline-reader {:mvn/version "4.0.10"}} + org.jline/jline-reader {:mvn/version "4.0.12"}} :aliases {:test {:extra-paths ["test"] :extra-deps {io.github.cognitect-labs/test-runner {:git/tag "v0.5.1" :git/sha "dfb30dd"}} diff --git a/doc/examples/README.md b/doc/examples/README.md index a94718b..afb0eda 100644 --- a/doc/examples/README.md +++ b/doc/examples/README.md @@ -3,37 +3,53 @@ ## Run examples ``` -clj -M -m examples.pomodoro +bb cheatsheet +``` +![cheatsheet gif](images/cheatsheet.gif) +``` +bb pomodoro ``` ![pomodoro gif](images/pomodoro.gif) ``` -clj -M -m examples.download +bb download ``` ![download gif](images/download.gif) ``` -clj -M -m examples.spinner-demo +bb spinner ``` ![spinner gif](images/spinner.gif) ``` -clj -M -m examples.todos +bb todos ``` ![todos gif](images/todos.gif) ``` -clj -M -m examples.countdown +bb countdown ``` ![countdown gif](images/countdown.gif) ``` -clj -M -m examples.file-browser +bb file-browser ``` ![file browser gif](images/file_browser.gif) ``` -clj -M -m examples.form +bb form ``` ![form gif](images/form.gif) ``` -clj -M -m examples.counter +bb counter ``` ![counter gif](images/counter.gif) +``` +bb timer 5 +``` +![timer gif](images/timer.gif) +``` +bb sketch +``` +![sketch gif](images/sketch.gif) +``` +bb emojis +``` +![emojis gif](images/emojis.gif) ## native-image compilation @@ -42,4 +58,3 @@ clj -T:build all native-image -jar target/timer.jar -o timer ./timer -n Pomodoro 30m ``` - diff --git a/doc/examples/bb.edn b/doc/examples/bb.edn index 1d9711c..8b32028 100644 --- a/doc/examples/bb.edn +++ b/doc/examples/bb.edn @@ -9,8 +9,8 @@ counter {:doc "Run counter example" :task (exec 'examples.counter/-main)} - emoji-width {:doc "Run emoji width demo" - :task (exec 'examples.emoji-width/-main)} + emojis {:doc "Run emojis example" + :task (exec 'examples.emojis/-main)} download {:doc "Run download example" :task (exec 'examples.download/-main)} @@ -24,11 +24,29 @@ pomodoro {:doc "Run pomodoro example" :task (exec 'examples.pomodoro/-main)} - spinner {:doc "Run spinner demo" + sketch {:doc "Run sketch example" + :task (exec 'examples.sketch/-main)} + + spinner {:doc "Run spinner example" :task (exec 'examples.spinner-demo/-main)} timer {:doc "Run timer example" - :task (exec 'examples.timer/-main)} + :requires ([examples.timer]) + :task (apply examples.timer/-main *command-line-args*)} todos {:doc "Run todos example" - :task (exec 'examples.todos/-main)}}} + :task (exec 'examples.todos/-main)} + + recreate-gifs {:doc "Recreate all gifs with vhs" + :task (do (shell "vhs vhs/cheatsheet.tape") + (shell "vhs vhs/countdown.tape") + (shell "vhs vhs/counter.tape") + #_(shell "vhs vhs/emojis.tape") + (shell "vhs vhs/download.tape") + (shell "vhs vhs/file-browser.tape") + (shell "vhs vhs/form.tape") + (shell "vhs vhs/pomodoro.tape") + (shell "vhs vhs/sketch.tape") + (shell "vhs vhs/spinner.tape") + #_(shell "vhs vhs/timer.tape") + (shell "vhs vhs/todos.tape"))}}} diff --git a/doc/examples/images/cheatsheet.gif b/doc/examples/images/cheatsheet.gif new file mode 100644 index 0000000..6135186 Binary files /dev/null and b/doc/examples/images/cheatsheet.gif differ diff --git a/doc/examples/images/countdown.gif b/doc/examples/images/countdown.gif index 3be125d..3d22eea 100644 Binary files a/doc/examples/images/countdown.gif and b/doc/examples/images/countdown.gif differ diff --git a/doc/examples/images/counter.gif b/doc/examples/images/counter.gif index 17cc135..0d0983d 100644 Binary files a/doc/examples/images/counter.gif and b/doc/examples/images/counter.gif differ diff --git a/doc/examples/images/download.gif b/doc/examples/images/download.gif index 3579ecb..69d6a65 100644 Binary files a/doc/examples/images/download.gif and b/doc/examples/images/download.gif differ diff --git a/doc/examples/images/emojis.gif b/doc/examples/images/emojis.gif new file mode 100644 index 0000000..7a4c650 Binary files /dev/null and b/doc/examples/images/emojis.gif differ diff --git a/doc/examples/images/file_browser.gif b/doc/examples/images/file_browser.gif index f0908e6..ac11576 100644 Binary files a/doc/examples/images/file_browser.gif and b/doc/examples/images/file_browser.gif differ diff --git a/doc/examples/images/form.gif b/doc/examples/images/form.gif index 73d1565..ff00a65 100644 Binary files a/doc/examples/images/form.gif and b/doc/examples/images/form.gif differ diff --git a/doc/examples/images/pomodoro.gif b/doc/examples/images/pomodoro.gif index b1e37ee..c529117 100644 Binary files a/doc/examples/images/pomodoro.gif and b/doc/examples/images/pomodoro.gif differ diff --git a/doc/examples/images/sketch.gif b/doc/examples/images/sketch.gif new file mode 100644 index 0000000..82cb03d Binary files /dev/null and b/doc/examples/images/sketch.gif differ diff --git a/doc/examples/images/spinner.gif b/doc/examples/images/spinner.gif index 536747f..b754124 100644 Binary files a/doc/examples/images/spinner.gif and b/doc/examples/images/spinner.gif differ diff --git a/doc/examples/images/timer.gif b/doc/examples/images/timer.gif new file mode 100644 index 0000000..b24fd8f Binary files /dev/null and b/doc/examples/images/timer.gif differ diff --git a/doc/examples/images/todos.gif b/doc/examples/images/todos.gif index b6d391e..37616b0 100644 Binary files a/doc/examples/images/todos.gif and b/doc/examples/images/todos.gif differ diff --git a/doc/examples/src/examples/cheatsheet.clj b/doc/examples/src/examples/cheatsheet.clj index 01f44c2..7107d66 100644 --- a/doc/examples/src/examples/cheatsheet.clj +++ b/doc/examples/src/examples/cheatsheet.clj @@ -224,10 +224,10 @@ (vec (map (fn [kw] (symbol (namespace kw) (name kw))) see-alsos))))) (defn- open-overlay [state fn-sym] - (let [overlay-width (max 40 (min 60 (- (:width state) 10))) + (let [overlay-width (max 40 (- (:width state) 10)) content-width (- overlay-width 4) content (build-overlay-content fn-sym content-width) - overlay-height (max 5 (min (- (:height state) 6) 20)) + overlay-height (max 5 (- (:height state) 12)) see-alsos (or (extract-see-alsos fn-sym) [])] (-> state (assoc :mode :overlay) diff --git a/doc/examples/src/examples/emoji_width.clj b/doc/examples/src/examples/emojis.clj similarity index 73% rename from doc/examples/src/examples/emoji_width.clj rename to doc/examples/src/examples/emojis.clj index cc0d024..6df1401 100644 --- a/doc/examples/src/examples/emoji_width.clj +++ b/doc/examples/src/examples/emojis.clj @@ -1,11 +1,13 @@ -(ns examples.emoji-width +(ns examples.emojis "Demonstrates grapheme cluster width handling with emoji in tables and borders. Shows that ZWJ sequences, flags, and skin-tone emoji are measured correctly - when JLine 4 Mode 2027 is active (see ADR 006)." + when JLine 4 Mode 2027 is active (see ADR 007)." (:require - [charm.core :as charm] - [charm.ansi.width :as w])) + [charm.components.table :as table] + [charm.message :as msg] + [charm.program :as program] + [charm.style.core :as style])) ;; --------------------------------------------------------------------------- ;; Data @@ -34,28 +36,28 @@ ;; --------------------------------------------------------------------------- (def title-style - (charm/style :bold true :fg charm/magenta)) + (style/style :bold true :fg style/magenta)) (def subtitle-style - (charm/style :fg charm/cyan :italic true)) + (style/style :fg style/cyan :italic true)) (def box-style - (charm/style :border charm/rounded-border + (style/style :border style/rounded-border :padding [0 1] - :border-fg charm/cyan)) + :border-fg style/cyan)) (def header-style - (charm/style :bold true :fg charm/yellow)) + (style/style :bold true :fg style/yellow)) (def cursor-style - (charm/style :bold true :fg charm/green)) + (style/style :bold true :fg style/green)) ;; --------------------------------------------------------------------------- ;; Init / Update / View ;; --------------------------------------------------------------------------- (defn init [] - (let [tbl (charm/table [{:title "Emoji" :width 6} + (let [tbl (table/table [{:title "Emoji" :width 6} {:title "Name" :width 22} {:title "Type" :width 34} {:title "Expect" :width 6} @@ -70,21 +72,21 @@ (defn update-fn [tbl msg] (cond - (or (charm/key-match? msg "q") - (charm/key-match? msg "ctrl+c")) - [tbl charm/quit-cmd] + (or (msg/key-match? msg "q") + (msg/key-match? msg "ctrl+c")) + [tbl program/quit-cmd] :else - (charm/table-update tbl msg))) + (table/table-update tbl msg))) (defn view [tbl] (let [rows (mapv (fn [[emoji name desc]] - [emoji name desc "2" (str (w/string-width emoji))]) + [emoji name desc "2" (str (style/string-width emoji))]) emoji-rows) tbl (assoc tbl :rows rows)] - (str (charm/render title-style "Grapheme Cluster Width Demo") "\n" - (charm/render subtitle-style "Emoji should align neatly if Mode 2027 is active") "\n\n" - (charm/render box-style (charm/table-view tbl {:separator " │ "})) + (str (style/render title-style "Grapheme Cluster Width Demo") "\n" + (style/render subtitle-style "Emoji should align neatly if Mode 2027 is active") "\n\n" + (style/render box-style (table/table-view tbl {:separator " │ "})) "\n\n" "j/k navigate q quit"))) @@ -93,7 +95,7 @@ ;; --------------------------------------------------------------------------- (defn -main [& _args] - (charm/run {:init init - :update update-fn - :view view - :alt-screen true})) + (program/run {:init init + :update update-fn + :view view + :alt-screen true})) diff --git a/doc/examples/vhs/cheatsheet.tape b/doc/examples/vhs/cheatsheet.tape new file mode 100644 index 0000000..89008cc --- /dev/null +++ b/doc/examples/vhs/cheatsheet.tape @@ -0,0 +1,25 @@ +Output images/cheatsheet.gif + +Set Width 1200 +Set Height 600 +Set TypingSpeed 300ms +Set Shell bash + +Type "bb cheatsheet" +Enter +Escape +Type "[?2027;2$y" +Escape +Type "jjjjllllll/walk" +Sleep 500ms +Escape +Type "[C" +Enter +Type "jjjjjjjjq" +Escape +Type "q" +Sleep 500ms +Backspace +Sleep 500ms +Escape +Type "q" diff --git a/doc/examples/vhs/emojis.tape b/doc/examples/vhs/emojis.tape new file mode 100644 index 0000000..1447443 --- /dev/null +++ b/doc/examples/vhs/emojis.tape @@ -0,0 +1,14 @@ +Output images/emojis.gif + +Set Shell zsh +Set TypingSpeed 200ms +Set Width 2000 +Set FontFamily "Fira Code" + +Type "bb emojis" +Enter +Escape +Type "[?2027;2$y" +Escape +Type "jjjjjkkkjjjjjjjq" +Type "q" diff --git a/doc/examples/vhs/sketch.tape b/doc/examples/vhs/sketch.tape new file mode 100644 index 0000000..18d7b36 --- /dev/null +++ b/doc/examples/vhs/sketch.tape @@ -0,0 +1,207 @@ +Output images/sketch.gif + +Set Shell bash + +Type "bb sketch" +Enter +Escape +Type "[?2027;2$y" +Escape +Type "[?62;4;22;28;52c" +Escape +Type "[<0;6;4M" +Escape +Type "[<32;7;4M" +Escape +Type "[<32;8;4M" +Escape +Type "[<32;9;4M" +Escape +Type "[<32;10;4M" +Escape +Type "[<32;11;4M" +Escape +Type "[<32;12;4M" +Escape +Type "[<32;13;4M" +Escape +Type "[<32;14;4M" +Escape +Type "[<32;15;4M" +Escape +Type "[<32;16;4M" +Escape +Type "[<32;17;4M" +Escape +Type "[<32;18;4M" +Escape +Type "[<32;19;4M" +Escape +Type "[<32;20;4M" +Escape +Type "[<32;21;4M" +Escape +Type "[<0;21;4m" +Escape +Type "[<2;21;4M" +Escape +Type "[<34;20;4M" +Escape +Type "[<34;19;4M" +Escape +Type "[<34;18;4M" +Escape +Type "[<34;17;4M" +Escape +Type "[<34;16;4M" +Escape +Type "[<34;15;4M" +Escape +Type "[<34;14;4M" +Escape +Type "[<34;13;4M" +Escape +Type "[<34;12;4M" +Escape +Type "[<34;11;4M" +Escape +Type "[<34;10;4M" +Escape +Type "[<34;9;4M" +Escape +Type "[<34;9;3M" +Escape +Type "[<34;8;3M" +Escape +Type "[<34;7;3M" +Escape +Type "[<34;7;4M" +Escape +Type "[<34;6;4M" +Escape +Type "[<2;6;4m" +Escape +Type "[<65;6;4M" +Escape +Type "[<65;6;4M" +Escape +Type "[<65;6;4M" +Escape +Type "[<65;6;4M" +Escape +Type "[<65;6;4M" +Escape +Type "[<0;6;4M" +Escape +Type "[<32;7;4M" +Escape +Type "[<32;8;4M" +Escape +Type "[<32;9;4M" +Escape +Type "[<32;10;4M" +Escape +Type "[<32;11;4M" +Escape +Type "[<32;12;4M" +Escape +Type "[<32;13;4M" +Escape +Type "[<32;14;4M" +Escape +Type "[<32;15;4M" +Escape +Type "[<32;16;4M" +Escape +Type "[<32;17;4M" +Escape +Type "[<32;18;4M" +Escape +Type "[<0;18;4m" +Escape +Type "[<2;18;4M" +Escape +Type "[<34;17;4M" +Escape +Type "[<34;16;4M" +Escape +Type "[<34;15;4M" +Escape +Type "[<34;14;4M" +Escape +Type "[<34;13;4M" +Escape +Type "[<34;12;4M" +Escape +Type "[<34;11;4M" +Escape +Type "[<34;10;4M" +Escape +Type "[<34;9;4M" +Escape +Type "[<34;8;4M" +Escape +Type "[<34;7;4M" +Escape +Type "[<34;6;4M" +Escape +Type "[<2;6;4m" +Escape +Type "[<65;6;4M" +Escape +Type "[<0;6;4M" +Escape +Type "[<32;7;4M" +Escape +Type "[<32;8;4M" +Escape +Type "[<32;9;4M" +Escape +Type "[<32;10;4M" +Escape +Type "[<32;11;4M" +Escape +Type "[<32;12;4M" +Escape +Type "[<32;13;4M" +Escape +Type "[<32;14;4M" +Escape +Type "[<32;15;4M" +Escape +Type "[<32;16;4M" +Escape +Type "[<32;17;4M" +Escape +Type "[<32;18;4M" +Escape +Type "[<0;18;4m" +Escape +Type "[<2;18;4M" +Escape +Type "[<34;17;4M" +Escape +Type "[<34;16;4M" +Escape +Type "[<34;15;4M" +Escape +Type "[<34;14;4M" +Escape +Type "[<34;13;4M" +Escape +Type "[<34;12;4M" +Escape +Type "[<34;11;4M" +Escape +Type "[<34;10;4M" +Escape +Type "[<34;9;4M" +Escape +Type "[<34;8;4M" +Escape +Type "[<34;7;4M" +Escape +Type "[<34;6;4M" +Escape +Type "[<2;6;4m" +Type "q" diff --git a/doc/examples/vhs/timer.tape b/doc/examples/vhs/timer.tape new file mode 100644 index 0000000..ba3d880 --- /dev/null +++ b/doc/examples/vhs/timer.tape @@ -0,0 +1,7 @@ +Output images/timer.gif + +Set Shell bash + +Type "bb timer 5" +Enter +Sleep 6s