blob: 1aba8d9291df4b5b82e4738efafd74370a7c85cc [file] [log] [blame]
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------*/
'use strict';
import cp = require('child_process');
import path = require('path');
import vscode = require('vscode');
import { toolExecutionEnvironment } from './goEnv';
import { promptForMissingTool } from './goInstallTools';
import {
byteOffsetAt,
canonicalizeGOPATHPrefix,
getBinPath,
getFileArchive,
getGoConfig
} from './util';
import {killProcessTree} from './utils/processUtils';
export class GoReferenceProvider implements vscode.ReferenceProvider {
public provideReferences(
document: vscode.TextDocument,
position: vscode.Position,
options: { includeDeclaration: boolean },
token: vscode.CancellationToken
): Thenable<vscode.Location[]> {
return this.doFindReferences(document, position, options, token);
}
private doFindReferences(
document: vscode.TextDocument,
position: vscode.Position,
options: { includeDeclaration: boolean },
token: vscode.CancellationToken
): Thenable<vscode.Location[]> {
return new Promise<vscode.Location[]>((resolve, reject) => {
// get current word
const wordRange = document.getWordRangeAtPosition(position);
if (!wordRange) {
return resolve([]);
}
const goGuru = getBinPath('guru');
if (!path.isAbsolute(goGuru)) {
promptForMissingTool('guru');
return reject('Cannot find tool "guru" to find references.');
}
const filename = canonicalizeGOPATHPrefix(document.fileName);
const cwd = path.dirname(filename);
const offset = byteOffsetAt(document, wordRange.start);
const env = toolExecutionEnvironment();
const buildTags = getGoConfig(document.uri)['buildTags'];
const args = buildTags ? ['-tags', buildTags] : [];
args.push('-modified', 'referrers', `${filename}:#${offset.toString()}`);
const process = cp.execFile(goGuru, args, { env }, (err, stdout, stderr) => {
try {
if (err && (<any>err).code === 'ENOENT') {
promptForMissingTool('guru');
return reject('Cannot find tool "guru" to find references.');
}
if (err && (<any>err).killed !== true) {
return reject(`Error running guru: ${err.message || stderr}`);
}
const lines = stdout.toString().split('\n');
const results: vscode.Location[] = [];
for (const line of lines) {
const match = /^(.*):(\d+)\.(\d+)-(\d+)\.(\d+):/.exec(line);
if (!match) {
continue;
}
const [_, file, lineStartStr, colStartStr, lineEndStr, colEndStr] = match;
const referenceResource = vscode.Uri.file(path.resolve(cwd, file));
if (!options.includeDeclaration) {
if (
document.uri.fsPath === referenceResource.fsPath &&
position.line === Number(lineStartStr) - 1
) {
continue;
}
}
const range = new vscode.Range(
+lineStartStr - 1,
+colStartStr - 1,
+lineEndStr - 1,
+colEndStr
);
results.push(new vscode.Location(referenceResource, range));
}
resolve(results);
} catch (e) {
reject(e);
}
});
if (process.pid) {
process.stdin.end(getFileArchive(document));
}
token.onCancellationRequested(() => killProcessTree(process));
});
}
}