use crate::colors::Colors;
use crate::layout::Layout;
use std::io::stdout;
use std::io::Result;
use std::io::Write;
use std::process::Command;
#[derive(Clone, Debug)]
pub struct Keybind {
modifier: String,
keymap: String,
command: String,
}
pub struct KeyboardLayout<T> {
pub rules: Option<T>,
pub model: Option<T>,
pub variant: Option<T>,
pub options: Option<T>,
pub layout: Option<T>,
}
#[derive(Debug)]
pub struct Config {
keybinds: Vec<Keybind>,
colors: Colors,
layout: Layout,
modifier: String,
}
impl Config {
fn serialize_to_owned(&self, arr: &Vec<[&str; 2]>) -> Vec<Vec<String>> {
let mut new_arr: Vec<Vec<String>> = Vec::new();
for keybind in arr {
new_arr.push(vec![String::from(keybind[0]), String::from(keybind[1])])
}
new_arr
}
pub fn print_keybindings(&self) {
let mut writer = stdout();
write!(writer, "{:?}", self.keybinds).unwrap();
}
}
impl Config {
pub fn set_keybind(&mut self, keys: &str, command: &str) -> &mut Self {
let keybind = Keybind {
modifier: self.modifier.clone(),
keymap: String::from(keys),
command: String::from(command),
};
self.keybinds.push(keybind);
self
}
pub fn set_keybinds(&mut self, keybinds: Vec<[&str; 2]>) -> &mut Self {
let keybinds = self.serialize_to_owned(&keybinds);
for keybind in keybinds {
self.set_keybind(&keybind[0], &keybind[1]);
}
self
}
pub fn set_mouse_keybinds(
&mut self,
left: Option<&str>,
right: Option<&str>,
middle: Option<&str>,
) -> &mut Self {
if let Some(left_command) = left {
self.apply_mouse_keybind("left", left_command);
}
if let Some(right_command) = right {
self.apply_mouse_keybind("right", right_command);
}
if let Some(middle_command) = middle {
self.apply_mouse_keybind("middle", middle_command);
}
self
}
fn apply_mouse_keybind(&self, position: &str, command: &str) {
let pos: &str = match position {
"left" => "BTN_LEFT",
"right" => "BTN_RIGHT",
"middle" => "BTN_MIDDLE",
_ => "BTN_LEFT",
};
Command::new("riverctl")
.args([
"map-pointer",
"normal",
self.modifier.as_str(),
pos,
command,
])
.spawn()
.expect("Can't set the mouse keybind")
.wait()
.unwrap();
}
fn apply_keybind(&self, keybind: Keybind) {
let command: Vec<&str> = keybind.command.split_whitespace().collect();
match command.len() {
1 => {
Command::new("riverctl")
.args([
"map",
"normal",
keybind.modifier.as_str(),
keybind.keymap.as_str(),
command[0],
])
.spawn()
.expect("Can't set the keybind\n")
.wait()
.unwrap();
}
2 => {
let args = [
"map",
"normal",
keybind.modifier.as_str(),
keybind.keymap.as_str(),
command[0],
command[1],
];
Command::new("riverctl")
.args(args)
.spawn()
.expect("Can't set the keybind\n")
.wait()
.unwrap();
}
0 => {
panic!("There are no commands provided for the riverctl!\n")
}
_ => {
let args: Vec<&str> = [
"map",
"normal",
keybind.modifier.as_str(),
keybind.keymap.as_str(),
]
.iter()
.chain(&command)
.copied()
.collect();
Command::new("riverctl")
.args(args)
.spawn()
.expect("Can't set the keybind\n")
.wait()
.unwrap();
}
}
}
}
impl Default for Config {
fn default() -> Self {
Config {
keybinds: vec![],
colors: Colors::default(),
layout: Layout::default(),
modifier: String::from("Super"),
}
}
}
impl Config {
pub fn set_repeat(&mut self, repeat_rate: u32, repeat_delay: u32) -> &mut Self {
Command::new("riverctl")
.args([
"set-repeat",
repeat_rate.to_string().as_str(),
repeat_delay.to_string().as_str(),
])
.spawn()
.expect("Can't set xkb settings")
.wait()
.unwrap();
self
}
pub fn set_keyboard_layout(&mut self, layout: KeyboardLayout<&str>) -> &mut Self {
let rules = layout.rules.unwrap_or("");
let model = layout.model.unwrap_or("");
let variant = layout.variant.unwrap_or("");
let options = layout.options.unwrap_or("");
let layout = match layout.options {
Some(layout) => layout,
None => panic!("Keyboard layout is not set"),
};
Command::new("riverctl")
.args([
"-rules", rules, "-model", model, "-variant", variant, "-options", options,
"-layout", layout,
])
.spawn()
.expect("Can't set the keyboard layout!\n")
.wait()
.unwrap();
self
}
pub fn change_super(&mut self, key: &str) -> &mut Self {
self.modifier = String::from(key);
self
}
pub fn set_tags(&mut self, modifier: &str, switch_modifier: &str) -> &mut Self {
let tags: Vec<u32> = (0..9).collect();
let tag_ids: Vec<u32> = tags.iter().map(|x| 2_u32.pow(*x)).collect();
let mut keybinds: Vec<Keybind> = Vec::new();
let mut idx = 0;
while idx < tags.len() {
keybinds.push(Keybind {
modifier: String::from(modifier),
keymap: (tags[idx] + 1).to_string(),
command: String::from("set-focused-tags ") + tag_ids[idx].to_string().as_str(),
});
keybinds.push(Keybind {
modifier: String::from(switch_modifier),
keymap: (tags[idx] + 1).to_string(),
command: String::from("set-view-tags ") + tag_ids[idx].to_string().as_str(),
});
idx += 1;
}
for keybind in keybinds {
self.keybinds.push(keybind);
}
self
}
pub fn autostart(&mut self, applications: Vec<&str>) -> &mut Self {
for app in applications {
Command::new("riverctl")
.args(["spawn", app])
.spawn()
.expect("Can't spawn autostart programs")
.wait()
.unwrap();
}
self
}
fn apply_colors(&mut self) -> &mut Self {
let background_color = format!("{:#X}", self.colors.background_color);
let border_color_focused = format!("{:#X}", self.colors.border_color_focused);
let border_color_unfocused = format!("{:#X}", self.colors.border_color_unfocused);
let commands = vec![
["background-color", background_color.as_str()],
["border-color-focused", border_color_focused.as_str()],
["border-color-unfocused", border_color_unfocused.as_str()],
];
for command in commands {
Command::new("riverctl")
.args(command)
.spawn()
.expect("Can't set colors with riverctl\n")
.wait()
.unwrap();
}
self
}
pub fn apply(&mut self) -> Result<()> {
for keybind in &self.keybinds {
let keybind = keybind.clone();
self.apply_keybind(keybind);
}
self.apply_colors();
self.layout.spawn();
Ok(())
}
}