fix(0132): cross-platform demos + auto-launch + black bg prompt
- Demo 1 (one-shot): auto-launch al primer frame, sin boton Run. Linux: bash; Windows: cmd.exe con "echo hello && date /t && dir /b %TEMP%" - Demo 2 (interactive): auto-launch al entrar al tab. Sin boton Open shell. Linux: bash; Windows: cmd.exe. Boton Close/Reopen post-exit. - Demo 3 (readonly): Linux tail -f igual que antes. Windows: panel readonly con cmd.exe one-shot + mensaje informativo. - shell_exists() helper para mostrar error si el binario no existe. - Render: fondo negro + prompt "$ " implementados en terminal_panel.cpp. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+139
-26
@@ -1,9 +1,17 @@
|
||||
// demos_terminal.cpp — demos del modulo terminal_panel (issue 0132).
|
||||
//
|
||||
// Demo 1: One-shot — spawn bash que ejecuta "echo hello; date; ls /tmp | head"
|
||||
// con auto-close cuando el proceso termina. Muestra el scrollback.
|
||||
// Demo 2: Interactivo — bash -i (Linux) / cmd.exe (Windows) con input box.
|
||||
// Demo 3: Readonly — tail simulado de un archivo de log.
|
||||
// Demo 1: One-shot — auto-launch al primer frame. Cross-platform:
|
||||
// Linux → bash "echo hello; date; ls /tmp | head"
|
||||
// Windows → cmd.exe "echo hello && date /t && dir /b %TEMP%"
|
||||
// Demo 2: Interactivo — auto-launch al entrar al tab.
|
||||
// Linux → bash -i
|
||||
// Windows → cmd.exe
|
||||
// Demo 3: Readonly — tail simulado en Linux / mensaje en Windows.
|
||||
//
|
||||
// Cambios issue 0132:
|
||||
// - Fondo negro + prompt input: en terminal_panel.cpp.
|
||||
// - Cross-platform: _WIN32 en todos los demos.
|
||||
// - Auto-launch: sin boton "Open shell" / "Run" en Demo 1 y Demo 2.
|
||||
|
||||
#include "demos.h"
|
||||
#include "demo.h"
|
||||
@@ -13,31 +21,64 @@
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
// Para verificar que el binario del shell existe antes de abrir.
|
||||
#ifdef _WIN32
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# include <windows.h>
|
||||
static bool shell_exists(const char* path) {
|
||||
return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
#else
|
||||
# include <unistd.h>
|
||||
static bool shell_exists(const char* path) {
|
||||
return access(path, X_OK) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace gallery {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Demo 1: One-shot con auto-close
|
||||
// Demo 1: One-shot con auto-launch
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void demo_terminal_oneshot() {
|
||||
demo_header("terminal_panel", "v1.0.0",
|
||||
"Emulador TTY embebible. Demo 1: one-shot — spawn bash, ejecuta comandos, auto-close.");
|
||||
"Emulador TTY embebible. Demo 1: one-shot — auto-launch al primer frame, cross-platform.");
|
||||
|
||||
static fn_term::TerminalPanel s_term;
|
||||
static bool s_started = false;
|
||||
static bool s_launched = false;
|
||||
static bool s_shell_missing = false;
|
||||
|
||||
if (!s_started) {
|
||||
ImGui::TextUnformatted("Pulsa 'Run' para lanzar el one-shot.");
|
||||
if (ImGui::Button("Run")) {
|
||||
if (!s_term.is_open()) {
|
||||
s_term.shell = "/bin/bash";
|
||||
if (!s_launched && !s_shell_missing) {
|
||||
#ifdef _WIN32
|
||||
const char* sh = "cmd.exe";
|
||||
const char* cmd = "echo hello && date /t && dir /b %TEMP% 2>nul\r\n";
|
||||
#else
|
||||
const char* sh = "/bin/bash";
|
||||
const char* cmd = "echo hello; date; ls /tmp | head -5; exit 0\n";
|
||||
#endif
|
||||
if (!shell_exists(sh)) {
|
||||
s_shell_missing = true;
|
||||
} else {
|
||||
s_term.shell = sh;
|
||||
s_term.scrollback_lines = 200;
|
||||
s_term.readonly = true; // solo output, sin input
|
||||
s_term.readonly = true;
|
||||
fn_term::open(s_term);
|
||||
fn_term::send(s_term, "echo hello; date; ls /tmp | head -5; exit 0\n");
|
||||
s_started = true;
|
||||
fn_term::send(s_term, cmd);
|
||||
s_launched = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_shell_missing) {
|
||||
#ifdef _WIN32
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
|
||||
"Shell not available: cmd.exe");
|
||||
#else
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
|
||||
"Shell not available: /bin/bash");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -50,10 +91,21 @@ void demo_terminal_oneshot() {
|
||||
|
||||
if (ImGui::Button("Reset demo")) {
|
||||
if (s_term.is_open()) fn_term::close(s_term);
|
||||
s_started = false;
|
||||
s_launched = false;
|
||||
s_shell_missing = false;
|
||||
}
|
||||
|
||||
code_block(
|
||||
#ifdef _WIN32
|
||||
"fn_term::TerminalPanel term;\n"
|
||||
"term.shell = \"cmd.exe\";\n"
|
||||
"term.readonly = true;\n"
|
||||
"fn_term::open(term);\n"
|
||||
"fn_term::send(term, \"echo hello && date /t\\r\\n\");\n"
|
||||
"// En cada frame ImGui:\n"
|
||||
"fn_term::render(term);\n"
|
||||
"if (term.process_exited.load()) fn_term::close(term);"
|
||||
#else
|
||||
"fn_term::TerminalPanel term;\n"
|
||||
"term.shell = \"/bin/bash\";\n"
|
||||
"term.readonly = true;\n"
|
||||
@@ -62,55 +114,115 @@ void demo_terminal_oneshot() {
|
||||
"// En cada frame ImGui:\n"
|
||||
"fn_term::render(term);\n"
|
||||
"if (term.process_exited.load()) fn_term::close(term);"
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Demo 2: Interactivo
|
||||
// Demo 2: Interactivo con auto-launch
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void demo_terminal_interactive() {
|
||||
demo_header("terminal_panel", "v1.0.0",
|
||||
"Demo 2: terminal interactivo — bash -i (Linux) / cmd.exe (Windows).");
|
||||
"Demo 2: terminal interactivo — auto-launch al entrar al tab. "
|
||||
"Linux: bash -i / Windows: cmd.exe.");
|
||||
|
||||
static fn_term::TerminalPanel s_term;
|
||||
static bool s_launched = false;
|
||||
static bool s_shell_missing = false;
|
||||
|
||||
if (!s_term.is_open()) {
|
||||
if (ImGui::Button("Open shell")) {
|
||||
// Auto-launch en el primer frame que se renderiza esta demo.
|
||||
if (!s_launched && !s_shell_missing) {
|
||||
#ifdef _WIN32
|
||||
s_term.shell = "cmd.exe";
|
||||
const char* sh = "cmd.exe";
|
||||
#else
|
||||
s_term.shell = "/bin/bash";
|
||||
const char* sh = "/bin/bash";
|
||||
#endif
|
||||
if (!shell_exists(sh)) {
|
||||
s_shell_missing = true;
|
||||
} else {
|
||||
s_term.shell = sh;
|
||||
s_term.scrollback_lines = 1000;
|
||||
s_term.readonly = false;
|
||||
fn_term::open(s_term);
|
||||
s_launched = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_shell_missing) {
|
||||
#ifdef _WIN32
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
|
||||
"Shell not available: cmd.exe");
|
||||
#else
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f),
|
||||
"Shell not available: /bin/bash");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
fn_term::render(s_term);
|
||||
|
||||
if (s_term.is_open()) {
|
||||
ImGui::Spacing();
|
||||
if (ImGui::Button("Close shell")) {
|
||||
fn_term::close(s_term);
|
||||
s_launched = false;
|
||||
}
|
||||
} else if (s_launched) {
|
||||
ImGui::TextDisabled("[shell exited — click Reopen]");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reopen")) {
|
||||
s_launched = false;
|
||||
s_shell_missing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Demo 3: Readonly tail
|
||||
// Demo 3: Readonly tail (Linux) / mensaje informativo (Windows)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void demo_terminal_readonly() {
|
||||
demo_header("terminal_panel", "v1.0.0",
|
||||
"Demo 3: readonly — tail de /tmp/fn_gallery_test.log (creado al abrir).");
|
||||
"Demo 3: readonly — "
|
||||
#ifdef _WIN32
|
||||
"demo disponible solo en Linux (tail -f). En Windows se muestra un mensaje.");
|
||||
#else
|
||||
"tail de /tmp/fn_gallery_test.log (creado al abrir).");
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// En Windows nativo, tail -f no existe y /tmp tampoco.
|
||||
// Mostramos un panel readonly con mensaje estático para seguir ejercitando el render.
|
||||
static fn_term::TerminalPanel s_term;
|
||||
static bool s_launched = false;
|
||||
|
||||
if (!s_launched) {
|
||||
s_term.shell = "cmd.exe";
|
||||
s_term.readonly = true;
|
||||
s_term.scrollback_lines = 100;
|
||||
fn_term::open(s_term);
|
||||
// Imprimir unas líneas de muestra y terminar el proceso.
|
||||
fn_term::send(s_term,
|
||||
"echo [terminal_panel demo 3 - readonly] && "
|
||||
"echo This demo uses tail -f on Linux. && "
|
||||
"echo On Windows the panel renders static output. && "
|
||||
"exit 0\r\n");
|
||||
s_launched = true;
|
||||
}
|
||||
|
||||
fn_term::render(s_term);
|
||||
|
||||
if (ImGui::Button("Reset demo")) {
|
||||
if (s_term.is_open()) fn_term::close(s_term);
|
||||
s_launched = false;
|
||||
}
|
||||
#else
|
||||
static fn_term::TerminalPanel s_term;
|
||||
static bool s_log_created = false;
|
||||
|
||||
// Crear el archivo de log de prueba si no existe.
|
||||
if (!s_log_created) {
|
||||
if (ImGui::Button("Start tail")) {
|
||||
// Escribir unas líneas de muestra al log.
|
||||
FILE* f = fopen("/tmp/fn_gallery_test.log", "w");
|
||||
if (f) {
|
||||
for (int i = 0; i < 5; i++)
|
||||
@@ -153,6 +265,7 @@ void demo_terminal_readonly() {
|
||||
"// En cada frame:\n"
|
||||
"fn_term::render(term);"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user