Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions packages/browser-repl/src/components/shell.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [];
Expand All @@ -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 () {
Expand Down
31 changes: 17 additions & 14 deletions packages/browser-repl/src/components/shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -375,39 +375,42 @@ const _Shell: ForwardRefRenderFunction<EditorRef | null, ShellProps> = (

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(
Expand Down
Loading