diff --git a/rq-cli/src/app.rs b/rq-cli/src/app.rs index d963b79..88e2cf3 100644 --- a/rq-cli/src/app.rs +++ b/rq-cli/src/app.rs @@ -280,6 +280,16 @@ impl App { .popup(), ); } + crate::event::InputType::VarValue(name) => { + self.input_popup = Some( + InputComponent::from(content.as_str()) + .with_confirm_callback(move |value| { + Event::emit(Event::InputConfirm); + Event::emit(Event::UpdateVar((name.clone(), value))); + }) + .popup(), + ); + } }; Ok(()) } @@ -304,6 +314,13 @@ impl App { Err(e) => Err(anyhow!(e)), } } + Event::UpdateVar((name, value)) => match value.parse() { + Ok(value) => { + self.vars_panel.update(name, value); + Ok(()) + } + Err(e) => Err(anyhow!(e)), + }, }; if let Err(e) = result { MessageDialog::push_message(Message::Error(e.to_string())); diff --git a/rq-cli/src/components/menu.rs b/rq-cli/src/components/menu.rs index c1b277f..f8a2938 100644 --- a/rq-cli/src/components/menu.rs +++ b/rq-cli/src/components/menu.rs @@ -53,6 +53,19 @@ impl Menu { &self.items[idx] } + pub fn update

(&mut self, predicate: P, value: T) + where + P: Fn(&T) -> bool, + { + if let Some(idx) = self.items.iter().position(predicate) { + self.items[idx] = value; + } + } + + pub fn add(&mut self, value: T) { + self.items.push(value); + } + pub fn with_confirm_callback(self, confirm_callback: F) -> Self where F: Fn(&T) + 'static, diff --git a/rq-cli/src/components/variables/panel.rs b/rq-cli/src/components/variables/panel.rs index 1af5e5e..5b9749e 100644 --- a/rq-cli/src/components/variables/panel.rs +++ b/rq-cli/src/components/variables/panel.rs @@ -5,7 +5,7 @@ use rq_core::parser::variables::TemplateString; use crate::{ components::{menu::Menu, BlockComponent, HandleSuccess}, - event::Event, + event::{Event, InputType}, }; pub struct VarsPanel { @@ -15,15 +15,30 @@ pub struct VarsPanel { impl VarsPanel { pub fn new(vars: HashMap) -> Self { - Self { - menu: Menu::new(vars.iter().map(|(k, v)| (k.clone(), v.clone())).collect()), - vars, - } + let menu = Menu::new(vars.iter().map(|(k, v)| (k.clone(), v.clone())).collect()) + .with_confirm_callback(|(name, value)| { + Event::emit(Event::NewInput(( + value.to_string(), + InputType::VarValue(name.clone()), + ))); + }); + + Self { vars, menu } } pub fn vars(&self) -> &HashMap { &self.vars } + + pub fn update(&mut self, name: String, value: TemplateString) { + match self.vars.insert(name.clone(), value.clone()) { + Some(_) => { + let cloned = name.clone(); + self.menu.update(move |(n, _)| n == &cloned, (name, value)); + } + None => self.menu.add((name, value)), + }; + } } impl BlockComponent for VarsPanel { @@ -51,4 +66,8 @@ impl BlockComponent for VarsPanel { Ok(HandleSuccess::Ignored) } + + fn keymaps() -> impl Iterator { + std::iter::once(&("Esc", "back to list")).chain(Menu::<(String, TemplateString)>::keymaps()) + } } diff --git a/rq-cli/src/event.rs b/rq-cli/src/event.rs index 295f74d..39a24ab 100644 --- a/rq-cli/src/event.rs +++ b/rq-cli/src/event.rs @@ -13,12 +13,14 @@ pub enum Event { InputConfirm, InputCancel, SendRequest(usize), + UpdateVar((String, String)), Key(crossterm::event::KeyEvent), Other(crossterm::event::Event), } pub enum InputType { FileName(SaveOption), + VarValue(String), } impl Event { diff --git a/rq-core/src/parser/variables.rs b/rq-core/src/parser/variables.rs index 1d118f5..60ab6ee 100644 --- a/rq-core/src/parser/variables.rs +++ b/rq-core/src/parser/variables.rs @@ -1,9 +1,9 @@ -use std::{collections::HashMap, fmt::Display, hash::Hash, ops::Deref}; +use std::{collections::HashMap, fmt::Display, hash::Hash, ops::Deref, str::FromStr}; -use pest::iterators::Pair; +use pest::{iterators::Pair, Parser}; use thiserror::Error; -use super::{values, Rule}; +use super::{values, HttpParser, Rule}; #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct Variable { @@ -101,6 +101,18 @@ impl From> for TemplateString { } } +impl FromStr for TemplateString { + type Err = String; + + fn from_str(s: &str) -> Result { + Ok(HttpParser::parse(Rule::var_def_value, s) + .map_err(|e| e.to_string())? + .next() + .unwrap() + .into()) + } +} + #[derive(Debug, Error)] #[error("missing field '{}'", .missing_variable.name)] pub struct FillError {