TUI is done, tsk is live
So last time I had the CLI working. Today I finished the TUI and shipped the whole thing.
Getting ratatui going was interesting. It doesn’t work like anything I’ve done before. Instead of just printing stuff, you’ve got a loop that redraws the whole screen every time you press a key. You also have to set up and tear down the terminal manually. If you don’t, your terminal just breaks after you exit. Took me a second to get my head around it but once it clicked it made sense.
The TUI has two modes, Normal and Adding. Normal is where you scroll around and do things to tasks. Adding turns the bottom bar into a text input where you type your task and hit Enter. I think using enums for that was pretty clean.
I added two things that weren’t in the original plan. A reset command that wipes everything and brings the IDs back to 1, and making the done button a toggle instead of one way. The toggle was annoying, but in the end it worked out fine. The problem was that I forgot to update the function’s name to the updated one. Small thing but it tripped me up.
After that, I published to crates.io as task-manager-kotter (tsk) because task-manager was already taken. Then I set up GitHub Actions to build binaries for Linux, Windows, and Mac automatically when I push a tag. Hit a permissions error first try, so I had to go into the repo settings and flip on read/write for workflows. After that I programmed the yml file wrong, so it would merge the binaries instead of having them seperate. I fixed that, and it worked, all three binaries showed up in the release.
What’s working
I got the core database and CLI working
Built the foundation today for my SQLite task store and a working CLI with four commands: add, list, done, and delete. You can actually add tasks and check them off from the terminal now.
What’s working
cargo run – add “buy milk”
cargo run – list
Output: 1: buy milk [ ]
cargo run – done 1
cargo run – list
Output: 1: buy milk [x]
The stack is rusqlite for SQLite (with the bundled feature so there are no system deps), clap for argument parsing with the derive macro, and chrono for timestamps. The project is split into models.rs, db.rs, commands.rs, and main.rs. These keep the database logic completely separate from the CLI wiring.
One thing that tripped me up: Rust’s ownership model means you can’t just pass a Connection willy nilly, you have to borrow it with &Connection everywhere. Took a few compiler errors to get the hang of it, but now it makes sense.
Next up
Building the TUI with ratatui so you can navigate tasks without typing commands. After that: publishing to crates.io and updating the README.