in src/goSuggest.ts [279:491]
private runGoCode(
document: vscode.TextDocument,
filename: string,
inputText: string,
offset: number,
inString: boolean,
position: vscode.Position,
lineText: string,
currentWord: string,
includeUnimportedPkgs: boolean,
config: vscode.WorkspaceConfiguration
): Thenable<vscode.CompletionItem[]> {
return new Promise<vscode.CompletionItem[]>((resolve, reject) => {
const gocodeName = this.isGoMod ? 'gocode-gomod' : 'gocode';
const gocode = getBinPath(gocodeName);
if (!path.isAbsolute(gocode)) {
promptForMissingTool(gocodeName);
return reject();
}
const env = toolExecutionEnvironment();
let stdout = '';
let stderr = '';
// stamblerre/gocode does not support -unimported-packages flags.
if (this.isGoMod) {
const unimportedPkgIndex = this.gocodeFlags.indexOf('-unimported-packages');
if (unimportedPkgIndex >= 0) {
this.gocodeFlags.splice(unimportedPkgIndex, 1);
}
}
// -exclude-docs is something we use internally and is not related to gocode
const excludeDocsIndex = this.gocodeFlags.indexOf('-exclude-docs');
if (excludeDocsIndex >= 0) {
this.gocodeFlags.splice(excludeDocsIndex, 1);
this.excludeDocs = true;
}
// Spawn `gocode` process
const p = cp.spawn(gocode, [...this.gocodeFlags, 'autocomplete', filename, '' + offset], { env });
p.stdout.on('data', (data) => (stdout += data));
p.stderr.on('data', (data) => (stderr += data));
p.on('error', (err) => {
if (err && (<any>err).code === 'ENOENT') {
promptForMissingTool(gocodeName);
return reject();
}
return reject(err);
});
p.on('close', (code) => {
try {
if (code !== 0) {
if (stderr.indexOf("rpc: can't find service Server.AutoComplete") > -1 && !this.killMsgShown) {
vscode.window.showErrorMessage(
'Auto-completion feature failed as an older gocode process is still running. Please kill the running process for gocode and try again.'
);
this.killMsgShown = true;
}
if (stderr.startsWith('flag provided but not defined:')) {
promptForUpdatingTool(gocodeName);
}
return reject();
}
const results = <[number, GoCodeSuggestion[]]>JSON.parse(stdout.toString());
let suggestions: vscode.CompletionItem[] = [];
const packageSuggestions: string[] = [];
const wordAtPosition = document.getWordRangeAtPosition(position);
let areCompletionsForPackageSymbols = false;
if (results && results[1]) {
for (const suggest of results[1]) {
if (inString && suggest.class !== 'import') {
continue;
}
const item = new ExtendedCompletionItem(suggest.name);
item.kind = vscodeKindFromGoCodeClass(suggest.class, suggest.type);
item.package = suggest.package;
item.receiver = suggest.receiver;
item.fileName = document.fileName;
item.detail = suggest.type;
if (!areCompletionsForPackageSymbols && item.package && item.package !== 'builtin') {
areCompletionsForPackageSymbols = true;
}
if (suggest.class === 'package') {
let { label } = item;
if (typeof label !== 'string') label = label.label;
const possiblePackageImportPaths = this.getPackageImportPath(label);
if (possiblePackageImportPaths.length === 1) {
item.detail = possiblePackageImportPaths[0];
}
packageSuggestions.push(suggest.name);
}
if (inString && suggest.class === 'import') {
item.textEdit = new vscode.TextEdit(
new vscode.Range(
position.line,
lineText.substring(0, position.character).lastIndexOf('"') + 1,
position.line,
position.character
),
suggest.name
);
}
if (
(config['useCodeSnippetsOnFunctionSuggest'] ||
config['useCodeSnippetsOnFunctionSuggestWithoutType']) &&
((suggest.class === 'func' && lineText.substr(position.character, 2) !== '()') || // Avoids met() -> method()()
(suggest.class === 'var' &&
suggest.type.startsWith('func(') &&
lineText.substr(position.character, 1) !== ')' && // Avoids snippets when typing params in a func call
lineText.substr(position.character, 1) !== ',')) // Avoids snippets when typing params in a func call
) {
const got = getParametersAndReturnType(suggest.type.substring(4));
const params = got.params;
const paramSnippets = [];
for (let i = 0; i < params.length; i++) {
let param = params[i].trim();
if (param) {
param = param.replace('${', '\\${').replace('}', '\\}');
if (config['useCodeSnippetsOnFunctionSuggestWithoutType']) {
if (param.includes(' ')) {
// Separate the variable name from the type
param = param.substr(0, param.indexOf(' '));
}
}
paramSnippets.push('${' + (i + 1) + ':' + param + '}');
}
}
item.insertText = new vscode.SnippetString(
suggest.name + '(' + paramSnippets.join(', ') + ')'
);
}
if (
config['useCodeSnippetsOnFunctionSuggest'] &&
suggest.class === 'type' &&
suggest.type.startsWith('func(')
) {
const { params, returnType } = getParametersAndReturnType(suggest.type.substring(4));
const paramSnippets = [];
for (let i = 0; i < params.length; i++) {
let param = params[i].trim();
if (param) {
param = param.replace('${', '\\${').replace('}', '\\}');
if (!param.includes(' ')) {
// If we don't have an argument name, we need to create one
param = 'arg' + (i + 1) + ' ' + param;
}
const arg = param.substr(0, param.indexOf(' '));
paramSnippets.push(
'${' +
(i + 1) +
':' +
arg +
'}' +
param.substr(param.indexOf(' '), param.length)
);
}
}
item.insertText = new vscode.SnippetString(
suggest.name +
'(func(' +
paramSnippets.join(', ') +
') {\n $' +
(params.length + 1) +
'\n})' +
returnType
);
}
if (
wordAtPosition &&
wordAtPosition.start.character === 0 &&
suggest.class === 'type' &&
!goBuiltinTypes.has(suggest.name)
) {
const auxItem = new vscode.CompletionItem(
suggest.name + ' method',
vscode.CompletionItemKind.Snippet
);
auxItem.label = 'func (*' + suggest.name + ')';
auxItem.filterText = suggest.name;
auxItem.detail = 'Method snippet';
auxItem.sortText = 'b';
const prefix = 'func (' + suggest.name[0].toLowerCase() + ' *' + suggest.name + ')';
const snippet = prefix + ' ${1:methodName}(${2}) ${3} {\n\t$0\n}';
auxItem.insertText = new vscode.SnippetString(snippet);
suggestions.push(auxItem);
}
// Add same sortText to all suggestions from gocode so that they appear before the unimported packages
item.sortText = 'a';
suggestions.push(item);
}
}
// Add importable packages matching currentword to suggestions
if (includeUnimportedPkgs && !this.isGoMod && !areCompletionsForPackageSymbols) {
suggestions = suggestions.concat(
getPackageCompletions(document, currentWord, this.pkgsList, packageSuggestions)
);
}
resolve(suggestions);
} catch (e) {
reject(e);
}
});
if (p.pid) {
p.stdin.end(inputText);
}
});
}