diff --git a/supabase/migrations/202607300003_mission_catalog_v3_visible_inputs.sql b/supabase/migrations/202607300003_mission_catalog_v3_visible_inputs.sql index 1f02be1..49b2209 100644 --- a/supabase/migrations/202607300003_mission_catalog_v3_visible_inputs.sql +++ b/supabase/migrations/202607300003_mission_catalog_v3_visible_inputs.sql @@ -1524,7 +1524,8 @@ function necesitaReposicion(stock, minimo) { // stockSeguro(12, 5) // Resultado esperado: 7 ', - 'function stockSeguro(stock, retiro)', + 'function stockSeguro(stock, retiro) +function necesitaReposicion(stock, minimo)', '[{"id":"stock-update","label":"Descuenta un retiro válido","input":"stockSeguro(12, 5)","output":"7","explanation":"Resta solo después de validar."},{"id":"stock-invalid","label":"Impide stock negativo","input":"stockSeguro(4, 8)","output":"-1","explanation":"Un retiro mayor al stock debe rechazarse."}]'::jsonb, '[{"id":"stock-update","label":"Descuenta un retiro válido","expression":"stockSeguro(12, 5) === 7","expected":"7","feedback":"Resta solo después de validar.","actualExpression":"stockSeguro(12, 5)"},{"id":"stock-invalid","label":"Impide stock negativo","expression":"stockSeguro(4, 8) === -1","expected":"-1","feedback":"Un retiro mayor al stock debe rechazarse.","actualExpression":"stockSeguro(4, 8)"}]'::jsonb, 1 @@ -1589,7 +1590,8 @@ def necesita_reposicion(stock, minimo): # stock_seguro(12, 5) # Resultado esperado: 7 ', - 'def stock_seguro(stock, retiro)', + 'def stock_seguro(stock, retiro) +def necesita_reposicion(stock, minimo)', '[{"id":"stock-update","label":"Descuenta un retiro válido","input":"stock_seguro(12, 5)","output":"7","explanation":"Resta solo después de validar."},{"id":"stock-invalid","label":"Impide stock negativo","input":"stock_seguro(4, 8)","output":"-1","explanation":"Un retiro mayor al stock debe rechazarse."}]'::jsonb, '[{"id":"stock-update","label":"Descuenta un retiro válido","expression":"stock_seguro(12, 5) == 7","expected":"7","feedback":"Resta solo después de validar.","actualExpression":"stock_seguro(12, 5)"},{"id":"stock-invalid","label":"Impide stock negativo","expression":"stock_seguro(4, 8) == -1","expected":"-1","feedback":"Un retiro mayor al stock debe rechazarse.","actualExpression":"stock_seguro(4, 8)"}]'::jsonb, 1 @@ -1669,7 +1671,8 @@ bool necesitaReposicion(int stock, int minimo) { // stockSeguro(12, 5) == 7 // Resultado esperado: 7 ', - 'int stockSeguro(int stock, int retiro)', + 'int stockSeguro(int stock, int retiro) +bool necesitaReposicion(int stock, int minimo)', '[{"id":"stock-update","label":"Descuenta un retiro válido","input":"stockSeguro(12, 5) == 7","output":"7","explanation":"Resta solo después de validar."},{"id":"stock-invalid","label":"Impide stock negativo","input":"stockSeguro(4, 8) == -1","output":"-1","explanation":"Un retiro mayor al stock debe rechazarse."}]'::jsonb, '[{"id":"stock-update","label":"Descuenta un retiro válido","expression":"stockSeguro(12, 5) == 7","expected":"7","feedback":"Resta solo después de validar."},{"id":"stock-invalid","label":"Impide stock negativo","expression":"stockSeguro(4, 8) == -1","expected":"-1","feedback":"Un retiro mayor al stock debe rechazarse."}]'::jsonb, 1 @@ -3599,7 +3602,10 @@ select # (lambda l: (l.agregar(3), l.agregar(5), l.contiene(5) and l.largo == 2)[-1])(ListaEnlazada()) # Resultado esperado: True ', - 'def __init__(self)', + 'def __init__(self) +def agregar(self, valor) +def eliminar(self, valor) +def contiene(self, valor)', '[{"id":"list-add","label":"Agrega y encuentra","input":"(lambda l: (l.agregar(3), l.agregar(5), l.contiene(5) and l.largo == 2)[-1])(ListaEnlazada())","output":"True","explanation":"Enlaza el nuevo nodo y actualiza el largo."},{"id":"list-remove-head","label":"Elimina la cabeza","input":"(lambda l: (l.agregar(3), l.agregar(5), l.eliminar(3) and not l.contiene(3) and l.largo == 1)[-1])(ListaEnlazada())","output":"True","explanation":"Actualiza cabeza cuando eliminas el primer nodo."}]'::jsonb, '[{"id":"list-add","label":"Agrega y encuentra","expression":"(lambda l: (l.agregar(3), l.agregar(5), l.contiene(5) and l.largo == 2)[-1])(ListaEnlazada())","expected":"True","feedback":"Enlaza el nuevo nodo y actualiza el largo."},{"id":"list-remove-head","label":"Elimina la cabeza","expression":"(lambda l: (l.agregar(3), l.agregar(5), l.eliminar(3) and not l.contiene(3) and l.largo == 1)[-1])(ListaEnlazada())","expected":"True","feedback":"Actualiza cabeza cuando eliminas el primer nodo."}]'::jsonb, 1 @@ -3969,7 +3975,11 @@ select # (lambda q: (q.encolar(4), q.encolar(8), q.desencolar() == 4 and q.frente() == 8)[-1])(Cola()) # Resultado esperado: True ', - 'def __init__(self)', + 'def __init__(self) +def encolar(self, valor) +def desencolar(self) +def frente(self) +def esta_vacia(self)', '[{"id":"queue-order","label":"Respeta FIFO","input":"(lambda q: (q.encolar(4), q.encolar(8), q.desencolar() == 4 and q.frente() == 8)[-1])(Cola())","output":"True","explanation":"El primer valor que entra debe ser el primero que sale."},{"id":"queue-empty","label":"Maneja una cola vacía","input":"(lambda q: q.esta_vacia() and q.desencolar() is None and q.frente() is None)(Cola())","output":"True","explanation":"Define una salida estable para la cola vacía."}]'::jsonb, '[{"id":"queue-order","label":"Respeta FIFO","expression":"(lambda q: (q.encolar(4), q.encolar(8), q.desencolar() == 4 and q.frente() == 8)[-1])(Cola())","expected":"True","feedback":"El primer valor que entra debe ser el primero que sale."},{"id":"queue-empty","label":"Maneja una cola vacía","expression":"(lambda q: q.esta_vacia() and q.desencolar() is None and q.frente() is None)(Cola())","expected":"True","feedback":"Define una salida estable para la cola vacía."}]'::jsonb, 1 @@ -4276,7 +4286,9 @@ select # (lambda a: ([a.insertar(x) for x in [8, 3, 10, 6]], a.contiene(6) and not a.contiene(9))[-1])(ArbolBusqueda()) # Resultado esperado: True ', - 'def __init__(self)', + 'def __init__(self) +def insertar(self, valor) +def contiene(self, valor)', '[{"id":"tree-find","label":"Inserta y encuentra","input":"(lambda a: ([a.insertar(x) for x in [8, 3, 10, 6]], a.contiene(6) and not a.contiene(9))[-1])(ArbolBusqueda())","output":"True","explanation":"Compara y avanza por la rama correspondiente."},{"id":"tree-order","label":"Mantiene el orden","input":"(lambda a: ([a.insertar(x) for x in [8, 3, 10]], a.raiz[''izquierda''][''valor''] == 3 and a.raiz[''derecha''][''valor''] == 10)[-1])(ArbolBusqueda())","output":"True","explanation":"Menores van a la izquierda y mayores a la derecha."}]'::jsonb, '[{"id":"tree-find","label":"Inserta y encuentra","expression":"(lambda a: ([a.insertar(x) for x in [8, 3, 10, 6]], a.contiene(6) and not a.contiene(9))[-1])(ArbolBusqueda())","expected":"True","feedback":"Compara y avanza por la rama correspondiente."},{"id":"tree-order","label":"Mantiene el orden","expression":"(lambda a: ([a.insertar(x) for x in [8, 3, 10]], a.raiz[''izquierda''][''valor''] == 3 and a.raiz[''derecha''][''valor''] == 10)[-1])(ArbolBusqueda())","expected":"True","feedback":"Menores van a la izquierda y mayores a la derecha."}]'::jsonb, 1 diff --git a/supabase/seed.sql b/supabase/seed.sql index 1f02be1..49b2209 100644 --- a/supabase/seed.sql +++ b/supabase/seed.sql @@ -1524,7 +1524,8 @@ function necesitaReposicion(stock, minimo) { // stockSeguro(12, 5) // Resultado esperado: 7 ', - 'function stockSeguro(stock, retiro)', + 'function stockSeguro(stock, retiro) +function necesitaReposicion(stock, minimo)', '[{"id":"stock-update","label":"Descuenta un retiro válido","input":"stockSeguro(12, 5)","output":"7","explanation":"Resta solo después de validar."},{"id":"stock-invalid","label":"Impide stock negativo","input":"stockSeguro(4, 8)","output":"-1","explanation":"Un retiro mayor al stock debe rechazarse."}]'::jsonb, '[{"id":"stock-update","label":"Descuenta un retiro válido","expression":"stockSeguro(12, 5) === 7","expected":"7","feedback":"Resta solo después de validar.","actualExpression":"stockSeguro(12, 5)"},{"id":"stock-invalid","label":"Impide stock negativo","expression":"stockSeguro(4, 8) === -1","expected":"-1","feedback":"Un retiro mayor al stock debe rechazarse.","actualExpression":"stockSeguro(4, 8)"}]'::jsonb, 1 @@ -1589,7 +1590,8 @@ def necesita_reposicion(stock, minimo): # stock_seguro(12, 5) # Resultado esperado: 7 ', - 'def stock_seguro(stock, retiro)', + 'def stock_seguro(stock, retiro) +def necesita_reposicion(stock, minimo)', '[{"id":"stock-update","label":"Descuenta un retiro válido","input":"stock_seguro(12, 5)","output":"7","explanation":"Resta solo después de validar."},{"id":"stock-invalid","label":"Impide stock negativo","input":"stock_seguro(4, 8)","output":"-1","explanation":"Un retiro mayor al stock debe rechazarse."}]'::jsonb, '[{"id":"stock-update","label":"Descuenta un retiro válido","expression":"stock_seguro(12, 5) == 7","expected":"7","feedback":"Resta solo después de validar.","actualExpression":"stock_seguro(12, 5)"},{"id":"stock-invalid","label":"Impide stock negativo","expression":"stock_seguro(4, 8) == -1","expected":"-1","feedback":"Un retiro mayor al stock debe rechazarse.","actualExpression":"stock_seguro(4, 8)"}]'::jsonb, 1 @@ -1669,7 +1671,8 @@ bool necesitaReposicion(int stock, int minimo) { // stockSeguro(12, 5) == 7 // Resultado esperado: 7 ', - 'int stockSeguro(int stock, int retiro)', + 'int stockSeguro(int stock, int retiro) +bool necesitaReposicion(int stock, int minimo)', '[{"id":"stock-update","label":"Descuenta un retiro válido","input":"stockSeguro(12, 5) == 7","output":"7","explanation":"Resta solo después de validar."},{"id":"stock-invalid","label":"Impide stock negativo","input":"stockSeguro(4, 8) == -1","output":"-1","explanation":"Un retiro mayor al stock debe rechazarse."}]'::jsonb, '[{"id":"stock-update","label":"Descuenta un retiro válido","expression":"stockSeguro(12, 5) == 7","expected":"7","feedback":"Resta solo después de validar."},{"id":"stock-invalid","label":"Impide stock negativo","expression":"stockSeguro(4, 8) == -1","expected":"-1","feedback":"Un retiro mayor al stock debe rechazarse."}]'::jsonb, 1 @@ -3599,7 +3602,10 @@ select # (lambda l: (l.agregar(3), l.agregar(5), l.contiene(5) and l.largo == 2)[-1])(ListaEnlazada()) # Resultado esperado: True ', - 'def __init__(self)', + 'def __init__(self) +def agregar(self, valor) +def eliminar(self, valor) +def contiene(self, valor)', '[{"id":"list-add","label":"Agrega y encuentra","input":"(lambda l: (l.agregar(3), l.agregar(5), l.contiene(5) and l.largo == 2)[-1])(ListaEnlazada())","output":"True","explanation":"Enlaza el nuevo nodo y actualiza el largo."},{"id":"list-remove-head","label":"Elimina la cabeza","input":"(lambda l: (l.agregar(3), l.agregar(5), l.eliminar(3) and not l.contiene(3) and l.largo == 1)[-1])(ListaEnlazada())","output":"True","explanation":"Actualiza cabeza cuando eliminas el primer nodo."}]'::jsonb, '[{"id":"list-add","label":"Agrega y encuentra","expression":"(lambda l: (l.agregar(3), l.agregar(5), l.contiene(5) and l.largo == 2)[-1])(ListaEnlazada())","expected":"True","feedback":"Enlaza el nuevo nodo y actualiza el largo."},{"id":"list-remove-head","label":"Elimina la cabeza","expression":"(lambda l: (l.agregar(3), l.agregar(5), l.eliminar(3) and not l.contiene(3) and l.largo == 1)[-1])(ListaEnlazada())","expected":"True","feedback":"Actualiza cabeza cuando eliminas el primer nodo."}]'::jsonb, 1 @@ -3969,7 +3975,11 @@ select # (lambda q: (q.encolar(4), q.encolar(8), q.desencolar() == 4 and q.frente() == 8)[-1])(Cola()) # Resultado esperado: True ', - 'def __init__(self)', + 'def __init__(self) +def encolar(self, valor) +def desencolar(self) +def frente(self) +def esta_vacia(self)', '[{"id":"queue-order","label":"Respeta FIFO","input":"(lambda q: (q.encolar(4), q.encolar(8), q.desencolar() == 4 and q.frente() == 8)[-1])(Cola())","output":"True","explanation":"El primer valor que entra debe ser el primero que sale."},{"id":"queue-empty","label":"Maneja una cola vacía","input":"(lambda q: q.esta_vacia() and q.desencolar() is None and q.frente() is None)(Cola())","output":"True","explanation":"Define una salida estable para la cola vacía."}]'::jsonb, '[{"id":"queue-order","label":"Respeta FIFO","expression":"(lambda q: (q.encolar(4), q.encolar(8), q.desencolar() == 4 and q.frente() == 8)[-1])(Cola())","expected":"True","feedback":"El primer valor que entra debe ser el primero que sale."},{"id":"queue-empty","label":"Maneja una cola vacía","expression":"(lambda q: q.esta_vacia() and q.desencolar() is None and q.frente() is None)(Cola())","expected":"True","feedback":"Define una salida estable para la cola vacía."}]'::jsonb, 1 @@ -4276,7 +4286,9 @@ select # (lambda a: ([a.insertar(x) for x in [8, 3, 10, 6]], a.contiene(6) and not a.contiene(9))[-1])(ArbolBusqueda()) # Resultado esperado: True ', - 'def __init__(self)', + 'def __init__(self) +def insertar(self, valor) +def contiene(self, valor)', '[{"id":"tree-find","label":"Inserta y encuentra","input":"(lambda a: ([a.insertar(x) for x in [8, 3, 10, 6]], a.contiene(6) and not a.contiene(9))[-1])(ArbolBusqueda())","output":"True","explanation":"Compara y avanza por la rama correspondiente."},{"id":"tree-order","label":"Mantiene el orden","input":"(lambda a: ([a.insertar(x) for x in [8, 3, 10]], a.raiz[''izquierda''][''valor''] == 3 and a.raiz[''derecha''][''valor''] == 10)[-1])(ArbolBusqueda())","output":"True","explanation":"Menores van a la izquierda y mayores a la derecha."}]'::jsonb, '[{"id":"tree-find","label":"Inserta y encuentra","expression":"(lambda a: ([a.insertar(x) for x in [8, 3, 10, 6]], a.contiene(6) and not a.contiene(9))[-1])(ArbolBusqueda())","expected":"True","feedback":"Compara y avanza por la rama correspondiente."},{"id":"tree-order","label":"Mantiene el orden","expression":"(lambda a: ([a.insertar(x) for x in [8, 3, 10]], a.raiz[''izquierda''][''valor''] == 3 and a.raiz[''derecha''][''valor''] == 10)[-1])(ArbolBusqueda())","expected":"True","feedback":"Menores van a la izquierda y mayores a la derecha."}]'::jsonb, 1 diff --git a/v2/src/data/mission-builders.ts b/v2/src/data/mission-builders.ts index fddee24..2cf6701 100644 --- a/v2/src/data/mission-builders.ts +++ b/v2/src/data/mission-builders.ts @@ -77,13 +77,13 @@ function inferSignature(language: Language, starterCode: string): string { .split("\n") .map((line) => line.trim()) .filter(Boolean); - const signature = + const signatures = language === "python" - ? lines.find((line) => line.startsWith("def ")) - : lines.find((line) => line.includes("(") && line.endsWith("{")); - return (signature ?? lines[0] ?? "") - .replace(/\s*\{$/, "") - .replace(/:$/, ""); + ? lines.filter((line) => line.startsWith("def ")) + : lines.filter((line) => line.includes("(") && line.endsWith("{") && !line.includes(";") && !line.includes(":")); + return (signatures.length ? signatures : [lines[0] ?? ""]) + .map((signature) => signature.replace(/\s*\{$/, "").replace(/:$/, "")) + .join("\n"); } function exampleFromTest(testCase: MissionTest, index: number): MissionExample { diff --git a/v2/src/data/missions-public.generated.ts b/v2/src/data/missions-public.generated.ts index 48f1919..93db375 100644 --- a/v2/src/data/missions-public.generated.ts +++ b/v2/src/data/missions-public.generated.ts @@ -1046,7 +1046,7 @@ export const publicMissions = [ "javascript": { "language": "javascript", "starterCode": "function stockSeguro(stock, retiro) {\n const retiroInvalido = false; // TODO: valida ambos casos inválidos.\n if (retiroInvalido) return -1;\n return stock; // TODO: aplica el retiro.\n}\n\nfunction necesitaReposicion(stock, minimo) {\n return false; // TODO: compara el stock con el mínimo.\n}\n\n// DATOS DE EJEMPLO (el evaluador usará también otros valores):\n// stockSeguro(12, 5)\n// Resultado esperado: 7\n", - "expectedSignature": "function stockSeguro(stock, retiro)", + "expectedSignature": "function stockSeguro(stock, retiro)\nfunction necesitaReposicion(stock, minimo)", "examples": [ { "id": "stock-update", @@ -1086,7 +1086,7 @@ export const publicMissions = [ "python": { "language": "python", "starterCode": "def stock_seguro(stock, retiro):\n retiro_invalido = False # TODO: valida ambos casos inválidos.\n if retiro_invalido:\n return -1\n return stock # TODO: aplica el retiro.\n\ndef necesita_reposicion(stock, minimo):\n return False # TODO: compara el stock con el mínimo.\n\n# DATOS DE EJEMPLO (el evaluador usará también otros valores):\n# stock_seguro(12, 5)\n# Resultado esperado: 7\n", - "expectedSignature": "def stock_seguro(stock, retiro)", + "expectedSignature": "def stock_seguro(stock, retiro)\ndef necesita_reposicion(stock, minimo)", "examples": [ { "id": "stock-update", @@ -1126,7 +1126,7 @@ export const publicMissions = [ "cpp": { "language": "cpp", "starterCode": "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nusing namespace std;\n\nint stockSeguro(int stock, int retiro) {\n bool retiroInvalido = false; // TODO: valida ambos casos inválidos.\n if (retiroInvalido) return -1;\n return stock; // TODO: aplica el retiro.\n}\n\nbool necesitaReposicion(int stock, int minimo) {\n return false; // TODO: compara el stock con el mínimo.\n}\n\n// DATOS DE EJEMPLO (el evaluador usará también otros valores):\n// stockSeguro(12, 5) == 7\n// Resultado esperado: 7\n", - "expectedSignature": "int stockSeguro(int stock, int retiro)", + "expectedSignature": "int stockSeguro(int stock, int retiro)\nbool necesitaReposicion(int stock, int minimo)", "examples": [ { "id": "stock-update", @@ -2424,7 +2424,7 @@ export const publicMissions = [ "python": { "language": "python", "starterCode": "class ListaEnlazada:\n def __init__(self):\n self.cabeza = None\n self.largo = 0\n\n def agregar(self, valor):\n pass\n\n def eliminar(self, valor):\n pass\n\n def contiene(self, valor):\n pass\n\n# DATOS DE EJEMPLO (el evaluador usará también otros valores):\n# (lambda l: (l.agregar(3), l.agregar(5), l.contiene(5) and l.largo == 2)[-1])(ListaEnlazada())\n# Resultado esperado: True\n", - "expectedSignature": "def __init__(self)", + "expectedSignature": "def __init__(self)\ndef agregar(self, valor)\ndef eliminar(self, valor)\ndef contiene(self, valor)", "examples": [ { "id": "list-add", @@ -2588,7 +2588,7 @@ export const publicMissions = [ "python": { "language": "python", "starterCode": "class Cola:\n def __init__(self):\n self.datos = []\n self.inicio = 0\n\n def encolar(self, valor):\n pass\n\n def desencolar(self):\n pass\n\n def frente(self):\n pass\n\n def esta_vacia(self):\n pass\n\n# DATOS DE EJEMPLO (el evaluador usará también otros valores):\n# (lambda q: (q.encolar(4), q.encolar(8), q.desencolar() == 4 and q.frente() == 8)[-1])(Cola())\n# Resultado esperado: True\n", - "expectedSignature": "def __init__(self)", + "expectedSignature": "def __init__(self)\ndef encolar(self, valor)\ndef desencolar(self)\ndef frente(self)\ndef esta_vacia(self)", "examples": [ { "id": "queue-order", @@ -2752,7 +2752,7 @@ export const publicMissions = [ "python": { "language": "python", "starterCode": "class ArbolBusqueda:\n def __init__(self):\n self.raiz = None\n\n def insertar(self, valor):\n pass\n\n def contiene(self, valor):\n pass\n\n# DATOS DE EJEMPLO (el evaluador usará también otros valores):\n# (lambda a: ([a.insertar(x) for x in [8, 3, 10, 6]], a.contiene(6) and not a.contiene(9))[-1])(ArbolBusqueda())\n# Resultado esperado: True\n", - "expectedSignature": "def __init__(self)", + "expectedSignature": "def __init__(self)\ndef insertar(self, valor)\ndef contiene(self, valor)", "examples": [ { "id": "tree-find", diff --git a/v2/src/pages/MissionWorkspace.tsx b/v2/src/pages/MissionWorkspace.tsx index 6ed3622..33c723e 100644 --- a/v2/src/pages/MissionWorkspace.tsx +++ b/v2/src/pages/MissionWorkspace.tsx @@ -49,7 +49,7 @@ import { loadDraft, saveDraft, } from "@/services/draft-store"; -import { runMissionCode } from "@/services/runner"; +import { runManualCode, runMissionCode } from "@/services/runner"; import { runMissionAdmin, type MissionSolution, @@ -62,6 +62,7 @@ import { type Attempt, type AttemptKind, type Language, + type ManualRunResult, type RunResult, } from "@/types"; @@ -70,6 +71,7 @@ const MonacoEditor = lazy(() => import("@monaco-editor/react")); type MobilePane = "brief" | "code" | "results"; type BriefTab = "problem" | "hints" | "history" | "solution"; type SaveState = "loading" | "saving" | "synced" | "local" | "error"; +type ManualRunState = "idle" | "running"; const RESULTS_WIDTH_KEY = "tomatin.v3.workspace-results-width"; const MIN_RESULTS_WIDTH = 290; @@ -432,6 +434,10 @@ export function Component() { const [saveState, setSaveState] = useState("loading"); const [saveMessage, setSaveMessage] = useState(""); const [result, setResult] = useState(null); + const [manualOpen, setManualOpen] = useState(false); + const [manualExpression, setManualExpression] = useState(""); + const [manualResult, setManualResult] = useState(null); + const [manualRunning, setManualRunning] = useState("idle"); const [running, setRunning] = useState(null); const [briefTab, setBriefTab] = useState( linkedAttemptId || linkedReviewId ? "history" : "problem", @@ -745,6 +751,10 @@ export function Component() { testCase.actualExpression ?? testCase.expression, ]), ); + const manualSignatureHints = activeMission.variants[language].expectedSignature + .split("\n") + .map((entry) => entry.trim()) + .filter(Boolean); const contractGuide = languageContract(language); const visibleExample = activeMission.variants[language].examples[0]; const visibleCall = @@ -817,6 +827,19 @@ export function Component() { setRunning(null); } + async function executeManualTest() { + if (language === "cpp" || manualRunning === "running") return; + setManualRunning("running"); + setManualResult(null); + const manual = await runManualCode({ + language, + code: currentCode, + expression: manualExpression, + }); + setManualResult(manual); + setManualRunning("idle"); + } + function clampResultsWidth(nextWidth: number) { const workbenchWidth = workbenchRef.current?.clientWidth ?? 0; const maxWidth = Math.max( @@ -1428,6 +1451,23 @@ export function Component() { ? "Pyodide Worker" : "Web Worker"} + + + + {manualSignatureHints.length > 0 ? ( +

+ Funciones evaluadas en este ejercicio:{" "} + {manualSignatureHints.map((signature, index) => ( + + {index > 0 ? ", " : ""} + {signature} + + ))} +

+ ) : null} +
+ + +
+ {manualResult ? ( +
+ + {manualResult.status === "passed" + ? "Resultado" + : "No se pudo ejecutar"} + +
+
+
Expresión
+
+ {manualResult.expression} +
+
+ {manualResult.value !== undefined ? ( +
+
Valor
+
+ {manualResult.value} +
+
+ ) : null} +
+ {manualResult.stdout || manualResult.stderr ? ( +
+                        {manualResult.stdout ? `$ ${manualResult.stdout}\n` : ""}
+                        {manualResult.stderr
+                          ? `[stderr]\n${manualResult.stderr}`
+                          : ""}
+                      
+ ) : null} +
+ ) : null} + + + ) : null} +