From c1bdb59445d66b517aa0b319dd4f3433c509f1e0 Mon Sep 17 00:00:00 2001 From: Le Roux Bodenstein Date: Tue, 17 Dec 2024 12:38:22 +0000 Subject: [PATCH] fix(browser-repl): don't override output that came from onPrint (#2304) don't override output that came from onPrint --- .../src/components/shell.spec.tsx | 33 +++++++++++++++---- .../browser-repl/src/components/shell.tsx | 31 +++++++++-------- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/packages/browser-repl/src/components/shell.spec.tsx b/packages/browser-repl/src/components/shell.spec.tsx index 0d4a8a265..dfe4804ca 100644 --- a/packages/browser-repl/src/components/shell.spec.tsx +++ b/packages/browser-repl/src/components/shell.spec.tsx @@ -372,7 +372,22 @@ describe('shell', function () { expect(filterEvaluateCalls(fakeRuntime.evaluate.args)).to.have.length(1); }); - it('prints when onPrint is called', async function () { + it('prints when onPrint is called while evaluating', async function () { + fakeRuntime = { + evaluate: sinon.stub().callsFake(async (command: string) => { + if (command === 'my command') { + // don't print every time we update the prompt, only once for the actual command being input + await listener?.onPrint?.([ + { type: null, printable: 'from inside onPrint' }, + ]); + } + return { printable: 'some result' }; + }), + setEvaluationListener: (_listener) => { + listener = _listener; + }, + }; + const initialEvaluate = 'my command'; let output = []; @@ -389,16 +404,22 @@ describe('shell', function () { /> ); - await waitFor(() => expect(listener).to.exist); - await listener?.onPrint?.([{ type: null, printable: 42 }]); - await waitFor(() => { expect(output[output.length - 1]).to.deep.equal({ format: 'output', - type: null, - value: 42, + type: undefined, + value: 'some result', }); }); + + expect(output).to.deep.equal([ + // we typed "my command" + { format: 'input', value: 'my command' }, + // while evaluating it printed something + { format: 'output', type: null, value: 'from inside onPrint' }, + // we then printed the result of the evaluation + { format: 'output', type: undefined, value: 'some result' }, + ]); }); it('clears the output when onClearCommand is called', async function () { diff --git a/packages/browser-repl/src/components/shell.tsx b/packages/browser-repl/src/components/shell.tsx index 18e4f0626..d7a220a65 100644 --- a/packages/browser-repl/src/components/shell.tsx +++ b/packages/browser-repl/src/components/shell.tsx @@ -375,39 +375,42 @@ const _Shell: ForwardRefRenderFunction = ( const onInput = useCallback( async (code: string) => { - const newOutput = [...(outputRef.current ?? [])]; - const newHistory = [...(historyRef.current ?? [])]; + const newOutputBeforeEval = [...(outputRef.current ?? [])]; // don't evaluate empty input, but do add it to the output if (!code || code.trim() === '') { - newOutput.push({ + newOutputBeforeEval.push({ format: 'input', value: ' ', }); - capLengthEnd(newOutput, maxOutputLength); - outputRef.current = newOutput; - onOutputChanged?.(newOutput); + capLengthEnd(newOutputBeforeEval, maxOutputLength); + outputRef.current = newOutputBeforeEval; + onOutputChanged?.(newOutputBeforeEval); return; } // add input to output - newOutput.push({ + newOutputBeforeEval.push({ format: 'input', value: code, }); - capLengthEnd(newOutput, maxOutputLength); - outputRef.current = newOutput; - onOutputChanged?.(newOutput); + capLengthEnd(newOutputBeforeEval, maxOutputLength); + outputRef.current = newOutputBeforeEval; + onOutputChanged?.(newOutputBeforeEval); const outputLine = await evaluate(code); + // outputRef.current could have changed if evaluate() used onPrint + const newOutputAfterEval = [...(outputRef.current ?? [])]; + // add output to output - newOutput.push(outputLine); - capLengthEnd(newOutput, maxOutputLength); - outputRef.current = newOutput; - onOutputChanged?.(newOutput); + newOutputAfterEval.push(outputLine); + capLengthEnd(newOutputAfterEval, maxOutputLength); + outputRef.current = newOutputAfterEval; + onOutputChanged?.(newOutputAfterEval); // update history + const newHistory = [...(historyRef.current ?? [])]; newHistory.unshift(code); capLengthStart(newHistory, maxHistoryLength); changeHistory(