From f3c88a010ce1e6815cb64b7a212076f15b7407e8 Mon Sep 17 00:00:00 2001 From: nyx Date: Fri, 11 Oct 2024 17:54:17 -0400 Subject: [PATCH] progress --- hyprland-parser/src/lib.rs | 191 ++++++++----------------------------- src/main.rs | 6 +- 2 files changed, 43 insertions(+), 154 deletions(-) diff --git a/hyprland-parser/src/lib.rs b/hyprland-parser/src/lib.rs index 28a6f90..902fa55 100644 --- a/hyprland-parser/src/lib.rs +++ b/hyprland-parser/src/lib.rs @@ -1,32 +1,10 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; #[derive(Debug, Default)] pub struct HyprlandConfig { - general: HashMap, - decoration: HashMap, - animations: HashMap, - input: HashMap, - gestures: HashMap, - group: HashMap, - misc: HashMap, - binds: HashMap, - xwayland: HashMap, - opengl: HashMap, - render: HashMap, - cursor: HashMap, - debug: HashMap, - blur: HashMap, - touchpad: HashMap, - touchdevice: HashMap, - tablet: HashMap, - groupbar: HashMap, - exec: Vec, - exec_once: Vec, - monitor: Vec, - windowrule: Vec, - windowrulev2: Vec, - bind: Vec, - bindm: Vec, + content: Vec, + sections: HashMap, + added_entries: HashMap>, } impl HyprlandConfig { @@ -35,146 +13,57 @@ impl HyprlandConfig { } pub fn parse(&mut self, config_str: &str) { - let mut section_stack = Vec::new(); - - for line in config_str.lines() { + let mut current_section = String::new(); + let mut section_start = 0; + for (i, line) in config_str.lines().enumerate() { let trimmed = line.trim(); - if trimmed.is_empty() || trimmed.starts_with('#') { - continue; - } - if trimmed.ends_with('{') { - let section = trimmed.trim_end_matches('{').trim().to_string(); - section_stack.push(section); - continue; - } - - if trimmed == "}" { - section_stack.pop(); - continue; - } - - if trimmed.starts_with("exec = ") { - self.exec.push(trimmed[6..].to_string()); - } else if trimmed.starts_with("exec-once = ") { - self.exec_once.push(trimmed[11..].to_string()); - } else if trimmed.starts_with("monitor = ") { - self.monitor.push(trimmed[9..].to_string()); - } else if trimmed.starts_with("windowrule = ") { - self.windowrule.push(trimmed[12..].to_string()); - } else if trimmed.starts_with("windowrulev2 = ") { - self.windowrulev2.push(trimmed[14..].to_string()); - } else if trimmed.starts_with("bind = ") { - self.bind.push(trimmed[6..].to_string()); - } else if trimmed.starts_with("bindm = ") { - self.bindm.push(trimmed[7..].to_string()); - } else { - let parts: Vec<&str> = trimmed.splitn(2, '=').collect(); - if parts.len() == 2 { - let key = parts[0].trim(); - let value = parts[1].trim(); - let current_section = section_stack.join(":"); - match current_section.as_str() { - "general" => self.general.insert(key.to_string(), value.to_string()), - "decoration" => self.decoration.insert(key.to_string(), value.to_string()), - "animations" => self.animations.insert(key.to_string(), value.to_string()), - "input" => self.input.insert(key.to_string(), value.to_string()), - "gestures" => self.gestures.insert(key.to_string(), value.to_string()), - "group" => self.group.insert(key.to_string(), value.to_string()), - "misc" => self.misc.insert(key.to_string(), value.to_string()), - "binds" => self.binds.insert(key.to_string(), value.to_string()), - "xwayland" => self.xwayland.insert(key.to_string(), value.to_string()), - "opengl" => self.opengl.insert(key.to_string(), value.to_string()), - "render" => self.render.insert(key.to_string(), value.to_string()), - "cursor" => self.cursor.insert(key.to_string(), value.to_string()), - "debug" => self.debug.insert(key.to_string(), value.to_string()), - "decoration:blur" => self.blur.insert(key.to_string(), value.to_string()), - "input:touchpad" => { - self.touchpad.insert(key.to_string(), value.to_string()) - } - "input:touchdevice" => { - self.touchdevice.insert(key.to_string(), value.to_string()) - } - "input:tablet" => self.tablet.insert(key.to_string(), value.to_string()), - "group:groupbar" => { - self.groupbar.insert(key.to_string(), value.to_string()) - } - _ => None, - }; + current_section = trimmed.trim_end_matches('{').trim().to_string(); + section_start = i; + } else if trimmed == "}" { + if !current_section.is_empty() { + self.sections.insert(current_section.clone(), section_start); + current_section.clear(); } } + self.content.push(line.to_string()); } } pub fn to_string(&self) -> String { - let mut config = String::new(); - - for (key, value) in &self.general { - config.push_str(&format!("{} = {}\n", key, value)); - } - - let sections = [ - ("decoration", &self.decoration), - ("animations", &self.animations), - ("input", &self.input), - ("gestures", &self.gestures), - ("group", &self.group), - ("misc", &self.misc), - ("binds", &self.binds), - ("xwayland", &self.xwayland), - ("opengl", &self.opengl), - ("render", &self.render), - ("cursor", &self.cursor), - ("debug", &self.debug), - ]; - - for (section, map) in sections { - if !map.is_empty() { - config.push_str(&format!("\n{} {{\n", section)); - for (key, value) in map { - config.push_str(&format!(" {} = {}\n", key, value)); + let mut result = self.content.join("\n"); + for (category, entries) in &self.added_entries { + for entry in entries { + if !self.entry_exists(category, entry) { + result.push_str(&format!("\n{} = {}", category, entry)); } - config.push_str("}\n"); } } - - if !self.blur.is_empty() { - config.push_str("\ndecoration:blur {\n"); - for (key, value) in &self.blur { - config.push_str(&format!(" {} = {}\n", key, value)); - } - config.push_str("}\n"); - } - - let lists = [ - ("exec", &self.exec), - ("exec-once", &self.exec_once), - ("monitor", &self.monitor), - ("windowrule", &self.windowrule), - ("windowrulev2", &self.windowrulev2), - ("bind", &self.bind), - ("bindm", &self.bindm), - ]; - - for (prefix, list) in lists { - for item in list { - config.push_str(&format!("{} = {}\n", prefix, item)); - } - } - - config - } - - pub fn insert_general(&mut self, key: String, value: String) { - self.general.insert(key, value); + result } - pub fn add_exec(&mut self, command: String) { - self.exec.push(command); + fn entry_exists(&self, category: &str, entry: &str) -> bool { + let full_entry = format!("{} = {}", category, entry); + self.content.iter().any(|line| line.trim() == full_entry) } - pub fn add_bind(&mut self, binding: String) { - self.bind.push(binding); + pub fn add_entry(&mut self, category: &str, entry: &str) { + if !self.entry_exists(category, entry) { + if let Some(§ion_start) = self.sections.get(category) { + let insert_position = self.content[section_start..] + .iter() + .position(|line| line.trim() == "}") + .map(|pos| section_start + pos) + .unwrap_or(self.content.len()); + self.content + .insert(insert_position, format!(" {} = {}", category, entry)); + } else { + self.added_entries + .entry(category.to_string()) + .or_insert_with(HashSet::new) + .insert(entry.to_string()); + } + } } } diff --git a/src/main.rs b/src/main.rs index ab005cb..e704f45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,9 +10,9 @@ fn main() { let mut parsed_config = parse_config(&config_str); - parsed_config.insert_general("new_option".to_string(), "value".to_string()); - parsed_config.add_exec("some_command --with-args".to_string()); - parsed_config.add_bind("$mod, T, exec, kitty".to_string()); + parsed_config.add_entry("general", "new_option = value"); + parsed_config.add_entry("exec", "some_command --with-args"); + parsed_config.add_entry("bind", "$mod, T, exec, kitty"); let updated_config_str = parsed_config.to_string();