import { Command, FileDecoration, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri } from 'vscode'; /** * Class which represents a resource within the repository, containing its URI and Pijul state */ export class Resource implements SourceControlResourceState { /** * Create a new resource * @param _resourceUri The URI of the resource * @param status The Pijul status of the resource */ constructor ( private readonly _resourceUri: Uri, private readonly status: ResourceStatus ) { } /** * The URI of the resource */ get resourceUri (): Uri { // TODO: Handle moves? return this._resourceUri; } /** * The command which will be run when the resource is clicked on */ get command (): Command { return { command: 'vscode.open', title: 'Open', arguments: [this.resourceUri] }; } /** * The tooltip briefly explaining the state of the resource */ private get tooltip (): string { switch (this.status) { case ResourceStatus.Edit: return 'Edit'; case ResourceStatus.Replacement: return 'Replacement'; case ResourceStatus.FileAdd: return 'Added'; case ResourceStatus.FileMove: return 'Moved'; case ResourceStatus.FileDel: return 'Deleted'; case ResourceStatus.FileUndel: return 'Undeleted'; case ResourceStatus.SolveNameConflict: return 'Solve Name Conflict'; case ResourceStatus.SolveOrderConflict: return 'Solve Order Conflict'; case ResourceStatus.UnsolveNameConflict: return 'Unsolve Name Conflict'; case ResourceStatus.UnsolveOrderConflict: return 'Unsolve Order Conflict'; case ResourceStatus.ResurrectZombies: return 'Resurrect Zombies'; case ResourceStatus.Untracked: return 'Untracked'; // I don't know why typescript doesn't complain about this one default: return ''; } } /** * Boolean indicating if the filename should be rendered with strikethrough */ private get strikeThrough (): boolean { return this.status === ResourceStatus.FileDel; } /** * Boolean indicating if the filename should be faded */ private get faded (): boolean { return this.status === ResourceStatus.Untracked; } /** * Accessor for the decoration applied to the resource in the source control menu */ get decorations (): SourceControlResourceDecorations { const tooltip = this.tooltip; const strikeThrough = this.strikeThrough; const faded = this.faded; return { strikeThrough, faded, tooltip }; } /** * The badge, a short string indicating the state of the resource */ get badge (): string { switch (this.status) { case ResourceStatus.FileMove: return 'MV'; case ResourceStatus.FileDel: return 'D'; case ResourceStatus.FileUndel: return 'UD'; case ResourceStatus.FileAdd: return 'A'; case ResourceStatus.SolveNameConflict: case ResourceStatus.SolveOrderConflict: return 'SC'; case ResourceStatus.UnsolveNameConflict: case ResourceStatus.UnsolveOrderConflict: return 'UC'; case ResourceStatus.Edit: return 'M'; case ResourceStatus.Replacement: return 'R'; case ResourceStatus.ResurrectZombies: return 'RZ'; case ResourceStatus.Untracked: return ''; default: // This should never happen so typescript won't accept it without error, but // I'm leaving it in for safety. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions throw new Error(`Unknown pijul status: ${this.status}`); } } /** * The theme colour that should be used for the badge */ get colour (): ThemeColor { switch (this.status) { case ResourceStatus.Replacement: return new ThemeColor('pijulDecoration.replacementForeground'); case ResourceStatus.Edit: return new ThemeColor('pijulDecoration.editForeground'); case ResourceStatus.FileDel: case ResourceStatus.FileUndel: return new ThemeColor('pijulDecoration.deletedResourceForeground'); case ResourceStatus.FileAdd: return new ThemeColor('pijulDecoration.addedForeground'); case ResourceStatus.FileMove: case ResourceStatus.Untracked: return new ThemeColor('pijulDecoration.untrackedForeground'); case ResourceStatus.SolveNameConflict: case ResourceStatus.SolveOrderConflict: case ResourceStatus.UnsolveNameConflict: case ResourceStatus.UnsolveOrderConflict: case ResourceStatus.ResurrectZombies: return new ThemeColor('pijulDecoration.conflictForeground'); default: // This should never happen so typescript won't accept it without error, but // I'm leaving it in for safety. // eslint-disable-next-line @typescript-eslint/restrict-template-expressions throw new Error(`Unknown pijul status: ${this.status}`); } } /** * Accessor for the file decoration that should be applied to this resource */ get resourceDecoration (): FileDecoration { const decorations = new FileDecoration(this.badge, this.tooltip, this.colour); decorations.propagate = this.status !== ResourceStatus.FileDel; return decorations; } } /** * Enum corresponding to the various Pijul file states. Using a string enum * allows for direct casting of the operation string in a pijul JSON diff. */ export enum ResourceStatus { FileMove = 'file move', FileDel = 'file del', FileUndel = 'file undel', SolveNameConflict = 'solve name conflict', UnsolveNameConflict = 'unsolve name conflict', FileAdd = 'file add', Edit = 'edit', Replacement = 'replacement', SolveOrderConflict = 'solve order conflict', UnsolveOrderConflict = 'unsolve order conflict', ResurrectZombies = 'resurrect zombies', Untracked = 'untracked' } /** * Interface which represents a groups of resources that is tracked by * the Pijul source control manager. */ export interface PijulResourceGroup extends SourceControlResourceGroup { resourceStates: Resource[] }