Skip to content

Commit d28b0e9

Browse files
Use openExternalProject to keep project live in tsserver
The server can now correctly handle files that are not open, including finding references, etc. The performance should also be better, since the project is not recreated on the server each time the "first" file is opened. Closes angelozerr#142
1 parent bdd8ff6 commit d28b0e9

File tree

10 files changed

+224
-4
lines changed

10 files changed

+224
-4
lines changed

core/ts.core/src/ts/client/CommandNames.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*
88
* Contributors:
99
* Angelo Zerr <[email protected]> - initial API and implementation
10+
* Lorenzo Dalla Vecchia <[email protected]> - openExternalProject
1011
*/
1112
package ts.client;
1213

@@ -36,6 +37,7 @@ public enum CommandNames {
3637
Configure("configure"),
3738
ProjectInfo("projectInfo"),
3839
Rename("rename"),
40+
OpenExternalProject("openExternalProject"),
3941

4042
// 2.0.3
4143
SemanticDiagnosticsSync("semanticDiagnosticsSync", "2.0.3"),

core/ts.core/src/ts/client/ITypeScriptServiceClient.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
* Contributors:
99
* Angelo Zerr <[email protected]> - initial API and implementation
10-
* Lorenzo Dalla Vecchia <[email protected]> - adjusted usage of CompletableFuture
10+
* Lorenzo Dalla Vecchia <[email protected]> - adjusted usage of CompletableFuture, openExternalProject
1111
*/
1212
package ts.client;
1313

@@ -198,6 +198,16 @@ CompletableFuture<RenameResponseBody> rename(String file, int line, int offset,
198198

199199
CompletableFuture<ProjectInfo> projectInfo(String file, String projectFileName, boolean needFileNameList);
200200

201+
/**
202+
* Defines a TypeScript project that is "handled by the client" and
203+
* therefore never closed automatically by the server.
204+
*
205+
* @param projectFileName
206+
* @param rootFileNames
207+
* @return
208+
*/
209+
CompletableFuture<Void> openExternalProject(String projectFileName, List<String> rootFileNames);
210+
201211
// Since 2.0.3
202212

203213
/**

core/ts.core/src/ts/client/TypeScriptServiceClient.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
* Contributors:
99
* Angelo Zerr <[email protected]> - initial API and implementation
10-
* Lorenzo Dalla Vecchia <[email protected]> - adjusted usage of CompletableFuture, added required requests
10+
* Lorenzo Dalla Vecchia <[email protected]> - adjusted usage of CompletableFuture, added required requests, openExternalProject
1111
*/
1212
package ts.client;
1313

@@ -72,6 +72,7 @@
7272
import ts.internal.client.protocol.NavBarRequest;
7373
import ts.internal.client.protocol.NavTreeRequest;
7474
import ts.internal.client.protocol.OccurrencesRequest;
75+
import ts.internal.client.protocol.OpenExternalProjectRequest;
7576
import ts.internal.client.protocol.OpenRequest;
7677
import ts.internal.client.protocol.ProjectInfoRequest;
7778
import ts.internal.client.protocol.QuickInfoRequest;
@@ -230,7 +231,10 @@ private void dispatchMessage(String message) {
230231
// message " + json);
231232
return;
232233
}
233-
Response responseMessage = pendingRequestInfo.requestMessage.parseResponse(json);
234+
Response<?> responseMessage = pendingRequestInfo.requestMessage.parseResponse(json);
235+
if (responseMessage == null) {
236+
responseMessage = GsonHelper.DEFAULT_GSON.fromJson(json, Response.class);
237+
}
234238
try {
235239
handleResponse(responseMessage, message, pendingRequestInfo.startTime);
236240
pendingRequestInfo.responseHandler.accept(responseMessage);
@@ -414,6 +418,11 @@ public CompletableFuture<ProjectInfo> projectInfo(String file, String projectFil
414418
return execute(new ProjectInfoRequest(file, needFileNameList));
415419
}
416420

421+
@Override
422+
public CompletableFuture<Void> openExternalProject(String projectFileName, List<String> rootFileNames) {
423+
return executeCausingWait(new OpenExternalProjectRequest(projectFileName, rootFileNames));
424+
}
425+
417426
// Since 2.0.3
418427

419428
@Override
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Copyright (c) 2015-2017 Angelo ZERR.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Lorenzo Dalla Vecchia <[email protected]> - initial API and implementation
10+
*/
11+
package ts.client.external;
12+
13+
/**
14+
* Represents a file in external project.
15+
*/
16+
public class ExternalFile {
17+
/**
18+
* Name of file
19+
*/
20+
private String fileName;
21+
22+
public ExternalFile(String fileName) {
23+
this.fileName = fileName;
24+
}
25+
26+
public String getFileName() {
27+
return fileName;
28+
}
29+
30+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Copyright (c) 2015-2017 Angelo ZERR.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Lorenzo Dalla Vecchia <[email protected]> - initial API and implementation
10+
*/
11+
package ts.client.external;
12+
13+
import java.util.ArrayList;
14+
import java.util.Collections;
15+
import java.util.List;
16+
17+
/**
18+
* Represents an external project
19+
*/
20+
public class ExternalProject {
21+
/**
22+
* Project name
23+
*/
24+
private String projectFileName;
25+
/**
26+
* List of root files in project
27+
*/
28+
private List<ExternalFile> rootFiles;
29+
/**
30+
* Compiler options for the project
31+
*/
32+
private ExternalProjectCompilerOptions options;
33+
34+
public ExternalProject(String projectFileName, List<ExternalFile> rootFiles) {
35+
this.projectFileName = projectFileName;
36+
this.rootFiles = new ArrayList<ExternalFile>(rootFiles);
37+
}
38+
39+
public String getProjectFileName() {
40+
return projectFileName;
41+
}
42+
43+
public List<ExternalFile> getRootFiles() {
44+
return Collections.unmodifiableList(rootFiles);
45+
}
46+
47+
public ExternalProjectCompilerOptions getOptions() {
48+
return options;
49+
}
50+
51+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Copyright (c) 2015-2017 Angelo ZERR.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Lorenzo Dalla Vecchia <[email protected]> - initial API and implementation
10+
*/
11+
package ts.client.external;
12+
13+
/**
14+
* For external projects, some of the project settings are sent together with
15+
* compiler settings.
16+
*/
17+
public class ExternalProjectCompilerOptions {
18+
19+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Copyright (c) 2015-2017 Angelo ZERR.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Lorenzo Dalla Vecchia <[email protected]> - initial API and implementation
10+
*/
11+
package ts.internal.client.protocol;
12+
13+
import java.util.List;
14+
import java.util.stream.Collectors;
15+
16+
import com.google.gson.JsonObject;
17+
18+
import ts.client.CommandNames;
19+
import ts.client.external.ExternalFile;
20+
import ts.client.external.ExternalProject;
21+
22+
/**
23+
* A request to open or update external project.
24+
*
25+
* @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts
26+
*/
27+
public class OpenExternalProjectRequest extends Request<ExternalProject> {
28+
29+
public OpenExternalProjectRequest(String projectFileName, List<String> rootFileNames) {
30+
super(CommandNames.OpenExternalProject.getName(),
31+
new ExternalProject(projectFileName, createExternalFileList(rootFileNames)));
32+
}
33+
34+
private static List<ExternalFile> createExternalFileList(List<String> fileNames) {
35+
return fileNames.stream().map(ExternalFile::new).collect(Collectors.toList());
36+
}
37+
38+
@Override
39+
public Response<Boolean> parseResponse(JsonObject json) {
40+
return GsonHelper.DEFAULT_GSON.fromJson(json, OpenExternalProjectResponse.class);
41+
}
42+
43+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Copyright (c) 2015-2017 Angelo ZERR.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Lorenzo Dalla Vecchia <[email protected]> - initial API and implementation
10+
*/
11+
package ts.internal.client.protocol;
12+
13+
/**
14+
* Response to OpenExternalProjectRequest request. This is just an
15+
* acknowledgement, so no body field is required.
16+
*
17+
* @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts
18+
*/
19+
public class OpenExternalProjectResponse extends Response<Boolean> {
20+
21+
}

core/ts.core/src/ts/resources/TypeScriptProject.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
*
88
* Contributors:
99
* Angelo Zerr <[email protected]> - initial API and implementation
10+
* Lorenzo Dalla Vecchia <[email protected]> - openExternalProject
1011
*/
1112
package ts.resources;
1213

1314
import java.io.File;
1415
import java.util.ArrayList;
16+
import java.util.Collections;
1517
import java.util.HashMap;
1618
import java.util.List;
1719
import java.util.Map;
@@ -85,6 +87,20 @@ public File getProjectDir() {
8587
return projectDir;
8688
}
8789

90+
/**
91+
* Gets the paths of the tsconfig.json files to take into account for this
92+
* project. This is called each time a new server is started for this
93+
* project.
94+
* <p>
95+
* The default implementation returns an empty list.
96+
*
97+
* @return tsconfigFilePaths list of tsconfig.json paths, relative to the
98+
* project directory.
99+
*/
100+
protected List<String> getTsconfigFilePaths() {
101+
return Collections.emptyList();
102+
}
103+
88104
void openFile(ITypeScriptFile tsFile) throws TypeScriptException {
89105
String name = tsFile.getName();
90106
String contents = tsFile.getContents();
@@ -134,13 +150,20 @@ public final ITypeScriptServiceClient getClient() throws TypeScriptException {
134150
this.client = createServiceClient(getProjectDir());
135151
copyListeners();
136152
onCreateClient(client);
153+
// determine root files and project name
154+
String projectName = projectDir.getCanonicalPath();
155+
List<String> rootFiles = new ArrayList<>();
156+
for (String tsconfigFilePath : getTsconfigFilePaths()) {
157+
rootFiles.add(new File(projectDir, tsconfigFilePath).getCanonicalPath());
158+
}
159+
// opens or updates the external project
160+
client.openExternalProject(projectName, rootFiles);
137161
} catch (Exception e) {
138162
if (e instanceof TypeScriptException) {
139163
throw (TypeScriptException) e;
140164
}
141165
throw new TypeScriptException(e);
142166
}
143-
144167
}
145168
return client;
146169
}

eclipse/ts.eclipse.ide.core/src/ts/eclipse/ide/internal/core/resources/IDETypeScriptProject.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*
88
* Contributors:
99
* Angelo Zerr <[email protected]> - initial API and implementation
10+
* Lorenzo Dalla Vecchia <[email protected]> - openExternalProject
1011
*/
1112
package ts.eclipse.ide.internal.core.resources;
1213

@@ -351,6 +352,17 @@ public void disposeBuildPath() {
351352
IDEResourcesManager.getInstance().fireBuildPathChanged(this, oldBuildPath, newBuildPath);
352353
}
353354

355+
@Override
356+
protected List<String> getTsconfigFilePaths() {
357+
ITsconfigBuildPath[] tsconfigBuildPaths = getTypeScriptBuildPath().getTsconfigBuildPaths();
358+
List<String> result = new ArrayList<>(tsconfigBuildPaths.length);
359+
for (ITsconfigBuildPath tsconfigBuildPath : tsconfigBuildPaths) {
360+
IFile tsconfigFile = tsconfigBuildPath.getTsconfigFile();
361+
result.add(tsconfigFile.getLocation().makeRelativeTo(tsconfigFile.getProject().getLocation()).toString());
362+
}
363+
return result;
364+
}
365+
354366
@Override
355367
public IIDETypeScriptCompiler getCompiler() throws TypeScriptException {
356368
return (IIDETypeScriptCompiler) super.getCompiler();

0 commit comments

Comments
 (0)