pub fn longest_backtick_run(s: &str) -> usize {
let mut max = 0;
let mut cur = 0;
for ch in s.chars() {
if ch == '`' {
cur += 1;
max = max.max(cur);
} else {
cur = 0;
}
}
max
}
pub fn md_code_block(commands: &[String]) -> String {
let max_run = commands
.iter()
.map(|c| longest_backtick_run(c))
.max()
.unwrap_or(0);
let fence = "`".repeat(max_run.max(2) + 1);
let mut out = String::new();
out.push_str(&fence);
out.push_str("bash\n");
for c in commands {
out.push_str(c);
out.push('\n');
}
out.push_str(&fence);
out.push('\n');
out
}
pub fn md_inline_code(s: &str) -> String {
let ticks = "`".repeat(longest_backtick_run(s) + 1);
let pad = if s.starts_with('`') || s.ends_with('`') {
" "
} else {
""
};
format!("{ticks}{pad}{s}{pad}{ticks}")
}
pub fn md_table_cell_text(s: &str) -> String {
s.replace('|', "\\|").replace(['\n', '\r'], " ")
}
pub fn md_table_cell_code(s: &str) -> String {
let oneline = s.replace(['\n', '\r'], " ");
let escaped = oneline.replace('|', "\\|");
md_inline_code(&escaped)
}
pub fn display_home(path: &str) -> String {
if let Some(home) = dirs::home_dir() {
if let Some(home_str) = home.to_str() {
if let Some(rest) = path.strip_prefix(home_str) {
let rest = rest.trim_start_matches('/');
if rest.is_empty() {
return "~".to_string();
}
return format!("~/{rest}");
}
}
}
path.to_string()
}
pub fn opt_home(value: &Option<String>) -> String {
value
.as_deref()
.filter(|s| !s.is_empty())
.map(display_home)
.unwrap_or_else(|| "-".to_string())
}
pub fn opt(value: &Option<String>) -> String {
value
.as_deref()
.filter(|s| !s.is_empty())
.unwrap_or("-")
.to_string()
}
pub fn time_part(created_at: &str) -> &str {
created_at.split_whitespace().nth(1).unwrap_or(created_at)
}
pub fn short_datetime(created_at: &str) -> &str {
created_at.get(..16).unwrap_or(created_at)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn inline_code_protege_les_backticks() {
assert_eq!(md_inline_code("ls"), "`ls`");
assert_eq!(md_inline_code("echo `date`"), "`` echo `date` ``");
}
#[test]
fn code_block_choisit_une_cloture_assez_longue() {
let block = md_code_block(&["echo ```x```".to_string()]);
assert!(block.starts_with("````bash\n"));
assert!(block.trim_end().ends_with("````"));
}
#[test]
fn table_cell_echappe_les_pipes() {
let cell = md_table_cell_code("grep -E 'a|b'");
assert!(cell.contains("\\|"));
assert!(!cell.contains("a|b"));
}
#[test]
fn horaire_et_date_courte() {
assert_eq!(time_part("2026-06-23 10:12:01"), "10:12:01");
assert_eq!(short_datetime("2026-06-23 10:12:01"), "2026-06-23 10:12");
}
}