refactor(core): refactor modulo form invocation structure
This commit is contained in:
parent
248b62a6a2
commit
6d5507cc5f
|
@ -54,7 +54,8 @@ pub fn initialize_and_spawn(
|
||||||
super::engine::matcher::convert::MatchConverter::new(&*config_store, &*match_store);
|
super::engine::matcher::convert::MatchConverter::new(&*config_store, &*match_store);
|
||||||
let match_cache = super::engine::match_cache::MatchCache::load(&*config_store, &*match_store);
|
let match_cache = super::engine::match_cache::MatchCache::load(&*config_store, &*match_store);
|
||||||
|
|
||||||
let modulo_manager = ui::modulo::ModuloManager::new();
|
let modulo_manager = crate::gui::modulo::manager::ModuloManager::new();
|
||||||
|
let modulo_form_ui = crate::gui::modulo::form::ModuloFormUI::new(&modulo_manager, icon_paths.form_icon);
|
||||||
|
|
||||||
let (detect_source, modifier_state_store, sequencer) =
|
let (detect_source, modifier_state_store, sequencer) =
|
||||||
super::engine::source::init_and_spawn().expect("failed to initialize detector module");
|
super::engine::source::init_and_spawn().expect("failed to initialize detector module");
|
||||||
|
@ -94,8 +95,7 @@ pub fn initialize_and_spawn(
|
||||||
&paths.packages,
|
&paths.packages,
|
||||||
);
|
);
|
||||||
let shell_extension = espanso_render::extension::shell::ShellExtension::new(&paths.config);
|
let shell_extension = espanso_render::extension::shell::ShellExtension::new(&paths.config);
|
||||||
let form_adapter =
|
let form_adapter = ui::form::FormProviderAdapter::new(&modulo_form_ui);
|
||||||
ui::modulo::form::ModuloFormProviderAdapter::new(&modulo_manager, icon_paths.form_icon);
|
|
||||||
let form_extension = espanso_render::extension::form::FormExtension::new(&form_adapter);
|
let form_extension = espanso_render::extension::form::FormExtension::new(&form_adapter);
|
||||||
let renderer = espanso_render::create(vec![
|
let renderer = espanso_render::create(vec![
|
||||||
&clipboard_extension,
|
&clipboard_extension,
|
||||||
|
|
117
espanso/src/cli/worker/engine/ui/form.rs
Normal file
117
espanso/src/cli/worker/engine/ui/form.rs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019-2021 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 std::collections::HashMap;
|
||||||
|
|
||||||
|
use espanso_render::{
|
||||||
|
extension::form::{FormProvider, FormProviderResult},
|
||||||
|
Params, Value,
|
||||||
|
};
|
||||||
|
use log::error;
|
||||||
|
|
||||||
|
use crate::gui::{FormField, FormUI};
|
||||||
|
|
||||||
|
pub struct FormProviderAdapter<'a> {
|
||||||
|
form_ui: &'a dyn FormUI,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FormProviderAdapter<'a> {
|
||||||
|
pub fn new(form_ui: &'a dyn FormUI) -> Self {
|
||||||
|
Self { form_ui }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FormProvider for FormProviderAdapter<'a> {
|
||||||
|
fn show(&self, layout: &str, fields: &Params, _: &Params) -> FormProviderResult {
|
||||||
|
let fields = convert_fields(fields);
|
||||||
|
match self.form_ui.show(layout, &fields) {
|
||||||
|
Ok(Some(results)) => FormProviderResult::Success(results),
|
||||||
|
Ok(None) => FormProviderResult::Aborted,
|
||||||
|
Err(err) => FormProviderResult::Error(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test
|
||||||
|
fn convert_fields(fields: &Params) -> HashMap<String, FormField> {
|
||||||
|
let mut out = HashMap::new();
|
||||||
|
for (name, field) in fields {
|
||||||
|
let mut form_field = None;
|
||||||
|
|
||||||
|
if let Value::Object(params) = field {
|
||||||
|
if let Some(Value::String(field_type)) = params.get("type") {
|
||||||
|
form_field = match field_type.as_str() {
|
||||||
|
"text" => Some(FormField::Text {
|
||||||
|
default: params
|
||||||
|
.get("default")
|
||||||
|
.and_then(|val| val.as_string())
|
||||||
|
.cloned(),
|
||||||
|
multiline: params
|
||||||
|
.get("multiline")
|
||||||
|
.and_then(|val| val.as_bool())
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(false),
|
||||||
|
}),
|
||||||
|
"choice" => Some(FormField::Choice {
|
||||||
|
default: params
|
||||||
|
.get("default")
|
||||||
|
.and_then(|val| val.as_string())
|
||||||
|
.cloned(),
|
||||||
|
values: params
|
||||||
|
.get("values")
|
||||||
|
.and_then(|val| val.as_array())
|
||||||
|
.map(|arr| {
|
||||||
|
arr
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|choice| choice.as_string())
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default(),
|
||||||
|
}),
|
||||||
|
"list" => Some(FormField::List {
|
||||||
|
default: params
|
||||||
|
.get("default")
|
||||||
|
.and_then(|val| val.as_string())
|
||||||
|
.cloned(),
|
||||||
|
values: params
|
||||||
|
.get("values")
|
||||||
|
.and_then(|val| val.as_array())
|
||||||
|
.map(|arr| {
|
||||||
|
arr
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|choice| choice.as_string())
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default(),
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(form_field) = form_field {
|
||||||
|
out.insert(name.clone(), form_field);
|
||||||
|
} else {
|
||||||
|
error!("malformed form field format for '{}'", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
|
@ -17,5 +17,5 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub mod modulo;
|
pub mod form;
|
||||||
pub mod selector;
|
pub mod selector;
|
|
@ -1,125 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of espanso.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2019-2021 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 std::{collections::HashMap, path::PathBuf};
|
|
||||||
|
|
||||||
use super::ModuloManager;
|
|
||||||
use anyhow::Result;
|
|
||||||
use espanso_render::extension::form::{FormProvider, FormProviderResult};
|
|
||||||
use log::{error};
|
|
||||||
use serde::Serialize;
|
|
||||||
use serde_json::{Map, Value};
|
|
||||||
|
|
||||||
pub struct ModuloFormProviderAdapter<'a> {
|
|
||||||
manager: &'a ModuloManager,
|
|
||||||
icon_path: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ModuloFormProviderAdapter<'a> {
|
|
||||||
pub fn new(manager: &'a ModuloManager, icon_path: Option<PathBuf>) -> Self {
|
|
||||||
Self {
|
|
||||||
manager,
|
|
||||||
icon_path: icon_path.map(|path| path.to_string_lossy().to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FormProvider for ModuloFormProviderAdapter<'a> {
|
|
||||||
fn show(
|
|
||||||
&self,
|
|
||||||
layout: &str,
|
|
||||||
fields: &espanso_render::Params,
|
|
||||||
_: &espanso_render::Params,
|
|
||||||
) -> FormProviderResult {
|
|
||||||
let modulo_form_config = ModuloFormConfig {
|
|
||||||
icon: self.icon_path.as_deref(),
|
|
||||||
title: "espanso",
|
|
||||||
layout,
|
|
||||||
fields: convert_params_into_object(fields),
|
|
||||||
};
|
|
||||||
|
|
||||||
match serde_json::to_string(&modulo_form_config) {
|
|
||||||
Ok(json_config) => {
|
|
||||||
match self
|
|
||||||
.manager
|
|
||||||
.invoke(&["form", "-j", "-i", "-"], &json_config)
|
|
||||||
{
|
|
||||||
Ok(output) => {
|
|
||||||
let json: Result<HashMap<String, String>, _> = serde_json::from_str(&output);
|
|
||||||
match json {
|
|
||||||
Ok(json) => {
|
|
||||||
if json.is_empty() {
|
|
||||||
return FormProviderResult::Aborted;
|
|
||||||
} else {
|
|
||||||
return FormProviderResult::Success(json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
return FormProviderResult::Error(error.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
return FormProviderResult::Error(err.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
return FormProviderResult::Error(err.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
|
||||||
struct ModuloFormConfig<'a> {
|
|
||||||
icon: Option<&'a str>,
|
|
||||||
title: &'a str,
|
|
||||||
layout: &'a str,
|
|
||||||
fields: Map<String, Value>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
||||||
fn convert_params_into_object(params: &espanso_render::Params) -> Map<String, Value> {
|
|
||||||
let mut obj = Map::new();
|
|
||||||
for (field, value) in params {
|
|
||||||
obj.insert(field.clone(), convert_value(value));
|
|
||||||
}
|
|
||||||
obj
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: test
|
|
||||||
fn convert_value(value: &espanso_render::Value) -> Value {
|
|
||||||
match value {
|
|
||||||
espanso_render::Value::Null => Value::Null,
|
|
||||||
espanso_render::Value::Bool(value) => Value::Bool(*value),
|
|
||||||
espanso_render::Value::Number(num) => match num {
|
|
||||||
espanso_render::Number::Integer(val) => Value::Number((*val).into()),
|
|
||||||
espanso_render::Number::Float(val) => {
|
|
||||||
Value::Number(serde_json::Number::from_f64(*val).unwrap_or_else(|| {
|
|
||||||
error!("unable to convert float value to json");
|
|
||||||
0.into()
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
espanso_render::Value::String(value) => Value::String(value.clone()),
|
|
||||||
espanso_render::Value::Array(arr) => Value::Array(arr.into_iter().map(convert_value).collect()),
|
|
||||||
espanso_render::Value::Object(obj) => Value::Object(convert_params_into_object(obj)),
|
|
||||||
}
|
|
||||||
}
|
|
55
espanso/src/gui/mod.rs
Normal file
55
espanso/src/gui/mod.rs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019-2021 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 std::collections::HashMap;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
pub mod modulo;
|
||||||
|
|
||||||
|
pub trait SearchUI {
|
||||||
|
fn show(&self, items: &SearchItem) -> Result<Option<String>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SearchItem {
|
||||||
|
pub id: String,
|
||||||
|
pub label: String,
|
||||||
|
pub tag: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FormUI {
|
||||||
|
fn show(&self, layout: &str, fields: &HashMap<String, FormField>) -> Result<Option<HashMap<String, String>>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum FormField {
|
||||||
|
Text {
|
||||||
|
default: Option<String>,
|
||||||
|
multiline: bool,
|
||||||
|
},
|
||||||
|
Choice {
|
||||||
|
default: Option<String>,
|
||||||
|
values: Vec<String>,
|
||||||
|
},
|
||||||
|
List {
|
||||||
|
default: Option<String>,
|
||||||
|
values: Vec<String>,
|
||||||
|
}
|
||||||
|
}
|
107
espanso/src/gui/modulo/form.rs
Normal file
107
espanso/src/gui/modulo/form.rs
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019-2021 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::Serialize;
|
||||||
|
use serde_json::{json, Map, Value};
|
||||||
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
|
use crate::gui::{FormField, FormUI};
|
||||||
|
|
||||||
|
use super::manager::ModuloManager;
|
||||||
|
|
||||||
|
pub struct ModuloFormUI<'a> {
|
||||||
|
manager: &'a ModuloManager,
|
||||||
|
icon_path: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ModuloFormUI<'a> {
|
||||||
|
pub fn new(manager: &'a ModuloManager, icon_path: Option<PathBuf>) -> Self {
|
||||||
|
Self {
|
||||||
|
manager,
|
||||||
|
icon_path: icon_path.map(|path| path.to_string_lossy().to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FormUI for ModuloFormUI<'a> {
|
||||||
|
fn show(
|
||||||
|
&self,
|
||||||
|
layout: &str,
|
||||||
|
fields: &HashMap<String, FormField>,
|
||||||
|
) -> anyhow::Result<Option<HashMap<String, String>>> {
|
||||||
|
let modulo_form_config = ModuloFormConfig {
|
||||||
|
icon: self.icon_path.as_deref(),
|
||||||
|
title: "espanso",
|
||||||
|
layout,
|
||||||
|
fields: convert_fields_into_object(fields),
|
||||||
|
};
|
||||||
|
|
||||||
|
let json_config = serde_json::to_string(&modulo_form_config)?;
|
||||||
|
let output = self
|
||||||
|
.manager
|
||||||
|
.invoke(&["form", "-j", "-i", "-"], &json_config)?;
|
||||||
|
let json: Result<HashMap<String, String>, _> = serde_json::from_str(&output);
|
||||||
|
match json {
|
||||||
|
Ok(json) => {
|
||||||
|
if json.is_empty() {
|
||||||
|
return Ok(None);
|
||||||
|
} else {
|
||||||
|
return Ok(Some(json));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
return Err(error.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct ModuloFormConfig<'a> {
|
||||||
|
icon: Option<&'a str>,
|
||||||
|
title: &'a str,
|
||||||
|
layout: &'a str,
|
||||||
|
fields: Map<String, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test
|
||||||
|
fn convert_fields_into_object(fields: &HashMap<String, FormField>) -> Map<String, Value> {
|
||||||
|
let mut obj = Map::new();
|
||||||
|
for (name, field) in fields {
|
||||||
|
let value = match field {
|
||||||
|
FormField::Text { default, multiline } => json!({
|
||||||
|
"type": "text",
|
||||||
|
"default": default,
|
||||||
|
"multiline": multiline,
|
||||||
|
}),
|
||||||
|
FormField::Choice { default, values } => json!({
|
||||||
|
"type": "choice",
|
||||||
|
"default": default,
|
||||||
|
"values": values,
|
||||||
|
}),
|
||||||
|
FormField::List { default, values } => json!({
|
||||||
|
"type": "list",
|
||||||
|
"default": default,
|
||||||
|
"values": values,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
obj.insert(name.clone(), value);
|
||||||
|
}
|
||||||
|
obj
|
||||||
|
}
|
|
@ -23,8 +23,6 @@ use std::io::Write;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub mod form;
|
|
||||||
|
|
||||||
pub struct ModuloManager {
|
pub struct ModuloManager {
|
||||||
modulo_path: Option<String>,
|
modulo_path: Option<String>,
|
||||||
}
|
}
|
23
espanso/src/gui/modulo/mod.rs
Normal file
23
espanso/src/gui/modulo/mod.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* This file is part of espanso.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019-2021 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub mod form;
|
||||||
|
pub mod manager;
|
||||||
|
|
||||||
|
// TODO: implement FormUI and SearchUI traits using ModuloManager
|
|
@ -32,6 +32,7 @@ use simplelog::{
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod engine;
|
mod engine;
|
||||||
|
mod gui;
|
||||||
mod logging;
|
mod logging;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user