@@ -41,7 +41,7 @@ let projectsFiles: Map<
41
41
// ^ caching AND states AND distributed system. Why does LSP has to be stupid like this
42
42
43
43
// will be properly defined later depending on the mode (stdio/node-rpc)
44
- let send : ( msg : m . Message ) => void = ( _ ) => { } ;
44
+ let send : ( msg : m . Message ) => void = ( _ ) => { } ;
45
45
46
46
interface CreateInterfaceRequestParams {
47
47
uri : string ;
@@ -349,6 +349,174 @@ function completion(msg: p.RequestMessage) {
349
349
return response ;
350
350
}
351
351
352
+ function format ( msg : p . RequestMessage ) : Array < m . Message > {
353
+ // technically, a formatting failure should reply with the error. Sadly
354
+ // the LSP alert box for these error replies sucks (e.g. doesn't actually
355
+ // display the message). In order to signal the client to display a proper
356
+ // alert box (sometime with actionable buttons), we need to first send
357
+ // back a fake success message (because each request mandates a
358
+ // response), then right away send a server notification to display a
359
+ // nicer alert. Ugh.
360
+ let fakeSuccessResponse : m . ResponseMessage = {
361
+ jsonrpc : c . jsonrpcVersion ,
362
+ id : msg . id ,
363
+ result : [ ] ,
364
+ } ;
365
+
366
+ let params = msg . params as p . DocumentFormattingParams ;
367
+ let filePath = fileURLToPath ( params . textDocument . uri ) ;
368
+ let extension = path . extname ( params . textDocument . uri ) ;
369
+ if ( extension !== c . resExt && extension !== c . resiExt ) {
370
+ let params : p . ShowMessageParams = {
371
+ type : p . MessageType . Error ,
372
+ message : `Not a ${ c . resExt } or ${ c . resiExt } file. Cannot format it.` ,
373
+ } ;
374
+ let response : m . NotificationMessage = {
375
+ jsonrpc : c . jsonrpcVersion ,
376
+ method : "window/showMessage" ,
377
+ params : params ,
378
+ } ;
379
+ return [ fakeSuccessResponse , response ] ;
380
+ } else {
381
+ // See comment on findBscNativeDirOfFile for why we need
382
+ // to recursively search for bsc.exe upward
383
+ let bscNativePath = utils . findBscNativeOfFile ( filePath ) ;
384
+ if ( bscNativePath === null ) {
385
+ let params : p . ShowMessageParams = {
386
+ type : p . MessageType . Error ,
387
+ message : `Cannot find a nearby bsc.exe in rescript or bs-platform. It's needed for formatting.` ,
388
+ } ;
389
+ let response : m . NotificationMessage = {
390
+ jsonrpc : c . jsonrpcVersion ,
391
+ method : "window/showMessage" ,
392
+ params : params ,
393
+ } ;
394
+ return [ fakeSuccessResponse , response ]
395
+ } else {
396
+ // code will always be defined here, even though technically it can be undefined
397
+ let code = getOpenedFileContent ( params . textDocument . uri ) ;
398
+ let formattedResult = utils . formatUsingValidBscNativePath (
399
+ code ,
400
+ bscNativePath ,
401
+ extension === c . resiExt
402
+ ) ;
403
+ if ( formattedResult . kind === "success" ) {
404
+ let max = formattedResult . result . length ;
405
+ let result : p . TextEdit [ ] = [
406
+ {
407
+ range : {
408
+ start : { line : 0 , character : 0 } ,
409
+ end : { line : max , character : max } ,
410
+ } ,
411
+ newText : formattedResult . result ,
412
+ } ,
413
+ ] ;
414
+ let response : m . ResponseMessage = {
415
+ jsonrpc : c . jsonrpcVersion ,
416
+ id : msg . id ,
417
+ result : result ,
418
+ } ;
419
+ return [ response ] ;
420
+ } else {
421
+ // let the diagnostics logic display the updated syntax errors,
422
+ // from the build.
423
+ // Again, not sending the actual errors. See fakeSuccessResponse
424
+ // above for explanation
425
+ return [ fakeSuccessResponse ] ;
426
+ }
427
+ }
428
+ }
429
+ }
430
+
431
+ function createInterface ( msg : p . RequestMessage ) : m . Message {
432
+ let params = msg . params as CreateInterfaceRequestParams ;
433
+ let extension = path . extname ( params . uri ) ;
434
+ let filePath = fileURLToPath ( params . uri ) ;
435
+ let bscNativePath = utils . findBscNativeOfFile ( filePath ) ;
436
+ let projDir = utils . findProjectRootOfFile ( filePath ) ;
437
+
438
+ if ( bscNativePath === null || projDir === null ) {
439
+ let params : p . ShowMessageParams = {
440
+ type : p . MessageType . Error ,
441
+ message : `Cannot find a nearby bsc.exe to generate the interface file.` ,
442
+ } ;
443
+
444
+ let response : m . NotificationMessage = {
445
+ jsonrpc : c . jsonrpcVersion ,
446
+ method : "window/showMessage" ,
447
+ params : params ,
448
+ } ;
449
+
450
+ return response ;
451
+ } else if ( extension !== c . resExt ) {
452
+ let params : p . ShowMessageParams = {
453
+ type : p . MessageType . Error ,
454
+ message : `Not a ${ c . resExt } file. Cannot create an interface for it.` ,
455
+ } ;
456
+
457
+ let response : m . NotificationMessage = {
458
+ jsonrpc : c . jsonrpcVersion ,
459
+ method : "window/showMessage" ,
460
+ params : params ,
461
+ } ;
462
+
463
+ return response ;
464
+ } else {
465
+ let cmiPartialPath = utils . replaceFileExtension (
466
+ filePath . split ( projDir ) [ 1 ] ,
467
+ c . cmiExt
468
+ ) ;
469
+ let cmiPath = path . join (
470
+ projDir ,
471
+ c . compilerDirPartialPath ,
472
+ cmiPartialPath
473
+ ) ;
474
+ let cmiAvailable = fs . existsSync ( cmiPath ) ;
475
+
476
+ if ( ! cmiAvailable ) {
477
+ let params : p . ShowMessageParams = {
478
+ type : p . MessageType . Error ,
479
+ message : `No compiled interface file found. Please compile your project first.` ,
480
+ } ;
481
+
482
+ let response : m . NotificationMessage = {
483
+ jsonrpc : c . jsonrpcVersion ,
484
+ method : "window/showMessage" ,
485
+ params,
486
+ } ;
487
+
488
+ return response ;
489
+ } else {
490
+ let intfResult = utils . createInterfaceFileUsingValidBscExePath (
491
+ filePath ,
492
+ cmiPath ,
493
+ bscNativePath
494
+ ) ;
495
+
496
+ if ( intfResult . kind === "success" ) {
497
+ let response : m . ResponseMessage = {
498
+ jsonrpc : c . jsonrpcVersion ,
499
+ id : msg . id ,
500
+ result : intfResult . result ,
501
+ } ;
502
+
503
+ return response ;
504
+ } else {
505
+ let response : m . ResponseMessage = {
506
+ jsonrpc : c . jsonrpcVersion ,
507
+ id : msg . id ,
508
+ error : {
509
+ code : m . ErrorCodes . InternalError ,
510
+ message : "Unable to create interface file." ,
511
+ } ,
512
+ } ;
513
+
514
+ return response ;
515
+ }
516
+ }
517
+ }
518
+ }
519
+
352
520
function onMessage ( msg : m . Message ) {
353
521
if ( m . isNotificationMessage ( msg ) ) {
354
522
// notification message, aka the client ends it and doesn't want a reply
@@ -471,171 +639,10 @@ function onMessage(msg: m.Message) {
471
639
} else if ( msg . method === p . CompletionRequest . method ) {
472
640
send ( completion ( msg ) ) ;
473
641
} else if ( msg . method === p . DocumentFormattingRequest . method ) {
474
- // technically, a formatting failure should reply with the error. Sadly
475
- // the LSP alert box for these error replies sucks (e.g. doesn't actually
476
- // display the message). In order to signal the client to display a proper
477
- // alert box (sometime with actionable buttons), we need to first send
478
- // back a fake success message (because each request mandates a
479
- // response), then right away send a server notification to display a
480
- // nicer alert. Ugh.
481
- let fakeSuccessResponse : m . ResponseMessage = {
482
- jsonrpc : c . jsonrpcVersion ,
483
- id : msg . id ,
484
- result : [ ] ,
485
- } ;
486
-
487
- let params = msg . params as p . DocumentFormattingParams ;
488
- let filePath = fileURLToPath ( params . textDocument . uri ) ;
489
- let extension = path . extname ( params . textDocument . uri ) ;
490
- if ( extension !== c . resExt && extension !== c . resiExt ) {
491
- let params : p . ShowMessageParams = {
492
- type : p . MessageType . Error ,
493
- message : `Not a ${ c . resExt } or ${ c . resiExt } file. Cannot format it.` ,
494
- } ;
495
- let response : m . NotificationMessage = {
496
- jsonrpc : c . jsonrpcVersion ,
497
- method : "window/showMessage" ,
498
- params : params ,
499
- } ;
500
- send ( fakeSuccessResponse ) ;
501
- send ( response ) ;
502
- } else {
503
- // See comment on findBscNativeDirOfFile for why we need
504
- // to recursively search for bsc.exe upward
505
- let bscNativePath = utils . findBscNativeOfFile ( filePath ) ;
506
- if ( bscNativePath === null ) {
507
- let params : p . ShowMessageParams = {
508
- type : p . MessageType . Error ,
509
- message : `Cannot find a nearby bsc.exe in rescript or bs-platform. It's needed for formatting.` ,
510
- } ;
511
- let response : m . NotificationMessage = {
512
- jsonrpc : c . jsonrpcVersion ,
513
- method : "window/showMessage" ,
514
- params : params ,
515
- } ;
516
- send ( fakeSuccessResponse ) ;
517
- send ( response ) ;
518
- } else {
519
- // code will always be defined here, even though technically it can be undefined
520
- let code = getOpenedFileContent ( params . textDocument . uri ) ;
521
- let formattedResult = utils . formatUsingValidBscNativePath (
522
- code ,
523
- bscNativePath ,
524
- extension === c . resiExt
525
- ) ;
526
- if ( formattedResult . kind === "success" ) {
527
- let max = formattedResult . result . length ;
528
- let result : p . TextEdit [ ] = [
529
- {
530
- range : {
531
- start : { line : 0 , character : 0 } ,
532
- end : { line : max , character : max } ,
533
- } ,
534
- newText : formattedResult . result ,
535
- } ,
536
- ] ;
537
- let response : m . ResponseMessage = {
538
- jsonrpc : c . jsonrpcVersion ,
539
- id : msg . id ,
540
- result : result ,
541
- } ;
542
- send ( response ) ;
543
- } else {
544
- // let the diagnostics logic display the updated syntax errors,
545
- // from the build.
546
- // Again, not sending the actual errors. See fakeSuccessResponse
547
- // above for explanation
548
- send ( fakeSuccessResponse ) ;
549
- }
550
- }
551
- }
642
+ let responses = format ( msg ) ;
643
+ responses . forEach ( response => send ( response ) )
552
644
} else if ( msg . method === createInterfaceRequest . method ) {
553
- let params = msg . params as CreateInterfaceRequestParams ;
554
- let extension = path . extname ( params . uri ) ;
555
- let filePath = fileURLToPath ( params . uri ) ;
556
- let bscNativePath = utils . findBscNativeOfFile ( filePath ) ;
557
- let projDir = utils . findProjectRootOfFile ( filePath ) ;
558
-
559
- if ( bscNativePath === null || projDir === null ) {
560
- let params : p . ShowMessageParams = {
561
- type : p . MessageType . Error ,
562
- message : `Cannot find a nearby bsc.exe to generate the interface file.` ,
563
- } ;
564
-
565
- let response : m . NotificationMessage = {
566
- jsonrpc : c . jsonrpcVersion ,
567
- method : "window/showMessage" ,
568
- params : params ,
569
- } ;
570
-
571
- send ( response ) ;
572
- } else if ( extension !== c . resExt ) {
573
- let params : p . ShowMessageParams = {
574
- type : p . MessageType . Error ,
575
- message : `Not a ${ c . resExt } file. Cannot create an interface for it.` ,
576
- } ;
577
-
578
- let response : m . NotificationMessage = {
579
- jsonrpc : c . jsonrpcVersion ,
580
- method : "window/showMessage" ,
581
- params : params ,
582
- } ;
583
-
584
- send ( response ) ;
585
- } else {
586
- let cmiPartialPath = utils . replaceFileExtension (
587
- filePath . split ( projDir ) [ 1 ] ,
588
- c . cmiExt
589
- ) ;
590
- let cmiPath = path . join (
591
- projDir ,
592
- c . compilerDirPartialPath ,
593
- cmiPartialPath
594
- ) ;
595
- let cmiAvailable = fs . existsSync ( cmiPath ) ;
596
-
597
- if ( ! cmiAvailable ) {
598
- let params : p . ShowMessageParams = {
599
- type : p . MessageType . Error ,
600
- message : `No compiled interface file found. Please compile your project first.` ,
601
- } ;
602
-
603
- let response : m . NotificationMessage = {
604
- jsonrpc : c . jsonrpcVersion ,
605
- method : "window/showMessage" ,
606
- params,
607
- } ;
608
-
609
- send ( response ) ;
610
- } else {
611
- let intfResult = utils . createInterfaceFileUsingValidBscExePath (
612
- filePath ,
613
- cmiPath ,
614
- bscNativePath
615
- ) ;
616
-
617
- if ( intfResult . kind === "success" ) {
618
- let response : m . ResponseMessage = {
619
- jsonrpc : c . jsonrpcVersion ,
620
- id : msg . id ,
621
- result : intfResult . result ,
622
- } ;
623
-
624
- send ( response ) ;
625
- } else {
626
- let response : m . ResponseMessage = {
627
- jsonrpc : c . jsonrpcVersion ,
628
- id : msg . id ,
629
- error : {
630
- code : m . ErrorCodes . InternalError ,
631
- message : "Unable to create interface file." ,
632
- } ,
633
- } ;
634
-
635
- send ( response ) ;
636
- }
637
- }
638
- }
645
+ send ( createInterface ( msg ) )
639
646
} else {
640
647
let response : m . ResponseMessage = {
641
648
jsonrpc : c . jsonrpcVersion ,
0 commit comments