Files
brahman/crates/modules/nahual/libs/launcher/src/lib.rs
T
sergio 550c98f275 refactor(monorepo): reorganización lógica + renames + SDDs + split CHANGELOG
Reorganización física de crates/:
- core/ (mezclaba 6 propósitos) se divide en protocol/, init/, runtime/, compat/
- shared/ (3 crates) se redistribuye en protocol/ e init/
- lapaloma (sub-módulo de ui_engine) se promueve a modules/pineal/

Renames de proyectos:
- shipote → shuma (runtime de sandboxes)
- nouser → akasha (explorador de Mónadas)
- yahweh → nahual (motor GPUI, antes ui_engine/)
- lapaloma → pineal (data-viz agnóstica)

Fraccionamiento UI → core agnóstico:
- vista-core (DeckState + snap, 175 LOC, 5 tests verdes)
- barra-core (Task + render_html + sanitize, 90 LOC, 5 tests verdes)
- vista-web y barra-web ahora son thin DOM bindings

Documentación nueva:
- 16 SDDs por subdirectorio (≤80 LOC c/u): protocol/init/runtime/compat
  + 10 módulos + apps/
- docs/STATUS.md con cifras reales por proyecto
- docs/ROADMAP.md con plan a finalización (6 hitos, ~6-8 semanas)
- CHANGELOG.md particionado en docs/changelog/<proyecto>.md (7 buckets)

Automatización:
- scripts/reorg.py — script idempotente que: git mv directorios, renombra
  package names, recomputa path = refs, reescribe imports rust, actualiza
  workspace Cargo.toml. Soporta --dry-run.
- scripts/split-changelog.py — particiona CHANGELOG por componente.

Validación:
- cargo check --workspace pasa (124 crates + 2 nuevos cores).
- 10 tests adicionales (5 en vista-core + 5 en barra-core) verdes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 14:48:34 +00:00

124 lines
4.0 KiB
Rust

//! Yahweh shell — reduce el boot de un app GPUI temed a una línea.
//!
//! Las 4 (próximamente más) apps explorer del repo declaran el mismo
//! patrón: `Application::new + Theme::install_default + cx.open_window
//! + cx.activate(true)`. Sólo varían el título, el tamaño inicial y la
//! fábrica del root entity.
//!
//! Antes (~20 líneas):
//!
//! ```ignore
//! Application::new().run(|cx: &mut App| {
//! Theme::install_default(cx);
//! let bounds = Bounds::centered(None, gpui::size(px(900.), px(640.)), cx);
//! cx.open_window(
//! WindowOptions {
//! window_bounds: Some(WindowBounds::Windowed(bounds)),
//! titlebar: Some(gpui::TitlebarOptions {
//! title: Some(SharedString::from("Nakui — Event Log")),
//! ..Default::default()
//! }),
//! ..Default::default()
//! },
//! |_w, cx| cx.new(Explorer::new),
//! ).expect("open window");
//! cx.activate(true);
//! });
//! ```
//!
//! Ahora (1 línea):
//!
//! ```ignore
//! launch_app("Nakui — Event Log", (900., 640.), Explorer::new);
//! ```
use gpui::{
App, AppContext, Application, Bounds, Context, Render, SharedString, TitlebarOptions,
WindowBounds, WindowOptions, px,
};
use nahual_theme::Theme;
/// Configuración del primer (y normalmente único) ventana del app.
///
/// `size` es `(ancho, alto)` en píxeles lógicos. La ventana queda
/// centrada en el monitor primario.
pub struct AppLaunchConfig {
pub title: SharedString,
pub size: (f32, f32),
}
impl AppLaunchConfig {
pub fn new(title: impl Into<SharedString>, size: (f32, f32)) -> Self {
Self {
title: title.into(),
size,
}
}
}
/// Levanta un app GPUI con tema instalado y root entity construido.
///
/// El root debe implementar `Render`. La fábrica `root_factory` recibe
/// el `Context<T>` del nuevo entity para que pueda usar `cx.spawn`,
/// suscribirse a eventos, etc — lo mismo que en el patrón directo.
///
/// Bloquea el thread main hasta que se cierre la ventana
/// (`Application::run` no retorna).
pub fn launch_app<T, F>(title: impl Into<SharedString>, size: (f32, f32), root_factory: F)
where
T: Render + 'static,
F: FnOnce(&mut Context<T>) -> T + Send + 'static,
{
launch_app_with(AppLaunchConfig::new(title, size), root_factory);
}
/// Variante que acepta un `AppLaunchConfig` armado afuera. Útil cuando
/// el config se calcula condicionalmente (env var para tamaño, etc).
pub fn launch_app_with<T, F>(config: AppLaunchConfig, root_factory: F)
where
T: Render + 'static,
F: FnOnce(&mut Context<T>) -> T + Send + 'static,
{
Application::new().run(move |cx: &mut App| {
Theme::install_default(cx);
let bounds = Bounds::centered(None, gpui::size(px(config.size.0), px(config.size.1)), cx);
cx.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
titlebar: Some(TitlebarOptions {
title: Some(config.title.clone()),
..Default::default()
}),
..Default::default()
},
|_w, cx| cx.new(root_factory),
)
.expect("open window");
cx.activate(true);
});
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn config_new_normalizes_inputs() {
let c = AppLaunchConfig::new("My App", (800.0, 600.0));
assert_eq!(c.title.as_ref(), "My App");
assert_eq!(c.size, (800.0, 600.0));
}
#[test]
fn config_accepts_owned_string_title() {
let owned = String::from("Owned Title");
let c = AppLaunchConfig::new(owned, (400.0, 300.0));
assert_eq!(c.title.as_ref(), "Owned Title");
}
// No hay test de `launch_app` aquí: bloquea el thread main hasta
// que la ventana se cierre, y en sandbox no hay DISPLAY. La
// cobertura real es que cada explorer app lo invoque y arranque
// (smoke test manual o con DISPLAY).
}