diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 5b5ee27d707..d7eda52ce38 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -65,6 +65,7 @@ module ts.server { ls: ts.LanguageService = null; compilationSettings: ts.CompilerOptions; filenameToScript: ts.Map = {}; + roots: ScriptInfo[] = []; constructor(public host: ServerHost, public project: Project) { } @@ -144,7 +145,7 @@ module ts.server { var scriptInfo = ts.lookUp(this.filenameToScript, info.fileName); if (!scriptInfo) { this.filenameToScript[info.fileName] = info; - return info; + this.roots.push(info); } } @@ -286,10 +287,12 @@ module ts.server { return this.filenameToSourceFile[info.fileName]; } - getSourceFileFromName(filename: string) { + getSourceFileFromName(filename: string, requireOpen?: boolean) { var info = this.projectService.getScriptInfo(filename); if (info) { - return this.getSourceFile(info); + if ((!requireOpen) || info.isOpen) { + return this.getSourceFile(info); + } } } @@ -324,7 +327,7 @@ module ts.server { // add a root file to project addRoot(info: ScriptInfo) { info.defaultProject = this; - return this.compilerService.host.addRoot(info); + this.compilerService.host.addRoot(info); } filesToString() { @@ -360,7 +363,7 @@ module ts.server { } interface ProjectServiceEventHandler { - (eventName: string, project: Project): void; + (eventName: string, project: Project, fileName: string): void; } export class ProjectService { @@ -392,7 +395,6 @@ module ts.server { } } - log(msg: string, type = "Err") { this.psLogger.msg(msg, type); } @@ -423,7 +425,20 @@ module ts.server { for (var i = 0, len = referencingProjects.length; i < len; i++) { referencingProjects[i].removeReferencedFile(info); } + for (var j = 0, flen = this.openFileRoots.length; j < flen; j++) { + var openFile = this.openFileRoots[j]; + if (this.eventHandler) { + this.eventHandler("context", openFile.defaultProject, openFile.fileName); + } + } + for (var j = 0, flen = this.openFilesReferenced.length; j < flen; j++) { + var openFile = this.openFilesReferenced[j]; + if (this.eventHandler) { + this.eventHandler("context", openFile.defaultProject, openFile.fileName); + } + } } + this.printProjects(); } @@ -503,19 +518,52 @@ module ts.server { info.close(); } - findReferencingProjects(info: ScriptInfo) { + findReferencingProjects(info: ScriptInfo, excludedProject?: Project) { var referencingProjects: Project[] = []; info.defaultProject = undefined; for (var i = 0, len = this.inferredProjects.length; i < len; i++) { this.inferredProjects[i].updateGraph(); - if (this.inferredProjects[i].getSourceFile(info)) { - info.defaultProject = this.inferredProjects[i]; - referencingProjects.push(this.inferredProjects[i]); + if (this.inferredProjects[i] != excludedProject) { + if (this.inferredProjects[i].getSourceFile(info)) { + info.defaultProject = this.inferredProjects[i]; + referencingProjects.push(this.inferredProjects[i]); + } } } return referencingProjects; } + updateProjectStructure() { + this.log("updating project structure from ...", "Info"); + this.printProjects(); + for (var i = 0, len = this.openFilesReferenced.length; i < len; i++) { + var refdFile = this.openFilesReferenced[i]; + refdFile.defaultProject.updateGraph(); + var sourceFile = refdFile.defaultProject.getSourceFile(refdFile); + if (!sourceFile) { + this.openFilesReferenced = copyListRemovingItem(refdFile, this.openFilesReferenced); + this.addOpenFile(refdFile); + } + } + var openFileRoots: ScriptInfo[] = []; + for (var i = 0, len = this.openFileRoots.length; i < len; i++) { + var rootFile = this.openFileRoots[i]; + var rootedProject = rootFile.defaultProject; + var referencingProjects = this.findReferencingProjects(rootFile, rootedProject); + if (referencingProjects.length == 0) { + rootFile.defaultProject = rootedProject; + openFileRoots.push(rootFile); + } + else { + // remove project from inferred projects list + this.inferredProjects = copyListRemovingItem(rootedProject, this.inferredProjects); + this.openFilesReferenced.push(rootFile); + } + } + this.openFileRoots = openFileRoots; + this.printProjects(); + } + getScriptInfo(filename: string) { filename = ts.normalizePath(filename); return ts.lookUp(this.filenameToScriptInfo, filename); @@ -621,6 +669,7 @@ module ts.server { this.psLogger.startGroup(); for (var i = 0, len = this.inferredProjects.length; i < len; i++) { var project = this.inferredProjects[i]; + project.updateGraph(); this.psLogger.info("Project " + i.toString()); this.psLogger.info(project.filesToString()); this.psLogger.info("-----------------------------------------------"); diff --git a/src/server/server.ts b/src/server/server.ts index 8921a4b4768..2b9040b4df3 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -82,7 +82,6 @@ module ts.server { private watchedFiles: WatchedFile[] = []; private nextFileToCheck = 0; private watchTimer: NodeJS.Timer; - private static fileDeleted = 34; // average async stat takes about 30 microseconds // set chunk size to do 30 files in < 1 millisecond @@ -111,13 +110,7 @@ module ts.server { fs.stat(watchedFile.fileName,(err, stats) => { if (err) { - var msg = err.message; - if (err.errno) { - msg += " errno: " + err.errno.toString(); - } - if (err.errno == WatchedFileSet.fileDeleted) { - watchedFile.callback(watchedFile.fileName); - } + watchedFile.callback(watchedFile.fileName); } else if (watchedFile.mtime.getTime() != stats.mtime.getTime()) { watchedFile.mtime = WatchedFileSet.getModifiedTime(watchedFile.fileName); diff --git a/src/server/session.ts b/src/server/session.ts index 319690f3bfe..07642671c7c 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -114,7 +114,18 @@ module ts.server { changeSeq = 0; constructor(private host: ServerHost, private logger: Logger) { - this.projectService = new ProjectService(host, logger); + this.projectService = + new ProjectService(host, logger, (eventName,project,fileName) => { + this.handleEvent(eventName, project, fileName); + }); + } + + handleEvent(eventName: string, project: Project, fileName: string) { + if (eventName == "context") { + this.projectService.log("got context event, updating diagnostics for" + fileName, "Info"); + this.updateErrorCheck([{ fileName, project }], this.changeSeq, + (n) => n == this.changeSeq, 100); + } } logError(err: Error, cmd: string) { @@ -191,6 +202,14 @@ module ts.server { this.semanticCheck(file, project); } + updateProjectStructure(seq: number, matchSeq: (seq: number) => boolean, ms = 1500) { + setTimeout(() => { + if (matchSeq(seq)) { + this.projectService.updateProjectStructure(); + } + }, ms); + } + updateErrorCheck(checkList: PendingErrorCheck[], seq: number, matchSeq: (seq: number) => boolean, ms = 1500, followMs = 200) { if (followMs > ms) { @@ -207,7 +226,7 @@ module ts.server { var checkOne = () => { if (matchSeq(seq)) { var checkSpec = checkList[index++]; - if (checkSpec.project.getSourceFileFromName(checkSpec.fileName)) { + if (checkSpec.project.getSourceFileFromName(checkSpec.fileName, true)) { this.syntacticCheck(checkSpec.fileName, checkSpec.project); this.immediateId = setImmediate(() => { this.semanticCheck(checkSpec.fileName, checkSpec.project); @@ -535,6 +554,10 @@ module ts.server { compilerService.host.editScript(file, start, end, insertString); this.changeSeq++; } + // update project structure on idle commented out + // until we can have the host return only the root files + // from getScriptFileNames() + //this.updateProjectStructure(this.changeSeq, (n) => n == this.changeSeq); } }