---
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.
