33//! Handles Unix socket/named pipe communication with the VSCode extension.
44//! Ports the logic from server/src/ipc.ts to Rust with cross-platform support.
55
6+ use crate :: synthetic_pr:: { FeedbackType , UserFeedback } ;
67use crate :: types:: {
78 FindAllReferencesPayload , GetSelectionResult , GoodbyePayload , IPCMessage , IPCMessageType ,
8- LogLevel , LogParams , PoloPayload , PresentReviewParams , PresentReviewResult ,
9- ResolveSymbolByNamePayload , ResponsePayload , UserFeedbackPayload ,
9+ LogLevel , LogParams , PoloPayload , PresentReviewParams , ResolveSymbolByNamePayload ,
10+ ResponsePayload , UserFeedbackPayload ,
1011} ;
12+ use anyhow:: Context ;
1113use futures:: FutureExt ;
14+ use serde:: de:: DeserializeOwned ;
1215use serde_json;
1316use std:: collections:: HashMap ;
1417use std:: future:: Future ;
@@ -139,13 +142,10 @@ impl IPCCommunicator {
139142 Ok ( ( ) )
140143 }
141144
142- pub async fn present_review ( & self , params : PresentReviewParams ) -> Result < PresentReviewResult > {
145+ pub async fn present_review ( & self , params : PresentReviewParams ) -> Result < ( ) > {
143146 if self . test_mode {
144147 info ! ( "Present review called (test mode): {:?}" , params) ;
145- return Ok ( PresentReviewResult {
146- success : true ,
147- message : Some ( "Review successfully displayed (test mode)" . to_string ( ) ) ,
148- } ) ;
148+ return Ok ( ( ) ) ;
149149 }
150150
151151 // Ensure connection is established before proceeding
@@ -169,24 +169,15 @@ impl IPCCommunicator {
169169 debug ! ( "Sending present_review message: {:?}" , message) ;
170170 trace ! ( "About to call send_message_with_reply for present_review" ) ;
171171
172- let response = self . send_message_with_reply ( message) . await ?;
172+ let response: ( ) = self . send_message_with_reply ( message) . await ?;
173173
174174 trace ! (
175175 "Received response from send_message_with_reply: {:?}" ,
176176 response
177177 ) ;
178178
179179 // Convert response to PresentReviewResult
180- Ok ( PresentReviewResult {
181- success : response. success ,
182- message : response. error . or_else ( || {
183- if response. success {
184- Some ( "Review successfully displayed" . to_string ( ) )
185- } else {
186- Some ( "Unknown error" . to_string ( ) )
187- }
188- } ) ,
189- } )
180+ Ok ( ( ) )
190181 }
191182
192183 pub async fn get_selection ( & self ) -> Result < GetSelectionResult > {
@@ -224,25 +215,8 @@ impl IPCCommunicator {
224215
225216 debug ! ( "Sending get_selection message: {:?}" , message) ;
226217
227- let response = self . send_message_with_reply ( message) . await ?;
228-
229- if let Some ( data) = response. data {
230- let selection: GetSelectionResult = serde_json:: from_value ( data) ?;
231- Ok ( selection)
232- } else {
233- Ok ( GetSelectionResult {
234- selected_text : None ,
235- file_path : None ,
236- start_line : None ,
237- start_column : None ,
238- end_line : None ,
239- end_column : None ,
240- line_number : None ,
241- document_language : None ,
242- is_untitled : None ,
243- message : Some ( "No selection data in response" . to_string ( ) ) ,
244- } )
245- }
218+ let selection: GetSelectionResult = self . send_message_with_reply ( message) . await ?;
219+ Ok ( selection)
246220 }
247221
248222 pub async fn send_log ( & self , level : LogLevel , message : String ) {
@@ -364,10 +338,19 @@ impl IPCCommunicator {
364338 pub async fn send_create_synthetic_pr (
365339 & self ,
366340 review_response : & crate :: synthetic_pr:: ReviewData ,
367- ) -> Result < ( ) > {
341+ ) -> Result < UserFeedback > {
368342 if self . test_mode {
369343 info ! ( "Synthetic PR creation message sent (test mode)" ) ;
370- return Ok ( ( ) ) ;
344+ return Ok ( UserFeedback {
345+ review_id : None ,
346+ feedback_type : FeedbackType :: CompleteReview ,
347+ file_path : None ,
348+ line_number : None ,
349+ comment_text : None ,
350+ completion_action : None ,
351+ additional_notes : None ,
352+ context_lines : None ,
353+ } ) ;
371354 }
372355
373356 let shell_pid = {
@@ -396,7 +379,7 @@ impl IPCCommunicator {
396379 "Sending create_synthetic_pr message for review: {}" ,
397380 review_response. review_id
398381 ) ;
399- self . send_message_without_reply ( message) . await
382+ self . send_message_with_reply ( message) . await
400383 }
401384
402385 /// Wait for user feedback on a specific review
@@ -461,7 +444,10 @@ impl IPCCommunicator {
461444
462445 /// Send review update to VSCode extension and wait for user response
463446 /// This method blocks until the user provides feedback via the VSCode extension
464- pub async fn send_review_update < T : serde:: Serialize > ( & self , review : & T ) -> Result < crate :: synthetic_pr:: UserFeedback > {
447+ pub async fn send_review_update < T : serde:: Serialize > (
448+ & self ,
449+ review : & T ,
450+ ) -> Result < crate :: synthetic_pr:: UserFeedback > {
465451 if self . test_mode {
466452 info ! ( "Send review update called (test mode)" ) ;
467453 return Ok ( crate :: synthetic_pr:: UserFeedback {
@@ -492,19 +478,9 @@ impl IPCCommunicator {
492478 } ;
493479
494480 // Send message and wait for response
495- let response = self . send_message_with_reply ( message) . await ?;
481+ let response: UserFeedback = self . send_message_with_reply ( message) . await ?;
496482
497- // Parse UserFeedback from response data
498- if let Some ( data) = response. data {
499- let user_feedback: crate :: synthetic_pr:: UserFeedback = serde_json:: from_value ( data)
500- . map_err ( IPCError :: SerializationError ) ?;
501- Ok ( user_feedback)
502- } else {
503- Err ( IPCError :: ConnectionFailed {
504- path : "user_feedback" . to_string ( ) ,
505- source : std:: io:: Error :: new ( std:: io:: ErrorKind :: InvalidData , "No user feedback data in response" )
506- } )
507- }
483+ Ok ( response)
508484 }
509485
510486 /// Gracefully shutdown the IPC communicator, sending Goodbye discovery message
@@ -529,7 +505,10 @@ impl IPCCommunicator {
529505 /// Sets up response correlation using the message UUID and waits up to 5 seconds
530506 /// for the background reader task to deliver the matching response.
531507 /// Uses the underlying `write_message` primitive to send the data.
532- async fn send_message_with_reply ( & self , message : IPCMessage ) -> Result < ResponsePayload > {
508+ async fn send_message_with_reply < R > ( & self , message : IPCMessage ) -> Result < R >
509+ where
510+ R : DeserializeOwned ,
511+ {
533512 debug ! (
534513 "Sending IPC message with ID: {} (PID: {})" ,
535514 message. id,
@@ -572,7 +551,20 @@ impl IPCCommunicator {
572551 } ) ?
573552 . map_err ( |_| IPCError :: ChannelClosed ) ?;
574553
575- Ok ( response)
554+ // Parse UserFeedback from response data
555+ if let Some ( data) = response. data {
556+ let user_feedback: R =
557+ serde_json:: from_value ( data) . map_err ( IPCError :: SerializationError ) ?;
558+ Ok ( user_feedback)
559+ } else {
560+ Err ( IPCError :: ConnectionFailed {
561+ path : format ! ( "{:?}" , message. message_type) ,
562+ source : std:: io:: Error :: new (
563+ std:: io:: ErrorKind :: InvalidData ,
564+ "No response data in response" ,
565+ ) ,
566+ } )
567+ }
576568 }
577569
578570 /// Sends an IPC message without waiting for a response (fire-and-forget)
@@ -962,23 +954,10 @@ impl crate::ide::IpcClient for IPCCommunicator {
962954 id : Uuid :: new_v4 ( ) . to_string ( ) ,
963955 } ;
964956
965- let response = self . send_message_with_reply ( message) . await ?;
966-
967- if !response. success {
968- return Err ( anyhow:: anyhow!(
969- "VSCode extension failed to resolve symbol '{}': {}" ,
970- name,
971- response
972- . error
973- . unwrap_or_else( || "Unknown error" . to_string( ) )
974- ) ) ;
975- }
976-
977- // Parse the response data as Vec<ResolvedSymbol>
978- let symbols: Vec < crate :: ide:: SymbolDef > = match response. data {
979- Some ( data) => serde_json:: from_value ( data) ?,
980- None => vec ! [ ] ,
981- } ;
957+ let symbols: Vec < crate :: ide:: SymbolDef > = self
958+ . send_message_with_reply ( message)
959+ . await
960+ . with_context ( || format ! ( "failed to resolve symbol '{name}'" ) ) ?;
982961
983962 Ok ( symbols)
984963 }
@@ -1008,23 +987,15 @@ impl crate::ide::IpcClient for IPCCommunicator {
1008987 id : Uuid :: new_v4 ( ) . to_string ( ) ,
1009988 } ;
1010989
1011- let response = self . send_message_with_reply ( message) . await ?;
1012-
1013- if !response. success {
1014- return Err ( anyhow:: anyhow!(
1015- "VSCode extension failed to find references for symbol '{}': {}" ,
1016- symbol. name,
1017- response
1018- . error
1019- . unwrap_or_else( || "Unknown error" . to_string( ) )
1020- ) ) ;
1021- }
1022-
1023- // Parse the response data as Vec<FileLocation>
1024- let locations: Vec < crate :: ide:: FileRange > = match response. data {
1025- Some ( data) => serde_json:: from_value ( data) ?,
1026- None => vec ! [ ] ,
1027- } ;
990+ let locations: Vec < crate :: ide:: FileRange > = self
991+ . send_message_with_reply ( message)
992+ . await
993+ . with_context ( || {
994+ format ! (
995+ "VSCode extension failed to find references for symbol '{}'" ,
996+ symbol. name
997+ )
998+ } ) ?;
1028999
10291000 Ok ( locations)
10301001 }
@@ -1059,10 +1030,7 @@ mod test {
10591030 let result = ipc. present_review ( params) . await ;
10601031 assert ! ( result. is_ok( ) ) ;
10611032
1062- let review_result = result. unwrap ( ) ;
1063- assert ! ( review_result. success) ;
1064- assert ! ( review_result. message. is_some( ) ) ;
1065- assert ! ( review_result. message. unwrap( ) . contains( "test mode" ) ) ;
1033+ result. unwrap ( ) ;
10661034 }
10671035
10681036 #[ tokio:: test]
@@ -1097,8 +1065,7 @@ mod test {
10971065 let result = ipc. present_review ( params) . await ;
10981066 assert ! ( result. is_ok( ) ) ;
10991067
1100- let review_result = result. unwrap ( ) ;
1101- assert ! ( review_result. success) ;
1068+ result. unwrap ( ) ;
11021069 }
11031070
11041071 #[ tokio:: test]
0 commit comments