max / ripgrow
11 files changed,
+905 insertions,
-0 deletions
| @@ -0,0 +1,5 @@ | |||
| 1 | + | /target | |
| 2 | + | /Cargo.lock.bak | |
| 3 | + | CLAUDE.md | |
| 4 | + | .DS_Store | |
| 5 | + | *.swp |
| @@ -0,0 +1,1114 @@ | |||
| 1 | + | # This file is automatically @generated by Cargo. | |
| 2 | + | # It is not intended for manual editing. | |
| 3 | + | version = 4 | |
| 4 | + | ||
| 5 | + | [[package]] | |
| 6 | + | name = "allocator-api2" | |
| 7 | + | version = "0.2.21" | |
| 8 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 9 | + | checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" | |
| 10 | + | ||
| 11 | + | [[package]] | |
| 12 | + | name = "android_system_properties" | |
| 13 | + | version = "0.1.5" | |
| 14 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 15 | + | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" | |
| 16 | + | dependencies = [ | |
| 17 | + | "libc", | |
| 18 | + | ] | |
| 19 | + | ||
| 20 | + | [[package]] | |
| 21 | + | name = "autocfg" | |
| 22 | + | version = "1.5.1" | |
| 23 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 24 | + | checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" | |
| 25 | + | ||
| 26 | + | [[package]] | |
| 27 | + | name = "bitflags" | |
| 28 | + | version = "2.13.1" | |
| 29 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 30 | + | checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" | |
| 31 | + | ||
| 32 | + | [[package]] | |
| 33 | + | name = "bumpalo" | |
| 34 | + | version = "3.20.3" | |
| 35 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 36 | + | checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" | |
| 37 | + | ||
| 38 | + | [[package]] | |
| 39 | + | name = "cassowary" | |
| 40 | + | version = "0.3.0" | |
| 41 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 42 | + | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" | |
| 43 | + | ||
| 44 | + | [[package]] | |
| 45 | + | name = "castaway" | |
| 46 | + | version = "0.2.4" | |
| 47 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 48 | + | checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" | |
| 49 | + | dependencies = [ | |
| 50 | + | "rustversion", | |
| 51 | + | ] | |
| 52 | + | ||
| 53 | + | [[package]] | |
| 54 | + | name = "cc" | |
| 55 | + | version = "1.2.67" | |
| 56 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 57 | + | checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" | |
| 58 | + | dependencies = [ | |
| 59 | + | "find-msvc-tools", | |
| 60 | + | "shlex", | |
| 61 | + | ] | |
| 62 | + | ||
| 63 | + | [[package]] | |
| 64 | + | name = "cfg-if" | |
| 65 | + | version = "1.0.4" | |
| 66 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 67 | + | checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" | |
| 68 | + | ||
| 69 | + | [[package]] | |
| 70 | + | name = "chrono" | |
| 71 | + | version = "0.4.45" | |
| 72 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 73 | + | checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" | |
| 74 | + | dependencies = [ | |
| 75 | + | "iana-time-zone", | |
| 76 | + | "num-traits", | |
| 77 | + | "serde", | |
| 78 | + | "windows-link", | |
| 79 | + | ] | |
| 80 | + | ||
| 81 | + | [[package]] | |
| 82 | + | name = "compact_str" | |
| 83 | + | version = "0.8.2" | |
| 84 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 85 | + | checksum = "7fd622ebbb56a5b2ccb651b32b911cdeb2a9b4b11776b2473bf26a26a286244e" | |
| 86 | + | dependencies = [ | |
| 87 | + | "castaway", | |
| 88 | + | "cfg-if", | |
| 89 | + | "itoa", | |
| 90 | + | "rustversion", | |
| 91 | + | "ryu", | |
| 92 | + | "static_assertions", | |
| 93 | + | ] | |
| 94 | + | ||
| 95 | + | [[package]] | |
| 96 | + | name = "convert_case" | |
| 97 | + | version = "0.10.0" | |
| 98 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 99 | + | checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" | |
| 100 | + | dependencies = [ | |
| 101 | + | "unicode-segmentation", | |
| 102 | + | ] | |
| 103 | + | ||
| 104 | + | [[package]] | |
| 105 | + | name = "core-foundation-sys" | |
| 106 | + | version = "0.8.7" | |
| 107 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 108 | + | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" | |
| 109 | + | ||
| 110 | + | [[package]] | |
| 111 | + | name = "crossterm" | |
| 112 | + | version = "0.28.1" | |
| 113 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 114 | + | checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" | |
| 115 | + | dependencies = [ | |
| 116 | + | "bitflags", | |
| 117 | + | "crossterm_winapi", | |
| 118 | + | "mio", | |
| 119 | + | "parking_lot", | |
| 120 | + | "rustix 0.38.44", | |
| 121 | + | "signal-hook", | |
| 122 | + | "signal-hook-mio", | |
| 123 | + | "winapi", | |
| 124 | + | ] | |
| 125 | + | ||
| 126 | + | [[package]] | |
| 127 | + | name = "crossterm" | |
| 128 | + | version = "0.29.0" | |
| 129 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 130 | + | checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" | |
| 131 | + | dependencies = [ | |
| 132 | + | "bitflags", | |
| 133 | + | "crossterm_winapi", | |
| 134 | + | "derive_more", | |
| 135 | + | "document-features", | |
| 136 | + | "mio", | |
| 137 | + | "parking_lot", | |
| 138 | + | "rustix 1.1.4", | |
| 139 | + | "signal-hook", | |
| 140 | + | "signal-hook-mio", | |
| 141 | + | "winapi", | |
| 142 | + | ] | |
| 143 | + | ||
| 144 | + | [[package]] | |
| 145 | + | name = "crossterm_winapi" | |
| 146 | + | version = "0.9.1" | |
| 147 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 148 | + | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" | |
| 149 | + | dependencies = [ | |
| 150 | + | "winapi", | |
| 151 | + | ] | |
| 152 | + | ||
| 153 | + | [[package]] | |
| 154 | + | name = "darling" | |
| 155 | + | version = "0.23.0" | |
| 156 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 157 | + | checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" | |
| 158 | + | dependencies = [ | |
| 159 | + | "darling_core", | |
| 160 | + | "darling_macro", | |
| 161 | + | ] | |
| 162 | + | ||
| 163 | + | [[package]] | |
| 164 | + | name = "darling_core" | |
| 165 | + | version = "0.23.0" | |
| 166 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 167 | + | checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" | |
| 168 | + | dependencies = [ | |
| 169 | + | "ident_case", | |
| 170 | + | "proc-macro2", | |
| 171 | + | "quote", | |
| 172 | + | "strsim", | |
| 173 | + | "syn", | |
| 174 | + | ] | |
| 175 | + | ||
| 176 | + | [[package]] | |
| 177 | + | name = "darling_macro" | |
| 178 | + | version = "0.23.0" | |
| 179 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 180 | + | checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" | |
| 181 | + | dependencies = [ | |
| 182 | + | "darling_core", | |
| 183 | + | "quote", | |
| 184 | + | "syn", | |
| 185 | + | ] | |
| 186 | + | ||
| 187 | + | [[package]] | |
| 188 | + | name = "derive_more" | |
| 189 | + | version = "2.1.1" | |
| 190 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 191 | + | checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" | |
| 192 | + | dependencies = [ | |
| 193 | + | "derive_more-impl", | |
| 194 | + | ] | |
| 195 | + | ||
| 196 | + | [[package]] | |
| 197 | + | name = "derive_more-impl" | |
| 198 | + | version = "2.1.1" | |
| 199 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 200 | + | checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" | |
| 201 | + | dependencies = [ | |
| 202 | + | "convert_case", | |
| 203 | + | "proc-macro2", | |
| 204 | + | "quote", | |
| 205 | + | "rustc_version", | |
| 206 | + | "syn", | |
| 207 | + | ] | |
| 208 | + | ||
| 209 | + | [[package]] | |
| 210 | + | name = "dirs" | |
| 211 | + | version = "6.0.0" | |
| 212 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 213 | + | checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" | |
| 214 | + | dependencies = [ | |
| 215 | + | "dirs-sys", | |
| 216 | + | ] | |
| 217 | + | ||
| 218 | + | [[package]] | |
| 219 | + | name = "dirs-sys" | |
| 220 | + | version = "0.5.0" | |
| 221 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 222 | + | checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" | |
| 223 | + | dependencies = [ | |
| 224 | + | "libc", | |
| 225 | + | "option-ext", | |
| 226 | + | "redox_users", | |
| 227 | + | "windows-sys 0.61.2", | |
| 228 | + | ] | |
| 229 | + | ||
| 230 | + | [[package]] | |
| 231 | + | name = "document-features" | |
| 232 | + | version = "0.2.12" | |
| 233 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 234 | + | checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" | |
| 235 | + | dependencies = [ | |
| 236 | + | "litrs", | |
| 237 | + | ] | |
| 238 | + | ||
| 239 | + | [[package]] | |
| 240 | + | name = "either" | |
| 241 | + | version = "1.16.0" | |
| 242 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 243 | + | checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" | |
| 244 | + | ||
| 245 | + | [[package]] | |
| 246 | + | name = "equivalent" | |
| 247 | + | version = "1.0.2" | |
| 248 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 249 | + | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" | |
| 250 | + | ||
| 251 | + | [[package]] | |
| 252 | + | name = "errno" | |
| 253 | + | version = "0.3.14" | |
| 254 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 255 | + | checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" | |
| 256 | + | dependencies = [ | |
| 257 | + | "libc", | |
| 258 | + | "windows-sys 0.61.2", | |
| 259 | + | ] | |
| 260 | + | ||
| 261 | + | [[package]] | |
| 262 | + | name = "fallible-iterator" | |
| 263 | + | version = "0.3.0" | |
| 264 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 265 | + | checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" | |
| 266 | + | ||
| 267 | + | [[package]] | |
| 268 | + | name = "fallible-streaming-iterator" | |
| 269 | + | version = "0.1.9" | |
| 270 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 271 | + | checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" | |
| 272 | + | ||
| 273 | + | [[package]] | |
| 274 | + | name = "find-msvc-tools" | |
| 275 | + | version = "0.1.9" | |
| 276 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 277 | + | checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" | |
| 278 | + | ||
| 279 | + | [[package]] | |
| 280 | + | name = "foldhash" | |
| 281 | + | version = "0.1.5" | |
| 282 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 283 | + | checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" | |
| 284 | + | ||
| 285 | + | [[package]] | |
| 286 | + | name = "futures-core" | |
| 287 | + | version = "0.3.33" | |
| 288 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 289 | + | checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" | |
| 290 | + | ||
| 291 | + | [[package]] | |
| 292 | + | name = "futures-task" | |
| 293 | + | version = "0.3.33" | |
| 294 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 295 | + | checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" | |
| 296 | + | ||
| 297 | + | [[package]] | |
| 298 | + | name = "futures-util" | |
| 299 | + | version = "0.3.33" | |
| 300 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 301 | + | checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" | |
| 302 | + | dependencies = [ | |
| 303 | + | "futures-core", | |
| 304 | + | "futures-task", | |
| 305 | + | "pin-project-lite", | |
| 306 | + | "slab", | |
| 307 | + | ] | |
| 308 | + | ||
| 309 | + | [[package]] | |
| 310 | + | name = "getrandom" | |
| 311 | + | version = "0.2.17" | |
| 312 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 313 | + | checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" | |
| 314 | + | dependencies = [ | |
| 315 | + | "cfg-if", | |
| 316 | + | "libc", | |
| 317 | + | "wasi", | |
| 318 | + | ] | |
| 319 | + | ||
| 320 | + | [[package]] | |
| 321 | + | name = "hashbrown" | |
| 322 | + | version = "0.15.5" | |
| 323 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 324 | + | checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" | |
| 325 | + | dependencies = [ | |
| 326 | + | "allocator-api2", | |
| 327 | + | "equivalent", | |
| 328 | + | "foldhash", | |
| 329 | + | ] | |
| 330 | + | ||
| 331 | + | [[package]] | |
| 332 | + | name = "hashlink" | |
| 333 | + | version = "0.10.0" | |
| 334 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 335 | + | checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" | |
| 336 | + | dependencies = [ | |
| 337 | + | "hashbrown", | |
| 338 | + | ] | |
| 339 | + | ||
| 340 | + | [[package]] | |
| 341 | + | name = "heck" | |
| 342 | + | version = "0.5.0" | |
| 343 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 344 | + | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" | |
| 345 | + | ||
| 346 | + | [[package]] | |
| 347 | + | name = "iana-time-zone" | |
| 348 | + | version = "0.1.65" | |
| 349 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 350 | + | checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" | |
| 351 | + | dependencies = [ | |
| 352 | + | "android_system_properties", | |
| 353 | + | "core-foundation-sys", | |
| 354 | + | "iana-time-zone-haiku", | |
| 355 | + | "js-sys", | |
| 356 | + | "log", | |
| 357 | + | "wasm-bindgen", | |
| 358 | + | "windows-core", | |
| 359 | + | ] | |
| 360 | + | ||
| 361 | + | [[package]] | |
| 362 | + | name = "iana-time-zone-haiku" | |
| 363 | + | version = "0.1.2" | |
| 364 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 365 | + | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" | |
| 366 | + | dependencies = [ | |
| 367 | + | "cc", | |
| 368 | + | ] | |
| 369 | + | ||
| 370 | + | [[package]] | |
| 371 | + | name = "ident_case" | |
| 372 | + | version = "1.0.1" | |
| 373 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 374 | + | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" | |
| 375 | + | ||
| 376 | + | [[package]] | |
| 377 | + | name = "indoc" | |
| 378 | + | version = "2.0.7" | |
| 379 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 380 | + | checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" | |
| 381 | + | dependencies = [ | |
| 382 | + | "rustversion", | |
| 383 | + | ] | |
| 384 | + | ||
| 385 | + | [[package]] | |
| 386 | + | name = "instability" | |
| 387 | + | version = "0.3.12" | |
| 388 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 389 | + | checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971" | |
| 390 | + | dependencies = [ | |
| 391 | + | "darling", | |
| 392 | + | "indoc", | |
| 393 | + | "proc-macro2", | |
| 394 | + | "quote", | |
| 395 | + | "syn", | |
| 396 | + | ] | |
| 397 | + | ||
| 398 | + | [[package]] | |
| 399 | + | name = "itertools" | |
| 400 | + | version = "0.13.0" | |
| 401 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 402 | + | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" | |
| 403 | + | dependencies = [ | |
| 404 | + | "either", | |
| 405 | + | ] | |
| 406 | + | ||
| 407 | + | [[package]] | |
| 408 | + | name = "itoa" | |
| 409 | + | version = "1.0.18" | |
| 410 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 411 | + | checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" | |
| 412 | + | ||
| 413 | + | [[package]] | |
| 414 | + | name = "js-sys" | |
| 415 | + | version = "0.3.103" | |
| 416 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 417 | + | checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" | |
| 418 | + | dependencies = [ | |
| 419 | + | "cfg-if", | |
| 420 | + | "futures-util", | |
| 421 | + | "wasm-bindgen", | |
| 422 | + | ] | |
| 423 | + | ||
| 424 | + | [[package]] | |
| 425 | + | name = "libc" | |
| 426 | + | version = "0.2.186" | |
| 427 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 428 | + | checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" | |
| 429 | + | ||
| 430 | + | [[package]] | |
| 431 | + | name = "libredox" | |
| 432 | + | version = "0.1.18" | |
| 433 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 434 | + | checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" | |
| 435 | + | dependencies = [ | |
| 436 | + | "libc", | |
| 437 | + | ] | |
| 438 | + | ||
| 439 | + | [[package]] | |
| 440 | + | name = "libsqlite3-sys" | |
| 441 | + | version = "0.35.0" | |
| 442 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 443 | + | checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f" | |
| 444 | + | dependencies = [ | |
| 445 | + | "cc", | |
| 446 | + | "pkg-config", | |
| 447 | + | "vcpkg", | |
| 448 | + | ] | |
| 449 | + | ||
| 450 | + | [[package]] | |
| 451 | + | name = "linux-raw-sys" | |
| 452 | + | version = "0.4.15" | |
| 453 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 454 | + | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" | |
| 455 | + | ||
| 456 | + | [[package]] | |
| 457 | + | name = "linux-raw-sys" | |
| 458 | + | version = "0.12.1" | |
| 459 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 460 | + | checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" | |
| 461 | + | ||
| 462 | + | [[package]] | |
| 463 | + | name = "litrs" | |
| 464 | + | version = "1.0.0" | |
| 465 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 466 | + | checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" | |
| 467 | + | ||
| 468 | + | [[package]] | |
| 469 | + | name = "lock_api" | |
| 470 | + | version = "0.4.14" | |
| 471 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 472 | + | checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" | |
| 473 | + | dependencies = [ | |
| 474 | + | "scopeguard", | |
| 475 | + | ] | |
| 476 | + | ||
| 477 | + | [[package]] | |
| 478 | + | name = "log" | |
| 479 | + | version = "0.4.33" | |
| 480 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 481 | + | checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" | |
| 482 | + | ||
| 483 | + | [[package]] | |
| 484 | + | name = "lru" | |
| 485 | + | version = "0.12.5" | |
| 486 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 487 | + | checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" | |
| 488 | + | dependencies = [ | |
| 489 | + | "hashbrown", | |
| 490 | + | ] | |
| 491 | + | ||
| 492 | + | [[package]] | |
| 493 | + | name = "mio" | |
| 494 | + | version = "1.2.2" | |
| 495 | + | source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 496 | + | checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" | |
| 497 | + | dependencies = [ | |
| 498 | + | "libc", | |
| 499 | + | "log", | |
| 500 | + | "wasi", |
Lines truncated
| @@ -0,0 +1,18 @@ | |||
| 1 | + | [workspace] | |
| 2 | + | members = ["crates/ripgrow-core", "crates/ripgrow-tui"] | |
| 3 | + | resolver = "3" | |
| 4 | + | ||
| 5 | + | [workspace.package] | |
| 6 | + | version = "0.1.0" | |
| 7 | + | edition = "2024" | |
| 8 | + | license-file = "LICENSE" | |
| 9 | + | repository = "https://git.sr.ht/~maxjmath/ripgrow" | |
| 10 | + | ||
| 11 | + | [workspace.dependencies] | |
| 12 | + | ripgrow-core = { path = "crates/ripgrow-core" } | |
| 13 | + | rusqlite = { version = "0.37", features = ["bundled"] } | |
| 14 | + | thiserror = "2" | |
| 15 | + | chrono = { version = "0.4", default-features = false, features = ["clock", "serde"] } | |
| 16 | + | dirs = "6" | |
| 17 | + | ratatui = "0.29" | |
| 18 | + | crossterm = "0.29" |
| @@ -0,0 +1,21 @@ | |||
| 1 | + | MIT License | |
| 2 | + | ||
| 3 | + | Copyright (c) 2026 Make Creative, LLC | |
| 4 | + | ||
| 5 | + | Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 6 | + | of this software and associated documentation files (the "Software"), to deal | |
| 7 | + | in the Software without restriction, including without limitation the rights | |
| 8 | + | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 9 | + | copies of the Software, and to permit persons to whom the Software is | |
| 10 | + | furnished to do so, subject to the following conditions: | |
| 11 | + | ||
| 12 | + | The above copyright notice and this permission notice shall be included in all | |
| 13 | + | copies or substantial portions of the Software. | |
| 14 | + | ||
| 15 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 16 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 17 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 18 | + | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 19 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 20 | + | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 21 | + | SOFTWARE. |
| @@ -0,0 +1,40 @@ | |||
| 1 | + | # ripgrow | |
| 2 | + | ||
| 3 | + | A ratatui TUI for programming and tracking resistance-training workouts. You | |
| 4 | + | build a library of exercise templates, log each session's sets, and the app | |
| 5 | + | generates the next workout as a printable PDF using progression rules over your | |
| 6 | + | history and a self-reported readiness map. | |
| 7 | + | ||
| 8 | + | Two intended users, one binary: | |
| 9 | + | ||
| 10 | + | - Solo lifter. One profile, one SQLite file, log-then-generate. | |
| 11 | + | - Personal trainer. Multiple profiles side by side, one per client. Delivery | |
| 12 | + | is a texted PDF; clients never touch ripgrow. | |
| 13 | + | ||
| 14 | + | ## Crates | |
| 15 | + | ||
| 16 | + | - `ripgrow-core` — data model, schema migrations, progression state machine. | |
| 17 | + | - `ripgrow-tui` — ratatui frontend, ships the `ripgrow` binary. | |
| 18 | + | ||
| 19 | + | ## Storage | |
| 20 | + | ||
| 21 | + | One SQLite file per profile at | |
| 22 | + | `~/Library/Application Support/ripgrow/profiles/<name>.db`. Design detail | |
| 23 | + | lives in the internal design notes. | |
| 24 | + | ||
| 25 | + | ## Migrations | |
| 26 | + | ||
| 27 | + | `rusqlite` bundled + `PRAGMA user_version` as the version tracker, matching | |
| 28 | + | the audiofiles pattern. Migration steps are embedded SQL in `ripgrow-core`. | |
| 29 | + | ||
| 30 | + | ## Build | |
| 31 | + | ||
| 32 | + | Target `aarch64-apple-darwin` only, built on mbp. No cross-compilation. | |
| 33 | + | ||
| 34 | + | ``` | |
| 35 | + | cargo build --release | |
| 36 | + | ``` | |
| 37 | + | ||
| 38 | + | ## License | |
| 39 | + | ||
| 40 | + | MIT. |
| @@ -0,0 +1,12 @@ | |||
| 1 | + | [package] | |
| 2 | + | name = "ripgrow-core" | |
| 3 | + | version.workspace = true | |
| 4 | + | edition.workspace = true | |
| 5 | + | license-file.workspace = true | |
| 6 | + | repository.workspace = true | |
| 7 | + | description = "Core data model and progression logic for ripgrow, a resistance-training programmer." | |
| 8 | + | ||
| 9 | + | [dependencies] | |
| 10 | + | rusqlite = { workspace = true } | |
| 11 | + | thiserror = { workspace = true } | |
| 12 | + | chrono = { workspace = true } |
| @@ -0,0 +1,263 @@ | |||
| 1 | + | //! SQLite wrapper with versioned migrations for one ripgrow profile. | |
| 2 | + | //! | |
| 3 | + | //! Migrations are tracked with `PRAGMA user_version`. Each step runs inside a | |
| 4 | + | //! transaction so the schema change and version bump are atomic. Pattern is | |
| 5 | + | //! borrowed from audiofiles-core; kept minimal here because no migrations | |
| 6 | + | //! have shipped yet. | |
| 7 | + | ||
| 8 | + | use std::path::Path; | |
| 9 | + | ||
| 10 | + | use rusqlite::{Connection, OptionalExtension, params}; | |
| 11 | + | ||
| 12 | + | use crate::error::Error; | |
| 13 | + | ||
| 14 | + | const MIGRATIONS: &[&str] = &[MIGRATION_001]; | |
| 15 | + | ||
| 16 | + | /// Unit preference for a profile. Stored as `'kg'` or `'lb'`; the choice is | |
| 17 | + | /// made at profile-create time and hard to change safely later. | |
| 18 | + | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | |
| 19 | + | pub enum Unit { | |
| 20 | + | Kg, | |
| 21 | + | Lb, | |
| 22 | + | } | |
| 23 | + | ||
| 24 | + | impl Unit { | |
| 25 | + | pub fn as_str(&self) -> &'static str { | |
| 26 | + | match self { | |
| 27 | + | Unit::Kg => "kg", | |
| 28 | + | Unit::Lb => "lb", | |
| 29 | + | } | |
| 30 | + | } | |
| 31 | + | ||
| 32 | + | pub fn parse(s: &str) -> Result<Self, Error> { | |
| 33 | + | match s { | |
| 34 | + | "kg" => Ok(Unit::Kg), | |
| 35 | + | "lb" => Ok(Unit::Lb), | |
| 36 | + | other => Err(Error::InvalidUnit(other.to_string())), | |
| 37 | + | } | |
| 38 | + | } | |
| 39 | + | } | |
| 40 | + | ||
| 41 | + | pub struct Db { | |
| 42 | + | conn: Connection, | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | impl Db { | |
| 46 | + | /// Open (or create) a profile database at `path` and run migrations. | |
| 47 | + | /// Does not populate the `meta` row; call [`Db::init_profile`] once on | |
| 48 | + | /// first-run to record the profile name and unit choice. | |
| 49 | + | pub fn open(path: impl AsRef<Path>) -> Result<Self, Error> { | |
| 50 | + | let conn = Connection::open(path)?; | |
| 51 | + | conn.pragma_update(None, "foreign_keys", "ON")?; | |
| 52 | + | conn.pragma_update(None, "journal_mode", "WAL")?; | |
| 53 | + | let mut db = Self { conn }; | |
| 54 | + | db.migrate()?; | |
| 55 | + | Ok(db) | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | /// In-memory database for tests. | |
| 59 | + | #[cfg(test)] | |
| 60 | + | pub fn open_in_memory() -> Result<Self, Error> { | |
| 61 | + | let conn = Connection::open_in_memory()?; | |
| 62 | + | conn.pragma_update(None, "foreign_keys", "ON")?; | |
| 63 | + | let mut db = Self { conn }; | |
| 64 | + | db.migrate()?; | |
| 65 | + | Ok(db) | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | /// Insert the `meta` row on a freshly-created profile. Idempotent guard: | |
| 69 | + | /// returns Ok without touching the row if one already exists. | |
| 70 | + | pub fn init_profile(&self, profile_name: &str, unit: Unit) -> Result<(), Error> { | |
| 71 | + | let exists: bool = self | |
| 72 | + | .conn | |
| 73 | + | .query_row("SELECT 1 FROM meta LIMIT 1", [], |_| Ok(true)) | |
| 74 | + | .optional()? | |
| 75 | + | .unwrap_or(false); | |
| 76 | + | if exists { | |
| 77 | + | return Ok(()); | |
| 78 | + | } | |
| 79 | + | self.conn.execute( | |
| 80 | + | "INSERT INTO meta (profile_name, unit, created) \ | |
| 81 | + | VALUES (?1, ?2, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))", | |
| 82 | + | params![profile_name, unit.as_str()], | |
| 83 | + | )?; | |
| 84 | + | Ok(()) | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | pub fn profile_name(&self) -> Result<Option<String>, Error> { | |
| 88 | + | Ok(self | |
| 89 | + | .conn | |
| 90 | + | .query_row("SELECT profile_name FROM meta LIMIT 1", [], |row| row.get(0)) | |
| 91 | + | .optional()?) | |
| 92 | + | } | |
| 93 | + | ||
| 94 | + | pub fn unit(&self) -> Result<Option<Unit>, Error> { | |
| 95 | + | let s: Option<String> = self | |
| 96 | + | .conn | |
| 97 | + | .query_row("SELECT unit FROM meta LIMIT 1", [], |row| row.get(0)) | |
| 98 | + | .optional()?; | |
| 99 | + | s.map(|v| Unit::parse(&v)).transpose() | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | pub fn conn(&self) -> &Connection { | |
| 103 | + | &self.conn | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | fn migrate(&mut self) -> Result<(), Error> { | |
| 107 | + | let version: i32 = self | |
| 108 | + | .conn | |
| 109 | + | .query_row("PRAGMA user_version", [], |row| row.get(0))?; | |
| 110 | + | ||
| 111 | + | for (i, sql) in MIGRATIONS.iter().enumerate() { | |
| 112 | + | let target = (i + 1) as i32; | |
| 113 | + | if version < target { | |
| 114 | + | let batch = | |
| 115 | + | format!("BEGIN;\n{sql}\nPRAGMA user_version = {target};\nCOMMIT;"); | |
| 116 | + | self.conn.execute_batch(&batch)?; | |
| 117 | + | } | |
| 118 | + | } | |
| 119 | + | Ok(()) | |
| 120 | + | } | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | const MIGRATION_001: &str = r#" | |
| 124 | + | CREATE TABLE meta ( | |
| 125 | + | id INTEGER PRIMARY KEY CHECK (id = 1), | |
| 126 | + | profile_name TEXT NOT NULL, | |
| 127 | + | unit TEXT NOT NULL CHECK (unit IN ('kg', 'lb')), | |
| 128 | + | created TEXT NOT NULL | |
| 129 | + | ); | |
| 130 | + | ||
| 131 | + | CREATE TABLE tags ( | |
| 132 | + | id INTEGER PRIMARY KEY, | |
| 133 | + | name TEXT NOT NULL UNIQUE | |
| 134 | + | ); | |
| 135 | + | ||
| 136 | + | CREATE TABLE exercises ( | |
| 137 | + | id INTEGER PRIMARY KEY, | |
| 138 | + | name TEXT NOT NULL UNIQUE, | |
| 139 | + | resistance_type TEXT NOT NULL CHECK (resistance_type IN ( | |
| 140 | + | 'bodyweight', 'machine', 'freeweight', | |
| 141 | + | 'cardio_time', 'cardio_distance' | |
| 142 | + | )), | |
| 143 | + | load_unit TEXT NOT NULL, | |
| 144 | + | increment REAL NOT NULL, | |
| 145 | + | notes TEXT NOT NULL DEFAULT '' | |
| 146 | + | ); | |
| 147 | + | ||
| 148 | + | CREATE TABLE exercise_tags ( | |
| 149 | + | exercise_id INTEGER NOT NULL REFERENCES exercises(id) ON DELETE CASCADE, | |
| 150 | + | tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE, | |
| 151 | + | weight REAL NOT NULL DEFAULT 1.0, | |
| 152 | + | PRIMARY KEY (exercise_id, tag_id) | |
| 153 | + | ); | |
| 154 | + | ||
| 155 | + | CREATE TABLE sets ( | |
| 156 | + | id INTEGER PRIMARY KEY, | |
| 157 | + | session_date TEXT NOT NULL, | |
| 158 | + | exercise_id INTEGER NOT NULL REFERENCES exercises(id) ON DELETE RESTRICT, | |
| 159 | + | set_index INTEGER NOT NULL, | |
| 160 | + | load REAL NOT NULL, | |
| 161 | + | reps INTEGER NOT NULL, | |
| 162 | + | rpe INTEGER NOT NULL CHECK (rpe BETWEEN 1 AND 5), | |
| 163 | + | UNIQUE (session_date, exercise_id, set_index) | |
| 164 | + | ); | |
| 165 | + | ||
| 166 | + | CREATE INDEX idx_sets_session_date ON sets(session_date); | |
| 167 | + | CREATE INDEX idx_sets_exercise_date ON sets(exercise_id, session_date); | |
| 168 | + | ||
| 169 | + | CREATE TABLE progression_state ( | |
| 170 | + | exercise_id INTEGER PRIMARY KEY REFERENCES exercises(id) ON DELETE CASCADE, | |
| 171 | + | state TEXT NOT NULL CHECK (state IN ( | |
| 172 | + | 'progressing', 'probation', 'deloading', 'rebuilding' | |
| 173 | + | )), | |
| 174 | + | since_date TEXT NOT NULL | |
| 175 | + | ); | |
| 176 | + | ||
| 177 | + | CREATE TABLE readiness ( | |
| 178 | + | date TEXT NOT NULL, | |
| 179 | + | tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE, | |
| 180 | + | state TEXT NOT NULL CHECK (state IN ('ready', 'tired', 'sore')), | |
| 181 | + | PRIMARY KEY (date, tag_id) | |
| 182 | + | ); | |
| 183 | + | "#; | |
| 184 | + | ||
| 185 | + | #[cfg(test)] | |
| 186 | + | mod tests { | |
| 187 | + | use super::*; | |
| 188 | + | ||
| 189 | + | #[test] | |
| 190 | + | fn open_runs_migrations_and_sets_user_version() { | |
| 191 | + | let db = Db::open_in_memory().unwrap(); | |
| 192 | + | let v: i32 = db | |
| 193 | + | .conn | |
| 194 | + | .query_row("PRAGMA user_version", [], |row| row.get(0)) | |
| 195 | + | .unwrap(); | |
| 196 | + | assert_eq!(v, MIGRATIONS.len() as i32); | |
| 197 | + | } | |
| 198 | + | ||
| 199 | + | #[test] | |
| 200 | + | fn init_profile_writes_meta_row_and_is_idempotent() { | |
| 201 | + | let db = Db::open_in_memory().unwrap(); | |
| 202 | + | db.init_profile("self", Unit::Kg).unwrap(); | |
| 203 | + | db.init_profile("self", Unit::Kg).unwrap(); | |
| 204 | + | assert_eq!(db.profile_name().unwrap().as_deref(), Some("self")); | |
| 205 | + | assert_eq!(db.unit().unwrap(), Some(Unit::Kg)); | |
| 206 | + | } | |
| 207 | + | ||
| 208 | + | #[test] | |
| 209 | + | fn rpe_check_constraint_rejects_out_of_range() { | |
| 210 | + | let db = Db::open_in_memory().unwrap(); | |
| 211 | + | db.init_profile("self", Unit::Kg).unwrap(); | |
| 212 | + | db.conn | |
| 213 | + | .execute( | |
| 214 | + | "INSERT INTO exercises (name, resistance_type, load_unit, increment) \ | |
| 215 | + | VALUES ('squat', 'freeweight', 'kg', 2.5)", | |
| 216 | + | [], | |
| 217 | + | ) | |
| 218 | + | .unwrap(); | |
| 219 | + | let err = db.conn.execute( | |
| 220 | + | "INSERT INTO sets (session_date, exercise_id, set_index, load, reps, rpe) \ | |
| 221 | + | VALUES ('2026-07-18', 1, 1, 100.0, 5, 6)", | |
| 222 | + | [], | |
| 223 | + | ); | |
| 224 | + | assert!(err.is_err(), "rpe=6 should violate CHECK constraint"); | |
| 225 | + | } | |
| 226 | + | ||
| 227 | + | #[test] | |
| 228 | + | fn unit_check_constraint_rejects_bogus_unit() { | |
| 229 | + | let db = Db::open_in_memory().unwrap(); | |
| 230 | + | let err = db.conn.execute( | |
| 231 | + | "INSERT INTO meta (id, profile_name, unit, created) \ | |
| 232 | + | VALUES (1, 'x', 'stone', '2026-07-18T00:00:00Z')", | |
| 233 | + | [], | |
| 234 | + | ); | |
| 235 | + | assert!(err.is_err(), "unit='stone' should violate CHECK constraint"); | |
| 236 | + | } | |
| 237 | + | ||
| 238 | + | #[test] | |
| 239 | + | fn sets_unique_constraint_on_session_exercise_set() { | |
| 240 | + | let db = Db::open_in_memory().unwrap(); | |
| 241 | + | db.init_profile("self", Unit::Kg).unwrap(); | |
| 242 | + | db.conn | |
| 243 | + | .execute( | |
| 244 | + | "INSERT INTO exercises (name, resistance_type, load_unit, increment) \ | |
| 245 | + | VALUES ('bench', 'freeweight', 'kg', 2.5)", | |
| 246 | + | [], | |
| 247 | + | ) | |
| 248 | + | .unwrap(); | |
| 249 | + | db.conn | |
| 250 | + | .execute( | |
| 251 | + | "INSERT INTO sets (session_date, exercise_id, set_index, load, reps, rpe) \ | |
| 252 | + | VALUES ('2026-07-18', 1, 1, 80.0, 5, 3)", | |
| 253 | + | [], | |
| 254 | + | ) | |
| 255 | + | .unwrap(); | |
| 256 | + | let err = db.conn.execute( | |
| 257 | + | "INSERT INTO sets (session_date, exercise_id, set_index, load, reps, rpe) \ | |
| 258 | + | VALUES ('2026-07-18', 1, 1, 82.5, 5, 3)", | |
| 259 | + | [], | |
| 260 | + | ); | |
| 261 | + | assert!(err.is_err(), "duplicate (date, exercise, set_index) should fail"); | |
| 262 | + | } | |
| 263 | + | } |
| @@ -0,0 +1,13 @@ | |||
| 1 | + | use thiserror::Error; | |
| 2 | + | ||
| 3 | + | #[derive(Debug, Error)] | |
| 4 | + | pub enum Error { | |
| 5 | + | #[error("sqlite: {0}")] | |
| 6 | + | Sqlite(#[from] rusqlite::Error), | |
| 7 | + | ||
| 8 | + | #[error("io: {0}")] | |
| 9 | + | Io(#[from] std::io::Error), | |
| 10 | + | ||
| 11 | + | #[error("invalid unit: {0}")] | |
| 12 | + | InvalidUnit(String), | |
| 13 | + | } |
| @@ -0,0 +1,10 @@ | |||
| 1 | + | //! ripgrow-core: data model, schema, and progression logic for ripgrow. | |
| 2 | + | //! | |
| 3 | + | //! One SQLite file per profile. No `profile_id` column anywhere — a profile | |
| 4 | + | //! is a file, hand-off is copy-the-file, deletion is `rm`. | |
| 5 | + | ||
| 6 | + | pub mod db; | |
| 7 | + | pub mod error; | |
| 8 | + | ||
| 9 | + | pub use db::{Db, Unit}; | |
| 10 | + | pub use error::Error; |
| @@ -0,0 +1,18 @@ | |||
| 1 | + | [package] | |
| 2 | + | name = "ripgrow-tui" | |
| 3 | + | version.workspace = true | |
| 4 | + | edition.workspace = true | |
| 5 | + | license-file.workspace = true | |
| 6 | + | repository.workspace = true | |
| 7 | + | description = "Ratatui frontend for ripgrow, a resistance-training programmer." | |
| 8 | + | ||
| 9 | + | [[bin]] | |
| 10 | + | name = "ripgrow" | |
| 11 | + | path = "src/main.rs" | |
| 12 | + | ||
| 13 | + | [dependencies] | |
| 14 | + | ripgrow-core = { workspace = true } | |
| 15 | + | ratatui = { workspace = true } | |
| 16 | + | crossterm = { workspace = true } | |
| 17 | + | dirs = { workspace = true } | |
| 18 | + | thiserror = { workspace = true } |
| @@ -0,0 +1,5 @@ | |||
| 1 | + | //! ripgrow — ratatui frontend. Placeholder entry point; screens land next. | |
| 2 | + | ||
| 3 | + | fn main() { | |
| 4 | + | println!("ripgrow: TUI not implemented yet. See ripgrow-core for schema."); | |
| 5 | + | } |