Skip to content

Commit d5cd1f8

Browse files
rv32imagopherbot
authored andcommitted
gopls: add WorkspaceFiles option
WorkspaceFiles allows an end-user to specify a set of files which, when modified, will trigger a full reload of any views currently open in a session. This is especially important for users who use custom GOPACKAGESDRIVERS, as previously, you were forced to restart the language server in order to get up-to-date diagnostics in some certain instances. For golang/go#59625 Change-Id: Iba7a6137cb0b88a59318217a9a28d079100192a4 Reviewed-on: https://go-review.googlesource.com/c/tools/+/640076 Auto-Submit: Robert Findley <[email protected]> Reviewed-by: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 30bd6fd commit d5cd1f8

File tree

7 files changed

+93
-28
lines changed

7 files changed

+93
-28
lines changed

gopls/doc/settings.md

+10
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,16 @@ This setting is only supported when gopls is built with Go 1.16 or later.
143143

144144
Default: `["ignore"]`.
145145

146+
<a id='workspaceFiles'></a>
147+
### `workspaceFiles []string`
148+
149+
workspaceFiles configures the set of globs that match files defining the logical build of the current workspace.
150+
Any on-disk changes to any files matching a glob specified here will trigger a reload of the workspace.
151+
152+
This setting need only be customized in environments with a custom GOPACKAGESDRIVER.
153+
154+
Default: `[]`.
155+
146156
<a id='formatting'></a>
147157
## Formatting
148158

gopls/internal/cache/session.go

