@@ -37,7 +37,6 @@ type Editor struct {
37
37
serverConn jsonrpc2.Conn
38
38
client * Client
39
39
sandbox * Sandbox
40
- defaultEnv map [string ]string
41
40
42
41
// TODO(adonovan): buffers should be keyed by protocol.DocumentURI.
43
42
mu sync.Mutex
@@ -75,8 +74,14 @@ func (b buffer) text() string {
75
74
// source.UserOptions, but we use a separate type here so that we expose only
76
75
// that configuration which we support.
77
76
//
78
- // The zero value for EditorConfig should correspond to its defaults .
77
+ // The zero value for EditorConfig is the default configuration .
79
78
type EditorConfig struct {
79
+ // ClientName sets the clientInfo.name for the LSP session (in the initialize request).
80
+ //
81
+ // Since this can only be set during initialization, changing this field via
82
+ // Editor.ChangeConfiguration has no effect.
83
+ ClientName string
84
+
80
85
// Env holds environment variables to apply on top of the default editor
81
86
// environment. When applying these variables, the special string
82
87
// $SANDBOX_WORKDIR is replaced by the absolute path to the sandbox working
@@ -109,10 +114,9 @@ type EditorConfig struct {
109
114
// NewEditor creates a new Editor.
110
115
func NewEditor (sandbox * Sandbox , config EditorConfig ) * Editor {
111
116
return & Editor {
112
- buffers : make (map [string ]buffer ),
113
- sandbox : sandbox ,
114
- defaultEnv : sandbox .GoEnv (),
115
- config : config ,
117
+ buffers : make (map [string ]buffer ),
118
+ sandbox : sandbox ,
119
+ config : config ,
116
120
}
117
121
}
118
122
@@ -198,19 +202,17 @@ func (e *Editor) Client() *Client {
198
202
return e .client
199
203
}
200
204
201
- // settingsLocked builds the settings map for use in LSP settings RPCs.
202
- //
203
- // e.mu must be held while calling this function.
204
- func (e * Editor ) settingsLocked () map [string ]interface {} {
205
+ // makeSettings builds the settings map for use in LSP settings RPCs.
206
+ func makeSettings (sandbox * Sandbox , config EditorConfig ) map [string ]interface {} {
205
207
env := make (map [string ]string )
206
- for k , v := range e . defaultEnv {
208
+ for k , v := range sandbox . GoEnv () {
207
209
env [k ] = v
208
210
}
209
- for k , v := range e . config .Env {
211
+ for k , v := range config .Env {
210
212
env [k ] = v
211
213
}
212
214
for k , v := range env {
213
- v = strings .ReplaceAll (v , "$SANDBOX_WORKDIR" , e . sandbox .Workdir .RootURI ().SpanURI ().Filename ())
215
+ v = strings .ReplaceAll (v , "$SANDBOX_WORKDIR" , sandbox .Workdir .RootURI ().SpanURI ().Filename ())
214
216
env [k ] = v
215
217
}
216
218
@@ -226,7 +228,7 @@ func (e *Editor) settingsLocked() map[string]interface{} {
226
228
"completionBudget" : "10s" ,
227
229
}
228
230
229
- for k , v := range e . config .Settings {
231
+ for k , v := range config .Settings {
230
232
if k == "env" {
231
233
panic ("must not provide env via the EditorConfig.Settings field: use the EditorConfig.Env field instead" )
232
234
}
@@ -237,20 +239,22 @@ func (e *Editor) settingsLocked() map[string]interface{} {
237
239
}
238
240
239
241
func (e * Editor ) initialize (ctx context.Context ) error {
242
+ config := e .Config ()
243
+
240
244
params := & protocol.ParamInitialize {}
241
- params . ClientInfo = & protocol. Msg_XInitializeParams_clientInfo {}
242
- params .ClientInfo . Name = "fakeclient"
243
- params .ClientInfo .Version = "v1.0.0"
244
- e . mu . Lock ()
245
- params . WorkspaceFolders = e . makeWorkspaceFoldersLocked ()
246
- params .InitializationOptions = e . settingsLocked ( )
247
- e . mu . Unlock ( )
248
- params .Capabilities .Workspace .Configuration = true
249
- params .Capabilities .Window .WorkDoneProgress = true
245
+ if e . config . ClientName != "" {
246
+ params .ClientInfo = & protocol. Msg_XInitializeParams_clientInfo {}
247
+ params .ClientInfo .Name = e . config . ClientName
248
+ params . ClientInfo . Version = "v1.0.0"
249
+ }
250
+ params .InitializationOptions = makeSettings ( e . sandbox , config )
251
+ params . WorkspaceFolders = makeWorkspaceFolders ( e . sandbox , config . WorkspaceFolders )
252
+ params .Capabilities .Workspace .Configuration = true // support workspace/configuration
253
+ params .Capabilities .Window .WorkDoneProgress = true // support window/workDoneProgress
250
254
251
- // TODO: set client capabilities
252
- params .Capabilities .TextDocument .Completion .CompletionItem .TagSupport .ValueSet = []protocol.CompletionItemTag {protocol .ComplDeprecated }
255
+ // TODO(rfindley): set client capabilities (note from the future: why?)
253
256
257
+ params .Capabilities .TextDocument .Completion .CompletionItem .TagSupport .ValueSet = []protocol.CompletionItemTag {protocol .ComplDeprecated }
254
258
params .Capabilities .TextDocument .Completion .CompletionItem .SnippetSupport = true
255
259
params .Capabilities .TextDocument .SemanticTokens .Requests .Full .Value = true
256
260
// copied from lsp/semantic.go to avoid import cycle in tests
@@ -269,11 +273,12 @@ func (e *Editor) initialize(ctx context.Context) error {
269
273
// but really we should test both ways for older editors.
270
274
params .Capabilities .TextDocument .DocumentSymbol .HierarchicalDocumentSymbolSupport = true
271
275
272
- // This is a bit of a hack, since the fake editor doesn't actually support
273
- // watching changed files that match a specific glob pattern. However, the
274
- // editor does send didChangeWatchedFiles notifications, so set this to
275
- // true.
276
+ // Glob pattern watching is enabled.
276
277
params .Capabilities .Workspace .DidChangeWatchedFiles .DynamicRegistration = true
278
+
279
+ // "rename" operations are used for package renaming.
280
+ //
281
+ // TODO(rfindley): add support for other resource operations (create, delete, ...)
277
282
params .Capabilities .Workspace .WorkspaceEdit = & protocol.WorkspaceEditClientCapabilities {
278
283
ResourceOperations : []protocol.ResourceOperationKind {
279
284
"rename" ,
@@ -300,18 +305,15 @@ func (e *Editor) initialize(ctx context.Context) error {
300
305
return nil
301
306
}
302
307
303
- // makeWorkspaceFoldersLocked creates a slice of workspace folders to use for
308
+ // makeWorkspaceFolders creates a slice of workspace folders to use for
304
309
// this editing session, based on the editor configuration.
305
- //
306
- // e.mu must be held while calling this function.
307
- func (e * Editor ) makeWorkspaceFoldersLocked () (folders []protocol.WorkspaceFolder ) {
308
- paths := e .config .WorkspaceFolders
310
+ func makeWorkspaceFolders (sandbox * Sandbox , paths []string ) (folders []protocol.WorkspaceFolder ) {
309
311
if len (paths ) == 0 {
310
- paths = append ( paths , string ( e . sandbox .Workdir .RelativeTo ))
312
+ paths = [] string { string ( sandbox .Workdir .RelativeTo )}
311
313
}
312
314
313
315
for _ , path := range paths {
314
- uri := string (e . sandbox .Workdir .URI (path ))
316
+ uri := string (sandbox .Workdir .URI (path ))
315
317
folders = append (folders , protocol.WorkspaceFolder {
316
318
URI : uri ,
317
319
Name : filepath .Base (uri ),
@@ -1329,14 +1331,18 @@ func (e *Editor) Config() EditorConfig {
1329
1331
return e .config
1330
1332
}
1331
1333
1334
+ func (e * Editor ) SetConfig (cfg EditorConfig ) {
1335
+ e .mu .Lock ()
1336
+ e .config = cfg
1337
+ e .mu .Unlock ()
1338
+ }
1339
+
1332
1340
// ChangeConfiguration sets the new editor configuration, and if applicable
1333
1341
// sends a didChangeConfiguration notification.
1334
1342
//
1335
1343
// An error is returned if the change notification failed to send.
1336
1344
func (e * Editor ) ChangeConfiguration (ctx context.Context , newConfig EditorConfig ) error {
1337
- e .mu .Lock ()
1338
- e .config = newConfig
1339
- e .mu .Unlock () // don't hold e.mu during server calls
1345
+ e .SetConfig (newConfig )
1340
1346
if e .Server != nil {
1341
1347
var params protocol.DidChangeConfigurationParams // empty: gopls ignores the Settings field
1342
1348
if err := e .Server .DidChangeConfiguration (ctx , & params ); err != nil {
@@ -1351,12 +1357,13 @@ func (e *Editor) ChangeConfiguration(ctx context.Context, newConfig EditorConfig
1351
1357
//
1352
1358
// The given folders must all be unique.
1353
1359
func (e * Editor ) ChangeWorkspaceFolders (ctx context.Context , folders []string ) error {
1360
+ config := e .Config ()
1361
+
1354
1362
// capture existing folders so that we can compute the change.
1355
- e .mu .Lock ()
1356
- oldFolders := e .makeWorkspaceFoldersLocked ()
1357
- e .config .WorkspaceFolders = folders
1358
- newFolders := e .makeWorkspaceFoldersLocked ()
1359
- e .mu .Unlock ()
1363
+ oldFolders := makeWorkspaceFolders (e .sandbox , config .WorkspaceFolders )
1364
+ newFolders := makeWorkspaceFolders (e .sandbox , folders )
1365
+ config .WorkspaceFolders = folders
1366
+ e .SetConfig (config )
1360
1367
1361
1368
if e .Server == nil {
1362
1369
return nil
0 commit comments