88import watcher from '@parcel/watcher' ;
99import path from 'path' ;
1010import ts from 'typescript' ;
11- import { FILTER_FILENAME , FIXTURES_PATH , PROJECT_ROOT } from './constants' ;
12- import { TestFilter , readTestFilter } from './fixture-utils' ;
11+ import { FIXTURES_PATH , PROJECT_ROOT } from './constants' ;
12+ import { TestFilter } from './fixture-utils' ;
1313import { execSync } from 'child_process' ;
1414
1515export function watchSrc (
@@ -117,6 +117,10 @@ export type RunnerState = {
117117 lastUpdate : number ;
118118 mode : RunnerMode ;
119119 filter : TestFilter | null ;
120+ debug : boolean ;
121+ // Input mode for interactive pattern entry
122+ inputMode : 'none' | 'pattern' ;
123+ inputBuffer : string ;
120124} ;
121125
122126function subscribeFixtures (
@@ -142,26 +146,6 @@ function subscribeFixtures(
142146 } ) ;
143147}
144148
145- function subscribeFilterFile (
146- state : RunnerState ,
147- onChange : ( state : RunnerState ) => void ,
148- ) {
149- watcher . subscribe ( PROJECT_ROOT , async ( err , events ) => {
150- if ( err ) {
151- console . error ( err ) ;
152- process . exit ( 1 ) ;
153- } else if (
154- events . findIndex ( event => event . path . includes ( FILTER_FILENAME ) ) !== - 1
155- ) {
156- if ( state . mode . filter ) {
157- state . filter = await readTestFilter ( ) ;
158- state . mode . action = RunnerAction . Test ;
159- onChange ( state ) ;
160- }
161- }
162- } ) ;
163- }
164-
165149function subscribeTsc (
166150 state : RunnerState ,
167151 onChange : ( state : RunnerState ) => void ,
@@ -200,15 +184,67 @@ function subscribeKeyEvents(
200184 onChange : ( state : RunnerState ) => void ,
201185) {
202186 process . stdin . on ( 'keypress' , async ( str , key ) => {
187+ // Handle input mode (pattern entry)
188+ if ( state . inputMode !== 'none' ) {
189+ if ( key . name === 'return' ) {
190+ // Enter pressed - process input
191+ const pattern = state . inputBuffer . trim ( ) ;
192+ state . inputMode = 'none' ;
193+ state . inputBuffer = '' ;
194+ process . stdout . write ( '\n' ) ;
195+
196+ if ( pattern !== '' ) {
197+ // Set the pattern as filter
198+ state . filter = { paths : [ pattern ] } ;
199+ state . mode . filter = true ;
200+ state . mode . action = RunnerAction . Test ;
201+ onChange ( state ) ;
202+ }
203+ // If empty, just exit input mode without changes
204+ return ;
205+ } else if ( key . name === 'escape' ) {
206+ // Cancel input mode
207+ state . inputMode = 'none' ;
208+ state . inputBuffer = '' ;
209+ process . stdout . write ( ' (cancelled)\n' ) ;
210+ return ;
211+ } else if ( key . name === 'backspace' ) {
212+ if ( state . inputBuffer . length > 0 ) {
213+ state . inputBuffer = state . inputBuffer . slice ( 0 , - 1 ) ;
214+ // Erase character: backspace, space, backspace
215+ process . stdout . write ( '\b \b' ) ;
216+ }
217+ return ;
218+ } else if ( str && ! key . ctrl && ! key . meta ) {
219+ // Regular character - accumulate and echo
220+ state . inputBuffer += str ;
221+ process . stdout . write ( str ) ;
222+ return ;
223+ }
224+ return ; // Ignore other keys in input mode
225+ }
226+
227+ // Normal mode keypress handling
203228 if ( key . name === 'u' ) {
204229 // u => update fixtures
205230 state . mode . action = RunnerAction . Update ;
206231 } else if ( key . name === 'q' ) {
207232 process . exit ( 0 ) ;
208- } else if ( key . name === 'f' ) {
209- state . mode . filter = ! state . mode . filter ;
210- state . filter = state . mode . filter ? await readTestFilter ( ) : null ;
233+ } else if ( key . name === 'a' ) {
234+ // a => exit filter mode and run all tests
235+ state . mode . filter = false ;
236+ state . filter = null ;
237+ state . mode . action = RunnerAction . Test ;
238+ } else if ( key . name === 'd' ) {
239+ // d => toggle debug logging
240+ state . debug = ! state . debug ;
211241 state . mode . action = RunnerAction . Test ;
242+ } else if ( key . name === 'p' ) {
243+ // p => enter pattern input mode
244+ state . inputMode = 'pattern' ;
245+ state . inputBuffer = '' ;
246+ process . stdout . write ( 'Pattern: ' ) ;
247+ return ; // Don't trigger onChange yet
212248 } else {
213249 // any other key re-runs tests
214250 state . mode . action = RunnerAction . Test ;
@@ -219,21 +255,33 @@ function subscribeKeyEvents(
219255
220256export async function makeWatchRunner (
221257 onChange : ( state : RunnerState ) => void ,
222- filterMode : boolean ,
258+ debugMode : boolean ,
259+ initialPattern ?: string ,
223260) : Promise < void > {
224- const state = {
261+ // Determine initial filter state
262+ let filter : TestFilter | null = null ;
263+ let filterEnabled = false ;
264+
265+ if ( initialPattern ) {
266+ filter = { paths : [ initialPattern ] } ;
267+ filterEnabled = true ;
268+ }
269+
270+ const state : RunnerState = {
225271 compilerVersion : 0 ,
226272 isCompilerBuildValid : false ,
227273 lastUpdate : - 1 ,
228274 mode : {
229275 action : RunnerAction . Test ,
230- filter : filterMode ,
276+ filter : filterEnabled ,
231277 } ,
232- filter : filterMode ? await readTestFilter ( ) : null ,
278+ filter,
279+ debug : debugMode ,
280+ inputMode : 'none' ,
281+ inputBuffer : '' ,
233282 } ;
234283
235284 subscribeTsc ( state , onChange ) ;
236285 subscribeFixtures ( state , onChange ) ;
237286 subscribeKeyEvents ( state , onChange ) ;
238- subscribeFilterFile ( state , onChange ) ;
239287}
0 commit comments