//! The Placeholders window: every `[TODO]`/`[TK]`/`[???]`-style marker left //! in the manuscript, so a fast first-draft pass doesn't lose track of the //! gaps it left behind. use super::*; use crate::placeholder_scan::find_placeholders; impl App { /// The Placeholders window: one row per marker found, grouped by file in /// manuscript order. Clicking a row jumps straight to it. pub(super) fn placeholders_window(&mut self, ctx: &egui::Context) { let mut open = self.show_placeholders; // Collect up front (reads the in-memory buffer for the open file, // disk for the rest), so the window closure only reads. let selected_name = self.selected.and_then(|i| self.files.get(i)).cloned(); let rows: Vec<(String, Vec)> = self .manuscript_files() .into_iter() .filter_map(|(_, name)| { let raw = if Some(name) == selected_name.as_ref() { self.document().into_owned() } else { std::fs::read_to_string(self.path_for(name)).unwrap_or_default() }; let found = find_placeholders(&raw); if found.is_empty() { None } else { Some((name.clone(), found)) } }) .collect(); let total: usize = rows.iter().map(|(_, m)| m.len()).sum(); let mut jump_to: Option<(String, usize, usize)> = None; egui::Window::new("Placeholders") .open(&mut open) .resizable(true) .collapsible(false) .default_width(480.0) .default_height(420.0) .show(ctx, |ui| { ui.label( egui::RichText::new( "Bracketed markers like [TODO], [TK], [FIXME] or [???] left in \ the draft. Click one to jump to it.", ) .small() .weak(), ); ui.separator(); egui::ScrollArea::vertical() .auto_shrink([false, false]) .show(ui, |ui| { if total == 0 { ui.label("No placeholders found โ€” ๐ŸŽ‰"); return; } for (name, found) in &rows { ui.label(egui::RichText::new(name).strong()); for marker in found { if ui .link(format!(" line {} ยท [{}]", marker.line, marker.marker)) .clicked() { jump_to = Some((name.clone(), marker.start, marker.end)); } } ui.add_space(4.0); } }); }); if let Some((name, start, end)) = jump_to { if let Some(idx) = self.files.iter().position(|f| *f == name) { self.select(idx); self.issue_jump = Some((start, end)); } } self.show_placeholders = open; } }