Skip to content

Commit

Permalink
move the inline app.rs modules to nu/
Browse files Browse the repository at this point in the history
  • Loading branch information
amtoine committed Aug 22, 2023
1 parent 6151071 commit 27031c1
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 234 deletions.
237 changes: 3 additions & 234 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ pub(super) fn run(
exit: false,
result: Some(val),
..
} => value = nu_value::mutate_value_cell(&value, &state.cell_path, &val),
} => value = crate::nu::value::mutate_value_cell(&value, &state.cell_path, &val),
TransitionResult {
exit: false,
result: None,
Expand Down Expand Up @@ -318,11 +318,9 @@ mod tests {

use super::{transition_state, State};
use crate::{
app::{
nu_cell_path::{to_path_member_vec, PM},
Mode,
},
app::Mode,
config::{repr_keycode, Config},
nu::cell_path::{to_path_member_vec, PM},
};

/// {
Expand Down Expand Up @@ -654,232 +652,3 @@ mod tests {
todo!()
}
}

mod nu_cell_path {
use nu_protocol::{ast::PathMember, Span};

#[allow(dead_code)]
/// a simplified [`PathMember`] that can be put in a single vector, without being too long
pub(super) enum PM<'a> {
// the [`PathMember::String`] variant
S(&'a str),
// the [`PathMember::Int`] variant
I(usize),
}

#[allow(dead_code)]
pub(super) fn to_path_member_vec(cell_path: Vec<PM>) -> Vec<PathMember> {
cell_path
.iter()
.map(|x| match *x {
PM::S(val) => PathMember::String {
val: val.into(),
span: Span::test_data(),
optional: false,
},
PM::I(val) => PathMember::Int {
val,
span: Span::test_data(),
optional: false,
},
})
.collect::<Vec<_>>()
}
}

/// TODO: documentation
mod nu_value {
use nu_protocol::{
ast::{CellPath, PathMember},
Span, Value,
};

/// TODO: documentation
pub(super) fn mutate_value_cell(value: &Value, cell_path: &CellPath, val: &Value) -> Value {
if cell_path.members.is_empty() {
return val.clone();
}

if value
.clone()
.follow_cell_path(&cell_path.members, false)
.is_err()
{
return value.clone();
}

let mut cell_path = cell_path.clone();

// NOTE: cell_path.members cannot be empty thanks to the guard above
let first = cell_path.members.first().unwrap();

match value {
Value::List { vals, .. } => {
let id = match first {
PathMember::Int { val, .. } => *val,
_ => panic!("first cell path element should be an int"),
};
cell_path.members.remove(0);

let mut vals = vals.clone();
vals[id] = mutate_value_cell(&vals[id], &cell_path, val);

Value::list(vals, Span::unknown())
}
Value::Record { cols, vals, .. } => {
let col = match first {
PathMember::String { val, .. } => val.clone(),
_ => panic!("first cell path element should be an string"),
};
cell_path.members.remove(0);

let id = cols.iter().position(|x| *x == col).unwrap_or(0);

let mut vals = vals.clone();
vals[id] = mutate_value_cell(&vals[id], &cell_path, val);

Value::record(cols.to_vec(), vals, Span::unknown())
}
_ => val.clone(),
}
}

#[cfg(test)]
mod tests {
use nu_protocol::{ast::CellPath, Value};

use super::mutate_value_cell;
use crate::app::nu_cell_path::{to_path_member_vec, PM};

#[test]
fn value_mutation() {
let list = Value::test_list(vec![
Value::test_int(1),
Value::test_int(2),
Value::test_int(3),
]);
let record = Value::test_record(
vec!["a", "b", "c"],
vec![Value::test_int(1), Value::test_int(2), Value::test_int(3)],
);

let cases = vec![
// simple value -> simple value
(
Value::test_string("foo"),
vec![],
Value::test_string("bar"),
Value::test_string("bar"),
),
// list -> simple value
(
list.clone(),
vec![],
Value::test_nothing(),
Value::test_nothing(),
),
// record -> simple value
(
record.clone(),
vec![],
Value::test_nothing(),
Value::test_nothing(),
),
// mutate a list element with simple value
(
list.clone(),
vec![PM::I(0)],
Value::test_int(0),
Value::test_list(vec![
Value::test_int(0),
Value::test_int(2),
Value::test_int(3),
]),
),
// mutate a list element with complex value
(
list.clone(),
vec![PM::I(1)],
record.clone(),
Value::test_list(vec![Value::test_int(1), record.clone(), Value::test_int(3)]),
),
// invalid list index -> do not mutate
(
list.clone(),
vec![PM::I(5)],
Value::test_int(0),
list.clone(),
),
// mutate a record field with a simple value
(
record.clone(),
vec![PM::S("a")],
Value::test_nothing(),
Value::test_record(
vec!["a", "b", "c"],
vec![
Value::test_nothing(),
Value::test_int(2),
Value::test_int(3),
],
),
),
// mutate a record field with a complex value
(
record.clone(),
vec![PM::S("c")],
list.clone(),
Value::test_record(
vec!["a", "b", "c"],
vec![Value::test_int(1), Value::test_int(2), list.clone()],
),
),
// mutate a deeply-nested list element
(
Value::test_list(vec![Value::test_list(vec![Value::test_list(vec![
Value::test_string("foo"),
])])]),
vec![PM::I(0), PM::I(0), PM::I(0)],
Value::test_string("bar"),
Value::test_list(vec![Value::test_list(vec![Value::test_list(vec![
Value::test_string("bar"),
])])]),
),
// mutate a deeply-nested record field
(
Value::test_record(
vec!["a"],
vec![Value::test_record(
vec!["b"],
vec![Value::test_record(
vec!["c"],
vec![Value::test_string("foo")],
)],
)],
),
vec![PM::S("a"), PM::S("b"), PM::S("c")],
Value::test_string("bar"),
Value::test_record(
vec!["a"],
vec![Value::test_record(
vec!["b"],
vec![Value::test_record(
vec!["c"],
vec![Value::test_string("bar")],
)],
)],
),
),
];

for (value, members, cell, expected) in cases {
let cell_path = CellPath {
members: to_path_member_vec(members),
};

// TODO: add proper error messages
assert_eq!(mutate_value_cell(&value, &cell_path, &cell), expected);
}
}
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod app;
mod config;
mod edit;
mod navigation;
mod nu;
mod terminal;
mod tui;

Expand Down
29 changes: 29 additions & 0 deletions src/nu/cell_path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use nu_protocol::{ast::PathMember, Span};

#[allow(dead_code)]
/// a simplified [`PathMember`] that can be put in a single vector, without being too long
pub(crate) enum PM<'a> {
// the [`PathMember::String`] variant
S(&'a str),
// the [`PathMember::Int`] variant
I(usize),
}

#[allow(dead_code)]
pub(crate) fn to_path_member_vec(cell_path: Vec<PM>) -> Vec<PathMember> {
cell_path
.iter()
.map(|x| match *x {
PM::S(val) => PathMember::String {
val: val.into(),
span: Span::test_data(),
optional: false,
},
PM::I(val) => PathMember::Int {
val,
span: Span::test_data(),
optional: false,
},
})
.collect::<Vec<_>>()
}
2 changes: 2 additions & 0 deletions src/nu/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub(super) mod cell_path;
pub(super) mod value;
Loading

0 comments on commit 27031c1

Please sign in to comment.