From c00273d2dd02bf91fb1ec11f9264535aa3430dc4 Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Tue, 20 Aug 2024 08:36:52 +0330 Subject: [PATCH 01/22] Setup criterion (bench library) --- Cargo.lock | 359 +++++++++++++++++++++++++++++++-- Cargo.toml | 7 + benches/test_100k_todo_sort.rs | 14 ++ 3 files changed, 367 insertions(+), 13 deletions(-) create mode 100644 benches/test_100k_todo_sort.rs diff --git a/Cargo.lock b/Cargo.lock index 3dd5c2b..8bd32b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "allocator-api2" version = "0.2.16" @@ -35,6 +44,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anstream" version = "0.6.11" @@ -123,6 +138,7 @@ dependencies = [ "chrono", "clap", "clap_complete", + "criterion", "crossterm", "home", "ratatui", @@ -136,6 +152,12 @@ 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 = "cc" version = "1.0.83" @@ -165,6 +187,33 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" version = "4.5.10" @@ -235,6 +284,67 @@ dependencies = [ "libc", ] +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "crossterm" version = "0.27.0" @@ -260,6 +370,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -296,6 +412,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.14.3" @@ -318,6 +444,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "home" version = "0.5.9" @@ -356,6 +488,26 @@ version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.0" @@ -365,11 +517,17 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -405,6 +563,12 @@ 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 = "0.8.10" @@ -432,6 +596,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + [[package]] name = "parking_lot" version = "0.12.1" @@ -461,6 +631,34 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "plotters" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" + +[[package]] +name = "plotters-svg" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +dependencies = [ + "plotters-backend", +] + [[package]] name = "proc-macro2" version = "1.0.71" @@ -489,7 +687,7 @@ dependencies = [ "cassowary", "crossterm", "indoc", - "itertools", + "itertools 0.12.0", "lru", "paste", "stability", @@ -498,6 +696,26 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -507,18 +725,93 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + [[package]] name = "rustversion" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.43", +] + +[[package]] +name = "serde_json" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha1" version = "0.10.6" @@ -626,6 +919,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tui-textarea" version = "0.4.0" @@ -673,6 +976,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -681,19 +994,20 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", @@ -706,9 +1020,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -716,9 +1030,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -729,9 +1043,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "web-sys" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "winapi" @@ -749,6 +1073,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index c0c7dbc..1e35659 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,10 @@ codegen-units = 1 lto = "fat" panic = "abort" strip = "debuginfo" + +[dev-dependencies] +criterion = { version = "0.5", features = ["html_reports"] } + +[[bench]] +name = "test_100k_todo_sort" +harness = false diff --git a/benches/test_100k_todo_sort.rs b/benches/test_100k_todo_sort.rs new file mode 100644 index 0000000..c6c1c65 --- /dev/null +++ b/benches/test_100k_todo_sort.rs @@ -0,0 +1,14 @@ +use std::{hint::black_box, path::PathBuf}; +use criterion::{criterion_group, criterion_main, Criterion}; + +use c3::{todo_app::App, AppArgs}; + +fn criterion_benchmark(c: &mut Criterion) { + let mut app = App::new(AppArgs { + todo_path: PathBuf::from("../fuckc3-100000-todo"), + ..Default::default() + }); + c.bench_function("sort 100k todo", |b| b.iter(|| black_box(&mut app).read())); +} +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); From 7cc565ec6eeb8fbae4215ea34184484212043c74 Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Tue, 20 Aug 2024 08:46:21 +0330 Subject: [PATCH 02/22] Update jalali patch after criterion --- patches/jalali-date.patch | 40 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/patches/jalali-date.patch b/patches/jalali-date.patch index 9113e9d..1ccbb14 100644 --- a/patches/jalali-date.patch +++ b/patches/jalali-date.patch @@ -1,10 +1,9 @@ diff --git a/Cargo.lock b/Cargo.lock -index 314718e..286bd3f 100644 +index 8bd32b6..c01bbf4 100644 --- a/Cargo.lock +++ b/Cargo.lock -@@ -124,8 +124,10 @@ dependencies = [ - "clap", - "clap_complete", +@@ -141,7 +141,9 @@ dependencies = [ + "criterion", "crossterm", "home", + "jalali-date", @@ -13,9 +12,9 @@ index 314718e..286bd3f 100644 "sha1", "tui-textarea", ] -@@ -349,6 +351,12 @@ dependencies = [ - "either", - ] +@@ -523,6 +525,12 @@ version = "1.0.11" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jalali-date" @@ -25,17 +24,11 @@ index 314718e..286bd3f 100644 + [[package]] name = "js-sys" - version = "0.3.67" -@@ -389,6 +397,18 @@ dependencies = [ - "hashbrown", - ] + version = "0.3.70" +@@ -569,6 +577,12 @@ version = "2.7.4" + source = "registry+https://github.com/rust-lang/crates.io-index" + checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -+[[package]] -+name = "memchr" -+version = "2.7.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" -+ +[[package]] +name = "minimal-lexical" +version = "0.2.1" @@ -45,7 +38,7 @@ index 314718e..286bd3f 100644 [[package]] name = "mio" version = "0.8.10" -@@ -401,6 +421,16 @@ dependencies = [ +@@ -581,6 +595,16 @@ dependencies = [ "windows-sys 0.48.0", ] @@ -62,9 +55,9 @@ index 314718e..286bd3f 100644 [[package]] name = "num-traits" version = "0.2.17" -@@ -497,6 +527,15 @@ version = "1.0.14" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +@@ -775,6 +799,15 @@ dependencies = [ + "winapi-util", + ] +[[package]] +name = "scanf" @@ -79,11 +72,10 @@ index 314718e..286bd3f 100644 name = "scopeguard" version = "1.2.0" diff --git a/Cargo.toml b/Cargo.toml -index 1e9f2ec..4e69d4a 100644 +index 1e35659..2aea84d 100644 --- a/Cargo.toml +++ b/Cargo.toml -@@ -11,6 +11,8 @@ crossterm = "0.27.0" - tui-textarea = "0.4.0" +@@ -12,6 +12,8 @@ tui-textarea = "0.4.0" chrono = "0.4.31" clap = { version = "4.4.18", features = ["derive", "string"] } clap_complete = "4.5.9" From 21614b9342795d6d62c1115439514161f64db45d Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Wed, 21 Aug 2024 10:21:04 +0330 Subject: [PATCH 03/22] Add more benchmarks Add display benchmark --- Cargo.toml | 2 +- benches/bench_500k.rs | 36 ++++++++++++++++++++++++++++++++++ benches/test_100k_todo_sort.rs | 14 ------------- 3 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 benches/bench_500k.rs delete mode 100644 benches/test_100k_todo_sort.rs diff --git a/Cargo.toml b/Cargo.toml index 1e35659..15bc100 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,5 +23,5 @@ strip = "debuginfo" criterion = { version = "0.5", features = ["html_reports"] } [[bench]] -name = "test_100k_todo_sort" +name = "bench_500k" harness = false diff --git a/benches/bench_500k.rs b/benches/bench_500k.rs new file mode 100644 index 0000000..40323e7 --- /dev/null +++ b/benches/bench_500k.rs @@ -0,0 +1,36 @@ +use std::{hint::black_box, path::PathBuf}; +use criterion::{criterion_group, criterion_main, Criterion}; + +use c3::{todo_app::App, AppArgs}; + +fn sort(c: &mut Criterion) { + let mut app = App::new(AppArgs { + todo_path: PathBuf::from("../fuckc3-todo"), + ..Default::default() + }); + c.bench_function("sort 500k todos", |b| b.iter(|| black_box(&mut app).read())); +} + +fn reorder(c: &mut Criterion) { + let mut app = App::new(AppArgs { + todo_path: PathBuf::from("../fuckc3-todo"), + ..Default::default() + }); + c.bench_function("reorder 500k todos", |b| b.iter(|| { + app.index = 400000; + black_box(&mut app).set_current_priority(1); + })); +} + +fn display(c: &mut Criterion) { + let mut app = App::new(AppArgs { + todo_path: PathBuf::from("../fuckc3-todo"), + ..Default::default() + }); + c.bench_function("display 500k todos", |b| b.iter(|| { + black_box(&mut app).display_current(); + })); +} + +criterion_group!(benches, sort, reorder, display); +criterion_main!(benches); diff --git a/benches/test_100k_todo_sort.rs b/benches/test_100k_todo_sort.rs deleted file mode 100644 index c6c1c65..0000000 --- a/benches/test_100k_todo_sort.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::{hint::black_box, path::PathBuf}; -use criterion::{criterion_group, criterion_main, Criterion}; - -use c3::{todo_app::App, AppArgs}; - -fn criterion_benchmark(c: &mut Criterion) { - let mut app = App::new(AppArgs { - todo_path: PathBuf::from("../fuckc3-100000-todo"), - ..Default::default() - }); - c.bench_function("sort 100k todo", |b| b.iter(|| black_box(&mut app).read())); -} -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); From 2ccd957017c55686950cebc74aafeb7599b22a8c Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Wed, 21 Aug 2024 12:07:25 +0330 Subject: [PATCH 04/22] Add better import formatting Add vim better vim fold --- src/cli_app.rs | 3 +++ src/fileio.rs | 3 +++ src/lib.rs | 3 +++ src/main.rs | 2 ++ src/todo_app.rs | 3 +++ src/todo_app/todo.rs | 21 +++++++++++---------- src/tui_app.rs | 8 ++------ 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/cli_app.rs b/src/cli_app.rs index 9d798e5..515fe26 100644 --- a/src/cli_app.rs +++ b/src/cli_app.rs @@ -1,3 +1,5 @@ +// vim:fileencoding=utf-8:foldmethod=marker +// imports {{{ use c3::todo_app::{App, Restriction, Todo, TodoList}; use clap_complete::Shell; use crate::Args; @@ -8,6 +10,7 @@ use std::io; use std::process; use std::path::PathBuf; use clap::Parser; +// }}} #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] diff --git a/src/fileio.rs b/src/fileio.rs index b5037ac..1c473c2 100644 --- a/src/fileio.rs +++ b/src/fileio.rs @@ -1,3 +1,5 @@ +// vim:fileencoding=utf-8:foldmethod=marker +// imports {{{ use home::home_dir; use std::fs::{remove_dir, remove_file, File}; use std::io::{self, prelude::*, Write}; @@ -6,6 +8,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use std::env; use std::process::Command; +// }}} #[inline(always)] pub fn append_notes_to_path_parent(filename: &Path) -> PathBuf { diff --git a/src/lib.rs b/src/lib.rs index 2b9dd98..d110e8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +// vim:fileencoding=utf-8:foldmethod=marker +// imports {{{ use clap::{Parser, ValueEnum}; use todo_app::SortMethod; use std::path::PathBuf; @@ -7,6 +9,7 @@ use std::fmt; pub mod date; pub mod fileio; pub mod todo_app; +// }}} #[derive(ValueEnum, Clone, Debug)] pub enum DoOnSelected { diff --git a/src/main.rs b/src/main.rs index 5a52bc4..de004bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ // vim:fileencoding=utf-8:foldmethod=marker +// imports {{{ use std::io; use clap::Parser; pub(crate) mod cli_app; @@ -9,6 +10,7 @@ use c3::{ }; use cli_app::CliArgs; use tui_app::TuiArgs; +// }}} /// A tree-like todo application that makes you smile #[derive(Parser, Debug)] diff --git a/src/todo_app.rs b/src/todo_app.rs index c5b860f..34d37bc 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -1,3 +1,5 @@ +// vim:fileencoding=utf-8:foldmethod=marker +// imports {{{ use std::cmp; use std::collections::VecDeque; use std::fs::create_dir_all; @@ -15,6 +17,7 @@ use std::rc::Rc; pub use todo::Todo; pub use self::todo_list::TodoList; +// }}} #[derive(Clone)] struct SearchPosition { diff --git a/src/todo_app/todo.rs b/src/todo_app/todo.rs index 7bb3b6e..37ceae0 100644 --- a/src/todo_app/todo.rs +++ b/src/todo_app/todo.rs @@ -1,11 +1,12 @@ -use std::fmt; -use std::path::Path; // vim:fileencoding=utf-8:foldmethod=marker -//std{{{ -use std::str::{self, FromStr}; -use std::{fs::remove_file, io}; -//}}} -// mod{{{ +//imports {{{ +use std::{ + fmt, + path::Path, + str::FromStr, + fs, + io, +}; mod dependency; mod note; pub mod schedule; @@ -14,7 +15,7 @@ use crate::{DisplayArgs, TodoDisplay}; use dependency::Dependency; use note::{open_note_temp_editor, sha1}; use schedule::Schedule; -//}}} +// }}} #[derive(Debug, Eq, PartialEq, Clone, Default)] pub struct Todo { @@ -248,7 +249,7 @@ impl Todo { pub fn delete_dependency_file(&mut self, path: &Path) -> io::Result<()> { if let Some(dependency) = &mut self.dependency { dependency.todo_list.remove_dependency_files(path)?; - let _ = remove_file(path.join(dependency.get_name())); + let _ = fs::remove_file(path.join(dependency.get_name())); } Ok(()) } @@ -257,7 +258,7 @@ impl Todo { pub fn delete_removed_dependent_files(&mut self, path: &Path) -> io::Result<()> { if let Some(dependency) = &mut self.removed_dependency { let _ = dependency.todo_list.remove_dependency_files(path); - let _ = remove_file(path.join(dependency.get_name())); + let _ = fs::remove_file(path.join(dependency.get_name())); } Ok(()) } diff --git a/src/tui_app.rs b/src/tui_app.rs index 236c635..4f9e298 100644 --- a/src/tui_app.rs +++ b/src/tui_app.rs @@ -1,13 +1,11 @@ // vim:fileencoding=utf-8:foldmethod=marker -// std {{{ +// imports {{{ use std::{ io::{self, BufRead, BufReader}, path::PathBuf, process::{Command, Stdio}, rc::Rc, }; -// }}} -// lib {{{ use clap::Parser; use crossterm::{ event::{ @@ -21,9 +19,6 @@ use crossterm::{ }; use ratatui::{prelude::*, widgets::*}; use tui_textarea::{CursorMove, Input, TextArea}; -// }}} -// mod {{{ - mod modules; use c3::{ todo_app::{App, Restriction, Todo, Schedule}, @@ -32,6 +27,7 @@ use c3::{ use modules::{potato::Potato, Module}; // }}} + #[derive(Debug)] pub enum HandlerOperation { Nothing, From c7c9d2fa2b265c534fb3d773e865df429620eca6 Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Thu, 22 Aug 2024 07:59:02 +0330 Subject: [PATCH 05/22] Add a unittest for AbandonedFirst --- src/todo_app.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/todo_app.rs b/src/todo_app.rs index 34d37bc..3b545db 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -848,6 +848,8 @@ mod tests { use clap::Parser; + use crate::date; + use super::*; fn dir(dir_name: &str) -> io::Result { @@ -1061,10 +1063,24 @@ mod tests { todo_path, ..Default::default() })?; + app.append("a todo".to_string()); + if let Some(todo) = app.todo_mut() { + todo.schedule= Some(Schedule::new_reminder(date::current())); + todo.set_done(true); + } + app.index = 0; app.go_down(); app.toggle_current_daily(); - assert!(app.todo().unwrap().schedule.is_some()); + assert!(!app.todo().unwrap().schedule.as_ref().unwrap().is_reminder()); + assert_eq!(app.index(), 1); + if let Some(schedule) = app.todo_mut().as_mut().map(|todo| todo.schedule.as_mut()).flatten() { + schedule.set_current_date(); + schedule.add_days_to_date(-2); + } + app.reorder_current(); + app.write_to_stdout(); assert_eq!(app.index(), 0); + Ok(()) } } From c32c4d80edff81980fd70033a2f9d441affdff4d Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sat, 24 Aug 2024 09:18:25 +0330 Subject: [PATCH 06/22] Remove unnecessary functions --- benches/bench_500k.rs | 14 ++++++++-- src/todo_app.rs | 53 ++++++++++++++------------------------ src/todo_app/todo.rs | 54 +++++++++------------------------------ src/todo_app/todo_list.rs | 6 ++--- src/tui_app.rs | 15 +++++++---- 5 files changed, 56 insertions(+), 86 deletions(-) diff --git a/benches/bench_500k.rs b/benches/bench_500k.rs index 40323e7..17955ee 100644 --- a/benches/bench_500k.rs +++ b/benches/bench_500k.rs @@ -1,4 +1,4 @@ -use std::{hint::black_box, path::PathBuf}; +use std::{fs::File, hint::black_box, io::BufWriter, path::PathBuf}; use criterion::{criterion_group, criterion_main, Criterion}; use c3::{todo_app::App, AppArgs}; @@ -32,5 +32,15 @@ fn display(c: &mut Criterion) { })); } -criterion_group!(benches, sort, reorder, display); +fn write_to_stdout(c: &mut Criterion) { + let mut app = App::new(AppArgs { + todo_path: PathBuf::from("../fuckc3-todo"), + ..Default::default() + }); + c.bench_function("write to stdout 500k todos", |b| b.iter(|| { + black_box(&mut app).write_to_stdout() + })); +} + +criterion_group!(benches, sort, reorder, display, write_to_stdout); criterion_main!(benches); diff --git a/src/todo_app.rs b/src/todo_app.rs index 3b545db..e6b01f2 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -41,9 +41,10 @@ impl SortMethod { .abandonment_coefficient() .total_cmp(&a.abandonment_coefficient()); if order.is_eq() { - return a.cmp(b); + a.cmp(b) + } else { + order } - order } } Self::Normal => { @@ -137,12 +138,6 @@ impl App { app } - pub fn toggle_schedule(&mut self) { - if let Some(todo) = self.todo_mut() { - todo.toggle_schedule(); - } - } - #[inline(always)] fn read_a_todo_list(path: &Path, notes_dir: &Path, args: &AppArgs) -> TodoList { let mut todo_list = TodoList::read(path); @@ -340,19 +335,14 @@ impl App { self.index } - #[inline] - pub fn show_done(&self) -> bool { - self.args.display_args.show_done - } - #[inline] pub fn toggle_show_done(&mut self) { - self.args.display_args.show_done = !self.show_done(); + self.args.display_args.show_done = !self.args.display_args.show_done; self.update_show_done_restriction(); } pub fn update_show_done_restriction(&mut self) { - if self.show_done() { + if self.args.display_args.show_done { self.unset_restriction() } else { self.set_restriction(Rc::new(|todo| !todo.done())) @@ -407,7 +397,7 @@ impl App { pub fn toggle_current_done(&mut self) { let index = self.index; self.todo_mut().unwrap().toggle_done(); - if self.show_done() { + if self.args.display_args.show_done { self.index = self.current_list_mut().reorder(index); } else { self.current_list_mut().sort(); @@ -456,7 +446,7 @@ impl App { #[inline] pub fn go_down(&mut self) { - let size = self.len(); + let size = self.current_list().len(&self.restriction); if size == 0 || self.index == size - 1 { self.index = 0; } else { @@ -511,7 +501,7 @@ impl App { #[inline] pub fn bottom(&self) -> usize { - match self.len() { + match self.current_list().len(&self.restriction) { 0 => 0, length => length - 1, } @@ -540,11 +530,6 @@ impl App { } } - #[inline] - pub fn len(&self) -> usize { - self.current_list().len(&self.restriction) - } - #[inline] pub fn current_list_mut(&mut self) -> &mut TodoList { self.changed = true; @@ -913,11 +898,11 @@ mod tests { let dir = dir("test-set-restrictions-done")?; let mut app = write_test_todos(&dir)?; app.toggle_current_done(); - assert_eq!(app.len(), 2); + assert_eq!(app.current_list().len(app.restriction()), 2); app.toggle_show_done(); - assert_eq!(app.len(), 3); + assert_eq!(app.current_list().len(app.restriction()), 3); app.toggle_show_done(); - assert_eq!(app.len(), 2); + assert_eq!(app.current_list().len(app.restriction()), 2); remove_dir_all(dir)?; Ok(()) } @@ -926,18 +911,18 @@ mod tests { fn test_set_restrictions_query() -> io::Result<()> { let dir = dir("test-set-restrictions-query")?; let mut app = write_test_todos(&dir)?; - assert_eq!(app.len(), 3); + assert_eq!(app.current_list().len(app.restriction()), 3); app.set_query_restriction(String::from("hello"), None); - assert_eq!(app.len(), 2); + assert_eq!(app.current_list().len(app.restriction()), 2); assert_eq!(app.index, 1); app.traverse_down(); app.unset_restriction(); app.traverse_up(); app.set_query_restriction(String::from("hello"), None); - assert_eq!(app.len(), 2); + assert_eq!(app.current_list().len(app.restriction()), 2); assert_eq!(app.index, 1); app.add_dependency_traverse_down(); - assert_eq!(app.len(), 1); + assert_eq!(app.current_list().len(app.restriction()), 1); remove_dir_all(dir)?; Ok(()) } @@ -947,14 +932,14 @@ mod tests { let dir = dir("test-set-restrictions-priority")?; let mut app = write_test_todos(&dir)?; app.set_current_priority(2); - assert_eq!(app.len(), 3); + assert_eq!(app.current_list().len(app.restriction()), 3); app.set_priority_restriction(2, None); - assert_eq!(app.len(), 1); + assert_eq!(app.current_list().len(app.restriction()), 1); app.set_priority_restriction(0, None); - assert_eq!(app.len(), 0); + assert_eq!(app.current_list().len(app.restriction()), 0); app.update_show_done_restriction(); app.set_priority_restriction(0, None); - assert_eq!(app.len(), 2); + assert_eq!(app.current_list().len(app.restriction()), 2); remove_dir_all(dir)?; Ok(()) } diff --git a/src/todo_app/todo.rs b/src/todo_app/todo.rs index 37ceae0..f0e0aab 100644 --- a/src/todo_app/todo.rs +++ b/src/todo_app/todo.rs @@ -223,21 +223,6 @@ impl Todo { }) } - #[inline] - pub fn is_note(&self) -> bool { - self.dependency.as_ref().map_or(false, |dep| dep.is_note()) - } - - #[inline] - pub fn dependencies(&self) -> Option<&TodoList> { - self.dependency.as_ref()?.todo_list() - } - - #[inline] - pub fn no_dependency(&self) -> bool { - self.dependency.is_none() - } - #[inline] pub fn add_todo_dependency(&mut self) { if self.dependency.is_none() { @@ -347,22 +332,9 @@ impl Todo { self.done = done; } - #[inline(always)] - fn standardize_priority(priority: u8) -> u8 { - match priority { - 0 => 10, - any => any, - } - } - - #[inline(always)] - fn standardized_priority(&self) -> u8 { - Self::standardize_priority(self.priority) - } - #[inline] pub fn decrease_priority(&mut self) { - if self.standardized_priority() < 9 { + if Self::standardize_priority(self.priority) < 9 { self.priority += 1 } else { self.priority = 0 @@ -371,8 +343,9 @@ impl Todo { #[inline] pub fn increase_priority(&mut self) { - if self.standardized_priority() > 1 { - self.priority = self.standardized_priority() - 1 + let standardize_priority = Self::standardize_priority(self.priority); + if standardize_priority > 1 { + self.priority = standardize_priority - 1 } else { self.priority = 1 } @@ -380,18 +353,12 @@ impl Todo { #[inline] pub fn set_priority(&mut self, priority: u8) { - self.priority = priority; - self.fix_priority(); - } - - #[inline] - fn fix_priority(&mut self) { - self.priority = Todo::fixed_priority(self.priority) + self.priority = Todo::fixed_priority(priority) } #[inline(always)] fn cmp_value(&self) -> u8 { - let mut priority = self.standardized_priority() * 2; + let mut priority = Self::standardize_priority(self.priority) * 2; if self.schedule.as_ref().map_or(false, Schedule::is_reminder) { priority -= 1; } @@ -411,9 +378,12 @@ impl Todo { } } - #[inline] - pub fn as_string(&self) -> String { - self.into() + #[inline(always)] + fn standardize_priority(priority: u8) -> u8 { + match priority { + 0 => 10, + any => any, + } } } diff --git a/src/todo_app/todo_list.rs b/src/todo_app/todo_list.rs index 57ce941..fb7b02b 100644 --- a/src/todo_app/todo_list.rs +++ b/src/todo_app/todo_list.rs @@ -10,7 +10,7 @@ pub type TodoCmp = fn(&Todo, &Todo) -> cmp::Ordering; #[derive(Debug, Eq, PartialEq, Clone)] pub struct TodoList { pub todos: Vec, - pub(super) changed: bool, + pub changed: bool, pub todo_cmp: TodoCmp, } @@ -161,8 +161,8 @@ impl TodoList { #[inline] fn write_to_buf(&self, writer: &mut BufWriter) -> io::Result<()> { - for todo in &self.todos { - writeln!(writer, "{}", todo.as_string())?; + for todo_string in self.todos.iter().map(String::from) { + writeln!(writer, "{todo_string}")?; } writer.flush()?; Ok(()) diff --git a/src/tui_app.rs b/src/tui_app.rs index 4f9e298..ef5ca11 100644 --- a/src/tui_app.rs +++ b/src/tui_app.rs @@ -99,12 +99,12 @@ impl<'a> TuiApp<'a> { #[inline] pub fn title(&mut self) -> String { - let changed_str = if self.todo_app.is_current_changed() { + let changed_str = if self.todo_app.current_list().changed { "*" } else { "" }; - let size = self.todo_app.len(); + let size = self.todo_app.current_list().len(self.todo_app.restriction()); let todo_string = format!("Todos ({size}){changed_str}"); if self.todo_app.is_root() { @@ -320,7 +320,7 @@ impl<'a> TuiApp<'a> { #[inline] pub fn quit_save_prompt(&mut self) { - if self.todo_app.is_changed() || self.todo_app.is_current_changed() { + if self.todo_app.is_changed() || self.todo_app.current_list().changed { self.set_text_mode( Self::on_save_prompt, "You have done changes. You wanna save? [n: no, y: yes, c: cancel] (default: n)", @@ -488,7 +488,11 @@ impl<'a> TuiApp<'a> { Char('W') => self.todo_app.toggle_current_weekly(), Char('S') => self.schedule_prompt(), Char('m') => self.reminder_prompt(), - Char('M') => self.todo_app.toggle_schedule(), + Char('M') => { + if let Some(todo) = self.todo_app.todo_mut() { + todo.toggle_schedule(); + } + }, Char('!') => self.todo_app.toggle_show_done(), Char('@') => self.priority_prompt(), Char('y') => self.todo_app.yank_todo(), @@ -639,7 +643,8 @@ impl<'a> TuiApp<'a> { let first = self.todo_app.index(); let last = self .todo_app - .len() + .current_list() + .len(self.todo_app.restriction()) .min(todo_layout.height as usize + first - 2); self.todo_app.display_current_slice(first, last) } else { From 4ad6645da14d97c5f52f46a1fb6d4c543637a0fd Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sat, 24 Aug 2024 09:34:41 +0330 Subject: [PATCH 07/22] Refactor and update fmt --- benches/bench_500k.rs | 26 ++++++++------ src/cli_app.rs | 10 +++--- src/lib.rs | 6 ++-- src/main.rs | 8 ++--- src/todo_app.rs | 67 ++++++++++++++++++++--------------- src/todo_app/todo.rs | 10 ++---- src/todo_app/todo/schedule.rs | 10 ++++-- src/tui_app.rs | 31 ++++++++-------- 8 files changed, 89 insertions(+), 79 deletions(-) diff --git a/benches/bench_500k.rs b/benches/bench_500k.rs index 17955ee..ce92ffc 100644 --- a/benches/bench_500k.rs +++ b/benches/bench_500k.rs @@ -1,5 +1,5 @@ -use std::{fs::File, hint::black_box, io::BufWriter, path::PathBuf}; use criterion::{criterion_group, criterion_main, Criterion}; +use std::{fs::File, hint::black_box, io::BufWriter, path::PathBuf}; use c3::{todo_app::App, AppArgs}; @@ -16,10 +16,12 @@ fn reorder(c: &mut Criterion) { todo_path: PathBuf::from("../fuckc3-todo"), ..Default::default() }); - c.bench_function("reorder 500k todos", |b| b.iter(|| { - app.index = 400000; - black_box(&mut app).set_current_priority(1); - })); + c.bench_function("reorder 500k todos", |b| { + b.iter(|| { + app.index = 400000; + black_box(&mut app).set_current_priority(1); + }) + }); } fn display(c: &mut Criterion) { @@ -27,9 +29,11 @@ fn display(c: &mut Criterion) { todo_path: PathBuf::from("../fuckc3-todo"), ..Default::default() }); - c.bench_function("display 500k todos", |b| b.iter(|| { - black_box(&mut app).display_current(); - })); + c.bench_function("display 500k todos", |b| { + b.iter(|| { + black_box(&mut app).display_current(); + }) + }); } fn write_to_stdout(c: &mut Criterion) { @@ -37,9 +41,9 @@ fn write_to_stdout(c: &mut Criterion) { todo_path: PathBuf::from("../fuckc3-todo"), ..Default::default() }); - c.bench_function("write to stdout 500k todos", |b| b.iter(|| { - black_box(&mut app).write_to_stdout() - })); + c.bench_function("write to stdout 500k todos", |b| { + b.iter(|| black_box(&mut app).write_to_stdout()) + }); } criterion_group!(benches, sort, reorder, display, write_to_stdout); diff --git a/src/cli_app.rs b/src/cli_app.rs index 515fe26..10c71f1 100644 --- a/src/cli_app.rs +++ b/src/cli_app.rs @@ -1,15 +1,15 @@ // vim:fileencoding=utf-8:foldmethod=marker // imports {{{ -use c3::todo_app::{App, Restriction, Todo, TodoList}; -use clap_complete::Shell; use crate::Args; -use c3::{DisplayArgs, TodoDisplay, DoOnSelected}; +use c3::todo_app::{App, Restriction, Todo, TodoList}; +use c3::{DisplayArgs, DoOnSelected, TodoDisplay}; +use clap::Parser; use clap::{Command, CommandFactory}; +use clap_complete::Shell; use clap_complete::{generate, Generator}; use std::io; -use std::process; use std::path::PathBuf; -use clap::Parser; +use std::process; // }}} #[derive(Parser, Debug)] diff --git a/src/lib.rs b/src/lib.rs index d110e8f..96b868b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,10 @@ // vim:fileencoding=utf-8:foldmethod=marker // imports {{{ use clap::{Parser, ValueEnum}; -use todo_app::SortMethod; -use std::path::PathBuf; use fileio::get_todo_path; use std::fmt; +use std::path::PathBuf; +use todo_app::SortMethod; pub mod date; pub mod fileio; @@ -17,7 +17,6 @@ pub enum DoOnSelected { Done, } - #[derive(Parser, Debug, Default)] #[command(author, version, about, long_about = None)] pub struct AppArgs { @@ -56,4 +55,3 @@ pub struct DisplayArgs { pub trait TodoDisplay: fmt::Display { fn display_with_args(&self, args: &DisplayArgs) -> String; } - diff --git a/src/main.rs b/src/main.rs index de004bd..95cb865 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,10 @@ // vim:fileencoding=utf-8:foldmethod=marker // imports {{{ -use std::io; use clap::Parser; +use std::io; pub(crate) mod cli_app; pub(crate) mod tui_app; -use c3::{ - todo_app::App, - AppArgs, -}; +use c3::{todo_app::App, AppArgs}; use cli_app::CliArgs; use tui_app::TuiArgs; // }}} @@ -38,4 +35,3 @@ fn main() -> io::Result<()> { Ok(()) } } - diff --git a/src/todo_app.rs b/src/todo_app.rs index e6b01f2..5c2992b 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -33,25 +33,19 @@ pub enum SortMethod { } impl SortMethod { - pub fn cmp_function(&self) -> fn(&Todo, &Todo) -> cmp::Ordering { + pub fn cmp_function(&self) -> fn(&Todo, &Todo) -> cmp::Ordering { match self { - Self::AbandonedFirst => { - |a:&Todo, b:&Todo| { - let order = b - .abandonment_coefficient() - .total_cmp(&a.abandonment_coefficient()); - if order.is_eq() { - a.cmp(b) - } else { - order - } - } - } - Self::Normal => { - |a:&Todo, b:&Todo| { + Self::AbandonedFirst => |a: &Todo, b: &Todo| { + let order = b + .abandonment_coefficient() + .total_cmp(&a.abandonment_coefficient()); + if order.is_eq() { a.cmp(b) + } else { + order } - } + }, + Self::Normal => |a: &Todo, b: &Todo| a.cmp(b), } } } @@ -747,13 +741,19 @@ impl App { pub fn move_current_down(&mut self) { let index = self.index; let restriction = self.restriction.clone(); - let next_priority = self.current_list().index(index+1, &restriction).map(|x|x.priority()); - let current_priority = self.current_list().index(index, &restriction).map(|x|x.priority()); + let next_priority = self + .current_list() + .index(index + 1, &restriction) + .map(|x| x.priority()); + let current_priority = self + .current_list() + .index(index, &restriction) + .map(|x| x.priority()); if current_priority.is_some() && current_priority == next_priority { let list = self.current_list_mut(); list.changed = true; - self.index = list.move_index(index, index+1, 0); - return + self.index = list.move_index(index, index + 1, 0); + return; } if let Some(todo) = self.todo_mut() { todo.decrease_priority(); @@ -764,17 +764,23 @@ impl App { #[inline] pub fn move_current_up(&mut self) { if self.index == 0 { - return + return; } let index = self.index; let restriction = self.restriction.clone(); - let prev_priority = self.current_list().index(index-1, &restriction).map(|x|x.priority()); - let current_priority = self.current_list().index(index, &restriction).map(|x|x.priority()); + let prev_priority = self + .current_list() + .index(index - 1, &restriction) + .map(|x| x.priority()); + let current_priority = self + .current_list() + .index(index, &restriction) + .map(|x| x.priority()); if current_priority.is_some() && current_priority == prev_priority { let list = self.current_list_mut(); list.changed = true; - self.index = list.move_index(index, index-1, 1); - return + self.index = list.move_index(index, index - 1, 1); + return; } if let Some(todo) = self.todo_mut() { todo.increase_priority(); @@ -843,7 +849,7 @@ mod tests { Ok(path) } - fn get_test_app(args: AppArgs) -> io::Result{ + fn get_test_app(args: AppArgs) -> io::Result { let mut app = App::new(args); app.append(String::from("Hello")); app.append(String::from("Goodbye")); @@ -1050,7 +1056,7 @@ mod tests { })?; app.append("a todo".to_string()); if let Some(todo) = app.todo_mut() { - todo.schedule= Some(Schedule::new_reminder(date::current())); + todo.schedule = Some(Schedule::new_reminder(date::current())); todo.set_done(true); } app.index = 0; @@ -1058,7 +1064,12 @@ mod tests { app.toggle_current_daily(); assert!(!app.todo().unwrap().schedule.as_ref().unwrap().is_reminder()); assert_eq!(app.index(), 1); - if let Some(schedule) = app.todo_mut().as_mut().map(|todo| todo.schedule.as_mut()).flatten() { + if let Some(schedule) = app + .todo_mut() + .as_mut() + .map(|todo| todo.schedule.as_mut()) + .flatten() + { schedule.set_current_date(); schedule.add_days_to_date(-2); } diff --git a/src/todo_app/todo.rs b/src/todo_app/todo.rs index f0e0aab..7c6482b 100644 --- a/src/todo_app/todo.rs +++ b/src/todo_app/todo.rs @@ -1,12 +1,6 @@ // vim:fileencoding=utf-8:foldmethod=marker //imports {{{ -use std::{ - fmt, - path::Path, - str::FromStr, - fs, - io, -}; +use std::{fmt, fs, io, path::Path, str::FromStr}; mod dependency; mod note; pub mod schedule; @@ -162,7 +156,7 @@ impl FromStr for Todo { let dependency = dependency_string.parse().ok(); if let Some(schedule) = schedule.as_ref() { - done = schedule.date_should_be_done(); + done = schedule.date_should_be_done(); } Ok(Todo { dependency, diff --git a/src/todo_app/todo/schedule.rs b/src/todo_app/todo/schedule.rs index 03799f3..a651651 100644 --- a/src/todo_app/todo/schedule.rs +++ b/src/todo_app/todo/schedule.rs @@ -77,7 +77,11 @@ impl FromStr for Schedule { Err(_) => None, }; if let Some(mode) = mode { - Ok(Schedule { day, saved_date: date, mode }) + Ok(Schedule { + day, + saved_date: date, + mode, + }) } else { Err(Self::Err {}) } @@ -200,7 +204,9 @@ impl Schedule { pub fn date_should_be_done(&self) -> bool { match self.mode { ScheduleMode::Reminder => self.saved_date != Some(date::current()), - ScheduleMode::Scheduled => self.saved_date.is_some() && self.current_minus_saved_date() < self.day, + ScheduleMode::Scheduled => { + self.saved_date.is_some() && self.current_minus_saved_date() < self.day + } } } } diff --git a/src/tui_app.rs b/src/tui_app.rs index ef5ca11..18664d4 100644 --- a/src/tui_app.rs +++ b/src/tui_app.rs @@ -1,11 +1,5 @@ // vim:fileencoding=utf-8:foldmethod=marker // imports {{{ -use std::{ - io::{self, BufRead, BufReader}, - path::PathBuf, - process::{Command, Stdio}, - rc::Rc, -}; use clap::Parser; use crossterm::{ event::{ @@ -18,11 +12,17 @@ use crossterm::{ ExecutableCommand, }; use ratatui::{prelude::*, widgets::*}; +use std::{ + io::{self, BufRead, BufReader}, + path::PathBuf, + process::{Command, Stdio}, + rc::Rc, +}; use tui_textarea::{CursorMove, Input, TextArea}; mod modules; use c3::{ - todo_app::{App, Restriction, Todo, Schedule}, date, + todo_app::{App, Restriction, Schedule, Todo}, }; use modules::{potato::Potato, Module}; @@ -104,13 +104,16 @@ impl<'a> TuiApp<'a> { } else { "" }; - let size = self.todo_app.current_list().len(self.todo_app.restriction()); + let size = self + .todo_app + .current_list() + .len(self.todo_app.restriction()); let todo_string = format!("Todos ({size}){changed_str}"); - if self.todo_app.is_root() { - todo_string + if let Some(parent) = self.todo_app.parent() { + format!("{todo_string} {}", parent.message) } else { - format!("{todo_string} {}", self.todo_app.parent().unwrap().message) + todo_string } } @@ -492,7 +495,7 @@ impl<'a> TuiApp<'a> { if let Some(todo) = self.todo_app.todo_mut() { todo.toggle_schedule(); } - }, + } Char('!') => self.todo_app.toggle_show_done(), Char('@') => self.priority_prompt(), Char('y') => self.todo_app.yank_todo(), @@ -517,9 +520,7 @@ impl<'a> TuiApp<'a> { KeyCode::Home | Char('g') => { self.todo_app.index = 0; } - KeyCode::End | Char('G') => { - self.todo_app.index = self.todo_app.bottom() - }, + KeyCode::End | Char('G') => self.todo_app.index = self.todo_app.bottom(), Char('w') => self.write()?, Char('J') => self.todo_app.move_current_down(), Char('K') => self.todo_app.move_current_up(), From 37656f723679e7175df0740e708451860d9348fd Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sat, 24 Aug 2024 13:14:05 +0330 Subject: [PATCH 08/22] Refactor code --- benches/bench_500k.rs | 6 +++--- src/cli_app.rs | 2 +- src/todo_app.rs | 7 +------ src/todo_app/todo/dependency.rs | 3 +++ src/todo_app/todo_list.rs | 9 ++++++--- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/benches/bench_500k.rs b/benches/bench_500k.rs index ce92ffc..6fc8188 100644 --- a/benches/bench_500k.rs +++ b/benches/bench_500k.rs @@ -1,5 +1,5 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use std::{fs::File, hint::black_box, io::BufWriter, path::PathBuf}; +use std::{hint::black_box, path::PathBuf}; use c3::{todo_app::App, AppArgs}; @@ -37,12 +37,12 @@ fn display(c: &mut Criterion) { } fn write_to_stdout(c: &mut Criterion) { - let mut app = App::new(AppArgs { + let app = App::new(AppArgs { todo_path: PathBuf::from("../fuckc3-todo"), ..Default::default() }); c.bench_function("write to stdout 500k todos", |b| { - b.iter(|| black_box(&mut app).write_to_stdout()) + b.iter(|| black_box(&app.todo_list).write_to_stdout()) }); } diff --git a/src/cli_app.rs b/src/cli_app.rs index 10c71f1..9dc2af2 100644 --- a/src/cli_app.rs +++ b/src/cli_app.rs @@ -109,7 +109,7 @@ pub fn run(app: &mut App, args: CliArgs) -> Result<(), NotCli> { } if args.stdout { - app.write_to_stdout(); + app.todo_list.write_to_stdout(); return Ok(()); } if args.minimal_tree || args.list { diff --git a/src/todo_app.rs b/src/todo_app.rs index 5c2992b..bbe0bb6 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -823,11 +823,6 @@ impl App { self.traverse_down() } } - - #[inline] - pub fn write_to_stdout(&self) -> io::Result<()> { - self.todo_list.write_to_stdout() - } } #[cfg(test)] @@ -1074,7 +1069,7 @@ mod tests { schedule.add_days_to_date(-2); } app.reorder_current(); - app.write_to_stdout(); + app.todo_list.write_to_stdout(); assert_eq!(app.index(), 0); Ok(()) diff --git a/src/todo_app/todo/dependency.rs b/src/todo_app/todo/dependency.rs index d6f9ffe..671417b 100644 --- a/src/todo_app/todo/dependency.rs +++ b/src/todo_app/todo/dependency.rs @@ -1,3 +1,5 @@ +// vim:fileencoding=utf-8:foldmethod=marker +// imports {{{ use crate::todo_app::todo_list::TodoCmp; use super::Todo; @@ -8,6 +10,7 @@ use std::{ io::{self, Write}, path::Path, }; +//}}} #[derive(Debug, Eq, PartialEq, Clone, Default)] enum DependencyMode { diff --git a/src/todo_app/todo_list.rs b/src/todo_app/todo_list.rs index fb7b02b..27ad650 100644 --- a/src/todo_app/todo_list.rs +++ b/src/todo_app/todo_list.rs @@ -1,10 +1,13 @@ +// vim:fileencoding=utf-8:foldmethod=marker +// imports {{{ +use std::cmp; use std::fs::{read, File}; -use std::io::{stdout, BufRead, BufWriter, Write}; +use std::io::{self, BufRead, BufWriter, Write}; use std::path::Path; -use std::{cmp, io}; use super::{App, Restriction, SortMethod, Todo}; use crate::{DisplayArgs, TodoDisplay}; +//}}} pub type TodoCmp = fn(&Todo, &Todo) -> cmp::Ordering; #[derive(Debug, Eq, PartialEq, Clone)] @@ -96,7 +99,7 @@ impl TodoList { #[inline] pub fn write_to_stdout(&self) -> io::Result<()> { - let mut stdout_writer = BufWriter::new(stdout()); + let mut stdout_writer = BufWriter::new(io::stdout()); self.write_to_buf(&mut stdout_writer)?; Ok(()) } From 25e41a9b933a8582cbb1a5b81d699dfa65e0fa09 Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sat, 24 Aug 2024 14:31:37 +0330 Subject: [PATCH 09/22] Refactor code --- benches/bench_500k.rs | 2 +- src/cli_app.rs | 2 +- src/todo_app.rs | 17 +++----- src/todo_app/todo.rs | 38 ++++++++--------- src/todo_app/todo/dependency.rs | 72 ++++++++++++++------------------- src/tui_app.rs | 10 +++-- 6 files changed, 61 insertions(+), 80 deletions(-) diff --git a/benches/bench_500k.rs b/benches/bench_500k.rs index 6fc8188..9823e22 100644 --- a/benches/bench_500k.rs +++ b/benches/bench_500k.rs @@ -31,7 +31,7 @@ fn display(c: &mut Criterion) { }); c.bench_function("display 500k todos", |b| { b.iter(|| { - black_box(&mut app).display_current(); + black_box(&mut app).display_current_list(); }) }); } diff --git a/src/cli_app.rs b/src/cli_app.rs index 9dc2af2..339a59d 100644 --- a/src/cli_app.rs +++ b/src/cli_app.rs @@ -133,7 +133,7 @@ fn print_completions(gen: G, cmd: &mut Command) { } fn print_todos(app: &App) { - for display in app.display_current() { + for display in app.display_current_list() { println!("{}", display); } } diff --git a/src/todo_app.rs b/src/todo_app.rs index bbe0bb6..913a72e 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -266,7 +266,7 @@ impl App { let todo = &mut todolist.todos[index]; if line.priority != todo.priority() || line.message != todo.message { changed = true; - todo.set_message(line.message); + todo.message = line.message; todo.set_priority(line.priority); } } else { @@ -667,11 +667,6 @@ impl App { } } - #[inline] - pub fn get_cloned_current_message(&mut self) -> Option { - self.todo().map(|todo| todo.message.clone()) - } - #[inline] pub fn todo(&self) -> Option<&Todo> { self.current_list().index(self.index, &self.restriction) @@ -693,9 +688,9 @@ impl App { } } - #[inline] - pub fn display_current(&self) -> Vec { - self.display_list(self.current_list()) + #[inline(always)] + pub fn display_current_list(&self) -> Vec { + self.display_a_list(self.current_list()) } #[inline] @@ -704,8 +699,8 @@ impl App { .display_slice(&self.args.display_args, &self.restriction, min, max) } - #[inline] - pub fn display_list(&self, todo_list: &TodoList) -> Vec { + #[inline(always)] + pub fn display_a_list(&self, todo_list: &TodoList) -> Vec { todo_list.display(&self.args.display_args, &self.restriction) } diff --git a/src/todo_app/todo.rs b/src/todo_app/todo.rs index 7c6482b..0f859a2 100644 --- a/src/todo_app/todo.rs +++ b/src/todo_app/todo.rs @@ -173,6 +173,15 @@ impl FromStr for Todo { } impl Todo { + #[inline] + pub fn new(message: String, priority: u8) -> Self { + Todo { + message, + priority: Self::fixed_priority(priority), + ..Default::default() + } + } + #[inline] pub fn matches(&self, query: &str) -> bool { self.message.contains(query) || self.message.to_lowercase().contains(query) @@ -182,23 +191,15 @@ impl Todo { pub fn priority(&self) -> u8 { self.priority } - #[inline] - pub fn new(message: String, priority: u8) -> Self { - Todo { - message, - priority: Self::fixed_priority(priority), - ..Default::default() - } - } pub fn toggle_schedule(&mut self) -> bool { if self.schedule.is_none() && self.last_schedule.is_none() { return false; } - if self.schedule.is_some() { - self.last_schedule = std::mem::take(&mut self.schedule); + if let Some(schedule) = self.schedule.take() { + self.last_schedule = Some(schedule); } else { - self.schedule = std::mem::take(&mut self.last_schedule); + self.schedule = self.last_schedule.take(); } true } @@ -228,7 +229,7 @@ impl Todo { pub fn delete_dependency_file(&mut self, path: &Path) -> io::Result<()> { if let Some(dependency) = &mut self.dependency { dependency.todo_list.remove_dependency_files(path)?; - let _ = fs::remove_file(path.join(dependency.get_name())); + let _ = fs::remove_file(path.join(dependency.name())); } Ok(()) } @@ -237,7 +238,7 @@ impl Todo { pub fn delete_removed_dependent_files(&mut self, path: &Path) -> io::Result<()> { if let Some(dependency) = &mut self.removed_dependency { let _ = dependency.todo_list.remove_dependency_files(path); - let _ = fs::remove_file(path.join(dependency.get_name())); + let _ = fs::remove_file(path.join(dependency.name())); } Ok(()) } @@ -275,11 +276,6 @@ impl Todo { } } - #[inline] - pub fn set_message(&mut self, message: String) { - self.message = message; - } - #[inline] pub fn hash(&self) -> String { sha1(&format!("{} {}", self.priority, self.message)) @@ -437,7 +433,7 @@ mod tests { let expected = "900a80c94f076b4ee7006a9747667ccf6878a72b.todo"; todo.add_todo_dependency(); - let result = todo.dependency.unwrap().get_name().to_string(); + let result = todo.dependency.unwrap().name().to_string(); assert_eq!(result, expected); } @@ -455,7 +451,7 @@ mod tests { let expected = "900a80c94f076b4ee7006a9747667ccf6878a72b.todo"; todo.add_todo_dependency(); - let result = todo.dependency.unwrap().get_name().to_string(); + let result = todo.dependency.unwrap().name().to_string(); assert_eq!(result, expected); } @@ -475,7 +471,7 @@ mod tests { .expect("Error setting note"); assert_eq!( - todo.dependency.unwrap().get_name(), + todo.dependency.unwrap().name(), "2c924e3088204ee77ba681f72be3444357932fca" ); } diff --git a/src/todo_app/todo/dependency.rs b/src/todo_app/todo/dependency.rs index 671417b..dbd6e84 100644 --- a/src/todo_app/todo/dependency.rs +++ b/src/todo_app/todo/dependency.rs @@ -29,6 +29,25 @@ pub struct Dependency { } impl Dependency { + #[inline] + pub fn new_todo_list(hash: String) -> Self { + Self { + name: format!("{}.todo", hash), + mode: DependencyMode::TodoList, + ..Default::default() + } + } + + #[inline] + pub fn new_note(hash: String, note: String) -> Self { + Self { + note, + name: hash, + mode: DependencyMode::Note, + ..Default::default() + } + } + #[inline] pub fn is_written(&self) -> bool { self.written @@ -36,15 +55,17 @@ impl Dependency { #[inline] pub fn note(&self) -> Option<&str> { - if self.is_note() { - Some(&self.note) - } else { - None - } + self.is_note().then_some(&self.note) } #[inline] - pub fn get_name(&self) -> &str { + pub fn todo_list(&self) -> Option<&TodoList> { + self.is_list().then_some(&self.todo_list) + } + + + #[inline] + pub fn name(&self) -> &str { &self.name } @@ -56,25 +77,6 @@ impl Dependency { } } - #[inline] - pub fn new_todo_list(hash: String) -> Self { - Self { - name: format!("{}.todo", hash), - mode: DependencyMode::TodoList, - ..Default::default() - } - } - - #[inline] - pub fn new_note(hash: String, note: String) -> Self { - Self { - note, - name: hash, - mode: DependencyMode::Note, - ..Default::default() - } - } - #[inline] pub fn read(&mut self, path: &Path, todo_cmp: TodoCmp) -> io::Result<()> { let file_path = path.join(&self.name); @@ -105,15 +107,6 @@ impl Dependency { Ok(()) } - #[inline] - pub fn todo_list(&self) -> Option<&TodoList> { - if self.mode == DependencyMode::TodoList { - Some(&self.todo_list) - } else { - None - } - } - #[inline] pub fn todo_list_mut(&mut self) -> Option<&mut TodoList> { if self.mode == DependencyMode::TodoList { @@ -138,7 +131,7 @@ impl Dependency { Ok(()) } - #[inline] + #[inline(always)] fn write_note(&self, path: &Path) -> io::Result<()> { let mut file = File::create(path.join(&self.name))?; write!(file, "{}", self.note)?; @@ -158,12 +151,12 @@ impl Dependency { Ok(()) } - #[inline] + #[inline(always)] pub fn is_note(&self) -> bool { self.mode == DependencyMode::Note } - #[inline] + #[inline(always)] pub fn is_list(&self) -> bool { self.mode == DependencyMode::TodoList } @@ -175,11 +168,6 @@ impl Dependency { DependencyMode::TodoList => "-", } } - - #[inline] - pub fn remove(&mut self) { - *self = Self::default(); - } } impl From<&Dependency> for String { diff --git a/src/tui_app.rs b/src/tui_app.rs index 18664d4..e71d5cd 100644 --- a/src/tui_app.rs +++ b/src/tui_app.rs @@ -288,7 +288,7 @@ impl<'a> TuiApp<'a> { #[inline] pub fn edit_prompt(&mut self, start: bool) { - if let Some(message) = &self.todo_app.get_cloned_current_message() { + if let Some(message) = &self.todo_app.todo().map(|todo| todo.message.clone()) { self.set_text_mode(Self::on_edit_todo, "Edit todo", message); self.textarea.insert_str(message); if start { @@ -370,7 +370,9 @@ impl<'a> TuiApp<'a> { #[inline] fn on_edit_todo(&mut self, str: String) { if !str.is_empty() { - self.todo_app.todo_mut().unwrap().set_message(str); + if let Some(todo) = self.todo_app.todo_mut() { + todo.message = str; + } } } @@ -625,7 +627,7 @@ impl<'a> TuiApp<'a> { frame, None, dependency_layout, - self.todo_app.display_list(todo_list), + self.todo_app.display_a_list(todo_list), String::from("Todo dependencies"), ) } @@ -649,7 +651,7 @@ impl<'a> TuiApp<'a> { .min(todo_layout.height as usize + first - 2); self.todo_app.display_current_slice(first, last) } else { - self.todo_app.display_current() + self.todo_app.display_current_list() }; Self::render_todos_widget( self.highlight_string(), From f3312c24dc5d8edccb2e3c6b5627144250f644da Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sun, 25 Aug 2024 08:58:43 +0330 Subject: [PATCH 10/22] Display only the shown todos in the dependency list Using display_a_slice method of App only 0 to height - 2 --- src/todo_app.rs | 13 ++++--------- src/tui_app.rs | 4 ++-- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/todo_app.rs b/src/todo_app.rs index 913a72e..57e5263 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -690,20 +690,15 @@ impl App { #[inline(always)] pub fn display_current_list(&self) -> Vec { - self.display_a_list(self.current_list()) - } - - #[inline] - pub fn display_current_slice(&self, min: usize, max: usize) -> Vec { - self.current_list() - .display_slice(&self.args.display_args, &self.restriction, min, max) + self.current_list().display(&self.args.display_args, &self.restriction) } #[inline(always)] - pub fn display_a_list(&self, todo_list: &TodoList) -> Vec { - todo_list.display(&self.args.display_args, &self.restriction) + pub fn display_a_slice(&self, todo_list: &TodoList, min: usize, max: usize) -> Vec { + todo_list.display_slice(&self.args.display_args, &self.restriction, min, max) } + #[inline] pub fn remove_current_dependent(&mut self) { if let Some(todo) = self.todo_mut() { diff --git a/src/tui_app.rs b/src/tui_app.rs index e71d5cd..c0f37a1 100644 --- a/src/tui_app.rs +++ b/src/tui_app.rs @@ -627,7 +627,7 @@ impl<'a> TuiApp<'a> { frame, None, dependency_layout, - self.todo_app.display_a_list(todo_list), + self.todo_app.display_a_slice(todo_list, 0, dependency_layout.height as usize - 2), String::from("Todo dependencies"), ) } @@ -649,7 +649,7 @@ impl<'a> TuiApp<'a> { .current_list() .len(self.todo_app.restriction()) .min(todo_layout.height as usize + first - 2); - self.todo_app.display_current_slice(first, last) + self.todo_app.display_a_slice(self.todo_app.current_list(), first, last) } else { self.todo_app.display_current_list() }; From e3f943d88c724aa3a501d46b05aea6ce572c8e7f Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sun, 25 Aug 2024 09:23:09 +0330 Subject: [PATCH 11/22] Refactor modules --- src/tui_app.rs | 24 +++--- src/tui_app/modules.rs | 17 ---- src/tui_app/modules/mpc.rs | 128 ---------------------------- src/tui_app/{modules => }/potato.rs | 86 ++++--------------- 4 files changed, 30 insertions(+), 225 deletions(-) delete mode 100644 src/tui_app/modules.rs delete mode 100644 src/tui_app/modules/mpc.rs rename src/tui_app/{modules => }/potato.rs (70%) diff --git a/src/tui_app.rs b/src/tui_app.rs index c0f37a1..b926ed3 100644 --- a/src/tui_app.rs +++ b/src/tui_app.rs @@ -19,13 +19,13 @@ use std::{ rc::Rc, }; use tui_textarea::{CursorMove, Input, TextArea}; -mod modules; +mod potato; use c3::{ date, todo_app::{App, Restriction, Schedule, Todo}, }; -use modules::{potato::Potato, Module}; +use potato::Potato; // }}} #[derive(Debug)] @@ -557,16 +557,16 @@ impl<'a> TuiApp<'a> { self.todo_app.set_current_priority(priority as u8); } - Char('s') => self.potato_module.on_s(), - Char('H') => self.potato_module.on_capital_h(), - Char('c') => self.potato_module.on_c(), - Char('C') => self.potato_module.on_capital_c(), - Char('L') => self.potato_module.on_capital_l(), - Char('f') => self.potato_module.on_f(), - Char('+') | Char('=') => self.potato_module.on_plus(), - Char('-') => self.potato_module.on_minus(), - Char('.') => self.potato_module.on_dot(), - Char(',') => self.potato_module.on_comma(), + Char('s') => self.potato_module.skip(), + Char('H') => self.potato_module.increase_timer(), + Char('c') => self.potato_module.toggle_pause(), + Char('C') => self.potato_module.quit(), + Char('L') => self.potato_module.decrease_timer(), + Char('f') => self.potato_module.restart(), + Char('+') | Char('=') => self.potato_module.increase_pomodoro(), + Char('-') => self.potato_module.decrease_pomodoro(), + Char('.') => self.potato_module.next(), + Char(',') => self.potato_module.prev(), _ => {} } } diff --git a/src/tui_app/modules.rs b/src/tui_app/modules.rs deleted file mode 100644 index 29c98c9..0000000 --- a/src/tui_app/modules.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub mod potato; -use ratatui::widgets::Paragraph; - -pub trait Module { - fn update_time_ms(&self) -> u64; - fn get_widget(&self) -> Paragraph<'_>; - fn on_capital_c(&mut self); - fn on_s(&mut self); - fn on_capital_h(&mut self); - fn on_capital_l(&mut self); - fn on_f(&mut self); - fn on_minus(&mut self); - fn on_plus(&mut self); - fn on_dot(&mut self); - fn on_comma(&mut self); - fn on_c(&mut self); -} diff --git a/src/tui_app/modules/mpc.rs b/src/tui_app/modules/mpc.rs deleted file mode 100644 index ddb13ad..0000000 --- a/src/tui_app/modules/mpc.rs +++ /dev/null @@ -1,128 +0,0 @@ -use ratatui::widgets::Paragraph; -use std::io; -use std::process::{Command, Output}; -use crate::tui::modules::Module; -use crate::tui::default_block; - -pub struct MusicPlayerClient<'a>{ - command: &'a str, -} - -impl <'a> Module <'a> for MusicPlayerClient <'a> { - #[inline] - fn get_widget(&self) -> Paragraph<'a> { - let str = match self.output(vec![]) { - Ok(output) => String::from_utf8(output.stdout).unwrap(), - Err(_) => String::from("mpc command not found at path.") - }; - - Paragraph::new(str).block(default_block("MPC")) - } - - #[inline] - fn update_time_ms(&self) -> u64 { - 500 - } - - #[inline] - fn on_c(&mut self) { - self.toggle_pause() - } - - #[inline] - fn on_space(&mut self) { - self.toggle_pause() - } - - #[inline] - fn on_s(&mut self) { - self.stop(); - } - - #[inline] - fn on_capital_h(&mut self) { - self.seek_backward() - } - - #[inline] - fn on_capital_l(&mut self) { - self.seek_forward() - } - - #[inline] - fn on_r(&mut self) { - } - - #[inline] - fn on_plus(&mut self) { - self.vol_up(); - } - - #[inline] - fn on_minus(&mut self) { - self.vol_down(); - } - - #[inline] - fn on_dot(&mut self) { - self.next(); - } - - #[inline] - fn on_comma(&mut self) { - self.prev(); - } -} - -impl<'a> MusicPlayerClient<'a> { - #[inline] - pub fn new(command_name: Option<&'a str>) -> Self { - let command = match command_name { - Some(str) => str, - None => "mpc", - }; - Self { command } - } - - #[inline] - fn run(&self, args:Vec<&str>) { - let _ = Command::new(self.command).args(args).status(); - } - - #[inline] - fn output(&self, args:Vec<&str>) -> io::Result{ - Command::new(self.command).args(args).output() - } - - pub fn next(&self) { - self.output(vec!["next"]); - } - - pub fn prev(&self) { - self.output(vec!["prev"]); - } - - pub fn stop(&self) { - self.output(vec!["stop"]); - } - - pub fn seek_forward(&self) { - self.output(vec!["seek", "+5"]); - } - - pub fn seek_backward(&self) { - self.output(vec!["seek", "-5"]); - } - - pub fn toggle_pause(&self) { - self.output(vec!["toggle"]); - } - - pub fn vol_up(&self) { - self.output(vec!["volume", "+1"]); - } - - pub fn vol_down(&self) { - self.output(vec!["volume", "-1"]); - } -} diff --git a/src/tui_app/modules/potato.rs b/src/tui_app/potato.rs similarity index 70% rename from src/tui_app/modules/potato.rs rename to src/tui_app/potato.rs index afbeb04..8e82ba0 100644 --- a/src/tui_app/modules/potato.rs +++ b/src/tui_app/potato.rs @@ -1,8 +1,10 @@ -use super::super::default_block; -use super::Module; +// vim:fileencoding=utf-8:foldmethod=marker +// imports {{{ use ratatui::widgets::Paragraph; +use super::default_block; use std::io; use std::process::{Command, Output}; +//}}} #[derive(Default)] pub struct Potato { @@ -33,6 +35,18 @@ impl Potato { format!("-{arg}{}", self.index) } + #[inline] + pub fn get_widget(&self) -> Paragraph { + let args = vec!["+%m\n%t\n%p".to_string(), self.resolve_arg("1")]; + + let time_str = match self.output(args) { + Ok(output) => String::from_utf8(output.stdout).unwrap(), + Err(_) => String::from("potctl command not found at path."), + }; + + Paragraph::new(time_str).block(default_block("Potato")) + } + #[inline] pub fn decrease_timer(&self) { self.run(vec![self.resolve_arg("d")]) @@ -90,73 +104,9 @@ impl Potato { pub fn quit(&mut self) { self.run(vec![self.resolve_arg("q")]) } -} -impl Module for Potato { - #[inline] - fn get_widget(&self) -> Paragraph { - let args = vec!["+%m\n%t\n%p".to_string(), self.resolve_arg("1")]; - - let time_str = match self.output(args) { - Ok(output) => String::from_utf8(output.stdout).unwrap(), - Err(_) => String::from("potctl command not found at path."), - }; - - Paragraph::new(time_str).block(default_block("Potato")) - } - - #[inline] - fn update_time_ms(&self) -> u64 { + #[inline(always)] + pub fn update_time_ms(&self) -> u64 { 500 } - - #[inline] - fn on_c(&mut self) { - self.toggle_pause() - } - - #[inline] - fn on_capital_c(&mut self) { - self.quit() - } - - #[inline] - fn on_s(&mut self) { - self.skip(); - } - - #[inline] - fn on_capital_h(&mut self) { - self.increase_timer() - } - - #[inline] - fn on_capital_l(&mut self) { - self.decrease_timer() - } - - #[inline] - fn on_f(&mut self) { - self.restart() - } - - #[inline] - fn on_plus(&mut self) { - self.increase_pomodoro(); - } - - #[inline] - fn on_minus(&mut self) { - self.decrease_pomodoro(); - } - - #[inline] - fn on_dot(&mut self) { - self.next(); - } - - #[inline] - fn on_comma(&mut self) { - self.prev(); - } } From 4f192951cf0f1ef624ccf2aad1edeaa268f18a73 Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sun, 25 Aug 2024 09:56:13 +0330 Subject: [PATCH 12/22] Update README.md --- README.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ea80c30..317e577 100644 --- a/README.md +++ b/README.md @@ -80,11 +80,20 @@ The default mode of the app is TUI mode. Keybinds are vim-like. Here they are: | Ctrl+d | sort by todo's abandonment (how hasn't been done compared to their schedule) | | w | write changes to file | | R | read from file (discard changes)| -#### Modules -TUI mode has a section called module. You can develop modules, and assign methods to Module trait methods. -A very simple example has been done by default for [potato-c](https://github.com/nimaaskarian/potato-c). -Keybinds that modules can use are **C, c, H, L, comma, period, +, -, s, r** +#### [potato-c](https://github.com/nimaaskarian/potato-c) module keybinds +| key | action | +|---|---| +| s | skip current | +| H | increase timer | +| L | decrease timer | +| +,= | increase pomodoro count | +| - | decrease pomodoro count | +| c | toggle pause | +| C | quit | +| f | restart | +| . | next server | +| , | prev server | ### Non interactive mode For command line arguments and such, run `c3 -h` to see full usage. From e05de01e9a0990eabba171e2678af540dfd253ba Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sun, 25 Aug 2024 10:08:02 +0330 Subject: [PATCH 13/22] Fix index after cuting a todo --- src/todo_app.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/todo_app.rs b/src/todo_app.rs index 57e5263..1e4ec4c 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -521,6 +521,7 @@ impl App { let todo = self.current_list_mut().remove(index, &restriction); let todo_string: String = (&todo).into(); self.clipboard.set_text(todo_string); + self.fix_index() } } From 10cd21a54aad0e27dc176cafb79bcceeef16ac7f Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sun, 25 Aug 2024 10:12:51 +0330 Subject: [PATCH 14/22] Remove mouse scroll support --- src/tui_app.rs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/tui_app.rs b/src/tui_app.rs index b926ed3..ed5c48c 100644 --- a/src/tui_app.rs +++ b/src/tui_app.rs @@ -470,17 +470,6 @@ impl<'a> TuiApp<'a> { #[inline] fn handle_normal_input(&mut self) -> io::Result { let event = event::read()?; - if let event::Event::Mouse(mouse) = event { - match mouse.kind { - event::MouseEventKind::ScrollUp => { - self.todo_app.go_up(); - } - event::MouseEventKind::ScrollDown => { - self.todo_app.go_down(); - } - _ => {} - } - } if let Key(key) = event { if key.kind == event::KeyEventKind::Press { match key.code { @@ -766,8 +755,7 @@ pub fn shutdown() -> io::Result<()> { disable_raw_mode()?; io::stdout() .execute(LeaveAlternateScreen)? - .execute(crossterm::cursor::Show)? - .execute(crossterm::event::DisableMouseCapture)?; + .execute(crossterm::cursor::Show)?; Ok(()) } @@ -775,8 +763,7 @@ pub fn startup() -> io::Result<()> { enable_raw_mode()?; io::stdout() .execute(EnterAlternateScreen)? - .execute(crossterm::cursor::Hide)? - .execute(crossterm::event::EnableMouseCapture)?; + .execute(crossterm::cursor::Hide)?; Ok(()) } From ec08f88e3b8b6ac38cbf5d04737e50c68c44dd6c Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Fri, 30 Aug 2024 22:39:32 +0330 Subject: [PATCH 15/22] Add aliases for ValueEnum options Minor improvements --- src/lib.rs | 2 ++ src/todo_app.rs | 2 ++ src/tui_app.rs | 27 ++++++++++++++------------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 96b868b..56a3c9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,9 @@ pub mod todo_app; #[derive(ValueEnum, Clone, Debug)] pub enum DoOnSelected { + #[value(alias="del")] Delete, + #[value(alias="do")] Done, } diff --git a/src/todo_app.rs b/src/todo_app.rs index 1e4ec4c..39f9504 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -28,7 +28,9 @@ struct SearchPosition { #[derive(ValueEnum, Clone, Debug, PartialEq, Default)] pub enum SortMethod { #[default] + #[value(alias = "n")] Normal, + #[value(alias = "a", alias = "abandoned")] AbandonedFirst, } diff --git a/src/tui_app.rs b/src/tui_app.rs index ed5c48c..98f96d5 100644 --- a/src/tui_app.rs +++ b/src/tui_app.rs @@ -564,15 +564,10 @@ impl<'a> TuiApp<'a> { } #[inline] - fn get_dependency_width(&self, todo: Option<&Todo>) -> u16 { - if let Some(todo) = todo { - if !self.show_right || todo.dependency.is_none() || !self.todo_app.is_tree() { - return 0; - } - 40 - } else { - 0 - } + fn is_dependency_enabled(&self, todo: Option<&Todo>) -> bool { + todo.map_or(false, |todo| { + self.show_right && todo.dependency.is_some() && self.todo_app.is_tree() + }) } #[inline] @@ -680,7 +675,8 @@ impl<'a> TuiApp<'a> { list_state.select(Some(self.todo_app.index())); } - let dependency_width = self.get_dependency_width(todo); + let dependency_enabled = self.is_dependency_enabled(todo); + let dependency_width = if dependency_enabled { 40 } else { 0 }; let main_layout = if self.args.enable_module { self.render_module_widget( @@ -703,17 +699,22 @@ impl<'a> TuiApp<'a> { Constraint::Percentage(dependency_width), ]) .split(main_layout[self.args.enable_module as usize]); + let is_editing = self.mode == Mode::Editing; let todo_and_textarea_layout = Layout::default() .direction(Direction::Vertical) .constraints([ - Constraint::Length(3 * (self.mode == Mode::Editing) as u16), + Constraint::Length(3 * is_editing as u16), Constraint::Min(0), ]) .split(todo_app_layout[0]); - self.render_dependency_widget(frame, todo, todo_app_layout[1]); + if dependency_enabled { + self.render_dependency_widget(frame, todo, todo_app_layout[1]); + } - frame.render_widget(self.textarea.widget(), todo_and_textarea_layout[0]); + if is_editing { + frame.render_widget(self.textarea.widget(), todo_and_textarea_layout[0]); + } self.render_current_todos_widget(frame, list_state, todo_and_textarea_layout[1]); } } From 74be3269d30ce633c4e926547d33108c8091ca0f Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Mon, 2 Sep 2024 08:35:09 +0330 Subject: [PATCH 16/22] Improve batch edit speed --- src/todo_app.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/todo_app.rs b/src/todo_app.rs index 39f9504..4f376b6 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -233,7 +233,7 @@ impl App { let content = String::from("# INDEX PRIORITY MESSAGE\n") + self .current_list() - .filter(&self.restriction) + .iter() .enumerate() .map(|(i, x)| format!("{i: <7} {: <8} {}", x.priority(), x.message)) .collect::>() @@ -247,30 +247,29 @@ impl App { #[inline(always)] fn batch_edit_current_list(&mut self, messages: Lines<'_>) { - let restriction = self.restriction.clone(); + let todolist = self.current_list_mut(); + let mut delete_indices: Vec = vec![]; + let mut changed = false; let mut lines: Vec = messages .filter(|message| !message.starts_with('#')) - .flat_map(|message| message.parse()) + .flat_map(|message| message.parse::()) .collect(); - lines.sort_by_key(|a| a.index); - let todolist = self.current_list_mut(); - let size = todolist.len(&restriction); - let indices: Vec = lines.iter().filter_map(|x| x.index).collect(); - let delete_indices: Vec = (0..size) - .filter(|i| indices.binary_search(i).is_err()) - .collect(); - let mut changed = !delete_indices.is_empty(); + let mut last_index = 0; for line in lines { if let Some(index) = line.index { - let index = todolist.true_position_in_list(index, &restriction); let todo = &mut todolist.todos[index]; if line.priority != todo.priority() || line.message != todo.message { changed = true; todo.message = line.message; todo.set_priority(line.priority); } + for i in last_index..index { + delete_indices.push(i); + changed = true; + } + last_index = index+1; } else { todolist.push(Todo::new(line.message, line.priority)); } From c36c8f5bdf6bdb37247a968feffb49e7ffc5ea9f Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Mon, 2 Sep 2024 08:53:47 +0330 Subject: [PATCH 17/22] Add batch edit benchmark --- benches/bench_500k.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/benches/bench_500k.rs b/benches/bench_500k.rs index 9823e22..bbaab03 100644 --- a/benches/bench_500k.rs +++ b/benches/bench_500k.rs @@ -1,5 +1,5 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use std::{hint::black_box, path::PathBuf}; +use std::{env, hint::black_box, path::PathBuf}; use c3::{todo_app::App, AppArgs}; @@ -46,5 +46,16 @@ fn write_to_stdout(c: &mut Criterion) { }); } -criterion_group!(benches, sort, reorder, display, write_to_stdout); +fn batch_edit(c: &mut Criterion) { + let mut app = App::new(AppArgs { + todo_path: PathBuf::from("../fuckc3-todo"), + ..Default::default() + }); + env::set_var("EDITOR", "cat"); + c.bench_function("batch edit 500k todos", |b| { + b.iter(|| black_box(&mut app).batch_editor_messages()) + }); +} + +criterion_group!(benches, sort, reorder, display, write_to_stdout, batch_edit); criterion_main!(benches); From c060298b295d8f0cad41dc82c1ad775319553837 Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Wed, 4 Sep 2024 16:29:53 +0330 Subject: [PATCH 18/22] Replace clipboard with a todo buffer Refactor delete_todo and cut_todo --- patches/clipboard-patch.diff | 600 ----------------------------------- src/todo_app.rs | 45 ++- src/todo_app/clipboard.rs | 20 -- src/tui_app.rs | 46 ++- 4 files changed, 37 insertions(+), 674 deletions(-) delete mode 100644 patches/clipboard-patch.diff delete mode 100644 src/todo_app/clipboard.rs diff --git a/patches/clipboard-patch.diff b/patches/clipboard-patch.diff deleted file mode 100644 index 0dfbf61..0000000 --- a/patches/clipboard-patch.diff +++ /dev/null @@ -1,600 +0,0 @@ -diff --git a/Cargo.lock b/Cargo.lock -index 12df265..c369f7b 100644 ---- a/Cargo.lock -+++ b/Cargo.lock -@@ -2,6 +2,12 @@ - # It is not intended for manual editing. - version = 3 - -+[[package]] -+name = "adler" -+version = "1.0.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -+ - [[package]] - name = "ahash" - version = "0.8.7" -@@ -83,6 +89,24 @@ dependencies = [ - "windows-sys 0.52.0", - ] - -+[[package]] -+name = "arboard" -+version = "3.4.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" -+dependencies = [ -+ "clipboard-win", -+ "core-graphics", -+ "image", -+ "log", -+ "objc2", -+ "objc2-app-kit", -+ "objc2-foundation", -+ "parking_lot", -+ "windows-sys 0.48.0", -+ "x11rb", -+] -+ - [[package]] - name = "autocfg" - version = "1.1.0" -@@ -97,9 +121,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - - [[package]] - name = "bitflags" --version = "2.4.1" -+version = "2.6.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" -+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - - [[package]] - name = "block-buffer" -@@ -110,16 +134,38 @@ dependencies = [ - "generic-array", - ] - -+[[package]] -+name = "block2" -+version = "0.5.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" -+dependencies = [ -+ "objc2", -+] -+ - [[package]] - name = "bumpalo" - version = "3.14.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -+[[package]] -+name = "bytemuck" -+version = "1.16.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" -+ -+[[package]] -+name = "byteorder-lite" -+version = "0.1.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" -+ - [[package]] - name = "c3" - version = "1.2.1" - dependencies = [ -+ "arboard", - "chrono", - "clap", - "clap_complete", -@@ -214,18 +260,61 @@ version = "0.7.1" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" - -+[[package]] -+name = "clipboard-win" -+version = "5.4.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" -+dependencies = [ -+ "error-code", -+] -+ - [[package]] - name = "colorchoice" - version = "1.0.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -+[[package]] -+name = "core-foundation" -+version = "0.9.4" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -+dependencies = [ -+ "core-foundation-sys", -+ "libc", -+] -+ - [[package]] - name = "core-foundation-sys" - version = "0.8.6" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -+[[package]] -+name = "core-graphics" -+version = "0.23.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" -+dependencies = [ -+ "bitflags 1.3.2", -+ "core-foundation", -+ "core-graphics-types", -+ "foreign-types", -+ "libc", -+] -+ -+[[package]] -+name = "core-graphics-types" -+version = "0.1.3" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -+dependencies = [ -+ "bitflags 1.3.2", -+ "core-foundation", -+ "libc", -+] -+ - [[package]] - name = "cpufeatures" - version = "0.2.11" -@@ -235,13 +324,22 @@ dependencies = [ - "libc", - ] - -+[[package]] -+name = "crc32fast" -+version = "1.4.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -+dependencies = [ -+ "cfg-if", -+] -+ - [[package]] - name = "crossterm" - version = "0.27.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" - dependencies = [ -- "bitflags 2.4.1", -+ "bitflags 2.6.0", - "crossterm_winapi", - "libc", - "mio", -@@ -286,6 +384,68 @@ version = "1.9.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -+[[package]] -+name = "errno" -+version = "0.3.9" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -+dependencies = [ -+ "libc", -+ "windows-sys 0.52.0", -+] -+ -+[[package]] -+name = "error-code" -+version = "3.2.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" -+ -+[[package]] -+name = "fdeflate" -+version = "0.3.4" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" -+dependencies = [ -+ "simd-adler32", -+] -+ -+[[package]] -+name = "flate2" -+version = "1.0.30" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" -+dependencies = [ -+ "crc32fast", -+ "miniz_oxide", -+] -+ -+[[package]] -+name = "foreign-types" -+version = "0.5.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -+dependencies = [ -+ "foreign-types-macros", -+ "foreign-types-shared", -+] -+ -+[[package]] -+name = "foreign-types-macros" -+version = "0.2.3" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -+dependencies = [ -+ "proc-macro2", -+ "quote", -+ "syn 2.0.43", -+] -+ -+[[package]] -+name = "foreign-types-shared" -+version = "0.3.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" -+ - [[package]] - name = "generic-array" - version = "0.14.7" -@@ -296,6 +456,16 @@ dependencies = [ - "version_check", - ] - -+[[package]] -+name = "gethostname" -+version = "0.4.3" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" -+dependencies = [ -+ "libc", -+ "windows-targets 0.48.5", -+] -+ - [[package]] - name = "hashbrown" - version = "0.14.3" -@@ -350,6 +520,19 @@ dependencies = [ - "cc", - ] - -+[[package]] -+name = "image" -+version = "0.25.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" -+dependencies = [ -+ "bytemuck", -+ "byteorder-lite", -+ "num-traits", -+ "png", -+ "tiff", -+] -+ - [[package]] - name = "indoc" - version = "2.0.4" -@@ -365,6 +548,12 @@ dependencies = [ - "either", - ] - -+[[package]] -+name = "jpeg-decoder" -+version = "0.3.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" -+ - [[package]] - name = "js-sys" - version = "0.3.67" -@@ -380,6 +569,12 @@ version = "0.2.151" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" - -+[[package]] -+name = "linux-raw-sys" -+version = "0.4.14" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" -+ - [[package]] - name = "lock_api" - version = "0.4.11" -@@ -405,6 +600,16 @@ dependencies = [ - "hashbrown", - ] - -+[[package]] -+name = "miniz_oxide" -+version = "0.7.4" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -+dependencies = [ -+ "adler", -+ "simd-adler32", -+] -+ - [[package]] - name = "mio" - version = "0.8.10" -@@ -426,6 +631,105 @@ dependencies = [ - "autocfg", - ] - -+[[package]] -+name = "objc-sys" -+version = "0.3.5" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" -+ -+[[package]] -+name = "objc2" -+version = "0.5.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" -+dependencies = [ -+ "objc-sys", -+ "objc2-encode", -+] -+ -+[[package]] -+name = "objc2-app-kit" -+version = "0.2.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" -+dependencies = [ -+ "bitflags 2.6.0", -+ "block2", -+ "libc", -+ "objc2", -+ "objc2-core-data", -+ "objc2-core-image", -+ "objc2-foundation", -+ "objc2-quartz-core", -+] -+ -+[[package]] -+name = "objc2-core-data" -+version = "0.2.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" -+dependencies = [ -+ "bitflags 2.6.0", -+ "block2", -+ "objc2", -+ "objc2-foundation", -+] -+ -+[[package]] -+name = "objc2-core-image" -+version = "0.2.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" -+dependencies = [ -+ "block2", -+ "objc2", -+ "objc2-foundation", -+ "objc2-metal", -+] -+ -+[[package]] -+name = "objc2-encode" -+version = "4.0.3" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" -+ -+[[package]] -+name = "objc2-foundation" -+version = "0.2.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -+dependencies = [ -+ "bitflags 2.6.0", -+ "block2", -+ "libc", -+ "objc2", -+] -+ -+[[package]] -+name = "objc2-metal" -+version = "0.2.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" -+dependencies = [ -+ "bitflags 2.6.0", -+ "block2", -+ "objc2", -+ "objc2-foundation", -+] -+ -+[[package]] -+name = "objc2-quartz-core" -+version = "0.2.2" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" -+dependencies = [ -+ "bitflags 2.6.0", -+ "block2", -+ "objc2", -+ "objc2-foundation", -+ "objc2-metal", -+] -+ - [[package]] - name = "once_cell" - version = "1.19.0" -@@ -461,6 +765,19 @@ version = "1.0.14" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - -+[[package]] -+name = "png" -+version = "0.17.13" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" -+dependencies = [ -+ "bitflags 1.3.2", -+ "crc32fast", -+ "fdeflate", -+ "flate2", -+ "miniz_oxide", -+] -+ - [[package]] - name = "proc-macro2" - version = "1.0.71" -@@ -485,7 +802,7 @@ version = "0.25.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "a5659e52e4ba6e07b2dad9f1158f578ef84a73762625ddb51536019f34d180eb" - dependencies = [ -- "bitflags 2.4.1", -+ "bitflags 2.6.0", - "cassowary", - "crossterm", - "indoc", -@@ -507,6 +824,19 @@ dependencies = [ - "bitflags 1.3.2", - ] - -+[[package]] -+name = "rustix" -+version = "0.38.28" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" -+dependencies = [ -+ "bitflags 2.6.0", -+ "errno", -+ "libc", -+ "linux-raw-sys", -+ "windows-sys 0.52.0", -+] -+ - [[package]] - name = "rustversion" - version = "1.0.14" -@@ -560,6 +890,12 @@ dependencies = [ - "libc", - ] - -+[[package]] -+name = "simd-adler32" -+version = "0.3.7" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" -+ - [[package]] - name = "smallvec" - version = "1.11.2" -@@ -626,6 +962,17 @@ dependencies = [ - "unicode-ident", - ] - -+[[package]] -+name = "tiff" -+version = "0.9.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" -+dependencies = [ -+ "flate2", -+ "jpeg-decoder", -+ "weezl", -+] -+ - [[package]] - name = "tui-textarea" - version = "0.4.0" -@@ -733,6 +1080,12 @@ version = "0.2.90" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" - -+[[package]] -+name = "weezl" -+version = "0.1.8" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" -+ - [[package]] - name = "winapi" - version = "0.3.9" -@@ -896,6 +1249,23 @@ version = "0.52.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -+[[package]] -+name = "x11rb" -+version = "0.13.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" -+dependencies = [ -+ "gethostname", -+ "rustix", -+ "x11rb-protocol", -+] -+ -+[[package]] -+name = "x11rb-protocol" -+version = "0.13.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" -+ - [[package]] - name = "zerocopy" - version = "0.7.32" -diff --git a/Cargo.toml b/Cargo.toml -index b6a62c4..24a9706 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -4,6 +4,7 @@ version = "1.2.1" - edition = "2021" - - [dependencies] -+arboard = "3.3.0" - sha1 = "0.10.1" - home = "0.5.9" - ratatui = "0.25.0" -diff --git a/src/todo_app/clipboard.rs b/src/todo_app/clipboard.rs -index c1fedee..d175293 100644 ---- a/src/todo_app/clipboard.rs -+++ b/src/todo_app/clipboard.rs -@@ -1,20 +1,27 @@ --#[derive(Debug)] -+use arboard; - pub struct Clipboard { -- buffer: String, -+ clipboard: Option, - } - - impl Clipboard { - pub fn new() -> Self { - Clipboard { -- buffer: String::new(), -+ clipboard: arboard::Clipboard::new().ok() - } - } - - pub fn get_text(&self) -> &str { -- &self.buffer -+ if let Some(clipboard) = &mut self.clipboard { -+ if let Ok(text) = clipboard.get_text() { -+ return text -+ } -+ } -+ "" - } - - pub fn set_text(&mut self, text: String) { -- self.buffer = text; -+ if let Some(clipboard) = &mut self.clipboard { -+ let _ = clipboard.set_text(text); -+ } - } - } diff --git a/src/todo_app.rs b/src/todo_app.rs index 4f376b6..398e912 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -6,9 +6,7 @@ use std::fs::create_dir_all; use std::path::Path; use std::str::{FromStr, Lines}; use std::{io, path::PathBuf}; -mod clipboard; use clap::ValueEnum; -use clipboard::Clipboard; pub use todo::schedule::Schedule; mod todo; mod todo_list; @@ -55,7 +53,7 @@ impl SortMethod { pub type Restriction = Rc bool>; pub struct App { notes_dir: PathBuf, - clipboard: Clipboard, + yanked_todo: Option, pub todo_list: TodoList, pub index: usize, changed: bool, @@ -117,13 +115,13 @@ impl App { let notes_dir = fileio::append_notes_to_path_parent(&args.todo_path); let todo_list = Self::read_a_todo_list(&args.todo_path, ¬es_dir, &args); let mut app = App { + yanked_todo: None, notes_dir, x_index: 0, y_index: 0, tree_search_positions: vec![], removed_todos: vec![], todo_list, - clipboard: Clipboard::new(), index: 0, tree_path: vec![], changed: false, @@ -409,6 +407,7 @@ impl App { self.todo_list = Self::read_a_todo_list(&self.args.todo_path, &self.notes_dir, &self.args); let len = self.max_tree_length(); self.tree_path.truncate(len); + self.fix_index(); } #[inline] @@ -514,18 +513,6 @@ impl App { self.current_list_mut().index_mut(index, &restriction) } - #[inline] - pub fn cut_todo(&mut self) { - if !self.is_todos_empty() { - let restriction = self.restriction.clone(); - let index = self.index; - let todo = self.current_list_mut().remove(index, &restriction); - let todo_string: String = (&todo).into(); - self.clipboard.set_text(todo_string); - self.fix_index() - } - } - #[inline] pub fn current_list_mut(&mut self) -> &mut TodoList { self.changed = true; @@ -681,15 +668,25 @@ impl App { } #[inline] - pub fn delete_todo(&mut self) { + pub fn remove_todo(&mut self) { let restriction = self.restriction.clone(); if !self.is_todos_empty() { let index = self.index; let todo = self.current_list_mut().remove(index, &restriction); self.removed_todos.push(todo); + self.fix_index(); } } + #[inline] + pub fn cut_todo(&mut self) { + self.remove_todo(); + if let Some(todo) = self.removed_todos.pop() { + self.yanked_todo = Some(todo) + } + } + + #[inline(always)] pub fn display_current_list(&self) -> Vec { self.current_list().display(&self.args.display_args, &self.restriction) @@ -783,21 +780,15 @@ impl App { #[inline] pub fn yank_todo(&mut self) { if let Some(todo) = self.todo() { - let todo_string: String = todo.into(); - self.clipboard.set_text(todo_string); + self.yanked_todo = Some(todo.clone()); } } #[inline] pub fn paste_todo(&mut self) { - if let Ok(mut todo) = self.clipboard.get_text().parse::() { - if let Some(dependency) = todo.dependency.as_mut() { - if dependency.is_written() { - let _ = dependency.read(&self.notes_dir, self.todo_list.todo_cmp); - } - } + if let Some(todo) = self.yanked_todo.clone() { let list = &mut self.current_list_mut(); - list.push(todo); + list.push(todo.clone()); self.index = list.reorder_last(); } } @@ -978,7 +969,7 @@ mod tests { fn test_delete_todo() -> io::Result<()> { let dir = dir("test-delete-todo")?; let mut app = write_test_todos(&dir)?; - app.delete_todo(); + app.remove_todo(); app.write().expect("App writing failed"); let names: io::Result> = fs::read_dir(dir.join("notes")) diff --git a/src/todo_app/clipboard.rs b/src/todo_app/clipboard.rs deleted file mode 100644 index c1fedee..0000000 --- a/src/todo_app/clipboard.rs +++ /dev/null @@ -1,20 +0,0 @@ -#[derive(Debug)] -pub struct Clipboard { - buffer: String, -} - -impl Clipboard { - pub fn new() -> Self { - Clipboard { - buffer: String::new(), - } - } - - pub fn get_text(&self) -> &str { - &self.buffer - } - - pub fn set_text(&mut self, text: String) { - self.buffer = text; - } -} diff --git a/src/tui_app.rs b/src/tui_app.rs index 98f96d5..c89e9c5 100644 --- a/src/tui_app.rs +++ b/src/tui_app.rs @@ -413,35 +413,27 @@ impl<'a> TuiApp<'a> { #[inline] fn editor(&mut self) -> io::Result { - match crossterm::event::read()?.into() { - Input { - key: tui_textarea::Key::Esc, - .. - } => Ok(EditorOperation::Cancel), - Input { - key: tui_textarea::Key::Enter, - .. - } => Ok(EditorOperation::Submit), - Input { - key: tui_textarea::Key::Char('u'), - ctrl: true, - .. - } => { - let before_delete = self.current_textarea_message(); - self.textarea.delete_line_by_head(); - Ok(EditorOperation::Delete(before_delete)) - } - input => { - let is_backspace = input.key == tui_textarea::Key::Backspace; - let before_delete = self.current_textarea_message(); - self.textarea.input(input); - if is_backspace { - Ok(EditorOperation::Delete(before_delete)) - } else { - Ok(EditorOperation::Input) + let event = event::read()?; + if let Key(key) = event { + match key.code { + KeyCode::Esc => return Ok(EditorOperation::Cancel), + KeyCode::Enter => return Ok(EditorOperation::Submit), + Char('u') if key.modifiers == KeyModifiers::CONTROL => { + let before_delete = self.current_textarea_message(); + self.textarea.delete_line_by_head(); + return Ok(EditorOperation::Delete(before_delete)) + } + KeyCode::Backspace => { + let before_delete = self.current_textarea_message(); + self.textarea.delete_char(); + return Ok(EditorOperation::Delete(before_delete)) } + _ => {} } } + let input:Input = event.into(); + self.textarea.input(input); + Ok(EditorOperation::Input) } #[inline] @@ -523,7 +515,7 @@ impl<'a> TuiApp<'a> { } Char('t') => self.todo_app.add_dependency(), Char('D') => { - self.todo_app.delete_todo(); + self.todo_app.remove_todo(); } Char('R') => self.todo_app.read(), Char('T') => self.todo_app.remove_current_dependent(), From 24ba97bcf932a6ba2e86dcb59460be15ac0aa7ee Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Fri, 13 Sep 2024 12:22:21 +0330 Subject: [PATCH 19/22] Add schedule day restriction --- src/cli_app.rs | 9 +++++---- src/todo_app.rs | 43 ++++++++++++------------------------------- src/tui_app.rs | 31 ++++++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/cli_app.rs b/src/cli_app.rs index 339a59d..217cb8c 100644 --- a/src/cli_app.rs +++ b/src/cli_app.rs @@ -10,6 +10,7 @@ use clap_complete::{generate, Generator}; use std::io; use std::path::PathBuf; use std::process; +use std::rc::Rc; // }}} #[derive(Parser, Debug)] @@ -66,7 +67,7 @@ pub struct NotCli; pub fn run(app: &mut App, args: CliArgs) -> Result<(), NotCli> { if !args.search_and_select.is_empty() { for query in args.search_and_select { - app.set_query_restriction(query, None) + app.set_restriction(Rc::new(move |todo| todo.matches(query.as_str()))) } if app.is_todos_empty() { process::exit(1); @@ -93,7 +94,7 @@ pub fn run(app: &mut App, args: CliArgs) -> Result<(), NotCli> { app.batch_editor_messages(); } if app.is_changed() { - app.write(); + app.write().expect("Failed to write file."); } if args.print_path { println!("{}", app.args.todo_path.to_str().unwrap()); @@ -109,7 +110,7 @@ pub fn run(app: &mut App, args: CliArgs) -> Result<(), NotCli> { } if args.stdout { - app.todo_list.write_to_stdout(); + app.todo_list.write_to_stdout().expect("Failed to write the main todolist on stdout"); return Ok(()); } if args.minimal_tree || args.list { @@ -122,7 +123,7 @@ pub fn run(app: &mut App, args: CliArgs) -> Result<(), NotCli> { return Ok(()); } if let Some(path) = args.output_file.as_ref() { - app.output_list_to_path(path); + app.output_list_to_path(path).expect(format!("Failed to output to \"{}\"", path.to_str().unwrap()).as_str()); return Ok(()); } Err(NotCli) diff --git a/src/todo_app.rs b/src/todo_app.rs index 398e912..0d41b3d 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -140,7 +140,7 @@ impl App { todo_list.sort(); todo_list.changed = false; if !args.no_tree { - todo_list.read_dependencies(notes_dir); + let _ = todo_list.read_dependencies(notes_dir); } todo_list } @@ -181,11 +181,9 @@ impl App { self.current_list_mut().append_list(todo_list) } - pub fn set_query_restriction(&mut self, query: String, last_restriction: Option) { + pub fn set_restriction_with_last(&mut self, restriction: Restriction, last_restriction: Option) { let last_restriction = last_restriction.unwrap_or(self.restriction.clone()); - self.set_restriction(Rc::new(move |todo| { - todo.matches(query.as_str()) && last_restriction(todo) - })) + self.set_restriction(Rc::new(move |todo| restriction(todo) && last_restriction(todo))) } pub fn tree_search(&mut self, query: String) { @@ -628,26 +626,6 @@ impl App { self.fix_index(); } - #[inline] - pub fn set_priority_restriction( - &mut self, - priority: u8, - last_restriction: Option, - ) { - let last_restriction = last_restriction.unwrap_or(self.restriction.clone()); - self.set_restriction(Rc::new(move |todo| { - todo.priority() == priority && last_restriction(todo) - })) - } - - #[inline] - pub fn set_priority_limit_no_done(&mut self, priority: u8) { - self.args.display_args.show_done = false; - self.set_restriction(Rc::new(move |todo| { - todo.priority() == priority && !todo.done() - })) - } - #[inline] pub fn set_current_priority(&mut self, priority: u8) { if let Some(todo) = self.todo_mut() { @@ -896,13 +874,14 @@ mod tests { let dir = dir("test-set-restrictions-query")?; let mut app = write_test_todos(&dir)?; assert_eq!(app.current_list().len(app.restriction()), 3); - app.set_query_restriction(String::from("hello"), None); + let restriction: Restriction = Rc::new(|todo| todo.matches("hello")); + app.set_restriction(Rc::clone(&restriction)); assert_eq!(app.current_list().len(app.restriction()), 2); assert_eq!(app.index, 1); app.traverse_down(); app.unset_restriction(); app.traverse_up(); - app.set_query_restriction(String::from("hello"), None); + app.set_restriction(restriction); assert_eq!(app.current_list().len(app.restriction()), 2); assert_eq!(app.index, 1); app.add_dependency_traverse_down(); @@ -917,12 +896,14 @@ mod tests { let mut app = write_test_todos(&dir)?; app.set_current_priority(2); assert_eq!(app.current_list().len(app.restriction()), 3); - app.set_priority_restriction(2, None); + let restrict_with_priority: fn(u8) -> Restriction = |priority| Rc::new(move |todo| todo.priority() == priority); + app.set_restriction(restrict_with_priority(2)); + assert_eq!(app.current_list().len(app.restriction()), 1); - app.set_priority_restriction(0, None); + app.set_restriction_with_last(restrict_with_priority(0), None); assert_eq!(app.current_list().len(app.restriction()), 0); app.update_show_done_restriction(); - app.set_priority_restriction(0, None); + app.set_restriction_with_last(restrict_with_priority(0), None); assert_eq!(app.current_list().len(app.restriction()), 2); remove_dir_all(dir)?; Ok(()) @@ -1052,7 +1033,7 @@ mod tests { schedule.add_days_to_date(-2); } app.reorder_current(); - app.todo_list.write_to_stdout(); + app.todo_list.write_to_stdout()?; assert_eq!(app.index(), 0); Ok(()) diff --git a/src/tui_app.rs b/src/tui_app.rs index c89e9c5..9262419 100644 --- a/src/tui_app.rs +++ b/src/tui_app.rs @@ -181,9 +181,9 @@ impl<'a> TuiApp<'a> { } #[inline] - fn on_search(&mut self, str: String) { + fn on_search(&mut self, query: String) { self.todo_app - .set_query_restriction(str, self.last_restriction.clone()) + .set_restriction_with_last(Rc::new(move |todo| todo.matches(query.as_str())), self.last_restriction.clone()) } #[inline] @@ -312,6 +312,16 @@ impl<'a> TuiApp<'a> { self.on_delete = Some(Self::on_priority_delete); } + #[inline] + pub fn schedule_restriction_prompt(&mut self) { + const TITLE: &str = "Limit schedule"; + const PLACEHOLDER: &str = "Enter schedule to show"; + self.last_restriction = Some(self.todo_app.restriction().clone()); + self.set_text_mode(Self::on_schedule_prompt, TITLE, PLACEHOLDER); + self.set_responsive_text_mode(Self::on_schedule_prompt, TITLE, PLACEHOLDER); + self.on_delete = Some(Self::on_priority_delete); + } + #[inline] pub fn append_prompt(&mut self) { self.set_text_mode( @@ -342,7 +352,21 @@ impl<'a> TuiApp<'a> { let priority = str.parse(); if let Ok(priority) = priority { self.todo_app - .set_priority_restriction(priority, self.last_restriction.clone()) + .set_restriction_with_last(Rc::new(move |todo| todo.priority() == priority), self.last_restriction.clone()) + } + } + + #[inline] + fn on_schedule_prompt(&mut self, str: String) { + if str.is_empty() { + return self.todo_app.update_show_done_restriction(); + } + let schedule_day = str.parse(); + if let Ok(schedule_day) = schedule_day { + self.todo_app + .set_restriction_with_last(Rc::new(move |todo| { + todo.schedule.as_ref().map_or(0, |sch| if sch.is_reminder() {0} else {sch.days()}) == schedule_day + }), self.last_restriction.clone()) } } @@ -481,6 +505,7 @@ impl<'a> TuiApp<'a> { } Char('!') => self.todo_app.toggle_show_done(), Char('@') => self.priority_prompt(), + Char('%') => self.schedule_restriction_prompt(), Char('y') => self.todo_app.yank_todo(), Char('p') => self.todo_app.paste_todo(), Char('i') => self.todo_app.increase_day_done(), From 17945021955ea8fb592884a39753b8c8871a9eec Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sat, 12 Oct 2024 06:43:14 +0330 Subject: [PATCH 20/22] Fix out of boundary bugs - Add a set_index_in_bound function for a generalized approach - Update reorder_current --- src/todo_app.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/todo_app.rs b/src/todo_app.rs index 0d41b3d..9ae73c9 100644 --- a/src/todo_app.rs +++ b/src/todo_app.rs @@ -386,14 +386,9 @@ impl App { #[inline] pub fn toggle_current_done(&mut self) { - let index = self.index; self.todo_mut().unwrap().toggle_done(); - if self.args.display_args.show_done { - self.index = self.current_list_mut().reorder(index); - } else { - self.current_list_mut().sort(); - self.fix_index(); - } + self.reorder_current(); + self.fix_index(); while self.is_undone_empty() && self.traverse_up() { self.toggle_current_done() } @@ -409,7 +404,7 @@ impl App { } #[inline] - pub fn fix_index(&mut self) { + fn fix_index(&mut self) { let size = self.current_list().len(&self.restriction); self.index = match size { 0 => 0, @@ -417,6 +412,14 @@ impl App { } } + #[inline] + fn set_index_in_bound(&mut self, index: usize) { + let size = self.current_list().len(&self.restriction); + if index < size { + self.index = index; + } + } + #[inline] pub fn parent(&mut self) -> Option<&Todo> { let mut list = &self.todo_list; @@ -642,7 +645,8 @@ impl App { #[inline] pub fn reorder_current(&mut self) { let index = self.index; - self.index = self.current_list_mut().reorder(index); + let index = self.current_list_mut().reorder(index); + self.set_index_in_bound(index); } #[inline] From 6dcfe7a08ce88e3c37b45a1dd18f416a99fc9646 Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sun, 13 Oct 2024 06:47:57 +0330 Subject: [PATCH 21/22] Update keys in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 317e577..c78647e 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ The default mode of the app is TUI mode. Keybinds are vim-like. Here they are: | J | increase todo priority | | K | decrease todo priority | | @ | restrict todos by priority | +| % | restrict todos by schedule day | | d | toggle daily | | W | toggle weekly | | S | set custom schedule | From d9d478131bf36ebdd40616fc95096a6416e4ef63 Mon Sep 17 00:00:00 2001 From: nimaaskarian Date: Sun, 13 Oct 2024 06:50:20 +0330 Subject: [PATCH 22/22] Bumped version 1.6.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8bd32b6..557a14f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -133,7 +133,7 @@ checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "c3" -version = "1.5.1" +version = "1.6.0" dependencies = [ "chrono", "clap", diff --git a/Cargo.toml b/Cargo.toml index 15bc100..740a0f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "c3" -version = "1.5.1" +version = "1.6.0" edition = "2021" [dependencies]