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);
|
||||
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) =
|
||||
super::engine::source::init_and_spawn().expect("failed to initialize detector module");
|
||||
|
@ -94,8 +95,7 @@ pub fn initialize_and_spawn(
|
|||
&paths.packages,
|
||||
);
|
||||
let shell_extension = espanso_render::extension::shell::ShellExtension::new(&paths.config);
|
||||
let form_adapter =
|
||||
ui::modulo::form::ModuloFormProviderAdapter::new(&modulo_manager, icon_paths.form_icon);
|
||||
let form_adapter = ui::form::FormProviderAdapter::new(&modulo_form_ui);
|
||||
let form_extension = espanso_render::extension::form::FormExtension::new(&form_adapter);
|
||||
let renderer = espanso_render::create(vec![
|
||||
&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/>.
|
||||
*/
|
||||
|
||||
pub mod modulo;
|
||||
pub mod form;
|
||||
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 thiserror::Error;
|
||||
|
||||
pub mod form;
|
||||
|
||||
pub struct ModuloManager {
|
||||
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 engine;
|
||||
mod gui;
|
||||
mod logging;
|
||||
mod util;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user