Skip to content

Commit fcfedab

Browse files
committed
Actually find and load the original location projects
1 parent 5d230c1 commit fcfedab

File tree

26 files changed

+664
-63
lines changed

26 files changed

+664
-63
lines changed

internal/project/dirty/set.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package dirty
2+
3+
import "maps"
4+
5+
type SetEntry[K comparable] struct {
6+
m *Set[K]
7+
mapEntry[K, struct{}]
8+
}
9+
10+
func (e *SetEntry[K]) Delete() {
11+
if !e.dirty {
12+
e.m.dirty[e.key] = e
13+
}
14+
e.delete = true
15+
}
16+
17+
type Set[K comparable] struct {
18+
base map[K]struct{}
19+
dirty map[K]*SetEntry[K]
20+
}
21+
22+
func NewSet[K comparable](base map[K]struct{}) *Set[K] {
23+
return &Set[K]{
24+
base: base,
25+
dirty: make(map[K]*SetEntry[K]),
26+
}
27+
}
28+
29+
func (m *Set[K]) Get(key K) (*SetEntry[K], bool) {
30+
if entry, ok := m.dirty[key]; ok {
31+
if entry.delete {
32+
return nil, false
33+
}
34+
return entry, true
35+
}
36+
value, ok := m.base[key]
37+
if !ok {
38+
return nil, false
39+
}
40+
return &SetEntry[K]{
41+
m: m,
42+
mapEntry: mapEntry[K, struct{}]{
43+
key: key,
44+
original: value,
45+
value: value,
46+
dirty: false,
47+
},
48+
}, true
49+
}
50+
51+
func (m *Set[K]) Has(key K) bool {
52+
if entry, ok := m.dirty[key]; ok {
53+
if entry.delete {
54+
return false
55+
}
56+
return true
57+
}
58+
_, ok := m.base[key]
59+
return ok
60+
}
61+
62+
// Add sets a new entry in the dirty map without checking if it exists
63+
// in the base map. The entry added is considered dirty, so it should
64+
// be a fresh value, mutable until finalized (i.e., it will not be cloned
65+
// before changing if a change is made). If modifying an entry that may
66+
// exist in the base map, use `Change` instead.
67+
func (m *Set[K]) Add(key K) {
68+
m.dirty[key] = &SetEntry[K]{
69+
m: m,
70+
mapEntry: mapEntry[K, struct{}]{
71+
key: key,
72+
value: struct{}{},
73+
dirty: true,
74+
},
75+
}
76+
}
77+
78+
func (m *Set[K]) Delete(key K) {
79+
if entry, ok := m.Get(key); ok {
80+
entry.Delete()
81+
} else {
82+
panic("tried to delete a non-existent entry")
83+
}
84+
}
85+
86+
func (m *Set[K]) Range(fn func(*SetEntry[K]) bool) {
87+
seenInDirty := make(map[K]struct{})
88+
for _, entry := range m.dirty {
89+
seenInDirty[entry.key] = struct{}{}
90+
if !entry.delete && !fn(entry) {
91+
break
92+
}
93+
}
94+
for key, value := range m.base {
95+
if _, ok := seenInDirty[key]; ok {
96+
continue // already processed in dirty entries
97+
}
98+
if !fn(&SetEntry[K]{m: m, mapEntry: mapEntry[K, struct{}]{
99+
key: key,
100+
original: value,
101+
value: value,
102+
dirty: false,
103+
}}) {
104+
break
105+
}
106+
}
107+
}
108+
109+
func (m *Set[K]) Finalize() (result map[K]struct{}, changed bool) {
110+
if len(m.dirty) == 0 {
111+
return m.base, false // no changes, return base map
112+
}
113+
if m.base == nil {
114+
result = make(map[K]struct{}, len(m.dirty))
115+
} else {
116+
result = maps.Clone(m.base)
117+
}
118+
for key, entry := range m.dirty {
119+
if entry.delete {
120+
delete(result, key)
121+
} else {
122+
result[key] = entry.value
123+
}
124+
}
125+
return result, true
126+
}

