feat(0132): cpp terminal_panel module + ansi_parser
Nuevo modulo reutilizable terminal_panel (fn_term) para ImGui: Sub-fn ansi_parser_cpp_core (cpp/functions/core/): - Parser ANSI/VT100 byte-a-byte sin heap allocs por evento - SGR colores FG/BG 16-color + bold + reset - Cursor moves CUU/CUD/CUF/CUB + CUP absoluto - Erase ED(2)/EL(2), CR/LF/BS - Statemachine 4 estados, thread-unsafe por diseno - 21 tests unitarios (57 assertions), todos pasan terminal_panel_cpp_viz (cpp/functions/viz/terminal_panel/): - terminal_panel.cpp: render ImGui + process_output con list clipper - terminal_panel_linux.cpp: forkpty + reader thread no-blocking - terminal_panel_windows.cpp: ConPTY CreatePseudoConsole (SDK >= 17763) - Scrollback circular configurable (default 5000 lineas) - Toolbar: clear, copy, reset, scroll-lock + status indicator - readonly mode: sin input box, send() es no-op - uses_functions: ansi_parser_cpp_core, logger_cpp_core Tests: - test_ansi_parser.cpp: 21 test cases, 57 assertions (PASS) - test_terminal_panel_smoke.cpp: 3 test cases (PASS: spawn echo hello, process exits cleanly, readonly ignores send) CMake: - cpp/tests/CMakeLists.txt: add test_ansi_parser + test_terminal_panel_smoke - primitives_gallery (sub-repo): ver commit separado en apps/primitives_gallery Pendiente (anti-scope v1): - Windows ConPTY: stub funcional que compila; join() del reader thread via std::thread no implementado (usa CreateThread detached) - ANSI 256/24-bit color, italics, Unicode wide - Curses pesados (vim, htop, top) — cursor visible basic solo Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
---
|
||||
name: terminal_panel
|
||||
kind: component
|
||||
lang: cpp
|
||||
domain: viz
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "void fn_term::open(fn_term::TerminalPanel& panel); void fn_term::render(fn_term::TerminalPanel& panel); void fn_term::send(fn_term::TerminalPanel& panel, const std::string& text); void fn_term::close(fn_term::TerminalPanel& panel);"
|
||||
description: "Emulador TTY embebible en ImGui. Arranca un proceso hijo via PTY (Linux: forkpty) o ConPTY (Windows 10 v1809+), renderiza el scrollback con colores ANSI 16-color, toolbar (clear/copy/reset/scroll-lock) e input box. Scrollback circular configurable. Soporte readonly para tail-only."
|
||||
tags: [terminal, pty, conpty, imgui, viz, ansi, shell, cpp-dashboard-viz]
|
||||
uses_functions: [ansi_parser_cpp_core, logger_cpp_core]
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [atomic, functional, mutex, string, thread, vector]
|
||||
tested: true
|
||||
tests:
|
||||
- "smoke: spawn echo hello and exit, scrollback contains hello"
|
||||
test_file_path: "cpp/tests/test_terminal_panel_smoke.cpp"
|
||||
file_path: "cpp/functions/viz/terminal_panel/terminal_panel.cpp"
|
||||
framework: imgui
|
||||
params:
|
||||
- name: panel
|
||||
desc: "Struct TerminalPanel con config (shell, cwd, env, scrollback_lines, readonly) y estado interno gestionado por open/close/render"
|
||||
output: "render() dibuja toolbar + scrollback con colores ANSI + input box en el area ImGui disponible. open() arranca el proceso hijo y el reader thread. send() escribe texto al stdin del hijo. close() mata el proceso y libera recursos."
|
||||
notes: "Linux: requiere -lutil (libutil) para forkpty. Windows: requiere Windows SDK >= 17763 (v1809) para ConPTY. Si el SDK es anterior, open() loguea error y deja is_open()==false. Anti-scope v1: sin tabs multiples, sin SSH, sin curses pesados (vim/htop)."
|
||||
---
|
||||
|
||||
# terminal_panel
|
||||
|
||||
Emulador TTY embebible en ImGui. Util para: tail de logs en una app de monitoring, ejecutar comandos shell desde un panel de kanban, ver output de compilaciones, consola de debug de agentes.
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```cpp
|
||||
#include "viz/terminal_panel/terminal_panel.h"
|
||||
|
||||
static fn_term::TerminalPanel s_term;
|
||||
|
||||
void render_panel() {
|
||||
// Abrir al primer frame.
|
||||
if (!s_term.is_open()) {
|
||||
s_term.shell = "/bin/bash";
|
||||
s_term.scrollback_lines = 2000;
|
||||
fn_term::open(s_term);
|
||||
}
|
||||
fn_term::render(s_term);
|
||||
}
|
||||
|
||||
// Tail readonly de un log:
|
||||
static fn_term::TerminalPanel s_log_tail;
|
||||
|
||||
void render_log_tail() {
|
||||
if (!s_log_tail.is_open()) {
|
||||
s_log_tail.shell = "/bin/bash";
|
||||
s_log_tail.readonly = true;
|
||||
fn_term::open(s_log_tail);
|
||||
fn_term::send(s_log_tail, "tail -f /tmp/agent.log\n");
|
||||
}
|
||||
fn_term::render(s_log_tail);
|
||||
}
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando necesitas ver output crudo de un proceso (shell, compilacion, curl, tail) sin salir de la app ImGui. Alternativa a abrir un terminal externo. Especialmente util en apps de monitoring (services_monitor, agents_dashboard) y kanban panels de build.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Linux**: el CMakeLists del consumidor debe linkar `-lutil` (o `target_link_libraries(... util)`) para resolver `forkpty`.
|
||||
- **Windows**: requiere Windows 10 v1809+ (SDK >= 17763). Si el SDK es anterior, `open()` deja el panel cerrado y loguea error — no hay panic ni crash.
|
||||
- **Anti-scope v1**: sin soporte de curses pesados (vim, htop, top). El parser ANSI maneja SGR color + cursor básico; programas que usen el modo altscreen o muchas secuencias de cursor se verán mal.
|
||||
- **Scrollback circular**: cuando `lines.size() > scrollback_lines`, se elimina la primera fila. Esto puede causar saltos visuales si el contenido se está acumulando muy rápido (ej. `yes "x"`). En v1 el target es 60fps con scrollback de 5000 líneas.
|
||||
- **Thread safety**: `render()` toma el `buf_mutex` por el tiempo del render de cada frame. El reader thread también lo toma al actualizar el buffer. En condiciones normales no hay contención significativa.
|
||||
- **readonly**: si `true`, no se renderiza el input box y `send()` es no-op. Útil para `tail -f` o procesos que no necesitan stdin.
|
||||
Reference in New Issue
Block a user