tawasuyu

tawasuyu/brahman

Rust 582TOML 222Markdown 83JSON 198635 Definitions

chore(tahuantinsuyu): fase 28 — limpieza de warnings y dead_code

- Reemplaza `Context<Self>` por `Context<'_, Self>` (y la misma
  fórmula para `Context<TahuantinsuyuTree>`) en tree/panel/canvas:
  60 warnings de "hidden lifetime parameters are deprecated" → 0.
- Borra `TREE_WIDTH` y `PANEL_HEIGHT` (constantes muertas) y el
  campo `main_split` del shell (vive como child de outer_split,
  no necesita retención aparte).
- Quita `yahweh-bus` de tahuantinsuyu — el `bus: Entity<AppBus>`
  estaba con `#[allow(dead_code)]` sin cablear. Cuando lo
  necesitemos para coordinación cross-app lo reagregamos.
- Suprime imports `Module` (panel), `AppContext` (canvas) y
  prefija el `cx` no usado en `on_jog_down`.
- Marca `BrahmanStatus::Offline.reason` y `Shell.tree` con
  `#[allow(dead_code)]` documentando por qué se retienen
  (logs y subscripciones).

Workspace ahora compila limpio salvo un warning conocido de
`eternal-validation` (variable `sin_i` sin usar — fuera de
brahman).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

2192c29d4f69af77d17f1c5f6fa1627fe05774ab · by sergio · (5 months ago) · parent a4d1e0dc1 · browse the tree at this commit

Semantic delta · 66

crates/apps/tahuantinsuyu/src/shell.rs

crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs

crates/modules/tahuantinsuyu/tahuantinsuyu-panel/src/lib.rs

crates/modules/tahuantinsuyu/tahuantinsuyu-tree/src/lib.rs

6 files · +77 −81

