From 322779f805b0c9e0ab179a5a01823042f1a16a91 Mon Sep 17 00:00:00 2001 From: Rebel Cat Date: Wed, 27 Mar 2024 21:08:08 +0100 Subject: [PATCH] change keybindings to shift-{up,down}, query array length for cycling --- .gitignore | 2 + Cargo.lock | 4 +- Cargo.toml | 2 +- src/jnv.rs | 4 ++ src/jnv/editing.rs | 113 +++++++++++++++++++++++++++++++-------------- src/jnv/keymap.rs | 8 ++-- src/jnv/render.rs | 4 +- 7 files changed, 93 insertions(+), 44 deletions(-) diff --git a/.gitignore b/.gitignore index 6f38f4a..3d84a77 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ target/ # Ignore GIF files in the tapes directory tapes/*.gif + +.vscode diff --git a/Cargo.lock b/Cargo.lock index 6c14d02..931afb0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -503,9 +503,9 @@ dependencies = [ [[package]] name = "promkit" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa31233c1a91cf9b5e8753a57b59a3bcca559f45f38da508857fb866635ab92" +checksum = "a5d06099a0a47b6bd7414d6692596b754a12ec4537fc46b72c7363a88fee66d9" dependencies = [ "anyhow", "crossterm", diff --git a/Cargo.toml b/Cargo.toml index 4139a9e..fb819d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ anyhow = "1.0.80" clap = { version = "4.5.1", features = ["derive"] } gag = "1.0.0" j9 = "0.1.3" -promkit = "0.3.2" +promkit = "0.3.3" radix_trie = "0.2.1" # The profile that 'cargo dist' will build with diff --git a/src/jnv.rs b/src/jnv.rs index 800b025..5518a95 100644 --- a/src/jnv.rs +++ b/src/jnv.rs @@ -84,6 +84,7 @@ impl Jnv { active_char_style: StyleBuilder::new().bgc(Color::Magenta).build(), inactive_char_style: StyleBuilder::new().build(), edit_mode, + word_break_chars: Default::default(), lines: Default::default(), }, hint_message_renderer: text::Renderer { @@ -293,6 +294,8 @@ impl Jnv { let suggest_clone = rc_self_clone.borrow().suggest.clone(); let suggest_renderer_clone = rc_self_clone.borrow().suggest_renderer.clone(); let json_renderer_clone = rc_self_clone.borrow().json_renderer.clone(); + let input_json_stream_clone = rc_self_clone.borrow().input_json_stream.clone(); + Ok(Prompt::try_new( Box::new(self::render::Renderer { keymap: keymap_clone, @@ -303,6 +306,7 @@ impl Jnv { suggest: suggest_clone, suggest_snapshot: Snapshot::::new(suggest_renderer_clone), json_snapshot: Snapshot::::new(json_renderer_clone), + input_json_stream: input_json_stream_clone }), Box::new( move |event: &Event, diff --git a/src/jnv/editing.rs b/src/jnv/editing.rs index 7a39a2c..289583a 100644 --- a/src/jnv/editing.rs +++ b/src/jnv/editing.rs @@ -1,11 +1,19 @@ -pub fn add_to_nearest_integer(renderer: &mut promkit::text_editor::Renderer, value: isize) -> bool { - let cursor = renderer.texteditor.position(); - let chars = renderer.texteditor.text_without_cursor().chars(); +use gag::Gag; +use promkit::serde_json::Value; + +pub fn add_to_nearest_integer(renderer: &mut crate::jnv::render::Renderer, value: isize) -> bool { + let query_editor_after_mut = renderer.query_editor_snapshot.after_mut(); + let cursor = query_editor_after_mut.texteditor.position(); + let query = query_editor_after_mut + .texteditor + .text_without_cursor() + .to_string(); let mut previous = None; let mut previous_distance = usize::MAX; let mut pos = 0; - while pos < chars.len() { - match find_number(&chars, pos) { + + while pos < query.len() { + match find_array_index(&query, pos) { Some((start, end)) => { let distance = distance_from(start, end, cursor); if distance < previous_distance { @@ -13,37 +21,76 @@ pub fn add_to_nearest_integer(renderer: &mut promkit::text_editor::Renderer, val previous_distance = distance; } if distance == 0 { - pos = chars.len() + pos = query.len() } else { pos = end + 1; } } - None => pos = chars.len(), + None => pos = query.len(), } } match previous { None => false, Some((start, end)) => { - let before: String = chars[0..start].into_iter().collect(); - let after: String = chars[end..].into_iter().collect(); - let number: String = chars[start..end].into_iter().collect(); + let before = &query[0..start + 1]; // ends with '[' + let after = &query[end..]; // starts with ']' + let number = &query[start + 1..end]; let current_value: isize = match number.parse() { Ok(value) => value, Err(_) => return false, }; - let new_value = current_value + value; + let mut new_value = current_value + value; + + // array bound checking and cycling + let array = &before[..before.len() - 1]; + let len = query_array_length(&renderer.input_json_stream, array); + if len == -1 { + return false; + } + + if current_value == 0 && new_value == -1 { + new_value = len - 1; + } + if new_value > 0 && new_value >= len { + new_value = 0; + } else if new_value < -len { + new_value = -1; + } let new_query = format!("{before}{new_value}{after}"); - renderer.texteditor.replace(&new_query); - let mut npos = renderer.texteditor.position(); + query_editor_after_mut.texteditor.replace(&new_query); + let mut npos = query_editor_after_mut.texteditor.position(); while npos > cursor { - renderer.texteditor.backward(); - npos = renderer.texteditor.position(); + query_editor_after_mut.texteditor.backward(); + npos = query_editor_after_mut.texteditor.position(); } true } } } +fn query_array_length(input_json_stream: &[Value], array: &str) -> isize { + let stream_len = input_json_stream.len(); + if stream_len == 0 || stream_len > 1 { + // honestly, don't now how to handle it + return -1; + } + let query_len = format!("{array} | length"); + let v = &input_json_stream[0]; + + let _ignore_err = Gag::stderr().unwrap(); + + match j9::run(&query_len, &v.to_string()) { + Ok(ret) => { + if ret.is_empty() { + -1 + } else { + ret[0].parse().unwrap() + } + } + Err(_e) => -1, + } +} + fn distance_from(start: usize, end: usize, cursor: usize) -> usize { if start <= cursor && cursor < end { 0 @@ -53,26 +100,22 @@ fn distance_from(start: usize, end: usize, cursor: usize) -> usize { cursor - end } } - -fn find_number(chars: &Vec, start: usize) -> Option<(usize, usize)> { - if start >= chars.len() { - return None; - } - match chars[start..] - .iter() - .position(|ch| *ch == '-' || ch.is_digit(10)) - { - Some(num_start) => { - let ch = chars[num_start]; - eprintln!("matched: {ch} at offset {num_start}"); - let end = chars[start + num_start + 1..] - .iter() - .position(|ch| !ch.is_digit(10)); - match end { - Some(end) => Some((start + num_start, start + num_start + 1 + end)), - None => Some((start + num_start, chars.len())), - } - } +fn find_array_index(query: &str, start: usize) -> Option<(usize, usize)> { + let iter = query.chars().enumerate().skip(start); + let mut iter = iter.skip_while(|(_, ch)| *ch != '['); + let start = match iter.next() { + None => return None, + Some((pos, _)) => pos, + }; + let mut iter = iter.skip_while(|(i, ch)| *i == start + 1 && *ch == '-'); + let _minus = iter.next().is_some(); + let mut iter = iter.skip_while(|(_, ch)| ch.is_ascii_digit()); + match iter.next() { None => None, + Some((end, ']')) => Some((start, end)), + Some((end, ch)) => { + eprintln!("unterminated array index: {ch} at {end}"); + None + } } } diff --git a/src/jnv/keymap.rs b/src/jnv/keymap.rs index 9d0afee..4c212b7 100644 --- a/src/jnv/keymap.rs +++ b/src/jnv/keymap.rs @@ -166,19 +166,19 @@ pub fn default(event: &Event, renderer: &mut crate::jnv::render::Renderer) -> Re Event::Key(KeyEvent { code: KeyCode::Down, - modifiers: KeyModifiers::CONTROL, + modifiers: KeyModifiers::SHIFT, kind: KeyEventKind::Press, state: KeyEventState::NONE, }) => { - add_to_nearest_integer(query_editor_after_mut, 1); + add_to_nearest_integer(renderer, 1); } Event::Key(KeyEvent { code: KeyCode::Up, - modifiers: KeyModifiers::CONTROL, + modifiers: KeyModifiers::SHIFT, kind: KeyEventKind::Press, state: KeyEventState::NONE, }) => { - add_to_nearest_integer(query_editor_after_mut, -1); + add_to_nearest_integer(renderer, -1); } // Input char. diff --git a/src/jnv/render.rs b/src/jnv/render.rs index 6a275c4..a5d6fb0 100644 --- a/src/jnv/render.rs +++ b/src/jnv/render.rs @@ -1,6 +1,5 @@ use promkit::{ - impl_as_any, impl_cast, json, keymap::KeymapManager, listbox, pane::Pane, snapshot::Snapshot, - suggest::Suggest, text, text_editor, + impl_as_any, impl_cast, json, keymap::KeymapManager, listbox, pane::Pane, serde_json::Value, snapshot::Snapshot, suggest::Suggest, text, text_editor }; #[derive(Clone)] @@ -11,6 +10,7 @@ pub struct Renderer { pub suggest: Suggest, pub suggest_snapshot: Snapshot, pub json_snapshot: Snapshot, + pub input_json_stream: Vec } impl_as_any!(Renderer);