-
Notifications
You must be signed in to change notification settings - Fork 734
Expand file tree
/
Copy pathdirectoryTreeNode.ts
More file actions
144 lines (121 loc) · 4.19 KB
/
directoryTreeNode.ts
File metadata and controls
144 lines (121 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { GitFileChangeNode, InMemFileChangeNode, RemoteFileChangeNode } from './fileChangeNode';
import { TreeNode, TreeNodeParent } from './treeNode';
export class DirectoryTreeNode extends TreeNode implements vscode.TreeItem {
public collapsibleState: vscode.TreeItemCollapsibleState;
public override _children: (RemoteFileChangeNode | InMemFileChangeNode | GitFileChangeNode | DirectoryTreeNode)[] = [];
private pathToChild: Map<string, DirectoryTreeNode> = new Map();
public checkboxState?: { state: vscode.TreeItemCheckboxState, tooltip: string, accessibilityInformation: vscode.AccessibilityInformation };
constructor(parent: TreeNodeParent, label: string) {
super(parent);
this.label = label;
this.collapsibleState = vscode.TreeItemCollapsibleState.Expanded;
}
override async getChildren(): Promise<TreeNode[]> {
return this._children;
}
public finalize(): void {
this.trimTree();
this.sort();
}
private trimTree(): void {
if (this._children.length === 0) {
return;
}
this._children.forEach(n => {
if (n instanceof DirectoryTreeNode) {
n.trimTree(); // recursive
}
});
// merge if this only have single directory, eg:
// - a
// - b
// - c
// becomes:
// - a/b
// - c
if (this._children.length !== 1) {
return;
}
const child = this._children[0];
if (!(child instanceof DirectoryTreeNode)) {
return;
}
// perform the merge
this.label = this.label + '/' + child.label;
if (this.label.startsWith('/')) {
this.label = this.label.substr(1);
}
this._children = child._children;
this._children.forEach(child => { child.parent = this; });
}
private sort(): void {
if (this._children.length <= 1) {
return;
}
const dirs: DirectoryTreeNode[] = [];
const files: (RemoteFileChangeNode | InMemFileChangeNode | GitFileChangeNode)[] = [];
// process directory
this._children.forEach(node => {
if (node instanceof DirectoryTreeNode) {
node.sort(); // recc
dirs.push(node);
} else {
// files
files.push(node);
}
});
// sort
dirs.sort((a, b) => (a.label! < b.label! ? -1 : 1));
files.sort((a, b) => (a.label! < b.label! ? -1 : 1));
this._children = [...dirs, ...files];
}
public addFile(file: GitFileChangeNode | RemoteFileChangeNode | InMemFileChangeNode): void {
const paths = file.changeModel.fileName.split('/');
this.addPathRecc(paths, file);
}
private addPathRecc(paths: string[], file: GitFileChangeNode | RemoteFileChangeNode | InMemFileChangeNode): void {
if (paths.length <= 0) {
return;
}
if (paths.length === 1) {
file.parent = this;
this._children.push(file);
return;
}
const dir = paths[0]; // top directory
const tail = paths.slice(1); // rest
let node = this.pathToChild.get(dir);
if (!node) {
node = new DirectoryTreeNode(this, dir);
this.pathToChild.set(dir, node);
this._children.push(node);
}
node.addPathRecc(tail, file);
}
public allChildrenViewed(): boolean {
for (const child of this._children) {
if (child instanceof DirectoryTreeNode) {
if (!child.allChildrenViewed()) {
return false;
}
} else if (!child.checkboxState || child.checkboxState.state !== vscode.TreeItemCheckboxState.Checked) {
return false;
}
}
return true;
}
private setCheckboxState(isChecked: boolean) {
this.checkboxState = isChecked ?
{ state: vscode.TreeItemCheckboxState.Checked, tooltip: vscode.l10n.t('Mark all files unviewed'), accessibilityInformation: { label: vscode.l10n.t('Mark all files in folder {0} as unviewed', this.label!) } } :
{ state: vscode.TreeItemCheckboxState.Unchecked, tooltip: vscode.l10n.t('Mark all files viewed'), accessibilityInformation: { label: vscode.l10n.t('Mark all files in folder {0} as viewed', this.label!) } };
}
getTreeItem(): vscode.TreeItem {
this.setCheckboxState(this.allChildrenViewed());
return this;
}
}