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;
}
}
}