use ratatui::{
layout::{Constraint, Direction, Layout, Rect},
style::{Color, Style},
widgets::Paragraph,
Frame,
};
use super::app::{App, AppState};
use super::widgets::{file_tree, help, issue_list, status_bar};
pub fn draw(frame: &mut Frame, app: &App) {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(1), Constraint::Min(0), Constraint::Length(1), ])
.split(frame.area());
draw_header(frame, app, chunks[0]);
draw_content(frame, app, chunks[1]);
status_bar::draw(frame, app, chunks[2]);
if app.state == AppState::ShowingHelp {
help::draw(frame);
}
}
fn draw_header(frame: &mut Frame, app: &App, area: Rect) {
let watched = if app.watched_paths.len() == 1 {
app.watched_paths[0].display().to_string()
} else {
format!("{} paths", app.watched_paths.len())
};
let file_count = app.watch_state.file_count();
let header_text = format!(
" linthis watch - {} │ Watching: {} files",
watched, file_count
);
let header =
Paragraph::new(header_text).style(Style::default().bg(Color::Blue).fg(Color::White));
frame.render_widget(header, area);
}
fn draw_content(frame: &mut Frame, app: &App, area: Rect) {
let chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Percentage(30), Constraint::Percentage(70), ])
.split(area);
file_tree::draw(frame, app, chunks[0]);
issue_list::draw(frame, app, chunks[1]);
}
pub fn border_style(focused: bool) -> Style {
if focused {
Style::default().fg(Color::Cyan)
} else {
Style::default().fg(Color::DarkGray)
}
}
#[allow(dead_code)]
pub fn format_path(path: &std::path::Path, max_len: usize) -> String {
let s = path.display().to_string();
if s.len() <= max_len {
s
} else {
format!("...{}", &s[s.len() - max_len + 3..])
}
}
pub fn severity_color(severity: crate::Severity) -> Color {
match severity {
crate::Severity::Error => Color::Red,
crate::Severity::Warning => Color::Yellow,
crate::Severity::Info => Color::Cyan,
}
}
pub fn severity_symbol(severity: crate::Severity) -> &'static str {
match severity {
crate::Severity::Error => "E",
crate::Severity::Warning => "W",
crate::Severity::Info => "I",
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_path_short() {
let path = std::path::Path::new("src/main.rs");
assert_eq!(format_path(path, 50), "src/main.rs");
}
#[test]
fn test_format_path_long() {
let path = std::path::Path::new("very/long/path/to/some/file/main.rs");
let formatted = format_path(path, 20);
assert!(formatted.starts_with("..."));
assert!(formatted.len() <= 20);
}
#[test]
fn test_severity_color() {
assert_eq!(severity_color(crate::Severity::Error), Color::Red);
assert_eq!(severity_color(crate::Severity::Warning), Color::Yellow);
assert_eq!(severity_color(crate::Severity::Info), Color::Cyan);
}
}