From 1bb8dde4a4f083b1d0f5dc52ed341adec8f715c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABlle=20MARTIN?= <maelle.martin@proton.me>
Date: Thu, 5 Sep 2024 11:13:58 +0200
Subject: [PATCH] SCRIPT: Add ratatui

Still need to think how to handle it, it seems that the flux
architecture is something that can be Ok for us. The workers stores the
state, and the ui handle pulls and render the thing. This is exactly
what we want here.
---
 src/Rust/Cargo.lock                 | 396 +++++++++++++++++++++++++++-
 src/Rust/Cargo.toml                 |   3 +-
 src/Rust/vvs_cli/Cargo.toml         |   1 +
 src/Rust/vvs_cli/src/args.rs        |  17 +-
 src/Rust/vvs_cli/src/compiler.rs    |  48 ++++
 src/Rust/vvs_cli/src/config.rs      |   3 +-
 src/Rust/vvs_cli/src/lib.rs         |   1 +
 src/Rust/vvs_cli/src/main.rs        |  62 +----
 src/Rust/vvs_runtime/Cargo.toml     |   1 +
 src/Rust/vvs_runtime/src/runtime.rs |  64 +++--
 src/Rust/vvs_xdg/src/file/temp.rs   |  12 +
 11 files changed, 520 insertions(+), 88 deletions(-)
 create mode 100644 src/Rust/vvs_cli/src/compiler.rs

diff --git a/src/Rust/Cargo.lock b/src/Rust/Cargo.lock
index 79912599..9f75e1e9 100644
--- a/src/Rust/Cargo.lock
+++ b/src/Rust/Cargo.lock
@@ -106,6 +106,15 @@ version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
 
+[[package]]
+name = "approx"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
+dependencies = [
+ "num-traits",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.3.0"
@@ -143,18 +152,39 @@ version = "3.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
+[[package]]
+name = "by_address"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
+
 [[package]]
 name = "bytecount"
 version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
 
+[[package]]
+name = "cassowary"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
+
 [[package]]
 name = "cast"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
 
+[[package]]
+name = "castaway"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5"
+dependencies = [
+ "rustversion",
+]
+
 [[package]]
 name = "cbindgen"
 version = "0.27.0"
@@ -307,6 +337,20 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
 
+[[package]]
+name = "compact_str"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6050c3a16ddab2e412160b31f2c871015704239bca62f72f6e5f0be631d3f644"
+dependencies = [
+ "castaway",
+ "cfg-if",
+ "itoa",
+ "rustversion",
+ "ryu",
+ "static_assertions",
+]
+
 [[package]]
 name = "console"
 version = "0.15.8"
@@ -340,7 +384,7 @@ dependencies = [
  "clap",
  "criterion-plot",
  "is-terminal",
- "itertools",
+ "itertools 0.10.5",
  "num-traits",
  "once_cell",
  "oorandom",
@@ -361,7 +405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
 dependencies = [
  "cast",
- "itertools",
+ "itertools 0.10.5",
 ]
 
 [[package]]
@@ -389,6 +433,31 @@ version = "0.8.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
 
+[[package]]
+name = "crossterm"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
+dependencies = [
+ "bitflags",
+ "crossterm_winapi",
+ "mio",
+ "parking_lot",
+ "rustix",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
+]
+
+[[package]]
+name = "crossterm_winapi"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
+dependencies = [
+ "winapi",
+]
+
 [[package]]
 name = "crunchy"
 version = "0.2.2"
@@ -445,6 +514,12 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "fast-srgb8"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
+
 [[package]]
 name = "fastrand"
 version = "2.1.1"
@@ -496,6 +571,12 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
 [[package]]
 name = "hermit-abi"
 version = "0.4.0"
@@ -527,13 +608,23 @@ dependencies = [
  "walkdir",
 ]
 
+[[package]]
+name = "instability"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c"
+dependencies = [
+ "quote",
+ "syn 2.0.77",
+]
+
 [[package]]
 name = "is-terminal"
 version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
 dependencies = [
- "hermit-abi",
+ "hermit-abi 0.4.0",
  "libc",
  "windows-sys 0.52.0",
 ]
@@ -553,6 +644,15 @@ dependencies = [
  "either",
 ]
 
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
 [[package]]
 name = "itoa"
 version = "1.0.11"
@@ -606,18 +706,50 @@ dependencies = [
  "semver",
 ]
 
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
 [[package]]
 name = "log"
 version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
+[[package]]
+name = "lru"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904"
+dependencies = [
+ "hashbrown",
+]
+
 [[package]]
 name = "memchr"
 version = "2.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
+[[package]]
+name = "mio"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+dependencies = [
+ "hermit-abi 0.3.9",
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys 0.52.0",
+]
+
 [[package]]
 name = "num-traits"
 version = "0.2.19"
@@ -648,12 +780,101 @@ dependencies = [
  "ttf-parser",
 ]
 
+[[package]]
+name = "palette"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6"
+dependencies = [
+ "approx",
+ "fast-srgb8",
+ "palette_derive",
+ "phf",
+]
+
+[[package]]
+name = "palette_derive"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30"
+dependencies = [
+ "by_address",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets 0.52.6",
+]
+
 [[package]]
 name = "paste"
 version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
 
+[[package]]
+name = "phf"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
+dependencies = [
+ "phf_macros",
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
+dependencies = [
+ "phf_shared",
+ "rand",
+]
+
+[[package]]
+name = "phf_macros"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.77",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
+dependencies = [
+ "siphasher",
+]
+
 [[package]]
 name = "plotters"
 version = "0.3.6"
@@ -700,6 +921,43 @@ dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+
+[[package]]
+name = "ratatui"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdef7f9be5c0122f890d58bdf4d964349ba6a6161f705907526d891efabba57d"
+dependencies = [
+ "bitflags",
+ "cassowary",
+ "compact_str",
+ "crossterm",
+ "instability",
+ "itertools 0.13.0",
+ "lru",
+ "palette",
+ "paste",
+ "strum",
+ "strum_macros",
+ "unicode-segmentation",
+ "unicode-truncate",
+ "unicode-width",
+]
+
 [[package]]
 name = "rayon"
 version = "1.10.0"
@@ -720,6 +978,15 @@ dependencies = [
  "crossbeam-utils",
 ]
 
+[[package]]
+name = "redox_syscall"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
+dependencies = [
+ "bitflags",
+]
+
 [[package]]
 name = "regex"
 version = "1.10.6"
@@ -774,6 +1041,12 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "rustversion"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
+
 [[package]]
 name = "ryu"
 version = "1.0.18"
@@ -789,6 +1062,12 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
 [[package]]
 name = "semver"
 version = "1.0.23"
@@ -843,12 +1122,54 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
+[[package]]
+name = "signal-hook"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-mio"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
+dependencies = [
+ "libc",
+ "mio",
+ "signal-hook",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "similar"
 version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e"
 
+[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
 [[package]]
 name = "smol_str"
 version = "0.3.1"
@@ -859,12 +1180,40 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
 [[package]]
 name = "strsim"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
+[[package]]
+name = "strum"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
+dependencies = [
+ "strum_macros",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
+dependencies = [
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 2.0.77",
+]
+
 [[package]]
 name = "syn"
 version = "1.0.109"
@@ -1001,6 +1350,17 @@ version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
 
+[[package]]
+name = "unicode-truncate"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
+dependencies = [
+ "itertools 0.13.0",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
 [[package]]
 name = "unicode-width"
 version = "0.1.13"
@@ -1048,6 +1408,7 @@ dependencies = [
  "clap_complete",
  "clap_mangen",
  "log",
+ "ratatui",
  "serde",
  "thiserror",
  "toml",
@@ -1173,6 +1534,7 @@ version = "0.5.0"
 dependencies = [
  "anyhow",
  "log",
+ "ratatui",
  "serde",
  "serde_json",
  "vvs_ass",
@@ -1235,6 +1597,12 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
 [[package]]
 name = "wasm-bindgen"
 version = "0.2.93"
@@ -1300,6 +1668,22 @@ dependencies = [
  "wasm-bindgen",
 ]
 
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
 [[package]]
 name = "winapi-util"
 version = "0.1.9"
@@ -1309,6 +1693,12 @@ dependencies = [
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
diff --git a/src/Rust/Cargo.toml b/src/Rust/Cargo.toml
index 1bada05b..f5a301a4 100644
--- a/src/Rust/Cargo.toml
+++ b/src/Rust/Cargo.toml
@@ -91,7 +91,8 @@ ttf-parser = { version = "*" }
 ab_glyph   = { version = "*" }
 
 # CLI
-clap_mangen   = "*" # Could be replace by something crafter by hand…
+ratatui       = { version = "*", features = [ "macros", "palette" ] }
+clap_mangen   = "*" # TODO: Could be replace by something crafter by hand…
 clap_complete = "*"
 clap = { version = "*", default-features = false, features = [
     "usage",
diff --git a/src/Rust/vvs_cli/Cargo.toml b/src/Rust/vvs_cli/Cargo.toml
index a83fa5d4..dc91c6da 100644
--- a/src/Rust/vvs_cli/Cargo.toml
+++ b/src/Rust/vvs_cli/Cargo.toml
@@ -27,6 +27,7 @@ log.workspace           = true
 clap_mangen.workspace   = true
 clap_complete.workspace = true
 clap.workspace          = true
+ratatui.workspace       = true
 
 [build-dependencies]
 anyhow.workspace = true
diff --git a/src/Rust/vvs_cli/src/args.rs b/src/Rust/vvs_cli/src/args.rs
index 5f74ba2f..3b1bd4d7 100644
--- a/src/Rust/vvs_cli/src/args.rs
+++ b/src/Rust/vvs_cli/src/args.rs
@@ -1,9 +1,8 @@
 use crate::parser::FileTypeValueParser;
-use clap::Parser;
 use clap_complete::Shell;
 use std::path::PathBuf;
 
-#[derive(Parser, Debug)]
+#[derive(clap::Parser, Debug)]
 #[command( author
          , version
          , about
@@ -11,7 +10,6 @@ use std::path::PathBuf;
          , groups = [ clap::ArgGroup::new("action").args(["manpage", "shell", "font-file", "script.vvs"])
                     , clap::ArgGroup::new("ass")   .args(["subtitle.ass"]).conflicts_with_all(["manpage", "font-file"])
                     , clap::ArgGroup::new("opts")  .args(["options.ini"]) .conflicts_with_all(["shell", "manpage", "font-file"])
-                    , clap::ArgGroup::new("infos") .args(["info"])        .conflicts_with_all(["shell", "manpage", "font-file"])
 ])]
 pub struct Args {
     /// The script to run.
@@ -58,19 +56,6 @@ pub struct Args {
     )]
     pub includes: Vec<PathBuf>,
 
-    /// Shows informations about a script.
-    ///
-    /// The informations consists of the loaded modules, all the options, their possible values,
-    /// the order of the jobs, etc.
-    ///
-    /// When printing informations about a script you won't be able to run it. You can however
-    /// print the informations about a script then enter in iteractive mode.
-    #[arg( short  = 'P'
-         , long   = "info"
-         , action = clap::ArgAction::SetTrue
-    )]
-    pub info: bool,
-
     /// Display infos about embeded fonts or external fonts.
     #[arg( long   = "font-info"
          , action = clap::ArgAction::Set
diff --git a/src/Rust/vvs_cli/src/compiler.rs b/src/Rust/vvs_cli/src/compiler.rs
new file mode 100644
index 00000000..9fafdcc6
--- /dev/null
+++ b/src/Rust/vvs_cli/src/compiler.rs
@@ -0,0 +1,48 @@
+use crate::args::Args;
+use anyhow::Context as _;
+use clap::CommandFactory as _;
+use std::path::PathBuf;
+use vvs_lang::{FrontendPipeline, SearchPath, SourceCode};
+use vvs_runtime::Runtime;
+use vvs_xdg::file::TempFile;
+
+pub struct Settings {
+    pub script: Option<PathBuf>,
+    pub ass_file: Option<PathBuf>,
+    pub options: Option<PathBuf>,
+    pub includes: Vec<PathBuf>,
+    pub terminal: ratatui::DefaultTerminal,
+}
+
+pub fn run(settings: Settings) -> anyhow::Result<()> {
+    let script = match settings.script {
+        Some(script) => SourceCode::from_path(&script)?,
+        None => return Ok(Args::command().print_help()?),
+    };
+    let _ = script.module().context("expected a valid module name")?;
+
+    let Settings { ass_file, options, includes, .. } = settings;
+    let output = FrontendPipeline::new(&script)
+        .passes(&[])
+        .search(
+            &SearchPath::from_iter(includes)
+                .with_script_folder(script.folder().context("expected the script to have a parent folder")?),
+        )
+        .options(options.as_ref())?
+        .run()?;
+
+    let mut file = TempFile::new("vvcc")?;
+    Runtime::new(move |ctx| {
+        Ok(vvs_codegen::lowerer::Lowerer::new(&ctx, &output.main.name)?
+            .declare_globals(output.declared_functions())?
+            .lower_module(&output.main.name, output.ast)?
+            .lower_modules(output.imports)?
+            .generate_main(output.main)?
+            .finished())
+    })?
+    .with_output_file(&mut file)
+    .with_terminal(settings.terminal)
+    .run_on_file(ass_file.context("no subtitle file to run the script on")?)?;
+    file.leak();
+    Ok(())
+}
diff --git a/src/Rust/vvs_cli/src/config.rs b/src/Rust/vvs_cli/src/config.rs
index 25772ae6..026ea26f 100644
--- a/src/Rust/vvs_cli/src/config.rs
+++ b/src/Rust/vvs_cli/src/config.rs
@@ -29,7 +29,6 @@ pub struct Config {
     pub script: Option<PathBuf>,
     pub ass_file: Option<PathBuf>,
     pub options: Option<PathBuf>,
-    pub info: bool,
     pub manpage: bool,
     pub shell: Option<Shell>,
     pub font_info: Option<Option<PathBuf>>,
@@ -114,7 +113,7 @@ impl Config {
             append     args => self, { includes };
             set_if_not args => self, { script, ass_file, options, shell, font_info };
             max        args => self, { verbose };
-            override   args => self, { info, manpage };
+            override   args => self, { manpage };
         }
         self
     }
diff --git a/src/Rust/vvs_cli/src/lib.rs b/src/Rust/vvs_cli/src/lib.rs
index 2c31f840..784888b9 100644
--- a/src/Rust/vvs_cli/src/lib.rs
+++ b/src/Rust/vvs_cli/src/lib.rs
@@ -1,6 +1,7 @@
 #![forbid(unsafe_code)]
 
 pub mod args;
+pub mod compiler;
 pub mod config;
 pub mod logger;
 
diff --git a/src/Rust/vvs_cli/src/main.rs b/src/Rust/vvs_cli/src/main.rs
index c8030eca..ddf5ca0d 100644
--- a/src/Rust/vvs_cli/src/main.rs
+++ b/src/Rust/vvs_cli/src/main.rs
@@ -7,11 +7,10 @@ use clap::{CommandFactory as _, Parser as _};
 use std::{fs, io, path::Path};
 use vvs_cli::{
     args::Args,
+    compiler,
     config::{Config, ConfigFile},
 };
-use vvs_lang::{FrontendPipeline, SearchPath, SourceCode};
-use vvs_runtime::Runtime;
-use vvs_xdg::{file::TempFile, XDGConfig, XDGConfigMergedSilent};
+use vvs_xdg::{XDGConfig, XDGConfigMergedSilent};
 
 fn print_font(n: impl AsRef<Path>, f: &[u8]) -> Result<()> {
     let f = vvs_font::Font::try_from(f).with_context(|| format!("failed to parse font {}", n.as_ref().display()))?;
@@ -27,7 +26,7 @@ fn print_font(n: impl AsRef<Path>, f: &[u8]) -> Result<()> {
 fn main() -> Result<()> {
     vvs_cli::logger::init(None).context("failed to init logger")?;
 
-    let Config { script, ass_file, options, info, manpage, shell, font_info, includes, .. } = Config::default()
+    let Config { script, ass_file, options, manpage, shell, font_info, includes, .. } = Config::default()
         .with_config_file(
             XDGConfig::<ConfigFile, XDGConfigMergedSilent>::new("vvcc")
                 .file("vvcc.toml")
@@ -36,60 +35,21 @@ fn main() -> Result<()> {
         .with_args(Args::parse())
         .apply_logger();
 
-    // Handle auxiliary stuff
     if manpage {
-        return clap_mangen::Man::new(Args::command())
+        clap_mangen::Man::new(Args::command())
             .render(&mut io::stdout())
-            .context("failed to render manpage for vvcc");
+            .context("failed to render manpage for vvcc")
     } else if let Some(shell) = shell {
         clap_complete::generate(shell, &mut Args::command(), Args::command().get_name().to_string(), &mut io::stdout());
-        return Ok(());
+        Ok(())
     } else if let Some(font_info) = font_info {
-        return match font_info {
+        match font_info {
             Some(p) => print_font(&p, &fs::read(&p).with_context(|| format!("failed to read font: {}", p.display()))?),
             None => vvs_font::embeded_fonts().try_for_each(|(n, f)| print_font(n, f)),
-        };
-    }
-
-    // Parse, build, execute the script.
-    let script = match script {
-        Some(script) => SourceCode::from_path(&script)?,
-        None => return Ok(Args::command().print_help()?),
-    };
-    println!("main module ........ {}", script.module().context("expected a valid module name")?);
-    let output = FrontendPipeline::new(&script)
-        .passes(&[])
-        .search(
-            &SearchPath::from_iter(includes)
-                .with_script_folder(script.folder().context("expected the script to have a parent folder")?),
-        )
-        .options(options.as_ref())?
-        .run()?;
-
-    if info {
-        match ass_file {
-            Some(ref path) => println!("ass file ........... {}", path.display()),
-            None => println!("ass file ........... ø"),
         }
-        match options {
-            Some(path) => println!("options file ....... {}", path.display()),
-            None => println!("options file ....... ø"),
-        }
-        print!("{output}");
+    } else {
+        compiler::run(compiler::Settings { script, ass_file, options, includes, terminal: ratatui::init() })?;
+        ratatui::restore();
+        Ok(())
     }
-
-    let mut file = TempFile::new("vvcc")?;
-    Runtime::new(move |ctx| {
-        Ok(vvs_codegen::lowerer::Lowerer::new(&ctx, &output.main.name)?
-            .declare_globals(output.declared_functions())?
-            .lower_module(&output.main.name, output.ast)?
-            .lower_modules(output.imports)?
-            .generate_main(output.main)?
-            .finished())
-    })?
-    .run_on_file(ass_file.context("no subtitle file to run the script on")?)?
-    .write_ass_to_file(&mut file)?;
-
-    println!("output file ........ {}", file.leak().path().display());
-    Ok(())
 }
diff --git a/src/Rust/vvs_runtime/Cargo.toml b/src/Rust/vvs_runtime/Cargo.toml
index 25ee1821..40e2e947 100644
--- a/src/Rust/vvs_runtime/Cargo.toml
+++ b/src/Rust/vvs_runtime/Cargo.toml
@@ -11,6 +11,7 @@ log.workspace               = true
 anyhow.workspace            = true
 serde.workspace             = true
 serde_json.workspace        = true
+ratatui.workspace           = true
 vvs_runtime_types.workspace = true
 vvs_ass.workspace           = true
 vvs_utils.workspace         = true
diff --git a/src/Rust/vvs_runtime/src/runtime.rs b/src/Rust/vvs_runtime/src/runtime.rs
index 3eb25e53..a1b65e9c 100644
--- a/src/Rust/vvs_runtime/src/runtime.rs
+++ b/src/Rust/vvs_runtime/src/runtime.rs
@@ -1,28 +1,30 @@
 use crate::workers::Workers;
 use anyhow::{bail, Context as _};
-use std::{
-    path::Path,
-    sync::{
-        atomic::{AtomicU64, Ordering},
-        Arc,
-    },
-    thread,
-};
+use std::{fs, path::Path, sync::atomic::Ordering, thread};
 use vvs_ass::{ass_container_from_file, ASSContainer};
 use vvs_llvm::prelude::*;
 use vvs_runtime_types::types::VVRTTable;
 
+use ratatui::{
+    crossterm::event::{self, Event, KeyCode, KeyEventKind},
+    widgets::{Block, Paragraph},
+};
+
 #[allow(dead_code)]
-pub struct Runtime {
+pub struct Runtime<'a> {
     jit: JIT,
     workers: Workers,
+    output: Option<&'a mut fs::File>,
+    terminal: Option<ratatui::DefaultTerminal>,
 }
 
-impl Runtime {
-    pub fn new<'a>(init: impl FnOnce(Context<'a>) -> anyhow::Result<Module<'a>>) -> anyhow::Result<Self> {
+impl<'a> Runtime<'a> {
+    pub fn new<'ctx>(init: impl FnOnce(Context<'ctx>) -> anyhow::Result<Module<'ctx>>) -> anyhow::Result<Self> {
         Ok(Self {
             jit: JIT::init(init)?,
-            workers: Workers::new(|flag: Arc<AtomicU64>| loop {
+            output: None,
+            terminal: None,
+            workers: Workers::new(|flag| loop {
                 match flag.load(Ordering::SeqCst) {
                     0 => thread::yield_now(),
                     u64::MAX => return Ok(()),
@@ -32,13 +34,45 @@ impl Runtime {
         })
     }
 
-    pub fn run_on_container(self, ass: ASSContainer<VVRTTable>) -> anyhow::Result<ASSContainer<VVRTTable>> {
-        todo!("run on {ass:?}")
+    pub fn with_output_file(self, output: &'a mut fs::File) -> Self {
+        Self { output: Some(output), ..self }
     }
 
-    pub fn run_on_file(self, file: impl AsRef<Path>) -> anyhow::Result<ASSContainer<VVRTTable>> {
+    pub fn with_terminal(self, terminal: ratatui::DefaultTerminal) -> Self {
+        Self { terminal: Some(terminal), ..self }
+    }
+
+    pub fn run_on_file(self, file: impl AsRef<Path>) -> anyhow::Result<()> {
         self.run_on_container(
             ass_container_from_file::<VVRTTable>(file.as_ref()).context("failed to parse the subtitle file")?,
         )
     }
+
+    pub fn run_on_container(self, ass: ASSContainer<VVRTTable>) -> anyhow::Result<()> {
+        let Self { output, terminal, .. } = self;
+        log::error!("run on {ass:?}");
+
+        match terminal {
+            None => todo!("handle the case where we don't have a terminal"),
+            Some(mut terminal) => loop {
+                terminal.draw(|frame| {
+                    frame.render_widget(
+                        Paragraph::new("Hello World!").block(Block::bordered().title("Greeting")),
+                        frame.area(),
+                    );
+                })?;
+                if let Event::Key(key) = event::read()? {
+                    if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('q') {
+                        break;
+                    }
+                }
+            },
+        }
+
+        if let Some(output) = output {
+            ass.write_ass_to_file(output)?;
+        }
+
+        Ok(())
+    }
 }
diff --git a/src/Rust/vvs_xdg/src/file/temp.rs b/src/Rust/vvs_xdg/src/file/temp.rs
index 34816024..38360a1e 100644
--- a/src/Rust/vvs_xdg/src/file/temp.rs
+++ b/src/Rust/vvs_xdg/src/file/temp.rs
@@ -49,6 +49,18 @@ impl DerefMut for TempFile {
     }
 }
 
+impl AsRef<File> for TempFile {
+    fn as_ref(&self) -> &File {
+        self.deref()
+    }
+}
+
+impl AsMut<File> for TempFile {
+    fn as_mut(&mut self) -> &mut File {
+        self.deref_mut()
+    }
+}
+
 impl Drop for TempFile {
     fn drop(&mut self) {
         if !self.leak {
-- 
GitLab