Skip to content

Commit

Permalink
Merge pull request #26 from zaghaghi/feat/command-history
Browse files Browse the repository at this point in the history
Feat/command history
  • Loading branch information
zaghaghi committed May 1, 2024
2 parents 7846fff + 775a7fc commit f69a8fa
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 18 deletions.
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,21 @@ Then, add `openapi-tui` to your `configuration.nix`
| `:` | Run commands|
| `Backspace`, `b` | Get out of nested items in lists|

# Commands
# Commands Main Page
| Command | Description |
|:--------|:------------|
| `q` | Quit |
| `request` | Go to request page|
| `request`, `r` | Go to request page|
| `history` | Request history|

# Commands Request Page
| Command | Description |
|:--------|:------------|
| `q` | Quit |
| `send`, `s` | send request|



# Implemented Features
- [X] Viewer
- [X] OpenAPI v3.1
Expand All @@ -183,6 +191,7 @@ Then, add `openapi-tui` to your `configuration.nix`
# Next Release
- [ ] Import request body file
- [ ] Save response body and header
- [X] Command history with ↑/↓

# Backlog
- [ ] Schema Types (openapi-31)
Expand All @@ -191,3 +200,4 @@ Then, add `openapi-tui` to your `configuration.nix`
- [ ] Read Spec from STDIN
- [ ] Support array query strings
- [ ] Suppert extra headers
- [ ] Request progress bar
43 changes: 36 additions & 7 deletions src/pages/phone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ impl Page for Phone {
KeyCode::Char(']') => EventResponse::Stop(Action::TabNext),
KeyCode::Char('[') => EventResponse::Stop(Action::TabPrev),
KeyCode::Enter => EventResponse::Stop(Action::Submit),
KeyCode::Char(':') => EventResponse::Stop(Action::FocusFooter(":".into(), None)),
_ => {
return Ok(None);
},
Expand All @@ -157,33 +158,35 @@ impl Page for Phone {
}

fn update(&mut self, action: Action, state: &mut State) -> Result<Option<Action>> {
let mut actions: Vec<Option<Action>> = vec![];

match action {
Action::FocusNext => {
let next_index = self.focused_pane_index.saturating_add(1) % self.panes.len();
if let Some(pane) = self.panes.get_mut(self.focused_pane_index) {
pane.update(Action::UnFocus, state)?;
actions.push(pane.update(Action::UnFocus, state)?);
}
self.focused_pane_index = next_index;
if let Some(pane) = self.panes.get_mut(self.focused_pane_index) {
pane.update(Action::Focus, state)?;
actions.push(pane.update(Action::Focus, state)?);
}
},
Action::FocusPrev => {
let prev_index = self.focused_pane_index.saturating_add(self.panes.len() - 1) % self.panes.len();
if let Some(pane) = self.panes.get_mut(self.focused_pane_index) {
pane.update(Action::UnFocus, state)?;
actions.push(pane.update(Action::UnFocus, state)?);
}
self.focused_pane_index = prev_index;
if let Some(pane) = self.panes.get_mut(self.focused_pane_index) {
pane.update(Action::Focus, state)?;
actions.push(pane.update(Action::Focus, state)?);
}
},
Action::ToggleFullScreen => {
self.fullscreen_pane_index = self.fullscreen_pane_index.map_or(Some(self.focused_pane_index), |_| None);
},
Action::Update => {
for pane in self.panes.iter_mut() {
pane.update(action.clone(), state)?;
actions.push(pane.update(action.clone(), state)?);
}
},
Action::Dial => {
Expand All @@ -194,13 +197,39 @@ impl Page for Phone {
})?;
}
},

Action::FocusFooter(..) => {
if let Some(pane) = self.panes.get_mut(self.focused_pane_index) {
actions.push(pane.update(Action::UnFocus, state)?);
}
},
Action::FooterResult(cmd, Some(args)) if cmd.eq(":") => {
if let Some(pane) = self.panes.get_mut(self.focused_pane_index) {
pane.update(Action::Focus, state)?;
}
if args.eq("q") {
actions.push(Some(Action::Quit));
} else if args.eq("send") || args.eq("s") {
actions.push(Some(Action::Dial));
} else {
actions.push(Some(Action::TimedStatusLine("unknown command".into(), 1)));
}
},
Action::FooterResult(_cmd, None) => {
if let Some(pane) = self.panes.get_mut(self.focused_pane_index) {
actions.push(pane.update(Action::Focus, state)?);
}
},
_ => {
if let Some(pane) = self.panes.get_mut(self.focused_pane_index) {
return pane.update(action, state);
actions.push(pane.update(action, state)?);
}
},
}
if let Some(tx) = &mut self.command_tx {
actions.into_iter().flatten().for_each(|action| {
tx.send(action).ok();
});
}
Ok(None)
}

Expand Down
42 changes: 33 additions & 9 deletions src/panes/footer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::time::Instant;
use std::{collections::VecDeque, time::Instant};

use color_eyre::eyre::Result;
use crossterm::event::{Event, KeyCode, KeyEvent};
Expand All @@ -18,24 +18,26 @@ struct TimedStatusLine {
status_line: String,
}

struct Config {
max_command_history: usize,
}

static CONFIG: Config = Config { max_command_history: 20 };

#[derive(Default)]
pub struct FooterPane {
focused: bool,
input: Input,
command: String,
status_line: String,
timed_status_line: Option<TimedStatusLine>,
command_history: VecDeque<String>,
command_history_index: Option<usize>,
}

impl FooterPane {
pub fn new() -> Self {
Self {
focused: false,
input: Input::default(),
command: String::default(),
status_line: String::default(),
timed_status_line: None,
}
Self { focused: false, ..Default::default() }
}

fn get_status_line(&mut self) -> &String {
Expand All @@ -58,9 +60,31 @@ impl Pane for FooterPane {
self.input.handle_event(&Event::Key(key));
let response = match key.code {
KeyCode::Enter => {
self.command_history.push_front(self.input.to_string());
self.command_history.truncate(CONFIG.max_command_history);
self.command_history_index = None;
Some(EventResponse::Stop(Action::FooterResult(self.command.clone(), Some(self.input.to_string()))))
},
KeyCode::Esc => Some(EventResponse::Stop(Action::FooterResult(self.command.clone(), None))),
KeyCode::Esc => {
self.command_history_index = None;
Some(EventResponse::Stop(Action::FooterResult(self.command.clone(), None)))
},
KeyCode::Up if !self.command_history.is_empty() => {
let history_index =
self.command_history_index.map(|idx| idx.saturating_add(1) % self.command_history.len()).unwrap_or(0);
self.input = self.input.clone().with_value(self.command_history[history_index].clone());
self.command_history_index = Some(history_index);
None
},
KeyCode::Down if !self.command_history.is_empty() => {
let history_index = self
.command_history_index
.map(|idx| idx.saturating_add(self.command_history.len() - 1) % self.command_history.len())
.unwrap_or(self.command_history.len() - 1);
self.input = self.input.clone().with_value(self.command_history[history_index].clone());
self.command_history_index = Some(history_index);
None
},
_ => None,
};
Ok(response)
Expand Down

0 comments on commit f69a8fa

Please sign in to comment.