+23-17
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,25 @@ func (s *Session) DidModifyFiles(ctx context.Context, modifications []file.Modif
775775
// changed on disk.
776776
checkViews := false
777777

778+
// Hack: collect folders from existing views.
779+
// TODO(golang/go#57979): we really should track folders independent of
780+
// Views, but since we always have a default View for each folder, this
781+
// works for now.
782+
var folders []*Folder // preserve folder order
783+
workspaceFileGlobsSet := make(map[string]bool)
784+
seen := make(map[*Folder]unit)
785+
for _, v := range s.views {
786+
if _, ok := seen[v.folder]; ok {
787+
continue
788+
}
789+
seen[v.folder] = unit{}
790+
folders = append(folders, v.folder)
791+
for _, glob := range v.folder.Options.WorkspaceFiles {
792+
workspaceFileGlobsSet[glob] = true
793+
}
794+
}
795+
workspaceFileGlobs := slices.Collect(maps.Keys(workspaceFileGlobsSet))
796+
778797
changed := make(map[protocol.DocumentURI]file.Handle)
779798
for _, c := range modifications {
780799
fh := mustReadFile(ctx, s, c.URI)
@@ -790,7 +809,7 @@ func (s *Session) DidModifyFiles(ctx context.Context, modifications []file.Modif
790809
// TODO(rfindley): go.work files need not be named "go.work" -- we need to
791810
// check each view's source to handle the case of an explicit GOWORK value.
792811
// Write a test that fails, and fix this.
793-
if (isGoWork(c.URI) || isGoMod(c.URI)) && (c.Action == file.Save || c.OnDisk) {
812+
if (isGoWork(c.URI) || isGoMod(c.URI) || isWorkspaceFile(c.URI, workspaceFileGlobs)) && (c.Action == file.Save || c.OnDisk) {
794813
checkViews = true
795814
}
796815

@@ -817,20 +836,6 @@ func (s *Session) DidModifyFiles(ctx context.Context, modifications []file.Modif
817836
}
818837

819838
if checkViews {
820-
// Hack: collect folders from existing views.
821-
// TODO(golang/go#57979): we really should track folders independent of
822-
// Views, but since we always have a default View for each folder, this
823-
// works for now.
824-
var folders []*Folder // preserve folder order
825-
seen := make(map[*Folder]unit)
826-
for _, v := range s.views {
827-
if _, ok := seen[v.folder]; ok {
828-
continue
829-
}
830-
seen[v.folder] = unit{}
831-
folders = append(folders, v.folder)
832-
}
833-
834839
var openFiles []protocol.DocumentURI
835840
for _, o := range s.Overlays() {
836841
openFiles = append(openFiles, o.URI())
@@ -1085,11 +1090,12 @@ func (b brokenFile) Content() ([]byte, error) { return nil, b.err }
10851090
//
10861091
// This set includes
10871092
// 1. all go.mod and go.work files in the workspace; and
1088-
// 2. for each Snapshot, its modules (or directory for ad-hoc views). In
1093+
// 2. all files defined by the WorkspaceFiles option in BuildOptions (to support custom GOPACKAGESDRIVERS); and
1094+
// 3. for each Snapshot, its modules (or directory for ad-hoc views). In
10891095
// module mode, this is the set of active modules (and for VS Code, all
10901096
// workspace directories within them, due to golang/go#42348).
10911097
//
1092-
// The watch for workspace go.work and go.mod files in (1) is sufficient to
1098+
// The watch for workspace files in (1) is sufficient to
10931099
// capture changes to the repo structure that may affect the set of views.
10941100
// Whenever this set changes, we reload the workspace and invalidate memoized
10951101
// files.

gopls/internal/cache/snapshot.go

+22-11
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,10 @@ func (s *Snapshot) fileWatchingGlobPatterns() map[protocol.RelativePattern]unit
799799
patterns[workPattern] = unit{}
800800
}
801801

802+
for _, glob := range s.Options().WorkspaceFiles {
803+
patterns[protocol.RelativePattern{Pattern: glob}] = unit{}
804+
}
805+
802806
extensions := "go,mod,sum,work"
803807
for _, ext := range s.Options().TemplateExtensions {
804808
extensions += "," + ext
@@ -1540,24 +1544,31 @@ func (s *Snapshot) clone(ctx, bgCtx context.Context, changed StateChange, done f
15401544
}
15411545

15421546
reinit := false
1543-
1544-
// Changes to vendor tree may require reinitialization,
1545-
// either because of an initialization error
1546-
// (e.g. "inconsistent vendoring detected"), or because
1547-
// one or more modules may have moved into or out of the
1548-
// vendor tree after 'go mod vendor' or 'rm -fr vendor/'.
1549-
//
1550-
// In this case, we consider the actual modification to see if was a creation
1551-
// or deletion.
1552-
//
1553-
// TODO(rfindley): revisit the location of this check.
15541547
for _, mod := range changed.Modifications {
1548+
// Changes to vendor tree may require reinitialization,
1549+
// either because of an initialization error
1550+
// (e.g. "inconsistent vendoring detected"), or because
1551+
// one or more modules may have moved into or out of the
1552+
// vendor tree after 'go mod vendor' or 'rm -fr vendor/'.
1553+
//
1554+
// In this case, we consider the actual modification to see if was a creation
1555+
// or deletion.
1556+
//
1557+
// TODO(rfindley): revisit the location of this check.
15551558
if inVendor(mod.URI) && (mod.Action == file.Create || mod.Action == file.Delete) ||
15561559
strings.HasSuffix(string(mod.URI), "/vendor/modules.txt") {
15571560

15581561
reinit = true
15591562
break
15601563
}
1564+
1565+
// Changes to workspace files, as a rule of thumb, should require reinitialization. Since their behavior
1566+
// is generally user-defined, we want to do something sensible by re-triggering a query to the active GOPACKAGESDRIVER,
1567+
// and reloading the state of the workspace.
1568+
if isWorkspaceFile(mod.URI, s.view.folder.Options.WorkspaceFiles) && (mod.Action == file.Save || mod.OnDisk) {
1569+
reinit = true
1570+
break
1571+
}
15611572
}
15621573

15631574
// Collect observed file handles for changed URIs from the old snapshot, if

gopls/internal/cache/workspace.go

+16
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"golang.org/x/mod/modfile"
1414
"golang.org/x/tools/gopls/internal/file"
1515
"golang.org/x/tools/gopls/internal/protocol"
16+
"golang.org/x/tools/gopls/internal/test/integration/fake/glob"
1617
)
1718

1819
// isGoWork reports if uri is a go.work file.
@@ -65,6 +66,21 @@ func isGoMod(uri protocol.DocumentURI) bool {
6566
return filepath.Base(uri.Path()) == "go.mod"
6667
}
6768

69+
// isWorkspaceFile reports if uri matches a set of globs defined in workspaceFiles
70+
func isWorkspaceFile(uri protocol.DocumentURI, workspaceFiles []string) bool {
71+
for _, workspaceFile := range workspaceFiles {
72+
g, err := glob.Parse(workspaceFile)
73+
if err != nil {
74+
continue
75+
}
76+
77+
if g.Match(uri.Path()) {
78+
return true
79+
}
80+
}
81+
return false
82+
}
83+
6884
// goModModules returns the URIs of "workspace" go.mod files defined by a
6985
// go.mod file. This set is defined to be the given go.mod file itself, as well
7086
// as the modfiles of any locally replaced modules in the go.mod file.

gopls/internal/doc/api.json

+13
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@
9999
"Hierarchy": "build",
100100
"DeprecationMessage": ""
101101
},
102+
{
103+
"Name": "workspaceFiles",
104+
"Type": "[]string",
105+
"Doc": "workspaceFiles configures the set of globs that match files defining the logical build of the current workspace.\nAny on-disk changes to any files matching a glob specified here will trigger a reload of the workspace.\n\nThis setting need only be customized in environments with a custom GOPACKAGESDRIVER.\n",
106+
"EnumKeys": {
107+
"ValueType": "",
108+
"Keys": null
109+
},
110+
"EnumValues": null,
111+
"Default": "[]",
112+
"Status": "",
113+
"Hierarchy": "build"
114+
},
102115
{
103116
"Name": "hoverKind",
104117
"Type": "enum",

gopls/internal/settings/default.go

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ func DefaultOptions(overrides ...func(*Options)) *Options {
8787
DirectoryFilters: []string{"-**/node_modules"},
8888
TemplateExtensions: []string{},
8989
StandaloneTags: []string{"ignore"},
90+
WorkspaceFiles: []string{},
9091
},
9192
UIOptions: UIOptions{
9293
DiagnosticOptions: DiagnosticOptions{

gopls/internal/settings/settings.go

+8
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ type BuildOptions struct {
141141
//
142142
// This setting is only supported when gopls is built with Go 1.16 or later.
143143
StandaloneTags []string
144+
145+
// WorkspaceFiles configures the set of globs that match files defining the logical build of the current workspace.
146+
// Any on-disk changes to any files matching a glob specified here will trigger a reload of the workspace.
147+
//
148+
// This setting need only be customized in environments with a custom GOPACKAGESDRIVER.
149+
WorkspaceFiles []string
144150
}
145151

146152
// Note: UIOptions must be comparable with reflect.DeepEqual.
@@ -970,6 +976,8 @@ func (o *Options) setOne(name string, value any) error {
970976
}
971977
o.DirectoryFilters = filters
972978

979+
case "workspaceFiles":
980+
return setStringSlice(&o.WorkspaceFiles, value)
973981
case "completionDocumentation":
974982
return setBool(&o.CompletionDocumentation, value)
975983
case "usePlaceholders":

0 commit comments

Comments
 (0)