Skip to content

Commit

Permalink
refactor: add history mod
Browse files Browse the repository at this point in the history
  • Loading branch information
pythops committed Jan 23, 2024
1 parent e19682f commit b670058
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 154 deletions.
15 changes: 3 additions & 12 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::help::Help;
use crate::history::History;
use crate::prompt::Prompt;
use std;
use std::collections::HashMap;
Expand All @@ -14,7 +15,7 @@ use std::sync::Arc;

pub type AppResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;

#[derive(Debug, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub enum FocusedBlock {
Prompt,
Chat,
Expand All @@ -23,16 +24,6 @@ pub enum FocusedBlock {
Help,
}

#[derive(Debug, Default, Clone)]
pub struct History<'a> {
pub show: bool,
pub index: usize,
pub chat: Vec<Vec<String>>,
pub formatted_chat: Vec<Text<'a>>,
pub scroll: u16,
pub length: u16,
}

#[derive(Debug, Default)]
pub struct Chat<'a> {
pub messages: Vec<String>,
Expand Down Expand Up @@ -73,7 +64,7 @@ impl<'a> App<'a> {
focused_block: FocusedBlock::Prompt,
llm_messages: Vec::new(),
answer: Answer::default(),
history: History::default(),
history: History::new(),
notifications: Vec::new(),
spinner: Spinner::default(),
terminate_response_signal: Arc::new(AtomicBool::new(false)),
Expand Down
71 changes: 23 additions & 48 deletions src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,15 @@ pub fn handle_key_events(
// scroll down
KeyCode::Char('j') | KeyCode::Down => match app.focused_block {
FocusedBlock::History => {
if !app.history.formatted_chat.is_empty()
&& app.history.index < app.history.chat.len() - 1
{
app.history.index += 1;
}
app.history.scroll_down();
}

FocusedBlock::Chat => {
app.chat.scroll = app.chat.scroll.saturating_add(1);
}

FocusedBlock::Preview => {
app.history.scroll = app.history.scroll.saturating_add(1);
app.history.preview.scroll = app.history.preview.scroll.saturating_add(1);
}
FocusedBlock::Help => {
app.help.scroll_down();
Expand All @@ -64,10 +60,10 @@ pub fn handle_key_events(

// scroll up
KeyCode::Char('k') | KeyCode::Up => match app.focused_block {
FocusedBlock::History => app.history.index = app.history.index.saturating_sub(1),
FocusedBlock::History => app.history.scroll_up(),

FocusedBlock::Preview => {
app.history.scroll = app.history.scroll.saturating_sub(1);
app.history.preview.scroll = app.history.preview.scroll.saturating_sub(1);
}

FocusedBlock::Chat => {
Expand All @@ -81,6 +77,16 @@ pub fn handle_key_events(
_ => (),
},

// `G`: Mo to the bottom
KeyCode::Char('G') => match app.focused_block {
FocusedBlock::Chat => app.chat.scroll = app.chat.length,
FocusedBlock::History => app.history.move_to_bottom(),
_ => (),
},

// `gg`: Move to the top
//TODO:

// New chat
KeyCode::Char(c)
if c == app.config.key_bindings.new_chat
Expand All @@ -89,9 +95,12 @@ pub fn handle_key_events(
app.prompt.clear();

app.history
.formatted_chat
.preview
.text
.push(app.chat.formatted_chat.clone());
app.history.chat.push(app.chat.messages.clone());

app.history.text.push(app.chat.messages.clone());

app.chat = Chat::default();
app.llm_messages = Vec::new();

Expand All @@ -105,30 +114,8 @@ pub fn handle_key_events(
{
match app.focused_block {
FocusedBlock::History | FocusedBlock::Preview => {
if !app.history.chat.is_empty() {
match std::fs::write(
&app.config.archive_file_name,
app.history.chat[app.history.index].join(""),
) {
Ok(_) => {
let notif = Notification::new(
format!(
"Chat saved to `{}` file",
app.config.archive_file_name
),
NotificationLevel::Info,
);

sender.send(Event::Notification(notif)).unwrap();
}
Err(e) => {
let notif =
Notification::new(e.to_string(), NotificationLevel::Error);

sender.send(Event::Notification(notif)).unwrap();
}
}
}
app.history
.save(app.config.archive_file_name.as_str(), sender.clone());
}
FocusedBlock::Chat | FocusedBlock::Prompt => {
match std::fs::write(
Expand Down Expand Up @@ -170,11 +157,11 @@ pub fn handle_key_events(
}
FocusedBlock::History => {
app.focused_block = FocusedBlock::Preview;
app.history.scroll = 0;
app.history.preview.scroll = 0;
}
FocusedBlock::Preview => {
app.focused_block = FocusedBlock::History;
app.history.scroll = 0;
app.history.preview.scroll = 0;
}
_ => (),
},
Expand Down Expand Up @@ -203,18 +190,6 @@ pub fn handle_key_events(
_ => {}
},

// Go to the end: G
KeyCode::Char('G') => match app.focused_block {
FocusedBlock::Chat => app.chat.scroll = app.chat.length,
FocusedBlock::History => {
if !app.history.formatted_chat.is_empty() {
app.history.index = app.history.formatted_chat.len() - 1;
}
}
FocusedBlock::Preview => app.history.scroll = app.history.length,
_ => (),
},

_ => {}
}

Expand Down
172 changes: 172 additions & 0 deletions src/history.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
use std::sync::mpsc::Sender;

use ratatui::{
layout::{Alignment, Constraint, Direction, Layout, Rect},
style::{Color, Style},
text::Text,
widgets::{Block, BorderType, Borders, Clear, List, ListItem, ListState, Paragraph, Wrap},
Frame,
};

use crate::{
app::FocusedBlock,
event::Event,
notification::{Notification, NotificationLevel},
};

#[derive(Debug, Default, Clone)]
pub struct Preview<'a> {
pub text: Vec<Text<'a>>,
pub scroll: usize,
}

#[derive(Debug, Default, Clone)]
pub struct History<'a> {
block_height: usize,
state: ListState,
pub text: Vec<Vec<String>>,
pub preview: Preview<'a>,
}

impl History<'_> {
pub fn new() -> Self {
Self {
block_height: 0,
state: ListState::default(),
text: Vec::new(),
preview: Preview::default(),
}
}

pub fn move_to_bottom(&mut self) {
if !self.text.is_empty() {
self.state.select(Some(self.text.len() - 1));
}
}

pub fn move_to_top(&mut self) {
if !self.text.is_empty() {
self.state.select(Some(0));
}
}

pub fn scroll_down(&mut self) {
if self.text.is_empty() {
return;
}
let i = match self.state.selected() {
Some(i) => {
if i < self.text.len() - 1 {
i + 1
} else {
i
}
}
None => 0,
};
self.state.select(Some(i));
}
pub fn scroll_up(&mut self) {
if self.text.is_empty() {
return;
}
let i = match self.state.selected() {
Some(i) => {
if i > 1 {
i - 1
} else {
0
}
}
None => 0,
};
self.state.select(Some(i));
}

pub fn save(&mut self, archive_file_name: &str, sender: Sender<Event>) {
if !self.text.is_empty() {
match std::fs::write(
archive_file_name,
self.text[self.state.selected().unwrap_or(0)].join(""),
) {
Ok(_) => {
let notif = Notification::new(
format!("Chat saved to `{}` file", archive_file_name),
NotificationLevel::Info,
);

sender.send(Event::Notification(notif)).unwrap();
}
Err(e) => {
let notif = Notification::new(e.to_string(), NotificationLevel::Error);

sender.send(Event::Notification(notif)).unwrap();
}
}
}
}

pub fn render(&mut self, frame: &mut Frame, area: Rect, focused_block: FocusedBlock) {
self.block_height = area.height as usize;

if !self.text.is_empty() && self.state.selected().is_none() {
*self.state.offset_mut() = 0;
self.state.select(Some(0));
}

let (history_block, preview_block) = {
let chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(area);
(chunks[0], chunks[1])
};

let items = self
.text
.iter()
.map(|chat| match chat.first() {
Some(v) => ListItem::new(v.to_owned()),
None => ListItem::new(""),
})
.collect::<Vec<ListItem>>();

let list = List::new(items)
.block(
Block::default()
.borders(Borders::ALL)
.title(" History ")
.title_alignment(Alignment::Center)
.style(Style::default())
.border_style(Style::default())
.border_type(match focused_block {
FocusedBlock::History => BorderType::Thick,
_ => BorderType::Rounded,
}),
)
.highlight_style(Style::default().bg(Color::DarkGray));

let preview = Paragraph::new(match self.state.selected() {
Some(i) => self.preview.text[i].clone(),
None => Text::raw(""),
})
.wrap(Wrap { trim: false })
.scroll((self.preview.scroll as u16, 0))
.block(
Block::default()
.title(" Preview ")
.title_alignment(Alignment::Center)
.borders(Borders::ALL)
.style(Style::default())
.border_style(Style::default())
.border_type(match focused_block {
FocusedBlock::Preview => BorderType::Thick,
_ => BorderType::Rounded,
}),
);

frame.render_widget(Clear, area);
frame.render_widget(preview, preview_block);
frame.render_stateful_widget(list, history_block, &mut self.state);
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ pub mod formatter;
pub mod prompt;

pub mod help;

pub mod history;
Loading

0 comments on commit b670058

Please sign in to comment.