pub struct Budget;
impl Budget {
pub const TOTAL_CEILING: usize = 1000;
pub const TLDR_CAP: usize = 100;
pub const WHERE_CAP: usize = 200;
pub const LIVE_CAP: usize = 200;
pub const MEMORY_CAP: usize = 200;
pub const ACTION_CAP: usize = 100;
pub const AUTHORITY_CAP: usize = 100;
#[cfg(test)]
pub const fn sum_of_caps() -> usize {
Self::TLDR_CAP
+ Self::WHERE_CAP
+ Self::LIVE_CAP
+ Self::MEMORY_CAP
+ Self::ACTION_CAP
+ Self::AUTHORITY_CAP
}
}
pub fn truncate_with_tail(lines: Vec<String>, cap: usize) -> Vec<String> {
if lines.len() <= cap {
return lines;
}
if cap == 0 {
return Vec::new();
}
let kept = cap.saturating_sub(1);
let dropped = lines.len() - kept;
let mut out: Vec<String> = lines.into_iter().take(kept).collect();
out.push(format!(
"+ {dropped} more, run `loct context --full` for full data"
));
out
}
pub fn rank_and_render<T>(
mut items: Vec<T>,
cap: usize,
score: impl Fn(&T) -> i64,
render: impl Fn(&T) -> String,
) -> Vec<String> {
items.sort_by_key(|item| -score(item));
let lines: Vec<String> = items.iter().map(&render).collect();
truncate_with_tail(lines, cap)
}
pub fn count_lines(markdown: &str) -> usize {
if markdown.is_empty() {
return 0;
}
let mut n = markdown.matches('\n').count();
if !markdown.ends_with('\n') {
n += 1;
}
n
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sum_of_caps_fits_under_total_ceiling() {
let sum = Budget::sum_of_caps();
assert!(
sum <= Budget::TOTAL_CEILING,
"section caps {sum} exceed total ceiling {}",
Budget::TOTAL_CEILING
);
let headroom = Budget::TOTAL_CEILING - sum;
assert!(
headroom >= 50,
"expected ≥50 lines of headroom for header/footer, got {headroom}"
);
}
#[test]
fn truncate_keeps_everything_when_under_cap() {
let input = vec!["one".to_string(), "two".to_string(), "three".to_string()];
let out = truncate_with_tail(input.clone(), 10);
assert_eq!(out, input);
}
#[test]
fn truncate_appends_tail_when_over_cap() {
let input: Vec<String> = (0..20).map(|i| format!("row-{i}")).collect();
let out = truncate_with_tail(input, 5);
assert_eq!(out.len(), 5);
assert!(
out.last().unwrap().starts_with("+ "),
"tail line must start with '+ '"
);
assert!(
out.last().unwrap().contains("loct context --full"),
"tail must guide to --full"
);
assert!(
out.last().unwrap().contains("16"),
"tail must report the dropped count, got: {}",
out.last().unwrap()
);
}
#[test]
fn truncate_handles_zero_cap() {
let input = vec!["a".to_string(), "b".to_string()];
assert!(truncate_with_tail(input, 0).is_empty());
}
#[test]
fn rank_and_render_sorts_descending_then_caps() {
struct Row {
name: &'static str,
score: i64,
}
let rows = vec![
Row {
name: "low",
score: 1,
},
Row {
name: "high",
score: 10,
},
Row {
name: "mid",
score: 5,
},
];
let rendered = rank_and_render(rows, 2, |r| r.score, |r| r.name.to_string());
assert_eq!(rendered.len(), 2);
assert_eq!(rendered[0], "high");
assert!(
rendered[1].starts_with("+ ") || rendered[1] == "mid",
"second slot is mid or tail line, got: {}",
rendered[1]
);
}
#[test]
fn count_lines_matches_section_caps() {
let body = (0..50)
.map(|i| format!("line {i}"))
.collect::<Vec<_>>()
.join("\n");
assert_eq!(count_lines(&body), 50);
let with_nl = format!("{body}\n");
assert_eq!(count_lines(&with_nl), 50);
assert_eq!(count_lines(""), 0);
}
}