fixed string to int error
This commit is contained in:
71
src/app.rs
71
src/app.rs
@@ -164,4 +164,75 @@ impl App {
|
||||
self.commit_input();
|
||||
self.mode = Mode::Normal;
|
||||
}
|
||||
|
||||
/// Adds a new item to an array if the selected item is part of one.
|
||||
pub fn add_array_item(&mut self, after: bool) {
|
||||
if self.vars.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let (base, idx, depth) = {
|
||||
let selected_item = &self.vars[self.selected];
|
||||
if selected_item.is_group {
|
||||
return;
|
||||
}
|
||||
let path = &selected_item.path;
|
||||
if let Some((base, idx)) = parse_index(path) {
|
||||
(base.to_string(), idx, selected_item.depth)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let new_idx = if after { idx + 1 } else { idx };
|
||||
let insert_pos = if after {
|
||||
self.selected + 1
|
||||
} else {
|
||||
self.selected
|
||||
};
|
||||
|
||||
// 1. Shift all items in this array that have index >= new_idx
|
||||
for var in self.vars.iter_mut() {
|
||||
if var.path.starts_with(&base) {
|
||||
if let Some((b, i)) = parse_index(&var.path) {
|
||||
if b == base && i >= new_idx {
|
||||
var.path = format!("{}[{}]", base, i + 1);
|
||||
// Also update key if it was just the index
|
||||
if var.key == format!("[{}]", i) {
|
||||
var.key = format!("[{}]", i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Insert new item
|
||||
let new_item = ConfigItem {
|
||||
key: format!("[{}]", new_idx),
|
||||
path: format!("{}[{}]", base, new_idx),
|
||||
value: Some("".to_string()),
|
||||
template_value: None,
|
||||
default_value: None,
|
||||
depth,
|
||||
is_group: false,
|
||||
status: crate::format::ItemStatus::Modified,
|
||||
value_type: crate::format::ValueType::String,
|
||||
};
|
||||
self.vars.insert(insert_pos, new_item);
|
||||
self.selected = insert_pos;
|
||||
self.sync_input_with_selected();
|
||||
self.mode = Mode::Insert;
|
||||
self.status_message = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_index(path: &str) -> Option<(&str, usize)> {
|
||||
if path.ends_with(']') {
|
||||
if let Some(start) = path.rfind('[') {
|
||||
if let Ok(idx) = path[start + 1..path.len() - 1].parse::<usize>() {
|
||||
return Some((&path[..start], idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -114,6 +114,8 @@ pub struct KeybindsConfig {
|
||||
pub previous_match: String,
|
||||
pub jump_top: String,
|
||||
pub jump_bottom: String,
|
||||
pub append_item: String,
|
||||
pub prepend_item: String,
|
||||
}
|
||||
|
||||
impl Default for KeybindsConfig {
|
||||
@@ -130,6 +132,8 @@ impl Default for KeybindsConfig {
|
||||
previous_match: "N".to_string(),
|
||||
jump_top: "gg".to_string(),
|
||||
jump_bottom: "G".to_string(),
|
||||
append_item: "o".to_string(),
|
||||
prepend_item: "O".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::{ConfigItem, FormatHandler, ItemStatus};
|
||||
use super::{ConfigItem, FormatHandler, ItemStatus, ValueType};
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
@@ -27,6 +27,7 @@ impl FormatHandler for EnvHandler {
|
||||
depth: 0,
|
||||
is_group: false,
|
||||
status: ItemStatus::Present,
|
||||
value_type: ValueType::String,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -65,6 +66,7 @@ impl FormatHandler for EnvHandler {
|
||||
depth: 0,
|
||||
is_group: false,
|
||||
status: ItemStatus::MissingFromTemplate,
|
||||
value_type: ValueType::String,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -159,6 +161,7 @@ mod tests {
|
||||
depth: 0,
|
||||
is_group: false,
|
||||
status: ItemStatus::Present,
|
||||
value_type: ValueType::String,
|
||||
}];
|
||||
|
||||
let handler = EnvHandler;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::{ConfigItem, FormatHandler, FormatType, ItemStatus};
|
||||
use super::{ConfigItem, FormatHandler, FormatType, ItemStatus, ValueType};
|
||||
use serde_json::{Map, Value};
|
||||
use std::fs;
|
||||
use std::io;
|
||||
@@ -58,6 +58,8 @@ fn flatten(value: &Value, prefix: &str, depth: usize, key_name: &str, vars: &mut
|
||||
key_name.to_string()
|
||||
} else if key_name.is_empty() {
|
||||
prefix.to_string()
|
||||
} else if key_name.starts_with('[') {
|
||||
format!("{}{}", prefix, key_name)
|
||||
} else {
|
||||
format!("{}.{}", prefix, key_name)
|
||||
};
|
||||
@@ -74,6 +76,7 @@ fn flatten(value: &Value, prefix: &str, depth: usize, key_name: &str, vars: &mut
|
||||
depth,
|
||||
is_group: true,
|
||||
status: ItemStatus::Present,
|
||||
value_type: ValueType::Null,
|
||||
});
|
||||
}
|
||||
let next_depth = if path.is_empty() { depth } else { depth + 1 };
|
||||
@@ -92,6 +95,7 @@ fn flatten(value: &Value, prefix: &str, depth: usize, key_name: &str, vars: &mut
|
||||
depth,
|
||||
is_group: true,
|
||||
status: ItemStatus::Present,
|
||||
value_type: ValueType::Null,
|
||||
});
|
||||
}
|
||||
let next_depth = if path.is_empty() { depth } else { depth + 1 };
|
||||
@@ -110,6 +114,7 @@ fn flatten(value: &Value, prefix: &str, depth: usize, key_name: &str, vars: &mut
|
||||
depth,
|
||||
is_group: false,
|
||||
status: ItemStatus::Present,
|
||||
value_type: ValueType::String,
|
||||
});
|
||||
}
|
||||
Value::Number(n) => {
|
||||
@@ -123,6 +128,7 @@ fn flatten(value: &Value, prefix: &str, depth: usize, key_name: &str, vars: &mut
|
||||
depth,
|
||||
is_group: false,
|
||||
status: ItemStatus::Present,
|
||||
value_type: ValueType::Number,
|
||||
});
|
||||
}
|
||||
Value::Bool(b) => {
|
||||
@@ -136,6 +142,7 @@ fn flatten(value: &Value, prefix: &str, depth: usize, key_name: &str, vars: &mut
|
||||
depth,
|
||||
is_group: false,
|
||||
status: ItemStatus::Present,
|
||||
value_type: ValueType::Bool,
|
||||
});
|
||||
}
|
||||
Value::Null => {
|
||||
@@ -148,6 +155,7 @@ fn flatten(value: &Value, prefix: &str, depth: usize, key_name: &str, vars: &mut
|
||||
depth,
|
||||
is_group: false,
|
||||
status: ItemStatus::Present,
|
||||
value_type: ValueType::Null,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -205,14 +213,14 @@ impl FormatHandler for HierarchicalHandler {
|
||||
let val = var.value.as_deref()
|
||||
.or(var.template_value.as_deref())
|
||||
.unwrap_or("");
|
||||
insert_into_value(&mut root, &var.path, val);
|
||||
insert_into_value(&mut root, &var.path, val, var.value_type);
|
||||
}
|
||||
}
|
||||
self.write_value(path, &root)
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_into_value(root: &mut Value, path: &str, new_val_str: &str) {
|
||||
fn insert_into_value(root: &mut Value, path: &str, new_val_str: &str, value_type: ValueType) {
|
||||
let mut parts = path.split('.');
|
||||
let last_part = match parts.next_back() {
|
||||
Some(p) => p,
|
||||
@@ -255,13 +263,30 @@ fn insert_into_value(root: &mut Value, path: &str, new_val_str: &str) {
|
||||
}
|
||||
let map = current.as_object_mut().unwrap();
|
||||
|
||||
// Attempt basic type inference
|
||||
let final_val = if let Ok(n) = new_val_str.parse::<i64>() {
|
||||
Value::Number(n.into())
|
||||
} else if let Ok(b) = new_val_str.parse::<bool>() {
|
||||
Value::Bool(b)
|
||||
} else {
|
||||
Value::String(new_val_str.to_string())
|
||||
// Use the preserved ValueType instead of aggressive inference
|
||||
let final_val = match value_type {
|
||||
ValueType::Number => {
|
||||
if let Ok(n) = new_val_str.parse::<i64>() {
|
||||
Value::Number(n.into())
|
||||
} else if let Ok(f) = new_val_str.parse::<f64>() {
|
||||
if let Some(n) = serde_json::Number::from_f64(f) {
|
||||
Value::Number(n)
|
||||
} else {
|
||||
Value::String(new_val_str.to_string())
|
||||
}
|
||||
} else {
|
||||
Value::String(new_val_str.to_string())
|
||||
}
|
||||
}
|
||||
ValueType::Bool => {
|
||||
if let Ok(b) = new_val_str.parse::<bool>() {
|
||||
Value::Bool(b)
|
||||
} else {
|
||||
Value::String(new_val_str.to_string())
|
||||
}
|
||||
}
|
||||
ValueType::Null if new_val_str.is_empty() => Value::Null,
|
||||
_ => Value::String(new_val_str.to_string()),
|
||||
};
|
||||
|
||||
if let Some(i) = final_idx {
|
||||
@@ -316,7 +341,7 @@ mod tests {
|
||||
let mut root = Value::Object(Map::new());
|
||||
for var in vars {
|
||||
if !var.is_group {
|
||||
insert_into_value(&mut root, &var.path, var.value.as_deref().unwrap_or(""));
|
||||
insert_into_value(&mut root, &var.path, var.value.as_deref().unwrap_or(""), var.value_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,14 @@ pub enum ItemStatus {
|
||||
Modified,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ValueType {
|
||||
String,
|
||||
Number,
|
||||
Bool,
|
||||
Null,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConfigItem {
|
||||
pub key: String,
|
||||
@@ -22,6 +30,7 @@ pub struct ConfigItem {
|
||||
pub depth: usize,
|
||||
pub is_group: bool,
|
||||
pub status: ItemStatus,
|
||||
pub value_type: ValueType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
||||
@@ -122,6 +122,8 @@ where
|
||||
(&self.config.keybinds.previous_match, "previous_match"),
|
||||
(&self.config.keybinds.jump_top, "jump_top"),
|
||||
(&self.config.keybinds.jump_bottom, "jump_bottom"),
|
||||
(&self.config.keybinds.append_item, "append_item"),
|
||||
(&self.config.keybinds.prepend_item, "prepend_item"),
|
||||
(&"a".to_string(), "add_missing"),
|
||||
(&":".to_string(), "command"),
|
||||
(&"q".to_string(), "quit"),
|
||||
@@ -154,6 +156,8 @@ where
|
||||
"previous_match" => self.app.jump_previous_match(),
|
||||
"jump_top" => self.app.jump_top(),
|
||||
"jump_bottom" => self.app.jump_bottom(),
|
||||
"append_item" => self.app.add_array_item(true),
|
||||
"prepend_item" => self.app.add_array_item(false),
|
||||
"add_missing" => self.add_missing_item(),
|
||||
"command" => {
|
||||
self.command_buffer.push(':');
|
||||
|
||||
Reference in New Issue
Block a user