Skip to content

Commit

Permalink
Merge branch 'features/variables'
Browse files Browse the repository at this point in the history
  • Loading branch information
TheRealLorenz committed Feb 17, 2024
2 parents c74933a + 92bd67b commit 8356d33
Show file tree
Hide file tree
Showing 18 changed files with 837 additions and 182 deletions.
7 changes: 6 additions & 1 deletion demo.http
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ Foo: Bar

###

POST https://httpbin.org/post
@endpoint = httpbin.org
@method = post

###

POST https://{{endpoint}}/{{method}}
Bar: Baz

{
Expand Down
103 changes: 72 additions & 31 deletions rq-cli/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use ratatui::{
widgets::{Block, Borders},
};
use rq_core::{
parser::{HttpFile, HttpRequest},
parser::{HttpFile, HttpRequest, TemplateRequest},
request::Response,
};
use tokio::sync::mpsc::{channel, Receiver, Sender};
Expand All @@ -16,8 +16,8 @@ use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};

use crate::{
components::{
input::InputComponent, legend::Legend, menu::Menu, message_dialog::MessageDialog,
popup::Popup, response_panel::ResponsePanel, BlockComponent, HandleSuccess,
legend::Legend, menu::Menu, message_dialog::MessageDialog, popup::Popup,
response_panel::ResponsePanel, variables::panel::VarsPanel, BlockComponent, HandleSuccess,
},
event::{Event, Message},
};
Expand All @@ -27,16 +27,20 @@ pub enum FocusState {
#[default]
RequestsList,
ResponsePanel,
VarsPanel,
}

