Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
nnyyxxxx committed Oct 11, 2024
1 parent 07cb3c1 commit f3c88a0
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 154 deletions.
191 changes: 40 additions & 151 deletions hyprland-parser/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,10 @@
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};

#[derive(Debug, Default)]
pub struct HyprlandConfig {
general: HashMap<String, String>,
decoration: HashMap<String, String>,
animations: HashMap<String, String>,
input: HashMap<String, String>,
gestures: HashMap<String, String>,
group: HashMap<String, String>,
misc: HashMap<String, String>,
binds: HashMap<String, String>,
xwayland: HashMap<String, String>,
opengl: HashMap<String, String>,
render: HashMap<String, String>,
cursor: HashMap<String, String>,
debug: HashMap<String, String>,
blur: HashMap<String, String>,
touchpad: HashMap<String, String>,
touchdevice: HashMap<String, String>,
tablet: HashMap<String, String>,
groupbar: HashMap<String, String>,
exec: Vec<String>,
exec_once: Vec<String>,
monitor: Vec<String>,
windowrule: Vec<String>,
windowrulev2: Vec<String>,
bind: Vec<String>,
bindm: Vec<String>,
content: Vec<String>,
sections: HashMap<String, usize>,
added_entries: HashMap<String, HashSet<String>>,
}

impl HyprlandConfig {
Expand All @@ -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(&section_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());
}
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down

0 comments on commit f3c88a0

Please sign in to comment.