|
|
|
|
@@ -141,8 +141,8 @@ namespace ts.server {
|
|
|
|
|
) {
|
|
|
|
|
this.projectService =
|
|
|
|
|
new ProjectService(host, logger, (eventName, project, fileName) => {
|
|
|
|
|
this.handleEvent(eventName, project, fileName);
|
|
|
|
|
});
|
|
|
|
|
this.handleEvent(eventName, project, fileName);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private handleEvent(eventName: string, project: Project, fileName: string) {
|
|
|
|
|
@@ -412,14 +412,17 @@ namespace ts.server {
|
|
|
|
|
|
|
|
|
|
private getRenameLocations(line: number, offset: number, fileName: string, findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody {
|
|
|
|
|
const file = ts.normalizePath(fileName);
|
|
|
|
|
const project = this.projectService.getProjectForFile(file);
|
|
|
|
|
if (!project) {
|
|
|
|
|
const info = this.projectService.getScriptInfo(file);
|
|
|
|
|
const projects = this.projectService.findReferencingProjects(info);
|
|
|
|
|
if (!projects.length) {
|
|
|
|
|
throw Errors.NoProject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const compilerService = project.compilerService;
|
|
|
|
|
const position = compilerService.host.lineOffsetToPosition(file, line, offset);
|
|
|
|
|
const renameInfo = compilerService.languageService.getRenameInfo(file, position);
|
|
|
|
|
const defaultProject = projects[0];
|
|
|
|
|
// The rename info should be the same for every project
|
|
|
|
|
const defaultProjectCompilerService = defaultProject.compilerService;
|
|
|
|
|
const position = defaultProjectCompilerService.host.lineOffsetToPosition(file, line, offset);
|
|
|
|
|
const renameInfo = defaultProjectCompilerService.languageService.getRenameInfo(file, position);
|
|
|
|
|
if (!renameInfo) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
@@ -431,16 +434,43 @@ namespace ts.server {
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments);
|
|
|
|
|
if (!renameLocations) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
const fileSpans = combineProjectOutput(
|
|
|
|
|
projects,
|
|
|
|
|
(project: Project) => {
|
|
|
|
|
const compilerService = project.compilerService;
|
|
|
|
|
const renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments);
|
|
|
|
|
if (!renameLocations) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bakedRenameLocs = renameLocations.map(location => (<protocol.FileSpan>{
|
|
|
|
|
file: location.fileName,
|
|
|
|
|
start: compilerService.host.positionToLineOffset(location.fileName, location.textSpan.start),
|
|
|
|
|
end: compilerService.host.positionToLineOffset(location.fileName, ts.textSpanEnd(location.textSpan)),
|
|
|
|
|
})).sort((a, b) => {
|
|
|
|
|
return renameLocations.map(location => (<protocol.FileSpan>{
|
|
|
|
|
file: location.fileName,
|
|
|
|
|
start: compilerService.host.positionToLineOffset(location.fileName, location.textSpan.start),
|
|
|
|
|
end: compilerService.host.positionToLineOffset(location.fileName, 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;
|
|
|
|
|
}
|
|
|
|
|
@@ -459,70 +489,70 @@ namespace ts.server {
|
|
|
|
|
return b.start.offset - a.start.offset;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}).reduce<protocol.SpanGroup[]>((accum: protocol.SpanGroup[], cur: protocol.FileSpan) => {
|
|
|
|
|
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: bakedRenameLocs };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private getReferences(line: number, offset: number, fileName: string): protocol.ReferencesResponseBody {
|
|
|
|
|
// TODO: get all projects for this file; report refs for all projects deleting duplicates
|
|
|
|
|
// can avoid duplicates by eliminating same ref file from subsequent projects
|
|
|
|
|
const file = ts.normalizePath(fileName);
|
|
|
|
|
const project = this.projectService.getProjectForFile(file);
|
|
|
|
|
if (!project) {
|
|
|
|
|
const info = this.projectService.getScriptInfo(file);
|
|
|
|
|
const projects = this.projectService.findReferencingProjects(info);
|
|
|
|
|
if (!projects.length) {
|
|
|
|
|
throw Errors.NoProject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const compilerService = project.compilerService;
|
|
|
|
|
const position = compilerService.host.lineOffsetToPosition(file, line, offset);
|
|
|
|
|
|
|
|
|
|
const references = compilerService.languageService.getReferencesAtPosition(file, position);
|
|
|
|
|
if (!references) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const nameInfo = compilerService.languageService.getQuickInfoAtPosition(file, position);
|
|
|
|
|
const defaultProject = projects[0];
|
|
|
|
|
const position = defaultProject.compilerService.host.lineOffsetToPosition(file, line, offset);
|
|
|
|
|
const nameInfo = defaultProject.compilerService.languageService.getQuickInfoAtPosition(file, position);
|
|
|
|
|
if (!nameInfo) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const displayString = ts.displayPartsToString(nameInfo.displayParts);
|
|
|
|
|
const nameSpan = nameInfo.textSpan;
|
|
|
|
|
const nameColStart = compilerService.host.positionToLineOffset(file, nameSpan.start).offset;
|
|
|
|
|
const nameText = compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan));
|
|
|
|
|
const bakedRefs: protocol.ReferencesResponseItem[] = references.map(ref => {
|
|
|
|
|
const start = compilerService.host.positionToLineOffset(ref.fileName, ref.textSpan.start);
|
|
|
|
|
const refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1);
|
|
|
|
|
const snap = compilerService.host.getScriptSnapshot(ref.fileName);
|
|
|
|
|
const lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, "");
|
|
|
|
|
return {
|
|
|
|
|
file: ref.fileName,
|
|
|
|
|
start: start,
|
|
|
|
|
lineText: lineText,
|
|
|
|
|
end: compilerService.host.positionToLineOffset(ref.fileName, ts.textSpanEnd(ref.textSpan)),
|
|
|
|
|
isWriteAccess: ref.isWriteAccess
|
|
|
|
|
};
|
|
|
|
|
}).sort(compareFileStart);
|
|
|
|
|
const nameColStart = defaultProject.compilerService.host.positionToLineOffset(file, nameSpan.start).offset;
|
|
|
|
|
const nameText = defaultProject.compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan));
|
|
|
|
|
const refs = combineProjectOutput<protocol.ReferencesResponseItem>(
|
|
|
|
|
projects,
|
|
|
|
|
(project: Project) => {
|
|
|
|
|
const compilerService = project.compilerService;
|
|
|
|
|
const references = compilerService.languageService.getReferencesAtPosition(file, position);
|
|
|
|
|
if (!references) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return references.map(ref => {
|
|
|
|
|
const start = compilerService.host.positionToLineOffset(ref.fileName, ref.textSpan.start);
|
|
|
|
|
const refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1);
|
|
|
|
|
const snap = compilerService.host.getScriptSnapshot(ref.fileName);
|
|
|
|
|
const lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, "");
|
|
|
|
|
return {
|
|
|
|
|
file: ref.fileName,
|
|
|
|
|
start: start,
|
|
|
|
|
lineText: lineText,
|
|
|
|
|
end: compilerService.host.positionToLineOffset(ref.fileName, ts.textSpanEnd(ref.textSpan)),
|
|
|
|
|
isWriteAccess: ref.isWriteAccess
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
compareFileStart,
|
|
|
|
|
areReferencesResponseItemsForTheSameLocation
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
refs: bakedRefs,
|
|
|
|
|
refs,
|
|
|
|
|
symbolName: nameText,
|
|
|
|
|
symbolStartOffset: nameColStart,
|
|
|
|
|
symbolDisplayString: displayString
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function areReferencesResponseItemsForTheSameLocation(a: protocol.ReferencesResponseItem, b: protocol.ReferencesResponseItem) {
|
|
|
|
|
if (a && b) {
|
|
|
|
|
return a.file === b.file &&
|
|
|
|
|
a.start === b.start &&
|
|
|
|
|
a.end === b.end;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -836,41 +866,60 @@ namespace ts.server {
|
|
|
|
|
|
|
|
|
|
private getNavigateToItems(searchValue: string, fileName: string, maxResultCount?: number): protocol.NavtoItem[] {
|
|
|
|
|
const file = ts.normalizePath(fileName);
|
|
|
|
|
const project = this.projectService.getProjectForFile(file);
|
|
|
|
|
if (!project) {
|
|
|
|
|
const info = this.projectService.getScriptInfo(file);
|
|
|
|
|
const projects = this.projectService.findReferencingProjects(info);
|
|
|
|
|
const defaultProject = projects[0];
|
|
|
|
|
if (!defaultProject) {
|
|
|
|
|
throw Errors.NoProject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const compilerService = project.compilerService;
|
|
|
|
|
const navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount);
|
|
|
|
|
if (!navItems) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
const allNavToItems = combineProjectOutput(
|
|
|
|
|
projects,
|
|
|
|
|
(project: Project) => {
|
|
|
|
|
const compilerService = project.compilerService;
|
|
|
|
|
const navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount);
|
|
|
|
|
if (!navItems) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return navItems.map((navItem) => {
|
|
|
|
|
const start = compilerService.host.positionToLineOffset(navItem.fileName, navItem.textSpan.start);
|
|
|
|
|
const end = compilerService.host.positionToLineOffset(navItem.fileName, ts.textSpanEnd(navItem.textSpan));
|
|
|
|
|
const bakedItem: protocol.NavtoItem = {
|
|
|
|
|
name: navItem.name,
|
|
|
|
|
kind: navItem.kind,
|
|
|
|
|
file: navItem.fileName,
|
|
|
|
|
start: start,
|
|
|
|
|
end: end,
|
|
|
|
|
};
|
|
|
|
|
if (navItem.kindModifiers && (navItem.kindModifiers != "")) {
|
|
|
|
|
bakedItem.kindModifiers = navItem.kindModifiers;
|
|
|
|
|
return navItems.map((navItem) => {
|
|
|
|
|
const start = compilerService.host.positionToLineOffset(navItem.fileName, navItem.textSpan.start);
|
|
|
|
|
const end = compilerService.host.positionToLineOffset(navItem.fileName, ts.textSpanEnd(navItem.textSpan));
|
|
|
|
|
const bakedItem: protocol.NavtoItem = {
|
|
|
|
|
name: navItem.name,
|
|
|
|
|
kind: navItem.kind,
|
|
|
|
|
file: navItem.fileName,
|
|
|
|
|
start: start,
|
|
|
|
|
end: end,
|
|
|
|
|
};
|
|
|
|
|
if (navItem.kindModifiers && (navItem.kindModifiers !== "")) {
|
|
|
|
|
bakedItem.kindModifiers = navItem.kindModifiers;
|
|
|
|
|
}
|
|
|
|
|
if (navItem.matchKind !== "none") {
|
|
|
|
|
bakedItem.matchKind = navItem.matchKind;
|
|
|
|
|
}
|
|
|
|
|
if (navItem.containerName && (navItem.containerName.length > 0)) {
|
|
|
|
|
bakedItem.containerName = navItem.containerName;
|
|
|
|
|
}
|
|
|
|
|
if (navItem.containerKind && (navItem.containerKind.length > 0)) {
|
|
|
|
|
bakedItem.containerKind = navItem.containerKind;
|
|
|
|
|
}
|
|
|
|
|
return bakedItem;
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
/*comparer*/ undefined,
|
|
|
|
|
areNavToItemsForTheSameLocation
|
|
|
|
|
);
|
|
|
|
|
return allNavToItems;
|
|
|
|
|
|
|
|
|
|
function areNavToItemsForTheSameLocation(a: protocol.NavtoItem, b: protocol.NavtoItem) {
|
|
|
|
|
if (a && b) {
|
|
|
|
|
return a.file === b.file &&
|
|
|
|
|
a.start === b.start &&
|
|
|
|
|
a.end === b.end;
|
|
|
|
|
}
|
|
|
|
|
if (navItem.matchKind !== "none") {
|
|
|
|
|
bakedItem.matchKind = navItem.matchKind;
|
|
|
|
|
}
|
|
|
|
|
if (navItem.containerName && (navItem.containerName.length > 0)) {
|
|
|
|
|
bakedItem.containerName = navItem.containerName;
|
|
|
|
|
}
|
|
|
|
|
if (navItem.containerKind && (navItem.containerKind.length > 0)) {
|
|
|
|
|
bakedItem.containerKind = navItem.containerKind;
|
|
|
|
|
}
|
|
|
|
|
return bakedItem;
|
|
|
|
|
});
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private getBraceMatching(line: number, offset: number, fileName: string): protocol.TextSpan[] {
|
|
|
|
|
@@ -944,26 +993,26 @@ namespace ts.server {
|
|
|
|
|
exit() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private handlers: Map<(request: protocol.Request) => {response?: any, responseRequired?: boolean}> = {
|
|
|
|
|
private handlers: Map<(request: protocol.Request) => { response?: any, responseRequired?: boolean }> = {
|
|
|
|
|
[CommandNames.Exit]: () => {
|
|
|
|
|
this.exit();
|
|
|
|
|
return { responseRequired: false};
|
|
|
|
|
return { responseRequired: false };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Definition]: (request: protocol.Request) => {
|
|
|
|
|
const defArgs = <protocol.FileLocationRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true};
|
|
|
|
|
return { response: this.getDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.TypeDefinition]: (request: protocol.Request) => {
|
|
|
|
|
const defArgs = <protocol.FileLocationRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true};
|
|
|
|
|
return { response: this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.References]: (request: protocol.Request) => {
|
|
|
|
|
const defArgs = <protocol.FileLocationRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getReferences(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true};
|
|
|
|
|
return { response: this.getReferences(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Rename]: (request: protocol.Request) => {
|
|
|
|
|
const renameArgs = <protocol.RenameRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings), responseRequired: true};
|
|
|
|
|
return { response: this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Open]: (request: protocol.Request) => {
|
|
|
|
|
const openArgs = <protocol.OpenRequestArgs>request.arguments;
|
|
|
|
|
@@ -983,52 +1032,54 @@ namespace ts.server {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
this.openClientFile(openArgs.file, openArgs.fileContent, scriptKind);
|
|
|
|
|
return {responseRequired: false};
|
|
|
|
|
return { responseRequired: false };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Quickinfo]: (request: protocol.Request) => {
|
|
|
|
|
const quickinfoArgs = <protocol.FileLocationRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.offset, quickinfoArgs.file), responseRequired: true};
|
|
|
|
|
return { response: this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.offset, quickinfoArgs.file), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Format]: (request: protocol.Request) => {
|
|
|
|
|
const formatArgs = <protocol.FormatRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getFormattingEditsForRange(formatArgs.line, formatArgs.offset, formatArgs.endLine, formatArgs.endOffset, formatArgs.file), responseRequired: true};
|
|
|
|
|
return { response: this.getFormattingEditsForRange(formatArgs.line, formatArgs.offset, formatArgs.endLine, formatArgs.endOffset, formatArgs.file), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Formatonkey]: (request: protocol.Request) => {
|
|
|
|
|
const formatOnKeyArgs = <protocol.FormatOnKeyRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.offset, formatOnKeyArgs.key, formatOnKeyArgs.file), responseRequired: true};
|
|
|
|
|
return { response: this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.offset, formatOnKeyArgs.key, formatOnKeyArgs.file), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Completions]: (request: protocol.Request) => {
|
|
|
|
|
const completionsArgs = <protocol.CompletionsRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file), responseRequired: true};
|
|
|
|
|
return { response: this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.CompletionDetails]: (request: protocol.Request) => {
|
|
|
|
|
const completionDetailsArgs = <protocol.CompletionDetailsRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getCompletionEntryDetails(completionDetailsArgs.line, completionDetailsArgs.offset,
|
|
|
|
|
completionDetailsArgs.entryNames, completionDetailsArgs.file), responseRequired: true};
|
|
|
|
|
return {
|
|
|
|
|
response: this.getCompletionEntryDetails(completionDetailsArgs.line, completionDetailsArgs.offset,
|
|
|
|
|
completionDetailsArgs.entryNames, completionDetailsArgs.file), responseRequired: true
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.SignatureHelp]: (request: protocol.Request) => {
|
|
|
|
|
const signatureHelpArgs = <protocol.SignatureHelpRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file), responseRequired: true};
|
|
|
|
|
return { response: this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Geterr]: (request: protocol.Request) => {
|
|
|
|
|
const geterrArgs = <protocol.GeterrRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false};
|
|
|
|
|
return { response: this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.GeterrForProject]: (request: protocol.Request) => {
|
|
|
|
|
const { file, delay } = <protocol.GeterrForProjectRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getDiagnosticsForProject(delay, file), responseRequired: false};
|
|
|
|
|
return { response: this.getDiagnosticsForProject(delay, file), responseRequired: false };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Change]: (request: protocol.Request) => {
|
|
|
|
|
const changeArgs = <protocol.ChangeRequestArgs>request.arguments;
|
|
|
|
|
this.change(changeArgs.line, changeArgs.offset, changeArgs.endLine, changeArgs.endOffset,
|
|
|
|
|
changeArgs.insertString, changeArgs.file);
|
|
|
|
|
return {responseRequired: false};
|
|
|
|
|
changeArgs.insertString, changeArgs.file);
|
|
|
|
|
return { responseRequired: false };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Configure]: (request: protocol.Request) => {
|
|
|
|
|
const configureArgs = <protocol.ConfigureRequestArguments>request.arguments;
|
|
|
|
|
this.projectService.setHostConfiguration(configureArgs);
|
|
|
|
|
this.output(undefined, CommandNames.Configure, request.seq);
|
|
|
|
|
return {responseRequired: false};
|
|
|
|
|
return { responseRequired: false };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Reload]: (request: protocol.Request) => {
|
|
|
|
|
const reloadArgs = <protocol.ReloadRequestArgs>request.arguments;
|
|
|
|
|
@@ -1038,50 +1089,50 @@ namespace ts.server {
|
|
|
|
|
[CommandNames.Saveto]: (request: protocol.Request) => {
|
|
|
|
|
const savetoArgs = <protocol.SavetoRequestArgs>request.arguments;
|
|
|
|
|
this.saveToTmp(savetoArgs.file, savetoArgs.tmpfile);
|
|
|
|
|
return {responseRequired: false};
|
|
|
|
|
return { responseRequired: false };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Close]: (request: protocol.Request) => {
|
|
|
|
|
const closeArgs = <protocol.FileRequestArgs>request.arguments;
|
|
|
|
|
this.closeClientFile(closeArgs.file);
|
|
|
|
|
return {responseRequired: false};
|
|
|
|
|
return { responseRequired: false };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Navto]: (request: protocol.Request) => {
|
|
|
|
|
const navtoArgs = <protocol.NavtoRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getNavigateToItems(navtoArgs.searchValue, navtoArgs.file, navtoArgs.maxResultCount), responseRequired: true};
|
|
|
|
|
return { response: this.getNavigateToItems(navtoArgs.searchValue, navtoArgs.file, navtoArgs.maxResultCount), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Brace]: (request: protocol.Request) => {
|
|
|
|
|
const braceArguments = <protocol.FileLocationRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getBraceMatching(braceArguments.line, braceArguments.offset, braceArguments.file), responseRequired: true};
|
|
|
|
|
return { response: this.getBraceMatching(braceArguments.line, braceArguments.offset, braceArguments.file), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.NavBar]: (request: protocol.Request) => {
|
|
|
|
|
const navBarArgs = <protocol.FileRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getNavigationBarItems(navBarArgs.file), responseRequired: true};
|
|
|
|
|
return { response: this.getNavigationBarItems(navBarArgs.file), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.Occurrences]: (request: protocol.Request) => {
|
|
|
|
|
const { line, offset, file: fileName } = <protocol.FileLocationRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getOccurrences(line, offset, fileName), responseRequired: true};
|
|
|
|
|
return { response: this.getOccurrences(line, offset, fileName), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.DocumentHighlights]: (request: protocol.Request) => {
|
|
|
|
|
const { line, offset, file: fileName, filesToSearch } = <protocol.DocumentHighlightsRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getDocumentHighlights(line, offset, fileName, filesToSearch), responseRequired: true};
|
|
|
|
|
return { response: this.getDocumentHighlights(line, offset, fileName, filesToSearch), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.ProjectInfo]: (request: protocol.Request) => {
|
|
|
|
|
const { file, needFileNameList } = <protocol.ProjectInfoRequestArgs>request.arguments;
|
|
|
|
|
return {response: this.getProjectInfo(file, needFileNameList), responseRequired: true};
|
|
|
|
|
return { response: this.getProjectInfo(file, needFileNameList), responseRequired: true };
|
|
|
|
|
},
|
|
|
|
|
[CommandNames.ReloadProjects]: (request: protocol.ReloadProjectsRequest) => {
|
|
|
|
|
this.reloadProjects();
|
|
|
|
|
return {responseRequired: false};
|
|
|
|
|
return { responseRequired: false };
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
public addProtocolHandler(command: string, handler: (request: protocol.Request) => {response?: any, responseRequired: boolean}) {
|
|
|
|
|
public addProtocolHandler(command: string, handler: (request: protocol.Request) => { response?: any, responseRequired: boolean }) {
|
|
|
|
|
if (this.handlers[command]) {
|
|
|
|
|
throw new Error(`Protocol handler already exists for command "${command}"`);
|
|
|
|
|
}
|
|
|
|
|
this.handlers[command] = handler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public executeCommand(request: protocol.Request): {response?: any, responseRequired?: boolean} {
|
|
|
|
|
public executeCommand(request: protocol.Request): { response?: any, responseRequired?: boolean } {
|
|
|
|
|
const handler = this.handlers[request.command];
|
|
|
|
|
if (handler) {
|
|
|
|
|
return handler(request);
|
|
|
|
|
@@ -1089,7 +1140,7 @@ namespace ts.server {
|
|
|
|
|
else {
|
|
|
|
|
this.projectService.log("Unrecognized JSON command: " + JSON.stringify(request));
|
|
|
|
|
this.output(undefined, CommandNames.Unknown, request.seq, "Unrecognized JSON command: " + request.command);
|
|
|
|
|
return {responseRequired: false};
|
|
|
|
|
return { responseRequired: false };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|