internal/project/projectcollection.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ type ProjectCollection struct {
2727
// apiOpenedProjects is the set of projects that should be kept open for
2828
// API clients.
2929
apiOpenedProjects map[tspath.Path]struct{}
30+
// Files that are open
31+
openedFiles map[tspath.Path]struct{}
3032
}
3133

3234
func (c *ProjectCollection) ConfigFileRegistry() *ConfigFileRegistry { return c.configFileRegistry }
@@ -229,6 +231,7 @@ func (c *ProjectCollection) clone() *ProjectCollection {
229231
configuredProjects: c.configuredProjects,
230232
inferredProject: c.inferredProject,
231233
fileDefaultProjects: c.fileDefaultProjects,
234+
openedFiles: c.openedFiles,
232235
}
233236
}
234237

internal/project/projectcollectionbuilder.go

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ type ProjectCollectionBuilder struct {
3838

3939
newSnapshotID uint64
4040
programStructureChanged bool
41-
fileDefaultProjects map[tspath.Path]tspath.Path
42-
configuredProjects *dirty.SyncMap[tspath.Path, *Project]
43-
inferredProject *dirty.Box[*Project]
41+
42+
fileDefaultProjects map[tspath.Path]tspath.Path
43+
configuredProjects *dirty.SyncMap[tspath.Path, *Project]
44+
inferredProject *dirty.Box[*Project]
45+
openedFiles *dirty.Set[tspath.Path]
4446

4547
apiOpenedProjects map[tspath.Path]struct{}
4648
}
@@ -69,6 +71,7 @@ func newProjectCollectionBuilder(
6971
newSnapshotID: newSnapshotID,
7072
configuredProjects: dirty.NewSyncMap(oldProjectCollection.configuredProjects, nil),
7173
inferredProject: dirty.NewBox(oldProjectCollection.inferredProject),
74+
openedFiles: dirty.NewSet(oldProjectCollection.openedFiles),
7275
apiOpenedProjects: maps.Clone(oldAPIOpenedProjects),
7376
}
7477
}
@@ -98,6 +101,11 @@ func (b *ProjectCollectionBuilder) Finalize(logger *logging.LogTree) (*ProjectCo
98101
newProjectCollection.inferredProject = newInferredProject
99102
}
100103

