15
15
use actions:: { notifications, requests, ActionContext } ;
16
16
use analysis:: AnalysisHost ;
17
17
use config:: Config ;
18
- use jsonrpc_core:: { self as jsonrpc, Id } ;
18
+ use jsonrpc_core:: { self as jsonrpc, Id , types :: error :: ErrorCode } ;
19
19
pub use ls_types:: notification:: Exit as ExitNotification ;
20
20
pub use ls_types:: request:: Initialize as InitializeRequest ;
21
21
pub use ls_types:: request:: Shutdown as ShutdownRequest ;
@@ -27,13 +27,13 @@ use lsp_data;
27
27
use lsp_data:: { InitializationOptions , LSPNotification , LSPRequest } ;
28
28
use serde_json;
29
29
use server:: dispatch:: Dispatcher ;
30
- pub use server:: dispatch:: { RequestAction , ResponseError , DEFAULT_REQUEST_TIMEOUT } ;
30
+ pub use server:: dispatch:: { RequestAction , DEFAULT_REQUEST_TIMEOUT } ;
31
31
pub use server:: io:: { MessageReader , Output } ;
32
32
use server:: io:: { StdioMsgReader , StdioOutput } ;
33
33
use server:: message:: RawMessage ;
34
34
pub use server:: message:: {
35
35
Ack , BlockingNotificationAction , BlockingRequestAction , NoResponse , Notification , Request ,
36
- Response ,
36
+ Response , ResponseError
37
37
} ;
38
38
use std:: path:: PathBuf ;
39
39
use std:: sync:: atomic:: Ordering ;
@@ -45,6 +45,8 @@ mod dispatch;
45
45
mod io;
46
46
mod message;
47
47
48
+ const NOT_INITIALIZED_CODE : ErrorCode = ErrorCode :: ServerError ( -32002 ) ;
49
+
48
50
/// Run the Rust Language Server.
49
51
pub fn run_server ( analysis : Arc < AnalysisHost > , vfs : Arc < Vfs > ) {
50
52
debug ! ( "Language Server starting up. Version: {}" , version( ) ) ;
@@ -63,18 +65,21 @@ impl BlockingRequestAction for ShutdownRequest {
63
65
type Response = Ack ;
64
66
65
67
fn handle < O : Output > (
66
- _id : usize ,
67
68
_params : Self :: Params ,
68
69
ctx : & mut ActionContext ,
69
70
_out : O ,
70
- ) -> Result < Self :: Response , ( ) > {
71
- // Currently we don't perform an explicit cleanup, other than storing state
72
- ctx. inited ( )
73
- . expect ( "initialized context: todo -32002 response" )
74
- . shut_down
75
- . store ( true , Ordering :: SeqCst ) ;
76
-
77
- Ok ( Ack )
71
+ ) -> Result < Self :: Response , ResponseError > {
72
+ if let Ok ( ctx) = ctx. inited ( ) {
73
+ // Currently we don't perform an explicit cleanup, other than storing state
74
+ ctx. shut_down . store ( true , Ordering :: SeqCst ) ;
75
+ Ok ( Ack )
76
+ }
77
+ else {
78
+ Err ( ResponseError :: Message (
79
+ NOT_INITIALIZED_CODE ,
80
+ "not yet received `initialize` request" . to_owned ( ) ,
81
+ ) )
82
+ }
78
83
}
79
84
}
80
85
@@ -87,14 +92,13 @@ fn handle_exit_notification(ctx: &mut ActionContext) -> ! {
87
92
}
88
93
89
94
impl BlockingRequestAction for InitializeRequest {
90
- type Response = NoResponse ;
95
+ type Response = InitializeResult ;
91
96
92
97
fn handle < O : Output > (
93
- id : usize ,
94
98
params : Self :: Params ,
95
99
ctx : & mut ActionContext ,
96
100
out : O ,
97
- ) -> Result < NoResponse , ( ) > {
101
+ ) -> Result < InitializeResult , ResponseError > {
98
102
let init_options: InitializationOptions = params
99
103
. initialization_options
100
104
. as_ref ( )
@@ -106,13 +110,16 @@ impl BlockingRequestAction for InitializeRequest {
106
110
let result = InitializeResult {
107
111
capabilities : server_caps ( ) ,
108
112
} ;
109
- out. success ( id, & result) ;
110
113
111
114
let capabilities = lsp_data:: ClientCapabilities :: new ( & params) ;
112
- ctx. init ( get_root_path ( & params) , & init_options, capabilities, & out)
113
- . expect ( "context already initialized" ) ;
114
-
115
- Ok ( NoResponse )
115
+ match ctx. init ( get_root_path ( & params) , & init_options, capabilities, & out) {
116
+ Ok ( _) => Ok ( result) ,
117
+ Err ( _) => Err ( ResponseError :: Message (
118
+ // No code in the spec, just use some number
119
+ ErrorCode :: ServerError ( 123 ) ,
120
+ "Already received an initialize request" . to_owned ( ) ,
121
+ ) ) ,
122
+ }
116
123
}
117
124
}
118
125
@@ -169,7 +176,7 @@ impl<O: Output> LsService<O> {
169
176
}
170
177
else {
171
178
warn!(
172
- "Server has not yet received an `initialize` request, ignoring {}" , <$n_action as LSPNotification > :: METHOD ,
179
+ "Server has not yet received an `initialize` request, ignoring {}" , $method ,
173
180
) ;
174
181
}
175
182
}
@@ -182,20 +189,41 @@ impl<O: Output> LsService<O> {
182
189
// block until all nonblocking requests have been handled ensuring ordering
183
190
self . dispatcher. await_all_dispatched( ) ;
184
191
185
- if request. blocking_dispatch( & mut self . ctx, & self . output) . is_err( ) {
186
- debug!( "Error handling request: {:?}" , msg) ;
192
+ let req_id = request. id;
193
+ match request. blocking_dispatch( & mut self . ctx, & self . output) {
194
+ Ok ( res) => res. send( req_id, & self . output) ,
195
+ Err ( ResponseError :: Empty ) => {
196
+ debug!( "error handling {}" , $method) ;
197
+ self . output. failure_message(
198
+ req_id,
199
+ ErrorCode :: InternalError ,
200
+ "An unknown error occurred"
201
+ )
202
+ }
203
+ Err ( ResponseError :: Message ( code, msg) ) => {
204
+ debug!( "error handling {}: {}" , $method, msg) ;
205
+ self . output. failure_message( req_id, code, msg)
206
+ }
187
207
}
188
208
}
189
209
) *
190
210
191
211
$(
192
212
<$request as LSPRequest >:: METHOD => {
193
213
let request: Request <$request> = msg. parse_as_request( ) ?;
194
- let request = (
195
- request,
196
- self . ctx. inited( ) . expect( "initialized context: todo -32002 response" ) ,
197
- ) ;
198
- self . dispatcher. dispatch( request) ;
214
+ if let Ok ( ctx) = self . ctx. inited( ) {
215
+ self . dispatcher. dispatch( ( request, ctx) ) ;
216
+ }
217
+ else {
218
+ warn!(
219
+ "Server has not yet received an `initialize` request, cannot handle {}" , $method,
220
+ ) ;
221
+ self . output. failure_message(
222
+ request. id,
223
+ NOT_INITIALIZED_CODE ,
224
+ "not yet received `initialize` request" . to_owned( ) ,
225
+ ) ;
226
+ }
199
227
}
200
228
) *
201
229
// exit notification can uniquely handle pre `initialize` request state
0 commit comments