Add form extension
This commit is contained in:
parent
a6b78e7142
commit
45f90c87ed
78
src/extension/form.rs
Normal file
78
src/extension/form.rs
Normal file
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<String>, _: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult> {
|
||||||
|
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<HashMap<String, String>, _> = 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::clipboard::ClipboardManager;
|
use crate::{config::Configs, clipboard::ClipboardManager};
|
||||||
use serde_yaml::Mapping;
|
use serde_yaml::Mapping;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ mod shell;
|
||||||
pub mod multiecho;
|
pub mod multiecho;
|
||||||
pub mod vardummy;
|
pub mod vardummy;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
mod form;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum ExtensionResult {
|
pub enum ExtensionResult {
|
||||||
|
@ -42,7 +43,7 @@ pub trait Extension {
|
||||||
fn calculate(&self, params: &Mapping, args: &Vec<String>, current_vars: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult>;
|
fn calculate(&self, params: &Mapping, args: &Vec<String>, current_vars: &HashMap<String, ExtensionResult>) -> Option<ExtensionResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_extensions(clipboard_manager: Box<dyn ClipboardManager>) -> Vec<Box<dyn Extension>> {
|
pub fn get_extensions(config: &Configs, clipboard_manager: Box<dyn ClipboardManager>) -> Vec<Box<dyn Extension>> {
|
||||||
vec![
|
vec![
|
||||||
Box::new(date::DateExtension::new()),
|
Box::new(date::DateExtension::new()),
|
||||||
Box::new(shell::ShellExtension::new()),
|
Box::new(shell::ShellExtension::new()),
|
||||||
|
@ -52,5 +53,6 @@ pub fn get_extensions(clipboard_manager: Box<dyn ClipboardManager>) -> Vec<Box<d
|
||||||
Box::new(dummy::DummyExtension::new("dummy")),
|
Box::new(dummy::DummyExtension::new("dummy")),
|
||||||
Box::new(dummy::DummyExtension::new("echo")),
|
Box::new(dummy::DummyExtension::new("echo")),
|
||||||
Box::new(clipboard::ClipboardExtension::new(clipboard_manager)),
|
Box::new(clipboard::ClipboardExtension::new(clipboard_manager)),
|
||||||
|
Box::new(form::FormExtension::new(config)),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -671,7 +671,7 @@ fn worker_background(
|
||||||
|
|
||||||
let keyboard_manager = keyboard::get_manager();
|
let keyboard_manager = keyboard::get_manager();
|
||||||
|
|
||||||
let extensions = extension::get_extensions(Box::new(clipboard::get_manager()));
|
let extensions = extension::get_extensions(config_manager.default_config(), Box::new(clipboard::get_manager()));
|
||||||
|
|
||||||
let renderer =
|
let renderer =
|
||||||
render::default::DefaultRenderer::new(extensions, config_manager.default_config().clone());
|
render::default::DefaultRenderer::new(extensions, config_manager.default_config().clone());
|
||||||
|
|
|
@ -119,8 +119,6 @@ impl super::Renderer for DefaultRenderer {
|
||||||
// Then the ones explicitly specified, in the given order
|
// Then the ones explicitly specified, in the given order
|
||||||
variables.extend(&content.vars);
|
variables.extend(&content.vars);
|
||||||
|
|
||||||
println!("{:?}", variables);
|
|
||||||
|
|
||||||
// Replace variable type "global" with the actual reference
|
// Replace variable type "global" with the actual reference
|
||||||
let variables: Vec<&MatchVariable> = variables.into_iter().map(|variable| {
|
let variables: Vec<&MatchVariable> = variables.into_iter().map(|variable| {
|
||||||
if variable.var_type == "global" {
|
if variable.var_type == "global" {
|
||||||
|
@ -131,8 +129,6 @@ impl super::Renderer for DefaultRenderer {
|
||||||
variable
|
variable
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
println!("{:?}", variables);
|
|
||||||
|
|
||||||
let mut output_map: HashMap<String, ExtensionResult> = HashMap::new();
|
let mut output_map: HashMap<String, ExtensionResult> = HashMap::new();
|
||||||
|
|
||||||
for variable in variables.into_iter() {
|
for variable in variables.into_iter() {
|
||||||
|
|
|
@ -12,10 +12,13 @@ pub struct ModuloManager {
|
||||||
impl ModuloManager {
|
impl ModuloManager {
|
||||||
pub fn new(config: &Configs) -> Self {
|
pub fn new(config: &Configs) -> Self {
|
||||||
let mut modulo_path: Option<String> = None;
|
let mut modulo_path: Option<String> = 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());
|
modulo_path = Some(_modulo_path.to_owned());
|
||||||
}else{
|
}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 Ok(exe_path) = std::env::current_exe() {
|
||||||
if let Some(parent) = exe_path.parent() {
|
if let Some(parent) = exe_path.parent() {
|
||||||
let possible_path = parent.join("modulo");
|
let possible_path = parent.join("modulo");
|
||||||
|
@ -59,16 +62,18 @@ impl ModuloManager {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invoke(&self, args: &[&str], body: &str) -> Option<String> {
|
pub fn invoke(&self, args: &[&str], body: &str) -> Option<String> {
|
||||||
if self.modulo_path.is_none() {
|
if self.modulo_path.is_none() {
|
||||||
error!("Attempt to invoke modulo even though it's not configured");
|
error!("Attempt to invoke modulo even though it's not configured");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref modulo_path) = self.modulo_path {
|
if let Some(ref modulo_path) = self.modulo_path {
|
||||||
let mut child = Command::new(modulo_path)
|
let child = Command::new(modulo_path)
|
||||||
.args(args)
|
.args(args)
|
||||||
.stdin(std::process::Stdio::piped())
|
.stdin(std::process::Stdio::piped())
|
||||||
|
.stdout(std::process::Stdio::piped())
|
||||||
|
.stderr(std::process::Stdio::piped())
|
||||||
.spawn();
|
.spawn();
|
||||||
|
|
||||||
match child {
|
match child {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user