gioser

tawasuyu/brahman

Rust 492TOML 194Markdown 53JSON 176939 Definiciones

⎇ b31f98883379a172efd309cd2cec98d16eb591db crates/apps/mirada-ctl/src/main.rs Rust · 126 líneas · 4.5 KB Historia Quién tocó qué crudo

feat(mirada): API de acciones — mirada-ctl + HUD interactivo b31f98883 · sergio ·

1//! `mirada-ctl` — el control del compositor carmen por línea de comandos.
2//!
3//! Al estilo de `swaymsg` / `hyprctl`: dispara una acción de escritorio o
4//! consulta el estado, hablando con el Cerebro por su socket de control
5//! ([`mirada_brain::ctl`]). El Cerebro es la app `mirada`, o
6//! `mirada-compositor` cuando lleva el Cerebro embebido.
7//!
8//! ```sh
9//! mirada-ctl focus-next            # cambia el foco
10//! mirada-ctl focus-window 5        # enfoca una ventana concreta
11//! mirada-ctl workspace 3           # va al escritorio 3
12//! mirada-ctl layout grid           # fija el modo de teselado
13//! mirada-ctl windows               # lista las ventanas
14//! mirada-ctl actions               # lista las acciones
15//! ```
16
17use std::process::ExitCode;
18
19use mirada_brain::ctl::{self, CtlReply, CtlRequest, WindowLine};
20use mirada_brain::DesktopAction;
21
22fn main() -> ExitCode {
23    let args: Vec<String> = std::env::args().skip(1).collect();
24    match run(&args) {
25        Ok(()) => ExitCode::SUCCESS,
26        Err(msg) => {
27            eprintln!("mirada-ctl: {msg}");
28            ExitCode::FAILURE
29        }
30    }
31}
32
33fn run(args: &[String]) -> Result<(), String> {
34    match args.first().map(String::as_str) {
35        None | Some("-h" | "--help" | "help") => {
36            print_help();
37            Ok(())
38        }
39        Some("actions") => {
40            print_actions();
41            Ok(())
42        }
43        Some("windows") => match request(CtlRequest::ListWindows)? {
44            CtlReply::Windows(ws) => {
45                print_windows(&ws);
46                Ok(())
47            }
48            CtlReply::Error(e) => Err(e),
49            CtlReply::Ok => Err("respuesta inesperada del Cerebro".into()),
50        },
51        // Todo lo demás es una acción. `focus-window 5` y `workspace 3`
52        // se unen con `:` a la forma canónica (`focus-window:5`).
53        Some(_) => {
54            let spec = args.join(":");
55            let action: DesktopAction = spec
56                .parse()
57                .map_err(|e| format!("{e}\n  lista de acciones:  mirada-ctl actions"))?;
58            match request(CtlRequest::Do(action))? {
59                CtlReply::Ok => Ok(()),
60                CtlReply::Error(e) => Err(e),
61                CtlReply::Windows(_) => Err("respuesta inesperada del Cerebro".into()),
62            }
63        }
64    }
65}
66
67/// Manda una petición al Cerebro y devuelve su respuesta.
68fn request(req: CtlRequest) -> Result<CtlReply, String> {
69    let path = ctl::default_socket_path();
70    ctl::send_request(&path, &req).map_err(|e| {
71        format!(
72            "no pude hablar con el Cerebro en {} ({e})\n  \
73             ¿está corriendo `mirada` o `mirada-compositor`?",
74            path.display()
75        )
76    })
77}
78
79/// Imprime la lista de ventanas, marcando la enfocada con `*`.
80fn print_windows(windows: &[WindowLine]) {
81    if windows.is_empty() {
82        println!("(no hay ventanas)");
83        return;
84    }
85    for w in windows {
86        let mark = if w.focused { '*' } else { ' ' };
87        println!(
88            "{mark} id {:<4} esc {}  {:<24} {}",
89            w.id, w.workspace, w.app_id, w.title
90        );
91    }
92}
93
94fn print_help() {
95    println!(
96        "mirada-ctl — control del compositor carmen\n\
97         \n\
98         USO:\n  \
99           mirada-ctl <acción>      aplica una acción de escritorio\n  \
100           mirada-ctl windows       lista las ventanas\n  \
101           mirada-ctl actions       lista las acciones disponibles\n\
102         \n\
103         EJEMPLOS:\n  \
104           mirada-ctl focus-next\n  \
105           mirada-ctl focus-window 5\n  \
106           mirada-ctl workspace 3\n  \
107           mirada-ctl layout grid"
108    );
109}
110
111fn print_actions() {
112    println!(
113        "Acciones de mirada-ctl:\n  \
114           focus-next                 mueve el foco a la siguiente ventana\n  \
115           focus-prev                 mueve el foco a la anterior\n  \
116           focus-window <id>          enfoca la ventana <id>  (ver: mirada-ctl windows)\n  \
117           move-forward               adelanta la ventana enfocada en el teselado\n  \
118           move-backward              la atrasa\n  \
119           close-focused              cierra la ventana enfocada\n  \
120           cycle-layout               pasa al siguiente modo de teselado\n  \
121           layout <modo>              master-stack | monocle | grid | columns\n  \
122           workspace <n>              activa el escritorio n (1..9)\n  \
123           send-to-workspace <n>      manda la enfocada al escritorio n\n  \
124           quit                       apaga el compositor"
125    );
126}