Added update of project structure on idle following change (if no

changes in last s seconds (where s is currently 1.5), then check project
structure to account for references that may have changed.  Turned this
off pending fix for getScriptFileNames returning only the root names.
Added event handler for deleted file, so that session can update error
messages upon deletion of a file from a project.
This commit is contained in:
steveluc
2015-02-22 23:27:45 -08:00
parent f19619e22b
commit f9518b252b
3 changed files with 85 additions and 20 deletions

View File

@@ -65,6 +65,7 @@ module ts.server {
ls: ts.LanguageService = null;
compilationSettings: ts.CompilerOptions;
filenameToScript: ts.Map<ScriptInfo> = {};
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("-----------------------------------------------");

View File

@@ -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);

View File

@@ -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);
}
}