From 96fd6551f8d7f22124da7585d3400bdbdd8e4901 Mon Sep 17 00:00:00 2001 From: Dheepak Krishnamurthy Date: Sat, 10 Oct 2020 02:27:43 -0600 Subject: [PATCH 1/3] Use rustyline for input --- Cargo.lock | 239 ++++++++++++++++++++++++++++++++++++++++++---------- Cargo.toml | 1 + src/app.rs | 79 +++++++++-------- src/main.rs | 170 +++++++++++-------------------------- 4 files changed, 287 insertions(+), 202 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef4c27c5..408f49ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,6 +30,18 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + [[package]] name = "atty" version = "0.2.14" @@ -43,15 +55,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.50" +version = "0.3.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" +checksum = "f813291114c186a042350e787af10c26534601062603d888be110f59f85ef8fa" dependencies = [ "addr2line", "cfg-if", @@ -61,18 +73,41 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "blake2b_simd" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + [[package]] name = "cassowary" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" +[[package]] +name = "cc" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" + [[package]] name = "cfg-if" version = "0.1.10" @@ -81,20 +116,22 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chrono" -version = "0.4.13" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ + "libc", "num-integer", "num-traits", "time", + "winapi", ] [[package]] name = "clap" -version = "2.33.1" +version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "ansi_term", "atty", @@ -114,6 +151,23 @@ dependencies = [ "bitflags", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + [[package]] name = "crossterm" version = "0.17.7" @@ -199,11 +253,32 @@ dependencies = [ "syn", ] +[[package]] +name = "dirs-next" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cbcf9241d9e8d106295bd496bbe2e9cffd5fa098f2a8c9e2bbcbf09773c11a8" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c60f7b8a8953926148223260454befb50c751d3c50e1c178c4fd1ace4083c9a" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "either" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "failure" @@ -235,13 +310,13 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] @@ -252,9 +327,9 @@ checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ "libc", ] @@ -288,9 +363,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.74" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" +checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" [[package]] name = "lock_api" @@ -310,22 +385,28 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" + [[package]] name = "miniz_oxide" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" +checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" dependencies = [ "adler", + "autocfg", ] [[package]] name = "mio" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9971bc8349a361217a8f2a41f5d011274686bd4436465ba51730921039d7fb" +checksum = "e53a6ea5f38c0a48ca42159868c6d8e1bd56c0451238856cc08d58563643bdc3" dependencies = [ - "lazy_static", "libc", "log", "miow", @@ -343,6 +424,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "nix" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", +] + [[package]] name = "ntapi" version = "0.3.4" @@ -403,15 +496,15 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" [[package]] name = "proc-macro2" -version = "1.0.19" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] @@ -472,11 +565,53 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_users" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +dependencies = [ + "getrandom", + "redox_syscall", + "rust-argon2", +] + +[[package]] +name = "rust-argon2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" +dependencies = [ + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + [[package]] name = "rustc-demangle" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +checksum = "b2610b7f643d18c87dff3b489950269617e6601a51f1f05aa5daefee36f64f0b" + +[[package]] +name = "rustyline" +version = "6.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0d5e7b0219a3eadd5439498525d4765c59b7c993ef0c12244865cd2d988413" +dependencies = [ + "cfg-if", + "dirs-next", + "libc", + "log", + "memchr", + "nix", + "scopeguard", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "winapi", +] [[package]] name = "ryu" @@ -492,18 +627,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.114" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" +checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.114" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ "proc-macro2", "quote", @@ -512,9 +647,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +checksum = "a230ea9107ca2220eea9d46de97eddcb04cd00e92d13dda78e478dd33fa82bd4" dependencies = [ "itoa", "ryu", @@ -540,9 +675,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" +checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035" dependencies = [ "arc-swap", "libc", @@ -550,15 +685,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f" +checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" [[package]] name = "socket2" -version = "0.3.12" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" dependencies = [ "cfg-if", "libc", @@ -580,9 +715,9 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] name = "syn" -version = "1.0.36" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250" +checksum = "1e2e59c50ed8f6b050b071aa7b6865293957a9af6b58b94f97c1c9434ad440ea" dependencies = [ "proc-macro2", "quote", @@ -604,7 +739,7 @@ dependencies = [ [[package]] name = "task-hookrs" version = "0.7.0" -source = "git+https://github.com/matthiasbeyer/task-hookrs#4041cc3513e9bda99aa346d570ec7e6791243828" +source = "git+https://github.com/matthiasbeyer/task-hookrs#2953cf02b3c56b164a44e95fac5aae6f38954620" dependencies = [ "chrono", "derive_builder", @@ -625,6 +760,7 @@ dependencies = [ "crossterm", "itertools", "rand", + "rustyline", "serde", "serde_json", "shlex", @@ -644,11 +780,12 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] @@ -683,6 +820,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +[[package]] +name = "utf8parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" + [[package]] name = "uuid" version = "0.8.1" @@ -705,6 +848,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index c9ca72c8..1ed48d34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,3 +29,4 @@ chrono = "0.4" unicode-width = "0.1" tui = { version = "0.10", optional = true, default-features = false } crossterm = { version = "0.17", optional = true, default-features = false } +rustyline = "6.3.0" diff --git a/src/app.rs b/src/app.rs index 975fde88..f7edc7d8 100644 --- a/src/app.rs +++ b/src/app.rs @@ -25,6 +25,12 @@ use tui::{ widgets::{Block, Borders, Clear, Paragraph, Row, Table, TableState}, }; +use rustyline::error::ReadlineError; +use rustyline::Editor; +use rustyline::line_buffer::LineBuffer; + +const MAX_LINE: usize = 4096; + pub fn cmp(t1: &Task, t2: &Task) -> Ordering { let urgency1 = match &t1.uda()["urgency"] { UDAValue::Str(_) => 0.0, @@ -127,13 +133,12 @@ pub enum AppMode { pub struct TTApp { pub should_quit: bool, pub state: TableState, - pub cursor_location: usize, - pub filter: String, pub context_filter: String, pub context_name: String, - pub command: String, + pub command: LineBuffer, + pub filter: LineBuffer, + pub modify: LineBuffer, pub error: String, - pub modify: String, pub tasks: Arc>>, pub task_report_labels: Vec, pub task_report_columns: Vec, @@ -149,16 +154,18 @@ impl TTApp { tasks: Arc::new(Mutex::new(vec![])), task_report_labels: vec![], task_report_columns: vec![], - filter: "status:pending ".to_string(), context_filter: "".to_string(), context_name: "".to_string(), - cursor_location: 0, - command: "".to_string(), - modify: "".to_string(), + command: LineBuffer::with_capacity(MAX_LINE), + filter: LineBuffer::with_capacity(MAX_LINE), + modify: LineBuffer::with_capacity(MAX_LINE), error: "".to_string(), mode: AppMode::TaskReport, colors: TColorConfig::default(), }; + for c in "status:pending ".chars() { + app.filter.insert(c, 1); + } app.get_context(); app.update(); app @@ -240,53 +247,53 @@ impl TTApp { .unwrap_or_default() }; match self.mode { - AppMode::TaskReport => self.draw_command(f, rects[1], &self.filter[..], "Filter Tasks"), + AppMode::TaskReport => self.draw_command(f, rects[1], self.filter.as_str(), "Filter Tasks"), AppMode::TaskFilter => { f.render_widget(Clear, rects[1]); - f.set_cursor(rects[1].x + self.cursor_location as u16 + 1, rects[1].y + 1); - self.draw_command(f, rects[1], &self.filter[..], "Filter Tasks"); + f.set_cursor(rects[1].x + self.filter.pos() as u16 + 1, rects[1].y + 1); + self.draw_command(f, rects[1], self.filter.as_str(), "Filter Tasks"); } AppMode::TaskModify => { - f.set_cursor(rects[1].x + self.cursor_location as u16 + 1, rects[1].y + 1); + f.set_cursor(rects[1].x + self.modify.pos() as u16 + 1, rects[1].y + 1); f.render_widget(Clear, rects[1]); self.draw_command( f, rects[1], - &self.modify[..], + self.modify.as_str(), format!("Modify Task {}", task_id).as_str(), ); } AppMode::TaskLog => { - f.set_cursor(rects[1].x + self.cursor_location as u16 + 1, rects[1].y + 1); + f.set_cursor(rects[1].x + self.command.pos() as u16 + 1, rects[1].y + 1); f.render_widget(Clear, rects[1]); - self.draw_command(f, rects[1], &self.command[..], "Log Task"); + self.draw_command(f, rects[1], self.command.as_str(), "Log Task"); } AppMode::TaskSubprocess => { - f.set_cursor(rects[1].x + self.cursor_location as u16 + 1, rects[1].y + 1); + f.set_cursor(rects[1].x + self.command.pos() as u16 + 1, rects[1].y + 1); f.render_widget(Clear, rects[1]); - self.draw_command(f, rects[1], &self.command[..], "Shell Command"); + self.draw_command(f, rects[1], self.command.as_str(), "Shell Command"); } AppMode::TaskAnnotate => { - f.set_cursor(rects[1].x + self.cursor_location as u16 + 1, rects[1].y + 1); + f.set_cursor(rects[1].x + self.command.pos() as u16 + 1, rects[1].y + 1); f.render_widget(Clear, rects[1]); self.draw_command( f, rects[1], - &self.command[..], + self.command.as_str(), format!("Annotate Task {}", task_id).as_str(), ); } AppMode::TaskAdd => { - f.set_cursor(rects[1].x + self.cursor_location as u16 + 1, rects[1].y + 1); + f.set_cursor(rects[1].x + self.command.pos() as u16 + 1, rects[1].y + 1); f.render_widget(Clear, rects[1]); - self.draw_command(f, rects[1], &self.command[..], "Add Task"); + self.draw_command(f, rects[1], self.command.as_str(), "Add Task"); } AppMode::TaskError => { f.render_widget(Clear, rects[1]); - self.draw_command(f, rects[1], &self.error[..], "Error"); + self.draw_command(f, rects[1], self.error.as_str(), "Error"); } AppMode::TaskHelpPopup => { - self.draw_command(f, rects[1], &self.filter[..], "Filter Tasks"); + self.draw_command(f, rects[1], self.filter.as_str(), "Filter Tasks"); self.draw_help_popup(f, f.size()); } AppMode::Calendar => { @@ -772,10 +779,10 @@ impl TTApp { task.arg("export"); let filter = if self.context_filter != "".to_string() { - let t = format!("{} {}", self.filter, self.context_filter); + let t = format!("{} {}", self.filter.as_str(), self.context_filter); t } else { - self.filter.clone() + self.filter.as_str().into() }; match shlex::split(&filter) { Some(cmd) => { @@ -818,15 +825,15 @@ impl TTApp { let output = command.output(); match output { Ok(_) => { - self.command = "".to_string(); + self.command.update("", 0); Ok(()) }, Err(_) => Err( - format!("Shell command `{}` exited with non-zero output", self.command), + format!("Shell command `{}` exited with non-zero output", self.command.as_str()), ) } } - None => Err(format!("Unable to split `{}`", &self.command)), + None => Err(format!("Unable to split `{}`", self.command.as_str())), } } @@ -847,7 +854,7 @@ impl TTApp { let output = command.output(); match output { Ok(_) => { - self.command = "".to_string(); + self.command.update("", 0); Ok(()) }, Err(_) => Err( @@ -855,7 +862,7 @@ impl TTApp { ) } } - None => Err(format!("Unable to run `task log` with `{}`", &self.command)), + None => Err(format!("Unable to run `task log` with `{}`", self.command.as_str())), } } @@ -878,7 +885,7 @@ impl TTApp { let output = command.output(); match output { Ok(_) => { - self.modify = "".to_string(); + self.modify.update("", 0); Ok(()) }, Err(_) => Err( @@ -888,7 +895,7 @@ impl TTApp { } None => Err(format!( "Unable to run `task modify` with `{}` on task {}", - &self.modify, &task_id + self.modify.as_str(), &task_id )), } } @@ -912,7 +919,7 @@ impl TTApp { let output = command.output(); match output { Ok(_) => { - self.command = "".to_string(); + self.command.update("", 0); Ok(()) } Err(_) => Err( @@ -921,7 +928,7 @@ impl TTApp { ), } } - None => Err(format!("Unable to run `task add` with `{}`", &self.command)), + None => Err(format!("Unable to run `task add` with `{}`", self.command.as_str())), } } @@ -937,7 +944,7 @@ impl TTApp { let output = command.output(); match output { Ok(_) => { - self.command = "".to_string(); + self.command.update("", 0); Ok(()) } Err(_) => Err( @@ -946,7 +953,7 @@ impl TTApp { ), } } - None => Err(format!("Unable to run `task add` with `{}`", &self.command)), + None => Err(format!("Unable to run `task add` with `{}`", self.command.as_str())), } } diff --git a/src/main.rs b/src/main.rs index 98f7b202..2f1aec82 100644 --- a/src/main.rs +++ b/src/main.rs @@ -109,33 +109,27 @@ fn tui_main(_config: &str) -> Result<(), Box> { Key::Char('m') => { app.mode = AppMode::TaskModify; match app.task_current() { - Some(t) => app.modify = t.description().to_string(), - None => app.modify = "".to_string(), + Some(t) => app.modify.update(t.description(), 0), + None => app.modify.update("", 0), } - app.cursor_location = app.modify.chars().count(); } Key::Char('!') => { app.mode = AppMode::TaskSubprocess; - app.cursor_location = app.command.chars().count(); } Key::Char('l') => { app.mode = AppMode::TaskLog; - app.cursor_location = app.command.chars().count(); } Key::Char('a') => { app.mode = AppMode::TaskAdd; - app.cursor_location = app.command.chars().count(); } Key::Char('A') => { app.mode = AppMode::TaskAnnotate; - app.cursor_location = app.command.chars().count(); } Key::Char('?') => { app.mode = AppMode::TaskHelpPopup; } Key::Char('/') => { app.mode = AppMode::TaskFilter; - app.cursor_location = app.filter.chars().count(); } _ => {} }, @@ -157,34 +151,23 @@ fn tui_main(_config: &str) -> Result<(), Box> { } }, Key::Esc => { - app.modify = "".to_string(); + app.modify.update("", 0); app.mode = AppMode::TaskReport; } Key::Right => { - if app.cursor_location < app.modify.chars().count() { - app.cursor_location += 1; - } + app.modify.move_forward(1); } Key::Left => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - } + app.modify.move_backward(1); } Key::Char(c) => { - if app.cursor_location < app.modify.chars().count() { - app.modify.insert_str(app.cursor_location, &c.to_string()); - } else { - app.modify.push(c); - } - app.cursor_location += 1; + app.modify.insert(c, 1); + } + Key::Delete => { + app.modify.delete(1); } Key::Backspace => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - let mut cs = app.modify.chars().collect::>(); - cs.remove(app.cursor_location); - app.modify = cs.into_iter().collect(); - } + app.modify.backspace(1); } _ => {} }, @@ -200,34 +183,23 @@ fn tui_main(_config: &str) -> Result<(), Box> { } }, Key::Esc => { - app.command = "".to_string(); + app.command.update("", 0); app.mode = AppMode::TaskReport; } Key::Right => { - if app.cursor_location < app.command.chars().count() { - app.cursor_location += 1; - } + app.command.move_forward(1); } Key::Left => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - } + app.command.move_backward(1); } Key::Char(c) => { - if app.cursor_location < app.command.chars().count() { - app.command.insert_str(app.cursor_location, &c.to_string()); - } else { - app.command.push(c); - } - app.cursor_location += 1; + app.command.insert(c, 1); } Key::Backspace => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - let mut cs = app.command.chars().collect::>(); - cs.remove(app.cursor_location); - app.command = cs.into_iter().collect(); - } + app.command.backspace(1); + } + Key::Delete => { + app.command.delete(1); } _ => {} }, @@ -243,34 +215,23 @@ fn tui_main(_config: &str) -> Result<(), Box> { } }, Key::Esc => { - app.command = "".to_string(); + app.command.update("", 0); app.mode = AppMode::TaskReport; } Key::Right => { - if app.cursor_location < app.command.chars().count() { - app.cursor_location += 1; - } + app.command.move_forward(1); } Key::Left => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - } + app.command.move_backward(1); } Key::Char(c) => { - if app.cursor_location < app.command.chars().count() { - app.command.insert_str(app.cursor_location, &c.to_string()); - } else { - app.command.push(c); - } - app.cursor_location += 1; + app.command.insert(c, 1); } Key::Backspace => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - let mut cs = app.command.chars().collect::>(); - cs.remove(app.cursor_location); - app.command = cs.into_iter().collect(); - } + app.command.backspace(1); + } + Key::Delete => { + app.command.delete(1); } _ => {} }, @@ -286,34 +247,23 @@ fn tui_main(_config: &str) -> Result<(), Box> { } }, Key::Esc => { - app.command = "".to_string(); + app.command.update("", 0); app.mode = AppMode::TaskReport; } Key::Right => { - if app.cursor_location < app.command.chars().count() { - app.cursor_location += 1; - } + app.command.move_forward(1); } Key::Left => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - } + app.command.move_backward(1); } Key::Char(c) => { - if app.cursor_location < app.command.chars().count() { - app.command.insert_str(app.cursor_location, &c.to_string()); - } else { - app.command.push(c); - } - app.cursor_location += 1; + app.command.insert(c, 1); } Key::Backspace => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - let mut cs = app.command.chars().collect::>(); - cs.remove(app.cursor_location); - app.command = cs.into_iter().collect(); - } + app.command.backspace(1); + } + Key::Delete => { + app.command.delete(1); } _ => {} }, @@ -329,34 +279,23 @@ fn tui_main(_config: &str) -> Result<(), Box> { } }, Key::Esc => { - app.command = "".to_string(); + app.command.update("", 0); app.mode = AppMode::TaskReport; } Key::Right => { - if app.cursor_location < app.command.chars().count() { - app.cursor_location += 1; - } + app.command.move_forward(1); } Key::Left => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - } + app.command.move_backward(1); } Key::Char(c) => { - if app.cursor_location < app.command.chars().count() { - app.command.insert_str(app.cursor_location, &c.to_string()); - } else { - app.command.push(c); - } - app.cursor_location += 1; + app.command.insert(c, 1); } Key::Backspace => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - let mut cs = app.command.chars().collect::>(); - cs.remove(app.cursor_location); - app.command = cs.into_iter().collect(); - } + app.command.backspace(1); + } + Key::Delete => { + app.command.delete(1); } _ => {} }, @@ -366,30 +305,19 @@ fn tui_main(_config: &str) -> Result<(), Box> { app.update(); } Key::Right => { - if app.cursor_location < app.filter.chars().count() { - app.cursor_location += 1; - } + app.filter.move_forward(1); } Key::Left => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - } + app.filter.move_backward(1); } Key::Char(c) => { - if app.cursor_location < app.filter.chars().count() { - app.filter.insert_str(app.cursor_location, &c.to_string()); - } else { - app.filter.push(c); - } - app.cursor_location += 1; + app.filter.insert(c, 1); } Key::Backspace => { - if app.cursor_location > 0 { - app.cursor_location -= 1; - let mut cs = app.filter.chars().collect::>(); - cs.remove(app.cursor_location); - app.filter = cs.into_iter().collect(); - } + app.filter.backspace(1); + } + Key::Delete => { + app.filter.delete(1); } _ => {} }, From 087aa145849e4e04e69f67c6cc5172242267818e Mon Sep 17 00:00:00 2001 From: Dheepak Krishnamurthy Date: Sat, 10 Oct 2020 02:28:02 -0600 Subject: [PATCH 2/3] Autoformat code --- src/app.rs | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/app.rs b/src/app.rs index f7edc7d8..bba37950 100644 --- a/src/app.rs +++ b/src/app.rs @@ -26,8 +26,8 @@ use tui::{ }; use rustyline::error::ReadlineError; -use rustyline::Editor; use rustyline::line_buffer::LineBuffer; +use rustyline::Editor; const MAX_LINE: usize = 4096; @@ -247,7 +247,9 @@ impl TTApp { .unwrap_or_default() }; match self.mode { - AppMode::TaskReport => self.draw_command(f, rects[1], self.filter.as_str(), "Filter Tasks"), + AppMode::TaskReport => { + self.draw_command(f, rects[1], self.filter.as_str(), "Filter Tasks") + } AppMode::TaskFilter => { f.render_widget(Clear, rects[1]); f.set_cursor(rects[1].x + self.filter.pos() as u16 + 1, rects[1].y + 1); @@ -827,10 +829,11 @@ impl TTApp { Ok(_) => { self.command.update("", 0); Ok(()) - }, - Err(_) => Err( - format!("Shell command `{}` exited with non-zero output", self.command.as_str()), - ) + } + Err(_) => Err(format!( + "Shell command `{}` exited with non-zero output", + self.command.as_str() + )), } } None => Err(format!("Unable to split `{}`", self.command.as_str())), @@ -862,7 +865,10 @@ impl TTApp { ) } } - None => Err(format!("Unable to run `task log` with `{}`", self.command.as_str())), + None => Err(format!( + "Unable to run `task log` with `{}`", + self.command.as_str() + )), } } @@ -895,7 +901,8 @@ impl TTApp { } None => Err(format!( "Unable to run `task modify` with `{}` on task {}", - self.modify.as_str(), &task_id + self.modify.as_str(), + &task_id )), } } @@ -928,7 +935,10 @@ impl TTApp { ), } } - None => Err(format!("Unable to run `task add` with `{}`", self.command.as_str())), + None => Err(format!( + "Unable to run `task add` with `{}`", + self.command.as_str() + )), } } @@ -953,7 +963,10 @@ impl TTApp { ), } } - None => Err(format!("Unable to run `task add` with `{}`", self.command.as_str())), + None => Err(format!( + "Unable to run `task add` with `{}`", + self.command.as_str() + )), } } From 7cf5e1a1f3f5a982a97d24910f74784025b99d14 Mon Sep 17 00:00:00 2001 From: Dheepak Krishnamurthy Date: Sat, 10 Oct 2020 03:01:39 -0600 Subject: [PATCH 3/3] Implement readline editing features --- src/main.rs | 205 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 185 insertions(+), 20 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2f1aec82..0612cee6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,9 @@ use app::{AppMode, TTApp}; const APP_VERSION: &str = env!("CARGO_PKG_VERSION"); const APP_NAME: &str = env!("CARGO_PKG_NAME"); +use rustyline::At; +use rustyline::Word; + fn main() -> Result<(), Box> { let matches = App::new(APP_NAME) .version(APP_VERSION) @@ -154,21 +157,48 @@ fn tui_main(_config: &str) -> Result<(), Box> { app.modify.update("", 0); app.mode = AppMode::TaskReport; } - Key::Right => { + Key::Ctrl('f') | Key::Right => { app.modify.move_forward(1); } - Key::Left => { + Key::Ctrl('b') | Key::Left => { app.modify.move_backward(1); } Key::Char(c) => { app.modify.insert(c, 1); } - Key::Delete => { - app.modify.delete(1); - } Key::Backspace => { app.modify.backspace(1); } + Key::Ctrl('d') | Key::Delete => { + app.modify.delete(1); + } + Key::Ctrl('a') | Key::Home => { + app.modify.move_home(); + } + Key::Ctrl('e') | Key::End => { + app.modify.move_end(); + } + Key::Ctrl('k') => { + app.modify.kill_line(); + } + Key::Ctrl('u') => { + app.modify.discard_line(); + } + Key::Ctrl('w') => { + app.modify.delete_prev_word(Word::Emacs, 1); + } + Key::Alt('d') => { + app.modify.delete_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('f') => { + app.modify.move_to_next_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('b') => { + app.modify.move_to_prev_word(Word::Emacs, 1); + } + Key::Alt('t') => { + app.modify.transpose_words(1); + } _ => {} }, AppMode::TaskSubprocess => match input { @@ -186,10 +216,10 @@ fn tui_main(_config: &str) -> Result<(), Box> { app.command.update("", 0); app.mode = AppMode::TaskReport; } - Key::Right => { + Key::Ctrl('f') | Key::Right => { app.command.move_forward(1); } - Key::Left => { + Key::Ctrl('b') | Key::Left => { app.command.move_backward(1); } Key::Char(c) => { @@ -198,9 +228,36 @@ fn tui_main(_config: &str) -> Result<(), Box> { Key::Backspace => { app.command.backspace(1); } - Key::Delete => { + Key::Ctrl('d') | Key::Delete => { app.command.delete(1); } + Key::Ctrl('a') | Key::Home => { + app.command.move_home(); + } + Key::Ctrl('e') | Key::End => { + app.command.move_end(); + } + Key::Ctrl('k') => { + app.command.kill_line(); + } + Key::Ctrl('u') => { + app.command.discard_line(); + } + Key::Ctrl('w') => { + app.command.delete_prev_word(Word::Emacs, 1); + } + Key::Alt('d') => { + app.command.delete_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('f') => { + app.command.move_to_next_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('b') => { + app.command.move_to_prev_word(Word::Emacs, 1); + } + Key::Alt('t') => { + app.command.transpose_words(1); + } _ => {} }, AppMode::TaskLog => match input { @@ -218,10 +275,10 @@ fn tui_main(_config: &str) -> Result<(), Box> { app.command.update("", 0); app.mode = AppMode::TaskReport; } - Key::Right => { + Key::Ctrl('f') | Key::Right => { app.command.move_forward(1); } - Key::Left => { + Key::Ctrl('b') | Key::Left => { app.command.move_backward(1); } Key::Char(c) => { @@ -230,9 +287,36 @@ fn tui_main(_config: &str) -> Result<(), Box> { Key::Backspace => { app.command.backspace(1); } - Key::Delete => { + Key::Ctrl('d') | Key::Delete => { app.command.delete(1); } + Key::Ctrl('a') | Key::Home => { + app.command.move_home(); + } + Key::Ctrl('e') | Key::End => { + app.command.move_end(); + } + Key::Ctrl('k') => { + app.command.kill_line(); + } + Key::Ctrl('u') => { + app.command.discard_line(); + } + Key::Ctrl('w') => { + app.command.delete_prev_word(Word::Emacs, 1); + } + Key::Alt('d') => { + app.command.delete_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('f') => { + app.command.move_to_next_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('b') => { + app.command.move_to_prev_word(Word::Emacs, 1); + } + Key::Alt('t') => { + app.command.transpose_words(1); + } _ => {} }, AppMode::TaskAnnotate => match input { @@ -250,10 +334,10 @@ fn tui_main(_config: &str) -> Result<(), Box> { app.command.update("", 0); app.mode = AppMode::TaskReport; } - Key::Right => { + Key::Ctrl('f') | Key::Right => { app.command.move_forward(1); } - Key::Left => { + Key::Ctrl('b') | Key::Left => { app.command.move_backward(1); } Key::Char(c) => { @@ -262,9 +346,36 @@ fn tui_main(_config: &str) -> Result<(), Box> { Key::Backspace => { app.command.backspace(1); } - Key::Delete => { + Key::Ctrl('d') | Key::Delete => { app.command.delete(1); } + Key::Ctrl('a') | Key::Home => { + app.command.move_home(); + } + Key::Ctrl('e') | Key::End => { + app.command.move_end(); + } + Key::Ctrl('k') => { + app.command.kill_line(); + } + Key::Ctrl('u') => { + app.command.discard_line(); + } + Key::Ctrl('w') => { + app.command.delete_prev_word(Word::Emacs, 1); + } + Key::Alt('d') => { + app.command.delete_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('f') => { + app.command.move_to_next_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('b') => { + app.command.move_to_prev_word(Word::Emacs, 1); + } + Key::Alt('t') => { + app.command.transpose_words(1); + } _ => {} }, AppMode::TaskAdd => match input { @@ -282,10 +393,10 @@ fn tui_main(_config: &str) -> Result<(), Box> { app.command.update("", 0); app.mode = AppMode::TaskReport; } - Key::Right => { + Key::Ctrl('f') | Key::Right => { app.command.move_forward(1); } - Key::Left => { + Key::Ctrl('b') | Key::Left => { app.command.move_backward(1); } Key::Char(c) => { @@ -294,9 +405,36 @@ fn tui_main(_config: &str) -> Result<(), Box> { Key::Backspace => { app.command.backspace(1); } - Key::Delete => { + Key::Ctrl('d') | Key::Delete => { app.command.delete(1); } + Key::Ctrl('a') | Key::Home => { + app.command.move_home(); + } + Key::Ctrl('e') | Key::End => { + app.command.move_end(); + } + Key::Ctrl('k') => { + app.command.kill_line(); + } + Key::Ctrl('u') => { + app.command.discard_line(); + } + Key::Ctrl('w') => { + app.command.delete_prev_word(Word::Emacs, 1); + } + Key::Alt('d') => { + app.command.delete_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('f') => { + app.command.move_to_next_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('b') => { + app.command.move_to_prev_word(Word::Emacs, 1); + } + Key::Alt('t') => { + app.command.transpose_words(1); + } _ => {} }, AppMode::TaskFilter => match input { @@ -304,10 +442,10 @@ fn tui_main(_config: &str) -> Result<(), Box> { app.mode = AppMode::TaskReport; app.update(); } - Key::Right => { + Key::Ctrl('f') | Key::Right => { app.filter.move_forward(1); } - Key::Left => { + Key::Ctrl('b') | Key::Left => { app.filter.move_backward(1); } Key::Char(c) => { @@ -316,9 +454,36 @@ fn tui_main(_config: &str) -> Result<(), Box> { Key::Backspace => { app.filter.backspace(1); } - Key::Delete => { + Key::Ctrl('d') | Key::Delete => { app.filter.delete(1); } + Key::Ctrl('a') | Key::Home => { + app.filter.move_home(); + } + Key::Ctrl('e') | Key::End => { + app.filter.move_end(); + } + Key::Ctrl('k') => { + app.filter.kill_line(); + } + Key::Ctrl('u') => { + app.filter.discard_line(); + } + Key::Ctrl('w') => { + app.filter.delete_prev_word(Word::Emacs, 1); + } + Key::Alt('d') => { + app.filter.delete_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('f') => { + app.filter.move_to_next_word(At::AfterEnd, Word::Emacs, 1); + } + Key::Alt('b') => { + app.filter.move_to_prev_word(Word::Emacs, 1); + } + Key::Alt('t') => { + app.filter.transpose_words(1); + } _ => {} }, AppMode::TaskError => match input {