Skip to content

Commit cefaa17

Browse files
committed
[in progress] project system work - major code reorg
1 parent cf616dc commit cefaa17

7 files changed

Lines changed: 385 additions & 329 deletions

File tree

src/server/editorServices.ts

Lines changed: 299 additions & 256 deletions
Large diffs are not rendered by default.

src/server/lshost.ts

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ namespace ts.server {
7272
return this.project.getProjectVersion();
7373
}
7474

75+
getCompilationSettings() {
76+
return this.compilationSettings;
77+
}
78+
7579
getCancellationToken() {
7680
return this.cancellationToken;
7781
}
@@ -90,53 +94,30 @@ namespace ts.server {
9094
}
9195

9296
getScriptSnapshot(filename: string): ts.IScriptSnapshot {
93-
const scriptInfo = this.project.getScriptInfo(filename);
97+
const scriptInfo = this.project.getScriptInfoLSHost(filename);
9498
if (scriptInfo) {
9599
return scriptInfo.snap();
96100
}
97101
}
98102

99-
setCompilationSettings(opt: ts.CompilerOptions) {
100-
this.compilationSettings = opt;
101-
// conservatively assume that changing compiler options might affect module resolution strategy
102-
this.resolvedModuleNames.clear();
103-
this.resolvedTypeReferenceDirectives.clear();
104-
}
105-
106-
getCompilationSettings() {
107-
// change this to return active project settings for file
108-
return this.compilationSettings;
109-
}
110-
111103
getScriptFileNames() {
112104
return this.project.getRootFiles();
113105
}
114106

115107
getScriptKind(fileName: string) {
116-
const info = this.project.getScriptInfo(fileName);
108+
const info = this.project.getScriptInfoLSHost(fileName);
117109
return info && info.scriptKind;
118110
}
119111

120112
getScriptVersion(filename: string) {
121-
return this.project.getScriptInfo(filename).getLatestVersion();
113+
const info = this.project.getScriptInfoLSHost(filename);
114+
return info && info.getLatestVersion();
122115
}
123116

124117
getCurrentDirectory(): string {
125118
return "";
126119
}
127120

128-
removeReferencedFile(info: ScriptInfo) {
129-
if (!info.isOpen) {
130-
this.resolvedModuleNames.remove(info.path);
131-
this.resolvedTypeReferenceDirectives.remove(info.path);
132-
}
133-
}
134-
135-
removeRoot(info: ScriptInfo) {
136-
this.resolvedModuleNames.remove(info.path);
137-
this.resolvedTypeReferenceDirectives.remove(info.path);
138-
}
139-
140121
resolvePath(path: string): string {
141122
return this.host.resolvePath(path);
142123
}
@@ -156,5 +137,17 @@ namespace ts.server {
156137
getDirectories(path: string): string[] {
157138
return this.host.getDirectories(path);
158139
}
140+
141+
notifyFileRemoved(info: ScriptInfo) {
142+
this.resolvedModuleNames.remove(info.path);
143+
this.resolvedTypeReferenceDirectives.remove(info.path);
144+
}
145+
146+
setCompilationSettings(opt: ts.CompilerOptions) {
147+
this.compilationSettings = opt;
148+
// conservatively assume that changing compiler options might affect module resolution strategy
149+
this.resolvedModuleNames.clear();
150+
this.resolvedTypeReferenceDirectives.clear();
151+
}
159152
}
160153
}

src/server/project.ts

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,22 @@
44
/// <reference path="lshost.ts"/>
55

