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