From e773588edb1230681ce7830803d266a52765454d Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 6 Dec 2016 15:47:00 -0800 Subject: [PATCH 1/2] remove projects that were no present in the input list in openExternalProjects --- .../unittests/tsserverProjectSystem.ts | 60 +++++++++++++++++++ src/server/editorServices.ts | 27 ++++++++- src/server/session.ts | 6 +- 3 files changed, 87 insertions(+), 6 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 3e9fd7a70e4da..77ebee6fadd70 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -727,6 +727,66 @@ namespace ts.projectSystem { checkNumberOfInferredProjects(projectService, 1); }); + it("remove not-listed external projects", () => { + const f1 = { + path: "/a/app.ts", + content: "let x = 1" + }; + const f2 = { + path: "/b/app.ts", + content: "let x = 1" + }; + const f3 = { + path: "/c/app.ts", + content: "let x = 1" + }; + const makeProject = (f: FileOrFolder) => ({ projectFileName: f.path + ".csproj", rootFiles: [toExternalFile(f.path)], options: {} }); + const p1 = makeProject(f1); + const p2 = makeProject(f2); + const p3 = makeProject(f3); + + const host = createServerHost([f1, f2, f3]); + const session = createSession(host); + + session.executeCommand({ + seq: 1, + type: "request", + command: "openExternalProjects", + arguments: { projects: [p1, p2] } + }); + + const projectService = session.getProjectService(); + checkNumberOfProjects(projectService, { externalProjects: 2 }); + assert.equal(projectService.externalProjects[0].getProjectName(), p1.projectFileName); + assert.equal(projectService.externalProjects[1].getProjectName(), p2.projectFileName); + + session.executeCommand({ + seq: 2, + type: "request", + command: "openExternalProjects", + arguments: { projects: [p1, p3] } + }); + checkNumberOfProjects(projectService, { externalProjects: 2 }); + assert.equal(projectService.externalProjects[0].getProjectName(), p1.projectFileName); + assert.equal(projectService.externalProjects[1].getProjectName(), p3.projectFileName); + + session.executeCommand({ + seq: 3, + type: "request", + command: "openExternalProjects", + arguments: { projects: [] } + }); + checkNumberOfProjects(projectService, { externalProjects: 0 }); + + session.executeCommand({ + seq: 3, + type: "request", + command: "openExternalProjects", + arguments: { projects: [p2] } + }); + assert.equal(projectService.externalProjects[0].getProjectName(), p2.projectFileName); + }); + it("handle recreated files correctly", () => { const configFile: FileOrFolder = { path: "/a/b/tsconfig.json", diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index df46f32672f33..9c31a5045ce27 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1327,7 +1327,28 @@ namespace ts.server { } } - openExternalProject(proj: protocol.ExternalProject): void { + openExternalProjects(projects: protocol.ExternalProject[]): void { + // record project list before the update + const projectsToClose = arrayToMap(this.externalProjects, p => p.getProjectName(), _ => true); + for (const externalProjectName in this.externalProjectToConfiguredProjectMap) { + projectsToClose[externalProjectName] = true; + } + + for (const externalProject of projects) { + this.openExternalProject(externalProject, /*suppressRefreshOfInferredProjects*/ true); + // delete project that is present in input list + delete projectsToClose[externalProject.projectFileName]; + } + + // close projects that were missing in the input list + for (const externalProjectName in projectsToClose) { + this.closeExternalProject(externalProjectName, /*suppressRefresh*/ true) + } + + this.refreshInferredProjects(); + } + + openExternalProject(proj: protocol.ExternalProject, suppressRefreshOfInferredProjects = false): void { // typingOptions has been deprecated and is only supported for backward compatibility // purposes. It should be removed in future releases - use typeAcquisition instead. if (proj.typingOptions && !proj.typeAcquisition) { @@ -1420,7 +1441,9 @@ namespace ts.server { delete this.externalProjectToConfiguredProjectMap[proj.projectFileName]; this.createAndAddExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typeAcquisition); } - this.refreshInferredProjects(); + if (!suppressRefreshOfInferredProjects) { + this.refreshInferredProjects(); + } } } } diff --git a/src/server/session.ts b/src/server/session.ts index 36144b3212d66..9abc5a447bfce 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1365,14 +1365,12 @@ namespace ts.server { private handlers = createMap<(request: protocol.Request) => { response?: any, responseRequired?: boolean }>({ [CommandNames.OpenExternalProject]: (request: protocol.OpenExternalProjectRequest) => { - this.projectService.openExternalProject(request.arguments); + this.projectService.openExternalProject(request.arguments, /*suppressRefreshOfInferredProjects*/ false); // TODO: report errors return this.requiredResponse(true); }, [CommandNames.OpenExternalProjects]: (request: protocol.OpenExternalProjectsRequest) => { - for (const proj of request.arguments.projects) { - this.projectService.openExternalProject(proj); - } + this.projectService.openExternalProjects(request.arguments.projects); // TODO: report errors return this.requiredResponse(true); }, From e820e7a5e6c4c306f07c9b97f4e3b631732b6081 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 6 Dec 2016 16:31:52 -0800 Subject: [PATCH 2/2] address PR feedback --- src/server/editorServices.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 9c31a5045ce27..9e53b3cd52638 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1329,7 +1329,7 @@ namespace ts.server { openExternalProjects(projects: protocol.ExternalProject[]): void { // record project list before the update - const projectsToClose = arrayToMap(this.externalProjects, p => p.getProjectName(), _ => true); + const projectsToClose = arrayToMap(this.externalProjects, p => p.getProjectName(), _ => true); for (const externalProjectName in this.externalProjectToConfiguredProjectMap) { projectsToClose[externalProjectName] = true; }