Skip to content

Commit

Permalink
Merge pull request #19484 from Microsoft/reloadScriptsWithoutProject
Browse files Browse the repository at this point in the history
[release-2.6] On "reload" command, reload contents of file from disk irrespective of project presence and even if file already containing its own text
  • Loading branch information
sheetalkamat committed Oct 25, 2017
2 parents 6489a75 + 96c66a6 commit c35e90e
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 36 deletions.
90 changes: 90 additions & 0 deletions src/harness/unittests/tsserverProjectSystem.ts
Expand Up @@ -3893,6 +3893,96 @@ namespace ts.projectSystem {
assert.equal(snap2.getText(0, snap2.getLength()), f1.content, "content should be equal to the content of original file");

});

it("should work when script info doesnt have any project open", () => {
const f1 = {
path: "/a/b/app.ts",
content: "let x = 1"
};
const tmp = {
path: "/a/b/app.tmp",
content: "const y = 42"
};
const host = createServerHost([f1, tmp, libFile]);
const session = createSession(host);
const openContent = "let z = 1";
// send open request
session.executeCommandSeq(<server.protocol.OpenRequest>{
command: server.protocol.CommandTypes.Open,
arguments: { file: f1.path, fileContent: openContent }
});

const projectService = session.getProjectService();
checkNumberOfProjects(projectService, { inferredProjects: 1 });
const info = projectService.getScriptInfo(f1.path);
assert.isDefined(info);
checkScriptInfoContents(openContent, "contents set during open request");

// send close request
session.executeCommandSeq(<server.protocol.CloseRequest>{
command: server.protocol.CommandTypes.Close,
arguments: { file: f1.path }
});
checkScriptInfoAndProjects(0, f1.content, "contents of closed file");

// Can reload contents of the file when its not open and has no project
// reload from temp file
session.executeCommandSeq(<server.protocol.ReloadRequest>{
command: server.protocol.CommandTypes.Reload,
arguments: { file: f1.path, tmpfile: tmp.path }
});
checkScriptInfoAndProjects(0, tmp.content, "contents of temp file");

// reload from own file
session.executeCommandSeq(<server.protocol.ReloadRequest>{
command: server.protocol.CommandTypes.Reload,
arguments: { file: f1.path }
});
checkScriptInfoAndProjects(0, f1.content, "contents of closed file");

// Open file again without setting its content
session.executeCommandSeq(<server.protocol.OpenRequest>{
command: server.protocol.CommandTypes.Open,
arguments: { file: f1.path }
});
checkScriptInfoAndProjects(1, f1.content, "contents of file when opened without specifying contents");
const snap = info.getSnapshot();

// send close request
session.executeCommandSeq(<server.protocol.CloseRequest>{
command: server.protocol.CommandTypes.Close,
arguments: { file: f1.path }
});
checkScriptInfoAndProjects(0, f1.content, "contents of closed file");
assert.strictEqual(info.getSnapshot(), snap);

// reload from temp file
session.executeCommandSeq(<server.protocol.ReloadRequest>{
command: server.protocol.CommandTypes.Reload,
arguments: { file: f1.path, tmpfile: tmp.path }
});
checkScriptInfoAndProjects(0, tmp.content, "contents of temp file");
assert.notStrictEqual(info.getSnapshot(), snap);

// reload from own file
session.executeCommandSeq(<server.protocol.ReloadRequest>{
command: server.protocol.CommandTypes.Reload,
arguments: { file: f1.path }
});
checkScriptInfoAndProjects(0, f1.content, "contents of closed file");
assert.notStrictEqual(info.getSnapshot(), snap);

function checkScriptInfoAndProjects(inferredProjects: number, contentsOfInfo: string, captionForContents: string) {
checkNumberOfProjects(projectService, { inferredProjects });
assert.strictEqual(projectService.getScriptInfo(f1.path), info);
checkScriptInfoContents(contentsOfInfo, captionForContents);
}

function checkScriptInfoContents(contentsOfInfo: string, captionForContents: string) {
const snap = info.getSnapshot();
assert.equal(snap.getText(0, snap.getLength()), contentsOfInfo, "content should be equal to " + captionForContents);
}
});
});

