5e6a974a5d
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.8 KiB
6.8 KiB
id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
| id | title | status | type | domain | scope | priority | depends | blocks | related | created | updated | tags | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0025 | C++ text_editor + file_watcher | completado | feature |
|
multi-app | alta | 2026-05-17 | 2026-05-17 |
0025 — C++ text_editor + file_watcher
APP Metadata
| Campo | Valor |
|---|---|
| ID | 0025 |
| Estado | pendiente |
| Prioridad | alta |
| Tipo | feature — C++ devx (cpp/functions/core) |
Dependencias
Ninguna. Se apoya en lo que ya existe (tokens, app_base, ImGui vendoreado).
Desbloquea: ciclo de edicion completo dentro de shaders_lab (editar GLSL + reload automatico al guardar) sin alt-tab a un editor externo. Tambien util para un futuro sql_workbench (issue 0032).
Objetivo
Añadir dos primitivos al registry C++:
text_editor_cpp_core— editor de codigo embebido en ImGui con syntax highlighting (GLSL, SQL, generic). Wrapper de ImGuiColorTextEdit (header + cpp, MIT) vendoreado encpp/vendor/imgui_text_edit/.file_watcher_cpp_core— watcher de archivos cross-platform (inotify Linux / ReadDirectoryChangesW Win) puro en su API: registra paths + callback, exponepoll()no bloqueante.
Mostrar ambos en primitives_gallery con una demo combinada: editor que carga un .glsl, file_watcher detecta cambios externos y el editor recarga.
Contexto
shaders_lab actualmente compila un gl_shader desde texto en RAM. No hay editor in-app: el usuario edita en VSCode y copia/pega. Tampoco hay file_watcher: para iterar sobre .glsl externos hay que recompilar la app.
Otros usos del editor:
sql_workbench(0032) — editor SQL + ejecucion sobreregistry.db/operations.db.- Edicion de prompts/configs en apps futuras.
Arquitectura
cpp/
├── vendor/imgui_text_edit/ # NEW — vendor (MIT, 1 .h + 1 .cpp)
│ ├── TextEditor.h
│ └── TextEditor.cpp
├── functions/core/
│ ├── text_editor.h # NEW — wrapper en namespace fn
│ ├── text_editor.cpp # NEW
│ ├── text_editor.md # NEW
│ ├── file_watcher.h # NEW
│ ├── file_watcher.cpp # NEW (impure)
│ └── file_watcher.md # NEW
└── apps/primitives_gallery/
├── demos_text_editor.cpp # NEW — demo combinada (editor + watcher)
├── demos.h # MOD — declarar demo_text_editor()
├── main.cpp # MOD — registrar entrada en sidebar
└── CMakeLists.txt # MOD — añadir fuentes
cpp/CMakeLists.txt # MOD — añadir vendor/imgui_text_edit a sources
Pure core / impure shell
text_editor_cpp_core: API es pura en el sentido de "sin I/O propio" — todo el estado vive en una structTextEditorState. LaTextEditor::Render()hace draw calls de ImGui (igual que el resto de componentes). Marcar comopurity: pure,kind: component. Misma categoria quebutton_cpp_core.file_watcher_cpp_core: hace I/O del sistema de ficheros.purity: impure,kind: function,error_type: error_go_core(usar el equivalente C++ — vertokenspara errores existentes; si no, retornarboolconlast_error()).
API propuesta
namespace fn {
// text_editor.h
struct TextEditorState; // forward (PIMPL hacia TextEditor de vendor)
enum class CodeLang { Generic, GLSL, SQL, Cpp };
TextEditorState* text_editor_create(CodeLang lang = CodeLang::Generic);
void text_editor_destroy(TextEditorState*);
void text_editor_set_text(TextEditorState*, const char* text);
const char* text_editor_get_text(TextEditorState*); // valido hasta el siguiente call
bool text_editor_render(TextEditorState*, const char* label, ImVec2 size); // true si cambio
bool text_editor_is_dirty(const TextEditorState*);
void text_editor_clear_dirty(TextEditorState*);
// file_watcher.h
struct FileWatcher;
FileWatcher* file_watcher_create();
void file_watcher_destroy(FileWatcher*);
bool file_watcher_add(FileWatcher*, const char* path); // file or dir
struct FileEvent { std::string path; enum { Modified, Created, Deleted } kind; };
std::vector<FileEvent> file_watcher_poll(FileWatcher*); // non-blocking, drain
}
Tareas
Fase 1 — Vendor
- 1.1 Descargar ImGuiColorTextEdit (commit estable, MIT) a
cpp/vendor/imgui_text_edit/. - 1.2 Añadirlo al
cpp/CMakeLists.txtglobal como source list reusable.
Fase 2 — text_editor
- 2.1 Implementar
text_editor.h/.cppcon la API de arriba (PIMPL). Aplicartokenspara colores de fondo y border consistentes. - 2.2 Configurar lenguajes:
LanguageDefinition::GLSL()yLanguageDefinition::SQL()(vendor ya las trae). - 2.3
text_editor.mdcon frontmatter completo (kind: component,purity: pure,params,output, ejemplo).
Fase 3 — file_watcher
- 3.1 Implementar
file_watcher.h/.cpp. Linux: inotify. Windows: ReadDirectoryChangesW (solo dir-level, filtrar por path). Macros condicionales. - 3.2
file_watcher.md(kind: function,purity: impure).
Fase 4 — Gallery demo
- 4.1
demos_text_editor.cppcondemo_text_editor(): split horizontal — izquierda editor con un GLSL de ejemplo, derecha info (dirty flag, eventos del watcher). Botón "Save to /tmp/demo.glsl" + watcher activo sobre/tmp/demo.glslque muestra los eventos. - 4.2 Registrar en
demos.h,main.cpp,CMakeLists.txt.
Fase 5 — Integracion en shaders_lab (opcional)
- 5.1 (Stretch) Añadir flag
--watch <archivo.glsl>ashaders_labque abre el archivo con text_editor + file_watcher y recompila automaticamente.
Fase 6 — Tests + docs
- 6.1 Tests para
file_watcher(Linux): crear tmpfile, modify, verificar evento. Compilable solo en Linux con guard. - 6.2
./fn indexy./fn show text_editor_cpp_core/file_watcher_cpp_coreverifica frontmatter.
Ejemplo de uso
auto* ed = fn::text_editor_create(fn::CodeLang::GLSL);
auto* fw = fn::file_watcher_create();
fn::file_watcher_add(fw, "/tmp/demo.glsl");
fn::run_app("editor demo", [&]{
if (fn::text_editor_render(ed, "##ed", {600, 400}))
std::printf("changed\n");
for (auto& ev : fn::file_watcher_poll(fw))
std::printf("FS: %s\n", ev.path.c_str());
});
Decisiones de diseño
- PIMPL evita exponer
TextEditordel vendor en headers publicos. - Vendor in-tree sigue la convencion de ImGui/ImPlot ya presentes en
cpp/vendor/. - Sin tokens custom — heredamos los del color theme global.
Riesgos
- API del vendor cambia entre commits: pinear a un commit concreto en un README en
cpp/vendor/imgui_text_edit/. - inotify watch limit en Linux: documentar
fs.inotify.max_user_watchesen el .md. - Windows ReadDirectoryChangesW solo emite a nivel de directorio: filtrar el path en el poll.