@@ -27,8 +27,13 @@ use noirc_frontend::hir::FunctionNameMatch;
27
27
use serde_json:: Value as JsonValue ;
28
28
use tower:: Service ;
29
29
30
+ const ARROW : & str = "▶\u{fe0e} " ;
30
31
const TEST_COMMAND : & str = "nargo.test" ;
31
- const TEST_CODELENS_TITLE : & str = "▶\u{fe0e} Run Test" ;
32
+ const TEST_CODELENS_TITLE : & str = "Run Test" ;
33
+ const COMPILE_COMMAND : & str = "nargo.compile" ;
34
+ const COMPILE_CODELENS_TITLE : & str = "Compile" ;
35
+ const EXECUTE_COMMAND : & str = "nargo.execute" ;
36
+ const EXECUTE_CODELENS_TITLE : & str = "Execute" ;
32
37
33
38
// State for the LSP gets implemented on this struct and is internal to the implementation
34
39
pub struct LspState {
@@ -185,7 +190,7 @@ fn on_code_lens_request(
185
190
186
191
for package in & workspace {
187
192
let ( mut context, crate_id) = prepare_package ( package) ;
188
- // We ignore the warnings and errors produced by compilation for producing codelenses
193
+ // We ignore the warnings and errors produced by compilation for producing code lenses
189
194
// because we can still get the test functions even if compilation fails
190
195
let _ = check_crate ( & mut context, crate_id, false ) ;
191
196
@@ -209,8 +214,8 @@ fn on_code_lens_request(
209
214
let range = byte_span_to_range ( files, file_id. as_usize ( ) , location. span . into ( ) )
210
215
. unwrap_or_default ( ) ;
211
216
212
- let command = Command {
213
- title : TEST_CODELENS_TITLE . into ( ) ,
217
+ let test_command = Command {
218
+ title : format ! ( "{ARROW} {TEST_CODELENS_TITLE}" ) ,
214
219
command : TEST_COMMAND . into ( ) ,
215
220
arguments : Some ( vec ! [
216
221
"--program-dir" . into( ) ,
@@ -222,9 +227,158 @@ fn on_code_lens_request(
222
227
] ) ,
223
228
} ;
224
229
225
- let lens = CodeLens { range, command : command . into ( ) , data : None } ;
230
+ let test_lens = CodeLens { range, command : Some ( test_command ) , data : None } ;
226
231
227
- lenses. push ( lens) ;
232
+ lenses. push ( test_lens) ;
233
+ }
234
+
235
+ if package. is_binary ( ) {
236
+ if let Some ( main_func_id) = context. get_main_function ( & crate_id) {
237
+ let location = context. function_meta ( & main_func_id) . name . location ;
238
+ let file_id = location. file ;
239
+
240
+ // Ignore diagnostics for any file that wasn't the file we saved
241
+ // TODO: In the future, we could create "related" diagnostics for these files
242
+ // TODO: This currently just appends the `.nr` file extension that we store as a constant,
243
+ // but that won't work if we accept other extensions
244
+ if fm. path ( file_id) . with_extension ( FILE_EXTENSION ) != file_path {
245
+ continue ;
246
+ }
247
+
248
+ let range = byte_span_to_range ( files, file_id. as_usize ( ) , location. span . into ( ) )
249
+ . unwrap_or_default ( ) ;
250
+
251
+ let compile_command = Command {
252
+ title : format ! ( "{ARROW} {COMPILE_CODELENS_TITLE}" ) ,
253
+ command : COMPILE_COMMAND . into ( ) ,
254
+ arguments : Some ( vec ! [
255
+ "--program-dir" . into( ) ,
256
+ format!( "{}" , workspace. root_dir. display( ) ) . into( ) ,
257
+ "--package" . into( ) ,
258
+ format!( "{}" , package. name) . into( ) ,
259
+ ] ) ,
260
+ } ;
261
+
262
+ let compile_lens = CodeLens { range, command : Some ( compile_command) , data : None } ;
263
+
264
+ lenses. push ( compile_lens) ;
265
+
266
+ let execute_command = Command {
267
+ title : EXECUTE_CODELENS_TITLE . to_string ( ) ,
268
+ command : EXECUTE_COMMAND . into ( ) ,
269
+ arguments : Some ( vec ! [
270
+ "--program-dir" . into( ) ,
271
+ format!( "{}" , workspace. root_dir. display( ) ) . into( ) ,
272
+ "--package" . into( ) ,
273
+ format!( "{}" , package. name) . into( ) ,
274
+ ] ) ,
275
+ } ;
276
+
277
+ let execute_lens = CodeLens { range, command : Some ( execute_command) , data : None } ;
278
+
279
+ lenses. push ( execute_lens) ;
280
+ }
281
+ }
282
+
283
+ if package. is_contract ( ) {
284
+ // Currently not looking to deduplicate this since we don't have a clear decision on if the Contract stuff is staying
285
+ for contract in context. get_all_contracts ( & crate_id) {
286
+ let location = contract. location ;
287
+ let file_id = location. file ;
288
+
289
+ // Ignore diagnostics for any file that wasn't the file we saved
290
+ // TODO: In the future, we could create "related" diagnostics for these files
291
+ // TODO: This currently just appends the `.nr` file extension that we store as a constant,
292
+ // but that won't work if we accept other extensions
293
+ if fm. path ( file_id) . with_extension ( FILE_EXTENSION ) != file_path {
294
+ continue ;
295
+ }
296
+
297
+ let range = byte_span_to_range ( files, file_id. as_usize ( ) , location. span . into ( ) )
298
+ . unwrap_or_default ( ) ;
299
+
300
+ let compile_command = Command {
301
+ title : format ! ( "{ARROW} {COMPILE_CODELENS_TITLE}" ) ,
302
+ command : COMPILE_COMMAND . into ( ) ,
303
+ arguments : Some ( vec ! [
304
+ "--program-dir" . into( ) ,
305
+ format!( "{}" , workspace. root_dir. display( ) ) . into( ) ,
306
+ "--package" . into( ) ,
307
+ format!( "{}" , package. name) . into( ) ,
308
+ ] ) ,
309
+ } ;
310
+
311
+ let compile_lens = CodeLens { range, command : Some ( compile_command) , data : None } ;
312
+
313
+ lenses. push ( compile_lens) ;
314
+ }
315
+ }
316
+
317
+ if package. is_binary ( ) {
318
+ if let Some ( main_func_id) = context. get_main_function ( & crate_id) {
319
+ let location = context. function_meta ( & main_func_id) . name . location ;
320
+ let file_id = location. file ;
321
+
322
+ // Ignore diagnostics for any file that wasn't the file we saved
323
+ // TODO: In the future, we could create "related" diagnostics for these files
324
+ // TODO: This currently just appends the `.nr` file extension that we store as a constant,
325
+ // but that won't work if we accept other extensions
326
+ if fm. path ( file_id) . with_extension ( FILE_EXTENSION ) != file_path {
327
+ continue ;
328
+ }
329
+
330
+ let range = byte_span_to_range ( files, file_id. as_usize ( ) , location. span . into ( ) )
331
+ . unwrap_or_default ( ) ;
332
+
333
+ let command = Command {
334
+ title : format ! ( "{ARROW} {COMPILE_CODELENS_TITLE}" ) ,
335
+ command : COMPILE_COMMAND . into ( ) ,
336
+ arguments : Some ( vec ! [
337
+ "--program-dir" . into( ) ,
338
+ format!( "{}" , workspace. root_dir. display( ) ) . into( ) ,
339
+ "--package" . into( ) ,
340
+ format!( "{}" , package. name) . into( ) ,
341
+ ] ) ,
342
+ } ;
343
+
344
+ let lens = CodeLens { range, command : command. into ( ) , data : None } ;
345
+
346
+ lenses. push ( lens) ;
347
+ }
348
+ }
349
+
350
+ if package. is_contract ( ) {
351
+ // Currently not looking to deduplicate this since we don't have a clear decision on if the Contract stuff is staying
352
+ for contract in context. get_all_contracts ( & crate_id) {
353
+ let location = contract. location ;
354
+ let file_id = location. file ;
355
+
356
+ // Ignore diagnostics for any file that wasn't the file we saved
357
+ // TODO: In the future, we could create "related" diagnostics for these files
358
+ // TODO: This currently just appends the `.nr` file extension that we store as a constant,
359
+ // but that won't work if we accept other extensions
360
+ if fm. path ( file_id) . with_extension ( FILE_EXTENSION ) != file_path {
361
+ continue ;
362
+ }
363
+
364
+ let range = byte_span_to_range ( files, file_id. as_usize ( ) , location. span . into ( ) )
365
+ . unwrap_or_default ( ) ;
366
+
367
+ let command = Command {
368
+ title : format ! ( "{ARROW} {COMPILE_CODELENS_TITLE}" ) ,
369
+ command : COMPILE_COMMAND . into ( ) ,
370
+ arguments : Some ( vec ! [
371
+ "--program-dir" . into( ) ,
372
+ format!( "{}" , workspace. root_dir. display( ) ) . into( ) ,
373
+ "--package" . into( ) ,
374
+ format!( "{}" , package. name) . into( ) ,
375
+ ] ) ,
376
+ } ;
377
+
378
+ let lens = CodeLens { range, command : command. into ( ) , data : None } ;
379
+
380
+ lenses. push ( lens) ;
381
+ }
228
382
}
229
383
}
230
384
@@ -365,6 +519,9 @@ fn on_did_save_text_document(
365
519
}
366
520
}
367
521
522
+ // We need to refresh lenses when we compile since that's the only time they can be accurately reflected
523
+ let _ = state. client . code_lens_refresh ( ( ) ) ;
524
+
368
525
let _ = state. client . publish_diagnostics ( PublishDiagnosticsParams {
369
526
uri : params. text_document . uri ,
370
527
version : None ,
0 commit comments