@@ -30,11 +30,13 @@ async function findWorkingBaseUrl(){
3030 const baseTag = typeof document !== 'undefined' ? document . querySelector ( 'base' ) ?. getAttribute ( 'href' ) : null ;
3131 if ( baseTag ) candidates . push ( baseTag ) ;
3232
33+ // Prefer the known site root before falling back to the current page path (e.g. /docs/)
34+ candidates . push ( '/vampireGuide/' ) ;
35+
3336 if ( typeof location !== 'undefined' ) {
3437 candidates . push ( new URL ( './' , location . href ) . pathname ) ;
3538 }
3639
37- candidates . push ( '/vampireGuide/' ) ;
3840 candidates . push ( '/' ) ;
3941
4042 const seen = new Set ( ) ;
@@ -100,20 +102,48 @@ fof(b, conjecture, p).`,
100102 const [ out , setOut ] = useState ( 'Ready.' ) ;
101103 const [ pendingPrompt , setPendingPrompt ] = useState ( null ) ;
102104 const [ pendingInput , setPendingInput ] = useState ( '' ) ;
105+ const [ pendingInline , setPendingInline ] = useState ( false ) ;
106+ const [ pendingSpacer , setPendingSpacer ] = useState ( '' ) ;
107+ const [ pendingMatchText , setPendingMatchText ] = useState ( '' ) ;
103108 const pendingResolveRef = useRef ( null ) ;
104109 const [ running , setRunning ] = useState ( false ) ;
110+ const outWrapRef = useRef ( null ) ;
105111 const outCodeRef = useRef ( null ) ;
106112 const latestOutRef = useRef ( 'Ready.' ) ;
113+ const cancelRunRef = useRef ( null ) ;
114+ const runIdRef = useRef ( 0 ) ;
115+
116+ useEffect ( ( ) => {
117+ latestOutRef . current = out ;
118+ } , [ out ] ) ;
107119
108120 // Re-highlight output whenever it changes (or when Prism arrives)
109121 useEffect ( ( ) => {
110122 if ( typeof window === 'undefined' ) return ;
111123 highlightNowOrWhenReady ( outCodeRef . current ) ;
112- } , [ out , outputLanguage ] ) ;
124+ } , [ out , outputLanguage , pendingPrompt , pendingInput , pendingInline ] ) ;
113125
114126 useEffect ( ( ) => {
115- latestOutRef . current = out ;
116- } , [ out ] ) ;
127+ if ( ! outWrapRef . current ) return ;
128+ outWrapRef . current . scrollTop = outWrapRef . current . scrollHeight ;
129+ } , [ out , pendingPrompt , pendingInput , pendingInline ] ) ;
130+
131+ useEffect ( ( ) => {
132+ if ( ! pendingPrompt ) return ;
133+ outWrapRef . current ?. focus ( { preventScroll : true } ) ;
134+ } , [ pendingPrompt ] ) ;
135+
136+ const visibleOut = ( ( ) => {
137+ if ( ! pendingPrompt ) return out ;
138+ const lastLineRaw = out . split ( '\n' ) . slice ( - 1 ) [ 0 ] || '' ;
139+ const lastLine = lastLineRaw . replace ( / \s + $ / , '' ) ;
140+ const forceInline = pendingMatchText && lastLine . endsWith ( pendingMatchText ) ;
141+ if ( pendingInline || forceInline ) {
142+ return out + pendingSpacer + pendingInput ;
143+ }
144+ const sep = out ? '\n' : '' ;
145+ return out + sep + ( pendingPrompt || '> ' ) + pendingInput ;
146+ } ) ( ) ;
117147
118148 // Append a line to the transcript (one big string for highlighting)
119149 const appendLine = ( text ) => {
@@ -124,10 +154,27 @@ fof(b, conjecture, p).`,
124154 } ) ;
125155 } ;
126156
157+ const appendInline = ( text ) => {
158+ setOut ( prev => {
159+ const next = ( prev || '' ) + text ;
160+ latestOutRef . current = next ;
161+ return next ;
162+ } ) ;
163+ } ;
164+
127165 const handleRequestInput = ( promptText ) => {
128- const promptLine = promptText || '>' ;
129- appendLine ( promptLine ) ;
166+ const raw = String ( promptText ?? '' ) ;
167+ const trimmed = raw . replace ( / \s + $ / , '' ) ;
168+ const lastLineRaw = ( latestOutRef . current || '' ) . split ( '\n' ) . slice ( - 1 ) [ 0 ] || '' ;
169+ const lastLine = lastLineRaw . replace ( / \r / g, '' ) . trim ( ) ;
170+ const normalizedPrompt = trimmed . replace ( / \r / g, '' ) . trim ( ) ;
171+ const inline = Boolean ( normalizedPrompt ) && lastLine . endsWith ( normalizedPrompt ) ;
172+ const spacer = inline && ! / \s $ / . test ( lastLineRaw ) ? ' ' : '' ;
173+ const promptLine = inline ? '' : ( normalizedPrompt ? ( normalizedPrompt + ' ' ) : '> ' ) ;
130174 setPendingPrompt ( promptLine ) ;
175+ setPendingInline ( inline ) ;
176+ setPendingSpacer ( spacer ) ;
177+ setPendingMatchText ( normalizedPrompt ) ;
131178 setPendingInput ( '' ) ;
132179 return new Promise ( ( resolve ) => {
133180 pendingResolveRef . current = resolve ;
@@ -137,27 +184,61 @@ fof(b, conjecture, p).`,
137184 const submitPromptResponse = ( ) => {
138185 if ( ! pendingResolveRef . current ) return ;
139186 const answer = pendingInput ;
140- appendLine ( `> ${ answer } ` ) ;
187+ const lastLineRaw = ( latestOutRef . current || '' ) . split ( '\n' ) . slice ( - 1 ) [ 0 ] || '' ;
188+ const lastLine = lastLineRaw . replace ( / \s + $ / , '' ) ;
189+ const forceInline = pendingMatchText && lastLine . endsWith ( pendingMatchText ) ;
190+ if ( pendingInline || forceInline ) {
191+ appendInline ( `${ pendingSpacer } ${ answer } ` ) ;
192+ } else {
193+ appendLine ( `${ pendingPrompt ?? '> ' } ${ answer } ` ) ;
194+ }
141195 pendingResolveRef . current ( answer ) ;
142196 pendingResolveRef . current = null ;
143197 setPendingPrompt ( null ) ;
144198 setPendingInput ( '' ) ;
199+ setPendingInline ( false ) ;
200+ setPendingSpacer ( '' ) ;
201+ setPendingMatchText ( '' ) ;
145202 } ;
146203
147204 const handleKeyDown = ( ev ) => {
205+ if ( ! pendingPrompt ) return ;
148206 if ( ev . key === 'Enter' ) {
149207 ev . preventDefault ( ) ;
150208 submitPromptResponse ( ) ;
209+ return ;
210+ }
211+ if ( ev . key === 'Backspace' ) {
212+ ev . preventDefault ( ) ;
213+ setPendingInput ( prev => prev . slice ( 0 , - 1 ) ) ;
214+ return ;
215+ }
216+ if ( ev . key . length === 1 && ! ev . ctrlKey && ! ev . metaKey && ! ev . altKey ) {
217+ ev . preventDefault ( ) ;
218+ setPendingInput ( prev => prev + ev . key ) ;
151219 }
152220 } ;
153221
222+ const handlePaste = ( ev ) => {
223+ if ( ! pendingPrompt ) return ;
224+ const text = ev . clipboardData ?. getData ( 'text' ) ;
225+ if ( ! text ) return ;
226+ ev . preventDefault ( ) ;
227+ setPendingInput ( prev => prev + text . replace ( / \r / g, '' ) ) ;
228+ } ;
229+
154230 async function onRun ( ) {
231+ const newRunId = runIdRef . current + 1 ;
232+ runIdRef . current = newRunId ;
233+ if ( cancelRunRef . current ) {
234+ cancelRunRef . current ( ) ;
235+ cancelRunRef . current = null ;
236+ }
155237 setRunning ( true ) ;
156238 setOut ( 'Running…' ) ;
157239 setPendingPrompt ( null ) ;
158240 setPendingInput ( '' ) ;
159241 if ( pendingResolveRef . current ) {
160- pendingResolveRef . current ( '' ) ;
161242 pendingResolveRef . current = null ;
162243 }
163244 try {
@@ -173,12 +254,33 @@ fof(b, conjecture, p).`,
173254 const { code } = await runRaw ( {
174255 tptp,
175256 args,
176- onStdout : ( msg ) => String ( msg ?? '' ) . split ( '\n' ) . forEach ( appendLine ) ,
177- onStderr : ( msg ) => String ( msg ?? '' ) . split ( '\n' ) . forEach ( line => appendLine ( `[err] ${ line } ` ) ) ,
178- requestInput : handleRequestInput ,
257+ onStdout : ( msg ) => {
258+ if ( runIdRef . current !== newRunId ) return ;
259+ String ( msg ?? '' ) . split ( '\n' ) . forEach ( appendLine ) ;
260+ } ,
261+ onStderr : ( msg ) => {
262+ if ( runIdRef . current !== newRunId ) return ;
263+ String ( msg ?? '' ) . split ( '\n' ) . forEach ( line => appendLine ( `[err] ${ line } ` ) ) ;
264+ } ,
265+ requestInput : ( promptText ) => {
266+ if ( runIdRef . current !== newRunId ) return new Promise ( ( ) => { } ) ;
267+ return handleRequestInput ( promptText ) ;
268+ } ,
269+ onReady : ( instance ) => {
270+ if ( runIdRef . current !== newRunId ) {
271+ return ;
272+ }
273+ cancelRunRef . current = ( ) => {
274+ if ( pendingResolveRef . current ) {
275+ pendingResolveRef . current = null ;
276+ }
277+ } ;
278+ } ,
179279 } ) ;
180- const exitCode = typeof code === 'number' ? code : 0 ;
181- appendLine ( `(exit ${ exitCode } )` ) ;
280+ if ( runIdRef . current === newRunId ) {
281+ const exitCode = typeof code === 'number' ? code : 0 ;
282+ appendLine ( `(exit ${ exitCode } )` ) ;
283+ }
182284
183285 // Best-effort clipboard copy to speed up sharing logs
184286 if ( navigator ?. clipboard ?. writeText ) {
@@ -189,13 +291,15 @@ fof(b, conjecture, p).`,
189291 } catch ( e ) {
190292 setOut ( `Error: ${ e ?. message || e } ` ) ;
191293 } finally {
192- if ( pendingResolveRef . current ) {
193- pendingResolveRef . current ( '' ) ;
194- pendingResolveRef . current = null ;
294+ if ( runIdRef . current === newRunId ) {
295+ if ( pendingResolveRef . current ) {
296+ pendingResolveRef . current = null ;
297+ }
298+ setPendingPrompt ( null ) ;
299+ setPendingInput ( '' ) ;
300+ setRunning ( false ) ;
301+ cancelRunRef . current = null ;
195302 }
196- setPendingPrompt ( null ) ;
197- setPendingInput ( '' ) ;
198- setRunning ( false ) ;
199303 }
200304 }
201305
@@ -228,34 +332,29 @@ fof(b, conjecture, p).`,
228332 ) }
229333 </ div >
230334
231- < p > < button className = "vr-run" onClick = { onRun } disabled = { running } > Run Vampire</ button > </ p >
232-
233- { pendingPrompt && (
234- < div style = { { marginBottom : '0.75rem' } } >
235- < label > Input required (prompt: { pendingPrompt } )</ label >
236- < input
237- type = "text"
238- value = { pendingInput }
239- onChange = { e => setPendingInput ( e . target . value ) }
240- onKeyDown = { handleKeyDown }
241- style = { { width : '100%' , padding : '0.4rem' , fontFamily : 'monospace' } }
242- autoFocus
243- />
244- < button className = "vr-run" onClick = { submitPromptResponse } style = { { marginTop : '0.35rem' } } >
245- Send
246- </ button >
247- </ div >
248- ) }
335+ < p > < button className = "vr-run" onClick = { onRun } > Run Vampire</ button > </ p >
249336
250337 < label > Output</ label >
251- < pre style = { { maxHeight : outputMaxHeight , overflow : 'auto' , marginTop : 0 } } >
252- < code
253- ref = { outCodeRef }
254- className = { `language-${ outputLanguage } ` }
255- >
256- { out }
257- </ code >
258- </ pre >
338+ < div
339+ ref = { outWrapRef }
340+ tabIndex = { 0 }
341+ onKeyDown = { handleKeyDown }
342+ onPaste = { handlePaste }
343+ onClick = { ( ) => outWrapRef . current ?. focus ( ) }
344+ style = { {
345+ padding : '0.5rem' ,
346+ background : 'var(--prism-background-color, transparent)'
347+ } }
348+ >
349+ < pre style = { { margin : 0 , maxHeight : outputMaxHeight , overflow : 'auto' } } >
350+ < code
351+ ref = { outCodeRef }
352+ className = { `language-${ outputLanguage } ` }
353+ >
354+ { visibleOut }
355+ </ code >
356+ </ pre >
357+ </ div >
259358 </ div >
260359 ) ;
261360}
0 commit comments