Skip to content

Commit

Permalink
change keybindings to shift-{up,down}, query array length for cycling
Browse files Browse the repository at this point in the history
  • Loading branch information
charbeljc committed Mar 28, 2024
1 parent d3097b0 commit 322779f
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 44 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ target/

# Ignore GIF files in the tapes directory
tapes/*.gif

.vscode
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/jnv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -303,6 +306,7 @@ impl Jnv {
suggest: suggest_clone,
suggest_snapshot: Snapshot::<listbox::Renderer>::new(suggest_renderer_clone),
json_snapshot: Snapshot::<json::Renderer>::new(json_renderer_clone),
input_json_stream: input_json_stream_clone
}),
Box::new(
move |event: &Event,
Expand Down
113 changes: 78 additions & 35 deletions src/jnv/editing.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,96 @@
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 {
previous = Some((start, end));
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
Expand All @@ -53,26 +100,22 @@ fn distance_from(start: usize, end: usize, cursor: usize) -> usize {
cursor - end
}
}

fn find_number(chars: &Vec<char>, 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
}
}
}
8 changes: 4 additions & 4 deletions src/jnv/keymap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions src/jnv/render.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand All @@ -11,6 +10,7 @@ pub struct Renderer {
pub suggest: Suggest,
pub suggest_snapshot: Snapshot<listbox::Renderer>,
pub json_snapshot: Snapshot<json::Renderer>,
pub input_json_stream: Vec<Value>
}

impl_as_any!(Renderer);
Expand Down

0 comments on commit 322779f

Please sign in to comment.