swick-rs/src/main.rs
2024-10-24 16:10:23 +03:00

97 lines
2.4 KiB
Rust

use clap::{Parser, ValueEnum};
use swayipc::{Connection, Node};
use std::fmt;
/// sway program focuser/unfocuser/launcher
///
/// Launches a program if it isn't running.
/// If it is running, but not focused, focuses it.
/// If it is running and focused, sends it to the scratchpad.
#[derive(Parser)]
#[command(version)]
struct Cli {
/// Qualifier to use
#[arg(short, long, default_value_t = UseField::Class)]
use_field: UseField,
/// The window's identifier as per the qualifier
#[arg(short, long)]
identifier: String,
/// Command to use to launch the application
#[arg(short, long)]
cmd: String,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum UseField {
Class,
AppId,
}
impl fmt::Display for UseField {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}",
match self {
UseField::Class => "class",
UseField::AppId => "app_id",
}
)
}
}
fn find_node<F>(root: Node, predicate: F) -> Option<Node>
where
F: Fn(&Node) -> bool,
{
let mut stack = vec![root];
while let Some(node) = stack.pop() {
if predicate(&node) {
return Some(node);
}
stack.extend(node.floating_nodes.into_iter());
stack.extend(node.nodes.into_iter());
}
None
}
fn main() -> Result<(), Box<dyn std::error::Error>>{
let cli = Cli::parse();
let mut connection = Connection::new()?;
let tree = connection.get_tree()?;
let node = match cli.use_field {
UseField::Class => find_node(tree, |node: &Node| {
node.window_properties
.as_ref()
.and_then(|p| p.class.as_deref())
== Some(&cli.identifier)
}),
UseField::AppId => find_node(tree, |node: &Node| {
node.app_id.as_deref() == Some(&cli.identifier)
}),
};
let sway_cmd = if let Some(node) = node {
if node.focused {
format!("[{}={}] move scratchpad", cli.use_field, cli.identifier)
} else {
format!("[{}={}] focus", cli.use_field, cli.identifier)
}
} else {
format!("exec {}", cli.cmd)
};
let result = connection.run_command(&sway_cmd)?;
if let Some(res) = result.first() {
if res.is_err() {
return Err(format!("command failed: {:?}", res).into());
}
}
Ok(())
}