diff --git a/src/extension/form.rs b/src/extension/form.rs
new file mode 100644
index 0000000..b5b8e83
--- /dev/null
+++ b/src/extension/form.rs
@@ -0,0 +1,78 @@
+/*
+ * This file is part of espanso.
+ *
+ * Copyright (C) 2020 Federico Terzi
+ *
+ * espanso is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * espanso is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with espanso. If not, see .
+ */
+
+use serde_yaml::{Mapping, Value};
+use std::collections::HashMap;
+use crate::{ui::modulo::ModuloManager, extension::ExtensionResult, config::Configs};
+use log::error;
+
+pub struct FormExtension {
+ manager: ModuloManager,
+}
+
+impl FormExtension {
+ pub fn new(config: &Configs) -> FormExtension {
+ let manager = ModuloManager::new(config);
+ FormExtension {
+ manager,
+ }
+ }
+}
+
+impl super::Extension for FormExtension {
+ fn name(&self) -> String {
+ "form".to_owned()
+ }
+
+ fn calculate(&self, params: &Mapping, _: &Vec, _: &HashMap) -> Option {
+ let layout = params.get(&Value::from("layout"));
+ let layout = if let Some(value) = layout {
+ value.as_str().unwrap_or_default().to_string()
+ } else {
+ error!("invoking form extension without specifying a layout");
+ return None;
+ };
+
+ let mut form_config = Mapping::new();
+ form_config.insert(Value::from("layout"), Value::from(layout));
+
+ if let Some(fields) = params.get(&Value::from("fields")) {
+ form_config.insert(Value::from("fields"), fields.clone());
+ }
+
+ let serialized_config: String = serde_yaml::to_string(&form_config).expect("unable to serialize form config");
+
+ let output = self.manager.invoke(&["form", "-i", "-"], &serialized_config);
+ if let Some(output) = output {
+ let json: Result, _> = serde_json::from_str(&output);
+ match json {
+ Ok(json) => {
+ return Some(ExtensionResult::Multiple(json));
+ }
+ Err(error) => {
+ error!("modulo json parsing error: {}", error);
+ return None;
+ }
+ }
+ } else {
+ error!("modulo form didn't return any output");
+ return None;
+ }
+ }
+}
diff --git a/src/extension/mod.rs b/src/extension/mod.rs
index a25406b..a6a27a4 100644
--- a/src/extension/mod.rs
+++ b/src/extension/mod.rs
@@ -17,7 +17,7 @@
* along with espanso. If not, see .
*/
-use crate::clipboard::ClipboardManager;
+use crate::{config::Configs, clipboard::ClipboardManager};
use serde_yaml::Mapping;
use std::collections::HashMap;
@@ -30,6 +30,7 @@ mod shell;
pub mod multiecho;
pub mod vardummy;
mod utils;
+mod form;
#[derive(Clone, Debug, PartialEq)]
pub enum ExtensionResult {
@@ -42,7 +43,7 @@ pub trait Extension {
fn calculate(&self, params: &Mapping, args: &Vec, current_vars: &HashMap) -> Option;
}
-pub fn get_extensions(clipboard_manager: Box) -> Vec> {
+pub fn get_extensions(config: &Configs, clipboard_manager: Box) -> Vec> {
vec![
Box::new(date::DateExtension::new()),
Box::new(shell::ShellExtension::new()),
@@ -52,5 +53,6 @@ pub fn get_extensions(clipboard_manager: Box) -> Vec = variables.into_iter().map(|variable| {
if variable.var_type == "global" {
@@ -131,8 +129,6 @@ impl super::Renderer for DefaultRenderer {
variable
}).collect();
- println!("{:?}", variables);
-
let mut output_map: HashMap = HashMap::new();
for variable in variables.into_iter() {
diff --git a/src/ui/modulo/mod.rs b/src/ui/modulo/mod.rs
index 93c7921..93c523c 100644
--- a/src/ui/modulo/mod.rs
+++ b/src/ui/modulo/mod.rs
@@ -12,10 +12,13 @@ pub struct ModuloManager {
impl ModuloManager {
pub fn new(config: &Configs) -> Self {
let mut modulo_path: Option = None;
- if let Some(ref _modulo_path) = config.modulo_path {
+ // Check if the `MODULO_PATH` env variable is configured
+ if let Some(_modulo_path) = std::env::var_os("MODULO_PATH") {
+ modulo_path = Some(_modulo_path.to_string_lossy().to_string())
+ } else if let Some(ref _modulo_path) = config.modulo_path { // Check the configs
modulo_path = Some(_modulo_path.to_owned());
}else{
- // First check in the same directory of espanso
+ // Check in the same directory of espanso
if let Ok(exe_path) = std::env::current_exe() {
if let Some(parent) = exe_path.parent() {
let possible_path = parent.join("modulo");
@@ -59,16 +62,18 @@ impl ModuloManager {
None
}
- fn invoke(&self, args: &[&str], body: &str) -> Option {
+ pub fn invoke(&self, args: &[&str], body: &str) -> Option {
if self.modulo_path.is_none() {
error!("Attempt to invoke modulo even though it's not configured");
return None;
}
if let Some(ref modulo_path) = self.modulo_path {
- let mut child = Command::new(modulo_path)
+ let child = Command::new(modulo_path)
.args(args)
.stdin(std::process::Stdio::piped())
+ .stdout(std::process::Stdio::piped())
+ .stderr(std::process::Stdio::piped())
.spawn();
match child {