@@ -6,21 +6,50 @@ import * as v from "valibot";
66
77import { ProblemSchema } from "~shared/schemas" ;
88import type JudgeViewProvider from "~extension/providers/JudgeViewProvider" ;
9- import { AsyncQueue } from "./asyncQueue" ;
109
1110type Problem = v . InferOutput < typeof ProblemSchema > ;
1211
12+ /**
13+ * Queue that processes problems sequentially as they arrive from Competitive Companion.
14+ * Gathers workspace files once before processing a batch of problems.
15+ */
16+ class ProblemQueue {
17+ private queue : Problem [ ] = [ ] ;
18+ private processing = false ;
19+
20+ constructor ( private processor : ( problem : Problem , files : vscode . Uri [ ] ) => Promise < void > ) { }
21+
22+ enqueue ( problem : Problem ) : void {
23+ this . queue . push ( problem ) ;
24+ void this . processNext ( ) ;
25+ }
26+
27+ private async processNext ( ) : Promise < void > {
28+ if ( this . processing || this . queue . length === 0 ) return ;
29+
30+ this . processing = true ;
31+ const files = await gatherWorkspaceFiles ( ) ;
32+ while ( this . queue . length > 0 ) {
33+ const problem = this . queue . shift ( ) ! ;
34+ await this . processor ( problem , files ) ;
35+ }
36+ this . processing = false ;
37+ }
38+ }
39+
1340// Module state
1441let server : http . Server | undefined ;
1542let statusBarItem : vscode . StatusBarItem | undefined ;
1643
1744/**
18- * Shows a QuickPick to let the user select a target file for testcases.
45+ * Shows a QuickPick to let the user select a target file for testcases,
46+ * with the files provided.
1947 */
2048async function promptForTargetFile (
2149 problem : Problem ,
2250 workspaceRoot : string ,
23- defaultValue : string
51+ defaultValue : string ,
52+ files : vscode . Uri [ ]
2453) : Promise < string > {
2554 const config = vscode . workspace . getConfiguration ( "fastolympiccoding" ) ;
2655 const includePattern = config . get < string > ( "includePattern" ) ! ;
@@ -32,10 +61,15 @@ async function promptForTargetFile(
3261 description : path . parse ( path . relative ( workspaceRoot , file . fsPath ) ) . dir ,
3362 } ) ) ;
3463
64+ const options = files . map ( ( file ) => ( {
65+ label : path . parse ( file . fsPath ) . base ,
66+ description : path . parse ( path . relative ( workspaceRoot , file . fsPath ) ) . dir ,
67+ } ) ) ;
68+
3569 const pick = vscode . window . createQuickPick ( ) ;
3670 pick . title = `Testcases for "${ problem . name } "` ;
3771 pick . placeholder = "Full file path to put testcases onto" ;
38- pick . value = defaultValue ;
72+ pick . items = options ;
3973 pick . ignoreFocusOut = true ;
4074 pick . items = items ;
4175 pick . show ( ) ;
@@ -53,7 +87,11 @@ async function promptForTargetFile(
5387/**
5488 * Processes a single problem received from Competitive Companion.
5589 */
56- async function processProblem ( problem : Problem , judge : JudgeViewProvider ) : Promise < void > {
90+ async function processProblem (
91+ problem : Problem ,
92+ judge : JudgeViewProvider ,
93+ files : vscode . Uri [ ]
94+ ) : Promise < void > {
5795 const activeFile = vscode . window . activeTextEditor ?. document . fileName ;
5896 const workspaceRoot = vscode . workspace . workspaceFolders ?. at ( 0 ) ?. uri . fsPath ?? "" ;
5997 const config = vscode . workspace . getConfiguration ( "fastolympiccoding" ) ;
@@ -66,7 +104,7 @@ async function processProblem(problem: Problem, judge: JudgeViewProvider): Promi
66104 let relativePath = isSingleProblem && activeFile ? path . relative ( workspaceRoot , activeFile ) : "" ;
67105
68106 if ( needsPrompt ) {
69- relativePath = await promptForTargetFile ( problem , workspaceRoot , relativePath ) ;
107+ relativePath = await promptForTargetFile ( problem , workspaceRoot , relativePath , files ) ;
70108 }
71109
72110 if ( relativePath === "" ) {
@@ -85,11 +123,21 @@ async function processProblem(problem: Problem, judge: JudgeViewProvider): Promi
85123 }
86124}
87125
126+ /**
127+ * Gather files using VSCode's API with include and exclude patterns from settings.
128+ */
129+ async function gatherWorkspaceFiles ( ) : Promise < vscode . Uri [ ] > {
130+ const config = vscode . workspace . getConfiguration ( "fastolympiccoding" ) ;
131+ const includePattern = config . get < string > ( "includePattern" ) ! ;
132+ const excludePattern = config . get < string > ( "excludePattern" ) ! ;
133+ return vscode . workspace . findFiles ( includePattern , excludePattern ) ;
134+ }
135+
88136/**
89137 * Creates the request handler for the Competitive Companion HTTP server.
90138 */
91139function createRequestHandler ( judge : JudgeViewProvider ) : http . RequestListener {
92- const problemQueue = new AsyncQueue < Problem > ( ( problem ) => processProblem ( problem , judge ) ) ;
140+ const problemQueue = new ProblemQueue ( ( problem , files ) => processProblem ( problem , judge , files ) ) ;
93141
94142 return ( req , res ) => {
95143 if ( req . method !== "POST" ) {
0 commit comments