77 setError ,
88 codeRunHandled ,
99 loadingRunner ,
10+ triggerCodeRun ,
1011} from "../../../../../redux/EditorSlice" ;
1112import { Tab , Tabs , TabList , TabPanel } from "react-tabs" ;
1213import { useMediaQuery } from "react-responsive" ;
@@ -31,7 +32,7 @@ const getWorkerURL = (url) => {
3132} ;
3233
3334const PyodideRunner = ( props ) => {
34- const { active } = props ;
35+ const { active, consoleMode = false , autoRun = false } = props ;
3536
3637 // Blob approach + targeted headers - no errors but headers required in host app to interrupt code
3738 const workerUrl = getWorkerURL ( `${ process . env . PUBLIC_URL } /PyodideWorker.js` ) ;
@@ -60,6 +61,53 @@ const PyodideRunner = (props) => {
6061 const [ hasVisual , setHasVisual ] = useState ( showVisualTab || senseHatAlways ) ;
6162 const [ visuals , setVisuals ] = useState ( [ ] ) ;
6263 const [ showRunner , setShowRunner ] = useState ( active ) ;
64+ const [ inputStack , setInputStack ] = useState ( [ ] ) ;
65+ const prependToInputStack = ( input ) => {
66+ setInputStack ( ( prevInputStack ) => {
67+ if ( prevInputStack [ 0 ] === "" ) {
68+ console . log ( "overwriting..." ) ;
69+ const newStack = [ ...prevInputStack ] ;
70+ newStack [ 0 ] = input ;
71+ return newStack ;
72+ } else {
73+ console . log ( "prepending..." ) ;
74+ console . log ( prevInputStack ) ;
75+ return [ input , ...prevInputStack ] ;
76+ }
77+ } ) ;
78+ } ;
79+ const [ inputStackIndex , setInputStackIndex ] = useState ( 0 ) ;
80+
81+ useEffect ( ( ) => {
82+ const handleKeyDown = ( event ) => {
83+ if ( event . key === "ArrowUp" ) {
84+ if ( inputStackIndex < inputStack . length - 1 ) {
85+ setInputStackIndex ( inputStackIndex + 1 ) ;
86+ }
87+ } else if ( event . key === "ArrowDown" ) {
88+ if ( inputStackIndex > 0 ) {
89+ setInputStackIndex ( inputStackIndex - 1 ) ;
90+ }
91+ }
92+ } ;
93+ if ( consoleMode ) {
94+ const inputElement = getInputElement ( ) ;
95+ inputElement ?. removeEventListener ( "keydown" , handleKeyDown ) ;
96+ inputElement ?. addEventListener ( "keydown" , handleKeyDown ) ;
97+ }
98+ } , [ inputStack , inputStackIndex , consoleMode ] ) ;
99+
100+ useEffect ( ( ) => {
101+ console . log ( "inputStack" , inputStack ) ;
102+ } , [ inputStack ] ) ;
103+
104+ useEffect ( ( ) => {
105+ console . log ( "inputStackIndex" , inputStackIndex ) ;
106+ const inputElement = getInputElement ( ) ;
107+ if ( inputElement ) {
108+ inputElement . innerText = inputStack [ inputStackIndex ] ;
109+ }
110+ } , [ inputStackIndex ] ) ;
63111
64112 useEffect ( ( ) => {
65113 if ( pyodideWorker ) {
@@ -99,6 +147,13 @@ const PyodideRunner = (props) => {
99147 }
100148 } , [ ] ) ;
101149
150+ useEffect ( ( ) => {
151+ if ( autoRun ) {
152+ console . log ( "autorunning..." ) ;
153+ dispatch ( triggerCodeRun ( ) ) ;
154+ }
155+ } , [ ] ) ;
156+
102157 useEffect ( ( ) => {
103158 if ( codeRunTriggered && active ) {
104159 console . log ( "running with pyodide" ) ;
@@ -137,11 +192,19 @@ const PyodideRunner = (props) => {
137192 return ;
138193 }
139194
195+ prependToInputStack ( "" ) ;
196+ setInputStackIndex ( 0 ) ;
140197 const outputPane = output . current ;
141- outputPane . appendChild ( inputSpan ( ) ) ;
198+ // remove last new line character from last line
199+ outputPane . lastChild . innerText = outputPane . lastChild . innerText . slice (
200+ 0 ,
201+ - 1 ,
202+ ) ;
203+ outputPane . lastChild . appendChild ( inputSpan ( ) ) ;
142204
143205 const element = getInputElement ( ) ;
144206 const { content, ctrlD } = await getInputContent ( element ) ;
207+ prependToInputStack ( content ) ;
145208
146209 const encoder = new TextEncoder ( ) ;
147210 const bytes = encoder . encode ( content + "\n" ) ;
@@ -305,6 +368,7 @@ const PyodideRunner = (props) => {
305368 if ( element ) {
306369 element . removeAttribute ( "id" ) ;
307370 element . removeAttribute ( "contentEditable" ) ;
371+ element . addEventListener ( "keydown" ) ;
308372 }
309373 } ;
310374
0 commit comments