1- import  {  MessageSignature ,   MessageConnection   }  from  '@codingame/monaco -jsonrpc' 
1+ import  {  MessageReader ,   MessageWriter ,   Message ,   Event ,   DataCallback ,   Disposable ,   PartialMessageInfo   }  from  'vscode -jsonrpc' 
22import  {  Uri  }  from  'monaco-editor' 
33import  { 
4-   MonacoLanguageClient , 
5-   createConnection ,  ConnectionErrorHandler ,  ConnectionCloseHandler ,  IConnection ,  Middleware ,  ErrorHandler ,  IConnectionProvider ,  InitializeParams ,  RegistrationRequest ,  RegistrationParams ,  UnregistrationRequest ,  UnregistrationParams ,  LanguageClientOptions 
4+   MonacoLanguageClient ,  Middleware ,  ErrorHandler ,  IConnectionProvider ,  InitializeParams ,  RegistrationRequest ,  RegistrationParams ,  UnregistrationRequest ,  UnregistrationParams ,  LanguageClientOptions ,  MessageTransports ,  InitializeRequest 
65}  from  'monaco-languageclient' 
7- import  once  from  'once' 
86import  {  registerExtensionFeatures  }  from  './extensions' 
97import  {  LanguageClientId  }  from  './languageClientOptions' 
108import  {  Infrastructure  }  from  './infrastructure' 
119
12- async  function  messageConnectionToConnection  ( messageConnection : MessageConnection ,  errorHandler : ConnectionErrorHandler ,  closeHandler : ( )  =>  void ) : Promise < IConnection >  { 
13-   const  connection  =  createConnection ( messageConnection ,  errorHandler ,  closeHandler ) 
10+ interface  MessageMiddleware  { 
11+   ( message : Message ) : Message 
12+ } 
13+ 
14+ class  MiddlewareMessageWriter  implements  MessageWriter  { 
15+   constructor  ( private  delegate : MessageWriter ,  private  middleware : MessageMiddleware )  { } 
16+ 
17+   onError : Event < [ Error ,  Message  |  undefined ,  number  |  undefined ] >  =  ( cb )  =>  { 
18+     return  this . delegate . onError ( cb ) 
19+   } 
20+ 
21+   onClose : Event < void >  =  ( cb )  =>  { 
22+     return  this . delegate . onClose ( cb ) 
23+   } 
24+ 
25+   dispose  ( ) : void   { 
26+     this . delegate . dispose ( ) 
27+   } 
28+ 
29+   write  ( msg : Message ) : Promise < void >  { 
30+     return  this . delegate . write ( this . middleware ( msg ) ) 
31+   } 
32+ 
33+   end  ( ) : void   { 
34+     return  this . delegate . end ( ) 
35+   } 
36+ } 
37+ class  MiddlewareMessageReader  implements  MessageReader  { 
38+   constructor  ( private  delegate : MessageReader ,  private  middleware : MessageMiddleware )  { } 
39+ 
40+   onError : Event < Error >  =  ( cb )  =>  { 
41+     return  this . delegate . onError ( cb ) 
42+   } 
43+ 
44+   onClose : Event < void >  =  ( cb )  =>  { 
45+     return  this . delegate . onClose ( cb ) 
46+   } 
47+ 
48+   onPartialMessage : Event < PartialMessageInfo >  =  ( cb )  =>  { 
49+     return  this . delegate . onPartialMessage ( cb ) 
50+   } 
1451
52+   listen  ( callback : DataCallback ) : Disposable  { 
53+     return  this . delegate . listen ( message  =>  { 
54+       callback ( this . middleware ( message ) ) 
55+     } ) 
56+   } 
57+ 
58+   dispose  ( ) : void   { 
59+     this . delegate . dispose ( ) 
60+   } 
61+ } 
62+ 
63+ /** 
64+  * Add some hacks on transform for: 
65+  * - Dedup server capability registrations (for omnisharp roslyn) 
66+  * - Fix paths on windows 
67+  * @param  transports The original transports 
68+  * @returns  The transformed transports 
69+  */ 
70+ function  hackTransports  ( transports : MessageTransports ) : MessageTransports  { 
1571  const  existingRegistrations  =  new  Set < string > ( ) 
16-   const  fixedConnection : IConnection  =  { 
17-     ...connection , 
18-     initialize : ( params : InitializeParams )  =>  { 
19-       // Hack to fix url converted from /toto/tata to \\toto\tata in windows 
20-       const  rootPath  =  params . rootPath ?. replace ( / \\ / g,  '/' ) 
21-       const  fixedParams : InitializeParams  =  { 
22-         ...params , 
23-         rootPath, 
24-         rootUri : rootPath  !=  null  ? Uri . from ( {  scheme : 'file' ,  path : rootPath  } ) . toString ( )  : null 
25-       } 
26-       return  connection . initialize ( fixedParams ) 
27-     } , 
28-     onRequest  ( ...args : Parameters < typeof  connection . onRequest > )  { 
29-       return  connection . onRequest ( args [ 0 ] ,  ( ...params )  =>  { 
30-         // Hack for https://github.com/OmniSharp/omnisharp-roslyn/issues/2119 
31-         const  method  =  ( args [ 0 ]  as  MessageSignature ) . method 
32-         if  ( method  ===  RegistrationRequest . type . method )  { 
33-           const  registrationParams  =  params [ 0 ]  as  unknown  as  RegistrationParams 
34-           registrationParams . registrations  =  registrationParams . registrations . filter ( registration  =>  { 
72+   return  { 
73+     reader : new  MiddlewareMessageReader ( transports . reader ,  message  =>  { 
74+       if  ( Message . isRequest ( message ) )  { 
75+         if  ( message . method  ===  RegistrationRequest . type . method )  { 
76+           const  registrationParams  =  message . params  as  RegistrationParams 
77+           const  filteredRegistrations  =  registrationParams . registrations . filter ( registration  =>  { 
3578            const  alreadyExisting  =  existingRegistrations . has ( registration . id ) 
3679            if  ( alreadyExisting )  { 
3780              console . warn ( 'Registration already existing' ,  registration . id ,  registration . method ) 
@@ -41,64 +84,53 @@ async function messageConnectionToConnection (messageConnection: MessageConnecti
4184          registrationParams . registrations . forEach ( registration  =>  { 
4285            existingRegistrations . add ( registration . id ) 
4386          } ) 
87+           const  fixedParams : RegistrationParams  =  { 
88+             ...registrationParams , 
89+             registrations : filteredRegistrations 
90+           } 
91+           return  { 
92+             ...message , 
93+             params : fixedParams 
94+           } 
4495        } 
45-         if  ( method  ===  UnregistrationRequest . type . method )  { 
46-           const  unregistrationParams  =  params [ 0 ]   as   unknown  as  UnregistrationParams 
96+         if  ( message . method  ===  UnregistrationRequest . type . method )  { 
97+           const  unregistrationParams  =  message . params  as  UnregistrationParams 
4798          for  ( const  unregistration  of  unregistrationParams . unregisterations )  { 
4899            existingRegistrations . delete ( unregistration . id ) 
49100          } 
50101        } 
51-         return  args [ 1 ] ( ...params ) 
52-       } ) 
53-     } , 
54-     dispose : ( )  =>  { 
55-       try  { 
56-         connection . dispose ( ) 
57-       }  catch  ( error )  { 
58-         // The dispose should NEVER fail or the lsp client is not properly cleaned 
59-         // see https://github.com/microsoft/vscode-languageserver-node/blob/master/client/src/client.ts#L3105 
60-         console . warn ( '[LSP]' ,  'Error while disposing connection' ,  error ) 
61102      } 
62-       // Hack, when the language client is removed, the connection is disposed but the closeHandler is not always properly called 
63-       // The language client is then still active but without a proper connection and errors will occurs 
64-       closeHandler ( ) 
65-     } , 
66-     shutdown : async  ( )  =>  { 
67-       // The shutdown should NEVER fail or the connection is not closed and the lsp client is not properly cleaned 
68-       // see https://github.com/microsoft/vscode-languageserver-node/blob/master/client/src/client.ts#L3103 
69-       try  { 
70-         await  connection . shutdown ( ) 
71-       }  catch  ( error )  { 
72-         console . warn ( '[LSP]' ,  'Error while shutdown lsp' ,  error ) 
103+       return  message 
104+     } ) , 
105+     writer : new  MiddlewareMessageWriter ( transports . writer ,  message  =>  { 
106+       if  ( Message . isRequest ( message )  &&  message . method  ===  InitializeRequest . type . method )  { 
107+         const  params  =  message . params  as  InitializeParams 
108+         // Hack to fix url converted from /toto/tata to \\toto\tata in windows 
109+         const  rootPath  =  params . rootPath ?. replace ( / \\ / g,  '/' ) 
110+         const  fixedParams : InitializeParams  =  { 
111+           ...params , 
112+           rootPath, 
113+           rootUri : rootPath  !=  null  ? Uri . from ( {  scheme : 'file' ,  path : rootPath  } ) . toString ( )  : null 
114+         } 
115+         return  { 
116+           ...message , 
117+           params : fixedParams 
118+         } 
73119      } 
74-     } 
120+       return  message 
121+     } ) 
75122  } 
76- 
77-   return  fixedConnection 
78123} 
79124
80- const  RETRY_DELAY  =  3000 
81125class  CGLSPConnectionProvider  implements  IConnectionProvider  { 
82126  constructor  ( 
83127    private  id : LanguageClientId , 
84128    private  infrastructure : Infrastructure 
85129  )  { 
86130  } 
87131
88-   async  get  ( errorHandler : ConnectionErrorHandler ,  closeHandler : ConnectionCloseHandler )  { 
89-     const  onceDelayedCloseHandler  =  once ( ( )  =>  { 
90-       setTimeout ( ( )  =>  { 
91-         closeHandler ( ) 
92-       } ,  RETRY_DELAY ) 
93-     } ) 
94-     try  { 
95-       const  connection  =  await  this . infrastructure . openConnection ( this . id ) 
96- 
97-       return  await  messageConnectionToConnection ( connection ,  errorHandler ,  onceDelayedCloseHandler ) 
98-     }  catch  ( err )  { 
99-       onceDelayedCloseHandler ( ) 
100-       throw  err 
101-     } 
132+   async  get  ( )  { 
133+     return  hackTransports ( await  this . infrastructure . openConnection ( this . id ) ) 
102134  } 
103135} 
104136
0 commit comments