use crate::action::{Action, ImeState};
use crate::config::Config;
use crate::engine::Engine;
use crate::keys::Chord;
use anyhow::{Context, Result};
use std::process::{Command, Stdio};
pub trait Emitter {
fn tap(&mut self, chord: Chord) -> Result<()>;
fn ime(&mut self, state: ImeState) -> Result<()>;
fn input_source(&mut self, id: &str) -> Result<()>;
}
pub fn dispatch(emitter: &mut dyn Emitter, actions: &[Action]) -> Result<()> {
for action in actions {
match action {
Action::Tap(chord) => emitter.tap(*chord)?,
Action::Ime(state) => emitter.ime(*state)?,
Action::InputSource(id) => emitter.input_source(id)?,
Action::Cmd(cmd) => spawn_detached(cmd)?,
}
}
Ok(())
}
pub fn spawn_detached(cmd: &str) -> Result<()> {
let mut command = if cfg!(target_os = "windows") {
let mut c = Command::new("cmd");
c.args(["/C", cmd]);
c
} else {
let mut c = Command::new("sh");
c.args(["-c", cmd]);
c
};
let child = command
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.with_context(|| format!("spawning `{cmd}`"))?;
std::thread::spawn(move || {
let mut child = child;
let _ = child.wait();
});
Ok(())
}
#[allow(dead_code)]
pub fn run_blocking(cmd: &str) -> bool {
let mut command = if cfg!(target_os = "windows") {
let mut c = Command::new("cmd");
c.args(["/C", cmd]);
c
} else {
let mut c = Command::new("sh");
c.args(["-c", cmd]);
c
};
command
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
}
#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "macos")]
use macos as imp;
#[cfg(target_os = "windows")]
mod windows;
#[cfg(target_os = "windows")]
use windows as imp;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
use linux as imp;
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
compile_error!("kagi supports macOS, Windows and Linux only");
pub fn run(engine: Engine, config: &Config) -> Result<()> {
imp::run(engine, config)
}
pub fn watch(config: &Config) -> Result<()> {
imp::watch(config)
}
#[cfg(target_os = "macos")]
pub fn request_permissions() -> Result<bool> {
imp::request_permissions(imp::Prompt::Always)
}
#[cfg(not(target_os = "macos"))]
pub fn request_permissions() -> Result<bool> {
println!(
"no per-binary permission grant is required on {}",
std::env::consts::OS
);
Ok(true)
}