clipmem 0.4.0

macOS clipboard memory backed by SQLite and searchable from agent runtimes
Documentation
use super::*;

pub(in crate::cli) fn render_get_human(envelope: &GetEnvelope) -> String {
    let theme = HumanTheme::detect();
    let snapshot = &envelope.snapshot;
    let mut out = header(&theme, "clipmem Snapshot");
    let _ = writeln!(
        out,
        "Generated {}  Filters: {}",
        format_timestamp_short(&envelope.generated_at),
        render_filter_summary(&envelope.applied_filters)
    );
    out.push('\n');

    push_kpi(&mut out, "Snapshot", theme.id(snapshot.snapshot_id()));
    push_kpi(
        &mut out,
        "Kind",
        snapshot.snapshot_kind().as_str().to_string(),
    );
    push_kpi(&mut out, "SHA-256", truncate_cell(snapshot.sha256(), 24));
    push_kpi(
        &mut out,
        "First seen",
        format_timestamp_short(snapshot.first_observed_at()),
    );
    push_kpi(
        &mut out,
        "Last seen",
        format_timestamp_short(snapshot.last_observed_at()),
    );
    push_kpi(&mut out, "Captures", format_count(snapshot.capture_count()));
    push_kpi(&mut out, "Items", format_count(snapshot.item_count()));
    push_kpi(
        &mut out,
        "Size",
        format_bytes(snapshot.total_bytes() as u64),
    );
    if let Some(app) = snapshot
        .last_frontmost_app_name()
        .or(snapshot.last_frontmost_app_bundle_id())
    {
        push_kpi(&mut out, "Last app", app.to_string());
    }
    out.push('\n');

    push_optional_text(&mut out, &theme, "Best Text", snapshot.best_text(), 360);
    if let Some(best_text_uti) = snapshot.best_text_uti() {
        push_kpi(&mut out, "Best text UTI", best_text_uti.to_string());
    }
    push_optional_text(
        &mut out,
        &theme,
        "Text Summary",
        snapshot.text_summary(),
        280,
    );
    if !snapshot.urls().is_empty() {
        push_optional_text(&mut out, &theme, "URLs", &snapshot.urls().join(", "), 280);
    }
    if !snapshot.file_paths().is_empty() {
        push_optional_text(
            &mut out,
            &theme,
            "Files",
            &snapshot.file_paths().join(", "),
            280,
        );
    }
    if let Some(ocr_text) = snapshot.ocr_text() {
        push_optional_text(&mut out, &theme, "OCR", ocr_text, 280);
    }
    if let Some(ocr_status) = snapshot.ocr_status() {
        push_kpi(&mut out, "OCR status", ocr_status.to_string());
    }

    push_snapshot_items(&mut out, &theme, snapshot);
    push_recent_events(&mut out, snapshot);
    out
}

pub(in crate::cli) fn push_snapshot_items(
    out: &mut String,
    theme: &HumanTheme,
    snapshot: &SnapshotDetails,
) {
    out.push('\n');
    let _ = writeln!(out, "{}", theme.section("Items"));
    if snapshot.items().is_empty() {
        out.push_str("No items.\n");
        return;
    }
    out.push_str(&separator(WIDTH, false));
    out.push('\n');
    let _ = writeln!(
        out,
        "{:>4}  {:<22}  {:<7}  {:>8}  {:<12}  Preview",
        "Item", "UTI", "Kind", "Size", "SHA"
    );
    out.push_str(&separator(WIDTH, false));
    out.push('\n');
    for item in snapshot.items() {
        if item.representations().is_empty() {
            let _ = writeln!(
                out,
                "{:>4}  {:<22}  {:<7}  {:>8}  {:<12}  {}",
                item.item_index(),
                item.primary_uti().unwrap_or("unknown"),
                item.primary_kind().as_str(),
                format_bytes(item.total_bytes() as u64),
                "",
                truncate_cell(item.preview_text(), 28)
            );
            continue;
        }
        for (idx, rep) in item.representations().iter().enumerate() {
            let preview = rep.text_value().unwrap_or_else(|| item.preview_text());
            let _ = writeln!(
                out,
                "{:>4}  {:<22}  {:<7}  {:>8}  {:<12}  {}",
                if idx == 0 {
                    item.item_index().to_string()
                } else {
                    String::new()
                },
                truncate_cell(rep.uti(), 22),
                rep.kind().as_str(),
                format_bytes(rep.byte_len() as u64),
                truncate_cell(rep.raw_sha256(), 12),
                truncate_cell(preview, 28)
            );
        }
    }
}

pub(in crate::cli) fn push_recent_events(out: &mut String, snapshot: &SnapshotDetails) {
    out.push('\n');
    out.push_str("Recent Events\n");
    if snapshot.recent_events().is_empty() {
        out.push_str("No recent events.\n");
        return;
    }
    out.push_str(&separator(WIDTH, false));
    out.push('\n');
    let _ = writeln!(
        out,
        "{:>7}  {:<14}  {:>12}  Source",
        "Event", "Observed", "Change"
    );
    out.push_str(&separator(WIDTH, false));
    out.push('\n');
    for event in snapshot.recent_events() {
        let source = event
            .frontmost_app_name()
            .or(event.frontmost_app_bundle_id())
            .unwrap_or("unknown");
        let _ = writeln!(
            out,
            "{:>7}  {:<14}  {:>12}  {}",
            event.event_id(),
            format_timestamp_short(event.observed_at()),
            event.change_count(),
            truncate_cell(source, 46)
        );
    }
}

pub(in crate::cli) fn push_ignored_bundle_table(out: &mut String, bundle_ids: &[String]) {
    if bundle_ids.is_empty() {
        return;
    }
    out.push('\n');
    out.push_str("Ignored Bundle IDs\n");
    out.push_str(&separator(60, false));
    out.push('\n');
    for (idx, bundle_id) in bundle_ids.iter().enumerate() {
        let _ = writeln!(out, "{:>2}. {}", idx + 1, bundle_id);
    }
}

pub(in crate::cli) fn push_provider_row(out: &mut String, provider: &ServiceProviderStatus) {
    let _ = writeln!(
        out,
        "{:<13}  {:<16}  {:>9}  {:>7}  {:>7}  {:<8}  {}",
        provider.provider.as_str(),
        format!("{:?}", provider.state).to_ascii_lowercase(),
        provider.installed,
        provider.loaded,
        provider.running,
        truncate_cell(&provider.label, 8),
        provider
            .pid
            .map(|pid| pid.to_string())
            .unwrap_or_else(|| "-".to_string())
    );
}

pub(in crate::cli) fn push_optional_text(
    out: &mut String,
    theme: &HumanTheme,
    label: &str,
    text: &str,
    limit: usize,
) {
    if text.trim().is_empty() {
        return;
    }
    let _ = writeln!(out, "{}", theme.section(label));
    out.push_str(&truncate_multiline(text, limit));
    out.push('\n');
}

pub(in crate::cli) fn push_kpi(out: &mut String, label: &str, value: String) {
    let _ = writeln!(out, "{:<18} {}", format!("{label}:"), value);
}