@@ -109,6 +109,7 @@ type fileUpdateEvent struct {
109
109
Content string
110
110
}
111
111
112
+ //nolint:gocyclo
112
113
func (l * LanguageServer ) Handle (
113
114
ctx context.Context ,
114
115
conn * jsonrpc2.Conn ,
@@ -148,6 +149,8 @@ func (l *LanguageServer) Handle(
148
149
return l .handleTextDocumentHover (ctx , conn , req )
149
150
case "textDocument/inlayHint" :
150
151
return l .handleTextDocumentInlayHint (ctx , conn , req )
152
+ case "textDocument/codeLens" :
153
+ return l .handleTextDocumentCodeLens (ctx , conn , req )
151
154
case "textDocument/completion" :
152
155
return l .handleTextDocumentCompletion (ctx , conn , req )
153
156
case "workspace/didChangeWatchedFiles" :
@@ -447,6 +450,59 @@ func (l *LanguageServer) StartCommandWorker(ctx context.Context) {
447
450
commands.ParseOptions {TargetArgIndex : 0 , RowArgIndex : 1 , ColArgIndex : 2 },
448
451
params ,
449
452
)
453
+ case "regal.eval" :
454
+ fmt .Fprintf (os .Stderr , "regal.eval called with params: %v\n " , params )
455
+
456
+ if len (params .Arguments ) != 3 {
457
+ l .logError (fmt .Errorf ("expected three arguments, got %d" , len (params .Arguments )))
458
+
459
+ break
460
+ }
461
+
462
+ file , ok := params .Arguments [0 ].(string )
463
+ if ! ok {
464
+ l .logError (fmt .Errorf ("expected first argument to be a string, got %T" , params .Arguments [0 ]))
465
+
466
+ break
467
+ }
468
+
469
+ path , ok := params .Arguments [1 ].(string )
470
+ if ! ok {
471
+ l .logError (fmt .Errorf ("expected second argument to be a string, got %T" , params .Arguments [1 ]))
472
+
473
+ break
474
+ }
475
+
476
+ line , ok := params .Arguments [2 ].(float64 )
477
+ if ! ok {
478
+ l .logError (fmt .Errorf ("expected third argument to be a number, got %T" , params .Arguments [2 ]))
479
+
480
+ break
481
+ }
482
+
483
+ input := FindInput (
484
+ uri .ToPath (l .clientIdentifier , file ),
485
+ uri .ToPath (l .clientIdentifier , l .workspaceRootURI ),
486
+ )
487
+
488
+ result , err := l .EvalWorkspacePath (ctx , path , input )
489
+ if err != nil {
490
+ fmt .Fprintf (os .Stderr , "failed to evaluate workspace path: %v\n " , err )
491
+
492
+ break
493
+ }
494
+
495
+ responseParams := map [string ]any {
496
+ "result" : result ,
497
+ "line" : line ,
498
+ }
499
+
500
+ responseResult := map [string ]any {}
501
+
502
+ err = l .conn .Call (ctx , "regal/showEvalResult" , responseParams , & responseResult )
503
+ if err != nil {
504
+ l .logError (fmt .Errorf ("failed %s notify: %v" , "regal/hello" , err .Error ()))
505
+ }
450
506
}
451
507
452
508
if err != nil {
@@ -934,6 +990,78 @@ func (l *LanguageServer) handleTextDocumentInlayHint(
934
990
return inlayHints , nil
935
991
}
936
992
993
+ func (l * LanguageServer ) handleTextDocumentCodeLens (
994
+ _ context.Context ,
995
+ _ * jsonrpc2.Conn ,
996
+ req * jsonrpc2.Request ,
997
+ ) (result any , err error ) {
998
+ var params types.CodeLensParams
999
+ if err := json .Unmarshal (* req .Params , & params ); err != nil {
1000
+ return nil , fmt .Errorf ("failed to unmarshal params: %w" , err )
1001
+ }
1002
+
1003
+ if l .clientIdentifier != clients .IdentifierVSCode {
1004
+ // only VSCode has the client side capability to handle the callback request
1005
+ // to handle the result of evaluation, so displaying code lenses for any other
1006
+ // editor is likely just going to result in a bad experience
1007
+ return nil , nil // return a null response, as per the spec
1008
+ }
1009
+
1010
+ module , ok := l .cache .GetModule (params .TextDocument .URI )
1011
+ if ! ok {
1012
+ l .logError (fmt .Errorf ("failed to get module for uri %q" , params .TextDocument .URI ))
1013
+
1014
+ // return a null response, as per the spec
1015
+ return nil , nil
1016
+ }
1017
+
1018
+ codeLenses := make ([]types.CodeLens , 0 )
1019
+
1020
+ // Package
1021
+
1022
+ pkgLens := types.CodeLens {
1023
+ Range : locationToRange (module .Package .Location ),
1024
+ Command : & types.Command {
1025
+ Title : "Evaluate" ,
1026
+ Command : "regal.eval" ,
1027
+ Arguments : & []any {
1028
+ module .Package .Location .File ,
1029
+ module .Package .Path .String (),
1030
+ module .Package .Location .Row ,
1031
+ },
1032
+ },
1033
+ }
1034
+
1035
+ codeLenses = append (codeLenses , pkgLens )
1036
+
1037
+ // Rules
1038
+
1039
+ for _ , rule := range module .Rules {
1040
+ if rule .Head .Args != nil {
1041
+ // Skip functions for now, as it's not clear how to best
1042
+ // provide inputs for them.
1043
+ continue
1044
+ }
1045
+
1046
+ ruleLens := types.CodeLens {
1047
+ Range : locationToRange (rule .Location ),
1048
+ Command : & types.Command {
1049
+ Title : "Evaluate" ,
1050
+ Command : "regal.eval" ,
1051
+ Arguments : & []any {
1052
+ module .Package .Location .File ,
1053
+ module .Package .Path .String () + "." + string (rule .Head .Name ),
1054
+ rule .Head .Location .Row ,
1055
+ },
1056
+ },
1057
+ }
1058
+
1059
+ codeLenses = append (codeLenses , ruleLens )
1060
+ }
1061
+
1062
+ return codeLenses , nil
1063
+ }
1064
+
937
1065
func (l * LanguageServer ) handleTextDocumentCompletion (
938
1066
_ context.Context ,
939
1067
_ * jsonrpc2.Conn ,
@@ -1527,7 +1655,7 @@ func (l *LanguageServer) handleInitialize(
1527
1655
ctx context.Context ,
1528
1656
_ * jsonrpc2.Conn ,
1529
1657
req * jsonrpc2.Request ,
1530
- ) (result any , err error ) {
1658
+ ) (any , error ) {
1531
1659
var params types.InitializeParams
1532
1660
if err := json .Unmarshal (* req .Params , & params ); err != nil {
1533
1661
return nil , fmt .Errorf ("failed to unmarshal params: %w" , err )
@@ -1554,7 +1682,7 @@ func (l *LanguageServer) handleInitialize(
1554
1682
},
1555
1683
}
1556
1684
1557
- result = types.InitializeResult {
1685
+ initializeResult : = types.InitializeResult {
1558
1686
Capabilities : types.ServerCapabilities {
1559
1687
TextDocumentSyncOptions : types.TextDocumentSyncOptions {
1560
1688
OpenClose : true ,
@@ -1590,6 +1718,7 @@ func (l *LanguageServer) handleInitialize(
1590
1718
},
1591
1719
ExecuteCommandProvider : types.ExecuteCommandOptions {
1592
1720
Commands : []string {
1721
+ "regal.eval" ,
1593
1722
"regal.fix.opa-fmt" ,
1594
1723
"regal.fix.use-rego-v1" ,
1595
1724
"regal.fix.use-assignment-operator" ,
@@ -1610,6 +1739,13 @@ func (l *LanguageServer) handleInitialize(
1610
1739
},
1611
1740
}
1612
1741
1742
+ // Since evaluation requires some client side handling, this can't be supported
1743
+ // purely by the LSP. Clients that are capable of handling the code lens callback
1744
+ // should be added here though.
1745
+ if l .clientIdentifier == clients .IdentifierVSCode {
1746
+ initializeResult .Capabilities .CodeLensProvider = & types.CodeLensOptions {}
1747
+ }
1748
+
1613
1749
if l .workspaceRootURI != "" {
1614
1750
configFile , err := config .FindConfig (uri .ToPath (l .clientIdentifier , l .workspaceRootURI ))
1615
1751
if err == nil {
@@ -1624,7 +1760,7 @@ func (l *LanguageServer) handleInitialize(
1624
1760
l .diagnosticRequestWorkspace <- "server initialize"
1625
1761
}
1626
1762
1627
- return result , nil
1763
+ return initializeResult , nil
1628
1764
}
1629
1765
1630
1766
func (l * LanguageServer ) loadWorkspaceContents (ctx context.Context , newOnly bool ) ([]string , error ) {
0 commit comments