Skip to content

Commit

Permalink
wip - prompt layout
Browse files Browse the repository at this point in the history
  • Loading branch information
aprxi committed Jul 7, 2024
1 parent 9b4402e commit e978619
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 88 deletions.
18 changes: 8 additions & 10 deletions lumni/src/apps/builtin/llm/prompt/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::io;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use bytes::Bytes;

use bytes::Bytes;
use clap::{Arg, Command};
use crossterm::cursor::Show;
use crossterm::event::{
Expand All @@ -26,7 +26,7 @@ use tokio::time::{interval, timeout, Duration};

use super::chat::ChatSession;
use super::server::{ModelServer, PromptInstruction, ServerTrait};
use super::session::{TabSession, AppSession};
use super::session::{AppSession, TabSession};
use super::tui::{
ColorScheme, CommandLineAction, KeyEventHandler, PromptAction, TabUi,
TextWindowTrait, WindowEvent,
Expand All @@ -51,7 +51,8 @@ async fn prompt_app<B: Backend>(
.unwrap_or_else(|| defaults.get_color_scheme());

// add types
let (tx, mut rx): (mpsc::Sender<Bytes>, mpsc::Receiver<Bytes>) = mpsc::channel(CHANNEL_QUEUE_SIZE);
let (tx, mut rx): (mpsc::Sender<Bytes>, mpsc::Receiver<Bytes>) =
mpsc::channel(CHANNEL_QUEUE_SIZE);
let mut tick = interval(Duration::from_millis(1));
let keep_running = Arc::new(AtomicBool::new(false));
let mut current_mode = Some(WindowEvent::ResponseWindow);
Expand Down Expand Up @@ -494,17 +495,14 @@ async fn send_prompt<'a>(
&formatted_prompt,
Some(color_scheme.get_primary_style()),
);
tab.ui.response.text_append_with_insert(
"\n",
Some(Style::reset()),
);


tab.ui
.response
.text_append_with_insert("\n", Some(Style::reset()));
}
Err(e) => {
log::error!("Error sending message: {:?}", e);
tab.ui.command_line.set_alert(&e.to_string());
}
}
Ok(())
}
}
3 changes: 0 additions & 3 deletions lumni/src/apps/builtin/llm/prompt/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ impl TabSession<'_> {
&mut self,
terminal: &mut Terminal<B>,
) -> Result<(), io::Error> {
// Set the response window title to current server name
self.ui.response.set_window_title(self.chat.server_name());

// draw the UI in the terminal
draw_ui(terminal, self)?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -801,22 +801,30 @@ impl TextBuffer<'_> {
let span_length = span.content.len();
if line_column < span_length {
let mut chars = span.content.chars();
let before = chars.by_ref().take(line_column).collect::<String>();
let before = chars
.by_ref()
.take(line_column)
.collect::<String>();
let cursor_char = chars.next().unwrap_or(' '); // Safely get the cursor character or space if none
let after = chars.collect::<String>();

if !before.is_empty() {
new_spans.push(Span::styled(before, span.style));
}

new_spans.push(Span::styled(cursor_char.to_string(), span.style.bg(Color::Yellow)));


new_spans.push(Span::styled(
cursor_char.to_string(),
span.style.bg(Color::Yellow),
));

if !after.is_empty() {
new_spans.push(Span::styled(after, span.style));
}

// Add remaining spans as is
new_spans.extend(spans.iter().skip(span_offset + 1).cloned());
new_spans.extend(
spans.iter().skip(span_offset + 1).cloned(),
);
break;
} else {
new_spans.push(span.clone());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,7 @@ impl<'a> TextWindow<'a> {
}

if let Some(hint) = self.window_type.hint() {
block = block
.title(hint)
block = block.title(hint)
}

let start_idx = self.scroller.vertical_scroll;
Expand Down Expand Up @@ -353,10 +352,6 @@ pub trait TextWindowTrait<'a> {
self.set_window_status(WindowStatus::Background);
}

fn set_window_title(&mut self, title: &str) {
self.base().window_type.set_title_text(title);
}

fn is_status_insert(&mut self) -> bool {
self.window_status() == WindowStatus::Insert
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use ratatui::layout::Alignment;
use ratatui::style::{Color, Style, Stylize};
use ratatui::widgets::block::{Title, Position};
use ratatui::widgets::block::{Position, Title};
use ratatui::widgets::Borders;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -45,31 +45,32 @@ impl WindowConfig {

pub fn hint(&self) -> Option<Title> {
match self.kind {
WindowKind::PromptWindow => {
match self.status {
WindowStatus::Normal | WindowStatus::Background => {
Some(Title::from("press Enter to send prompt".dark_gray()).alignment(Alignment::Right).position(Position::Bottom))
}
WindowStatus::Insert => {
Some(Title::from("press Tab or Esc to exit insert mode".dark_gray()).alignment(Alignment::Right).position(Position::Bottom))
}
_ => None,
}
}
WindowKind::PromptWindow => match self.status {
WindowStatus::Normal | WindowStatus::Background => Some(
Title::from("press Enter to send prompt".dark_gray())
.alignment(Alignment::Right)
.position(Position::Bottom),
),
WindowStatus::Insert => Some(
Title::from(
"press Tab or Esc to exit insert mode".dark_gray(),
)
.alignment(Alignment::Right)
.position(Position::Bottom),
),
_ => None,
},
_ => None,
}
}

pub fn set_title_text(&mut self, title: &str) -> &Self {
self.title = Some(title.to_string());
self
}

pub fn placeholder_text(&self) -> &str {
match self.kind {
WindowKind::ResponseWindow => "",
WindowKind::PromptWindow => match self.status {
WindowStatus::Normal | WindowStatus::Background => "Press i to enter insert mode",
WindowStatus::Normal | WindowStatus::Background => {
"Press i to enter insert mode"
}
WindowStatus::Visual => "",
WindowStatus::InActive => "",
WindowStatus::Insert => "Type text",
Expand All @@ -80,7 +81,7 @@ impl WindowConfig {

pub fn borders(&self) -> Borders {
match self.kind {
WindowKind::ResponseWindow => Borders::ALL,
WindowKind::ResponseWindow => Borders::NONE,
WindowKind::PromptWindow => Borders::ALL,
WindowKind::CommandLine => Borders::NONE,
}
Expand All @@ -97,11 +98,21 @@ impl WindowConfig {
let light_gray = Color::Rgb(128, 128, 128);
let light_yellow = Color::Rgb(192, 192, 96);
match self.status {
WindowStatus::Normal => Style::default().fg(Color::LightGreen),
WindowStatus::Background => Style::default().fg(light_gray),
WindowStatus::Insert => Style::default().fg(Color::LightBlue),
WindowStatus::Visual => Style::default().fg(light_yellow),
WindowStatus::InActive => Style::default().fg(light_gray),
WindowStatus::Normal => {
Style::default().fg(Color::White).bg(Color::Black)
}
WindowStatus::Background => {
Style::default().fg(light_gray).bg(Color::Black)
}
WindowStatus::Insert => {
Style::default().fg(Color::LightBlue).bg(Color::Black)
}
WindowStatus::Visual => {
Style::default().fg(light_yellow).bg(Color::Black)
}
WindowStatus::InActive => {
Style::default().fg(light_gray).bg(Color::Black)
}
}
}

Expand Down
85 changes: 60 additions & 25 deletions lumni/src/apps/builtin/llm/prompt/src/tui/draw.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use std::io;

use ratatui::backend::Backend;
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::widgets::{Scrollbar, ScrollbarOrientation};
use ratatui::layout::{Alignment, Constraint, Direction, Layout, Rect};
use ratatui::style::{Color, Style};
use ratatui::text::Text;
use ratatui::widgets::block::{Padding, Position, Title};
use ratatui::widgets::{
Block, Borders, Paragraph, Scrollbar, ScrollbarOrientation, ScrollbarState,
};
use ratatui::Terminal;

use super::components::TextWindowTrait;
Expand All @@ -13,66 +18,75 @@ pub fn draw_ui<B: Backend>(
tab: &mut TabSession,
) -> Result<(), io::Error> {
terminal.draw(|frame| {
let terminal_size = frame.size();
const COMMAND_LINE_HEIGHT: u16 = 3;
let terminal_area = frame.size();
const COMMAND_LINE_HEIGHT: u16 = 2;

let prompt_log_area;
let prompt_edit_area;
let prompt_log_area_scrollbar;
// default background for unused area
frame.render_widget(
Block::default().style(Style::default().bg(Color::Black)),
terminal_area,
);

let main_window = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Min(0), // container for prompt_edit and prompt_log
Constraint::Length(COMMAND_LINE_HEIGHT), // command line
])
.split(terminal_size);
.split(terminal_area);

// add borders to main_window[0]
frame.render_widget(
main_widget(tab.chat.server_name(), window_hint()),
main_window[0],
);

let command_line_area = main_window[1];

let window = Layout::default()
let tab_window = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Percentage(70), // prompt_log
Constraint::Percentage(30), // prompt_edit
])
.margin(1)
.split(main_window[0]);

let log_window = Layout::default()
let response_window = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Min(10), // chat history
Constraint::Length(2), // vertical scrollbar
Constraint::Min(10), // response history
Constraint::Length(1), // vertical scrollbar
])
.split(window[0]);
.split(tab_window[0]);

let edit_window = Layout::default()
let prompt_window = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Min(10), // prompt
Constraint::Length(2), // vertical scrollbar
Constraint::Length(0), // vertical scrollbar (disabled)
])
.split(window[1]);
.horizontal_margin(1)
.split(tab_window[1]);

prompt_log_area = log_window[0];
prompt_log_area_scrollbar = log_window[1];
prompt_edit_area = edit_window[0];
let response_text_area = response_window[0];
let response_scrollbar = response_window[1];
let prompt_text_area = prompt_window[0];

frame.render_widget(
tab.ui.prompt.widget(&prompt_edit_area),
prompt_edit_area,
tab.ui.prompt.widget(&prompt_text_area),
prompt_text_area,
);
tab.ui.response.set_window_title(tab.chat.server_name());
frame.render_widget(
tab.ui.response.widget(&prompt_log_area),
prompt_log_area,
tab.ui.response.widget(&response_text_area),
response_text_area,
);
frame.render_stateful_widget(
Scrollbar::default()
.orientation(ScrollbarOrientation::VerticalRight)
.begin_symbol(Some("↑"))
.end_symbol(Some("↓")),
prompt_log_area_scrollbar,
response_scrollbar,
&mut tab.ui.response.vertical_scroll_bar_state(),
);

Expand All @@ -92,3 +106,24 @@ pub fn draw_ui<B: Backend>(
fn modal_area(area: Rect) -> Rect {
Rect::new(2, 1, area.width - 3, area.height - 4)
}

pub fn main_widget(title: &str, hint: Option<String>) -> Block<'_> {
let mut block = Block::default()
.style(Style::default().bg(Color::Black))
.borders(Borders::ALL)
.border_style(Style::default().fg(Color::LightGreen).bg(Color::Black))
.title(Title::from(title).alignment(Alignment::Left));

if let Some(hint) = hint {
let title_hint = Title::from(hint)
.alignment(Alignment::Right)
.position(Position::Top);
block = block.title(title_hint)
}
block
}

fn window_hint() -> Option<String> {
// TODO: implement window hint for main window
None
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ pub fn handle_prompt_window_event(
}
KeyCode::Enter => {
// handle enter if not in editing mode
if !tab_ui.prompt.is_status_insert()
{
if !tab_ui.prompt.is_status_insert() {
let question = tab_ui.prompt.text_buffer().to_string();
return Some(WindowEvent::Prompt(PromptAction::Write(question)));
return Some(WindowEvent::Prompt(PromptAction::Write(
question,
)));
}
}
KeyCode::Backspace => {
Expand Down
Loading

0 comments on commit e978619

Please sign in to comment.