Skip to content

Commit

Permalink
performance improvement/ fix text wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
aprxi committed Aug 18, 2024
1 parent d0ba08e commit 8592329
Show file tree
Hide file tree
Showing 13 changed files with 283 additions and 280 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashMap;
use ratatui::style::Style;

use super::db::{Attachment, AttachmentId, ConversationId, Message, MessageId};
use super::{ColorScheme, PromptRole, TextLine, TextSegment};
use super::{ColorScheme, PromptRole, SimpleString, TextLine, TextSegment};

#[derive(Debug, Clone)]
pub struct ConversationCache {
Expand Down Expand Up @@ -128,7 +128,7 @@ impl ConversationCache {
for line in message.content.lines() {
lines.push(TextLine {
segments: vec![TextSegment {
text: line.to_string(),
text: SimpleString::from(line.to_string()),
style: style.clone(),
}],
length: line.len(),
Expand All @@ -139,7 +139,7 @@ impl ConversationCache {
// Add an empty line after each message
lines.push(TextLine {
segments: vec![TextSegment {
text: String::new(),
text: SimpleString::new(""),
style: Some(Style::reset()),
}],
length: 0,
Expand All @@ -150,7 +150,7 @@ impl ConversationCache {
if message.role == PromptRole::Assistant {
lines.push(TextLine {
segments: vec![TextSegment {
text: String::new(),
text: SimpleString::new(""),
style: Some(Style::reset()),
}],
length: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub use prepare::NewConversation;
pub use super::db;
use super::{
ChatCompletionOptions, ChatMessage, ColorScheme, PromptError, PromptRole,
TextLine, TextSegment,
SimpleString, TextLine, TextSegment,
};

#[derive(Debug, Clone, PartialEq, Copy)]
Expand Down
4 changes: 2 additions & 2 deletions lumni/src/apps/builtin/llm/prompt/src/chat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use super::server::{CompletionResponse, ModelServer, ServerManager};
use super::tui::{
draw_ui, AppUi, ColorScheme, ColorSchemeType, CommandLineAction,
ConversationEvent, KeyEventHandler, ModalAction, ModalWindowType,
PromptAction, TextLine, TextSegment, TextWindowTrait, UserEvent,
WindowEvent, WindowKind,
PromptAction, SimpleString, TextLine, TextSegment, TextWindowTrait,
UserEvent, WindowEvent, WindowKind,
};

// gets PERSONAS from the generated code
Expand Down
4 changes: 2 additions & 2 deletions lumni/src/apps/builtin/llm/prompt/src/tui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use lumni::api::error::ApplicationError;
pub use modals::{ModalAction, ModalWindowTrait, ModalWindowType};
pub use ui::AppUi;
pub use window::{
CommandLine, PromptWindow, ResponseWindow, TextLine, TextSegment,
TextWindowTrait, WindowKind,
CommandLine, PromptWindow, ResponseWindow, SimpleString, TextLine,
TextSegment, TextWindowTrait, WindowKind,
};

use super::chat::db::{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::collections::HashMap;

use async_trait::async_trait;
use crossterm::event::KeyCode;
pub use lumni::Timestamp;
use lumni::Timestamp;
use ratatui::layout::{Constraint, Direction, Layout, Margin, Rect};
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Span};
Expand Down
19 changes: 11 additions & 8 deletions lumni/src/apps/builtin/llm/prompt/src/tui/modals/profiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,14 +357,12 @@ impl ProfileEditModal {
self.ui_state.set_focus(Focus::ProfileList);
return Ok(WindowEvent::Modal(ModalAction::Refresh));
}
KeyCode::Esc => {
// Cancel model selection, create profile without a model
KeyCode::Char('q') | KeyCode::Esc => {
// Cancel model selection and go back to profile type selection
self.new_profile_creator.model_selection_pending = false;
let profile_count = self.profile_list.total_items();
self.new_profile_creator
.create_new_profile(&self.db_handler, profile_count)
.await?;
self.ui_state.set_focus(Focus::ProfileList);
self.new_profile_creator.available_models.clear();
self.new_profile_creator.selected_model_index = 0;
self.ui_state.set_focus(Focus::NewProfileType);
return Ok(WindowEvent::Modal(ModalAction::Refresh));
}
_ => {}
Expand Down Expand Up @@ -479,7 +477,12 @@ impl ModalWindowTrait for ProfileEditModal {
self.render_new_profile_type(frame, content_chunks[1])
}
Focus::ModelSelection => {
self.render_model_selection(frame, content_chunks[1])
if self.new_profile_creator.model_selection_pending {
self.render_model_selection(frame, content_chunks[1]);
} else {
// If model selection was cancelled, render profile type selection instead
self.render_new_profile_type(frame, content_chunks[1]);
}
}
_ => self.renderer.render_settings_list(
frame,
Expand Down
3 changes: 2 additions & 1 deletion lumni/src/apps/builtin/llm/prompt/src/tui/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use ratatui::style::{Color, Style};
pub use scroller::Scroller;
pub use text_display::LineType;
pub use text_document::{
ReadDocument, ReadWriteDocument, TextDocumentTrait, TextLine, TextSegment,
ReadDocument, ReadWriteDocument, SimpleString, TextDocumentTrait, TextLine,
TextSegment,
};
pub use text_window::{TextWindow, TextWindowTrait};
pub use window_config::{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ impl<'a> TextDisplay<'a> {
let trailing_spaces =
text_str.len() - text_str.trim_end_matches(' ').len();
let wrapped_lines = text_wrapper.wrap_text_styled(line, None);

// length of the wrapped lines content
if wrapped_lines.is_empty() {
self.handle_empty_line(trailing_spaces, line.get_background());
} else {
Expand Down Expand Up @@ -241,8 +239,6 @@ impl<'a> TextDisplay<'a> {
&mut self,
wrapped_lines: Vec<TextLine>,
unwrapped_line_index: usize,
// trailing spaces of the unwrapped line are removed during wrapping,
// this is added back to the first and last (wrapped) line respectively
trailing_spaces: usize,
cursor: &Cursor,
background: Option<Color>,
Expand All @@ -251,49 +247,62 @@ impl<'a> TextDisplay<'a> {
cursor.get_selection_bounds();
let mut char_pos = 0;

for (idx, line) in wrapped_lines.iter().enumerate() {
let mut spans = Vec::new();
let wrapped_lines_len = wrapped_lines.len();
for (idx, line) in wrapped_lines.into_iter().enumerate() {
let mut spans = Vec::with_capacity(line.segments.len());

for segment in line.segments {
let mut segment_start = 0;
let mut current_style = segment.style;

// Start character position for this line from the cumulative offset
for segment in line.segments() {
let chars: Vec<char> = segment.text.chars().collect();
for ch in chars.into_iter() {
// Adjust row based on the index in wrapped lines
for (i, _) in segment.text.char_indices() {
let should_select = cursor.should_select(
unwrapped_line_index,
char_pos,
char_pos + i,
start_row,
start_col,
end_row,
end_col,
);

let mut effective_style =
segment.style.unwrap_or(Style::default());
if should_select {
effective_style = effective_style.bg(Color::Blue);
let effective_style = if should_select {
Some(current_style.unwrap_or_default().bg(Color::Blue))
} else {
current_style
};

if effective_style != current_style {
if segment_start < i {
spans.push(Span::styled(
segment.text[segment_start..i].to_string(),
current_style.unwrap_or_default(),
));
}
segment_start = i;
current_style = effective_style;
}
spans.push(Span::styled(ch.to_string(), effective_style));
char_pos += 1;
}
}

let mut current_line = Line::from(spans);
if segment_start < segment.text.len() {
spans.push(Span::styled(
segment.text[segment_start..].to_string(),
current_style.unwrap_or_default(),
));
}

char_pos += segment.text.len();
}

let last_segment = idx == wrapped_lines.len() - 1;
let last_segment = idx == wrapped_lines_len - 1;

if last_segment && trailing_spaces > 0 {
// Add trailing spaces back to end of the last line
let spaces = std::iter::repeat(' ')
.take(trailing_spaces)
.collect::<String>();
current_line.spans.push(Span::raw(spaces));
spans.push(Span::raw(" ".repeat(trailing_spaces)));
}
let current_line_length = current_line
.spans
.iter()
.map(|span| span.content.len())
.sum::<usize>();

let current_line = Line::from(spans);
let current_line_length =
line.length + if last_segment { trailing_spaces } else { 0 };

self.push_line(
current_line,
current_line_length,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
mod piece_table;
mod read_document;
mod read_write_document;
mod simple_string;
mod text_line;
mod text_wrapper;

use lumni::api::error::ApplicationError;
use ratatui::style::Style;
pub use read_document::ReadDocument;
pub use read_write_document::ReadWriteDocument;
pub use simple_string::SimpleString;
pub use text_line::{TextLine, TextSegment};
pub use text_wrapper::TextWrapper;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use std::borrow::Cow;
use std::ops::Deref;

#[derive(Clone, Debug, PartialEq)]
pub enum SimpleString {
Owned(String),
Borrowed(&'static str),
}

impl SimpleString {
pub fn new<S: Into<SimpleString>>(s: S) -> Self {
s.into()
}

pub fn as_str(&self) -> &str {
match self {
SimpleString::Owned(s) => s,
SimpleString::Borrowed(s) => s,
}
}

pub fn into_owned(self) -> String {
match self {
SimpleString::Owned(s) => s,
SimpleString::Borrowed(s) => s.to_owned(),
}
}

pub fn from_str(s: &str) -> Self {
SimpleString::Owned(s.to_owned())
}

pub fn from_string(s: String) -> Self {
SimpleString::Owned(s)
}
}

impl From<String> for SimpleString {
fn from(s: String) -> Self {
SimpleString::Owned(s)
}
}

impl From<&'static str> for SimpleString {
fn from(s: &'static str) -> Self {
SimpleString::Borrowed(s)
}
}

impl From<Cow<'static, str>> for SimpleString {
fn from(s: Cow<'static, str>) -> Self {
match s {
Cow::Borrowed(b) => SimpleString::Borrowed(b),
Cow::Owned(o) => SimpleString::Owned(o),
}
}
}

impl From<&String> for SimpleString {
fn from(s: &String) -> Self {
SimpleString::Owned(s.clone())
}
}

impl Deref for SimpleString {
type Target = str;

fn deref(&self) -> &Self::Target {
self.as_str()
}
}

impl From<SimpleString> for String {
fn from(s: SimpleString) -> Self {
s.into_owned()
}
}

impl std::fmt::Display for SimpleString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
use ratatui::style::{Color, Style};
use super::simple_string::SimpleString;

#[derive(Clone, Debug, PartialEq)]
pub struct TextSegment {
pub text: SimpleString,
pub style: Option<Style>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct TextLine {
Expand All @@ -16,18 +23,22 @@ impl TextLine {
}
}

pub fn add_segment(&mut self, text: String, style: Option<Style>) {
pub fn add_segment<S: Into<SimpleString>>(
&mut self,
text: S,
style: Option<Style>,
) {
let text = text.into();
self.length += text.len();

if let Some(last) = self.segments.last_mut() {
// update the length of the last segment
if last.style == style {
// Append text to the last segment if styles are the same
last.text.push_str(&text);
// Concatenate the strings if they have the same style
let new_text =
SimpleString::from(format!("{}{}", last.text, text));
last.text = new_text;
return;
}
}
// Otherwise, create a new segment
self.segments.push(TextSegment { text, style });
if let Some(style) = style {
self.background = style.bg;
Expand All @@ -51,16 +62,10 @@ impl TextLine {
}

pub fn to_string(&self) -> String {
let mut content = String::new();
let mut content = String::with_capacity(self.length);
for segment in &self.segments {
content.push_str(&segment.text);
content.push_str(segment.text.as_str());
}
content
}
}

#[derive(Clone, Debug, PartialEq)]
pub struct TextSegment {
pub text: String,
pub style: Option<Style>,
}
Loading

0 comments on commit 8592329

Please sign in to comment.