9979d74217
Add demos_terminal.cpp con 3 demos del modulo terminal_panel: - Demo 1: one-shot spawn bash, echo hello; date; ls /tmp - Demo 2: terminal interactivo bash/cmd.exe con input box - Demo 3: readonly tail -f con boton append Actualiza CMakeLists.txt con ansi_parser + terminal_panel + -lutil (Linux). Actualiza demos.h + main.cpp con entry "Terminal" en el sidebar. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
188 lines
5.7 KiB
C++
188 lines
5.7 KiB
C++
// 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.
|
|
|
|
#include "demos.h"
|
|
#include "demo.h"
|
|
#include "viz/terminal_panel/terminal_panel.h"
|
|
#include "imgui.h"
|
|
|
|
#include <cstring>
|
|
#include <string>
|
|
|
|
namespace gallery {
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Demo 1: One-shot con auto-close
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void demo_terminal_oneshot() {
|
|
demo_header("terminal_panel", "v1.0.0",
|
|
"Emulador TTY embebible. Demo 1: one-shot — spawn bash, ejecuta comandos, auto-close.");
|
|
|
|
static fn_term::TerminalPanel s_term;
|
|
static bool s_started = 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";
|
|
s_term.scrollback_lines = 200;
|
|
s_term.readonly = true; // solo output, sin input
|
|
fn_term::open(s_term);
|
|
fn_term::send(s_term, "echo hello; date; ls /tmp | head -5; exit 0\n");
|
|
s_started = true;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
fn_term::render(s_term);
|
|
|
|
if (s_term.process_exited.load() && s_term.is_open()) {
|
|
ImGui::SameLine();
|
|
ImGui::TextDisabled("[done — exit %d]", s_term.exit_code);
|
|
}
|
|
|
|
if (ImGui::Button("Reset demo")) {
|
|
if (s_term.is_open()) fn_term::close(s_term);
|
|
s_started = false;
|
|
}
|
|
|
|
code_block(
|
|
"fn_term::TerminalPanel term;\n"
|
|
"term.shell = \"/bin/bash\";\n"
|
|
"term.readonly = true;\n"
|
|
"fn_term::open(term);\n"
|
|
"fn_term::send(term, \"echo hello; date; exit 0\\n\");\n"
|
|
"// En cada frame ImGui:\n"
|
|
"fn_term::render(term);\n"
|
|
"if (term.process_exited.load()) fn_term::close(term);"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Demo 2: Interactivo
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void demo_terminal_interactive() {
|
|
demo_header("terminal_panel", "v1.0.0",
|
|
"Demo 2: terminal interactivo — bash -i (Linux) / cmd.exe (Windows).");
|
|
|
|
static fn_term::TerminalPanel s_term;
|
|
|
|
if (!s_term.is_open()) {
|
|
if (ImGui::Button("Open shell")) {
|
|
#ifdef _WIN32
|
|
s_term.shell = "cmd.exe";
|
|
#else
|
|
s_term.shell = "/bin/bash";
|
|
#endif
|
|
s_term.scrollback_lines = 1000;
|
|
s_term.readonly = false;
|
|
fn_term::open(s_term);
|
|
}
|
|
return;
|
|
}
|
|
|
|
fn_term::render(s_term);
|
|
|
|
if (ImGui::Button("Close shell")) {
|
|
fn_term::close(s_term);
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Demo 3: Readonly tail
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void demo_terminal_readonly() {
|
|
demo_header("terminal_panel", "v1.0.0",
|
|
"Demo 3: readonly — tail de /tmp/fn_gallery_test.log (creado al abrir).");
|
|
|
|
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++)
|
|
fprintf(f, "[sample] log line %d\n", i);
|
|
fclose(f);
|
|
}
|
|
s_term.shell = "/bin/bash";
|
|
s_term.readonly = true;
|
|
s_term.scrollback_lines = 500;
|
|
fn_term::open(s_term);
|
|
fn_term::send(s_term, "tail -f /tmp/fn_gallery_test.log\n");
|
|
s_log_created = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
fn_term::render(s_term);
|
|
|
|
ImGui::Separator();
|
|
if (ImGui::Button("Append line")) {
|
|
FILE* f = fopen("/tmp/fn_gallery_test.log", "a");
|
|
if (f) {
|
|
static int s_count = 0;
|
|
fprintf(f, "[appended] line %d\n", s_count++);
|
|
fclose(f);
|
|
}
|
|
}
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Stop")) {
|
|
if (s_term.is_open()) fn_term::close(s_term);
|
|
s_log_created = false;
|
|
}
|
|
|
|
code_block(
|
|
"fn_term::TerminalPanel term;\n"
|
|
"term.shell = \"/bin/bash\";\n"
|
|
"term.readonly = true; // sin input box\n"
|
|
"fn_term::open(term);\n"
|
|
"fn_term::send(term, \"tail -f /tmp/agent.log\\n\");\n"
|
|
"// En cada frame:\n"
|
|
"fn_term::render(term);"
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Entry point unificado (llamado desde main.cpp via demos.h)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void demo_terminal() {
|
|
static int s_tab = 0;
|
|
if (ImGui::BeginTabBar("##term_tabs")) {
|
|
if (ImGui::BeginTabItem("One-shot")) {
|
|
s_tab = 0;
|
|
ImGui::EndTabItem();
|
|
}
|
|
if (ImGui::BeginTabItem("Interactive")) {
|
|
s_tab = 1;
|
|
ImGui::EndTabItem();
|
|
}
|
|
if (ImGui::BeginTabItem("Readonly tail")) {
|
|
s_tab = 2;
|
|
ImGui::EndTabItem();
|
|
}
|
|
ImGui::EndTabBar();
|
|
}
|
|
|
|
switch (s_tab) {
|
|
case 0: demo_terminal_oneshot(); break;
|
|
case 1: demo_terminal_interactive(); break;
|
|
case 2: demo_terminal_readonly(); break;
|
|
}
|
|
}
|
|
|
|
} // namespace gallery
|