diff options
| -rw-r--r-- | Cargo.lock | 176 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | src/bill.rs | 15 | ||||
| -rw-r--r-- | src/cli.rs | 97 |
4 files changed, 286 insertions, 4 deletions
@@ -3,6 +3,65 @@ version = 4 [[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] name = "anyhow" version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -50,6 +109,12 @@ dependencies = [ ] [[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] name = "dirs" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -71,6 +136,29 @@ dependencies = [ ] [[package]] +name = "env_filter" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -146,12 +234,42 @@ dependencies = [ ] [[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] name = "itoa" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] +name = "jiff" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "js-sys" version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -222,8 +340,10 @@ dependencies = [ name = "mingling_core" version = "0.1.4" dependencies = [ + "env_logger", "just_fmt", "just_template", + "log", "once_cell", "ron", "serde", @@ -252,6 +372,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -264,6 +390,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + +[[package]] name = "prettyplease" version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -309,6 +450,35 @@ dependencies = [ ] [[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] name = "ron" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -557,6 +727,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] name = "uuid" version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -8,7 +8,7 @@ name = "cobill" path = "src/main.rs" [dependencies] -mingling = { path = "../mingling/mingling", features = ["full"] } +mingling = { path = "../mingling/mingling", features = ["full", "debug"] } tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread" ] } uuid = { version = "1", features = ["v4"] } serde = { version = "1", features = ["derive"] } diff --git a/src/bill.rs b/src/bill.rs index 4b66554..291b759 100644 --- a/src/bill.rs +++ b/src/bill.rs @@ -235,4 +235,19 @@ impl Bills { bills } + + pub fn get_members(&self) -> Vec<String> { + let mut members = std::collections::HashSet::new(); + + for item in self.items.values() { + members.insert(item.who_paid.to_string()); + for who in &item.split { + members.insert(who.to_string()); + } + } + + let mut result: Vec<String> = members.into_iter().collect(); + result.sort(); + result + } } @@ -1,8 +1,8 @@ use std::{fs::create_dir_all, io::ErrorKind, path::PathBuf}; use mingling::{ - AnyOutput, Groupped, - macros::{chain, dispatcher, gen_program, pack, r_println, renderer}, + AnyOutput, Groupped, ShellContext, Suggest, SuggestItem, + macros::{chain, completion, dispatcher, gen_program, pack, r_println, renderer, suggest}, marker::NextProcess, parser::Picker, setup::GeneralRendererSetup, @@ -52,6 +52,97 @@ dispatcher!("add", AddBillCommand => AddBillEntry); dispatcher!("edit", EditCommand => EditEntry); dispatcher!("ls", ListAllBillCommand => ListAllBillEntry); +#[completion(AddBillEntry)] +fn comp_add(ctx: &ShellContext) -> Suggest { + if ctx.filling_argument_first(["-p", "--paid"]) { + return suggest!(); + } + + if ctx.filling_argument_first(["-r", "--reason"]) { + return suggest!(); + } + + if ctx.previous_word == "add" { + return name_suggest(vec![]); + } + + let mut found_for_arg = false; + let mut typed_names = Vec::new(); + + // Collect all names that have already been typed after -f/--for + let mut i = 0; + while i < ctx.word_index { + if ctx.all_words[i] == "-f" || ctx.all_words[i] == "--for" { + // Start collecting names after this flag + let mut j = i + 1; + while j < ctx.word_index && !ctx.all_words[j].starts_with('-') { + typed_names.push(ctx.all_words[j].clone()); + j += 1; + } + found_for_arg = true; + } + i += 1; + } + + if found_for_arg { + return name_suggest(typed_names); + } + + if ctx.typing_argument() { + return suggest! { + "-p" : "Payment amount", + "--paid" : "Payment amount", + "-r" : "Payment reason", + "--reason" : "Payment reason", + "-f" : "Who to pay for", + "--for" : "Who to pay for", + } + .strip_typed_argument(ctx); + } + suggest!() +} + +fn name_suggest(typed: Vec<String>) -> Suggest { + let members = read_bills().get_members(); + let mut suggest = Suggest::new(); + for member in members { + if !typed.contains(&member) { + suggest.insert(SuggestItem::Simple(member)); + } + } + return suggest; +} + +#[completion(ListAllBillEntry)] +fn comp_ls(ctx: &ShellContext) -> Suggest { + if ctx.typing_argument() { + return suggest! { + "-O": "Output the bill optimized to the simplest result", + "--optimize": "Output the bill optimized to the simplest result" + }; + } + suggest!() +} + +#[completion(EditEntry)] +fn comp_edit(ctx: &ShellContext) -> Suggest { + if ctx.filling_argument_first(["-e", "--editor"]) { + let mut suggest = Suggest::new(); + for editor in ["vi", "vim", "nvim", "helix", "nano"] { + suggest.insert(SuggestItem::Simple(editor.to_string())); + } + return suggest; + } + if ctx.typing_argument() { + return suggest! { + "-e": "Specify editor to use", + "--editor": "Specify editor to use" + } + .strip_typed_argument(ctx); + } + suggest!() +} + #[chain] async fn do_clear_cmd(_prev: ClearAllBillEntry) -> NextProcess { op_bills(|b| b.clear_items()); @@ -143,7 +234,7 @@ fn render_bills(prev: ResultBills) { fn render_split_result(prev: ResultSplitResult) { let mut table = SimpleTable::new(string_vec!["Who", "|", "Should Pay", "|", "To"]); for ((who, to), paid) in prev.inner.final_result { - table.push_item(string_vec![who, "|", paid, "|", to]); + table.push_item(string_vec![who, "->", paid, "->", to]); } r_println!("{}", table) } |
