Skip to content

Commit e872fc6

Browse files
committed
flex table and correct size counts per convo
1 parent aa4223f commit e872fc6

File tree

2 files changed

+81
-37
lines changed

2 files changed

+81
-37
lines changed

src/commands/conversation.rs

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::fs;
2-
use std::path::{Path, PathBuf};
2+
use std::path::{Path};
33
use serde_json::{Value, json};
44
use clap::Parser;
55
use chrono::{DateTime, Local, Utc};
@@ -40,6 +40,8 @@ pub fn run_conversation(args: ThreadArgs) {
4040
let mut rows = Vec::new();
4141
let mut active_idx = None;
4242

43+
let mut total_size_bytes: u64 = 0;
44+
4345
// Collect conversation metadata first
4446
let mut conversation_info = Vec::new();
4547
for tid in threads {
@@ -56,7 +58,11 @@ pub fn run_conversation(args: ThreadArgs) {
5658
conversation_json["created_at"].as_str().unwrap_or("");
5759
let msg_ids = conversation_json["messages"]
5860
.as_array()
59-
.map(|a| a.iter().filter_map(|v| v.as_str().map(|s| s.to_string())).collect::<Vec<_>>())
61+
.map(|a| {
62+
a.iter()
63+
.filter_map(|v| v.as_str().map(|s| s.to_string()))
64+
.collect::<Vec<_>>()
65+
})
6066
.unwrap_or_default();
6167

6268
let msg_count = msg_ids.len();
@@ -72,9 +78,12 @@ pub fn run_conversation(args: ThreadArgs) {
7278
let time_str = local_time.format("%H:%M").to_string();
7379

7480
// Compute total footprint (JSON + markdown attachments)
75-
let size_bytes = compute_conversation_size(fur_dir, tid_str, &msg_ids);
76-
let size_mb =
77-
(size_bytes as f64 / (1024.0 * 1024.0)).min(9999.0);
81+
let size_bytes =
82+
compute_conversation_size(fur_dir, tid_str, &msg_ids);
83+
84+
total_size_bytes += size_bytes;
85+
86+
let size_str = format_size(size_bytes);
7887

7988
conversation_info.push((
8089
tid_str.to_string(),
@@ -83,7 +92,7 @@ pub fn run_conversation(args: ThreadArgs) {
8392
time_str,
8493
msg_count,
8594
parsed_time,
86-
size_mb,
95+
size_str,
8796
));
8897
}
8998
}
@@ -94,7 +103,7 @@ pub fn run_conversation(args: ThreadArgs) {
94103
conversation_info.sort_by(|a, b| b.5.cmp(&a.5));
95104

96105
// Build rows and track active index
97-
for (i, (tid, title, date, time, msg_count, _, size_mb)) in
106+
for (i, (tid, title, date, time, msg_count, _, size_str)) in
98107
conversation_info.iter().enumerate()
99108
{
100109
let short_id = &tid[..8];
@@ -104,7 +113,7 @@ pub fn run_conversation(args: ThreadArgs) {
104113
title.to_string(),
105114
format!("{} | {}", date, time),
106115
msg_count.to_string(),
107-
format!("{:.2} MB", size_mb),
116+
size_str.to_string(),
108117
]);
109118

110119
if tid == active {
@@ -119,6 +128,10 @@ pub fn run_conversation(args: ThreadArgs) {
119128
active_idx,
120129
);
121130

131+
let total_size_str = format_size(total_size_bytes);
132+
println!("----------------------------");
133+
println!("Total Memory Used: {}", total_size_str);
134+
122135
return;
123136
}
124137

@@ -191,7 +204,7 @@ fn compute_conversation_size(
191204
let convo_path = fur_dir.join("threads").join(format!("{}.json", tid));
192205
total += file_size(&convo_path);
193206

194-
// Add all messages JSON
207+
// Add all messages + markdowns
195208
total += get_message_file_sizes(fur_dir, msg_ids);
196209

197210
total
@@ -201,16 +214,25 @@ fn get_message_file_sizes(fur_dir: &Path, msg_ids: &[String]) -> u64 {
201214
let mut total = 0;
202215

203216
for mid in msg_ids {
204-
// message JSON
205217
let msg_path = fur_dir.join("messages").join(format!("{}.json", mid));
206218
total += file_size(&msg_path);
207219

208-
// check for markdown pointer inside JSON
220+
// Parse JSON to find ONLY message["markdown"]
209221
if let Ok(content) = fs::read_to_string(&msg_path) {
210222
if let Ok(json) = serde_json::from_str::<Value>(&content) {
211-
if let Some(markdown_rel) = json["markdown"].as_str() {
212-
let md_path = fur_dir.join(markdown_rel);
213-
total += file_size(&md_path);
223+
224+
if let Some(md_raw) = json["markdown"].as_str() {
225+
226+
// CASE 1: absolute path -> use as-is
227+
let md_path = Path::new(md_raw);
228+
if md_path.is_absolute() {
229+
total += file_size(md_path);
230+
continue;
231+
}
232+
233+
// CASE 2: relative path -> resolve relative to project root
234+
let project_root_path = Path::new(".").join(md_raw);
235+
total += file_size(&project_root_path);
214236
}
215237
}
216238
}
@@ -219,6 +241,14 @@ fn get_message_file_sizes(fur_dir: &Path, msg_ids: &[String]) -> u64 {
219241
total
220242
}
221243

222-
fn file_size(path: &PathBuf) -> u64 {
244+
fn file_size(path: &Path) -> u64 {
223245
fs::metadata(path).map(|m| m.len()).unwrap_or(0)
224246
}
247+
248+
pub fn format_size(bytes: u64) -> String {
249+
if bytes < 1_048_576 {
250+
format!("{} KB", (bytes as f64 / 1024.0).round() as u64)
251+
} else {
252+
format!("{:.2} MB", bytes as f64 / (1024.0 * 1024.0))
253+
}
254+
}

src/renderer/table.rs

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,55 @@
11
use colored::*;
22

3-
pub fn render_table(title: &str, headers: &[&str], rows: Vec<Vec<String>>, active_idx: Option<usize>) {
4-
// Header
5-
println!("{}", format!("=== {} ===", title).bold().bright_cyan());
6-
println!("{}", "-".repeat(28));
7-
8-
// Column headers
9-
let header_line = headers.join(" ");
10-
println!("{}", header_line.bold());
11-
12-
println!("{}", "=".repeat(28));
13-
14-
// Compute column widths for alignment
15-
let col_widths: Vec<usize> = (0..headers.len())
16-
.map(|i| {
17-
rows.iter()
3+
pub fn render_table(
4+
title: &str,
5+
headers: &[&str],
6+
rows: Vec<Vec<String>>,
7+
active_idx: Option<usize>,
8+
) {
9+
// Compute column widths
10+
let col_widths: Vec<usize> = headers
11+
.iter()
12+
.enumerate()
13+
.map(|(i, h)| {
14+
let max_cell = rows
15+
.iter()
1816
.map(|r| r.get(i).map(|s| s.len()).unwrap_or(0))
1917
.max()
20-
.unwrap_or(0)
18+
.unwrap_or(0);
19+
max_cell.max(h.len())
2120
})
2221
.collect();
2322

24-
// Print each row
23+
// Total table width
24+
let total_width: usize = col_widths.iter().map(|w| w + 4).sum::<usize>() + 2;
25+
26+
// Top title bar
27+
println!("{}", format!("=== {} ===", title).bold().bright_cyan());
28+
println!("{}", "-".repeat(total_width));
29+
30+
// Header
31+
let mut header_line = String::new();
32+
for (i, h) in headers.iter().enumerate() {
33+
header_line.push_str(&format!("{:width$} ", h, width = col_widths[i]));
34+
}
35+
println!("{}", header_line.bold());
36+
println!("{}", "=".repeat(total_width));
37+
38+
// Rows
2539
for (i, row) in rows.iter().enumerate() {
2640
let mut line = String::new();
2741
for (j, cell) in row.iter().enumerate() {
28-
let width = col_widths[j].max(headers[j].len());
29-
let padded = format!("{:width$}", cell, width = width + 2);
30-
line.push_str(&padded);
42+
line.push_str(&format!("{:width$} ", cell, width = col_widths[j]));
3143
}
44+
3245
if Some(i) == active_idx {
3346
println!("{}", line.bold().bright_yellow());
3447
} else {
3548
println!("{}", line);
3649
}
37-
println!(); // blank line for spacing
50+
println!();
3851
}
3952

40-
println!("{}", "-".repeat(28));
53+
// Bottom border
54+
println!("{}", "-".repeat(total_width));
4155
}

0 commit comments

Comments
 (0)