@@ -27,6 +27,13 @@ public class Channel : IDisposable
2727 private Thread _serverThread ;
2828 private CodePostData _pendingPostCodeData ;
2929
30+ /// <summary>
31+ /// Indicates if a code-post message is being processed:
32+ /// - value is 1: yes;
33+ /// - value is 0: no.
34+ /// </summary>
35+ private int _processingCodePost ;
36+
3037 private Channel ( Runspace runspace , Type psConsoleReadLineType )
3138 {
3239 _runspace = runspace ;
@@ -183,64 +190,79 @@ private void OnPostCode(PostCodeMessage postCodeMessage)
183190 {
184191 // Ignore 'code post' request when a posting operation is on-going.
185192 // This most likely would happen when user run 'code post' mutliple times to post the same code, which is safe to ignore.
186- if ( _pendingPostCodeData is not null || postCodeMessage . CodeBlocks . Count is 0 )
193+ if ( Interlocked . CompareExchange ( ref _processingCodePost , 1 , 0 ) is 1 )
187194 {
188195 return ;
189196 }
190197
191- string codeToInsert ;
192- List < string > codeBlocks = postCodeMessage . CodeBlocks ;
193- List < PredictionCandidate > predictionCandidates = null ;
194-
195- if ( codeBlocks . Count is 1 )
196- {
197- codeToInsert = codeBlocks [ 0 ] ;
198- }
199- else if ( Predictor . TryProcessForPrediction ( codeBlocks , out predictionCandidates ) )
200- {
201- codeToInsert = predictionCandidates [ 0 ] . Code ;
202- }
203- else
198+ try
204199 {
205- // Use LF as line ending to be consistent with the response from LLM.
206- StringBuilder sb = new ( capacity : 50 ) ;
207- for ( int i = 0 ; i < codeBlocks . Count ; i ++ )
200+ // If '_pendingPostCodeData' is already set, then we are still in an on-going posting operation,
201+ // waiting the code to be posted on the 'OnIdle' event.
202+ if ( _pendingPostCodeData is not null || postCodeMessage . CodeBlocks . Count is 0 )
203+ {
204+ return ;
205+ }
206+
207+ string codeToInsert ;
208+ List < string > codeBlocks = postCodeMessage . CodeBlocks ;
209+ List < PredictionCandidate > predictionCandidates = null ;
210+
211+ if ( codeBlocks . Count is 1 )
212+ {
213+ codeToInsert = codeBlocks [ 0 ] ;
214+ }
215+ else if ( Predictor . TryProcessForPrediction ( codeBlocks , out predictionCandidates ) )
216+ {
217+ codeToInsert = predictionCandidates [ 0 ] . Code ;
218+ }
219+ else
208220 {
209- if ( i > 0 )
221+ // Use LF as line ending to be consistent with the response from LLM.
222+ StringBuilder sb = new ( capacity : 50 ) ;
223+ for ( int i = 0 ; i < codeBlocks . Count ; i ++ )
210224 {
211- sb . Append ( '\n ' ) ;
225+ if ( i > 0 )
226+ {
227+ sb . Append ( '\n ' ) ;
228+ }
229+
230+ sb . Append ( codeBlocks [ i ] ) . Append ( '\n ' ) ;
212231 }
213232
214- sb . Append ( codeBlocks [ i ] ) . Append ( ' \n ' ) ;
233+ codeToInsert = sb . ToString ( ) ;
215234 }
216235
217- codeToInsert = sb . ToString ( ) ;
218- }
219-
220- // When PSReadLine is actively running, 'TreatControlCAsInput' would be set to 'true' because
221- // it handles 'Ctrl+c' as regular input.
222- // When the value is 'false', it means PowerShell is still busy running scripts or commands.
223- if ( Console . TreatControlCAsInput )
224- {
225- PSRLRevertLine ( ) ;
226- PSRLInsert ( codeToInsert ) ;
227- _predictor . SetCandidates ( predictionCandidates ) ;
236+ // When PSReadLine is actively running, 'TreatControlCAsInput' would be set to 'true' because
237+ // it handles 'Ctrl+c' as regular input.
238+ // When the value is 'false', it means PowerShell is still busy running scripts or commands.
239+ if ( Console . TreatControlCAsInput )
240+ {
241+ PSRLRevertLine ( ) ;
242+ PSRLInsert ( codeToInsert ) ;
243+ _predictor . SetCandidates ( predictionCandidates ) ;
244+ }
245+ else
246+ {
247+ _pendingPostCodeData = new CodePostData ( codeToInsert , predictionCandidates ) ;
248+ // We use script block handler instead of a delegate handler because the latter will run
249+ // in a background thread, while the former will run in the pipeline thread, which is way
250+ // more predictable.
251+ _runspace . Events . SubscribeEvent (
252+ source : null ,
253+ eventName : null ,
254+ sourceIdentifier : PSEngineEvent . OnIdle ,
255+ data : null ,
256+ action : _onIdleAction ,
257+ supportEvent : true ,
258+ forwardEvent : false ,
259+ maxTriggerCount : 1 ) ;
260+ }
228261 }
229- else
262+ finally
230263 {
231- _pendingPostCodeData = new CodePostData ( codeToInsert , predictionCandidates ) ;
232- // We use script block handler instead of a delegate handler because the latter will run
233- // in a background thread, while the former will run in the pipeline thread, which is way
234- // more predictable.
235- _runspace . Events . SubscribeEvent (
236- source : null ,
237- eventName : null ,
238- sourceIdentifier : PSEngineEvent . OnIdle ,
239- data : null ,
240- action : _onIdleAction ,
241- supportEvent : true ,
242- forwardEvent : false ,
243- maxTriggerCount : 1 ) ;
264+ // Reset the state.
265+ _processingCodePost = 0 ;
244266 }
245267 }
246268
0 commit comments