|
1 | | -import type { Event, TreeDataProvider, TreeItem } from 'vscode' |
2 | | -import { EventEmitter, TreeItemCollapsibleState } from 'vscode' |
| 1 | +import { TreeItemCollapsibleState } from 'vscode' |
| 2 | +import type { TreeViewNode } from 'reactive-vscode' |
3 | 3 | import { computed, createSingletonComposable, ref, useTreeView } from 'reactive-vscode' |
4 | 4 |
|
5 | 5 | import { CommitNode } from './entity/CommitNode' |
6 | | -import { FileTreeView } from './FileTreeView' |
| 6 | +import { useFileTreeView } from './FileTreeView' |
7 | 7 | import type { CommitDetails } from './types' |
8 | 8 | import { useGitService } from '@/git' |
9 | 9 | import { useStorage } from '@/storage' |
10 | 10 | import { EXTENSION_SYMBOL } from '@/constant' |
11 | 11 |
|
12 | | -export class DiffTreeView implements TreeDataProvider<CommitNode> { |
13 | | - private readonly _onDidChangeTreeData: EventEmitter<CommitNode | undefined | null | void> = new EventEmitter<CommitNode | undefined | null | void>() |
14 | | - readonly onDidChangeTreeData: Event<CommitNode | undefined | null | void> = this._onDidChangeTreeData.event |
15 | | - private storage = useStorage() |
16 | | - private fileTreeProvider: FileTreeView |
17 | | - private selectedCommitHash?: string |
18 | | - private static instance: DiffTreeView |
| 12 | +export const useDiffTreeView = createSingletonComposable(() => { |
| 13 | + const git = useGitService() |
| 14 | + const storage = useStorage() |
| 15 | + const fileTree = useFileTreeView() |
| 16 | + const selectedCommitHash = ref('') |
| 17 | + const commitDetails = ref<CommitDetails | null>(null) |
| 18 | + const files = ref<TreeViewNode[]>([]) |
19 | 19 |
|
20 | | - private constructor() { |
21 | | - this.fileTreeProvider = new FileTreeView() |
22 | | - } |
23 | | - |
24 | | - static getInstance(): DiffTreeView { |
25 | | - if (!DiffTreeView.instance) { |
26 | | - DiffTreeView.instance = new DiffTreeView() |
27 | | - } |
28 | | - return DiffTreeView.instance |
29 | | - } |
30 | | - |
31 | | - refresh(commitHash?: string): void { |
32 | | - this.selectedCommitHash = commitHash |
33 | | - this._onDidChangeTreeData.fire() |
34 | | - } |
35 | | - |
36 | | - getTreeItem(element: CommitNode): TreeItem { |
37 | | - return element |
38 | | - } |
39 | | - |
40 | | - private async getCommitByHash(hash?: string): Promise<CommitDetails | null> { |
| 20 | + async function loadCommitDetails(hash: string) { |
41 | 21 | try { |
42 | | - if (!hash) { |
43 | | - throw new Error('Commit hash is required') |
44 | | - } |
45 | | - |
46 | | - // First try to get from cache |
47 | | - let commit = this.storage.getCommit(hash) |
| 22 | + let commit = storage.getCommit(hash) |
48 | 23 |
|
49 | 24 | if (!commit) { |
50 | | - // Only fetch all commits if not found in cache |
51 | | - const { getHistory } = useGitService() |
52 | | - const history = await getHistory() |
53 | | - const historyCommit = history.all.find(c => c.hash === hash) |
54 | | - if (!historyCommit) { |
55 | | - return null |
56 | | - } |
| 25 | + const { all: history } = await git.getHistory() |
| 26 | + const historyCommit = history.find(c => c.hash === hash) |
| 27 | + if (!historyCommit) |
| 28 | + return |
57 | 29 |
|
58 | 30 | commit = { |
59 | 31 | ...historyCommit, |
60 | 32 | } |
| 33 | + |
| 34 | + storage.saveCommits(Array.from(history)) |
61 | 35 | } |
62 | 36 |
|
63 | | - return commit |
| 37 | + commitDetails.value = commit |
| 38 | + const { files: commitFiles, total } = await fileTree.getChildren(hash) |
| 39 | + |
| 40 | + files.value = [ |
| 41 | + { |
| 42 | + treeItem: new CommitNode( |
| 43 | + 'Changed Files', |
| 44 | + `${total} Files Changed`, |
| 45 | + total > 0 ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None, |
| 46 | + 'files', |
| 47 | + ), |
| 48 | + children: commitFiles, |
| 49 | + }, |
| 50 | + ] |
64 | 51 | } |
65 | 52 | catch (error) { |
66 | 53 | console.error('Error getting commit details:', error) |
67 | | - return null |
| 54 | + commitDetails.value = null |
| 55 | + files.value = [] |
68 | 56 | } |
69 | 57 | } |
70 | 58 |
|
71 | | - async getChildren(element?: CommitNode): Promise<CommitNode[]> { |
72 | | - if (!element && this.selectedCommitHash) { |
73 | | - const commitDetails = await this.getCommitByHash(this.selectedCommitHash) |
74 | | - |
75 | | - if (!commitDetails) { |
76 | | - return [] |
77 | | - } |
78 | | - |
79 | | - this.fileTreeProvider.refresh(commitDetails.hash) |
| 59 | + const treeNodes = computed<TreeViewNode[]>(() => { |
| 60 | + if (!commitDetails.value) |
| 61 | + return [] |
80 | 62 |
|
81 | | - const { files, total } = await this.fileTreeProvider.getChildren() |
82 | | - |
83 | | - return [ |
84 | | - new CommitNode( |
| 63 | + return [ |
| 64 | + { |
| 65 | + treeItem: new CommitNode( |
85 | 66 | 'Author', |
86 | | - `${commitDetails.authorName} <${commitDetails.authorEmail}>`, |
| 67 | + `${commitDetails.value.authorName} <${commitDetails.value.authorEmail}>`, |
87 | 68 | TreeItemCollapsibleState.None, |
88 | 69 | 'person', |
89 | 70 | ), |
90 | | - new CommitNode( |
| 71 | + }, |
| 72 | + { |
| 73 | + treeItem: new CommitNode( |
91 | 74 | 'Date', |
92 | | - new Date(commitDetails.date).toLocaleString(), |
| 75 | + new Date(commitDetails.value.date).toLocaleString(), |
93 | 76 | TreeItemCollapsibleState.None, |
94 | 77 | 'calendar', |
95 | 78 | ), |
96 | | - new CommitNode( |
| 79 | + }, |
| 80 | + { |
| 81 | + treeItem: new CommitNode( |
97 | 82 | 'Hash', |
98 | | - commitDetails.hash, |
| 83 | + commitDetails.value.hash, |
99 | 84 | TreeItemCollapsibleState.None, |
100 | 85 | 'git-commit', |
101 | 86 | ), |
102 | | - new CommitNode( |
103 | | - 'Changed Files', |
104 | | - `${total} Files Changed`, |
105 | | - total > 0 ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None, |
106 | | - 'files', |
107 | | - files, |
108 | | - ), |
109 | | - ] |
110 | | - } |
111 | | - |
112 | | - return element?.children as CommitNode[] || [] |
| 87 | + }, |
| 88 | + ...files.value, |
| 89 | + ] |
| 90 | + }) |
| 91 | + |
| 92 | + const tree = useTreeView( |
| 93 | + `${EXTENSION_SYMBOL}.changes`, |
| 94 | + treeNodes, |
| 95 | + { |
| 96 | + showCollapseAll: true, |
| 97 | + }, |
| 98 | + ) |
| 99 | + |
| 100 | + async function refresh(hash: string) { |
| 101 | + if (hash === selectedCommitHash.value) |
| 102 | + return |
| 103 | + |
| 104 | + selectedCommitHash.value = hash |
| 105 | + fileTree.refresh(hash) |
| 106 | + await loadCommitDetails(hash) |
113 | 107 | } |
114 | 108 |
|
115 | | - // Getter for selectedCommitHash |
116 | | - public getSelectedCommitHash(): string | undefined { |
117 | | - return this.selectedCommitHash |
| 109 | + return { |
| 110 | + tree, |
| 111 | + refresh, |
| 112 | + selectedCommitHash, |
118 | 113 | } |
119 | | -} |
120 | | - |
121 | | -// export const useDiffTreeView = createSingletonComposable(() => { |
122 | | -// const { git, parseGitStatus } = useGitService() |
123 | | -// const selectedCommitHash = ref<string[]>([]) |
124 | | - |
125 | | -// const tree = useTreeView( |
126 | | -// `${EXTENSION_SYMBOL}.changes`, |
127 | | -// [], |
128 | | -// { |
129 | | -// canSelectMany: false, |
130 | | -// }, |
131 | | -// ) |
132 | | - |
133 | | -// const treeData = computed(() => { |
134 | | -// if (selectedCommitHash.value.length === 1) { |
135 | | -// const commitDetail = selectedCommitHash.value[0] |
136 | | -// return [ |
137 | | -// new CommitNode( |
138 | | -// 'Author', |
139 | | -// `${commitDetail.authorName} <${commitDetail.authorEmail}>`, |
140 | | -// TreeItemCollapsibleState.None, |
141 | | -// 'person', |
142 | | -// ), |
143 | | -// new CommitNode( |
144 | | -// 'Date', |
145 | | -// new Date(commitDetail.date).toLocaleString(), |
146 | | -// TreeItemCollapsibleState.None, |
147 | | -// 'calendar', |
148 | | -// ), |
149 | | -// new CommitNode( |
150 | | -// 'Hash', |
151 | | -// commitDetail.hash, |
152 | | -// TreeItemCollapsibleState.None, |
153 | | -// 'git-commit', |
154 | | -// ), |
155 | | -// new CommitNode( |
156 | | -// 'Changed Files', |
157 | | -// `${total} Files Changed`, |
158 | | -// total > 0 ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.None, |
159 | | -// 'files', |
160 | | -// files, |
161 | | -// ), |
162 | | -// ] |
163 | | -// } |
164 | | -// return selectedCommitHash.value.map(hash => tree.getItem(hash)) |
165 | | -// }) |
166 | | - |
167 | | -// const refresh = (commitsHash: string[]) => { |
168 | | -// selectedCommitHash.value = commitsHash |
169 | | -// tree.refresh() |
170 | | -// } |
171 | | - |
172 | | -// const getCommitByHash = async (hash?: string): Promise<CommitDetails | null> => { |
173 | | -// try { |
174 | | -// if (!hash) { |
175 | | -// throw new Error('Commit hash is required') |
176 | | -// } |
177 | | - |
178 | | -// // First try to get from cache |
179 | | -// let commit = storageService.getCommit(hash) |
180 | | - |
181 | | -// if (!commit) { |
182 | | -// // Only fetch all commits if not found in cache |
183 | | -// const history = await git.getHistory() |
184 | | -// const historyCommit = history.all.find(c => c.hash === hash) |
185 | | -// if (!historyCommit) { |
186 | | -// return null |
187 | | -// } |
188 | | - |
189 | | -// commit = { |
190 | | -// hash: historyCommit.hash, |
191 | | -// authorName: historyCommit.author_name, |
192 | | -// authorEmail: historyCommit.author_email, |
193 | | -// date: historyCommit.date, |
194 | | -// message: historyCommit.message, |
195 | | -// body: historyCommit.body, |
196 | | -// stats: historyCommit.stats, |
197 | | -// } |
198 | | -// } |
199 | | - |
200 | | -// return commit |
201 | | -// } |
202 | | -// catch (error) { |
203 | | -// console.error('Error getting commit details:', error) |
204 | | -// return null |
205 | | -// } |
206 | | -// } |
207 | | - |
208 | | -// const getFiles = async () => { |
209 | | -// try { |
210 | | -// const status = await git.status() |
211 | | -// } |
212 | | -// catch (error) { |
213 | | -// console.error('Error getting files:', error) |
214 | | -// } |
215 | | -// } |
216 | | - |
217 | | -// return { |
218 | | -// diffTreeView: tree, |
219 | | -// selectedCommitHash, |
220 | | -// refresh, |
221 | | -// } |
222 | | -// }) |
| 114 | +}) |
0 commit comments