goc/tools/vscode-ext/src/gocserver.ts

185 lines
5.5 KiB
TypeScript
Raw Normal View History

2020-08-17 02:50:14 +00:00
import axios from 'axios';
axios.defaults.timeout = 3000;
import * as vscode from 'vscode';
import { spawnSync } from 'child_process';
import * as path from 'path';
import { promisify } from 'util';
const sleep = promisify(setTimeout);
export class GocServer {
private _serverUrl: string = '';
private timer = true;
private highlightDecorationType = vscode.window.createTextEditorDecorationType({
backgroundColor: 'green',
border: '2px solid white',
color: 'white'
});;
private lastProfile = '';
2020-08-17 09:11:06 +00:00
private lastFileNeedsRender = '';
2020-08-17 02:50:14 +00:00
construct() { }
async startQueryLoop(packages: any[]) {
this.timer = true;
while ( true === this.timer ) {
await sleep(2000);
if ( true !== this.timer ) {
this.clearHightlight();
return;
}
this.getConfigurations();
let profile = await this.getLatestProfile();
this.renderFile(packages, profile);
}
}
stopQueryLoop() {
this.timer = false;
2020-08-17 09:11:06 +00:00
this.lastProfile = '';
this.lastFileNeedsRender = '';
2020-08-17 02:50:14 +00:00
this.clearHightlight()
}
clearHightlight() {
vscode.window.visibleTextEditors.forEach(visibleEditor => {
visibleEditor.setDecorations(this.highlightDecorationType, []);
});
}
getConfigurations() {
this._serverUrl = vscode.workspace.getConfiguration().get('goc.serverUrl') || '';
}
async getLatestProfile(): Promise<string> {
let profileApi = `${this._serverUrl}/v1/cover/profile?force=true`;
try {
let res = await axios.get(profileApi, );
let body: string = res.data.toString();
return body;
} catch(err) {
console.error(err)
}
return "";
}
2020-09-02 07:35:03 +00:00
checkGoEnv() : Boolean {
let output = spawnSync('go', ['version']);
if (output.status != 0 || output.status == null) {
console.error(output.stderr.toString())
return true;
}
return false;
}
2020-08-17 02:50:14 +00:00
getGoList(): Array<any> {
let cwd = "";
let workspaces = vscode.workspace.workspaceFolders || [];
if (workspaces.length == 0) {
console.error("no workspace found");
return [];
} else {
cwd = workspaces[0].uri.path;
}
let opts = {
'cwd': cwd
};
let output = spawnSync('go', ['list', '-json', './...'], opts);
2020-09-02 07:35:03 +00:00
if (output.status != 0 || output.status == null) {
2020-08-17 02:50:14 +00:00
console.error(output.stderr.toString());
return [];
}
let packages = JSON.parse('[' + output.stdout.toString().replace(/}\n{/g, '},\n{') + ']');
return packages;
}
renderFile(packages: Array<any>, profile: string) {
let activeTextEditor = vscode.window.activeTextEditor;
2020-08-17 09:11:06 +00:00
let fileNeedsRender = activeTextEditor?.document.fileName || '---';
// check if needs to rerender
if (profile == this.lastProfile && fileNeedsRender == this.lastFileNeedsRender) {
return;
}
this.lastProfile = profile;
this.lastFileNeedsRender = fileNeedsRender;
2020-08-17 02:50:14 +00:00
for (let i=0; i<packages.length; i++) {
let p = packages[i];
let baseDir: string = p['Dir'];
for (let gofile of p['GoFiles']) {
let filepath = path.join(baseDir, gofile);
if (filepath == fileNeedsRender) {
let importPath: string = path.join(p['ImportPath'], gofile);
let ranges = this.parseProfile(profile, importPath)
this.triggerUpdateDecoration(ranges)
return;
}
}
}
}
parseProfile(profile: string, importPathNeedsRender: string): vscode.Range[] {
let lines = profile.split('\n');
if (lines.length <= 1) {
console.error("empty coverage profile from server");
return [];
}
let ranges: vscode.Range[] = [];
for (let i=0; i<lines.length; i++) {
let line = lines[i];
let importPath: string = line.split(':')[0];
let blockInfo: string = line.split(':')[1];
if (importPath != importPathNeedsRender) {
continue;
}
let rxp = /(\d+)\.(\d+),(\d+)\.(\d+)\s(\d+)\s(\d+)/g
let matches = rxp.exec(blockInfo)!;
let startLine = matches[1];
let startCol = matches[2];
let endLine = matches[3];
let endCol = matches[4];
let stmts = matches[5];
let count = matches[6];
// no need to render code block not covered
if (count == '0') {
continue;
}
let range = new vscode.Range(
new vscode.Position(Number(startLine)-1, Number(startCol)-1),
new vscode.Position(Number(endLine)-1, Number(endCol)-1)
);
ranges.push(range);
}
return ranges
}
triggerUpdateDecoration(ranges: vscode.Range[]) {
if (!vscode.window.activeTextEditor) {
return;
}
console.debug('[' + new Date().toUTCString() + '] ' + 'update latest profile success')
if (ranges.length == 0) {
this.clearHightlight();
} else {
vscode.window.activeTextEditor.setDecorations(
this.highlightDecorationType,
ranges
)
}
}
}