diff --git a/package.json b/package.json
index c874521..fa3b0d3 100644
--- a/package.json
+++ b/package.json
@@ -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.0",
"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"
}
]
},
diff --git a/resources/icon.svg b/resources/icon.svg
new file mode 100644
index 0000000..aee1666
--- /dev/null
+++ b/resources/icon.svg
@@ -0,0 +1,7 @@
+
diff --git a/src/coverageitem.ts b/src/coverageitem.ts
new file mode 100644
index 0000000..2968026
--- /dev/null
+++ b/src/coverageitem.ts
@@ -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)],
+ };
+ }
+}
diff --git a/src/extension.ts b/src/extension.ts
index 0447e1d..cf37972 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -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,9 +97,9 @@ 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');
}
}
@@ -204,6 +207,63 @@ async function setupCacheAndWatchers() {
setupFileWatchers(files);
}
+export class CoverageTreeViewProvider implements vscode.TreeDataProvider {
+ constructor(private workspaceRoot: string | undefined) {}
+
+ private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter();
+ readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event;
+
+ refresh(treeView: vscode.TreeView): void {
+ this._onDidChangeTreeData.fire();
+ this.updateBadge(treeView);
+ }
+
+
+ getTreeItem(element: CoverageFile): vscode.TreeItem {
+ return element;
+ }
+
+ getChildren(element?: CoverageFile): Thenable {
+ 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): 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) {
@@ -223,6 +283,20 @@ export async function activate(context: vscode.ExtensionContext) {
}
});
+ 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)
+ );
+
}
// This method is called when your extension is deactivated