import * as path from 'path'; import { Event, TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri, workspace } from 'vscode'; import { PijulChange, PijulFileChange, Repository } from '../pijul'; /** * The Changelog provider class is a Treedata provider which provides * TreeData for the `pijul.views.changelog` TreeView */ export class ChangelogViewProvider implements TreeDataProvider<PijulChange | PijulFileChange> { /** * Create a new ChangelogViewProvider instance * @param repository */ constructor ( private readonly repository: Repository, public readonly onDidChangeTreeData?: Event<void> ) {} /** * Convert a PijulChange into a TreeItem * @param element */ getTreeItem (element: PijulChange | PijulFileChange): TreeItem | Thenable<TreeItem> { if (element instanceof PijulChange) { const resourceUri = Uri.parse('pijul-change:' + element.hash); return { label: element.message, description: `${element.author.name}, ${element.date.toISOString()}`, collapsibleState: TreeItemCollapsibleState.Collapsed, contextValue: 'pijulChange', tooltip: `${element.hash}\nRecorded by ${element.author.fullName ?? element.author.name} at ${element.date.toISOString()}\n\n\t${element.message}\n`, command: { command: 'vscode.open', title: 'Open Change TOML', arguments: [resourceUri] } }; } else { // It's a PijulFileChange // TODO: Customize appearance depending on file action (Edit, Replacement, Deletion, etc.) const relativePath = path.relative(workspace.workspaceFolders?.[0]?.uri.path ?? '/', element.path.fsPath); return { label: path.basename(relativePath), description: path.dirname(relativePath), collapsibleState: TreeItemCollapsibleState.None, contextValue: 'pijulChangedFile', tooltip: `${element.operations.join(', ')} in ${relativePath}`, command: { command: 'vscode.open', title: 'Open Change TOML', arguments: [element.path] } }; } } /** * Get the children of the element or the root if no element is passed * @param element An optional element to get the children of */ async getChildren (element?: PijulChange | PijulFileChange): Promise<Array<PijulChange | PijulFileChange> | null | undefined> { if (element) { if (element instanceof PijulChange) { // Show the paths of the files altered by the parent change return await this.repository.getChangeFiles(element); } else { // Paths have no children return null; } } else { let children; // Retry if the pristine is locked. TODO: More robust solution while (!children) { try { children = await this.repository.getLog(); } catch (err) { if (!(err instanceof Error) || !err.message.includes('Pristine locked')) { throw err; } } } return children; } } }