Compare commits

..

2 Commits
0.1.0 ... main

Author SHA1 Message Date
d04cb3cb97 Fix some bugs 2024-09-02 19:32:21 +02:00
7cae5c6721 Add coverage summary view 2024-09-01 15:38:40 +02:00
5 changed files with 134 additions and 9 deletions

View File

@ -1,9 +1,9 @@
{
"name": "coveragetool",
"displayName": "Coverage Tool",
"publisher": "justinbossis",
"description": "Highlights coverage.py lines in VSCode",
"version": "0.1.0",
"publisher": "justinbossis",
"description": "Highlights coverage.py lines in VSCode",
"version": "0.2.1",
"engines": {
"vscode": "^1.92.0"
},
@ -68,10 +68,29 @@
}
}
},
"viewsContainers": {
"activitybar": [
{
"id": "coveragetool",
"title": "Coverage Tool",
"icon": "resources/icon.svg"
}
]
},
"views": {
"coveragetool": [
{
"id": "coveragetoolView",
"name": "Coverage Tool",
"order": 10,
"icon": "resources/icon.svg"
}
]
},
"commands": [
{
"command": "coverage-tool.helloWorld",
"title": "Hello World"
"command": "coveragetool.refreshEntry",
"title": "Refresh Coverage"
}
]
},

7
resources/icon.svg Normal file
View File

@ -0,0 +1,7 @@
<svg width="24" height="24" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
<rect x="12" y="10" width="40" height="48" rx="4" ry="4" fill="none" stroke="#000" stroke-width="4"/>
<line x1="18" y1="20" x2="46" y2="20" stroke="#000" stroke-width="4"/>
<line x1="18" y1="28" x2="40" y2="28" stroke="#000" stroke-width="4"/>
<line x1="18" y1="36" x2="34" y2="36" stroke="#000" stroke-width="4"/>
<path d="M24 44 L30 50 L44 36" fill="none" stroke="#000" stroke-width="4"/>
</svg>

After

Width:  |  Height:  |  Size: 492 B

View File

@ -16,6 +16,7 @@ function createDecor(bgColor: string) {
isWholeLine: true,
overviewRulerLane: OverviewRulerLane.Full,
overviewRulerColor: bgColor.replace(RegExp(/0\.(\d+)/), '0.8'),
rangeBehavior: 1,
},
);
}

19
src/coverageitem.ts Normal file
View File