describe("Inferred projects", () => {
Expand Down
10 changes: 0 additions & 10 deletions src/server/project.ts
Expand Up @@ -946,16 +946,6 @@ namespace ts.server {
}
}

reloadScript(filename: NormalizedPath, tempFileName?: NormalizedPath): boolean {
const script = this.projectService.getScriptInfoForNormalizedPath(filename);
if (script) {
Debug.assert(script.isAttached(this));
script.reloadFromFile(tempFileName);
return true;
}
return false;
}

/* @internal */
getChangesSinceVersion(lastKnownVersion?: number): ProjectFilesWithTSDiagnostics {
this.updateGraph();
Expand Down
42 changes: 22 additions & 20 deletions src/server/scriptInfo.ts
Expand Up @@ -67,7 +67,10 @@ namespace ts.server {
this.lineMap = undefined;
}

/** returns true if text changed */
/**
* Set the contents as newText
* returns true if text changed
*/
public reload(newText: string) {
Debug.assert(newText !== undefined);

Expand All @@ -87,31 +90,31 @@ namespace ts.server {
}
}

/** returns true if text changed */
/**
* Reads the contents from tempFile(if supplied) or own file and sets it as contents
* returns true if text changed
*/
public reloadWithFileText(tempFileName?: string) {
const reloaded = this.reload(this.getFileText(tempFileName));
this.ownFileText = !tempFileName || tempFileName === this.fileName;
return reloaded;
}

/**
* Reloads the contents from the file if there is no pending reload from disk or the contents of file are same as file text
* returns true if text changed
*/
public reloadFromDisk() {
let reloaded = false;
if (!this.pendingReloadFromDisk && !this.ownFileText) {
reloaded = this.reload(this.getFileText());
this.ownFileText = true;
return this.reloadWithFileText();
}
return reloaded;
return false;
}

public delayReloadFromFileIntoText() {
this.pendingReloadFromDisk = true;
}

/** returns true if text changed */
public reloadFromFile(tempFileName: string) {
let reloaded = false;
// Reload if different file or we dont know if we are working with own file text
if (tempFileName !== this.fileName || !this.ownFileText) {
reloaded = this.reload(this.getFileText(tempFileName));
this.ownFileText = !tempFileName || tempFileName === this.fileName;
}
return reloaded;
}

public getSnapshot(): IScriptSnapshot {
return this.useScriptVersionCacheIfValidOrOpen()
? this.svc.getSnapshot()
Expand Down Expand Up @@ -180,8 +183,7 @@ namespace ts.server {
private getOrLoadText() {
if (this.text === undefined || this.pendingReloadFromDisk) {
Debug.assert(!this.svc || this.pendingReloadFromDisk, "ScriptVersionCache should not be set when reloading from disk");
this.reload(this.getFileText());
this.ownFileText = true;
this.reloadWithFileText();
}
return this.text;
}
Expand Down Expand Up @@ -385,7 +387,7 @@ namespace ts.server {
this.markContainingProjectsAsDirty();
}
else {
if (this.textStorage.reloadFromFile(tempFileName)) {
if (this.textStorage.reloadWithFileText(tempFileName)) {
this.markContainingProjectsAsDirty();
}
}
Expand Down
12 changes: 7 additions & 5 deletions src/server/session.ts
Expand Up @@ -1311,11 +1311,13 @@ namespace ts.server {
private reload(args: protocol.ReloadRequestArgs, reqSeq: number) {
const file = toNormalizedPath(args.file);
const tempFileName = args.tmpfile && toNormalizedPath(args.tmpfile);
const project = this.projectService.getDefaultProjectForFile(file, /*ensureProject*/ true);
this.changeSeq++;
// make sure no changes happen before this one is finished
if (project.reloadScript(file, tempFileName)) {
this.doOutput(/*info*/ undefined, CommandNames.Reload, reqSeq, /*success*/ true);
const info = this.projectService.getScriptInfoForNormalizedPath(file);
if (info) {
this.changeSeq++;
// make sure no changes happen before this one is finished
if (info.reloadFromFile(tempFileName)) {
this.doOutput(/*info*/ undefined, CommandNames.Reload, reqSeq, /*success*/ true);
}
}
}

Expand Down
1 change: 0 additions & 1 deletion tests/baselines/reference/api/tsserverlibrary.d.ts
Expand Up @@ -7227,7 +7227,6 @@ declare namespace ts.server {
getScriptInfo(uncheckedFileName: string): ScriptInfo;
filesToString(writeProjectFileNames: boolean): string;
setCompilerOptions(compilerOptions: CompilerOptions): void;
reloadScript(filename: NormalizedPath, tempFileName?: NormalizedPath): boolean;
protected removeRoot(info: ScriptInfo): void;
}
/**
Expand Down

0 comments on commit c35e90e

Please sign in to comment.