150 lines
5.1 KiB
Rust
150 lines
5.1 KiB
Rust
|
use std::str::FromStr;
|
|||
|
|
|||
|
use serde::{Deserialize, Serialize};
|
|||
|
use strum::IntoEnumIterator;
|
|||
|
|
|||
|
use crate::gen_parse;
|
|||
|
|
|||
|
use super::{command::CommandParseError, window::Window, Monitor, Tag, ToCommandString};
|
|||
|
|
|||
|
#[derive(Debug, Clone, Serialize, Deserialize, strum::Display, strum::EnumIter, PartialEq)]
|
|||
|
#[strum(serialize_all = "snake_case")]
|
|||
|
pub enum Hook {
|
|||
|
/// The attribute `path` was changed from `old` to `new`.
|
|||
|
/// Requires that the attribute `path` has been passed to the [HlwmCommand::Watch] command before.
|
|||
|
AttributeChanged {
|
|||
|
path: String,
|
|||
|
old: String,
|
|||
|
new: String,
|
|||
|
},
|
|||
|
/// The fullscreen state of `window` was changed to [on|off].
|
|||
|
Fullscreen {
|
|||
|
on: bool,
|
|||
|
window: Window,
|
|||
|
},
|
|||
|
/// The `tag` was selected on `monitor`.
|
|||
|
TagChanged {
|
|||
|
tag: String,
|
|||
|
monitor: Monitor,
|
|||
|
},
|
|||
|
/// The `window` with title `title` was focused
|
|||
|
FocusChanged {
|
|||
|
window: Window,
|
|||
|
title: String,
|
|||
|
},
|
|||
|
WindowTitleChanged {
|
|||
|
window: Window,
|
|||
|
title: String,
|
|||
|
},
|
|||
|
/// The flags (i.e. urgent or filled state) have been changed.
|
|||
|
TagFlags,
|
|||
|
TagAdded(Tag),
|
|||
|
TagRenamed {
|
|||
|
old: String,
|
|||
|
new: String,
|
|||
|
},
|
|||
|
Urgent {
|
|||
|
on: bool,
|
|||
|
window: Window,
|
|||
|
},
|
|||
|
/// A `window` appeared which triggered a rule/hook.
|
|||
|
Rule {
|
|||
|
hook: String,
|
|||
|
window: Window,
|
|||
|
},
|
|||
|
/// Tells a panel to quit. The default panel.sh quits on this hook. Many scripts are using this hook.
|
|||
|
QuitPanel,
|
|||
|
/// Tells all daemons that the autostart file is reloaded — and tells them to quit.
|
|||
|
/// This hook **should** be emitted in the first line of every autostart file.
|
|||
|
Reload,
|
|||
|
}
|
|||
|
|
|||
|
impl Hook {
|
|||
|
fn from_raw_parts(command: &str, args: Vec<String>) -> Result<Self, CommandParseError> {
|
|||
|
let command = Self::iter()
|
|||
|
.find(|cmd| cmd.to_string() == command)
|
|||
|
.ok_or(CommandParseError::UnknownCommand(command.to_string()))?;
|
|||
|
gen_parse!(command, args);
|
|||
|
|
|||
|
match command {
|
|||
|
Hook::AttributeChanged {
|
|||
|
path: _,
|
|||
|
old: _,
|
|||
|
new: _,
|
|||
|
} => parse!(path: String, old: String, new: String => AttributeChanged),
|
|||
|
Hook::Fullscreen { on: _, window: _ } => {
|
|||
|
parse!(on: FromStr, window: FromStr => Fullscreen)
|
|||
|
}
|
|||
|
Hook::TagChanged { tag: _, monitor: _ } => {
|
|||
|
parse!(tag: String, monitor: FromStr => TagChanged)
|
|||
|
}
|
|||
|
Hook::FocusChanged {
|
|||
|
window: _,
|
|||
|
title: _,
|
|||
|
} => parse!(window: FromStr, title: String => FocusChanged),
|
|||
|
Hook::WindowTitleChanged {
|
|||
|
window: _,
|
|||
|
title: _,
|
|||
|
} => parse!(window: FromStr, title: String => WindowTitleChanged),
|
|||
|
Hook::TagFlags => Ok(Hook::TagFlags),
|
|||
|
Hook::TagAdded(_) => parse!(FromStr => TagAdded),
|
|||
|
Hook::TagRenamed { old: _, new: _ } => parse!(old: String, new: String => TagRenamed),
|
|||
|
Hook::Urgent { on: _, window: _ } => parse!(on: Bool, window: FromStr => Urgent),
|
|||
|
Hook::Rule { hook: _, window: _ } => parse!(hook: String, window: FromStr => Rule),
|
|||
|
Hook::QuitPanel => Ok(Hook::QuitPanel),
|
|||
|
Hook::Reload => Ok(Hook::Reload),
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
impl FromStr for Hook {
|
|||
|
type Err = CommandParseError;
|
|||
|
|
|||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|||
|
let mut split = s.split("\t");
|
|||
|
Hook::from_raw_parts(
|
|||
|
split
|
|||
|
.next()
|
|||
|
.ok_or(CommandParseError::UnknownCommand(format!("hook {s}")))?,
|
|||
|
split.map(String::from).collect(),
|
|||
|
)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
impl Default for Hook {
|
|||
|
fn default() -> Self {
|
|||
|
Self::Reload
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
impl ToCommandString for Hook {
|
|||
|
fn to_command_string(&self) -> String {
|
|||
|
[self.to_string()]
|
|||
|
.into_iter()
|
|||
|
.chain(match self {
|
|||
|
Hook::AttributeChanged { path, old, new } => {
|
|||
|
vec![path.to_string(), old.to_string(), new.to_string()].into_iter()
|
|||
|
}
|
|||
|
Hook::Fullscreen { on, window } => {
|
|||
|
vec![on.to_string(), window.to_string()].into_iter()
|
|||
|
}
|
|||
|
Hook::TagChanged { tag, monitor } => {
|
|||
|
vec![tag.to_string(), monitor.to_string()].into_iter()
|
|||
|
}
|
|||
|
Hook::WindowTitleChanged { window, title }
|
|||
|
| Hook::FocusChanged { window, title } => {
|
|||
|
vec![window.to_string(), title.to_string()].into_iter()
|
|||
|
}
|
|||
|
Hook::QuitPanel | Hook::Reload | Hook::TagFlags => vec![].into_iter(),
|
|||
|
Hook::TagAdded(tag) => vec![tag.to_string()].into_iter(),
|
|||
|
Hook::TagRenamed { old, new } => vec![old.to_string(), new.to_string()].into_iter(),
|
|||
|
Hook::Urgent { on, window } => vec![on.to_string(), window.to_string()].into_iter(),
|
|||
|
Hook::Rule { hook, window } => {
|
|||
|
vec![hook.to_string(), window.to_string()].into_iter()
|
|||
|
}
|
|||
|
})
|
|||
|
.collect::<Vec<_>>()
|
|||
|
.join("\t")
|
|||
|
}
|
|||
|
}
|