pub struct App {
res_rx: Receiver<(Response, usize)>,
req_tx: Sender<(HttpRequest, usize)>,

request_menu: Menu<HttpRequest>,
request_menu: Menu<TemplateRequest>,
vars_panel: VarsPanel,
file_path: String,

responses: Vec<ResponsePanel>,
should_exit: bool,
file_path: String,
vars_visible: bool,
focus: FocusState,
popups: VecDeque<Box<dyn BlockComponent>>,
}
Expand All @@ -47,19 +51,19 @@ fn spawn_request_handler(
) {
tokio::spawn(async move {
while let Some((req, i)) = req_rx.recv().await {
match rq_core::request::execute(&req).await {
match rq_core::request::execute(req).await {
Ok(data) => res_tx.send((data, i)).await.unwrap(),
Err(e) => {
Event::emit(Event::Message(Message::Error(e.to_string())));
continue;
}
};
}
});
}

impl App {
const KEYMAPS: &'static [(&'static str, &'static str); 1] = &[("q", "exit")];
const KEYMAPS: &'static [(&'static str, &'static str); 2] =
&[("q", "exit"), ("v", "variables")];

pub fn new(file_path: String, http_file: HttpFile) -> Self {
let (req_tx, req_rx) = channel::<(HttpRequest, usize)>(1);
Expand All @@ -75,12 +79,15 @@ impl App {
.with_confirm_callback(|_| Event::emit(Event::Focus(FocusState::ResponsePanel)));

App {
file_path,
res_rx,
req_tx,

request_menu,
file_path,
vars_panel: VarsPanel::new(http_file.variables),
responses,
should_exit: false,
vars_visible: true,
focus: FocusState::default(),
popups: VecDeque::new(),
}
Expand All @@ -107,6 +114,7 @@ impl App {
let event_result = match self.focus {
FocusState::RequestsList => self.request_menu.on_event(event),
FocusState::ResponsePanel => self.responses[self.request_menu.idx()].on_event(event),
FocusState::VarsPanel => self.vars_panel.on_event(event),
};

match event_result {
Expand All @@ -117,8 +125,12 @@ impl App {
Err(e) => return Err(e),
};

if let KeyCode::Char('q' | 'Q') = event.code {
self.should_exit = true;
match event.code {
KeyCode::Char('q' | 'Q') => {
self.should_exit = true;
}
KeyCode::Char('v') => Event::emit(Event::Focus(FocusState::VarsPanel)),
_ => (),
};

Ok(())
Expand All @@ -135,7 +147,7 @@ impl App {
};

// Create two chunks with equal screen space
let [list_chunk, response_chunk] = {
let [mut list_chunk, response_chunk] = {
let x = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
Expand All @@ -144,17 +156,26 @@ impl App {
[x[0], x[1]]
};

let (list_border_style, response_border_style, legend) = match self.focus {
let (list_border_style, response_border_style, vars_border_style, legend) = match self.focus
{
FocusState::RequestsList => (
Style::default().fg(Color::Blue),
Style::default(),
Style::default(),
Legend::new(Self::KEYMAPS.iter().chain(self.request_menu.keymaps())),
),
FocusState::ResponsePanel => (
Style::default(),
Style::default().fg(Color::Blue),
Style::default(),
Legend::new(Self::KEYMAPS.iter().chain(self.responses[0].keymaps())),
),
FocusState::VarsPanel => (
Style::default(),
Style::default(),
Style::default().fg(Color::Blue),
Legend::new(Self::KEYMAPS.iter().chain(self.vars_panel.keymaps())),
),
};

let list_block = Block::default()
Expand All @@ -166,6 +187,25 @@ impl App {
.borders(Borders::ALL)
.border_style(response_border_style);

if self.vars_visible {
let [new_list_chunk, var_chunk] = {
let x = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Percentage(70), Constraint::Percentage(30)])
.split(list_chunk);

[x[0], x[1]]
};

list_chunk = new_list_chunk;

let var_block = Block::default()
.borders(Borders::ALL)
.border_style(vars_border_style);

self.vars_panel.render(f, var_chunk, var_block);
}

self.request_menu.render(f, list_chunk, list_block);
let response_panel = &self.responses[self.request_menu.idx()];
response_panel.render(f, response_chunk, response_block);
Expand Down Expand Up @@ -203,38 +243,39 @@ impl App {
self.responses[self.request_menu.idx()].save_body(&file_name)
}
},
Event::NewInput((content, typ)) => {
match typ {
crate::event::InputType::FileName(save_option) => {
self.popups.push_back(Box::new(Popup::new(
InputComponent::from(content.as_str())
.with_cursor(0)
.with_confirm_callback(move |value| {
Event::emit(Event::PopupDismiss);
Event::emit(Event::Save((value, save_option)));
}),
)));
}
};
Event::NewInput(builder) => {
self.popups.push_back(Box::new(Popup::new(builder.build())));
Ok(())
}
Event::PopupDismiss => {
Event::PopupDismiss | Event::InputConfirm | Event::InputCancel => {
self.popups.pop_front();
Ok(())
}
Event::SendRequest(idx) => {
self.responses[idx].set_loading();

self.req_tx
.send((self.request_menu.get(idx).clone(), idx))
.await
.map_err(|e| anyhow!(e))
match self.request_menu.get(idx).fill(self.vars_panel.vars()) {
Ok(request) => self
.req_tx
.send((request, idx))
.await
.map_err(|e| anyhow!(e)),

Err(e) => Err(anyhow!(e)),
}
}
Event::Message(message) => {
self.popups
.push_back(Box::new(Popup::new(MessageDialog::new(message))));
Ok(())
}
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 {
Event::emit(Event::Message(Message::Error(e.to_string())));
Expand Down
12 changes: 7 additions & 5 deletions rq-cli/src/components/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use crate::event::Event;

use super::BlockComponent;

pub mod builder;

type ConfirmCallback = Box<dyn Fn(String)>;
type CancelCallback = Box<dyn Fn()>;

Expand All @@ -20,27 +22,27 @@ impl Default for InputComponent {
Self {
input: Input::default(),
on_confirm_callback: None,
on_cancel_callback: Box::new(|| Event::emit(Event::PopupDismiss)),
on_cancel_callback: Box::new(|| Event::emit(Event::InputCancel)),
}
}
}

impl InputComponent {
pub fn from(value: &str) -> Self {
fn from(value: &str) -> Self {
Self {
input: Input::from(value),
..Self::default()
}
}

pub fn with_cursor(self, cursor: usize) -> Self {
fn with_cursor(self, cursor: usize) -> Self {
Self {
input: self.input.with_cursor(cursor),
..self
}
}

pub fn with_confirm_callback<F>(self, confirm_callback: F) -> Self
fn with_confirm_callback<F>(self, confirm_callback: F) -> Self
where
F: Fn(String) + 'static,
{
Expand All @@ -50,7 +52,7 @@ impl InputComponent {
}
}

pub fn with_cancel_callback<F>(self, cancel_callback: F) -> Self
fn with_cancel_callback<F>(self, cancel_callback: F) -> Self

Check failure on line 55 in rq-cli/src/components/input.rs

View workflow job for this annotation

GitHub Actions / CI

method `with_cancel_callback` is never used
where
F: Fn() + 'static,
{
Expand Down
59 changes: 59 additions & 0 deletions rq-cli/src/components/input/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::{components::response_panel::SaveOption, event::Event};

use super::InputComponent;

pub struct InputBuilder {
content: String,
cursor: Option<usize>,
typ: InputType,
}

pub enum InputType {
FileName(SaveOption),
VarValue(String),
}

impl InputBuilder {
pub fn new(typ: InputType) -> Self {
Self {
content: String::new(),
cursor: None,
typ,
}
}

pub fn with_content(self, content: String) -> Self {
Self { content, ..self }
}

pub fn with_cursor(self, cursor: usize) -> Self {
Self {
cursor: Some(cursor),
..self
}
}

fn build_component(&self) -> InputComponent {
let input = InputComponent::from(&self.content);

match self.cursor {
Some(i) => input.with_cursor(i),
None => input,
}
}

pub fn build(self) -> InputComponent {
let input = self.build_component();

match self.typ {
InputType::FileName(save_option) => input.with_confirm_callback(move |value| {
Event::emit(Event::InputConfirm);
Event::emit(Event::Save((value, save_option)));
}),
InputType::VarValue(name) => input.with_confirm_callback(move |value| {
Event::emit(Event::InputConfirm);
Event::emit(Event::UpdateVar((name.clone(), value)));
}),
}
}
}
13 changes: 13 additions & 0 deletions rq-cli/src/components/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ impl<T: MenuItem> Menu<T> {
&self.items[idx]
}

pub fn update<P>(&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<F>(self, confirm_callback: F) -> Self
where
F: Fn(&T) + 'static,
Expand Down
3 changes: 2 additions & 1 deletion rq-cli/src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ use ratatui::{prelude::Rect, widgets::Block};

use crate::terminal::Frame;

pub mod http_request;
pub mod input;
pub mod legend;
pub mod menu;
pub mod message_dialog;
pub mod popup;
pub mod response_panel;
pub mod template_request;
pub mod variables;

pub enum HandleSuccess {
Consumed,
Expand Down
Loading

0 comments on commit 8356d33

Please sign in to comment.