release/0.5.0 #15
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1460,6 +1460,7 @@ version = "1.0.149"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
16
Cargo.toml
16
Cargo.toml
@@ -15,22 +15,16 @@ dirs = "6.0.0"
|
|||||||
env_logger = "0.11.9"
|
env_logger = "0.11.9"
|
||||||
java-properties = "2.0.0"
|
java-properties = "2.0.0"
|
||||||
log = "0.4.29"
|
log = "0.4.29"
|
||||||
quick-xml = { version = "0.39.2", features = ["serde", "serialize"] }
|
|
||||||
ratatui = "0.30.0"
|
ratatui = "0.30.0"
|
||||||
rust-ini = "0.21.3"
|
rust-ini = "0.21.3"
|
||||||
serde_json = "1.0.149"
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
serde_json = { version = "1.0.149", features = ["preserve_order"] }
|
||||||
serde_yaml = "0.9.34"
|
serde_yaml = "0.9.34"
|
||||||
thiserror = "2.0.18"
|
thiserror = "2.0.18"
|
||||||
toml = "1.0.7"
|
toml = { version = "1.0.7", features = ["preserve_order"] }
|
||||||
tui-input = "0.15.0"
|
tui-input = "0.15.0"
|
||||||
|
clap = { version = "4.6.0", features = ["derive"] }
|
||||||
[dependencies.clap]
|
quick-xml = { version = "0.39.2", features = ["serde", "serialize"] }
|
||||||
features = ["derive"]
|
|
||||||
version = "4.6.0"
|
|
||||||
|
|
||||||
[dependencies.serde]
|
|
||||||
features = ["derive"]
|
|
||||||
version = "1.0.228"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.27.0"
|
tempfile = "3.27.0"
|
||||||
|
|||||||
37
config.toml
37
config.toml
@@ -1,37 +0,0 @@
|
|||||||
[keybinds]
|
|
||||||
append_item = "o"
|
|
||||||
delete_item = "dd"
|
|
||||||
down = "j"
|
|
||||||
edit = "i"
|
|
||||||
edit_append = "A"
|
|
||||||
edit_substitute = "S"
|
|
||||||
jump_bottom = "G"
|
|
||||||
jump_top = "gg"
|
|
||||||
next_match = "n"
|
|
||||||
normal_mode = "Esc"
|
|
||||||
prepend_item = "O"
|
|
||||||
previous_match = "N"
|
|
||||||
quit = ":q"
|
|
||||||
save = ":w"
|
|
||||||
search = "/"
|
|
||||||
undo = "u"
|
|
||||||
up = "k"
|
|
||||||
|
|
||||||
[theme]
|
|
||||||
bg_active = "#a6e3a1"
|
|
||||||
bg_highlight = "#89b4fa"
|
|
||||||
bg_normal = "#1e1e2e"
|
|
||||||
bg_search = "#cba6f7"
|
|
||||||
border_active = "#a6e3a1"
|
|
||||||
border_normal = "#45475a"
|
|
||||||
fg_accent = "#b4befe"
|
|
||||||
fg_dimmed = "#6c7086"
|
|
||||||
fg_highlight = "#1e1e2e"
|
|
||||||
fg_modified = "#fab387"
|
|
||||||
fg_normal = "#cdd6f4"
|
|
||||||
fg_warning = "#f38ba8"
|
|
||||||
transparent = true
|
|
||||||
tree_depth_1 = "#b4befe"
|
|
||||||
tree_depth_2 = "#cba6f7"
|
|
||||||
tree_depth_3 = "#89b4fa"
|
|
||||||
tree_depth_4 = "#fab387"
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
use super::{ConfigItem, FormatHandler, ItemStatus, ValueType};
|
use super::{ConfigItem, FormatHandler, ItemStatus, ValueType};
|
||||||
use java_properties::{read, write};
|
use java_properties::{LineContent, PropertiesIter, PropertiesWriter};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, BufReader};
|
use std::io::{self, BufReader, BufWriter};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub struct PropertiesHandler;
|
pub struct PropertiesHandler;
|
||||||
@@ -11,69 +10,74 @@ impl FormatHandler for PropertiesHandler {
|
|||||||
fn parse(&self, path: &Path) -> io::Result<Vec<ConfigItem>> {
|
fn parse(&self, path: &Path) -> io::Result<Vec<ConfigItem>> {
|
||||||
let file = File::open(path)?;
|
let file = File::open(path)?;
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
let props = read(reader)
|
let iter = PropertiesIter::new(reader);
|
||||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
|
||||||
|
|
||||||
let mut vars = Vec::new();
|
let mut vars = Vec::new();
|
||||||
let mut groups = std::collections::HashSet::new();
|
let mut groups = std::collections::HashSet::new();
|
||||||
|
|
||||||
for (path, value) in &props {
|
for line_result in iter {
|
||||||
// Add groups based on dot notation
|
let line = line_result.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||||
let parts: Vec<&str> = path.split('.').collect();
|
|
||||||
let mut current_path = String::new();
|
|
||||||
|
|
||||||
for i in 0..parts.len() - 1 {
|
if let LineContent::KVPair(path, value) = line.consume_content() {
|
||||||
if !current_path.is_empty() {
|
// Add groups based on dot notation
|
||||||
current_path.push('.');
|
let parts: Vec<&str> = path.split('.').collect();
|
||||||
}
|
let mut current_path = String::new();
|
||||||
current_path.push_str(parts[i]);
|
|
||||||
|
|
||||||
if groups.insert(current_path.clone()) {
|
for i in 0..parts.len().saturating_sub(1) {
|
||||||
vars.push(ConfigItem {
|
if !current_path.is_empty() {
|
||||||
key: parts[i].to_string(),
|
current_path.push('.');
|
||||||
path: current_path.clone(),
|
}
|
||||||
value: None,
|
current_path.push_str(parts[i]);
|
||||||
template_value: None,
|
|
||||||
default_value: None,
|
if groups.insert(current_path.clone()) {
|
||||||
depth: i,
|
vars.push(ConfigItem {
|
||||||
is_group: true,
|
key: parts[i].to_string(),
|
||||||
status: ItemStatus::Present,
|
path: current_path.clone(),
|
||||||
value_type: ValueType::Null,
|
value: None,
|
||||||
});
|
template_value: None,
|
||||||
|
default_value: None,
|
||||||
|
depth: i,
|
||||||
|
is_group: true,
|
||||||
|
status: ItemStatus::Present,
|
||||||
|
value_type: ValueType::Null,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
vars.push(ConfigItem {
|
vars.push(ConfigItem {
|
||||||
key: parts.last().unwrap().to_string(),
|
key: parts.last().unwrap_or(&"").to_string(),
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
value: Some(value.clone()),
|
value: Some(value.clone()),
|
||||||
template_value: Some(value.clone()),
|
template_value: Some(value.clone()),
|
||||||
default_value: Some(value.clone()),
|
default_value: Some(value.clone()),
|
||||||
depth: parts.len() - 1,
|
depth: parts.len().saturating_sub(1),
|
||||||
is_group: false,
|
is_group: false,
|
||||||
status: ItemStatus::Present,
|
status: ItemStatus::Present,
|
||||||
value_type: ValueType::String,
|
value_type: ValueType::String,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by path to keep it organized
|
// We don't sort here to preserve the original file order!
|
||||||
vars.sort_by(|a, b| a.path.cmp(&b.path));
|
|
||||||
Ok(vars)
|
Ok(vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> io::Result<()> {
|
fn write(&self, path: &Path, vars: &[ConfigItem]) -> io::Result<()> {
|
||||||
let mut props = HashMap::new();
|
let file = File::create(path)?;
|
||||||
|
let writer = BufWriter::new(file);
|
||||||
|
let mut prop_writer = PropertiesWriter::new(writer);
|
||||||
|
|
||||||
for var in vars {
|
for var in vars {
|
||||||
if !var.is_group {
|
if !var.is_group {
|
||||||
let val = var.value.as_deref()
|
let val = var.value.as_deref()
|
||||||
.or(var.template_value.as_deref())
|
.or(var.template_value.as_deref())
|
||||||
.unwrap_or("");
|
.unwrap_or("");
|
||||||
props.insert(var.path.clone(), val.to_string());
|
prop_writer.write(&var.path, val)
|
||||||
|
.map_err(|e| io::Error::other(e))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let file = File::create(path)?;
|
prop_writer.finish().map_err(|e| io::Error::other(e))
|
||||||
write(file, &props).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user