Fix fourslash server (#33063)

This commit is contained in:
Andrew Branch 2019-08-26 08:46:41 -07:00 committed by GitHub
parent 25f609b3a2
commit b4417da646
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 8 deletions

View file

@ -134,11 +134,13 @@ namespace ts.server {
this.processRequest(CommandNames.Close, args);
}
changeFile(fileName: string, start: number, end: number, insertString: string): void {
createChangeFileRequestArgs(fileName: string, start: number, end: number, insertString: string): protocol.ChangeRequestArgs {
return { ...this.createFileLocationRequestArgsWithEndLineAndOffset(fileName, start, end), insertString };
}
changeFile(fileName: string, args: protocol.ChangeRequestArgs): void {
// clear the line map after an edit
this.lineMaps.set(fileName, undefined!); // TODO: GH#18217
const args: protocol.ChangeRequestArgs = { ...this.createFileLocationRequestArgsWithEndLineAndOffset(fileName, start, end), insertString };
this.processRequest(CommandNames.Change, args);
}

View file

@ -150,6 +150,7 @@ namespace FourSlash {
private languageServiceAdapterHost: Harness.LanguageService.LanguageServiceAdapterHost;
private languageService: ts.LanguageService;
private cancellationToken: TestCancellationToken;
private assertTextConsistent: ((fileName: string) => void) | undefined;
// The current caret position in the active file
public currentCaretPosition = 0;
@ -280,6 +281,9 @@ namespace FourSlash {
const languageServiceAdapter = this.getLanguageServiceAdapter(testType, this.cancellationToken, compilationOptions);
this.languageServiceAdapterHost = languageServiceAdapter.getHost();
this.languageService = memoWrap(languageServiceAdapter.getLanguageService(), this); // Wrap the LS to cache some expensive operations certain tests call repeatedly
if (this.testType === FourSlashTestType.Server) {
this.assertTextConsistent = fileName => (languageServiceAdapter as Harness.LanguageService.ServerLanguageServiceAdapter).assertTextConsistent(fileName);
}
if (startResolveFileRef) {
// Add the entry-point file itself into the languageServiceShimHost
@ -1867,6 +1871,9 @@ namespace FourSlash {
private editScriptAndUpdateMarkers(fileName: string, editStart: number, editEnd: number, newText: string) {
this.languageServiceAdapterHost.editScript(fileName, editStart, editEnd, newText);
if (this.assertTextConsistent) {
this.assertTextConsistent(fileName);
}
for (const marker of this.testData.markers) {
if (marker.fileName === fileName) {
marker.position = updatePosition(marker.position, editStart, editEnd, newText);

View file

@ -661,8 +661,9 @@ namespace Harness.LanguageService {
}
editScript(fileName: string, start: number, end: number, newText: string) {
const changeArgs = this.client.createChangeFileRequestArgs(fileName, start, end, newText);
super.editScript(fileName, start, end, newText);
this.client.changeFile(fileName, start, end, newText);
this.client.changeFile(fileName, changeArgs);
}
}
@ -719,8 +720,8 @@ namespace Harness.LanguageService {
return this.host.getCurrentDirectory();
}
getDirectories(): string[] {
return [];
getDirectories(path: string): string[] {
return this.host.getDirectories(path);
}
getEnvironmentVariable(name: string): string {
@ -890,9 +891,16 @@ namespace Harness.LanguageService {
}
}
class FourslashSession extends ts.server.Session {
getText(fileName: string) {
return ts.getSnapshotText(this.projectService.getDefaultProjectForFile(ts.server.toNormalizedPath(fileName), /*ensureProject*/ true)!.getScriptSnapshot(fileName)!);
}
}
export class ServerLanguageServiceAdapter implements LanguageServiceAdapter {
private host: SessionClientHost;
private client: ts.server.SessionClient;
private server: FourslashSession;
constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) {
// This is the main host that tests use to direct tests
const clientHost = new SessionClientHost(cancellationToken, options);
@ -912,11 +920,12 @@ namespace Harness.LanguageService {
logger: serverHost,
canUseEvents: true
};
const server = new ts.server.Session(opts);
this.server = new FourslashSession(opts);
// Fake the connection between the client and the server
serverHost.writeMessage = client.onMessage.bind(client);
clientHost.writeMessage = server.onMessage.bind(server);
clientHost.writeMessage = this.server.onMessage.bind(this.server);
// Wire the client to the host to get notifications when a file is open
// or edited.
@ -930,5 +939,20 @@ namespace Harness.LanguageService {
getLanguageService(): ts.LanguageService { return this.client; }
getClassifier(): ts.Classifier { throw new Error("getClassifier is not available using the server interface."); }
getPreProcessedFileInfo(): ts.PreProcessedFileInfo { throw new Error("getPreProcessedFileInfo is not available using the server interface."); }
assertTextConsistent(fileName: string) {
const serverText = this.server.getText(fileName);
const clientText = this.host.readFile(fileName);
ts.Debug.assert(serverText === clientText, [
"Server and client text are inconsistent.",
"",
"\x1b[1mServer\x1b[0m\x1b[31m:",
serverText,
"",
"\x1b[1mClient\x1b[0m\x1b[31m:",
clientText,
"",
"This probably means something is wrong with the fourslash infrastructure, not with the test."
].join(ts.sys.newLine));
}
}
}