Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/unreleased/lsp-no-root-sibling-scan.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- The language server no longer scans the filesystem root for sibling files when a document at the root is opened outside every workspace folder; the walk could take minutes.
8 changes: 6 additions & 2 deletions internal/frontend/lsp/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,16 +232,20 @@ func (s *Server) DidChangeWorkspaceFolders(ctx context.Context, params *protocol

// maxOpenedDirs bounds the directories the scan for an opened document's
// siblings visits: the document's directory was not chosen as a workspace, and
// may be a home directory or the filesystem root.
// may be a home directory.
const maxOpenedDirs = 2000

// indexOpenedDirectory indexes the directory of a document opened outside every
// folder, so sibling imports resolve; it is rescanned once all its documents close.
// folder, so sibling imports resolve; it is rescanned once all its documents
// close. The filesystem root is never indexed: walking it can take minutes.
func (s *Server) indexOpenedDirectory(name string) {
if !filepath.IsAbs(name) {
return
}
dir := filepath.Dir(name)
if dir == filepath.VolumeName(name)+string(filepath.Separator) {
return
}
s.mu.Lock()
if underAnyFolder(name, s.folders) || s.openDirs[dir] {
s.mu.Unlock()
Expand Down
24 changes: 24 additions & 0 deletions internal/frontend/lsp/files_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,30 @@ func TestOpeningFileOutsideFoldersIndexesItsDirectory(t *testing.T) {
}
}

// A document at the filesystem root indexes no siblings: scanning it would
// walk the whole filesystem.
func TestOpeningFileAtFilesystemRootIndexesNothing(t *testing.T) {
s := NewServer(model.NewWorkspace())
fc := &fakeClient{}
s.client = fc
ctx := context.Background()
if _, err := s.Initialize(ctx, &protocol.InitializeParams{}); err != nil {
t.Fatalf("Initialize err = %v", err)
}
if err := s.Initialized(ctx, &protocol.InitializedParams{}); err != nil {
t.Fatalf("Initialized err = %v", err)
}

name := filepath.Join(string(filepath.Separator), "m.sysml")
openFile(t, s, name, "package M {\n part def A;\n}\n")
if len(s.openDirs) != 0 {
t.Errorf("openDirs = %v, want none", s.openDirs)
}
if msgs := diagnosticsFor(fc, name); len(msgs) != 0 {
t.Fatalf("diagnostics for %s = %v, want none", name, msgs)
}
}

// The directory scan an open document triggers never overwrites another open
// buffer, whose text the editor owns.
func TestOpeningFileOutsideFoldersKeepsOpenBuffers(t *testing.T) {
Expand Down
Loading