--- name: vt_render kind: function lang: go domain: tui version: "1.0.0" purity: pure signature: "func VTRender(raw string, rows, cols int) string" description: "Emula un terminal virtual de tamaño cols×rows, alimenta raw (stream con secuencias ANSI/VT100 incluyendo posicionamiento absoluto de cursor) y devuelve el estado final de la pantalla como texto plano que preserva el layout visual. A diferencia de strip_ansi, reconstruye espacios reales entre columnas posicionadas con movimientos de cursor absolutos." tags: ["terminal", "vt100", "tui", "render", "ansi", "screen", "terminal-capture"] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "" imports: - "github.com/hinshun/vt10x" - "strings" tested: true tests: - "layout absoluto basico A y B separados por movimiento de cursor" - "dos palabras separadas por movimiento de columna no aparecen pegadas" - "texto multilinea simple con CRLF" - "trim de filas vacias al final de grid grande" - "determinismo misma entrada misma salida" - "defaults rows y cols al pasar cero" test_file_path: "functions/tui/vt_render_test.go" file_path: "functions/tui/vt_render.go" params: - name: raw desc: "Stream crudo de bytes de terminal, con secuencias de escape ANSI/VT100 intactas (colores, cursor moves, borrados de línea, scroll). Típicamente la salida de pty_capture_idle_go_infra." - name: rows desc: "Número de filas del terminal virtual. Debe coincidir con el tamaño de PTY usado al capturar. Si <=0 usa 40 como default." - name: cols desc: "Número de columnas del terminal virtual. Debe coincidir con el ancho de PTY usado al capturar. Si <=0 usa 120 como default." output: "Texto plano multilínea con el layout visual de la pantalla: espacios reales entre columnas, sin trailing spaces por línea, sin filas vacías finales. Las líneas vacías intermedias se conservan (son separación visual real)." --- ## Ejemplo ```go // Capturar output crudo de una TUI (ej. claude CLI) con el PTY del mismo tamaño. raw, _ := pty_capture_idle("claude", []string{"--help"}, 40, 120, 2*time.Second, 10*time.Second) // Renderizar el grid final como texto plano. screen := tui.VTRender(raw, 40, 120) fmt.Println(screen) // Salida: texto con columnas alineadas, igual a lo que se vería en pantalla. // Ejemplo real: "foo bar" si foo y bar estaban separados por ESC[10G. ``` ## Cuando usarla Úsala cuando captures el output crudo de una TUI con layout absoluto (claude CLI, htop, dialog, ncurses) y `strip_ansi_go_core` te deje las palabras pegadas (ej. "2newMCPservers"). Contrasta con `strip_ansi_go_core` y `strip_ansi_go_tui`, que sirven para output secuencial tipo logs donde no hay movimientos de cursor absolutos. Si el stream tiene `ESC[row;colH` o `ESC[colG`, este es el correcto. Librería emuladora usada: `github.com/hinshun/vt10x` (vt10x v0.0.0-20220301184237-5011da428d02). Implementa VT10x completo sin CGO. API: `vt10x.New(vt10x.WithSize(cols, rows))` + `Write([]byte)` + `String()`. ## Gotchas - **Tamaño debe coincidir**: rows×cols deben ser iguales a los que se usaron al capturar (pty_capture_idle usa 40×120 por defecto). Si no coinciden, el wrapping del texto no cuadra y las columnas se descuadran. - **Solo texto, sin color**: la función vuelca únicamente los caracteres (rune de cada celda). Los atributos de color se pierden — es texto plano. - **Solo estado final del grid**: si la TUI hizo scroll durante su ejecución, solo se ve el estado final de las 40 filas visibles. El historial de scroll no está disponible. - **Emojis y caracteres de doble ancho**: algunos caracteres Unicode (emojis, CJK) ocupan 2 columnas visualmente pero solo 1 celda en el grid de vt10x, lo que puede descuadrar columnas en TUIs que los usan. - **NUL en celdas vacías**: las celdas no escritas contienen `\x00` en algunas versiones del emulador. La función los reemplaza por espacio antes del trim, pero si el raw contiene NUL intencional, se trataría como espacio.