104+
if openedFiles, openedFilesChanged := b.openedFiles.Finalize(); openedFilesChanged {
105+
ensureCloned()
106+
newProjectCollection.openedFiles = openedFiles
107+
}
108+
101109
configFileRegistry := b.configFileRegistryBuilder.Finalize()
102110
newProjectCollection.configFileRegistry = configFileRegistry
103111
return newProjectCollection, configFileRegistry
@@ -174,6 +182,7 @@ func (b *ProjectCollectionBuilder) DidChangeFiles(summary FileChangeSummary, log
174182
if fh := b.fs.GetFileByPath(fileName, path); fh == nil || fh.Hash() != hash {
175183
changedFiles = append(changedFiles, path)
176184
}
185+
b.openedFiles.Delete(path)
177186
}
178187
for uri := range summary.Changed.Keys() {
179188
fileName := uri.FileName()
@@ -242,8 +251,9 @@ func (b *ProjectCollectionBuilder) DidChangeFiles(summary FileChangeSummary, log
242251
if summary.Opened != "" {
243252
fileName := summary.Opened.FileName()
244253
path := b.toPath(fileName)
254+
b.openedFiles.Add(path)
245255
var toRemoveProjects collections.Set[tspath.Path]
246-
openFileResult := b.ensureConfiguredProjectAndAncestorsForOpenFile(fileName, path, logger)
256+
openFileResult := b.ensureConfiguredProjectAndAncestorsForFile(fileName, path, logger)
247257
b.configuredProjects.Range(func(entry *dirty.SyncMapEntry[tspath.Path, *Project]) bool {
248258
toRemoveProjects.Add(entry.Value().configFilePath)
249259
b.updateProgram(entry, logger)
@@ -357,6 +367,23 @@ func (b *ProjectCollectionBuilder) DidRequestProject(projectId tspath.Path, logg
357367
}
358368
}
359369

370+
func (b *ProjectCollectionBuilder) DidRequestEnsureDefaultProject(uri lsproto.DocumentUri, logger *logging.LogTree) {
371+
fileName := uri.FileName()
372+
path := b.toPath(fileName)
373+
if b.openedFiles.Has(path) {
374+
b.DidRequestFile(uri, logger)
375+
return
376+
}
377+
378+
startTime := time.Now()
379+
b.ensureConfiguredProjectAndAncestorsForFile(fileName, path, logger)
380+
381+
if logger != nil {
382+
elapsed := time.Since(startTime)
383+
logger.Log(fmt.Sprintf("Completed file request for %s in %v", fileName, elapsed))
384+
}
385+
}
386+
360387
func (b *ProjectCollectionBuilder) DidUpdateATAState(ataChanges map[tspath.Path]*ATAStateChange, logger *logging.LogTree) {
361388
updateProject := func(project dirty.Value[*Project], ataChange *ATAStateChange) {
362389
project.ChangeIf(
@@ -427,7 +454,7 @@ func (b *ProjectCollectionBuilder) markProjectsAffectedByConfigChanges(
427454
var hasChanges bool
428455
for path := range configChangeResult.affectedFiles {
429456
fileName := b.fs.overlays[path].FileName()
430-
_ = b.ensureConfiguredProjectAndAncestorsForOpenFile(fileName, path, logger)
457+
_ = b.ensureConfiguredProjectAndAncestorsForFile(fileName, path, logger)
431458
hasChanges = true
432459
}
433460

@@ -468,17 +495,17 @@ func (b *ProjectCollectionBuilder) findDefaultConfiguredProject(fileName string,
468495
})
469496

470497
if multipleCandidates {
471-
if p := b.findOrCreateDefaultConfiguredProjectForOpenScriptInfo(fileName, path, projectLoadKindFind, nil).project; p != nil {
498+
if p := b.findOrCreateDefaultConfiguredProjectForFile(fileName, path, projectLoadKindFind, nil).project; p != nil {
472499
return p
473500
}
474501
}
475502

476503
return configuredProjects[project]
477504
}
478505

479-
func (b *ProjectCollectionBuilder) ensureConfiguredProjectAndAncestorsForOpenFile(fileName string, path tspath.Path, logger *logging.LogTree) searchResult {
480-
result := b.findOrCreateDefaultConfiguredProjectForOpenScriptInfo(fileName, path, projectLoadKindCreate, logger)
481-
if result.project != nil {
506+
func (b *ProjectCollectionBuilder) ensureConfiguredProjectAndAncestorsForFile(fileName string, path tspath.Path, logger *logging.LogTree) searchResult {
507+
result := b.findOrCreateDefaultConfiguredProjectForFile(fileName, path, projectLoadKindCreate, logger)
508+
if result.project != nil && b.openedFiles.Has(path) {
482509
// !!! sheetal todo this later
483510
// // Create ancestor tree for findAllRefs (dont load them right away)
484511
// forEachAncestorProjectLoad(
@@ -672,7 +699,7 @@ func (b *ProjectCollectionBuilder) findOrCreateDefaultConfiguredProjectWorker(
672699
return searchResult{retain: retain}
673700
}
674701

675-
func (b *ProjectCollectionBuilder) findOrCreateDefaultConfiguredProjectForOpenScriptInfo(
702+
func (b *ProjectCollectionBuilder) findOrCreateDefaultConfiguredProjectForFile(
676703
fileName string,
677704
path tspath.Path,
678705
loadKind projectLoadKind,

0 commit comments

Comments
 (0)