@@ -41,7 +41,7 @@ let projectsFiles: Map<
4141// ^ caching AND states AND distributed system. Why does LSP has to be stupid like this
4242
4343// 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 = ( _ ) => { } ;
4545
4646interface CreateInterfaceRequestParams {
4747 uri : string ;
@@ -349,6 +349,174 @@ function completion(msg: p.RequestMessage) {
349349 return response ;
350350}
351351
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+
352520function onMessage ( msg : m . Message ) {
353521 if ( m . isNotificationMessage ( msg ) ) {
354522 // notification message, aka the client ends it and doesn't want a reply
@@ -471,171 +639,10 @@ function onMessage(msg: m.Message) {
471639 } else if ( msg . method === p . CompletionRequest . method ) {
472640 send ( completion ( msg ) ) ;
473641 } 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 ) )
552644 } 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 ) )
639646 } else {
640647 let response : m . ResponseMessage = {
641648 jsonrpc : c . jsonrpcVersion ,
0 commit comments