@@ -44,7 +44,7 @@ type INOLanguageServer struct {
4444 sketchName string
4545 sketchMapper * sourcemapper.SketchMapper
4646 sketchTrackedFilesCount int
47- trackedIDEDocs map [string ]lsp.TextDocumentItem
47+ trackedIdeDocs map [string ]lsp.TextDocumentItem
4848 ideInoDocsWithDiagnostics map [lsp.DocumentURI ]bool
4949 sketchRebuilder * SketchRebuilder
5050}
@@ -115,7 +115,7 @@ func (ls *INOLanguageServer) readUnlock(logger jsonrpc.FunctionLogger) {
115115func NewINOLanguageServer (stdin io.Reader , stdout io.Writer , config * Config ) * INOLanguageServer {
116116 logger := NewLSPFunctionLogger (color .HiWhiteString , "LS: " )
117117 ls := & INOLanguageServer {
118- trackedIDEDocs : map [string ]lsp.TextDocumentItem {},
118+ trackedIdeDocs : map [string ]lsp.TextDocumentItem {},
119119 ideInoDocsWithDiagnostics : map [lsp.DocumentURI ]bool {},
120120 closing : make (chan bool ),
121121 config : config ,
@@ -952,7 +952,7 @@ func (ls *INOLanguageServer) TextDocumentRangeFormattingReqFromIDE(ctx context.C
952952 }
953953}
954954
955- func (ls * INOLanguageServer ) InitializedNotifFromIDE (logger jsonrpc.FunctionLogger , params * lsp.InitializedParams ) {
955+ func (ls * INOLanguageServer ) InitializedNotifFromIDE (logger jsonrpc.FunctionLogger , ideParams * lsp.InitializedParams ) {
956956 logger .Logf ("Notification is not propagated to clangd" )
957957}
958958
@@ -962,18 +962,18 @@ func (ls *INOLanguageServer) ExitNotifFromIDE(logger jsonrpc.FunctionLogger) {
962962 os .Exit (0 )
963963}
964964
965- func (ls * INOLanguageServer ) TextDocumentDidOpenNotifFromIDE (logger jsonrpc.FunctionLogger , inoParam * lsp.DidOpenTextDocumentParams ) {
965+ func (ls * INOLanguageServer ) TextDocumentDidOpenNotifFromIDE (logger jsonrpc.FunctionLogger , ideParam * lsp.DidOpenTextDocumentParams ) {
966966 ls .writeLock (logger , true )
967967 defer ls .writeUnlock (logger )
968968
969969 ls .triggerRebuild ()
970970
971971 // Add the TextDocumentItem in the tracked files list
972- inoTextDocItem := inoParam .TextDocument
973- ls .trackedIDEDocs [ inoTextDocItem .URI .AsPath ().String ()] = inoTextDocItem
972+ ideTextDocItem := ideParam .TextDocument
973+ ls .trackedIdeDocs [ ideTextDocItem .URI .AsPath ().String ()] = ideTextDocItem
974974
975975 // If we are tracking a .ino...
976- if inoTextDocItem .URI .Ext () == ".ino" {
976+ if ideTextDocItem .URI .Ext () == ".ino" {
977977 ls .sketchTrackedFilesCount ++
978978 logger .Logf ("Increasing .ino tracked files count to %d" , ls .sketchTrackedFilesCount )
979979
@@ -984,10 +984,10 @@ func (ls *INOLanguageServer) TextDocumentDidOpenNotifFromIDE(logger jsonrpc.Func
984984 }
985985 }
986986
987- if cppItem , err := ls .ino2cppTextDocumentItem (logger , inoTextDocItem ); err != nil {
987+ if clangTextDocItem , err := ls .ino2cppTextDocumentItem (logger , ideTextDocItem ); err != nil {
988988 logger .Logf ("Error: %s" , err )
989989 } else if err := ls .Clangd .conn .TextDocumentDidOpen (& lsp.DidOpenTextDocumentParams {
990- TextDocument : cppItem ,
990+ TextDocument : clangTextDocItem ,
991991 }); err != nil {
992992 // Exit the process and trigger a restart by the client in case of a severe error
993993 logger .Logf ("Error sending notification to clangd server: %v" , err )
@@ -996,33 +996,109 @@ func (ls *INOLanguageServer) TextDocumentDidOpenNotifFromIDE(logger jsonrpc.Func
996996 }
997997}
998998
999- func (ls * INOLanguageServer ) TextDocumentDidChangeNotifFromIDE (logger jsonrpc.FunctionLogger , inoParams * lsp.DidChangeTextDocumentParams ) {
999+ func (ls * INOLanguageServer ) TextDocumentDidChangeNotifFromIDE (logger jsonrpc.FunctionLogger , ideParams * lsp.DidChangeTextDocumentParams ) {
10001000 ls .writeLock (logger , true )
10011001 defer ls .writeUnlock (logger )
10021002
10031003 ls .triggerRebuild ()
10041004
1005- logger .Logf ("didChange(%s)" , inoParams .TextDocument )
1006- for _ , change := range inoParams .ContentChanges {
1005+ logger .Logf ("didChange(%s)" , ideParams .TextDocument )
1006+ for _ , change := range ideParams .ContentChanges {
10071007 logger .Logf (" > %s" , change )
10081008 }
10091009
1010- if cppParams , err := ls .didChange (logger , inoParams ); err != nil {
1010+ // Clear all RangeLengths: it's a deprecated field and if the byte count is wrong the
1011+ // source text file will be unloaded from clangd without notice, leading to a "non-added
1012+ // document" error for all subsequent requests.
1013+ // https://github.com/clangd/clangd/issues/717#issuecomment-793220007
1014+ for i := range ideParams .ContentChanges {
1015+ ideParams .ContentChanges [i ].RangeLength = nil
1016+ }
1017+
1018+ ideTextDocIdentifier := ideParams .TextDocument
1019+
1020+ // Apply the change to the tracked sketch file.
1021+ trackedIdeDocID := ideTextDocIdentifier .URI .AsPath ().String ()
1022+ if doc , ok := ls .trackedIdeDocs [trackedIdeDocID ]; ! ok {
1023+ logger .Logf ("Error: %s" , & UnknownURI {ideTextDocIdentifier .URI })
1024+ return
1025+ } else if updatedDoc , err := textedits .ApplyLSPTextDocumentContentChangeEvent (doc , ideParams ); err != nil {
10111026 logger .Logf ("Error: %s" , err )
1012- } else if cppParams == nil {
1013- logger .Logf ("Notification is not propagated to clangd" )
1027+ return
10141028 } else {
1015- logger .Logf ("to Clang: didChange(%s@%d)" , cppParams .TextDocument )
1016- for _ , change := range cppParams .ContentChanges {
1017- logger .Logf (" > %s" , change )
1029+ ls .trackedIdeDocs [trackedIdeDocID ] = updatedDoc
1030+ logger .Logf ("Tracked SKETCH file:----------+\n " + updatedDoc .Text + "\n ----------------------" )
1031+ }
1032+
1033+ // If the file is not part of a .ino flie forward the change as-is to clangd
1034+ var clangParams * lsp.DidChangeTextDocumentParams
1035+
1036+ if ideTextDocIdentifier .URI .Ext () != ".ino" {
1037+
1038+ clangTextDocIdentifier , err := ls .ide2ClangVersionedTextDocumentIdentifier (logger , ideTextDocIdentifier )
1039+ if err != nil {
1040+ logger .Logf ("Error: %s" , err )
1041+ return
10181042 }
1019- if err := ls .Clangd .conn .TextDocumentDidChange (cppParams ); err != nil {
1020- // Exit the process and trigger a restart by the client in case of a severe error
1021- logger .Logf ("Connection error with clangd server: %v" , err )
1022- logger .Logf ("Please restart the language server." )
1023- ls .Close ()
1043+ clangParams = & lsp.DidChangeTextDocumentParams {
1044+ TextDocument : clangTextDocIdentifier ,
1045+ ContentChanges : ideParams .ContentChanges ,
1046+ }
1047+
1048+ } else {
1049+
1050+ // If changes are applied to a .ino file we increment the global .ino.cpp versioning
1051+ // for each increment of the single .ino file.
1052+
1053+ clangChanges := []lsp.TextDocumentContentChangeEvent {}
1054+ for _ , ideChange := range ideParams .ContentChanges {
1055+ var clangChangeRange * lsp.Range
1056+ if ideChange .Range != nil {
1057+ clangURI , clangRange , err := ls .ide2ClangRange (logger , ideTextDocIdentifier .URI , * ideChange .Range )
1058+ if err != nil {
1059+ logger .Logf ("Error: %s" , err )
1060+ return
1061+ }
1062+ if ! ls .clangURIRefersToIno (clangURI ) {
1063+ logger .Logf ("Error: change to .ino does not maps to a change in sketch.ino.cpp" )
1064+ return
1065+ }
1066+ clangChangeRange = & clangRange
1067+
1068+ _ = ls .sketchMapper .ApplyTextChange (ideTextDocIdentifier .URI , ideChange )
1069+ ls .sketchMapper .DebugLogAll ()
1070+ } else {
1071+ panic ("full-text change in .ino not implemented" )
1072+ }
1073+ clangChanges = append (clangChanges , lsp.TextDocumentContentChangeEvent {
1074+ Range : clangChangeRange ,
1075+ RangeLength : ideChange .RangeLength ,
1076+ Text : ideChange .Text ,
1077+ })
1078+ }
1079+
1080+ // build a cpp equivalent didChange request
1081+ clangParams = & lsp.DidChangeTextDocumentParams {
1082+ ContentChanges : clangChanges ,
1083+ TextDocument : lsp.VersionedTextDocumentIdentifier {
1084+ TextDocumentIdentifier : lsp.TextDocumentIdentifier {
1085+ URI : lsp .NewDocumentURIFromPath (ls .buildSketchCpp ),
1086+ },
1087+ Version : ls .sketchMapper .CppText .Version ,
1088+ },
10241089 }
10251090 }
1091+
1092+ logger .Logf ("to Clang: didChange(%s@%d)" , clangParams .TextDocument )
1093+ for _ , change := range clangParams .ContentChanges {
1094+ logger .Logf (" > %s" , change )
1095+ }
1096+ if err := ls .Clangd .conn .TextDocumentDidChange (clangParams ); err != nil {
1097+ // Exit the process and trigger a restart by the client in case of a severe error
1098+ logger .Logf ("Connection error with clangd server: %v" , err )
1099+ logger .Logf ("Please restart the language server." )
1100+ ls .Close ()
1101+ }
10261102}
10271103
10281104func (ls * INOLanguageServer ) TextDocumentDidSaveNotifFromIDE (logger jsonrpc.FunctionLogger , inoParams * lsp.DidSaveTextDocumentParams ) {
@@ -1244,8 +1320,8 @@ func (ls *INOLanguageServer) extractDataFolderFromArduinoCLI(logger jsonrpc.Func
12441320
12451321func (ls * INOLanguageServer ) didClose (logger jsonrpc.FunctionLogger , inoDidClose * lsp.DidCloseTextDocumentParams ) (* lsp.DidCloseTextDocumentParams , error ) {
12461322 inoIdentifier := inoDidClose .TextDocument
1247- if _ , exist := ls .trackedIDEDocs [inoIdentifier .URI .AsPath ().String ()]; exist {
1248- delete (ls .trackedIDEDocs , inoIdentifier .URI .AsPath ().String ())
1323+ if _ , exist := ls .trackedIdeDocs [inoIdentifier .URI .AsPath ().String ()]; exist {
1324+ delete (ls .trackedIdeDocs , inoIdentifier .URI .AsPath ().String ())
12491325 } else {
12501326 logger .Logf (" didClose of untracked document: %s" , inoIdentifier .URI )
12511327 return nil , & UnknownURI {inoIdentifier .URI }
@@ -1282,87 +1358,13 @@ func (ls *INOLanguageServer) ino2cppTextDocumentItem(logger jsonrpc.FunctionLogg
12821358 } else {
12831359 cppItem .LanguageID = inoItem .LanguageID
12841360 inoPath := inoItem .URI .AsPath ().String ()
1285- cppItem .Text = ls .trackedIDEDocs [inoPath ].Text
1286- cppItem .Version = ls .trackedIDEDocs [inoPath ].Version
1361+ cppItem .Text = ls .trackedIdeDocs [inoPath ].Text
1362+ cppItem .Version = ls .trackedIdeDocs [inoPath ].Version
12871363 }
12881364
12891365 return cppItem , nil
12901366}
12911367
1292- func (ls * INOLanguageServer ) didChange (logger jsonrpc.FunctionLogger , inoDidChangeParams * lsp.DidChangeTextDocumentParams ) (* lsp.DidChangeTextDocumentParams , error ) {
1293- // Clear all RangeLengths: it's a deprecated field and if the byte count is wrong the
1294- // source text file will be unloaded from clangd without notice, leading to a "non-added
1295- // document" error for all subsequent requests.
1296- // https://github.com/clangd/clangd/issues/717#issuecomment-793220007
1297- for i := range inoDidChangeParams .ContentChanges {
1298- inoDidChangeParams .ContentChanges [i ].RangeLength = nil
1299- }
1300-
1301- inoDoc := inoDidChangeParams .TextDocument
1302-
1303- // Apply the change to the tracked sketch file.
1304- trackedInoID := inoDoc .URI .AsPath ().String ()
1305- if doc , ok := ls .trackedIDEDocs [trackedInoID ]; ! ok {
1306- return nil , & UnknownURI {inoDoc .URI }
1307- } else if updatedDoc , err := textedits .ApplyLSPTextDocumentContentChangeEvent (doc , inoDidChangeParams ); err != nil {
1308- return nil , err
1309- } else {
1310- ls .trackedIDEDocs [trackedInoID ] = updatedDoc
1311- }
1312-
1313- logger .Logf ("Tracked SKETCH file:----------+\n " + ls .trackedIDEDocs [trackedInoID ].Text + "\n ----------------------" )
1314-
1315- // If the file is not part of a .ino flie forward the change as-is to clangd
1316- if inoDoc .URI .Ext () != ".ino" {
1317- if cppDoc , err := ls .ino2cppVersionedTextDocumentIdentifier (logger , inoDidChangeParams .TextDocument ); err != nil {
1318- return nil , err
1319- } else {
1320- cppDidChangeParams := * inoDidChangeParams
1321- cppDidChangeParams .TextDocument = cppDoc
1322- return & cppDidChangeParams , nil
1323- }
1324- }
1325-
1326- // If changes are applied to a .ino file we increment the global .ino.cpp versioning
1327- // for each increment of the single .ino file.
1328-
1329- cppChanges := []lsp.TextDocumentContentChangeEvent {}
1330- for _ , inoChange := range inoDidChangeParams .ContentChanges {
1331- cppChangeRange , ok := ls .sketchMapper .InoToCppLSPRangeOk (inoDoc .URI , * inoChange .Range )
1332- if ! ok {
1333- return nil , errors .Errorf ("invalid change range %s:%s" , inoDoc .URI , inoChange .Range )
1334- }
1335-
1336- _ = ls .sketchMapper .ApplyTextChange (inoDoc .URI , inoChange )
1337-
1338- ls .sketchMapper .DebugLogAll ()
1339-
1340- cppChanges = append (cppChanges , lsp.TextDocumentContentChangeEvent {
1341- Range : & cppChangeRange ,
1342- RangeLength : inoChange .RangeLength ,
1343- Text : inoChange .Text ,
1344- })
1345- }
1346-
1347- // build a cpp equivalent didChange request
1348- return & lsp.DidChangeTextDocumentParams {
1349- ContentChanges : cppChanges ,
1350- TextDocument : lsp.VersionedTextDocumentIdentifier {
1351- TextDocumentIdentifier : lsp.TextDocumentIdentifier {
1352- URI : lsp .NewDocumentURIFromPath (ls .buildSketchCpp ),
1353- },
1354- Version : ls .sketchMapper .CppText .Version ,
1355- },
1356- }, nil
1357- }
1358-
1359- func (ls * INOLanguageServer ) ino2cppVersionedTextDocumentIdentifier (logger jsonrpc.FunctionLogger , doc lsp.VersionedTextDocumentIdentifier ) (lsp.VersionedTextDocumentIdentifier , error ) {
1360- cppURI , err := ls .ide2ClangDocumentURI (logger , doc .URI )
1361- res := doc
1362- res .URI = cppURI
1363- return res , err
1364- }
1365-
13661368func (ls * INOLanguageServer ) clang2IdeCodeAction (logger jsonrpc.FunctionLogger , clangCodeAction lsp.CodeAction , origIdeURI lsp.DocumentURI ) * lsp.CodeAction {
13671369 ideCodeAction := & lsp.CodeAction {
13681370 Title : clangCodeAction .Title ,
0 commit comments