add tree data provider
This commit is contained in:
parent
8fcd2366f2
commit
cbab380bb0
35
package.json
35
package.json
|
@ -21,6 +21,36 @@
|
|||
"activationEvents": [],
|
||||
"main": "./dist/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "gitcommitfilter.showastree",
|
||||
"title": "Show as tree"
|
||||
},
|
||||
{
|
||||
"command": "gitcommitfilter.showaslist",
|
||||
"title": "Show as list"
|
||||
},
|
||||
{
|
||||
"command": "gitcommitfilter.compare"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"view/title":[
|
||||
{
|
||||
"command": "gitcommitfilter.showastree",
|
||||
"when": "view == gitcommitfilter.commit-list && gitcommitfilter.viewState=='list'",
|
||||
"group": "navigation",
|
||||
"icon":"${list-tree}"
|
||||
},
|
||||
{
|
||||
"command": "gitcommitfilter.showaslist",
|
||||
"when": "view == gitcommitfilter.commit-list && gitcommitfilter.viewState=='tree'",
|
||||
"group": "navigation",
|
||||
"icon":"${list-flat}"
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
"viewsContainers": {
|
||||
"activitybar": [
|
||||
{
|
||||
|
@ -37,6 +67,11 @@
|
|||
"id": "gitcommitfilter.view",
|
||||
"name": "MyCustomView",
|
||||
"when": "true"
|
||||
},
|
||||
{
|
||||
"id": "gitcommitfilter.commit-list",
|
||||
"name": "Commitlist",
|
||||
"type": "tree"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -15,6 +15,15 @@ export interface GitCommit {
|
|||
files?: string[];
|
||||
}
|
||||
|
||||
export interface GitCommitFilter{
|
||||
path?:string;
|
||||
contains?:string;
|
||||
committer?:string;
|
||||
dateRange?:[Date, Date]
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class GitService {
|
||||
private _repoPath: string;
|
||||
|
||||
|
@ -25,9 +34,46 @@ export class GitService {
|
|||
}
|
||||
this._repoPath = workspaceFolders[0].uri.fsPath;
|
||||
}
|
||||
|
||||
private transformFilter(filter: GitCommitFilter): string[] {
|
||||
const gitArgs: string[] = [];
|
||||
if(filter.committer) {
|
||||
gitArgs.push(`--author=${filter.committer}`);
|
||||
}
|
||||
if(filter.dateRange) {
|
||||
const [from, to] = filter.dateRange;
|
||||
gitArgs.push(`--since=${this.getDateStr(from)}`);
|
||||
// get next day of to
|
||||
const toNextDay = new Date(to);
|
||||
toNextDay.setDate(toNextDay.getDate() + 1);
|
||||
gitArgs.push(`--until=${this.getDateStr(toNextDay)}`);
|
||||
}
|
||||
if(filter.contains) {
|
||||
gitArgs.push(`--grep=${filter.contains}`);
|
||||
}
|
||||
return gitArgs;
|
||||
}
|
||||
|
||||
getDateStr(d:Date) :string {
|
||||
return d.toLocaleDateString('zh-CN');
|
||||
}
|
||||
private defaultFilter(): string[] {
|
||||
return ['--author=$(git config user.name)', '--since=\"7 days ago\"'];
|
||||
}
|
||||
getCommitters() : string[] {
|
||||
const command = `git log --format='%aN' | sort -u`;
|
||||
const result = child_process.execSync(`git log --format='%aN' | sort -u`, {
|
||||
cwd: this._repoPath,
|
||||
});
|
||||
return result.toString().split("\n");
|
||||
}
|
||||
|
||||
getCurrentUser(): string {
|
||||
const result = child_process.execSync(`git config user.name`, {
|
||||
cwd: this._repoPath,
|
||||
});
|
||||
return result.toString().trim();
|
||||
}
|
||||
|
||||
public async getCommits(filter: string = ""): Promise<any[]> {
|
||||
const filterParts = filter.split(" ");
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import * as vscode from "vscode";
|
||||
import { GitService, GitCommit } from "./GitService";
|
||||
import path from "path";
|
||||
import { CommitItem } from "./commit-tree.item";
|
||||
import { EventBus } from "./event-bus";
|
||||
|
||||
export class CommitListProvider implements vscode.TreeDataProvider<CommitItem> {
|
||||
private state:string = "list";
|
||||
private filter: any = {};
|
||||
private _commits: GitCommit[] = [];
|
||||
private _onDidChangeTreeData: vscode.EventEmitter<CommitItem | undefined | void> = new vscode.EventEmitter<CommitItem | undefined | void>();
|
||||
readonly onDidChangeTreeData: vscode.Event<CommitItem | undefined | void> = this._onDidChangeTreeData.event;
|
||||
|
||||
private _showFullPath: boolean = false;
|
||||
|
||||
constructor(private readonly _gitService: GitService,private event: EventBus) {
|
||||
this.event.on("filter",(filter)=>{
|
||||
this.filter = filter;
|
||||
this.refresh();
|
||||
});
|
||||
this.event.on("refresh",()=>{
|
||||
this._makeCommitItems();
|
||||
this._onDidChangeTreeData.fire();
|
||||
});
|
||||
}
|
||||
|
||||
_makeCommitItems() {
|
||||
|
||||
}
|
||||
|
||||
refresh(): void {
|
||||
this._onDidChangeTreeData.fire();
|
||||
}
|
||||
|
||||
toggleFullPath(): void {
|
||||
this._showFullPath = !this._showFullPath;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
getTreeItem(element: CommitItem): vscode.TreeItem {
|
||||
return element;
|
||||
}
|
||||
|
||||
async getChildren(element?: CommitItem): Promise<CommitItem[]> {
|
||||
if (!element) {
|
||||
const commits = await this._gitService.getCommits("");
|
||||
return commits.map(commit => new CommitItem(`${commit.msg} -- ${commit.author}@${commit.hash} ${commit.date}`, vscode.TreeItemCollapsibleState.Expanded, commit.files));
|
||||
}
|
||||
if (element.files) {
|
||||
return element.files.map(file => new CommitItem(this._showFullPath ? file : path.basename(file), vscode.TreeItemCollapsibleState.None, undefined, file));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
import * as vscode from "vscode";
|
||||
import * as path from "path";
|
||||
|
||||
|
||||
// interface PathItem {
|
||||
// fpath?: string;
|
||||
// label: string;
|
||||
// children?: PathTree;
|
||||
// }
|
||||
// interface PathTree {
|
||||
// [key: string]: PathItem;
|
||||
// }
|
||||
// function makePathTree(paths: string[]): PathTree{
|
||||
// const pathTree: PathTree = {};
|
||||
// for (const file of paths) {
|
||||
// const pathParts = file.split("/");
|
||||
// if(pathParts.length === 1){
|
||||
// pathTree[pathParts[0]] = {fpath: file, label: pathParts[0]};
|
||||
// continue;
|
||||
// }
|
||||
// let currentNode = pathTree;
|
||||
// for (let i = 0; i < pathParts.length; i++) {
|
||||
// const pathItem = pathParts[i];
|
||||
// if(!currentNode.chilren){
|
||||
// currentNode.chilren = {};
|
||||
// }
|
||||
// if (!currentNode.chilren[pathItem]) {
|
||||
// currentNode[pathItem] = {
|
||||
// label: pathItem,
|
||||
// children: i !== pathParts.length - 1 ? {} : undefined,
|
||||
// fpath: i === pathParts.length - 1 ? file : undefined,
|
||||
// };
|
||||
// } else
|
||||
// if(i !== pathParts.length - 1) {
|
||||
// currentNode = currentNode[pathItem].children;
|
||||
// }
|
||||
|
||||
// }
|
||||
// }
|
||||
// return {};
|
||||
// }
|
||||
|
||||
export class CommitItem extends vscode.TreeItem {
|
||||
public iconPath?: string | vscode.IconPath | undefined = 'file';
|
||||
public children?: CommitItem[];
|
||||
constructor(
|
||||
public readonly label:string,
|
||||
public state : vscode.TreeItemCollapsibleState,
|
||||
public readonly commitHash: string,
|
||||
public readonly style:string,
|
||||
public readonly fpath?: string,
|
||||
public readonly files?: string[]
|
||||
){
|
||||
super(label, state);
|
||||
if(this.isFileItem()){
|
||||
this.tooltip = this.fpath;
|
||||
}
|
||||
if(this.isCommitItem()) {
|
||||
this.iconPath = 'git-commit';
|
||||
}
|
||||
}
|
||||
makeChildren() {
|
||||
if(this.isCommitItem()) {
|
||||
if(this.style === "list"){
|
||||
this.children = this.files?.map(file => {
|
||||
return new CommitItem(path.basename(file), vscode.TreeItemCollapsibleState.None, this.commitHash, "list", file);
|
||||
});
|
||||
} else {
|
||||
if(!this.files) {
|
||||
return
|
||||
}
|
||||
for(const file of this.files) {
|
||||
const fileParts = file.split("/");
|
||||
if(fileParts.length === 1){
|
||||
this.addChildren(new CommitItem(fileParts[0], vscode.TreeItemCollapsibleState.None, this.commitHash, "tree", file));
|
||||
continue;
|
||||
}
|
||||
let currentNode: CommitItem = this;
|
||||
for (let i = 0; i < fileParts.length; i++) {
|
||||
const pathItem = fileParts[i];
|
||||
const child = currentNode.getChildItem(pathItem);
|
||||
if(!child) {
|
||||
const newChild = new CommitItem(pathItem, vscode.TreeItemCollapsibleState.Collapsed, this.commitHash, "tree");
|
||||
currentNode.addChildren(newChild);
|
||||
currentNode = newChild;
|
||||
} else {
|
||||
currentNode = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isCommitItem() {
|
||||
return this.files && !this.fpath;
|
||||
}
|
||||
|
||||
isFileItem() {
|
||||
return this.fpath && this.children?.length === 0;
|
||||
}
|
||||
isFolderPath() {
|
||||
return this.fpath && this.children && this.children?.length > 0;
|
||||
}
|
||||
addChildren(item: CommitItem) {
|
||||
this.iconPath = 'folder';
|
||||
const index = this.children?.findIndex(child => child.label === item.label);
|
||||
if(index === -1) {
|
||||
this.children?.push(item);
|
||||
}
|
||||
}
|
||||
getChildItem(label: string) {
|
||||
return this.children?.find(child => child.label === label);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import { EventEmitter } from "events";
|
||||
|
||||
export class EventBus extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue