From 35998a25aa9c0cf69a4a1a97b12cbdc701e525c4 Mon Sep 17 00:00:00 2001 From: Vijay Janapa Reddi Date: Mon, 17 Nov 2025 00:03:44 -0500 Subject: [PATCH] Fix terminal box alignment in carousel demo YAML files - Add proper padding to account for emoji display width (2 columns) - Ensure all box content lines are exactly 100 characters wide - Update fix-box-alignment.py to calculate display width correctly - Apply fixes to all 4 carousel demo YMLs This ensures the terminal box borders align properly in generated GIFs. --- site/_static/demos/01-clone-setup.yml | 16 ++-- site/_static/demos/02-build-jupyter.yml | 26 ++--- site/_static/demos/03-export-tito.yml | 38 ++++---- site/_static/demos/04-validate-history.yml | 72 +++++++------- site/_static/demos/fix-box-alignment.py | 105 +++++++++++++-------- 5 files changed, 144 insertions(+), 113 deletions(-) mode change 100644 => 100755 site/_static/demos/fix-box-alignment.py diff --git a/site/_static/demos/01-clone-setup.yml b/site/_static/demos/01-clone-setup.yml index 70aa125b..88dda372 100644 --- a/site/_static/demos/01-clone-setup.yml +++ b/site/_static/demos/01-clone-setup.yml @@ -357,21 +357,21 @@ records: - delay: 600 content: "\e[1;36m╭──────────────────────────────────────────────────────────────────────────────────────────────────╮\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ Python 3.11.9\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ Python 3.11.9 \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ NumPy 1.26.4\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ NumPy 1.26.4 \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ Jupyter Lab 4.0.9\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ Jupyter Lab 4.0.9 \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ All dependencies installed\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ All dependencies installed \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m🎉 Ready to build ML systems!\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m 🎉 Ready to build ML systems! \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 content: "\e[1;36m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\e[0m\r\n" - delay: 2000 diff --git a/site/_static/demos/02-build-jupyter.yml b/site/_static/demos/02-build-jupyter.yml index d7da4cfa..594ab167 100644 --- a/site/_static/demos/02-build-jupyter.yml +++ b/site/_static/demos/02-build-jupyter.yml @@ -103,25 +103,25 @@ records: - delay: 600 content: "\e[1;36m╭──────────────────────────────────────────────────────────────────────────────────────────────────╮\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m📓 Opening module in Jupyter Lab...\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m📓 Opening module in Jupyter Lab... \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32mBuild the foundation:\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m Build the foundation: \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m • Implement Tensor class \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m • Implement Tensor class \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m • Array operations (add, mul, reshape) \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m • Array operations (add, mul, reshape) \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m • Broadcasting & indexing \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m • Broadcasting & indexing \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36mTest inline, iterate fast 🚀\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m Test inline, iterate fast 🚀 \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 content: "\e[1;36m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\e[0m\r\n" - delay: 800 @@ -141,11 +141,11 @@ records: - delay: 400 content: "\e[1;36m┌─────────────────────────────────────────────────────────┐\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m💡 Tip:\e[0m Code → Run tests → See results instantly \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m💡 Tip: Code → Run tests → See results instantly \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m💡 NBGrader:\e[0m Automated feedback as you code \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m💡 NBGrader: Automated feedback as you code \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m💡 When done:\e[0m tito module complete 01 \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m💡 When done: tito module complete 01 \e[1;36m│\e[0m\r\n" - delay: 100 content: "\e[1;36m└─────────────────────────────────────────────────────────┘\e[0m\r\n" - delay: 2000 diff --git a/site/_static/demos/03-export-tito.yml b/site/_static/demos/03-export-tito.yml index ef4aeea9..76256b9c 100644 --- a/site/_static/demos/03-export-tito.yml +++ b/site/_static/demos/03-export-tito.yml @@ -109,11 +109,11 @@ records: - delay: 600 content: "\e[1;36m╭──────────────────────────────────────────────────────────────────────────────────────────────────╮\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m🔍 Step 1/3: Running tests...\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m🔍 Step 1/3: Running tests... \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 content: "\e[1;36m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\e[0m\r\n" - delay: 800 @@ -151,11 +151,11 @@ records: - delay: 400 content: "\e[1;36m╭──────────────────────────────────────────────────────────────────────────────────────────────────╮\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m📦 Step 2/3: Exporting to tinytorch/...\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m📦 Step 2/3: Exporting to tinytorch/... \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 content: "\e[1;36m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\e[0m\r\n" - delay: 600 @@ -169,11 +169,11 @@ records: - delay: 400 content: "\e[1;36m╭──────────────────────────────────────────────────────────────────────────────────────────────────╮\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m💾 Step 3/3: Tracking completion...\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m💾 Step 3/3: Tracking completion... \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 content: "\e[1;36m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\e[0m\r\n" - delay: 400 @@ -185,25 +185,25 @@ records: - delay: 600 content: "\e[1;36m╭──────────────────────────────────────────────────────────────────────────────────────────────────╮\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32mYour code is now part of TinyTorch!\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m Your code is now part of TinyTorch! \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33mTry it:\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33mTry it: \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;37mpython\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;37mpython \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;37m>>> from tinytorch import Tensor\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;37m>>> from tinytorch import Tensor \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;37m>>> t = Tensor([1, 2, 3])\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;37m>>> t = Tensor([1, 2, 3]) \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33mNext:\e[0m tito module start 02 \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33mNext: tito module start 02 \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 content: "\e[1;36m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\e[0m\r\n" - delay: 2000 diff --git a/site/_static/demos/04-validate-history.yml b/site/_static/demos/04-validate-history.yml index 249ee5b7..3a55bbfb 100644 --- a/site/_static/demos/04-validate-history.yml +++ b/site/_static/demos/04-validate-history.yml @@ -105,27 +105,27 @@ records: - delay: 600 content: "\e[1;36m╭──────────────────────────────────────────────────────────────────────────────────────────────────╮\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m🔍 Checking prerequisites...\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m🔍 Checking prerequisites... \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ Module 01: Tensor\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ Module 01: Tensor \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ Module 02: Activations\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ Module 02: Activations \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ Module 03: Layers\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ Module 03: Layers \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ Module 04: Losses\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ Module 04: Losses \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ Module 05: Autograd\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ Module 05: Autograd \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ Module 06: Optimizers\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ Module 06: Optimizers \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ Module 07: Training\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ Module 07: Training \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 content: "\e[1;36m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\e[0m\r\n" - delay: 800 @@ -133,15 +133,15 @@ records: - delay: 600 content: "\e[1;36m╭──────────────────────────────────────────────────────────────────────────────────────────────────╮\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m📊 Dataset:\e[0m MNIST (60k train, 10k test) \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m📊 Dataset: MNIST (60k train, 10k test) \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m🏗️ Model:\e[0m 784 → 128 → 64 → 10 \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m🏗️ Model: 784 → 128 → 64 → 10 \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m⚙️ Using:\e[0m YOUR TinyTorch implementation \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m⚙️ Using: YOUR TinyTorch implementation \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 content: "\e[1;36m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\e[0m\r\n" - delay: 800 @@ -181,13 +181,13 @@ records: - delay: 600 content: "\e[1;36m╭──────────────────────────────────────────────────────────────────────────────────────────────────╮\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ Test Accuracy: 96.3%\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ Test Accuracy: 96.3% \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m✅ Threshold Met: >95% (1986 baseline)\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m ✅ Threshold Met: >95% (1986 baseline) \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 content: "\e[1;36m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\e[0m\r\n" - delay: 800 @@ -195,37 +195,37 @@ records: - delay: 600 content: "\e[1;36m╭──────────────────────────────────────────────────────────────────────────────────────────────────╮\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33m🎉 Milestone 03: MLP (1986) COMPLETE!\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33m🎉 Milestone 03: MLP (1986) COMPLETE! \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m You've recreated Rumelhart's breakthrough using \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m You've recreated Rumelhart's breakthrough using \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m YOUR OWN implementation of: \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m YOUR OWN implementation of: \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m • Tensor operations \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m • Tensor operations \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m • Activation functions \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m • Activation functions \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m • Neural network layers \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m • Neural network layers \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m • Backpropagation \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m • Backpropagation \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m • Gradient descent optimization \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m • Gradient descent optimization \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;32m💡 You didn't import it. You BUILT it.\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m 💡 You didn't import it. You BUILT it. \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;33mNext milestone:\e[0m tito milestone run 04 \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;33mNext milestone: tito milestone run 04 \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;90m(CNN Revolution - 1998)\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;90m(CNN Revolution - 1998) \e[1;36m│\e[0m\r\n" - delay: 100 - content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" + content: "\e[1;36m│\e[0m \e[1;36m│\e[0m\r\n" - delay: 100 content: "\e[1;36m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\e[0m\r\n" - delay: 2000 diff --git a/site/_static/demos/fix-box-alignment.py b/site/_static/demos/fix-box-alignment.py old mode 100644 new mode 100755 index bbbcc4bb..2e803439 --- a/site/_static/demos/fix-box-alignment.py +++ b/site/_static/demos/fix-box-alignment.py @@ -4,74 +4,105 @@ Fix box-drawing alignment in Terminalizer YAML files. This script ensures all box lines have consistent width by: 1. Finding all box-drawing content lines -2. Calculating the correct width based on terminal columns +2. Calculating the correct width based on terminal columns (100) 3. Padding text to fit within the box """ import re +import yaml from pathlib import Path # Terminal width from configs COLS = 100 -def fix_box_line(content, cols=COLS): - """Fix a single box-drawing line to have correct width.""" - # Extract ANSI codes and actual text - ansi_pattern = r'\x1b\[[0-9;]+m' +def get_display_width(text): + """ + Calculate display width accounting for emoji and special characters. + Emojis typically take 2 display columns. + """ + # Remove ANSI escape codes + text = re.sub(r'\\e\[[0-9;]+m', '', text) - # Box top/bottom patterns - if '╭' in content and '╮' in content: - # Top line: ╭─...─╮ - return f"\\e[1;36m╭{'─' * (cols - 2)}╮\\e[0m\\r\\n" + width = 0 + for char in text: + # Emoji and other wide characters + if ord(char) > 0x1F300: # Approximate emoji range + width += 2 + else: + width += 1 + return width - if '╰' in content and '╯' in content: - # Bottom line: ╰─...─╯ - return f"\\e[1;36m╰{'─' * (cols - 2)}╯\\e[0m\\r\\n" +def fix_box_content_line(content): + """Fix a box content line to be exactly 100 characters wide.""" + # This is a line like: │ ✅ Python 3.11.9 │ - if '│' in content: - # Side line with content: │ text... │ - # Strip ANSI codes to measure actual content - text_only = re.sub(ansi_pattern, '', content.replace('\\e', '\x1b')) - text_only = text_only.replace('\\r\\n', '').replace('│', '') - - # Calculate padding needed - content_width = len(text_only) - total_padding = cols - 2 - content_width # -2 for the │ on each side - - if total_padding < 0: - # Content too wide, truncate - text_only = text_only[:cols - 5] + '...' - total_padding = 0 - - # Keep original ANSI-formatted content but adjust spacing - # This is a simplified version - you may need to preserve exact ANSI codes + if '│' not in content: return content - return content + # Extract the content between the │ characters + # Pattern: \e[color]│\e[reset] content \e[color]│\e[reset] + + # Remove escape sequences to get clean content + clean = content.replace('\\e[1;36m', '').replace('\\e[0m', '').replace('\\e[1;32m', '') + clean = clean.replace('\\r\\n', '') + + if not clean.startswith('│') or not clean.endswith('│'): + return content + + # Get the inner content + inner = clean[1:-1] + + # Calculate how much padding we need + # Total width should be 100: │ (1) + content (98) + │ (1) + target_inner_width = 98 + current_width = get_display_width(inner) + + if current_width > target_inner_width: + # Content is too wide, we need to truncate + # This shouldn't happen with our content, but handle it + print(f"Warning: Content too wide ({current_width} > {target_inner_width}): {inner[:50]}...") + return content + + # Add padding spaces to the right + padding_needed = target_inner_width - current_width + padded_inner = inner + (' ' * padding_needed) + + # Reconstruct with ANSI codes + result = f"\\e[1;36m│\\e[0m{padded_inner}\\e[1;36m│\\e[0m\\r\\n" + + return result def process_yaml_file(filepath): """Process a single YAML file to fix box alignment.""" print(f"Processing {filepath.name}...") with open(filepath, 'r') as f: - lines = f.readlines() + content = f.read() + # Find all content lines with box characters + lines = content.split('\n') modified = False + for i, line in enumerate(lines): - if 'content:' in line and any(char in line for char in ['╭', '╮', '╰', '╯', '│']): - # This line contains box-drawing characters + if 'content:' in line and '│' in line: # Extract the content string match = re.search(r'content: "(.*)"', line) if match: original = match.group(1) - fixed = fix_box_line(original) + + # Skip top and bottom lines (they're already correct) + if '╭' in original or '╰' in original: + continue + + fixed = fix_box_content_line(original) if fixed != original: lines[i] = line.replace(original, fixed) modified = True + print(f" Fixed line {i}: {original[:50]}...") if modified: with open(filepath, 'w') as f: - f.writelines(lines) + f.write('\n'.join(lines)) print(f" ✅ Fixed {filepath.name}") else: print(f" ℹ️ No changes needed for {filepath.name}") @@ -81,12 +112,12 @@ def main(): demos_dir = Path(__file__).parent yaml_files = list(demos_dir.glob('[0-9][0-9]-*.yml')) - print(f"Found {len(yaml_files)} YAML files to process\\n") + print(f"Found {len(yaml_files)} YAML files to process\n") for yaml_file in sorted(yaml_files): process_yaml_file(yaml_file) - print("\\n✨ Done!") + print("\n✨ Done!") if __name__ == '__main__': main()