renameLocations
This commit is contained in:
parent
0b7fb0dba8
commit
bdccb8d0eb
3 changed files with 127 additions and 113 deletions
|
@ -395,7 +395,7 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
getScriptInfo(fileName: string) {
|
||||
const scriptInfo = this.projectService.getOrCreateScriptInfo(fileName, /*openedByClient*/ false);
|
||||
const scriptInfo = this.projectService.getOrCreateScriptInfo(fileName, /*openedByClient*/ false, this);
|
||||
if (scriptInfo && !scriptInfo.defaultProject) {
|
||||
scriptInfo.defaultProject = this;
|
||||
}
|
||||
|
@ -1157,7 +1157,7 @@ namespace ts.server {
|
|||
let errors: Diagnostic[];
|
||||
for (const rootFilename of files) {
|
||||
if (this.host.fileExists(rootFilename)) {
|
||||
const info = this.getOrCreateScriptInfo(rootFilename, /*openedByClient*/ clientFileName == rootFilename);
|
||||
const info = this.getOrCreateScriptInfo(rootFilename, /*openedByClient*/ clientFileName == rootFilename, project);
|
||||
project.addRoot(info);
|
||||
}
|
||||
else {
|
||||
|
@ -1195,7 +1195,7 @@ namespace ts.server {
|
|||
for (const fileName of fileNamesToAdd) {
|
||||
let info = this.getScriptInfo(fileName);
|
||||
if (!info) {
|
||||
info = this.getOrCreateScriptInfo(fileName, /*openedByClient*/ false);
|
||||
info = this.getOrCreateScriptInfo(fileName, /*openedByClient*/ false, project);
|
||||
}
|
||||
else {
|
||||
// if the root file was opened by client, it would belong to either
|
||||
|
@ -1268,7 +1268,7 @@ namespace ts.server {
|
|||
* @param filename is absolute pathname
|
||||
* @param fileContent is a known version of the file content that is more up to date than the one on disk
|
||||
*/
|
||||
getOrCreateScriptInfo(fileName: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind) {
|
||||
getOrCreateScriptInfo(fileName: string, openedByClient: boolean, containingProject: Project, fileContent?: string, scriptKind?: ScriptKind) {
|
||||
fileName = ts.normalizePath(fileName);
|
||||
let info = ts.lookUp(this.filenameToScriptInfo, fileName);
|
||||
if (!info) {
|
||||
|
@ -1284,6 +1284,7 @@ namespace ts.server {
|
|||
if (content !== undefined) {
|
||||
info = new ScriptInfo(this.host, fileName, content, openedByClient);
|
||||
info.scriptKind = scriptKind;
|
||||
info.defaultProject = containingProject;
|
||||
info.setFormatOptions(toEditorSettings(this.getFormatCodeOptions()));
|
||||
this.filenameToScriptInfo[fileName] = info;
|
||||
if (!info.isOpen) {
|
||||
|
@ -1333,27 +1334,27 @@ namespace ts.server {
|
|||
findReferencingProjects(info: ScriptInfo, excludedProject?: Project) {
|
||||
const referencingProjects: Project[] = [];
|
||||
info.defaultProject = undefined;
|
||||
for (let i = 0, len = this.inferredProjects.length; i < len; i++) {
|
||||
const inferredProject = this.inferredProjects[i];
|
||||
inferredProject.updateGraph();
|
||||
if (inferredProject !== excludedProject) {
|
||||
if (inferredProject.containsScriptInfo(info)) {
|
||||
info.defaultProject = inferredProject;
|
||||
referencingProjects.push(inferredProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 0, len = this.configuredProjects.length; i < len; i++) {
|
||||
const configuredProject = this.configuredProjects[i];
|
||||
configuredProject.updateGraph();
|
||||
if (configuredProject.containsScriptInfo(info)) {
|
||||
info.defaultProject = configuredProject;
|
||||
referencingProjects.push(configuredProject);
|
||||
}
|
||||
this.collectContainingProjects(info, referencingProjects, this.inferredProjects, excludedProject);
|
||||
this.collectContainingProjects(info, referencingProjects, this.configuredProjects);
|
||||
this.collectContainingProjects(info, referencingProjects, this.externalProjects);
|
||||
if (referencingProjects.length) {
|
||||
info.defaultProject = referencingProjects[0];
|
||||
}
|
||||
return referencingProjects;
|
||||
}
|
||||
|
||||
private collectContainingProjects(info: ScriptInfo, result: Project[], projects: Project[], excludedProject?: Project) {
|
||||
for (const p of projects) {
|
||||
if (p === excludedProject) {
|
||||
continue;
|
||||
}
|
||||
p.updateGraph();
|
||||
if (p.containsScriptInfo(info)) {
|
||||
result.push(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function rebuilds the project for every file opened by the client
|
||||
*/
|
||||
|
@ -1464,7 +1465,7 @@ namespace ts.server {
|
|||
if (!this.findContainingExternalProject(fileName)) {
|
||||
({ configFileName, configFileErrors } = this.openOrUpdateConfiguredProjectForFile(fileName));
|
||||
}
|
||||
const info = this.getOrCreateScriptInfo(fileName, /*openedByClient*/ true, fileContent, scriptKind);
|
||||
const info = this.getOrCreateScriptInfo(fileName, /*openedByClient*/ true, /*containingProject*/ undefined, fileContent, scriptKind);
|
||||
this.addOpenFile(info);
|
||||
this.printProjects();
|
||||
return { configFileName, configFileErrors };
|
||||
|
|
|
@ -135,6 +135,7 @@ namespace ts.server {
|
|||
export const Reload = "reload";
|
||||
export const Rename = "rename";
|
||||
export const RenameInfoFull = "rename-full";
|
||||
export const RenameLocationsFull = "renameLocations-full";
|
||||
export const Saveto = "saveto";
|
||||
export const SignatureHelp = "signatureHelp";
|
||||
export const SignatureHelpFull = "signatureHelp-full";
|
||||
|
@ -512,7 +513,7 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
const scriptInfo = project.getScriptInfo(fileName);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
|
||||
const documentHighlights = project.languageService.getDocumentHighlights(fileName, position, args.filesToSearch);
|
||||
|
||||
|
@ -563,72 +564,109 @@ namespace ts.server {
|
|||
private getRenameInfo(args: protocol.FileLocationRequestArgs) {
|
||||
const { file, project } = this.getFileAndProject(args.file);
|
||||
const scriptInfo = project.getScriptInfo(file);
|
||||
const position = this.getPosition(args, scriptInfo)
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
return project.languageService.getRenameInfo(file, position);
|
||||
}
|
||||
|
||||
private getRenameLocations(line: number, offset: number, fileName: string, findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody {
|
||||
const file = ts.normalizePath(fileName);
|
||||
const info = this.projectService.getScriptInfo(file);
|
||||
const projects = this.projectService.findReferencingProjects(info);
|
||||
if (!projects.length) {
|
||||
private getProjects(args: protocol.FileRequestArgs) {
|
||||
let projects: Project[];
|
||||
if (args.projectFileName) {
|
||||
const project = this.getProject(args.projectFileName);
|
||||
if (project) {
|
||||
projects = [project];
|
||||
}
|
||||
}
|
||||
else {
|
||||
const file = normalizePath(args.file);
|
||||
const info = this.projectService.getScriptInfo(file);
|
||||
projects = this.projectService.findReferencingProjects(info);
|
||||
}
|
||||
if (!projects || !projects.length) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
return projects;
|
||||
}
|
||||
|
||||
const defaultProject = projects[0];
|
||||
// The rename info should be the same for every project
|
||||
const scriptInfo = defaultProject.getScriptInfo(file);
|
||||
const position = scriptInfo.lineOffsetToPosition(line, offset);
|
||||
const renameInfo = defaultProject.languageService.getRenameInfo(file, position);
|
||||
if (!renameInfo) {
|
||||
return undefined;
|
||||
private getRenameLocations(args: protocol.RenameRequestArgs, simplifiedResult: boolean): protocol.RenameResponseBody | RenameLocation[] {
|
||||
const file = ts.normalizePath(args.file);
|
||||
const info = this.projectService.getScriptInfo(file);
|
||||
const position = this.getPosition(args, info);
|
||||
const projects = this.getProjects(args);
|
||||
if (simplifiedResult) {
|
||||
|
||||
const defaultProject = projects[0];
|
||||
// The rename info should be the same for every project
|
||||
const renameInfo = defaultProject.languageService.getRenameInfo(file, position);
|
||||
if (!renameInfo) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!renameInfo.canRename) {
|
||||
return {
|
||||
info: renameInfo,
|
||||
locs: []
|
||||
};
|
||||
}
|
||||
|
||||
const fileSpans = combineProjectOutput(
|
||||
projects,
|
||||
(project: Project) => {
|
||||
const renameLocations = project.languageService.findRenameLocations(file, position, args.findInStrings, args.findInComments);
|
||||
if (!renameLocations) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return renameLocations.map(location => {
|
||||
const locationScriptInfo = project.getScriptInfo(location.fileName);
|
||||
return <protocol.FileSpan>{
|
||||
file: location.fileName,
|
||||
start: locationScriptInfo.positionToLineOffset(location.textSpan.start),
|
||||
end: locationScriptInfo.positionToLineOffset(ts.textSpanEnd(location.textSpan)),
|
||||
};
|
||||
});
|
||||
},
|
||||
compareRenameLocation,
|
||||
(a, b) => a.file === b.file && a.start.line === b.start.line && a.start.offset === b.start.offset
|
||||
);
|
||||
const locs = fileSpans.reduce<protocol.SpanGroup[]>((accum, cur) => {
|
||||
let curFileAccum: protocol.SpanGroup;
|
||||
if (accum.length > 0) {
|
||||
curFileAccum = accum[accum.length - 1];
|
||||
if (curFileAccum.file !== cur.file) {
|
||||
curFileAccum = undefined;
|
||||
}
|
||||
}
|
||||
if (!curFileAccum) {
|
||||
curFileAccum = { file: cur.file, locs: [] };
|
||||
accum.push(curFileAccum);
|
||||
}
|
||||
curFileAccum.locs.push({ start: cur.start, end: cur.end });
|
||||
return accum;
|
||||
}, []);
|
||||
|
||||
return { info: renameInfo, locs };
|
||||
}
|
||||
else {
|
||||
return combineProjectOutput(
|
||||
projects,
|
||||
p => p.languageService.findRenameLocations(file, position, args.findInStrings, args.findInComments),
|
||||
/*comparer*/ undefined,
|
||||
renameLocationIsEqualTo
|
||||
);
|
||||
}
|
||||
|
||||
if (!renameInfo.canRename) {
|
||||
return {
|
||||
info: renameInfo,
|
||||
locs: []
|
||||
};
|
||||
function renameLocationIsEqualTo(a: RenameLocation, b: RenameLocation) {
|
||||
if (a === b) {
|
||||
return true;
|
||||
}
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
return a.fileName === b.fileName &&
|
||||
a.textSpan.start === b.textSpan.start &&
|
||||
a.textSpan.length === b.textSpan.length;
|
||||
}
|
||||
|
||||
const fileSpans = combineProjectOutput(
|
||||
projects,
|
||||
(project: Project) => {
|
||||
const renameLocations = project.languageService.findRenameLocations(file, position, findInStrings, findInComments);
|
||||
if (!renameLocations) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return renameLocations.map(location => {
|
||||
const locationScriptInfo = project.getScriptInfo(location.fileName);
|
||||
return <protocol.FileSpan>{
|
||||
file: location.fileName,
|
||||
start: locationScriptInfo.positionToLineOffset(location.textSpan.start),
|
||||
end: locationScriptInfo.positionToLineOffset(ts.textSpanEnd(location.textSpan)),
|
||||
};
|
||||
});
|
||||
},
|
||||
compareRenameLocation,
|
||||
(a, b) => a.file === b.file && a.start.line === b.start.line && a.start.offset === b.start.offset
|
||||
);
|
||||
const locs = fileSpans.reduce<protocol.SpanGroup[]>((accum, cur) => {
|
||||
let curFileAccum: protocol.SpanGroup;
|
||||
if (accum.length > 0) {
|
||||
curFileAccum = accum[accum.length - 1];
|
||||
if (curFileAccum.file !== cur.file) {
|
||||
curFileAccum = undefined;
|
||||
}
|
||||
}
|
||||
if (!curFileAccum) {
|
||||
curFileAccum = { file: cur.file, locs: [] };
|
||||
accum.push(curFileAccum);
|
||||
}
|
||||
curFileAccum.locs.push({ start: cur.start, end: cur.end });
|
||||
return accum;
|
||||
}, []);
|
||||
|
||||
return { info: renameInfo, locs };
|
||||
|
||||
function compareRenameLocation(a: protocol.FileSpan, b: protocol.FileSpan) {
|
||||
if (a.file < b.file) {
|
||||
return -1;
|
||||
|
@ -651,22 +689,9 @@ namespace ts.server {
|
|||
}
|
||||
}
|
||||
|
||||
private getReferences(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.ReferencesResponseBody | ReferencedSymbol[] {
|
||||
private getReferences(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.ReferencesResponseBody | ReferencedSymbol[] {
|
||||
const file = ts.normalizePath(args.file);
|
||||
let projects: Project[];
|
||||
if (args.projectFileName) {
|
||||
const project = this.getProject(args.projectFileName);
|
||||
if (project) {
|
||||
projects = [project];
|
||||
}
|
||||
}
|
||||
else {
|
||||
const info = this.projectService.getScriptInfo(file);
|
||||
projects = this.projectService.findReferencingProjects(info);
|
||||
}
|
||||
if (!projects || !projects.length) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
const projects = this.getProjects(args);
|
||||
|
||||
const defaultProject = projects[0];
|
||||
const scriptInfo = defaultProject.getScriptInfo(file);
|
||||
|
@ -1133,21 +1158,7 @@ namespace ts.server {
|
|||
}
|
||||
|
||||
private getNavigateToItems(args: protocol.NavtoRequestArgs, simplifiedResult: boolean): protocol.NavtoItem[] | NavigateToItem[] {
|
||||
let projects: Project[];
|
||||
if (args.projectFileName) {
|
||||
const project = this.getProject(args.projectFileName);
|
||||
if (project) {
|
||||
projects = [project];
|
||||
}
|
||||
}
|
||||
else {
|
||||
const file = normalizePath(args.file);
|
||||
const info = this.projectService.getScriptInfo(file);
|
||||
projects = this.projectService.findReferencingProjects(info);
|
||||
}
|
||||
if (!projects || !projects.length) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
const projects = this.getProjects(args);
|
||||
|
||||
if (simplifiedResult) {
|
||||
return combineProjectOutput(
|
||||
|
@ -1352,8 +1363,10 @@ namespace ts.server {
|
|||
return this.requiredResponse(this.getReferences(request.arguments, /*simplifiedResult*/ false));
|
||||
},
|
||||
[CommandNames.Rename]: (request: protocol.Request) => {
|
||||
const renameArgs = <protocol.RenameRequestArgs>request.arguments;
|
||||
return this.requiredResponse(this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings));
|
||||
return this.requiredResponse(this.getRenameLocations(request.arguments, /*simplifiedResult*/ true));
|
||||
},
|
||||
[CommandNames.RenameLocationsFull]: (request: protocol.RenameRequest) => {
|
||||
return this.requiredResponse(this.getRenameLocations(request.arguments, /*simplifiedResult*/ false));
|
||||
},
|
||||
[CommandNames.RenameInfoFull]: (request: protocol.FileLocationRequest) => {
|
||||
return this.requiredResponse(this.getRenameInfo(request.arguments));
|
||||
|
@ -1476,7 +1489,7 @@ namespace ts.server {
|
|||
[CommandNames.Reload]: (request: protocol.Request) => {
|
||||
const reloadArgs = <protocol.ReloadRequestArgs>request.arguments;
|
||||
this.reload(reloadArgs.file, reloadArgs.tmpfile, request.seq);
|
||||
return {response: { reloadFinished: true }, responseRequired: true};
|
||||
return { response: { reloadFinished: true }, responseRequired: true };
|
||||
},
|
||||
[CommandNames.Saveto]: (request: protocol.Request) => {
|
||||
const savetoArgs = <protocol.SavetoRequestArgs>request.arguments;
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace ts {
|
|||
};
|
||||
|
||||
const projectService = new server.ProjectService(serverHost, logger, { isCancellationRequested: () => false });
|
||||
const rootScriptInfo = projectService.getOrCreateScriptInfo(rootFile, /* openedByClient */true);
|
||||
const rootScriptInfo = projectService.getOrCreateScriptInfo(rootFile, /* openedByClient */true, /*containingProject*/ undefined);
|
||||
const project = projectService.createAndAddInferredProject(rootScriptInfo);
|
||||
project.setCompilerOptions({ module: ts.ModuleKind.AMD } );
|
||||
return {
|
||||
|
|
Loading…
Reference in a new issue