66
namespace ts.server {
7+
78
export enum ProjectKind {
89
Inferred,
910
Configured,
1011
External
1112
}
1213

14+
function remove<T>(items: T[], item: T) {
15+
const index = items.indexOf(item);
16+
if (index >= 0) {
17+
items.splice(index, 1);
18+
}
19+
}
20+
1321
export abstract class Project {
14-
private rootFiles: ScriptInfo[] = [];
22+
private readonly rootFiles: ScriptInfo[] = [];
1523
private readonly rootFilesMap: FileMap<ScriptInfo> = createFileMap<ScriptInfo>();
1624
private lsHost: ServerLanguageServiceHost;
1725
private program: ts.Program;
@@ -130,10 +138,8 @@ namespace ts.server {
130138

131139
containsFile(filename: NormalizedPath, requireOpen?: boolean) {
132140
const info = this.projectService.getScriptInfoForNormalizedPath(filename);
133-
if (info) {
134-
if ((!requireOpen) || info.isOpen) {
135-
return this.containsScriptInfo(info);
136-
}
141+
if (info && (info.isOpen || !requireOpen)) {
142+
return this.containsScriptInfo(info);
137143
}
138144
}
139145

@@ -153,12 +159,13 @@ namespace ts.server {
153159
}
154160

155161
removeFile(info: ScriptInfo, detachFromProject: boolean = true) {
156-
if (!this.removeRoot(info)) {
157-
this.removeReferencedFile(info)
158-
}
162+
this.removeRootFileIfNecessary(info);
163+
this.lsHost.notifyFileRemoved(info);
164+
159165
if (detachFromProject) {
160166
info.detachFromProject(this);
161167
}
168+
162169
this.markAsDirty();
163170
}
164171

@@ -179,14 +186,31 @@ namespace ts.server {
179186
// - newProgram is different from the old program and structure of the old program was not reused.
180187
if (!oldProgram || (this.program !== oldProgram && !oldProgram.structureIsReused)) {
181188
this.projectStructureVersion++;
189+
if (oldProgram) {
190+
for (const f of oldProgram.getSourceFiles()) {
191+
if (!this.program.getSourceFileByPath(f.path)) {
192+
// new program does not contain this file - detach it from the project
193+
const scriptInfoToDetach = this.projectService.getScriptInfo(f.fileName);
194+
if (scriptInfoToDetach) {
195+
scriptInfoToDetach.detachFromProject(this);
196+
}
197+
}
198+
}
199+
}
182200
}
183201
}
184202

203+
getScriptInfoLSHost(fileName: string) {
204+
const scriptInfo = this.projectService.getOrCreateScriptInfo(fileName, /*openedByClient*/ false);
205+
if (scriptInfo) {
206+
scriptInfo.attachToProject(this);
207+
}
208+
return scriptInfo;
209+
}
210+
185211
getScriptInfoForNormalizedPath(fileName: NormalizedPath) {
186212
const scriptInfo = this.projectService.getOrCreateScriptInfoForNormalizedPath(fileName, /*openedByClient*/ false);
187-
if (scriptInfo && scriptInfo.attachToProject(this)) {
188-
this.markAsDirty();
189-
}
213+
Debug.assert(!scriptInfo || scriptInfo.isAttached(this));
190214
return scriptInfo;
191215
}
192216

@@ -215,19 +239,23 @@ namespace ts.server {
215239
}
216240
}
217241

218-
saveTo(filename: string, tmpfilename: string) {
219-
const script = this.getScriptInfo(filename);
242+
saveTo(filename: NormalizedPath, tmpfilename: NormalizedPath) {
243+
const script = this.projectService.getScriptInfoForNormalizedPath(filename);
220244
if (script) {
245+
Debug.assert(script.isAttached(this));
221246
const snap = script.snap();
222247
this.projectService.host.writeFile(tmpfilename, snap.getText(0, snap.getLength()));
223248
}
224249
}
225250

226-
reloadScript(filename: NormalizedPath, cb: () => void) {
227-
const script = this.getScriptInfoForNormalizedPath(filename);
251+
reloadScript(filename: NormalizedPath): boolean {
252+
const script = this.projectService.getScriptInfoForNormalizedPath(filename);
228253
if (script) {
229-
script.reloadFromFile(filename, cb);
254+
Debug.assert(script.isAttached(this));
255+
script.reloadFromFile();
256+
return true;
230257
}
258+
return false;
231259
}
232260

233261
getChangesSinceVersion(lastKnownVersion?: number): protocol.ProjectFiles {
@@ -274,18 +302,11 @@ namespace ts.server {
274302
}
275303

276304
// remove a root file from project
277-
private removeRoot(info: ScriptInfo): boolean {
305+
private removeRootFileIfNecessary(info: ScriptInfo): void {
278306
if (this.isRoot(info)) {
279-
this.rootFiles = copyListRemovingItem(info, this.rootFiles);
307+
remove(this.rootFiles, info);
280308
this.rootFilesMap.remove(info.path);
281-
this.lsHost.removeRoot(info);
282-
return true;
283309
}
284-
return false;
285-
}
286-
287-
private removeReferencedFile(info: ScriptInfo) {
288-
this.lsHost.removeReferencedFile(info)
289310
}
290311
}
291312

src/server/scriptInfo.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
namespace ts.server {
44

55
export class ScriptInfo {
6-
private svc: ScriptVersionCache;
76
/**
87
* All projects that include this file
98
*/
109
readonly containingProjects: Project[] = [];
10+
readonly formatCodeSettings: ts.FormatCodeSettings;
11+
readonly path: Path;
1112

1213
private fileWatcher: FileWatcher;
13-
formatCodeSettings: ts.FormatCodeSettings;
14-
readonly path: Path;
14+
private svc: ScriptVersionCache;
1515

1616
constructor(
1717
private readonly host: ServerHost,
@@ -29,11 +29,15 @@ namespace ts.server {
2929
}
3030

3131
attachToProject(project: Project): boolean {
32-
if (!contains(this.containingProjects, project)) {
32+
const isNew = !this.isAttached(project);
33+
if (isNew) {
3334
this.containingProjects.push(project);
34-
return true;
3535
}
36-
return false;
36+
return isNew;
37+
}
38+
39+
isAttached(project: Project) {
40+
return contains(this.containingProjects, project);
3741
}
3842

3943
detachFromProject(project: Project) {
@@ -80,8 +84,8 @@ namespace ts.server {
8084
this.markContainingProjectsAsDirty();
8185
}
8286

83-
reloadFromFile(fileName: string, cb?: () => void) {
84-
this.svc.reloadFromFile(fileName, cb)
87+
reloadFromFile() {
88+
this.svc.reloadFromFile(this.fileName);
8589
this.markContainingProjectsAsDirty();
8690
}
8791

src/server/scriptVersionCache.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,16 +297,14 @@ namespace ts.server {
297297
return this.currentVersion;
298298
}
299299

300-
reloadFromFile(filename: string, cb?: () => void) {
300+
reloadFromFile(filename: string) {
301301
let content = this.host.readFile(filename);
302302
// If the file doesn't exist or cannot be read, we should
303303
// wipe out its cached content on the server to avoid side effects.
304304
if (!content) {
305305
content = "";
306306
}
307307
this.reload(content);
308-
if (cb)
309-
cb();
310308
}
311309

312310
// reload whole script, leaving no change history behind reload

src/server/session.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,7 @@ namespace ts.server {
10181018
scriptInfo.editContent(start, end, args.insertString);
10191019
this.changeSeq++;
10201020
}
1021-
this.updateProjectStructure(this.changeSeq, (n) => n === this.changeSeq);
1021+
this.updateProjectStructure(this.changeSeq, n => n === this.changeSeq);
10221022
}
10231023
}
10241024

@@ -1028,15 +1028,15 @@ namespace ts.server {
10281028
if (project) {
10291029
this.changeSeq++;
10301030
// make sure no changes happen before this one is finished
1031-
project.reloadScript(file, () => {
1031+
if (project.reloadScript(file)) {
10321032
this.output(undefined, CommandNames.Reload, reqSeq);
1033-
});
1033+
}
10341034
}
10351035
}
10361036

10371037
private saveToTmp(fileName: string, tempFileName: string) {
10381038
const file = toNormalizedPath(fileName);
1039-
const tmpfile = ts.normalizePath(tempFileName);
1039+
const tmpfile = toNormalizedPath(tempFileName);
10401040

10411041
const project = this.projectService.getDefaultProjectForFile(file);
10421042
if (project) {
@@ -1267,6 +1267,7 @@ namespace ts.server {
12671267
},
12681268
[CommandNames.ApplyChangedToOpenFiles]: (request: protocol.ApplyChangedToOpenFilesRequest) => {
12691269
this.projectService.applyChangesInOpenFiles(request.arguments.openFiles, request.arguments.changedFiles, request.arguments.closedFiles);
1270+
this.changeSeq++;
12701271
// TODO: report errors
12711272
return this.requiredResponse(true);
12721273
},

src/server/utilities.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,17 +140,13 @@ namespace ts.server {
140140
};
141141

142142
export interface ServerLanguageServiceHost {
143-
getCompilationSettings(): CompilerOptions;
144143
setCompilationSettings(options: CompilerOptions): void;
145-
removeRoot(info: ScriptInfo): void;
146-
removeReferencedFile(info: ScriptInfo): void;
144+
notifyFileRemoved(info: ScriptInfo): void;
147145
}
148146

149147
export const nullLanguageServiceHost: ServerLanguageServiceHost = {
150-
getCompilationSettings: () => undefined,
151148
setCompilationSettings: () => undefined,
152-
removeRoot: () => undefined,
153-
removeReferencedFile: () => undefined
149+
notifyFileRemoved: () => undefined
154150
};
155151

156152
export interface ProjectOptions {

0 commit comments

Comments
 (0)