@@ -27,16 +27,16 @@ export function parse(input) {
2727}
2828
2929document . querySelectorAll ( 'pre' ) . forEach ( ( pre ) => {
30- const code = pre . textContent . trim ( ) ;
30+ let code = pre . textContent . trim ( ) ;
3131
3232 let ast ;
3333 try {
3434 ast = parse ( code ) ;
3535 } catch {
36- return ;
36+ return ; // Don't process non-stepcode pre blocks
3737 }
3838
39- const lines = code . split ( '\n' ) ;
39+ let lines = code . split ( '\n' ) ;
4040 let state = null ;
4141 let running = false ;
4242 let history = [ ] ;
@@ -45,21 +45,39 @@ document.querySelectorAll('pre').forEach((pre) => {
4545 wrapper . className = 'pseudo-runner' ;
4646 pre . replaceWith ( wrapper ) ;
4747
48+ const editor = document . createElement ( 'textarea' ) ;
49+ editor . className = 'pseudo-editor' ;
50+ editor . value = code ;
51+ editor . spellcheck = false ;
52+ wrapper . appendChild ( editor ) ;
53+
4854 const display = document . createElement ( 'pre' ) ;
55+ display . style . display = 'none' ; // Initially hidden, shows when running
4956 wrapper . appendChild ( display ) ;
5057
5158 const controls = document . createElement ( 'div' ) ;
5259 controls . className = 'pseudo-runner-controls' ;
5360 wrapper . appendChild ( controls ) ;
5461
62+ const btn = document . createElement ( 'button' ) ;
63+ btn . textContent = '▶ Run' ;
64+ controls . appendChild ( btn ) ;
65+
5566 const prevBtn = document . createElement ( 'button' ) ;
5667 prevBtn . textContent = '⏮ Previous' ;
5768 prevBtn . style . display = 'none' ;
5869 controls . appendChild ( prevBtn ) ;
5970
60- const btn = document . createElement ( 'button' ) ;
61- btn . textContent = '▶ Run' ;
62- controls . appendChild ( btn ) ;
71+ const editBtn = document . createElement ( 'button' ) ;
72+ editBtn . textContent = '✏️ Edit' ;
73+ editBtn . style . display = 'none' ;
74+ controls . appendChild ( editBtn ) ;
75+
76+ const errorDisplay = document . createElement ( 'div' ) ;
77+ errorDisplay . className = 'pseudo-error' ;
78+ errorDisplay . style . color = 'var(--accent-color)' ;
79+ errorDisplay . style . display = 'none' ;
80+ wrapper . appendChild ( errorDisplay ) ;
6381
6482 function formatVars ( variables ) {
6583 const vars = Object . entries ( variables || { } )
@@ -70,6 +88,17 @@ document.querySelectorAll('pre').forEach((pre) => {
7088 }
7189
7290 function render ( ) {
91+ if ( ! running ) {
92+ editor . style . display = 'block' ;
93+ display . style . display = 'none' ;
94+ editBtn . style . display = 'none' ;
95+ return ;
96+ }
97+
98+ editor . style . display = 'none' ;
99+ display . style . display = 'block' ;
100+ editBtn . style . display = 'flex' ;
101+
73102 const isReturning = state ?. variables ?. [ '<return>' ] !== undefined ;
74103 const rows = [ ] ;
75104
@@ -94,14 +123,14 @@ document.querySelectorAll('pre').forEach((pre) => {
94123 if ( ! state ) {
95124 btn . textContent = '▶ Run' ;
96125 running = false ;
126+ render ( ) ; // switch back to editor
97127 } else if ( state . nextLine === null ) {
98128 const vars = formatVars ( state . variables ) ;
99129 rows . push ( `<span class="indicator">>>> ${ vars } </span>` ) ;
100130 btn . textContent = '↺ Restart' ;
101- running = false ;
131+ // running remains true, waiting for user to restart or edit
102132 } else {
103133 btn . textContent = '⏭ Next' ;
104- running = true ;
105134 }
106135
107136 prevBtn . style . display = history . length > 0 ? 'flex' : 'none' ;
@@ -110,9 +139,22 @@ document.querySelectorAll('pre').forEach((pre) => {
110139 }
111140
112141 btn . addEventListener ( 'click' , ( ) => {
113- if ( ! running || ! state || state . nextLine === null ) {
114- state = step ( ast , null ) ;
115- history = [ ] ;
142+ errorDisplay . style . display = 'none' ;
143+ if ( ! running || ( ! state && btn . textContent === '▶ Run' ) || ( state && state . nextLine === null ) ) {
144+ // Start or Restart
145+ code = editor . value ;
146+ lines = code . split ( '\n' ) ;
147+ try {
148+ ast = parse ( code ) ;
149+ state = step ( ast , null ) ;
150+ history = [ ] ;
151+ running = true ;
152+ } catch ( e ) {
153+ errorDisplay . textContent = e . message ;
154+ errorDisplay . style . display = 'block' ;
155+ running = false ;
156+ return ;
157+ }
116158 } else {
117159 history . push ( state ) ;
118160 state = step ( ast , state ) ;
@@ -127,5 +169,15 @@ document.querySelectorAll('pre').forEach((pre) => {
127169 }
128170 } ) ;
129171
172+ editBtn . addEventListener ( 'click' , ( ) => {
173+ running = false ;
174+ state = null ;
175+ history = [ ] ;
176+ btn . textContent = '▶ Run' ;
177+ render ( ) ;
178+ } ) ;
179+
180+ // initial render as editor
181+ editor . style . height = lines . length * 1.6 + 2 + 'em' ; // approx height
130182 render ( ) ;
131183} ) ;
0 commit comments