feat(core): integrate new built-in modulo with existing interface

This commit is contained in:
Federico Terzi 2021-05-22 12:20:49 +02:00
parent a7c51fe803
commit 2b5e77e1da

View File

@ -18,50 +18,25 @@
*/ */
use anyhow::Result; use anyhow::Result;
use log::{error, info}; use log::{error, warn};
use std::io::Write; use std::io::Write;
use std::process::Command; use std::process::Command;
use thiserror::Error; use thiserror::Error;
pub struct ModuloManager { pub struct ModuloManager {
modulo_path: Option<String>, is_support_enabled: bool,
} }
impl ModuloManager { impl ModuloManager {
pub fn new() -> Self { pub fn new() -> Self {
let mut modulo_path: Option<String> = None; let is_support_enabled = if cfg!(feature = "modulo") {
// Check if the `MODULO_PATH` env variable is configured true
if let Some(_modulo_path) = std::env::var_os("MODULO_PATH") {
info!("using modulo from env variable at {:?}", _modulo_path);
modulo_path = Some(_modulo_path.to_string_lossy().to_string())
} else { } else {
// Check in the same directory of espanso warn!("this version of espanso doesn't come with modulo support, so graphical features (such as Forms and Search) might not be available");
if let Ok(exe_path) = std::env::current_exe() { false
if let Some(parent) = exe_path.parent() { };
let possible_path = parent.join("modulo");
let possible_path = possible_path.to_string_lossy().to_string();
if let Ok(output) = Command::new(&possible_path).arg("--version").output() { Self { is_support_enabled }
if output.status.success() {
info!("using modulo from exe directory at {:?}", possible_path);
modulo_path = Some(possible_path);
}
}
}
}
// Otherwise check if present in the PATH
if modulo_path.is_none() {
if let Ok(output) = Command::new("modulo").arg("--version").output() {
if output.status.success() {
info!("using modulo executable found in PATH");
modulo_path = Some("modulo".to_owned());
}
}
}
}
Self { modulo_path }
} }
// pub fn is_valid(&self) -> bool { // pub fn is_valid(&self) -> bool {
@ -80,10 +55,13 @@ impl ModuloManager {
// } // }
pub fn invoke(&self, args: &[&str], body: &str) -> Result<String> { pub fn invoke(&self, args: &[&str], body: &str) -> Result<String> {
if let Some(modulo_path) = &self.modulo_path { if self.is_support_enabled {
let mut command = Command::new(modulo_path); let exec_path = std::env::current_exe().expect("unable to obtain current exec path");
let mut command = Command::new(exec_path);
let mut full_args = vec!["modulo"];
full_args.extend(args);
command command
.args(args) .args(full_args)
.stdin(std::process::Stdio::piped()) .stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped()); .stderr(std::process::Stdio::piped());
@ -109,37 +87,37 @@ impl ModuloManager {
} }
if !output.trim().is_empty() { if !output.trim().is_empty() {
return Ok(output.to_string()); Ok(output.to_string())
} else { } else {
return Err(ModuloError::EmptyOutput.into()); Err(ModuloError::EmptyOutput.into())
} }
} }
Err(error) => { Err(error) => {
return Err(ModuloError::Error(error).into()); Err(ModuloError::Error(error).into())
} }
} }
} }
Err(error) => { Err(error) => {
return Err(ModuloError::Error(error).into()); Err(ModuloError::Error(error).into())
} }
} }
} else { } else {
return Err(ModuloError::StdinError.into()); Err(ModuloError::StdinError.into())
} }
} }
Err(error) => { Err(error) => {
return Err(ModuloError::Error(error).into()); Err(ModuloError::Error(error).into())
} }
} }
} else { } else {
return Err(ModuloError::MissingModulo.into()); Err(ModuloError::MissingModulo.into())
} }
} }
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ModuloError { pub enum ModuloError {
#[error("attempt to invoke modulo even though it's not configured")] #[error("attempt to invoke modulo, but this version of espanso is not compiled with support for it")]
MissingModulo, MissingModulo,
#[error("modulo returned an empty output")] #[error("modulo returned an empty output")]