Skip to content

Commit 1dacffc

Browse files
committed
perf: autocomplete is now async
refs #27
1 parent bda36cf commit 1dacffc

10 files changed

+154
-79
lines changed

lib/main/atom/autoCompleteProvider.js

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
var programManager = require('../lang/programManager');
2-
var ts = require('typescript');
1+
var parent = require('../../worker/parent');
32
var fs = require('fs');
43
var atomUtils = require('./atomUtils');
54
var fuzzaldrin = require('fuzzaldrin');
@@ -20,39 +19,27 @@ var provider = {
2019
requestHandler: function (options) {
2120
var filePath = options.editor.getPath();
2221
if (!filePath)
23-
return [];
22+
return Promise.resolve([]);
2423
if (!fs.existsSync(filePath))
25-
return;
26-
var program = programManager.getOrCreateProgram(filePath);
27-
program.languageServiceHost.updateScript(filePath, options.editor.getText());
24+
return Promise.resolve([]);
2825
var position = atomUtils.getEditorPositionForBufferPosition(options.editor, options.position);
29-
var completions = program.languageService.getCompletionsAtPosition(filePath, position);
30-
var completionList = completions ? completions.entries.filter(function (x) { return !!x; }) : [];
31-
if (options.prefix.length && options.prefix !== '.') {
32-
completionList = fuzzaldrin.filter(completionList, options.prefix, { key: 'name' });
33-
}
34-
if (completionList.length > 10)
35-
completionList = completionList.slice(0, 10);
36-
function docComment(c) {
37-
var completionDetails = program.languageService.getCompletionEntryDetails(filePath, position, c.name);
38-
if (c.kind == "method" || c.kind == "function") {
39-
var display = ts.displayPartsToString(completionDetails.displayParts || []);
40-
}
41-
else {
42-
var display = c.kind;
43-
}
44-
var comment = ts.displayPartsToString(completionDetails.documentation || []);
45-
return { display: display, comment: comment };
46-
}
47-
var suggestions = completionList.map(function (c) {
48-
return {
49-
word: c.name,
50-
prefix: options.prefix == '.' ? '' : options.prefix,
51-
label: '<span style="color: ' + kindToColor(c.kind) + '">' + docComment(c).display + '</span>',
52-
renderLabelAsHtml: true,
53-
};
26+
var promisedSuggestions = parent.updateText({ filePath: filePath, text: options.editor.getText() }).then(function () { return parent.getCompletionsAtPosition({
27+
filePath: filePath,
28+
position: position,
29+
prefix: options.prefix
30+
}); }).then(function (resp) {
31+
var completionList = resp.completions;
32+
var suggestions = completionList.map(function (c) {
33+
return {
34+
word: c.name,
35+
prefix: options.prefix == '.' ? '' : options.prefix,
36+
label: '<span style="color: ' + kindToColor(c.kind) + '">' + c.display + '</span>',
37+
renderLabelAsHtml: true,
38+
};
39+
});
40+
return suggestions;
5441
});
55-
return suggestions;
42+
return promisedSuggestions;
5643
}
5744
};
5845
module.exports = provider;

lib/main/atom/autoCompleteProvider.ts

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
///ts:import=programManager
77
import programManager = require('../lang/programManager'); ///ts:import:generated
8+
///ts:import=parent
9+
import parent = require('../../worker/parent'); ///ts:import:generated
810
import ts = require('typescript');
911
import fs = require('fs');
1012

@@ -46,58 +48,37 @@ function kindToColor(kind: string) {
4648

4749
var provider = {
4850
selector: '.source.ts',
49-
requestHandler: (options: autocompleteplus.RequestOptions): autocompleteplus.Suggestion[]=> {
51+
requestHandler: (options: autocompleteplus.RequestOptions): Promise<autocompleteplus.Suggestion[]>=> {
5052
var filePath = options.editor.getPath();
5153

5254
// We refuse to work on files that are not on disk.
53-
if (!filePath) return [];
54-
if (!fs.existsSync(filePath)) return;
55-
56-
var program = programManager.getOrCreateProgram(filePath);
57-
// Update the file
58-
program.languageServiceHost.updateScript(filePath, options.editor.getText());
55+
if (!filePath) return Promise.resolve([]);
56+
if (!fs.existsSync(filePath)) return Promise.resolve([]);
5957

6058
var position = atomUtils.getEditorPositionForBufferPosition(options.editor, options.position);
6159

62-
var completions: ts.CompletionInfo = program.languageService.getCompletionsAtPosition(
63-
filePath, position);
64-
65-
var completionList = completions ? completions.entries.filter(x=> !!x) : [];
66-
67-
if (options.prefix.length && options.prefix !== '.') {
68-
completionList = fuzzaldrin.filter(completionList, options.prefix, { key: 'name' });
69-
}
70-
71-
// limit to 10
72-
if (completionList.length > 10) completionList = completionList.slice(0, 10);
73-
74-
// Potentially use it at some point
75-
function docComment(c: ts.CompletionEntry): { display: string; comment: string; } {
76-
var completionDetails = program.languageService.getCompletionEntryDetails(filePath, position, c.name);
77-
78-
// Show the signatures for methods / functions
79-
if (c.kind == "method" || c.kind == "function") {
80-
var display = ts.displayPartsToString(completionDetails.displayParts || []);
81-
} else {
82-
var display = c.kind;
83-
}
84-
var comment = ts.displayPartsToString(completionDetails.documentation || []);
85-
86-
return { display: display, comment: comment };
87-
}
88-
89-
// console.log(completionList.map(docComment));
90-
91-
var suggestions = completionList.map(c => {
92-
return {
93-
word: c.name,
94-
prefix: options.prefix == '.' ? '' : options.prefix,
95-
label: '<span style="color: ' + kindToColor(c.kind) + '">' + docComment(c).display + '</span>',
96-
renderLabelAsHtml: true,
97-
};
98-
});
99-
100-
return suggestions;
60+
var promisedSuggestions: Promise<autocompleteplus.Suggestion[]>
61+
// TODO: remove updateText once we have edit on change in place
62+
= parent.updateText({ filePath: filePath, text: options.editor.getText() })
63+
.then(() => parent.getCompletionsAtPosition({
64+
filePath: filePath,
65+
position: position,
66+
prefix: options.prefix
67+
}))
68+
.then((resp) => {
69+
var completionList = resp.completions;
70+
var suggestions = completionList.map(c => {
71+
return {
72+
word: c.name,
73+
prefix: options.prefix == '.' ? '' : options.prefix,
74+
label: '<span style="color: ' + kindToColor(c.kind) + '">' + c.display + '</span>',
75+
renderLabelAsHtml: true,
76+
};
77+
});
78+
return suggestions;
79+
});
80+
81+
return promisedSuggestions;
10182
}
10283
}
10384

lib/main/lang/programManager.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ var fs = require('fs');
22
var path = require('path');
33
var os = require('os');
44
var ts = require('typescript');
5+
var fuzzaldrin = require('fuzzaldrin');
56
var tsconfig = require('../tsconfig/tsconfig');
67
var languageServiceHost = require('./languageServiceHost');
78
var utils = require('./utils');
@@ -176,3 +177,34 @@ function defaultFormatCodeOptions() {
176177
};
177178
}
178179
exports.defaultFormatCodeOptions = defaultFormatCodeOptions;
180+
function getCompletionsAtPosition(filePath, position, prefix) {
181+
var program = getOrCreateProgram(filePath);
182+
var completions = program.languageService.getCompletionsAtPosition(filePath, position);
183+
var completionList = completions ? completions.entries.filter(function (x) { return !!x; }) : [];
184+
if (prefix.length && prefix !== '.') {
185+
completionList = fuzzaldrin.filter(completionList, prefix, { key: 'name' });
186+
}
187+
if (completionList.length > 10)
188+
completionList = completionList.slice(0, 10);
189+
function docComment(c) {
190+
var completionDetails = program.languageService.getCompletionEntryDetails(filePath, position, c.name);
191+
if (c.kind == "method" || c.kind == "function") {
192+
var display = ts.displayPartsToString(completionDetails.displayParts || []);
193+
}
194+
else {
195+
var display = c.kind;
196+
}
197+
var comment = ts.displayPartsToString(completionDetails.documentation || []);
198+
return { display: display, comment: comment };
199+
}
200+
return completionList.map(function (c) {
201+
var details = docComment(c);
202+
return {
203+
name: c.name,
204+
kind: c.kind,
205+
comment: details.comment,
206+
display: details.display
207+
};
208+
});
209+
}
210+
exports.getCompletionsAtPosition = getCompletionsAtPosition;

lib/main/lang/programManager.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import fs = require('fs');
55
import path = require('path');
66
import os = require('os');
77
import ts = require('typescript');
8+
var fuzzaldrin = require('fuzzaldrin');
89

910
import tsconfig = require('../tsconfig/tsconfig');
1011
import languageServiceHost = require('./languageServiceHost');
@@ -236,3 +237,50 @@ export function defaultFormatCodeOptions(): ts.FormatCodeOptions {
236237
PlaceOpenBraceOnNewLineForControlBlocks: false,
237238
};
238239
}
240+
241+
export interface Completion {
242+
name: string; // stuff like "toString"
243+
kind: string; // stuff like "var"
244+
comment: string; // the docComment if any
245+
display: string; // This is either displayParts (for functions) or just the kind duplicated
246+
}
247+
248+
/** gets the first 10 completions only */
249+
export function getCompletionsAtPosition(filePath: string, position: number, prefix: string): Completion[] {
250+
var program = getOrCreateProgram(filePath);
251+
var completions: ts.CompletionInfo = program.languageService.getCompletionsAtPosition(
252+
filePath, position);
253+
var completionList = completions ? completions.entries.filter(x=> !!x) : [];
254+
255+
if (prefix.length && prefix !== '.') {
256+
completionList = fuzzaldrin.filter(completionList, prefix, { key: 'name' });
257+
}
258+
259+
// limit to 10
260+
if (completionList.length > 10) completionList = completionList.slice(0, 10);
261+
262+
// Potentially use it more aggresively at some point
263+
function docComment(c: ts.CompletionEntry): { display: string; comment: string; } {
264+
var completionDetails = program.languageService.getCompletionEntryDetails(filePath, position, c.name);
265+
266+
// Show the signatures for methods / functions
267+
if (c.kind == "method" || c.kind == "function") {
268+
var display = ts.displayPartsToString(completionDetails.displayParts || []);
269+
} else {
270+
var display = c.kind;
271+
}
272+
var comment = ts.displayPartsToString(completionDetails.documentation || []);
273+
274+
return { display: display, comment: comment };
275+
}
276+
277+
return completionList.map(c=> {
278+
var details = docComment(c);
279+
return {
280+
name: c.name,
281+
kind: c.kind,
282+
comment: details.comment,
283+
display: details.display
284+
};
285+
});
286+
}

lib/worker/messages.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ exports.orphanExitCode = 100;
4040
exports.echo = 'echo';
4141
exports.updateText = 'updateText';
4242
exports.getErrorsForFile = 'getErrorsForFile';
43+
exports.getCompletionsAtPosition = 'getCompletionsAtPosition';

lib/worker/messages.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,14 @@ export interface GetErrorsForFileQuery {
8888
export interface GetErrorsForFileResponse {
8989
errors: programManager.TSError[];
9090
}
91+
92+
93+
export var getCompletionsAtPosition = 'getCompletionsAtPosition';
94+
export interface GetCompletionsAtPositionQuery {
95+
filePath: string;
96+
position: number;
97+
prefix: string;
98+
}
99+
export interface GetCompletionsAtPositionResponse {
100+
completions: programManager.Completion[];
101+
}

lib/worker/parent.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ function showError(error) {
101101
exports.echo = function (data) { return query(messages.echo, data); };
102102
exports.updateText = function (data) { return query(messages.updateText, data); };
103103
exports.getErrorsForFile = function (data) { return query(messages.getErrorsForFile, data); };
104+
exports.getCompletionsAtPosition = function (data) { return query(messages.getCompletionsAtPosition, data); };

lib/worker/parent.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,6 @@ export var updateText: Exec<messages.UpdateTextQuery, messages.EchoResponse>
142142

143143
export var getErrorsForFile: Exec<messages.GetErrorsForFileQuery, messages.GetErrorsForFileResponse>
144144
= (data) => query(messages.getErrorsForFile, data);
145+
146+
export var getCompletionsAtPosition: Exec<messages.GetCompletionsAtPositionQuery, messages.GetCompletionsAtPositionResponse>
147+
= (data) => query(messages.getCompletionsAtPosition, data);

lib/worker/workerProcess.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,8 @@ responders[messages.getErrorsForFile] = function (data) {
3737
errors: programManager.getErrorsForFile(data.filePath)
3838
};
3939
};
40+
responders[messages.getCompletionsAtPosition] = function (data) {
41+
return {
42+
completions: programManager.getCompletionsAtPosition(data.filePath, data.position, data.prefix)
43+
};
44+
};

lib/worker/workerProcess.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,14 @@ responders[messages.updateText] = (data: messages.UpdateTextQuery): messages.Upd
5050
return {};
5151
}
5252

53-
responders[messages.getErrorsForFile] = (data: messages.GetErrorsForFileQuery): messages.GetErrorsForFileResponse => {
53+
responders[messages.getErrorsForFile] = (data: messages.GetErrorsForFileQuery): messages.GetErrorsForFileResponse => {
5454
return {
5555
errors: programManager.getErrorsForFile(data.filePath)
5656
};
5757
}
58+
59+
responders[messages.getCompletionsAtPosition] = (data: messages.GetCompletionsAtPositionQuery): messages.GetCompletionsAtPositionResponse => {
60+
return {
61+
completions: programManager.getCompletionsAtPosition(data.filePath,data.position,data.prefix)
62+
};
63+
}

0 commit comments

Comments
 (0)