diff --git a/Cargo.lock b/Cargo.lock
index cbb59c2..005766b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10917,7 +10917,6 @@ dependencies = [
  "tahuantinsuyu-store",
  "tahuantinsuyu-theme",
  "tahuantinsuyu-tree",
- "yahweh-bus",
  "yahweh-core",
  "yahweh-theme",
  "yahweh-widget-container-core",
diff --git a/crates/apps/tahuantinsuyu/Cargo.toml b/crates/apps/tahuantinsuyu/Cargo.toml
index f6e2994..03a85fc 100644
--- a/crates/apps/tahuantinsuyu/Cargo.toml
+++ b/crates/apps/tahuantinsuyu/Cargo.toml
@@ -17,7 +17,6 @@ tahuantinsuyu-theme = { path = "../../modules/tahuantinsuyu/tahuantinsuyu-theme"
 tahuantinsuyu-tree = { path = "../../modules/tahuantinsuyu/tahuantinsuyu-tree" }
 brahman-sidecar = { path = "../../shared/brahman-sidecar" }
 
-yahweh-bus = { workspace = true }
 yahweh-core = { workspace = true }
 yahweh-theme = { workspace = true }
 yahweh-widget-theme-switcher = { path = "../../modules/ui_engine/widgets/theme-switcher" }
diff --git a/crates/apps/tahuantinsuyu/src/shell.rs b/crates/apps/tahuantinsuyu/src/shell.rs
index 6b31c23..4623f5c 100644
--- a/crates/apps/tahuantinsuyu/src/shell.rs
+++ b/crates/apps/tahuantinsuyu/src/shell.rs
@@ -39,16 +39,12 @@ use tahuantinsuyu_model::{Chart, ChartId, ModuleState, TreeSelection};
 use tahuantinsuyu_panel::{ChartOption, ControlPanel, PanelEvent};
 use tahuantinsuyu_store::Store;
 use tahuantinsuyu_tree::{parse_city_atlas_tsv, TahuantinsuyuTree, TreeEvent};
-use yahweh_bus::AppBus;
 use yahweh_core::{LayoutDirection, NodeId};
 use yahweh_theme::Theme;
 use yahweh_widget_container_core::ChildSlot;
 use yahweh_widget_splitter::SplitContainer;
 use yahweh_widget_theme_switcher::theme_switcher;
 
-const TREE_WIDTH: f32 = 280.0;
-const PANEL_HEIGHT: f32 = 180.0;
-
 /// Status del broker brahman tal como lo vimos en el último ping.
 /// Se refresca cada 30 segundos desde un background task.
 #[derive(Clone, Debug)]
@@ -58,22 +54,28 @@ pub enum BrahmanStatus {
     /// Connect OK al broker, devolvió la lista de sessions activas.
     Connected { session_count: usize },
     /// Connect falló — broker no escucha en el socket o tomó timeout.
-    Offline { reason: String },
+    /// `reason` se incluye para diagnóstico en logs aunque la UI hoy
+    /// muestra solo "offline".
+    Offline {
+        #[allow(dead_code)]
+        reason: String,
+    },
 }
 
 pub struct Shell {
     store: Store,
+    /// El árbol vive como child de `outer_split` (vía AnyView clone),
+    /// pero retenemos el Entity acá para que las subscripciones
+    /// registradas en `new` sigan vivas — al droppear el último handle,
+    /// gpui cancela los suscriptores.
     #[allow(dead_code)]
-    bus: Entity<AppBus>,
     tree: Entity<TahuantinsuyuTree>,
     canvas: Entity<AstrologyCanvas>,
     panel: Entity<ControlPanel>,
-    /// Splitter horizontal entre tree (izq) y canvas (der). El divisor
-    /// es draggable — el flex se persiste in-memory mientras la app
-    /// está abierta.
-    main_split: Entity<SplitContainer>,
-    /// Splitter vertical entre el main_row (arriba) y el panel de
-    /// control (abajo).
+    /// Splitter vertical entre el main_row (arriba — tree + canvas) y
+    /// el panel de control (abajo). El splitter horizontal interno se
+    /// arma en `new` y queda referenciado vía `outer_split` (es uno de
+    /// sus children), sin necesidad de retenerlo aparte.
     outer_split: Entity<SplitContainer>,
     /// Último estado conocido del broker brahman — refrescado cada
     /// 30s desde el background task.
@@ -95,7 +97,6 @@ impl Shell {
     pub fn new(store: Store, cx: &mut Context<Self>) -> Self {
         cx.observe_global::<Theme>(|_, cx| cx.notify()).detach();
 
-        let bus = cx.new(|_| AppBus);
         let tree = cx.new(|cx| {
             let mut t = TahuantinsuyuTree::new(store.clone(), cx);
             // Si hay un atlas custom en $XDG_DATA_HOME/tahuantinsuyu/
@@ -169,13 +170,11 @@ impl Shell {
             sc
         });
 
-        let mut shell = Self {
+        let shell = Self {
             store,
-            bus,
             tree,
             canvas,
             panel,
-            main_split,
             outer_split,
             brahman_status: BrahmanStatus::Pending,
             current_chart: None,
@@ -818,7 +817,6 @@ impl Shell {
                 // header con switch (vs. el toggle por-control de hoy).
             }
         }
-        let _ = (&self.store, &self.tree, &self.bus);
     }
 }
 
diff --git a/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs b/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs
index bf174c9..1f5a720 100644
--- a/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs
+++ b/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs
@@ -34,7 +34,7 @@ use std::collections::HashMap;
 use std::f32::consts::PI;
 
 use gpui::{
-    AppContext, Bounds, Context, EventEmitter, FocusHandle, Focusable, Hsla, IntoElement,
+    Bounds, Context, EventEmitter, FocusHandle, Focusable, Hsla, IntoElement,
     KeyDownEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement,
     PathBuilder, Pixels, Point, Render, SharedString, Styled, Window, canvas, div, hsla,
     linear_color_stop, linear_gradient, point, prelude::*, px,
@@ -218,7 +218,7 @@ impl Focusable for AstrologyCanvas {
 }
 
 impl AstrologyCanvas {
-    pub fn new(cx: &mut Context<Self>) -> Self {
+    pub fn new(cx: &mut Context<'_, Self>) -> Self {
         cx.observe_global::<Theme>(|_, cx| cx.notify()).detach();
         Self {
             state: CanvasState::default(),
@@ -230,17 +230,17 @@ impl AstrologyCanvas {
         &self.state
     }
 
-    pub fn set_mode(&mut self, mode: CanvasMode, cx: &mut Context<Self>) {
+    pub fn set_mode(&mut self, mode: CanvasMode, cx: &mut Context<'_, Self>) {
         self.state.mode = mode;
         cx.notify();
     }
 
-    pub fn set_layer_visible(&mut self, kind: LayerKind, visible: bool, cx: &mut Context<Self>) {
+    pub fn set_layer_visible(&mut self, kind: LayerKind, visible: bool, cx: &mut Context<'_, Self>) {
         self.state.layer_visibility.insert(kind, visible);
         cx.notify();
     }
 
-    pub fn toggle_layer(&mut self, kind: LayerKind, cx: &mut Context<Self>) {
+    pub fn toggle_layer(&mut self, kind: LayerKind, cx: &mut Context<'_, Self>) {
         let current = self.state.is_layer_visible(kind);
         self.set_layer_visible(kind, !current, cx);
         cx.emit(CanvasEvent::LayerVisibilityChanged {
@@ -249,7 +249,7 @@ impl AstrologyCanvas {
         });
     }
 
-    pub fn reset_time_offset(&mut self, cx: &mut Context<Self>) {
+    pub fn reset_time_offset(&mut self, cx: &mut Context<'_, Self>) {
         if self.state.time_offset_minutes != 0 || self.state.view_rotation_deg != 0.0 {
             self.state.time_offset_minutes = 0;
             self.state.view_rotation_deg = 0.0;
@@ -258,7 +258,7 @@ impl AstrologyCanvas {
         }
     }
 
-    pub fn set_view_rotation(&mut self, deg: f32, cx: &mut Context<Self>) {
+    pub fn set_view_rotation(&mut self, deg: f32, cx: &mut Context<'_, Self>) {
         self.state.view_rotation_deg = deg.rem_euclid(360.0);
         cx.notify();
     }
@@ -269,7 +269,7 @@ impl AstrologyCanvas {
         &mut self,
         position: Point<Pixels>,
         bounds: Bounds<Pixels>,
-        cx: &mut Context<Self>,
+        _cx: &mut Context<'_, Self>,
     ) {
         let (cx_px, cy_px) = bounds_center(bounds);
         let mx: f32 = position.x.into();
@@ -294,7 +294,7 @@ impl AstrologyCanvas {
         &mut self,
         position: Point<Pixels>,
         bounds: Bounds<Pixels>,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         let Some(jog) = self.state.drag_jog.as_mut() else {
             return;
@@ -327,7 +327,7 @@ impl AstrologyCanvas {
         &mut self,
         position: Point<Pixels>,
         bounds: Bounds<Pixels>,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         let CanvasMode::Wheel { render } = &self.state.mode else {
             if self.state.hover.take().is_some() {
@@ -494,7 +494,7 @@ impl AstrologyCanvas {
         }
     }
 
-    fn on_jog_up(&mut self, cx: &mut Context<Self>) {
+    fn on_jog_up(&mut self, cx: &mut Context<'_, Self>) {
         let Some(jog) = self.state.drag_jog.take() else {
             return;
         };
@@ -516,7 +516,7 @@ impl AstrologyCanvas {
         }
     }
 
-    fn on_key_down(&mut self, event: &KeyDownEvent, _w: &mut Window, cx: &mut Context<Self>) {
+    fn on_key_down(&mut self, event: &KeyDownEvent, _w: &mut Window, cx: &mut Context<'_, Self>) {
         let key = event.keystroke.key.as_str();
         let kind = match key {
             "d" | "D" => LayerKind::SignDial,
@@ -558,7 +558,7 @@ fn bounds_center(bounds: Bounds<Pixels>) -> (f32, f32) {
 // =====================================================================
 
 impl Render for AstrologyCanvas {
-    fn render(&mut self, _w: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+    fn render(&mut self, _w: &mut Window, cx: &mut Context<'_, Self>) -> impl IntoElement {
         let theme = Theme::global(cx).clone();
         let palette = AstroPalette::for_theme(&theme);
         let entity = cx.entity();
diff --git a/crates/modules/tahuantinsuyu/tahuantinsuyu-panel/src/lib.rs b/crates/modules/tahuantinsuyu/tahuantinsuyu-panel/src/lib.rs
index 5396da6..2d5445d 100644
--- a/crates/modules/tahuantinsuyu/tahuantinsuyu-panel/src/lib.rs
+++ b/crates/modules/tahuantinsuyu/tahuantinsuyu-panel/src/lib.rs
@@ -30,7 +30,7 @@ use gpui::{
 };
 
 use tahuantinsuyu_model::ChartKind;
-use tahuantinsuyu_modules::{Control, Module, Registry, SelectOption};
+use tahuantinsuyu_modules::{Control, Registry, SelectOption};
 use yahweh_theme::Theme;
 
 // =====================================================================
@@ -101,7 +101,7 @@ pub struct ControlPanel {
 impl EventEmitter<PanelEvent> for ControlPanel {}
 
 impl ControlPanel {
-    pub fn new(cx: &mut Context<Self>) -> Self {
+    pub fn new(cx: &mut Context<'_, Self>) -> Self {
         cx.observe_global::<Theme>(|_, cx| cx.notify()).detach();
         Self {
             active_kind: None,
@@ -134,13 +134,13 @@ impl ControlPanel {
             .unwrap_or(false)
     }
 
-    fn toggle_collapsed(&mut self, module_id: String, cx: &mut Context<Self>) {
+    fn toggle_collapsed(&mut self, module_id: String, cx: &mut Context<'_, Self>) {
         let current = self.is_collapsed(&module_id);
         self.collapse_overrides.insert(module_id, !current);
         cx.notify();
     }
 
-    pub fn set_active_kind(&mut self, kind: Option<ChartKind>, cx: &mut Context<Self>) {
+    pub fn set_active_kind(&mut self, kind: Option<ChartKind>, cx: &mut Context<'_, Self>) {
         if self.active_kind != kind {
             if let Some(k) = kind {
                 for m in self.registry.for_kind(k) {
@@ -180,7 +180,7 @@ impl ControlPanel {
 
     /// Setea un toggle desde afuera (sin emitir evento). Usado por el
     /// shell para sincronizar cuando el canvas se autotoggleó via hotkey.
-    pub fn set_toggle(&mut self, module_id: &str, key: &str, value: bool, cx: &mut Context<Self>) {
+    pub fn set_toggle(&mut self, module_id: &str, key: &str, value: bool, cx: &mut Context<'_, Self>) {
         self.toggle_state
             .insert((module_id.to_string(), key.to_string()), value);
         cx.notify();
@@ -189,7 +189,7 @@ impl ControlPanel {
     /// Setea un slider desde afuera (sin emitir evento). El shell la
     /// usa, por ejemplo, para inicializar `progression.target_age_years`
     /// con la edad actual del sujeto al cargar una carta nueva.
-    pub fn set_slider(&mut self, module_id: &str, key: &str, value: f64, cx: &mut Context<Self>) {
+    pub fn set_slider(&mut self, module_id: &str, key: &str, value: f64, cx: &mut Context<'_, Self>) {
         self.slider_state
             .insert((module_id.to_string(), key.to_string()), value);
         cx.notify();
@@ -199,7 +199,7 @@ impl ControlPanel {
     /// `Control::ChartPicker`. El shell la llama cada vez que la
     /// jerarquía de cartas cambia (crear/borrar) para que el dropdown
     /// quede al día sin necesidad de re-instanciar el panel.
-    pub fn set_chart_options(&mut self, options: Vec<ChartOption>, cx: &mut Context<Self>) {
+    pub fn set_chart_options(&mut self, options: Vec<ChartOption>, cx: &mut Context<'_, Self>) {
         self.chart_options = options;
         cx.notify();
     }
@@ -212,7 +212,7 @@ impl ControlPanel {
         module_id: &str,
         key: &str,
         value: Option<String>,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         self.string_state
             .insert((module_id.to_string(), key.to_string()), value);
@@ -226,14 +226,14 @@ impl ControlPanel {
         module_id: &str,
         key: &str,
         chart_id: Option<String>,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         self.set_string(module_id, key, chart_id, cx);
     }
 
     // ----- internos: handlers -----
 
-    fn on_toggle_click(&mut self, module_id: String, key: String, cx: &mut Context<Self>) {
+    fn on_toggle_click(&mut self, module_id: String, key: String, cx: &mut Context<'_, Self>) {
         let entry = self
             .toggle_state
             .entry((module_id.clone(), key.clone()))
@@ -256,7 +256,7 @@ impl ControlPanel {
         max: f64,
         bounds: Bounds<Pixels>,
         position: Point<Pixels>,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         self.slider_drag = Some(SliderDrag {
             module_id: module_id.clone(),
@@ -271,20 +271,20 @@ impl ControlPanel {
         &mut self,
         bounds: Bounds<Pixels>,
         position: Point<Pixels>,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         if self.slider_drag.is_some() {
             self.apply_slider_position(bounds, position, cx);
         }
     }
 
-    fn end_slider_drag(&mut self, cx: &mut Context<Self>) {
+    fn end_slider_drag(&mut self, cx: &mut Context<'_, Self>) {
         if self.slider_drag.take().is_some() {
             cx.notify();
         }
     }
 
-    fn toggle_dropdown_open(&mut self, module_id: String, key: String, cx: &mut Context<Self>) {
+    fn toggle_dropdown_open(&mut self, module_id: String, key: String, cx: &mut Context<'_, Self>) {
         let key_pair = (module_id, key);
         let new_state = match self.dropdown_open.as_ref() {
             Some(open) if open == &key_pair => None,
@@ -299,7 +299,7 @@ impl ControlPanel {
         module_id: String,
         key: String,
         value: Option<String>,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         self.string_state
             .insert((module_id.clone(), key.clone()), value.clone());
@@ -320,7 +320,7 @@ impl ControlPanel {
         &mut self,
         bounds: Bounds<Pixels>,
         position: Point<Pixels>,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         let Some(drag) = self.slider_drag.as_ref().cloned() else {
             return;
@@ -354,7 +354,7 @@ const SLIDER_TRACK_H: f32 = 8.0;
 const SLIDER_THUMB: f32 = 12.0;
 
 impl Render for ControlPanel {
-    fn render(&mut self, _w: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+    fn render(&mut self, _w: &mut Window, cx: &mut Context<'_, Self>) -> impl IntoElement {
         let theme = Theme::global(cx).clone();
         let modules: Vec<(String, String, String, Vec<Control>)> = match self.active_kind {
             Some(k) => self
@@ -438,7 +438,7 @@ impl ControlPanel {
         label: &str,
         description: &str,
         controls: &[Control],
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) -> gpui::Div {
         let collapsed = self.is_collapsed(module_id);
         let chevron = if collapsed { "▸" } else { "▾" };
@@ -510,7 +510,7 @@ impl ControlPanel {
         theme: &Theme,
         module_id: &str,
         c: &Control,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) -> gpui::Div {
         match c {
             Control::Toggle {
@@ -548,7 +548,7 @@ impl ControlPanel {
         label: &str,
         default: bool,
         hotkey: Option<&str>,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) -> gpui::Div {
         let active = self
             .toggle_state
@@ -606,7 +606,7 @@ impl ControlPanel {
         min: f64,
         max: f64,
         default: f64,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) -> gpui::Div {
         let value = self
             .slider_state
@@ -750,7 +750,7 @@ impl ControlPanel {
         module_id: &str,
         key: &str,
         label: &str,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) -> gpui::Div {
         let options: Vec<(String, String)> = self
             .chart_options
@@ -777,7 +777,7 @@ impl ControlPanel {
         label: &str,
         options: &[SelectOption],
         default: &str,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) -> gpui::Div {
         let opts: Vec<(String, String)> = options
             .iter()
@@ -801,7 +801,7 @@ impl ControlPanel {
         placeholder: &str,
         options: &[(String, String)],
         include_auto: bool,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) -> gpui::Div {
         let current_value = self
             .string_state
@@ -877,7 +877,7 @@ impl ControlPanel {
         key: &str,
         options: &[(String, String)],
         include_auto: bool,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) -> gpui::Div {
         let mut popup = div()
             .absolute()
diff --git a/crates/modules/tahuantinsuyu/tahuantinsuyu-tree/src/lib.rs b/crates/modules/tahuantinsuyu/tahuantinsuyu-tree/src/lib.rs
index a19b1ff..2919c69 100644
--- a/crates/modules/tahuantinsuyu/tahuantinsuyu-tree/src/lib.rs
+++ b/crates/modules/tahuantinsuyu/tahuantinsuyu-tree/src/lib.rs
@@ -330,7 +330,7 @@ pub fn parse_city_atlas_tsv(content: &str) -> Vec<CityPreset> {
 impl EventEmitter<TreeEvent> for TahuantinsuyuTree {}
 
 impl TahuantinsuyuTree {
-    pub fn new(store: Store, cx: &mut Context<Self>) -> Self {
+    pub fn new(store: Store, cx: &mut Context<'_, Self>) -> Self {
         cx.observe_global::<Theme>(|_, cx| cx.notify()).detach();
 
         let inner = cx.new(|cx| TreeView::new("tahuantinsuyu-tree", cx));
@@ -373,14 +373,14 @@ impl TahuantinsuyuTree {
 
     /// Reemplaza el atlas de ciudades del dropdown. La app llama esto
     /// al boot si encuentra un archivo TSV custom en disco.
-    pub fn set_city_atlas(&mut self, atlas: Vec<CityPreset>, cx: &mut Context<Self>) {
+    pub fn set_city_atlas(&mut self, atlas: Vec<CityPreset>, cx: &mut Context<'_, Self>) {
         if !atlas.is_empty() {
             self.city_atlas = atlas;
             cx.notify();
         }
     }
 
-    pub fn refresh(&mut self, cx: &mut Context<Self>) {
+    pub fn refresh(&mut self, cx: &mut Context<'_, Self>) {
         let mut rows = Vec::new();
         self.append_groups(None, 0, &mut rows);
         self.append_contacts(None, 0, &mut rows);
@@ -391,7 +391,7 @@ impl TahuantinsuyuTree {
     /// Cuando hay filtro, expande automáticamente los ancestros que
     /// contienen matches para que el usuario vea los resultados sin
     /// tener que clickear chevrons.
-    fn set_search_filter(&mut self, filter: String, cx: &mut Context<Self>) {
+    fn set_search_filter(&mut self, filter: String, cx: &mut Context<'_, Self>) {
         self.search_filter = filter.trim().to_lowercase();
         if !self.search_filter.is_empty() {
             self.auto_expand_matches();
@@ -584,7 +584,7 @@ impl TahuantinsuyuTree {
         }
     }
 
-    fn on_inner(&mut self, ev: &InnerTreeEvent, cx: &mut Context<Self>) {
+    fn on_inner(&mut self, ev: &InnerTreeEvent, cx: &mut Context<'_, Self>) {
         match ev {
             InnerTreeEvent::ChevronToggled(id) => {
                 let s = id.as_str().to_string();
@@ -626,20 +626,20 @@ impl TahuantinsuyuTree {
     // Acciones del menú
     // -----------------------------------------------------------------
 
-    fn close_menu(&mut self, cx: &mut Context<Self>) {
+    fn close_menu(&mut self, cx: &mut Context<'_, Self>) {
         if self.menu.take().is_some() {
             cx.notify();
         }
     }
 
-    fn close_modal(&mut self, cx: &mut Context<Self>) {
+    fn close_modal(&mut self, cx: &mut Context<'_, Self>) {
         if self.modal.take().is_some() {
             self.city_picker_open = false;
             cx.notify();
         }
     }
 
-    fn toggle_city_picker(&mut self, cx: &mut Context<Self>) {
+    fn toggle_city_picker(&mut self, cx: &mut Context<'_, Self>) {
         self.city_picker_open = !self.city_picker_open;
         cx.notify();
     }
@@ -647,7 +647,7 @@ impl TahuantinsuyuTree {
     /// Aplica un city preset al ChartForm activo (CreateChart o
     /// EditChart). Setea place, lat, lon, tz_offset_min vía
     /// `TextInput::set_text` y cierra el picker.
-    fn apply_city_preset(&mut self, preset: &CityPreset, cx: &mut Context<Self>) {
+    fn apply_city_preset(&mut self, preset: &CityPreset, cx: &mut Context<'_, Self>) {
         let form = match self.modal.as_mut() {
             Some(Modal::CreateChart { form, .. }) => form,
             Some(Modal::EditChart { form, .. }) => form,
@@ -677,7 +677,7 @@ impl TahuantinsuyuTree {
         &mut self,
         parent: Option<GroupId>,
         window: &mut Window,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         let input = self.make_input("Nombre del grupo", "", window, cx);
         self.modal = Some(Modal::CreateGroup { parent, input });
@@ -688,7 +688,7 @@ impl TahuantinsuyuTree {
         &mut self,
         group: Option<GroupId>,
         window: &mut Window,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         let input = self.make_input("Nombre del contacto", "", window, cx);
         self.modal = Some(Modal::CreateContact { group, input });
@@ -699,7 +699,7 @@ impl TahuantinsuyuTree {
         &mut self,
         id: ChartId,
         window: &mut Window,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         // Cargar la carta existente; si no se puede, fallamos en silencio.
         let chart = match self.store.get_chart(id) {
@@ -751,7 +751,7 @@ impl TahuantinsuyuTree {
         &mut self,
         contact: ContactId,
         window: &mut Window,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         // Pre-cargamos el nombre del contacto en el campo "Sujeto" del
         // form como conveniencia — la mayoría de las cartas se nombran
@@ -795,7 +795,7 @@ impl TahuantinsuyuTree {
         self.close_menu(cx);
     }
 
-    fn open_rename(&mut self, target: MenuTarget, window: &mut Window, cx: &mut Context<Self>) {
+    fn open_rename(&mut self, target: MenuTarget, window: &mut Window, cx: &mut Context<'_, Self>) {
         let modal = match target {
             MenuTarget::Group(id) => {
                 let current = self
@@ -847,7 +847,7 @@ impl TahuantinsuyuTree {
         placeholder: &str,
         initial: &str,
         window: &mut Window,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) -> Entity<TextInput> {
         let placeholder = placeholder.to_string();
         let input = cx.new(|cx| {
@@ -862,14 +862,14 @@ impl TahuantinsuyuTree {
         input
     }
 
-    fn on_input_event(&mut self, ev: &TextInputEvent, cx: &mut Context<Self>) {
+    fn on_input_event(&mut self, ev: &TextInputEvent, cx: &mut Context<'_, Self>) {
         match ev {
             TextInputEvent::Cancelled => self.close_modal(cx),
             TextInputEvent::Confirmed(value) => self.submit_modal(value.clone(), cx),
         }
     }
 
-    fn submit_modal(&mut self, value: String, cx: &mut Context<Self>) {
+    fn submit_modal(&mut self, value: String, cx: &mut Context<'_, Self>) {
         let trimmed = value.trim().to_string();
         // Tomamos ownership del modal — si el submit falla en mitad,
         // lo restablecemos. Esto evita un borrow-mut sobre self.modal.
@@ -1012,7 +1012,7 @@ impl TahuantinsuyuTree {
         }
     }
 
-    fn after_mutation(&mut self, cx: &mut Context<Self>) {
+    fn after_mutation(&mut self, cx: &mut Context<'_, Self>) {
         self.modal = None;
         self.refresh(cx);
         cx.emit(TreeEvent::HierarchyChanged);
@@ -1023,7 +1023,7 @@ impl TahuantinsuyuTree {
         &mut self,
         target: MenuTarget,
         window: &mut Window,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) {
         let (label, kind) = match target {
             MenuTarget::Group(_) => ("este grupo (incluye sus subgrupos y contactos)", "group"),
@@ -1072,7 +1072,7 @@ impl TahuantinsuyuTree {
 
 fn build_chart_from_form(
     form: &ChartForm,
-    cx: &mut Context<TahuantinsuyuTree>,
+    cx: &mut Context<'_, TahuantinsuyuTree>,
 ) -> Result<(StoredBirthData, String), String> {
     let name = form.name.read(cx).text().trim().to_string();
     let place = form.place.read(cx).text().trim().to_string();
@@ -1208,7 +1208,7 @@ fn parse_row(id: &RowId) -> Option<TreeSelection> {
 const MENU_WIDTH: f32 = 220.0;
 
 impl Render for TahuantinsuyuTree {
-    fn render(&mut self, _w: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+    fn render(&mut self, _w: &mut Window, cx: &mut Context<'_, Self>) -> impl IntoElement {
         let theme = Theme::global(cx).clone();
         let search_bar = div()
             .px(px(6.0))
@@ -1242,7 +1242,7 @@ impl TahuantinsuyuTree {
         &self,
         theme: &Theme,
         menu: MenuState,
-        cx: &mut Context<Self>,
+        cx: &mut Context<'_, Self>,
     ) -> impl IntoElement {
         let mut items = div()
             .flex()
@@ -1353,7 +1353,7 @@ impl TahuantinsuyuTree {
             .child(items)
     }
 
-    fn render_modal(&self, theme: &Theme, cx: &mut Context<Self>) -> impl IntoElement {
+    fn render_modal(&self, theme: &Theme, cx: &mut Context<'_, Self>) -> impl IntoElement {
         let modal = self.modal.as_ref().expect("render_modal sin modal activo");
         let inner = match modal {
             Modal::RenameGroup { input, .. }
@@ -1454,7 +1454,7 @@ fn render_chart_form(
     title: &str,
     form: &ChartForm,
     error: Option<SharedString>,
-    cx: &mut Context<TahuantinsuyuTree>,
+    cx: &mut Context<'_, TahuantinsuyuTree>,
 ) -> gpui::Div {
     let labeled = |label: &'static str, input: Entity<TextInput>| -> gpui::Div {
         div()