Add command centre and refresh/init commands

[?]
Dec 24, 2020, 9:23 PM
ILH3GIVTVMKSU5TH5ZZSPB3URX622JA2BNBOO6K7ZTF4ISYDTJLAC

Dependencies

  • [2] ZI7ORD4P Add iconv dependency
  • [3] B4SKYP3Y Add repository model and add steps to initialize it
  • [4] NCBEWRYE Initialize Repository
  • [5] F2CO6Z7E Add LICENSE file
  • [6] 3N3RS66T Create pijul output channel and configure activation events
  • [7] TKKT6D4C Add failure loop to installation selection
  • [8] 4PN3R2LY Fix lint/style issues

Change contents

  • file addition: commands.ts (-xw-x--x--)
    [4.104980]
    import { commands, Disposable, OutputChannel, window, workspace } from 'vscode';
    import { Pijul } from './pijul';
    import { Repository } from './repository';
    import { dispose } from './utils/disposableUtils';
    /**
    * Interface representing the command creation options,
    * which determines which parameters are passed from the
    * command centre to the command.
    */
    interface ICommandOptions {
    repository?: boolean
    // diff?: boolean
    }
    /**
    * Interface that describes the fields required to register
    * a new command with VS Code.
    */
    interface ICommand {
    /** The command ID that the command will be registered under, matching the one in `package.json` */
    commandId: string
    /** The name of the function that the command invokes */
    key: string
    /** The function that will be invoked by the command */
    method: Function
    /** The options for the command creation */
    options: ICommandOptions
    }
    /**
    * An array which holds all of the commands which will
    * be registered by the command centre
    */
    const Commands: ICommand[] = [];
    /**
    * Decorator function for adding functions to the Commands array
    * for registration.
    * @param commandId The id that will be assigned to the command, matching the one in `package.json`
    * @param options The command options which control how it is created
    */
    function command (commandId: string, options: ICommandOptions = {}): Function {
    return (_target: any, key: string, descriptor: any) => {
    if (!(typeof descriptor.value === 'function')) {
    throw new Error('not supported');
    }
    Commands.push({ commandId, key, method: descriptor.value, options });
    };
    }
    export class CommandCentre {
    private disposables: Disposable[];
    constructor (
    private readonly pijul: Pijul,
    private readonly repository: Repository,
    private readonly outputChannel: OutputChannel
    ) {
    this.disposables = Commands.map(({ commandId, key, method, options }) => {
    const command = this.createCommand(key, method, options);
    return commands.registerCommand(commandId, command);
    });
    this.outputChannel.appendLine('Activated Command Centre');
    }
    /**
    * Wraps a specific command function in a generic command function for error
    * and argument handling.
    * @param key The name of the function that the command invokes
    * @param func The actual function which will be wrapped in the generic one
    * @param options The options which determine which Command centre fields will be passed to the command
    */
    private createCommand (key: string, func: Function, options: ICommandOptions): (...args: any[]) => any {
    const result = async (...args: any[]): Promise<any> => {
    let result: Promise<any>;
    if (!options.repository) {
    result = Promise.resolve(func.apply(this, args));
    } else {
    // TODO: Handle multiple open repositories
    return await Promise.resolve(func.apply(this, [this.repository, ...args]));
    }
    // TODO: Generic command-level error handling
    return await result;
    };
    // Update the object so that directly invoking the command function on the command centre calls the wrapped version.
    (this as any)[key] = result;
    return result;
    }
    /**
    * Initialize a new Pijul repository in the current working directory.
    */
    @command('pijul.init')
    async init (): Promise<void> {
    // TODO: Select workspace folder to init in
    const cwd = workspace.workspaceFolders?.[0]?.uri.path;
    if (cwd) {
    await this.pijul.init(cwd);
    this.refresh(this.repository);
    } else {
    await window.showErrorMessage('No workspace folders open, cannot initialize Pijul repository');
    }
    }
    /**
    * Refresh the the state of the files within the extension.
    * @param repository The repository to run the file in
    */
    @command('pijul.refresh', { repository: true })
    async refresh (repository: Repository): Promise<void> {
    await repository.refreshStatus();
    }
    dispose (): void {
    this.disposables = dispose(this.disposables);
    }
    }
  • edit in src/extension.ts at line 4
    [4.71]
    [3.1666]
    import { CommandCentre } from './commands';
  • replacement in src/extension.ts at line 125
    [3.2120][3.2120:2149]()
    console.log(repository);
    [3.2120]
    [4.1893]
    disposables.push(new CommandCentre(pijul, repository, outputChannel));
  • replacement in package.json at line 14
    [4.108440][4.1223:1255]()
    "workspaceContains:**/.pijul"
    [4.108440]
    [4.108484]
    "workspaceContains:**/.pijul",
    "onCommand:pijul.init"
  • replacement in package.json at line 21
    [4.108559][4.1256:1319]()
    "command": "pijul.helloWorld",
    "title": "Hello World",
    [4.108559]
    [4.1319]
    "command": "pijul.refresh",
    "title": "Refresh Repository",
  • edit in package.json at line 26
    [4.1354]
    [4.1354]
    "command": "pijul.init",
    "title": "Initialize Repository",
    "category": "Pijul"
    },
    {
  • replacement in package.json at line 37
    [2.342][2.342:378]()
    "title": "Record Pijul Change",
    [2.342]
    [4.1422]
    "title": "Record Change",