Split completions req/response pair into two messages "completions" and
"completionEntryDetails". This mirrors the function of the LS API and increases performance of completion in large projects.
This commit is contained in:
parent
3868fb5a6b
commit
4b590836e7
3 changed files with 83 additions and 41 deletions
|
@ -1,5 +1,5 @@
|
|||
/// <reference path="session.ts" />
|
||||
|
||||
|
||||
module ts.server {
|
||||
|
||||
export interface SessionClientHost extends LanguageServiceHost {
|
||||
|
@ -172,7 +172,7 @@ module ts.server {
|
|||
documentation: [{ kind: "text", text: response.body.documentation }]
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
getCompletionsAtPosition(fileName: string, position: number): CompletionInfo {
|
||||
var lineCol = this.positionToOneBasedLineCol(fileName, position);
|
||||
var args: protocol.CompletionsRequestArgs = {
|
||||
|
@ -185,27 +185,28 @@ module ts.server {
|
|||
var request = this.processRequest<protocol.CompletionsRequest>(CommandNames.Completions, args);
|
||||
var response = this.processResponse<protocol.CompletionsResponse>(request);
|
||||
|
||||
return this.lastCompletionEntry = {
|
||||
return {
|
||||
isMemberCompletion: false,
|
||||
isNewIdentifierLocation: false,
|
||||
entries: response.body.map(entry => ({
|
||||
kind: entry.kind,
|
||||
kindModifiers: entry.kindModifiers,
|
||||
name: entry.name,
|
||||
displayParts: entry.displayParts,
|
||||
documentation: entry.documentation
|
||||
})),
|
||||
entries: response.body,
|
||||
fileName: fileName,
|
||||
position: position
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails {
|
||||
if (!this.lastCompletionEntry || this.lastCompletionEntry.fileName !== fileName || this.lastCompletionEntry.position !== position) {
|
||||
this.getCompletionsAtPosition(fileName, position);
|
||||
}
|
||||
var lineCol = this.positionToOneBasedLineCol(fileName, position);
|
||||
var args: protocol.CompletionDetailsRequestArgs = {
|
||||
file: fileName,
|
||||
line: lineCol.line,
|
||||
col: lineCol.col,
|
||||
entryNames: [entryName]
|
||||
};
|
||||
|
||||
return <CompletionEntryDetails>this.lastCompletionEntry.entries.filter(entry => entry.name === entryName)[0];
|
||||
var request = this.processRequest<protocol.CompletionDetailsRequest>(CommandNames.CompletionDetails, args);
|
||||
var response = this.processResponse<protocol.CompletionDetailsResponse>(request);
|
||||
Debug.assert(response.body.length == 1, "Unexpected length of completion details response body.");
|
||||
return response.body[0];
|
||||
}
|
||||
|
||||
getNavigateToItems(searchTerm: string): NavigateToItem[] {
|
||||
|
|
43
src/server/protocol.d.ts
vendored
43
src/server/protocol.d.ts
vendored
|
@ -471,6 +471,26 @@ declare module ts.server.protocol {
|
|||
arguments: CompletionsRequestArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments for completion details request.
|
||||
*/
|
||||
export interface CompletionDetailsRequestArgs extends FileLocationRequestArgs {
|
||||
/**
|
||||
* Names of one or more entries for which to obtain details.
|
||||
*/
|
||||
entryNames: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Completion entry details request; value of command field is
|
||||
* "completionEntryDetails". Given a file location (file, line,
|
||||
* col) and an array of completion entry names return more
|
||||
* detailed information for each completion entry.
|
||||
*/
|
||||
export interface CompletionDetailsRequest extends FileLocationRequest {
|
||||
arguments: CompletionDetailsRequestArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of a symbol description.
|
||||
*/
|
||||
|
@ -489,35 +509,42 @@ declare module ts.server.protocol {
|
|||
/**
|
||||
* An item found in a completion response.
|
||||
*/
|
||||
export interface CompletionItem {
|
||||
export interface CompletionEntry {
|
||||
/**
|
||||
* The symbol's name.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The symbol's kind (such as 'className' or 'parameterName').
|
||||
*/
|
||||
kind: string;
|
||||
|
||||
/**
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
kindModifiers?: string;
|
||||
|
||||
kindModifiers: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional completion entry details, available on demand
|
||||
*/
|
||||
export interface CompletionEntryDetails extends CompletionEntry {
|
||||
/**
|
||||
* Display parts of the symbol (similar to quick info).
|
||||
*/
|
||||
displayParts?: SymbolDisplayPart[];
|
||||
displayParts: SymbolDisplayPart[];
|
||||
|
||||
/**
|
||||
* Documentation strings for the symbol.
|
||||
*/
|
||||
documentation?: SymbolDisplayPart[];
|
||||
documentation: SymbolDisplayPart[];
|
||||
}
|
||||
|
||||
export interface CompletionsResponse extends Response {
|
||||
body?: CompletionItem[];
|
||||
body?: CompletionEntry[];
|
||||
}
|
||||
|
||||
export interface CompletionDetailsResponse extends Response {
|
||||
body?: CompletionEntryDetails[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -81,7 +81,7 @@ module ts.server {
|
|||
function formatDiag(fileName: string, project: Project, diag: ts.Diagnostic) {
|
||||
return {
|
||||
start: project.compilerService.host.positionToLineCol(fileName, diag.start),
|
||||
end: project.compilerService.host.positionToLineCol(fileName, diag.start+diag.length),
|
||||
end: project.compilerService.host.positionToLineCol(fileName, diag.start + diag.length),
|
||||
text: ts.flattenDiagnosticMessageText(diag.messageText, "\n")
|
||||
};
|
||||
}
|
||||
|
@ -104,6 +104,7 @@ module ts.server {
|
|||
export var Change = "change";
|
||||
export var Close = "close";
|
||||
export var Completions = "completions";
|
||||
export var CompletionDetails = "completionEntryDetails";
|
||||
export var Definition = "definition";
|
||||
export var Format = "format";
|
||||
export var Formatonkey = "formatonkey";
|
||||
|
@ -486,8 +487,8 @@ module ts.server {
|
|||
};
|
||||
});
|
||||
}
|
||||
|
||||
getCompletions(line: number, col: number, prefix: string, fileName: string): protocol.CompletionItem[] {
|
||||
|
||||
getCompletions(line: number, col: number, prefix: string, fileName: string): protocol.CompletionEntry[] {
|
||||
if (!prefix) {
|
||||
prefix = "";
|
||||
}
|
||||
|
@ -505,27 +506,34 @@ module ts.server {
|
|||
throw Errors.NoContent;
|
||||
}
|
||||
|
||||
return completions.entries.reduce((result: ts.CompletionEntryDetails[], entry: ts.CompletionEntry) => {
|
||||
return completions.entries.reduce((result: protocol.CompletionEntry[], entry: ts.CompletionEntry) => {
|
||||
if (completions.isMemberCompletion || entry.name.indexOf(prefix) == 0) {
|
||||
var protoEntry = <ts.CompletionEntryDetails>{};
|
||||
protoEntry.name = entry.name;
|
||||
protoEntry.kind = entry.kind;
|
||||
if (entry.kindModifiers && (entry.kindModifiers.length > 0)) {
|
||||
protoEntry.kindModifiers = entry.kindModifiers;
|
||||
}
|
||||
var details = compilerService.languageService.getCompletionEntryDetails(file, position, entry.name);
|
||||
if (details && (details.documentation) && (details.documentation.length > 0)) {
|
||||
protoEntry.documentation = details.documentation;
|
||||
}
|
||||
if (details && (details.displayParts) && (details.displayParts.length > 0)) {
|
||||
protoEntry.displayParts = details.displayParts;
|
||||
}
|
||||
result.push(protoEntry);
|
||||
result.push(entry);
|
||||
}
|
||||
return result;
|
||||
}, []);
|
||||
}
|
||||
|
||||
getCompletionEntryDetails(line: number, col: number,
|
||||
entryNames: string[], fileName: string): protocol.CompletionEntryDetails[] {
|
||||
var file = ts.normalizePath(fileName);
|
||||
var project = this.projectService.getProjectForFile(file);
|
||||
if (!project) {
|
||||
throw Errors.NoProject;
|
||||
}
|
||||
|
||||
var compilerService = project.compilerService;
|
||||
var position = compilerService.host.lineColToPosition(file, line, col);
|
||||
|
||||
return entryNames.reduce((accum: protocol.CompletionEntryDetails[], entryName: string) => {
|
||||
var details = compilerService.languageService.getCompletionEntryDetails(file, position, entryName);
|
||||
if (details) {
|
||||
accum.push(details);
|
||||
}
|
||||
return accum;
|
||||
}, []);
|
||||
}
|
||||
|
||||
getDiagnostics(delay: number, fileNames: string[]) {
|
||||
var checkList = fileNames.reduce((accum: PendingErrorCheck[], fileName: string) => {
|
||||
fileName = ts.normalizePath(fileName);
|
||||
|
@ -724,6 +732,12 @@ module ts.server {
|
|||
response = this.getCompletions(request.arguments.line, request.arguments.col, completionsArgs.prefix, request.arguments.file);
|
||||
break;
|
||||
}
|
||||
case CommandNames.CompletionDetails: {
|
||||
var completionDetailsArgs = <protocol.CompletionDetailsRequestArgs>request.arguments;
|
||||
response = this.getCompletionEntryDetails(request.arguments.line, request.arguments.col, completionDetailsArgs.entryNames,
|
||||
request.arguments.file);
|
||||
break;
|
||||
}
|
||||
case CommandNames.Geterr: {
|
||||
var geterrArgs = <protocol.GeterrRequestArgs>request.arguments;
|
||||
response = this.getDiagnostics(geterrArgs.delay, geterrArgs.files);
|
||||
|
|
Loading…
Reference in a new issue