ci: add GitHub Actions workflows with semantic-release auto-versioning
chore: fix all 702 clippy warnings across codebase - auto-fix 475 via cargo clippy --fix - fix remaining 227 manually: uninlined_format_args, redundant_closure, match_same_arms, underscore_binding, format_push_string, items_after_statements, needless_pass_by_value, clone_on_copy, case_sensitive_extension, single_match/let-else, write_with_newline, and other clippy lints
This commit is contained in:
+8
-6
@@ -1,3 +1,4 @@
|
||||
#![allow(clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_precision_loss, clippy::cast_possible_wrap)]
|
||||
//! Chat transcript panel rendering — message cards with role badges.
|
||||
//!
|
||||
//! Flow: `draw_chat` turns `state.transcript_cache.messages` into a
|
||||
@@ -19,7 +20,7 @@ use ratatui::Frame;
|
||||
use super::theme::Theme;
|
||||
|
||||
/// Break a flat run of styled spans into `Line`s at embedded `\n` boundaries.
|
||||
fn split_spans_into_lines<'a>(spans: Vec<Span<'a>>) -> Vec<Line<'a>> {
|
||||
fn split_spans_into_lines(spans: Vec<Span<'_>>) -> Vec<Line<'_>> {
|
||||
let mut lines = Vec::new();
|
||||
let mut current_spans = Vec::new();
|
||||
|
||||
@@ -76,10 +77,11 @@ fn format_timestamp(ts: i64) -> String {
|
||||
let secs = ts / 1000;
|
||||
let mins = (secs / 60) % 60;
|
||||
let hrs = (secs / 3600) % 24;
|
||||
format!("{:02}:{:02}", hrs, mins)
|
||||
format!("{hrs:02}:{mins:02}")
|
||||
}
|
||||
|
||||
/// Render the scrollable chat transcript panel with message card styling.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub fn draw_chat(frame: &mut Frame, area: Rect, state: &crate::app::state::rest::AppStateRest) {
|
||||
let messages = &state.transcript_cache.messages;
|
||||
let scroll_offset = state.scroll.offset;
|
||||
@@ -95,7 +97,7 @@ pub fn draw_chat(frame: &mut Frame, area: Rect, state: &crate::app::state::rest:
|
||||
};
|
||||
|
||||
// ── Render messages as cards ─────────────────────────────────────────
|
||||
for (_msg_idx, msg) in messages.iter().enumerate() {
|
||||
for msg in messages {
|
||||
let accent = role_accent_color(&msg.role);
|
||||
let badge = role_badge(&msg.role);
|
||||
let label = role_label(&msg.role);
|
||||
@@ -119,12 +121,12 @@ pub fn draw_chat(frame: &mut Frame, area: Rect, state: &crate::app::state::rest:
|
||||
),
|
||||
// Role name
|
||||
Span::styled(
|
||||
format!(" {}", label),
|
||||
format!(" {label}"),
|
||||
Style::default().fg(accent).add_modifier(Modifier::BOLD),
|
||||
),
|
||||
// Timestamp
|
||||
Span::styled(
|
||||
if ts_str.is_empty() { String::new() } else { format!(" {}", ts_str) },
|
||||
if ts_str.is_empty() { String::new() } else { format!(" {ts_str}") },
|
||||
Style::default().fg(Theme::TEXT_DIM),
|
||||
),
|
||||
]);
|
||||
@@ -176,7 +178,7 @@ pub fn draw_chat(frame: &mut Frame, area: Rect, state: &crate::app::state::rest:
|
||||
.add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::styled(
|
||||
format!(" {} ", spinner),
|
||||
format!(" {spinner} "),
|
||||
Style::default().fg(Theme::ROLE_ASSISTANT).add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::styled(
|
||||
|
||||
+11
-25
@@ -14,12 +14,13 @@ use super::theme::Theme;
|
||||
|
||||
/// Render a markdown string into styled terminal spans, word-wrapped to `width`.
|
||||
///
|
||||
/// Flow: pulldown_cmark parses `text` into an event stream → each
|
||||
/// Flow: `pulldown_cmark` parses `text` into an event stream → each
|
||||
/// Start/End/Text/Code/Break event is translated into styled `Span`s →
|
||||
/// if `width > 0`, a second pass wraps long lines.
|
||||
///
|
||||
/// Return: a flat vec of styled spans; `chat::split_spans_into_lines`
|
||||
/// turns it back into `Line`s for the Paragraph widget.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub fn render_markdown(text: &str, width: u16) -> Vec<Span<'static>> {
|
||||
let mut spans = Vec::new();
|
||||
let parser = pulldown_cmark::Parser::new(text);
|
||||
@@ -61,9 +62,6 @@ pub fn render_markdown(text: &str, width: u16) -> Vec<Span<'static>> {
|
||||
pulldown_cmark::Tag::Paragraph => {
|
||||
first_in_paragraph = true;
|
||||
}
|
||||
pulldown_cmark::Tag::Emphasis => {}
|
||||
pulldown_cmark::Tag::Strong => {}
|
||||
pulldown_cmark::Tag::List(_) => {}
|
||||
pulldown_cmark::Tag::Item => {
|
||||
// List item bullet
|
||||
spans.push(Span::styled(
|
||||
@@ -79,7 +77,7 @@ pub fn render_markdown(text: &str, width: u16) -> Vec<Span<'static>> {
|
||||
// We push the URL as a tooltip-like suffix
|
||||
// After the link text ends, we'll add the URL
|
||||
spans.push(Span::styled(
|
||||
format!("]({})", dest_url),
|
||||
format!("]({dest_url})"),
|
||||
Style::default().fg(Theme::TEXT_MUTED).add_modifier(Modifier::ITALIC),
|
||||
));
|
||||
}
|
||||
@@ -111,14 +109,7 @@ pub fn render_markdown(text: &str, width: u16) -> Vec<Span<'static>> {
|
||||
first_in_paragraph = true;
|
||||
spans.push(Span::raw("\n\n"));
|
||||
}
|
||||
pulldown_cmark::TagEnd::Emphasis => {}
|
||||
pulldown_cmark::TagEnd::Strong => {}
|
||||
pulldown_cmark::TagEnd::List(_) => {}
|
||||
pulldown_cmark::TagEnd::Item => {
|
||||
spans.push(Span::raw("\n"));
|
||||
}
|
||||
pulldown_cmark::TagEnd::Link => {}
|
||||
pulldown_cmark::TagEnd::BlockQuote(_) => {
|
||||
pulldown_cmark::TagEnd::Item | pulldown_cmark::TagEnd::BlockQuote(_) => {
|
||||
spans.push(Span::raw("\n"));
|
||||
}
|
||||
_ => {}
|
||||
@@ -128,7 +119,7 @@ pub fn render_markdown(text: &str, width: u16) -> Vec<Span<'static>> {
|
||||
let s = text.to_string();
|
||||
if in_code_block {
|
||||
spans.push(Span::styled(
|
||||
format!(" {}", s),
|
||||
format!(" {s}"),
|
||||
Style::default().fg(Theme::ACCENT_TEAL).bg(Theme::CODE_BG),
|
||||
));
|
||||
} else if in_heading {
|
||||
@@ -138,14 +129,9 @@ pub fn render_markdown(text: &str, width: u16) -> Vec<Span<'static>> {
|
||||
3 => Theme::ACCENT_PURPLE,
|
||||
_ => Theme::TEXT,
|
||||
};
|
||||
let prefix = match heading_level {
|
||||
1 => " ",
|
||||
2 => " ",
|
||||
3 => " ",
|
||||
_ => " ",
|
||||
};
|
||||
let prefix = " ";
|
||||
spans.push(Span::styled(
|
||||
format!("{}{}", prefix, s),
|
||||
format!("{prefix}{s}"),
|
||||
Style::default().fg(color).add_modifier(Modifier::BOLD),
|
||||
));
|
||||
} else {
|
||||
@@ -160,7 +146,7 @@ pub fn render_markdown(text: &str, width: u16) -> Vec<Span<'static>> {
|
||||
pulldown_cmark::Event::Code(text) => {
|
||||
// Inline code with background
|
||||
spans.push(Span::styled(
|
||||
format!(" {} ", text),
|
||||
format!(" {text} "),
|
||||
Style::default()
|
||||
.fg(Theme::ACCENT_TEAL)
|
||||
.bg(Theme::CODE_BAR)
|
||||
@@ -195,10 +181,10 @@ pub fn render_markdown(text: &str, width: u16) -> Vec<Span<'static>> {
|
||||
|
||||
spans_out.push(Span::styled(text_str.to_string(), style));
|
||||
|
||||
if !text_str.contains('\n') {
|
||||
line_len += remaining;
|
||||
} else {
|
||||
if text_str.contains('\n') {
|
||||
line_len = text_str.split('\n').next_back().unwrap_or("").len();
|
||||
} else {
|
||||
line_len += remaining;
|
||||
}
|
||||
}
|
||||
spans = spans_out;
|
||||
|
||||
+39
-39
@@ -1,3 +1,4 @@
|
||||
#![allow(clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_precision_loss, clippy::cast_possible_wrap)]
|
||||
//! Top-level TUI render pipeline: layouts the terminal into chat / input
|
||||
//! / status regions, dispatches overlay rendering with glassmorphism-style
|
||||
//! centered panels, and floats toast notifications over the top-right corner.
|
||||
@@ -124,6 +125,7 @@ fn render_main_panel(
|
||||
/// - A top accent border strip (colored per variant)
|
||||
/// - A title line with icon
|
||||
/// - Content area with proper spacing
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn render_overlay(
|
||||
frame: &mut Frame,
|
||||
area: Rect,
|
||||
@@ -172,12 +174,12 @@ fn render_overlay(
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
format!(" Max tokens: {}",
|
||||
state.settings.max_tokens.map(|v| v.to_string()).unwrap_or_else(|| "auto".to_string())),
|
||||
state.settings.max_tokens.map_or_else(|| "auto".to_string(), |v| v.to_string())),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
format!(" Temperature: {}",
|
||||
state.settings.temperature.map(|v| format!("{:.1}", v)).unwrap_or_else(|| "auto".to_string())),
|
||||
state.settings.temperature.map_or_else(|| "auto".to_string(), |v| format!("{v:.1}"))),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
@@ -261,11 +263,11 @@ fn render_overlay(
|
||||
input_text.as_str()
|
||||
}
|
||||
};
|
||||
let masked = if !input_text.is_empty() {
|
||||
let suffix = if input_text.len() > 8 { "****" } else { "" };
|
||||
format!("{}{}", display, suffix)
|
||||
} else {
|
||||
let masked = if input_text.is_empty() {
|
||||
display.to_string()
|
||||
} else {
|
||||
let suffix = if input_text.len() > 8 { "****" } else { "" };
|
||||
format!("{display}{suffix}")
|
||||
};
|
||||
let lines = vec![
|
||||
Line::from(Span::styled(
|
||||
@@ -329,9 +331,9 @@ fn render_overlay(
|
||||
let selected = i == current_idx;
|
||||
lines.push(Line::from(Span::styled(
|
||||
if selected {
|
||||
format!(" ▸ {} (active)", l)
|
||||
format!(" ▸ {l} (active)")
|
||||
} else {
|
||||
format!(" {}", l)
|
||||
format!(" {l}")
|
||||
},
|
||||
if selected {
|
||||
Style::default().fg(Theme::HIGHLIGHT).add_modifier(Modifier::BOLD)
|
||||
@@ -386,7 +388,7 @@ fn render_overlay(
|
||||
)),
|
||||
Line::from(Span::raw("")),
|
||||
Line::from(Span::styled(
|
||||
format!(" Messages: {}", msg_count),
|
||||
format!(" Messages: {msg_count}"),
|
||||
Style::default().fg(Theme::INFO),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
@@ -427,7 +429,7 @@ fn render_overlay(
|
||||
};
|
||||
let preview: String = msg.content.chars().take(70).collect();
|
||||
lines.push(Line::from(Span::styled(
|
||||
format!(" [{}] {}", role_str, preview),
|
||||
format!(" [{role_str}] {preview}"),
|
||||
Style::default().fg(
|
||||
if matches!(msg.role, crate::dto::chat::message::Role::User) {
|
||||
Theme::INFO
|
||||
@@ -484,7 +486,7 @@ fn render_overlay(
|
||||
let (label, style) = match item {
|
||||
crate::app::mode::learning::LearningItem::Pending { name, .. } => {
|
||||
(
|
||||
format!("{}[Pending] {}", prefix, name),
|
||||
format!("{prefix}[Pending] {name}"),
|
||||
if is_selected {
|
||||
Style::default().fg(Theme::WARNING).bg(Theme::HIGHLIGHT_DIM)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
@@ -496,7 +498,7 @@ fn render_overlay(
|
||||
crate::app::mode::learning::LearningItem::Stored { name, lifecycle, .. } => {
|
||||
let status = if lifecycle == "stale" { "Stale" } else { "Active" };
|
||||
(
|
||||
format!("{}[{}] {}", prefix, status, name),
|
||||
format!("{prefix}[{status}] {name}"),
|
||||
if is_selected {
|
||||
Style::default().fg(Theme::TEXT).bg(Theme::HIGHLIGHT_DIM)
|
||||
.add_modifier(Modifier::BOLD)
|
||||
@@ -539,7 +541,7 @@ fn render_overlay(
|
||||
" Name:", Style::default().fg(Theme::TEXT_DIM),
|
||||
)));
|
||||
right_lines.push(Line::from(Span::styled(
|
||||
format!(" {}", name),
|
||||
format!(" {name}"),
|
||||
Style::default().fg(Theme::TEXT).add_modifier(Modifier::BOLD),
|
||||
)));
|
||||
right_lines.push(Line::from(Span::raw("")));
|
||||
@@ -548,11 +550,11 @@ fn render_overlay(
|
||||
Style::default().fg(Theme::WARNING),
|
||||
)));
|
||||
right_lines.push(Line::from(Span::styled(
|
||||
format!(" Scope: {}", scope),
|
||||
format!(" Scope: {scope}"),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)));
|
||||
right_lines.push(Line::from(Span::styled(
|
||||
format!(" Confidence: {}", confidence),
|
||||
format!(" Confidence: {confidence}"),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)));
|
||||
right_lines.push(Line::from(Span::raw("")));
|
||||
@@ -561,7 +563,7 @@ fn render_overlay(
|
||||
)));
|
||||
for line in content.lines() {
|
||||
right_lines.push(Line::from(Span::styled(
|
||||
format!(" {}", line),
|
||||
format!(" {line}"),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)));
|
||||
}
|
||||
@@ -578,7 +580,7 @@ fn render_overlay(
|
||||
" Name:", Style::default().fg(Theme::TEXT_DIM),
|
||||
)));
|
||||
right_lines.push(Line::from(Span::styled(
|
||||
format!(" {}", name),
|
||||
format!(" {name}"),
|
||||
Style::default().fg(Theme::TEXT).add_modifier(Modifier::BOLD),
|
||||
)));
|
||||
right_lines.push(Line::from(Span::raw("")));
|
||||
@@ -588,15 +590,15 @@ fn render_overlay(
|
||||
Theme::SUCCESS
|
||||
};
|
||||
right_lines.push(Line::from(Span::styled(
|
||||
format!(" Status: {}", lifecycle),
|
||||
format!(" Status: {lifecycle}"),
|
||||
Style::default().fg(status_color),
|
||||
)));
|
||||
right_lines.push(Line::from(Span::styled(
|
||||
format!(" Scope: {}", scope),
|
||||
format!(" Scope: {scope}"),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)));
|
||||
right_lines.push(Line::from(Span::styled(
|
||||
format!(" Description: {}", description),
|
||||
format!(" Description: {description}"),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)));
|
||||
right_lines.push(Line::from(Span::raw("")));
|
||||
@@ -605,7 +607,7 @@ fn render_overlay(
|
||||
)));
|
||||
for line in content.lines() {
|
||||
right_lines.push(Line::from(Span::styled(
|
||||
format!(" {}", line),
|
||||
format!(" {line}"),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)));
|
||||
}
|
||||
@@ -635,7 +637,7 @@ fn render_overlay(
|
||||
.border_style(Style::default().fg(Theme::INFO));
|
||||
let runtime = state.session_runtime.as_ref();
|
||||
let (tokens_in, tokens_out, api_calls, review_tokens, session_start) = runtime
|
||||
.map(|r| {
|
||||
.map_or((0, 0, 0, 0, 0), |r| {
|
||||
(
|
||||
r.usage.tokens_in,
|
||||
r.usage.tokens_out,
|
||||
@@ -643,18 +645,16 @@ fn render_overlay(
|
||||
r.usage.review_tokens,
|
||||
r.session_start,
|
||||
)
|
||||
})
|
||||
.unwrap_or((0, 0, 0, 0, 0));
|
||||
});
|
||||
let (edit_count, lesson_count, review_count, consec_empty) = runtime
|
||||
.map(|r| {
|
||||
.map_or((0, 0, 0, 0), |r| {
|
||||
(
|
||||
r.edit_count,
|
||||
r.lesson_count,
|
||||
r.review_count,
|
||||
r.consecutive_empty_reviews,
|
||||
)
|
||||
})
|
||||
.unwrap_or((0, 0, 0, 0));
|
||||
});
|
||||
let elapsed_ms = chrono::Utc::now().timestamp_millis().saturating_sub(session_start);
|
||||
let hours = elapsed_ms / 3_600_000;
|
||||
let minutes = (elapsed_ms % 3_600_000) / 60_000;
|
||||
@@ -669,19 +669,19 @@ fn render_overlay(
|
||||
)),
|
||||
Line::from(Span::raw("")),
|
||||
Line::from(Span::styled(
|
||||
format!(" Main agent: {} tokens", main_tokens),
|
||||
format!(" Main agent: {main_tokens} tokens"),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
format!(" Self-learning: {} tokens", self_learning_total),
|
||||
format!(" Self-learning: {self_learning_total} tokens"),
|
||||
Style::default().fg(Theme::TEXT_MUTED),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
format!(" Total: {} tokens", total_tokens),
|
||||
format!(" Total: {total_tokens} tokens"),
|
||||
Style::default().fg(Theme::TEXT).add_modifier(Modifier::BOLD),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
format!(" API calls: {}", api_calls),
|
||||
format!(" API calls: {api_calls}"),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)),
|
||||
Line::from(Span::raw("")),
|
||||
@@ -690,21 +690,21 @@ fn render_overlay(
|
||||
Style::default().fg(Theme::INFO).add_modifier(Modifier::BOLD),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
format!(" Edits: {}", edit_count),
|
||||
format!(" Edits: {edit_count}"),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
format!(" Reviews: {}", review_count),
|
||||
format!(" Reviews: {review_count}"),
|
||||
Style::default().fg(Theme::TEXT),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
format!(" Lessons: {}", lesson_count),
|
||||
format!(" Lessons: {lesson_count}"),
|
||||
Style::default().fg(Theme::TEXT_MUTED),
|
||||
)),
|
||||
Line::from(Span::styled(
|
||||
format!(" Empty reviews: {}",
|
||||
if consec_empty > 3 {
|
||||
format!("{} ⚠", consec_empty)
|
||||
format!("{consec_empty} ⚠")
|
||||
} else {
|
||||
consec_empty.to_string()
|
||||
},
|
||||
@@ -713,7 +713,7 @@ fn render_overlay(
|
||||
)),
|
||||
Line::from(Span::raw("")),
|
||||
Line::from(Span::styled(
|
||||
format!(" Session: {}h {}m {}s", hours, minutes, seconds),
|
||||
format!(" Session: {hours}h {minutes}m {seconds}s"),
|
||||
Style::default().fg(Theme::TEXT_DIM),
|
||||
)),
|
||||
];
|
||||
@@ -757,7 +757,7 @@ fn render_overlay(
|
||||
let is_selected = i == state.misc.selected_index;
|
||||
let prefix = if is_selected { " ▸ " } else { " " };
|
||||
let model_str = cfg.default_model.as_deref().unwrap_or("(any)");
|
||||
let label = format!("{}{} ({})", prefix, name, model_str);
|
||||
let label = format!("{prefix}{name} ({model_str})");
|
||||
let style = if is_current {
|
||||
Style::default().fg(Theme::HIGHLIGHT).add_modifier(Modifier::BOLD)
|
||||
} else if is_selected {
|
||||
@@ -842,7 +842,7 @@ fn render_input_bar(
|
||||
} else {
|
||||
Style::default().fg(Theme::TEXT)
|
||||
};
|
||||
let label = format!("{}{}", prefix, candidate);
|
||||
let label = format!("{prefix}{candidate}");
|
||||
lines.push(Line::from(Span::styled(label, style)));
|
||||
}
|
||||
let dropdown = Paragraph::new(lines).block(dropdown_block);
|
||||
@@ -901,7 +901,7 @@ fn render_input_bar(
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// Render active toasts as a floating stack at top-right of the terminal.
|
||||
/// Each toast auto-expires after its lifetime_ms. Max 4 visible at once.
|
||||
/// Each toast auto-expires after its `lifetime_ms`. Max 4 visible at once.
|
||||
///
|
||||
/// Toasts are stacked vertically with a 1-line gap. Each has a colored
|
||||
/// left border and a subtle background.
|
||||
|
||||
+8
-7
@@ -1,3 +1,4 @@
|
||||
#![allow(clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cast_precision_loss, clippy::cast_possible_wrap)]
|
||||
//! Status bar rendering for the TUI — modern segmented bar design.
|
||||
//!
|
||||
//! Flow: `draw_status_bar` reads live connection/turn state off
|
||||
@@ -20,14 +21,15 @@ use super::theme::Theme;
|
||||
/// Layout (left-to-right, space-filling):
|
||||
/// LEFT: [zesdex] + status indicator (READY/PROG/NOAPI)
|
||||
/// CENTER: spinner + optional contextual info
|
||||
/// RIGHT: provider · model · ↑tokens_in ↓tokens_out
|
||||
/// RIGHT: provider · model · ↑`tokens_in` ↓`tokens_out`
|
||||
pub fn draw_status_bar(frame: &mut Frame, area: Rect, state: &crate::app::state::rest::AppStateRest) {
|
||||
use ratatui::layout::{Constraint, Direction, Layout};
|
||||
let spinner_frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
||||
|
||||
// ── Agent status badge ────────────────────────────────────────────────
|
||||
let (status_text, badge_bg, status_fg) = if state.turn_in_flight() {
|
||||
let f = spinner_frames[(state.misc.tick_count as usize / 2) % spinner_frames.len()];
|
||||
(format!(" {} PROG ", f), Theme::MODE_YOLO, Theme::BG)
|
||||
(format!(" {f} PROG "), Theme::MODE_YOLO, Theme::BG)
|
||||
} else if state.misc.api_connected {
|
||||
(" READY ".to_string(), Theme::MODE_AUTO, Theme::BG)
|
||||
} else {
|
||||
@@ -61,7 +63,7 @@ pub fn draw_status_bar(frame: &mut Frame, area: Rect, state: &crate::app::state:
|
||||
|
||||
let total_chars: usize = rt.messages.iter()
|
||||
.filter_map(|m| m.content.as_deref())
|
||||
.map(|c| c.len())
|
||||
.map(str::len)
|
||||
.sum();
|
||||
let current_tokens = total_chars / 4;
|
||||
|
||||
@@ -69,8 +71,8 @@ pub fn draw_status_bar(frame: &mut Frame, area: Rect, state: &crate::app::state:
|
||||
if rt.usage.last_tokens_in > 0 || rt.usage.last_tokens_out > 0 {
|
||||
parts.push(format!("↑{} ↓{}", rt.usage.last_tokens_in, rt.usage.last_tokens_out));
|
||||
}
|
||||
let max_str = max_tokens.map(|v| v.to_string()).unwrap_or_else(|| "?".to_string());
|
||||
parts.push(format!("{}/{}", current_tokens, max_str));
|
||||
let max_str = max_tokens.map_or_else(|| "?".to_string(), |v| v.to_string());
|
||||
parts.push(format!("{current_tokens}/{max_str}"));
|
||||
parts.push(state.settings.provider.clone());
|
||||
parts.push(state.settings.model.clone());
|
||||
|
||||
@@ -79,7 +81,7 @@ pub fn draw_status_bar(frame: &mut Frame, area: Rect, state: &crate::app::state:
|
||||
let max_tokens = state.app_config.model_roles.values()
|
||||
.find(|role| role.provider == state.settings.provider && role.model == state.settings.model)
|
||||
.and_then(|role| role.context_window);
|
||||
let max_str = max_tokens.map(|v| v.to_string()).unwrap_or_else(|| "?".to_string());
|
||||
let max_str = max_tokens.map_or_else(|| "?".to_string(), |v| v.to_string());
|
||||
format!(" 0/{} · {} · {} ", max_str, state.settings.provider, state.settings.model)
|
||||
};
|
||||
|
||||
@@ -92,7 +94,6 @@ pub fn draw_status_bar(frame: &mut Frame, area: Rect, state: &crate::app::state:
|
||||
));
|
||||
|
||||
// Render the bar using two columns
|
||||
use ratatui::layout::{Constraint, Direction, Layout};
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([
|
||||
|
||||
@@ -55,6 +55,7 @@ fn is_company_pipeline(agents: &[crate::app::workflow::engine::WorkflowAgent]) -
|
||||
}
|
||||
|
||||
/// Render the workflow status panel.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub fn draw_workflow_panel(frame: &mut Frame, area: Rect, state: &crate::app::state::rest::AppStateRest) {
|
||||
use ratatui::layout::{Constraint, Direction, Layout};
|
||||
|
||||
@@ -179,7 +180,7 @@ pub fn draw_workflow_panel(frame: &mut Frame, area: Rect, state: &crate::app::st
|
||||
// Agent card header
|
||||
card_lines.push(Line::from(vec![
|
||||
Span::styled(
|
||||
format!(" {} ", icon),
|
||||
format!(" {icon} "),
|
||||
Style::default().fg(color).add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::styled(
|
||||
@@ -187,7 +188,7 @@ pub fn draw_workflow_panel(frame: &mut Frame, area: Rect, state: &crate::app::st
|
||||
Style::default().fg(Theme::TEXT).add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::styled(
|
||||
format!(" [{}]", label),
|
||||
format!(" [{label}]"),
|
||||
Style::default().fg(color),
|
||||
),
|
||||
Span::styled(
|
||||
@@ -240,18 +241,18 @@ fn build_session_lines(state: &crate::app::state::rest::AppStateRest) -> Vec<Lin
|
||||
]));
|
||||
lines.push(Line::from(vec![
|
||||
Span::styled(" Tool calls", Style::default().fg(Theme::TEXT_DIM)),
|
||||
Span::styled(format!(" {}", tool_count), Style::default().fg(Theme::SUCCESS)),
|
||||
Span::styled(format!(" {tool_count}"), Style::default().fg(Theme::SUCCESS)),
|
||||
]));
|
||||
if pending > 0 {
|
||||
lines.push(Line::from(vec![
|
||||
Span::styled(" Pending ", Style::default().fg(Theme::TEXT_DIM)),
|
||||
Span::styled(format!(" {}", pending), Style::default().fg(Theme::WARNING)),
|
||||
Span::styled(format!(" {pending}"), Style::default().fg(Theme::WARNING)),
|
||||
]));
|
||||
}
|
||||
if bash_count > 0 {
|
||||
lines.push(Line::from(vec![
|
||||
Span::styled(" Bash jobs ", Style::default().fg(Theme::TEXT_DIM)),
|
||||
Span::styled(format!(" {}", bash_count), Style::default().fg(Theme::WARNING)),
|
||||
Span::styled(format!(" {bash_count}"), Style::default().fg(Theme::WARNING)),
|
||||
]));
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user