Skip to content

Commit 3986990

Browse files
committed
internal/lsp: lowercase drive letters on Windows to fix file watching
This is a work-around for microsoft/vscode#104387. We now always lowercase the drive letter on Windows. This CL also fixes a bug introduced by CL 245327, which caused URIs to be used instead of paths in the GlobPattern. We really need VS Code integration tests for this (golang/vscode-go#404). Updates golang/go#40661 Change-Id: I21be6d929288cfe41168cea34001fc2f41ac6c8b Reviewed-on: https://go-review.googlesource.com/c/tools/+/247684 Run-TryBot: Rebecca Stambler <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
1 parent eb8585a commit 3986990

File tree

3 files changed

+43
-19
lines changed

3 files changed

+43
-19
lines changed

internal/lsp/general.go

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"io"
1212
"os"
1313
"path"
14+
"path/filepath"
15+
"strings"
1416
"sync"
1517

1618
"golang.org/x/tools/internal/event"
@@ -46,6 +48,10 @@ func (s *Server) initialize(ctx context.Context, params *protocol.ParamInitializ
4648
if params.RootURI != "" && !params.RootURI.SpanURI().IsFile() {
4749
return nil, fmt.Errorf("unsupported URI scheme: %v (gopls only supports file URIs)", params.RootURI)
4850
}
51+
if params.RootURI != "" {
52+
s.rootURI = params.RootURI.SpanURI()
53+
}
54+
4955
for _, folder := range params.WorkspaceFolders {
5056
uri := span.URIFromURI(folder.URI)
5157
if !uri.IsFile() {
@@ -144,20 +150,6 @@ func (s *Server) initialized(ctx context.Context, params *protocol.InitializedPa
144150
options := s.session.Options()
145151
defer func() { s.session.SetOptions(options) }()
146152

147-
var registrations []protocol.Registration
148-
if options.ConfigurationSupported && options.DynamicConfigurationSupported {
149-
registrations = append(registrations,
150-
protocol.Registration{
151-
ID: "workspace/didChangeConfiguration",
152-
Method: "workspace/didChangeConfiguration",
153-
},
154-
protocol.Registration{
155-
ID: "workspace/didChangeWorkspaceFolders",
156-
Method: "workspace/didChangeWorkspaceFolders",
157-
},
158-
)
159-
}
160-
161153
// TODO: this event logging may be unnecessary.
162154
// The version info is included in the initialize response.
163155
buf := &bytes.Buffer{}
@@ -169,9 +161,18 @@ func (s *Server) initialized(ctx context.Context, params *protocol.InitializedPa
169161
}
170162
s.pendingFolders = nil
171163

172-
if len(registrations) > 0 {
164+
if options.ConfigurationSupported && options.DynamicConfigurationSupported {
173165
if err := s.client.RegisterCapability(ctx, &protocol.RegistrationParams{
174-
Registrations: registrations,
166+
Registrations: []protocol.Registration{
167+
{
168+
ID: "workspace/didChangeConfiguration",
169+
Method: "workspace/didChangeConfiguration",
170+
},
171+
{
172+
ID: "workspace/didChangeWorkspaceFolders",
173+
Method: "workspace/didChangeWorkspaceFolders",
174+
},
175+
},
175176
}); err != nil {
176177
return err
177178
}
@@ -322,10 +323,25 @@ func (s *Server) registerWatchedDirectoriesLocked(ctx context.Context, dirs map[
322323
for k := range s.watchedDirectories {
323324
delete(s.watchedDirectories, k)
324325
}
325-
var watchers []protocol.FileSystemWatcher
326+
// Work-around microsoft/vscode#100870 by making sure that we are,
327+
// at least, watching the user's entire workspace. This will still be
328+
// applied to every folder in the workspace.
329+
watchers := []protocol.FileSystemWatcher{{
330+
GlobPattern: "**/*.{go,mod,sum}",
331+
Kind: float64(protocol.WatchChange + protocol.WatchDelete + protocol.WatchCreate),
332+
}}
326333
for dir := range dirs {
334+
filename := dir.Filename()
335+
// If the directory is within the root URI, we're already watching it
336+
// via the relative path above.
337+
if isSubdirectory(s.rootURI.Filename(), filename) {
338+
continue
339+
}
340+
// If microsoft/vscode#100870 is resolved before
341+
// microsoft/vscode#104387, we will need a work-around for Windows
342+
// drive letter casing.
327343
watchers = append(watchers, protocol.FileSystemWatcher{
328-
GlobPattern: fmt.Sprintf("%s/**/*.{go,mod,sum}", dir),
344+
GlobPattern: fmt.Sprintf("%s/**/*.{go,mod,sum}", filename),
329345
Kind: float64(protocol.WatchChange + protocol.WatchDelete + protocol.WatchCreate),
330346
})
331347
}
@@ -348,6 +364,11 @@ func (s *Server) registerWatchedDirectoriesLocked(ctx context.Context, dirs map[
348364
return nil
349365
}
350366

367+
func isSubdirectory(root, leaf string) bool {
368+
rel, err := filepath.Rel(root, leaf)
369+
return err == nil && !strings.HasPrefix(rel, "..")
370+
}
371+
351372
func (s *Server) fetchConfig(ctx context.Context, name string, folder span.URI, o *source.Options) error {
352373
if !s.session.Options().ConfigurationSupported {
353374
return nil

internal/lsp/server.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ type Server struct {
6464

6565
session source.Session
6666

67+
// rootURI is the root of the workspace opened in the editor (if any).
68+
rootURI span.URI
69+
6770
// changedFiles tracks files for which there has been a textDocument/didChange.
6871
changedFilesMu sync.Mutex
6972
changedFiles map[span.URI]struct{}

internal/span/uri.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func isWindowsDrivePath(path string) bool {
160160

161161
// isWindowsDriveURI returns true if the file URI is of the format used by
162162
// Windows URIs. The url.Parse package does not specially handle Windows paths
163-
// (see golang/go#6027). We check if the URI path has a drive prefix (e.g. "/C:").
163+
// (see golang/go#6027), so we check if the URI path has a drive prefix (e.g. "/C:").
164164
func isWindowsDriveURIPath(uri string) bool {
165165
if len(uri) < 4 {
166166
return false

0 commit comments

Comments
 (0)