@@ -12,18 +12,19 @@ import (
12
12
"golang.org/x/tools/internal/jsonrpc2"
13
13
"golang.org/x/tools/internal/lsp/protocol"
14
14
"golang.org/x/tools/internal/lsp/source"
15
- "golang.org/x/tools/internal/lsp/telemetry"
16
15
"golang.org/x/tools/internal/span"
17
16
errors "golang.org/x/xerrors"
18
17
)
19
18
20
19
func (s * Server ) didOpen (ctx context.Context , params * protocol.DidOpenTextDocumentParams ) error {
21
- _ , err := s .didModifyFile (ctx , source.FileModification {
22
- URI : span .NewURI (params .TextDocument .URI ),
23
- Action : source .Open ,
24
- Version : params .TextDocument .Version ,
25
- Text : []byte (params .TextDocument .Text ),
26
- LanguageID : params .TextDocument .LanguageID ,
20
+ _ , err := s .didModifyFiles (ctx , []source.FileModification {
21
+ {
22
+ URI : span .NewURI (params .TextDocument .URI ),
23
+ Action : source .Open ,
24
+ Version : params .TextDocument .Version ,
25
+ Text : []byte (params .TextDocument .Text ),
26
+ LanguageID : params .TextDocument .LanguageID ,
27
+ },
27
28
})
28
29
return err
29
30
}
@@ -40,10 +41,14 @@ func (s *Server) didChange(ctx context.Context, params *protocol.DidChangeTextDo
40
41
Version : params .TextDocument .Version ,
41
42
Text : text ,
42
43
}
43
- snapshot , err := s .didModifyFile (ctx , c )
44
+ snapshots , err := s .didModifyFiles (ctx , []source. FileModification { c } )
44
45
if err != nil {
45
46
return err
46
47
}
48
+ snapshot := snapshots [uri ]
49
+ if snapshot == nil {
50
+ return errors .Errorf ("no snapshot for %s" , uri )
51
+ }
47
52
// Ideally, we should be able to specify that a generated file should be opened as read-only.
48
53
// Tell the user that they should not be editing a generated file.
49
54
if s .wasFirstChange (uri ) && source .IsGenerated (ctx , snapshot , uri ) {
@@ -58,38 +63,23 @@ func (s *Server) didChange(ctx context.Context, params *protocol.DidChangeTextDo
58
63
}
59
64
60
65
func (s * Server ) didChangeWatchedFiles (ctx context.Context , params * protocol.DidChangeWatchedFilesParams ) error {
61
- // Keep track of each change's view and final snapshot.
62
- views := make (map [source.View ]source.Snapshot )
66
+ var modifications []source.FileModification
63
67
for _ , change := range params .Changes {
64
68
uri := span .NewURI (change .URI )
65
- ctx := telemetry .File .With (ctx , uri )
66
69
67
70
// Do nothing if the file is open in the editor.
68
71
// The editor is the source of truth.
69
72
if s .session .IsOpen (uri ) {
70
73
continue
71
74
}
72
- snapshots , err := s .session .DidModifyFiles (ctx , []source.FileModification {
73
- {
74
- URI : uri ,
75
- Action : changeTypeToFileAction (change .Type ),
76
- OnDisk : true ,
77
- },
75
+ modifications = append (modifications , source.FileModification {
76
+ URI : uri ,
77
+ Action : changeTypeToFileAction (change .Type ),
78
+ OnDisk : true ,
78
79
})
79
- if err != nil {
80
- return err
81
- }
82
- snapshot , _ , err := snapshotOf (s .session , uri , snapshots )
83
- if err != nil {
84
- return err
85
- }
86
- views [snapshot .View ()] = snapshot
87
- }
88
- // Diagnose all resulting snapshots.
89
- for _ , snapshot := range views {
90
- go s .diagnoseSnapshot (snapshot )
91
80
}
92
- return nil
81
+ _ , err := s .didModifyFiles (ctx , modifications )
82
+ return err
93
83
}
94
84
95
85
func (s * Server ) didSave (ctx context.Context , params * protocol.DidSaveTextDocumentParams ) error {
@@ -101,59 +91,54 @@ func (s *Server) didSave(ctx context.Context, params *protocol.DidSaveTextDocume
101
91
if params .Text != nil {
102
92
c .Text = []byte (* params .Text )
103
93
}
104
- _ , err := s .didModifyFile (ctx , c )
94
+ _ , err := s .didModifyFiles (ctx , []source. FileModification { c } )
105
95
return err
106
96
}
107
97
108
98
func (s * Server ) didClose (ctx context.Context , params * protocol.DidCloseTextDocumentParams ) error {
109
- _ , err := s .didModifyFile (ctx , source.FileModification {
110
- URI : span .NewURI (params .TextDocument .URI ),
111
- Action : source .Close ,
112
- Version : - 1 ,
113
- Text : nil ,
99
+ _ , err := s .didModifyFiles (ctx , []source.FileModification {
100
+ {
101
+ URI : span .NewURI (params .TextDocument .URI ),
102
+ Action : source .Close ,
103
+ Version : - 1 ,
104
+ Text : nil ,
105
+ },
114
106
})
115
107
return err
116
108
}
117
109
118
- func (s * Server ) didModifyFile (ctx context.Context , c source.FileModification ) (source.Snapshot , error ) {
119
- snapshots , err := s .session .DidModifyFiles (ctx , []source. FileModification { c } )
110
+ func (s * Server ) didModifyFiles (ctx context.Context , modifications [] source.FileModification ) (map [span. URI ] source.Snapshot , error ) {
111
+ snapshots , err := s .session .DidModifyFiles (ctx , modifications )
120
112
if err != nil {
121
113
return nil , err
122
114
}
123
- snapshot , _ , err := snapshotOf ( s . session , c . URI , snapshots )
124
- if err != nil {
125
- return nil , err
115
+ uris := make ( map [span. URI ]source. Snapshot )
116
+ for _ , c := range modifications {
117
+ uris [ c . URI ] = nil
126
118
}
127
- switch c .Action {
128
- case source .Save :
129
- // If we're saving a go.mod file, all of the metadata has been invalidated,
130
- // so we need to run diagnostics and make sure that they cannot be canceled.
131
- fh , err := snapshot .GetFile (c .URI )
119
+ // Avoid diagnosing the same snapshot twice.
120
+ snapshotSet := make (map [source.Snapshot ]struct {})
121
+ for uri := range uris {
122
+ view , err := s .session .ViewOf (uri )
132
123
if err != nil {
133
124
return nil , err
134
125
}
135
- if fh .Identity ().Kind == source .Mod {
136
- go s .diagnoseDetached (snapshot )
126
+ var snapshot source.Snapshot
127
+ for _ , s := range snapshots {
128
+ if s .View () == view {
129
+ if snapshot != nil {
130
+ return nil , errors .Errorf ("duplicate snapshots for the same view" )
131
+ }
132
+ snapshot = s
133
+ }
137
134
}
138
- default :
139
- go s . diagnoseSnapshot ( snapshot )
135
+ uris [ uri ] = snapshot
136
+ snapshotSet [ snapshot ] = struct {}{}
140
137
}
141
-
142
- return snapshot , nil
143
- }
144
-
145
- // snapshotOf returns the snapshot corresponding to the view for the given file URI.
146
- func snapshotOf (session source.Session , uri span.URI , snapshots []source.Snapshot ) (source.Snapshot , source.View , error ) {
147
- view , err := session .ViewOf (uri )
148
- if err != nil {
149
- return nil , nil , err
150
- }
151
- for _ , s := range snapshots {
152
- if s .View () == view {
153
- return s , view , nil
154
- }
138
+ for snapshot := range snapshotSet {
139
+ go s .diagnoseSnapshot (snapshot )
155
140
}
156
- return nil , nil , errors . Errorf ( "bestSnapshot: no snapshot for %s" , uri )
141
+ return uris , nil
157
142
}
158
143
159
144
func (s * Server ) wasFirstChange (uri span.URI ) bool {
0 commit comments