@ -0,0 +1,19 @@
import { TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
export default class CoverageFile extends TreeItem {
constructor(
public readonly label: string,
public readonly relativePath: string,
public readonly filePath: string,
public readonly numberOfLines: number,
public readonly collapsibleState: TreeItemCollapsibleState,
) {
super(label, collapsibleState);
this.description = `${numberOfLines} missing lines | ${relativePath}`;
this.command = {
command: 'vscode.open',
title: '',
arguments: [Uri.file(this.filePath)],
};
}
}

View File

@ -9,6 +9,7 @@ import CoverageStatusBarItem from './statusBar/CoverageStatusBarItem';
import { CoverageStats, ICoverageCache, ICoverageStatsJson, IFileDecorationCache, IFileDecorationRange } from './models';
import Logger from './util/Logger';
import Configs from './config/Configs';
import CoverageFile from './coverageitem';
// Promisified Functions
const readFileAsync = promisify(readFile);
@ -21,6 +22,7 @@ const isWindows = platform() === 'win32';
let fileWatchers: vscode.FileSystemWatcher[] = [];
let COV_CACHE: ICoverageCache = {};
let FILE_CACHE: IFileDecorationCache = {};
let GLOBAL_COVERAGE: number = 0;
// Functions
@ -62,6 +64,7 @@ function processJsonCoverage(json: any) {
const covData: ICoverageCache = {};
if (json && json.files) {
GLOBAL_COVERAGE = parseInt(json.totals.percent_covered_display);
// Look for the 'files' key in coverage JSON, and iterate through each file
Object.keys(json.files).forEach((file: string) => {
// Create CoverageStats for each file and assign to covData
@ -94,17 +97,17 @@ async function updateCache(files: vscode.Uri) {
if (data && Object.keys(data).length > 0) {
FILE_CACHE = {};
COV_CACHE = processJsonCoverage(data);
vscode.commands.executeCommand('coveragetool.refreshEntry');
return;
}
Logger.log('No data found, could not update cache');
}
}
function updateDecorations(editor: vscode.TextEditor, coverage: IFileDecorationRange) {
editor.setDecorations(config.excludedDecor, coverage.excludedRanges);
editor.setDecorations(config.missingDecor, coverage.missingRanges);
editor.setDecorations(config.executedDecor, coverage.executedRanges);
editor.setDecorations(config.excludedDecor, coverage.excludedRanges.filter(range => editor.document.validateRange(range)));
editor.setDecorations(config.missingDecor, coverage.missingRanges.filter(range => editor.document.validateRange(range)));
editor.setDecorations(config.executedDecor, coverage.executedRanges.filter(range => editor.document.validateRange(range)));
}
function updateFileHighlight(editor: vscode.TextEditor) {
@ -204,6 +207,63 @@ async function setupCacheAndWatchers() {
setupFileWatchers(files);
}
export class CoverageTreeViewProvider implements vscode.TreeDataProvider<CoverageFile> {
constructor(private workspaceRoot: string | undefined) {}
private _onDidChangeTreeData: vscode.EventEmitter<CoverageFile | undefined | null | void> = new vscode.EventEmitter<CoverageFile | undefined | null | void>();
readonly onDidChangeTreeData: vscode.Event<CoverageFile | undefined | null | void> = this._onDidChangeTreeData.event;
refresh(treeView: vscode.TreeView<CoverageFile>): void {
this._onDidChangeTreeData.fire();
this.updateBadge(treeView);
}
getTreeItem(element: CoverageFile): vscode.TreeItem {
return element;
}
getChildren(element?: CoverageFile): Thenable<CoverageFile[]> {
if (!this.workspaceRoot) {
vscode.window.showInformationMessage('No missing coverage found');
return Promise.resolve([]);
}
if (element) {
return Promise.resolve([]);
}
else{
return Promise.resolve(this.getFilesInCoverageJson());
}
}
private getFilesInCoverageJson(): CoverageFile[] {
if (COV_CACHE) {
const toFile = (fileName: string, relativePath: string, filePath: string, numberOfLines: number): CoverageFile => {
return new CoverageFile(fileName, relativePath, filePath, numberOfLines, vscode.TreeItemCollapsibleState.None);
};
const files = Object.keys(COV_CACHE).map((file) => {
const stats = COV_CACHE[file];
return toFile(stats.path.split("/").pop() || "", stats.path, `${this.workspaceRoot}/${stats.path}`, stats.summary.missingLines);
});
return files.filter((file) => file.numberOfLines !== 0);
} else {
return [];
}
}
private updateBadge(treeView: vscode.TreeView<CoverageFile>): void {
if (GLOBAL_COVERAGE !== 100){
treeView.badge = {
value: GLOBAL_COVERAGE,
tooltip: 'Coverage percentage'
};
}else{
treeView.badge = undefined;
}
}
}
// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export async function activate(context: vscode.ExtensionContext) {
@ -222,6 +282,25 @@ export async function activate(context: vscode.ExtensionContext) {
updateFileHighlight(editor);
}
});
vscode.workspace.onDidChangeTextDocument(event => {
if (vscode.window.activeTextEditor && event.document === vscode.window.activeTextEditor.document) {
updateFileHighlight(vscode.window.activeTextEditor);
}
}, null, context.subscriptions);
const rootPath = vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0
? vscode.workspace.workspaceFolders[0].uri.fsPath
: undefined;
const coverageTreeViewProvider = new CoverageTreeViewProvider(rootPath);
// vscode.window.registerTreeDataProvider('coveragetoolView', coverageTreeViewProvider);
const treeView = vscode.window.createTreeView('coveragetoolView', {
treeDataProvider: coverageTreeViewProvider
});
context.subscriptions.push(treeView);
vscode.commands.registerCommand('coveragetool.refreshEntry', () =>
coverageTreeViewProvider.refresh(treeView)
);
}