256 lines
6.7 KiB
Markdown
256 lines
6.7 KiB
Markdown
# Refactorización Modular 2025-12-29
|
|
|
|
> **Objetivo:** Reducir archivos monolíticos (>700 LOC) a estructuras modulares mantenibles.
|
|
|
|
---
|
|
|
|
## Resumen Ejecutivo
|
|
|
|
| Módulo | Antes | Hub | Reducción |
|
|
|--------|-------|-----|-----------|
|
|
| autocomplete | 910 LOC | 571 LOC | **-37%** |
|
|
| icon | 805 LOC | 515 LOC | **-36%** |
|
|
| textarea | Ya modular | 404 LOC | - |
|
|
| progress | Ya modular | ~300 LOC | - |
|
|
|
|
**Archivos residuales eliminados:** `textarea.zig`, `progress.zig` (duplicados de carpetas existentes)
|
|
|
|
---
|
|
|
|
## Patrón de Modularización
|
|
|
|
### Estructura Estándar
|
|
|
|
```
|
|
widget/
|
|
├── widget.zig # Hub: API pública, re-exports, lógica principal
|
|
├── types.zig # Tipos, enums, Config, Colors, Result
|
|
├── state.zig # Estado del widget (si es stateful)
|
|
└── helpers.zig # Funciones auxiliares específicas
|
|
```
|
|
|
|
### Principios
|
|
|
|
1. **Hub Mínimo**: El archivo principal solo contiene API pública y lógica core
|
|
2. **Tipos Separados**: Todos los `struct`, `enum`, `Config`, `Colors` van a `types.zig`
|
|
3. **Estado Aislado**: Estado mutable con sus métodos en `state.zig`
|
|
4. **Helpers Específicos**: Funciones de dibujo, filtrado, etc. en su propio archivo
|
|
5. **Re-exports**: El hub re-exporta todo para compatibilidad con código existente
|
|
|
|
---
|
|
|
|
## autocomplete/ (910 → 571 LOC, -37%)
|
|
|
|
### Estructura
|
|
|
|
```
|
|
src/widgets/autocomplete/
|
|
├── autocomplete.zig (571 LOC) - Hub con API y lógica principal
|
|
├── state.zig (200 LOC) - AutoCompleteState + buffer management
|
|
├── types.zig (89 LOC) - MatchMode, Config, Colors, Result
|
|
└── filtering.zig (106 LOC) - matchesFilter, matchesPrefix, matchesFuzzy
|
|
```
|
|
|
|
### Archivos Modificados
|
|
|
|
- `widgets.zig`: Import actualizado a `autocomplete/autocomplete.zig`
|
|
|
|
### Detalles de Extracción
|
|
|
|
**state.zig:**
|
|
```zig
|
|
pub const AutoCompleteState = struct {
|
|
buffer: [256]u8 = [_]u8{0} ** 256,
|
|
cursor: usize = 0,
|
|
// ... métodos de gestión de buffer
|
|
};
|
|
```
|
|
|
|
**types.zig:**
|
|
```zig
|
|
pub const MatchMode = enum { prefix, contains, fuzzy };
|
|
pub const AutoCompleteConfig = struct { ... };
|
|
pub const AutoCompleteColors = struct { ... };
|
|
pub const AutoCompleteResult = struct { ... };
|
|
```
|
|
|
|
**filtering.zig:**
|
|
```zig
|
|
pub fn matchesFilter(text: []const u8, filter: []const u8, mode: MatchMode) bool;
|
|
pub fn matchesPrefix(text: []const u8, prefix: []const u8) bool;
|
|
pub fn matchesContains(text: []const u8, needle: []const u8) bool;
|
|
pub fn matchesFuzzy(text: []const u8, pattern: []const u8) bool;
|
|
```
|
|
|
|
---
|
|
|
|
## icon/ (805 → 515 LOC, -36%)
|
|
|
|
### Estructura
|
|
|
|
```
|
|
src/widgets/icon/
|
|
├── icon.zig (515 LOC) - Hub con API y switch de ~50 iconos
|
|
├── types.zig (146 LOC) - Size, IconType, Config, Colors
|
|
└── drawing_helpers.zig (93 LOC) - drawLine, fillCircle, strokeCircle
|
|
```
|
|
|
|
### Archivos Modificados
|
|
|
|
- `widgets.zig`: Import actualizado a `icon/icon.zig`
|
|
- `iconbutton.zig`: Import actualizado
|
|
- `appbar.zig`: Import actualizado
|
|
- `navdrawer.zig`: Import actualizado
|
|
|
|
### Detalles de Extracción
|
|
|
|
**types.zig:**
|
|
```zig
|
|
pub const Size = enum {
|
|
small, // 12x12
|
|
medium, // 16x16
|
|
large, // 24x24
|
|
xlarge, // 32x32
|
|
|
|
pub fn pixels(self: Size) u32 { ... }
|
|
};
|
|
|
|
pub const IconType = enum {
|
|
// Navigation (~12)
|
|
arrow_up, arrow_down, arrow_left, arrow_right,
|
|
chevron_up, chevron_down, chevron_left, chevron_right,
|
|
home, menu, more_horizontal, more_vertical,
|
|
|
|
// Actions (~16)
|
|
check, close, plus, minus, edit, delete, refresh,
|
|
search, settings, filter, sort, copy, paste, cut, undo, redo,
|
|
|
|
// Files (~8)
|
|
file, folder, folder_open, document, image_file,
|
|
download, upload, save,
|
|
|
|
// Status (~9)
|
|
info, warning, error_icon, success, question,
|
|
star, star_filled, heart, heart_filled,
|
|
|
|
// UI elements (~10)
|
|
eye, eye_off, lock, unlock, user, users,
|
|
calendar, clock, bell, mail,
|
|
|
|
// Media (~5)
|
|
play, pause, stop, volume, volume_off,
|
|
|
|
// Misc (~8)
|
|
grip, drag, expand, collapse, maximize, minimize, external_link,
|
|
};
|
|
|
|
pub const Config = struct {
|
|
size: Size = .medium,
|
|
custom_size: ?u32 = null,
|
|
stroke_width: u32 = 2,
|
|
filled: bool = false,
|
|
};
|
|
|
|
pub const Colors = struct {
|
|
foreground: Style.Color = Style.Color.rgba(220, 220, 220, 255),
|
|
background: ?Style.Color = null,
|
|
|
|
pub fn fromTheme(theme: Style.Theme) Colors { ... }
|
|
};
|
|
```
|
|
|
|
**drawing_helpers.zig:**
|
|
```zig
|
|
/// Dibuja línea con grosor variable
|
|
pub fn drawLine(ctx: *Context, x1: i32, y1: i32, x2: i32, y2: i32,
|
|
thickness: u32, color: Style.Color) void;
|
|
|
|
/// Rellena círculo
|
|
pub fn fillCircle(ctx: *Context, cx: i32, cy: i32, radius: u32, color: Style.Color) void;
|
|
|
|
/// Dibuja contorno de círculo (Bresenham)
|
|
pub fn strokeCircle(ctx: *Context, cx: i32, cy: i32, radius: u32,
|
|
thickness: u32, color: Style.Color) void;
|
|
|
|
fn setPixelThick(ctx: *Context, x: i32, y: i32, thickness: u32, color: Style.Color) void;
|
|
```
|
|
|
|
---
|
|
|
|
## Limpieza de Archivos Residuales
|
|
|
|
### Problema Detectado
|
|
|
|
Existían archivos duplicados:
|
|
- `src/widgets/textarea.zig` (26KB) - archivo antiguo
|
|
- `src/widgets/textarea/` - carpeta con módulos
|
|
|
|
Lo mismo con `progress.zig` / `progress/`.
|
|
|
|
### Solución
|
|
|
|
```bash
|
|
rm src/widgets/textarea.zig
|
|
rm src/widgets/progress.zig
|
|
```
|
|
|
|
Los imports en `widgets.zig` ya apuntaban a las carpetas, por lo que los archivos sueltos eran código muerto.
|
|
|
|
---
|
|
|
|
## Módulos Ya Modulares (No Modificados)
|
|
|
|
### textarea/ (404 LOC hub)
|
|
|
|
```
|
|
src/widgets/textarea/
|
|
├── textarea.zig (404 LOC)
|
|
├── state.zig
|
|
├── render.zig
|
|
└── types.zig
|
|
```
|
|
|
|
### progress/ (~300 LOC hub)
|
|
|
|
```
|
|
src/widgets/progress/
|
|
├── progress.zig
|
|
├── bar.zig
|
|
├── circle.zig
|
|
└── spinner.zig
|
|
```
|
|
|
|
---
|
|
|
|
## Beneficios de la Modularización
|
|
|
|
1. **Mantenibilidad**: Archivos <600 LOC son más fáciles de navegar
|
|
2. **Compilación**: Cambios en types.zig no recompilan lógica principal
|
|
3. **Testing**: Módulos aislados son más fáciles de testear
|
|
4. **Colaboración**: Menos conflictos de merge en archivos grandes
|
|
5. **Documentación**: Estructura refleja responsabilidades
|
|
|
|
---
|
|
|
|
## Candidatos Futuros
|
|
|
|
| Archivo | LOC | Prioridad |
|
|
|---------|-----|-----------|
|
|
| font_data.zig | 1157 | Baja (datos estáticos) |
|
|
| style.zig | 858 | Media |
|
|
| table.zig | ~750 | Media |
|
|
|
|
---
|
|
|
|
## Commits
|
|
|
|
```
|
|
chore: Eliminar archivos residuales textarea.zig y progress.zig
|
|
refactor(autocomplete): Modularizar en carpeta (910→571 LOC hub, -37%)
|
|
refactor(icon): Modularizar en carpeta (805→515 LOC hub, -36%)
|
|
```
|
|
|
|
---
|
|
|
|
*Fecha: 2025-12-29*
|
|
*Autor: Claude (Opus 4.5) + R.Eugenio*
|