import { Event, TreeDataProvider, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode'; import { PijulChange, PijulChannel, Repository } from '../pijul'; /** * The Channels provider class is a Treedata provider which provides * TreeData for the `pijul.views.channels` TreeView */ export class ChannelsViewProvider implements TreeDataProvider<PijulChannel | PijulChange> { /** * Create a new ChannelViewProvider instance * @param repository */ constructor ( private readonly repository: Repository, public readonly onDidChangeTreeData?: Event<void> ) {} /** * Convert a PijulChannel into a TreeItem * @param element */ getTreeItem (element: PijulChannel | PijulChange): TreeItem | Thenable<TreeItem> { if (element instanceof PijulChannel) { return { id: element.name, label: element.name, description: element.isCurrent ? 'Current' : undefined, collapsibleState: element.isCurrent ? TreeItemCollapsibleState.None : TreeItemCollapsibleState.Collapsed, // Different context menu options for current and inactive channels contextValue: 'pijulChannel' + (element.isCurrent ? 'Current' : '') }; } else { return { label: element.message, description: `${element.author.name}, ${element.date.toISOString()}`, collapsibleState: TreeItemCollapsibleState.None, 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: [Uri.parse('pijul-change:' + element.hash)] } }; } } /** * 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?: PijulChannel | PijulChange): Promise<Array<PijulChannel | PijulChange> | null | undefined> { if (element) { // Channels don't have children if (element instanceof PijulChannel) { // TODO: Distinguish between changes in the current channel and not in the other channel and // changes in the other channel which are not in the current channel return await this.repository.compareChannelChanges(element.name); } else { return null; } } else { let children; // Retry if the pristine is locked. while (!children) { try { children = await this.repository.getChannels(); } catch (err) { if (!(err instanceof Error) || !err.message.includes('Pristine locked')) { throw err; } } } return children; } } }