From 90157000d29c0a26777fa1927f11ff4d2823ede8 Mon Sep 17 00:00:00 2001 From: Maik Riechert Date: Sat, 5 Aug 2023 20:44:03 +0100 Subject: [PATCH] add option to show checkboxes --- CHANGELOG.md | 5 +++++ package.json | 55 ++++++++++++++++++++++++++++++++++++--------- src/extension.ts | 6 +++++ src/treeProvider.ts | 41 ++++++++++++++++++++++++++++++--- 4 files changed, 93 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a1268a..80bb92f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.16.0 + +* Added option to show checkboxes to tick off reviewed files +* Organized title menu items into groups + ## 1.15.1 * Fixed "Discard Changes" incorrectly restoring files to base ref instead of merge base diff --git a/package.json b/package.json index c65e0db..35e05c4 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ }, "homepage": "https://github.com/letmaik/vscode-git-tree-compare", "engines": { - "vscode": "^1.75.0" + "vscode": "^1.81.0" }, "capabilities": { "virtualWorkspaces": false, @@ -126,6 +126,16 @@ "title": "Switch to Merge Diff", "category": "Git Tree Compare" }, + { + "command": "gitTreeCompare.showCheckboxes", + "title": "Show checkboxes", + "category": "Git Tree Compare" + }, + { + "command": "gitTreeCompare.hideCheckboxes", + "title": "Hide checkboxes", + "category": "Git Tree Compare" + }, { "command": "gitTreeCompare.viewAsList", "title": "View as List", @@ -143,7 +153,8 @@ "view/title": [ { "command": "gitTreeCompare.changeRepository", - "when": "view == gitTreeCompare && gitOpenRepositoryCount != 1" + "when": "view == gitTreeCompare && gitOpenRepositoryCount != 1", + "group": "1_state" }, { "command": "gitTreeCompare.changeRepository", @@ -152,23 +163,28 @@ }, { "command": "gitTreeCompare.changeBase", - "when": "view == gitTreeCompare" + "when": "view == gitTreeCompare", + "group": "1_state" }, { "command": "gitTreeCompare.openAllChanges", - "when": "view == gitTreeCompare" + "when": "view == gitTreeCompare", + "group": "2_files" }, { "command": "gitTreeCompare.openChangedFiles", - "when": "view == gitTreeCompare" + "when": "view == gitTreeCompare", + "group": "2_files" }, { "command": "gitTreeCompare.discardAllChanges", - "when": "view == gitTreeCompare" + "when": "view == gitTreeCompare", + "group": "2_files" }, { "command": "gitTreeCompare.refresh", - "when": "view == gitTreeCompare" + "when": "view == gitTreeCompare", + "group": "1_state" }, { "command": "gitTreeCompare.refresh", @@ -177,11 +193,23 @@ }, { "command": "gitTreeCompare.switchToFullDiff", - "when": "view == gitTreeCompare && config.gitTreeCompare.diffMode == merge" + "when": "view == gitTreeCompare && config.gitTreeCompare.diffMode == merge", + "group": "3_options" }, { "command": "gitTreeCompare.switchToMergeDiff", - "when": "view == gitTreeCompare && config.gitTreeCompare.diffMode == full" + "when": "view == gitTreeCompare && config.gitTreeCompare.diffMode == full", + "group": "3_options" + }, + { + "command": "gitTreeCompare.showCheckboxes", + "when": "view == gitTreeCompare && !config.gitTreeCompare.showCheckboxes", + "group": "3_options" + }, + { + "command": "gitTreeCompare.hideCheckboxes", + "when": "view == gitTreeCompare && config.gitTreeCompare.showCheckboxes", + "group": "3_options" }, { "command": "gitTreeCompare.viewAsList", @@ -364,6 +392,11 @@ "type": "boolean", "description": "Whether to compact (flatten) single-child folders into a single tree element. Useful for Java package structures, for example. May have a performance impact for large diff trees.", "default": true + }, + "gitTreeCompare.showCheckboxes": { + "type": "boolean", + "description": "Whether to show checkboxes such that files or folders can be ticked off, for example when reviewing.", + "default": false } } } @@ -378,9 +411,9 @@ "@types/byline": "4.2.31", "@types/file-type": "^5.2.1", "@types/node": "^13.5.0", - "@types/vscode": "^1.60.0", + "@types/vscode": "^1.81.0", "@types/which": "^1.0.28", - "@vscode/vsce": "^2.19.0", + "@vscode/vsce": "^2.20.1", "ts-loader": "^9.2.6", "typescript": "^4.4.3", "webpack": "^5.44.0", diff --git a/src/extension.ts b/src/extension.ts index 299fd76..526494c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -77,6 +77,12 @@ export function activate(context: ExtensionContext) { commands.registerCommand(NAMESPACE + '.switchToMergeDiff', () => { runAfterInit(() => provider!.switchToMergeDiff()); }); + commands.registerCommand(NAMESPACE + '.showCheckboxes', () => { + runAfterInit(() => provider!.hideCheckboxes(false)); + }); + commands.registerCommand(NAMESPACE + '.hideCheckboxes', () => { + runAfterInit(() => provider!.hideCheckboxes(true)); + }); commands.registerCommand(NAMESPACE + '.viewAsList', () => { runAfterInit(() => provider!.viewAsTree(false)); }); diff --git a/src/treeProvider.ts b/src/treeProvider.ts index 113d5e4..e46855e 100644 --- a/src/treeProvider.ts +++ b/src/treeProvider.ts @@ -5,7 +5,7 @@ import * as fs from 'fs' import { TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri, Disposable, EventEmitter, TextDocumentShowOptions, QuickPickItem, ProgressLocation, Memento, OutputChannel, - workspace, commands, window, WorkspaceFoldersChangeEvent, TreeView, ThemeIcon } from 'vscode' + workspace, commands, window, WorkspaceFoldersChangeEvent, TreeView, ThemeIcon, TreeItemCheckboxState, TreeCheckboxChangeEvent } from 'vscode' import { NAMESPACE } from './constants' import { Repository, Git } from './git/git' import { Ref, RefType } from './git/api/git' @@ -102,6 +102,7 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos private findRenames: boolean; private showCollapsed: boolean; private compactFolders: boolean; + private showCheckboxes: boolean; // Dynamic options private repository: Repository | undefined; @@ -132,6 +133,7 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos // UI state private treeView: TreeView; private isPaused: boolean; + private checkboxStates: Map = new Map(); // Other private readonly disposables: Disposable[] = []; @@ -182,6 +184,8 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos const onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete); const onRelevantWorkspaceChange = filterEvent(onWorkspaceChange, isRelevantChange); this.disposables.push(onRelevantWorkspaceChange(this.handleWorkspaceChange, this)); + + this.disposables.push(treeView.onDidChangeCheckboxState(this.handleChangeCheckboxState, this)); } async setRepository(repositoryRoot: string) { @@ -236,6 +240,7 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos window.showErrorMessage(`${msg}: ${e.message}`); return; } + this.checkboxStates.clear(); this._onDidChangeTreeData.fire(); } @@ -301,6 +306,14 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos } } + private async handleChangeCheckboxState(e: TreeCheckboxChangeEvent) { + for (let [element, state] of e.items) { + if (element instanceof FileElement || element instanceof FolderElement) { + this.checkboxStates.set(element.dstAbsPath, state); + } + } + } + private log(msg: string, error: Error | undefined=undefined) { if (error) { console.warn(msg, error); @@ -331,6 +344,7 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos this.findRenames = config.get('findRenames', true); this.showCollapsed = config.get('collapsed', false); this.compactFolders = config.get('compactFolders', false); + this.showCheckboxes = config.get('showCheckboxes', false); } private async getStoredBaseRef(): Promise { @@ -366,7 +380,13 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos } getTreeItem(element: Element): TreeItem { - return toTreeItem(element, this.openChangesOnSelect, this.iconsMinimal, this.showCollapsed, this.viewAsList, this.asAbsolutePath); + let checkboxState: TreeItemCheckboxState | undefined; + if (this.showCheckboxes) { + if (element instanceof FileElement || element instanceof FolderElement) { + checkboxState = this.checkboxStates.get(element.dstAbsPath) ?? TreeItemCheckboxState.Unchecked; + } + } + return toTreeItem(element, this.openChangesOnSelect, this.iconsMinimal, this.showCollapsed, this.viewAsList, checkboxState, this.asAbsolutePath); } async getChildren(element?: Element): Promise { @@ -456,6 +476,7 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos } if (this.headName !== headName) { this.log(`HEAD ref updated: ${this.headName} -> ${headName}`); + this.checkboxStates.clear(); } if (this.headCommit !== headCommit) { this.log(`HEAD ref commit updated: ${this.headCommit} -> ${headCommit}`); @@ -642,6 +663,7 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos const oldFullDiff = this.fullDiff; const oldFindRenames = this.findRenames; const oldCompactFolders = this.compactFolders; + const oldshowCheckboxes = this.showCheckboxes; this.readConfig(); if (oldTreeRootIsRepo != this.treeRootIsRepo || oldInclude != this.includeFilesOutsideWorkspaceFolderRoot || @@ -651,7 +673,8 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos (!oldRefreshIndex && this.refreshIndex) || oldFullDiff != this.fullDiff || oldFindRenames != this.findRenames || - oldCompactFolders != this.compactFolders) { + oldCompactFolders != this.compactFolders || + oldshowCheckboxes != this.showCheckboxes) { if (!this.repository) { return; @@ -1062,6 +1085,11 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos await config.update('diffMode', 'full', true); } + async hideCheckboxes(v: boolean) { + const config = workspace.getConfiguration(NAMESPACE); + await config.update('showCheckboxes', !v, true); + } + viewAsTree(v: boolean) { const viewAsList = !v; if (viewAsList === this.viewAsList) @@ -1079,6 +1107,7 @@ export class GitTreeCompareProvider implements TreeDataProvider, Dispos function toTreeItem(element: Element, openChangesOnSelect: boolean, iconsMinimal: boolean, showCollapsed: boolean, viewAsList: boolean, + checkboxState: TreeItemCheckboxState | undefined, asAbsolutePath: (relPath: string) => string): TreeItem { const gitIconRoot = asAbsolutePath('resources/git-icons'); if (element instanceof FileElement) { @@ -1097,6 +1126,9 @@ function toTreeItem(element: Element, openChangesOnSelect: boolean, iconsMinimal item.contextValue = element.isSubmodule ? 'submodule' : 'file'; item.id = element.dstAbsPath; item.iconPath = path.join(gitIconRoot, toIconName(element) + '.svg'); + if (checkboxState !== undefined) { + item.checkboxState = checkboxState; + } if (!element.isSubmodule) { const command = openChangesOnSelect ? 'openChanges' : 'openFile'; item.command = { @@ -1120,6 +1152,9 @@ function toTreeItem(element: Element, openChangesOnSelect: boolean, iconsMinimal item.tooltip = element.dstAbsPath; item.contextValue = 'folder'; item.id = element.dstAbsPath; + if (checkboxState !== undefined) { + item.checkboxState = checkboxState; + } if (!iconsMinimal) { item.iconPath = new ThemeIcon('folder-opened'); }