Expand description
llimphi-module-fif — find-in-files reutilizable (estilo JetBrains).
Módulo Llimphi con dos vistas independientes:
view_dialog— popup compacto (header + input) que el host pinta como overlay modal centrado. Sólo visible cuandoFifState::dialog_openestrue.view_results_bar— barra inferior persistente con la lista de matches. El host la pinta como tool window al pie (estilo JetBrains “Find” tool window). Sobrevive al cierre del dialog: el user puede Esc-cerrar el popup y seguir clickeando los resultados.
El flujo típico es: Ctrl+Shift+F abre el dialog → tipear → Enter
ejecuta search → resultados aparecen en la barra inferior → Esc
cierra el popup pero la barra queda → click en una fila abre el
archivo. Re-disparar Ctrl+Shift+F reabre el popup conservando los
últimos resultados.
§Cómo lo enchufa una app
ⓘ
struct AppModel {
all_files: Vec<PathBuf>,
fif: Option<FifState>,
// …
}
enum AppMsg { Fif(llimphi_module_fif::FifMsg), … }
// En update(model, msg):
AppMsg::Fif(fm) => {
// Lazy-init en Open:
if matches!(fm, FifMsg::Open) && model.fif.is_none() {
model.fif = Some(FifState::new());
} else if matches!(fm, FifMsg::Open) {
model.fif.as_mut().unwrap().dialog_open = true;
}
let action = match model.fif.as_mut() {
Some(s) => llimphi_module_fif::apply(s, fm, &model.all_files),
None => FifAction::None,
};
match action {
FifAction::None => {}
FifAction::CloseDialog => {
if let Some(s) = model.fif.as_mut() { s.dialog_open = false; }
}
FifAction::CloseAll => model.fif = None,
FifAction::Searched { .. } => { /* actualizar status bar */ }
FifAction::OpenAt { path, line, col } => {
if let Some(s) = model.fif.as_mut() { s.dialog_open = false; }
open_path_in_app(path, line, col);
}
}
}
// En on_key(model, event): solo rutea cuando el dialog está visible.
if let Some(state) = model.fif.as_ref() {
if let Some(fm) = llimphi_module_fif::on_key(state, event) {
return Some(AppMsg::Fif(fm));
}
}
if llimphi_module_fif::open_shortcut(event) {
return Some(AppMsg::Fif(FifMsg::Open));
}
// En view(model):
// - dialog como overlay arriba del editor:
if let Some(s) = model.fif.as_ref().filter(|s| s.dialog_open) {
overlay_children.push(view_dialog(s, &palette, AppMsg::Fif));
}
// - barra de resultados como panel inferior persistente:
if let Some(s) = model.fif.as_ref().filter(|s| !s.results.is_empty()) {
bottom_panels.push(view_results_bar(
s, &model.all_files, &model.root, &palette, AppMsg::Fif,
));
}§Por qué Action en lugar de un trait FifHost
El módulo no toma &mut Host porque acoplar el módulo a un trait
arrastra problemas de ownership/lifetimes en el loop tipo Elm que usa
Llimphi (Model se mueve por value en update). Devolver una FifAction
deja al host libre de aplicar el efecto donde y como quiera, y mantiene
al módulo libre de cualquier conocimiento sobre el host.
Structs§
- FifMatch
- Un match individual.
- FifPalette
- Paleta visual. Construible desde un
llimphi_theme::Theme. - FifState
- Estado interno del módulo.
Enums§
- FifAction
- Efecto solicitado al host. El módulo nunca toca el FS ni el resto del modelo de la app — devuelve el deseo, el host elige cómo lo aplica.
- FifFocus
- Qué input tiene el foco dentro del dialog.
Tabalterna. - FifMsg
- Vocabulario interno. El host lo wrapea en su propio Msg.
Constants§
- CAPABILITIES
- Capabilities que este módulo aporta al host. Convención del protocolo
Brahman Card aplicada a módulos compile-time: el host (cuando construye
su [
card_core::Card]) puede agregar esto aprovidespara anunciar — vía broker — que su instancia ofrece find-in-files al ecosistema. - MAX_
FILE_ SIZE - MAX_
RESULTS - Caps razonables para que un workspace grande no funda el UI.
- MIN_
QUERY_ LEN - SNIPPET_
MAX_ CHARS
Functions§
- apply
- Aplica un mensaje al estado y retorna el efecto que el host debe ejecutar.
- on_key
- Routing de teclas cuando el dialog está abierto. Si el popup está
cerrado, devuelve
Noney el host puede seguir routeando al editor. - open_
shortcut - Chequea si el evento es el atajo recomendado: Ctrl+Shift+F. El host puede ignorar esto y definir su propio binding.
- replace_
all - Reemplazo case-insensitive sobre los archivos involucrados en
results. Devuelve(files_changed, replacements, failures). Lee cada archivo una sola vez, sustituye todas las apariciones dequeryporreplacement(case-insensitive, preservando el resto), y escribe sólo si hubo cambios. No toca buffers en memoria del host — el host es responsable de recargar tabs si quiere ver los cambios. - search
- Búsqueda substring case-insensitive. Pública para tests / hosts que quieran disparar una búsqueda sin pasar por el state machine.
- view_
dialog - Popup modal compacto: header + input. Sin lista de resultados — esa
vive en
view_results_bar. El host lo pinta como overlay centrado. - view_
results_ bar - Barra inferior persistente con los matches. Filas clickeables (click
→
FifMsg::ActivateAt). El host la pinta como tool window al pie del editor, hermana del terminal/output (estilo JetBrains).