feat(ui): add configurable role label display and syntax highlighting support
- Introduce `RoleLabelDisplay` enum (inline, above, none) and integrate it into UI rendering and message formatting. - Replace `show_role_labels` boolean with `role_label_mode` across config, formatter, session, and TUI components. - Add `syntax_highlighting` boolean to UI settings with default `false` and support in message rendering. - Update configuration schema version to 1.3.0 and provide deserialization handling for legacy boolean values. - Extend theme definitions with code block styling fields (background, border, text, keyword, string, comment) and default values in `Theme`. - Adjust related modules (`formatting.rs`, `ui.rs`, `session.rs`, `chat_app.rs`) to use the new settings and theme fields.
This commit is contained in:
@@ -12,7 +12,7 @@ use crate::chat_app::{ChatApp, HELP_TAB_COUNT, MessageRenderContext, ModelSelect
|
||||
use owlen_core::model::DetailedModelInfo;
|
||||
use owlen_core::theme::Theme;
|
||||
use owlen_core::types::{ModelInfo, Role};
|
||||
use owlen_core::ui::{FocusedPanel, InputMode};
|
||||
use owlen_core::ui::{FocusedPanel, InputMode, RoleLabelDisplay};
|
||||
|
||||
const PRIVACY_TAB_INDEX: usize = HELP_TAB_COUNT - 1;
|
||||
|
||||
@@ -687,7 +687,7 @@ fn render_messages(frame: &mut Frame<'_>, area: Rect, app: &mut ChatApp) {
|
||||
|
||||
// Build the lines for messages using cached rendering
|
||||
let mut lines: Vec<Line<'static>> = Vec::new();
|
||||
let show_role_labels = formatter.show_role_labels();
|
||||
let role_label_mode = formatter.role_label_mode();
|
||||
for message_index in 0..total_messages {
|
||||
let is_streaming = {
|
||||
let conversation = app.conversation();
|
||||
@@ -701,12 +701,13 @@ fn render_messages(frame: &mut Frame<'_>, area: Rect, app: &mut ChatApp) {
|
||||
message_index,
|
||||
MessageRenderContext::new(
|
||||
&mut formatter,
|
||||
show_role_labels,
|
||||
role_label_mode,
|
||||
content_width as usize,
|
||||
message_index + 1 == total_messages,
|
||||
is_streaming,
|
||||
app.get_loading_indicator(),
|
||||
&theme,
|
||||
app.should_highlight_code(),
|
||||
),
|
||||
);
|
||||
lines.extend(message_lines);
|
||||
@@ -729,20 +730,53 @@ fn render_messages(frame: &mut Frame<'_>, area: Rect, app: &mut ChatApp) {
|
||||
};
|
||||
|
||||
if app.get_loading_indicator() != "" && last_message_is_user {
|
||||
let loading_spans = vec![
|
||||
Span::raw("🤖 "),
|
||||
Span::styled(
|
||||
"Assistant:",
|
||||
Style::default()
|
||||
.fg(theme.assistant_message_role)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::styled(
|
||||
format!(" {}", app.get_loading_indicator()),
|
||||
Style::default().fg(theme.info),
|
||||
),
|
||||
];
|
||||
lines.push(Line::from(loading_spans));
|
||||
match role_label_mode {
|
||||
RoleLabelDisplay::Inline => {
|
||||
let (emoji, title) = crate::chat_app::role_label_parts(&Role::Assistant);
|
||||
let inline_label = format!("{emoji} {title}:");
|
||||
let label_width = UnicodeWidthStr::width(inline_label.as_str());
|
||||
let max_label_width = crate::chat_app::max_inline_label_width();
|
||||
let padding = max_label_width.saturating_sub(label_width);
|
||||
|
||||
let mut loading_spans = vec![
|
||||
Span::raw(format!("{emoji} ")),
|
||||
Span::styled(
|
||||
format!("{title}:"),
|
||||
Style::default()
|
||||
.fg(theme.assistant_message_role)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
),
|
||||
];
|
||||
|
||||
if padding > 0 {
|
||||
loading_spans.push(Span::raw(" ".repeat(padding)));
|
||||
}
|
||||
|
||||
loading_spans.push(Span::raw(" "));
|
||||
loading_spans.push(Span::styled(
|
||||
app.get_loading_indicator().to_string(),
|
||||
Style::default().fg(theme.info),
|
||||
));
|
||||
|
||||
lines.push(Line::from(loading_spans));
|
||||
}
|
||||
_ => {
|
||||
let loading_spans = vec![
|
||||
Span::raw("🤖 "),
|
||||
Span::styled(
|
||||
"Assistant:",
|
||||
Style::default()
|
||||
.fg(theme.assistant_message_role)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::styled(
|
||||
format!(" {}", app.get_loading_indicator()),
|
||||
Style::default().fg(theme.info),
|
||||
),
|
||||
];
|
||||
lines.push(Line::from(loading_spans));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if lines.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user