2017-04-30 16:08:58 +00:00
|
|
|
/*---------------------------------------------------------
|
|
|
|
* Copyright (C) Microsoft Corporation. All rights reserved.
|
|
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
|
|
*--------------------------------------------------------*/
|
|
|
|
'use strict';
|
|
|
|
const vscode = require('vscode');
|
|
|
|
const cp = require('child_process');
|
|
|
|
const path = require('path');
|
|
|
|
function definitionLocation(document, position, toolForDocs, includeDocs = true) {
|
|
|
|
return getGoVersion().then((ver) => {
|
|
|
|
if (!ver) {
|
|
|
|
return Promise.resolve(null);
|
|
|
|
}
|
|
|
|
if (toolForDocs === 'godoc' || ver.major < 1 || (ver.major === 1 && ver.minor < 6)) {
|
|
|
|
return definitionLocation_godef(document, position, includeDocs);
|
|
|
|
}
|
|
|
|
return definitionLocation_gogetdoc(document, position);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
exports.definitionLocation = definitionLocation;
|
|
|
|
function definitionLocation_godef(document, position, includeDocs = true) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
let wordAtPosition = document.getWordRangeAtPosition(position);
|
|
|
|
let offset = byteOffsetAt(document, position);
|
|
|
|
let godef = getBinPath('godef');
|
|
|
|
// Spawn `godef` process
|
|
|
|
let p = cp.execFile(godef, ['-t', '-i', '-f', document.fileName, '-o', offset.toString()], {}, (err, stdout, stderr) => {
|
|
|
|
try {
|
|
|
|
if (err && err.code === 'ENOENT') {
|
|
|
|
promptForMissingTool('godef');
|
|
|
|
}
|
|
|
|
if (err) {
|
|
|
|
console.log(err);
|
|
|
|
return resolve(null);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
let result = stdout.toString();
|
|
|
|
let lines = result.split('\n');
|
|
|
|
let match = /(.*):(\d+):(\d+)/.exec(lines[0]);
|
|
|
|
if (!match) {
|
|
|
|
// TODO: Gotodef on pkg name:
|
|
|
|
// /usr/local/go/src/html/template\n
|
|
|
|
return resolve(null);
|
|
|
|
}
|
|
|
|
let [_, file, line, col] = match;
|
|
|
|
let signature = lines[1];
|
|
|
|
let godoc = getBinPath('godoc');
|
|
|
|
let pkgPath = path.dirname(file);
|
|
|
|
let definitionInformation = {
|
|
|
|
file: file,
|
|
|
|
line: +line - 1,
|
|
|
|
column: +col - 1,
|
|
|
|
declarationlines: lines.splice(1),
|
|
|
|
toolUsed: 'godef',
|
|
|
|
doc: null,
|
|
|
|
name: null
|
|
|
|
};
|
|
|
|
if (!includeDocs) {
|
|
|
|
return resolve(definitionInformation);
|
|
|
|
}
|
|
|
|
cp.execFile(godoc, [pkgPath], {}, (err, stdout, stderr) => {
|
|
|
|
if (err && err.code === 'ENOENT') {
|
|
|
|
vscode.window.showInformationMessage('The "godoc" command is not available.');
|
|
|
|
}
|
|
|
|
let godocLines = stdout.toString().split('\n');
|
|
|
|
let doc = '';
|
|
|
|
let sigName = signature.substring(0, signature.indexOf(' '));
|
|
|
|
let sigParams = signature.substring(signature.indexOf(' func') + 5);
|
|
|
|
let searchSignature = 'func ' + sigName + sigParams;
|
|
|
|
for (let i = 0; i < godocLines.length; i++) {
|
|
|
|
if (godocLines[i] === searchSignature) {
|
|
|
|
while (godocLines[++i].startsWith(' ')) {
|
|
|
|
doc += godocLines[i].substring(4) + '\n';
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (doc !== '') {
|
|
|
|
definitionInformation.doc = doc;
|
|
|
|
}
|
|
|
|
return resolve(definitionInformation);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
reject(e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
p.stdin.end(document.getText());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
function definitionLocation_gogetdoc(document, position) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
let wordAtPosition = document.getWordRangeAtPosition(position);
|
|
|
|
let offset = byteOffsetAt(document, position);
|
|
|
|
let gogetdoc = getBinPath('gogetdoc');
|
|
|
|
let p = cp.execFile(gogetdoc, ['-u', '-json', '-modified', '-pos', document.fileName + ':#' + offset.toString()], {}, (err, stdout, stderr) => {
|
|
|
|
try {
|
|
|
|
if (err && err.code === 'ENOENT') {
|
|
|
|
promptForMissingTool('gogetdoc');
|
|
|
|
}
|
|
|
|
if (err) {
|
|
|
|
console.log(err);
|
|
|
|
return resolve(null);
|
|
|
|
}
|
|
|
|
;
|
|
|
|
let goGetDocOutput = JSON.parse(stdout.toString());
|
|
|
|
let match = /(.*):(\d+):(\d+)/.exec(goGetDocOutput.pos);
|
|
|
|
let definitionInfo = {
|
|
|
|
file: null,
|
|
|
|
line: 0,
|
|
|
|
column: 0,
|
|
|
|
toolUsed: 'gogetdoc',
|
|
|
|
declarationlines: goGetDocOutput.decl.split('\n'),
|
|
|
|
doc: goGetDocOutput.doc,
|
|
|
|
name: goGetDocOutput.name
|
|
|
|
};
|
|
|
|
if (!match) {
|
|
|
|
return resolve(definitionInfo);
|
|
|
|
}
|
|
|
|
let [_, file, line, col] = match;
|
|
|
|
definitionInfo.file = match[1];
|
|
|
|
definitionInfo.line = +match[2] - 1;
|
|
|
|
definitionInfo.column = +match[3] - 1;
|
|
|
|
return resolve(definitionInfo);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
reject(e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
let documentText = document.getText();
|
|
|
|
let documentArchive = document.fileName + '\n';
|
|
|
|
documentArchive = documentArchive + Buffer.byteLength(documentText) + '\n';
|
|
|
|
documentArchive = documentArchive + documentText;
|
|
|
|
p.stdin.end(documentArchive);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
class GoDefinitionProvider {
|
|
|
|
constructor(toolForDocs) {
|
|
|
|
this.toolForDocs = 'godoc';
|
|
|
|
this.toolForDocs = toolForDocs;
|
|
|
|
}
|
|
|
|
provideDefinition(document, position, token) {
|
|
|
|
return definitionLocation(document, position, this.toolForDocs, false).then(definitionInfo => {
|
|
|
|
if (definitionInfo == null || definitionInfo.file == null)
|
|
|
|
return null;
|
|
|
|
let definitionResource = vscode.Uri.file(definitionInfo.file);
|
|
|
|
let pos = new vscode.Position(definitionInfo.line, definitionInfo.column);
|
|
|
|
return new vscode.Location(definitionResource, pos);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2017-06-28 09:15:35 +00:00
|
|
|
exports.GoDefinitionProvider = GoDefinitionProvider;
|