Skip to content
Snippets Groups Projects
Select Git revision
  • f1dc5f76ca8cfdcde91f2ac4afda75ba2eb0dff5
  • main default protected
  • jw_sonar
  • v6.0.0 protected
  • interactive-mode-preference
  • bedran_exercise-list
  • add_route_user
  • Jw_sonar_backup
  • exercise_list_filter
  • assignment_filter
  • add_route_assignments
  • move-to-esm-only
  • 6.0.0-dev
  • Pre-alpha
  • 5.0.0
  • Latest
  • 4.2.0
  • 4.1.1
  • 4.1.0
  • 4.0.1
  • 4.0.0
  • 3.5.0
  • 3.4.2
  • 3.4.1
  • 3.3.0
  • 3.2.3
  • 3.2.2
  • 3.2.0
  • 3.1.2
  • 3.1.1
  • 3.1.0
  • 3.0.1
32 results

AutoCompletionHelper.ts

Blame
  • AutoCompletionHelper.ts 10.64 KiB
    import { Command } from 'commander';
    
    const fishFunction = `
    function __fish_dojo_using_commands
        set cmd (commandline -opc)
        set num_cmd (count $cmd)
        if [ $num_cmd -eq $argv[1] ]
            for i in (seq 1 (math $num_cmd))
                if [ $argv[(math $i+1)] != $cmd[$i] ]
                    return 1
                end
            end
            return 0
        end
        return 1
    end
    
    complete -f -c dojo
    `
    
    function isLeaf(cmd: Command): boolean {
        return cmd.commands.length == 0
    }
    
    function flatten(cmd: Command): Array<Command> {
        if (isLeaf(cmd)) {
            return [cmd]
        } else {
            return cmd.commands
                .map(child => flatten(child))
                .reduce((acc, cmd) => acc.concat(cmd), [cmd])
        }
    }
    
    // Computes the maximum number of commands until a leaf is reached
    function computeDepth(cmd: Command | undefined): number {
        if (cmd === undefined) {
            return 0
        } else {
            return 1 + cmd.commands.map(subCmd => computeDepth(subCmd)).reduce((acc, depth) => depth > acc ? depth : acc, 0)
        }
    }
    
    // Computes the maximum number of commands until the root is reached
    function computeHeight(cmd: Command | null): number {
        let height = 0
        let tmp = cmd
        while (tmp !== null) {
            tmp = tmp.parent
            height += 1
        }
        return height
    }
    
    // Computes the maximum number of commands until the root is reached
    export function getRoot(cmd: Command): Command {
        if (cmd.parent == null) {
            return cmd
        } else {
            return getRoot(cmd.parent)
        }
    }
    
    function getOptions(cmd: Command): string {
        // we remove <args>, [command], and , from option lines
        return cmd.options.filter(opt => !opt.hidden).map(opt =>
            opt.flags.replace(/<.*?>/, '').replace(/\[.*?\]/, '').replace(',', '').trimEnd()
        ).join(" ")
    }
    
    function commandsAndOptionsToString(cmd: Command): string {
        return cmd.commands.map(c => c.name()).join(" ").concat(' ' + getOptions(cmd)).trim().concat(' --help -h').trim()
    }
    
    function addLine(identLevel: number, pattern: string): string {
        return `${'    '.repeat(identLevel)}${pattern}\n`
    }
    
    function generateBashSubCommands(cmd: Command, current: number, maxDepth: number, ident: number): string {
        if (current == maxDepth) {
            return addLine(ident, `case "\${COMP_WORDS[$COMP_CWORD - ${maxDepth - current + 1}]}" in`)
                + addLine(ident + 1, `${cmd.name()})`)
                + addLine(ident + 2, `words="${commandsAndOptionsToString(cmd)}"`)
                + addLine(ident + 1, ';;')
                + addLine(ident + 1, '*)')
                + addLine(ident + 1, ';;')
                + addLine(ident, 'esac')
    
        } else {
            let data = addLine(ident, `case "\${COMP_WORDS[$COMP_CWORD - ${maxDepth - current + 1}]}" in`)
                + addLine(ident + 1, `${cmd.name()})`)
            cmd.commands.forEach(subCmd => {
                data += generateBashSubCommands(subCmd, current + 1, maxDepth, ident + 2)
            })
            data +=
                addLine(ident + 1, ';;')
                + addLine(ident + 1, '*)')
                + addLine(ident + 1, ';;')
                + addLine(ident, 'esac')
            return data
        }
    }
    
    export function generateBashCompletion(root: Command): string {
        const depth = computeDepth(root)
        let data =
            addLine(0, '#/usr/bin/env bash\nfunction _dojo_completions()')
            + addLine(0, '{')
            + addLine(1, 'latest="${COMP_WORDS[$COMP_CWORD]}"')
        for (let i = 1; i <= depth; i++) {
            data += addLine(1, `${i == 1 ? 'if' : 'elif'} [ $COMP_CWORD -eq ${depth - i + 1} ]`)
                + addLine(1, 'then')
            data += generateBashSubCommands(root, i, depth, 2)
        }
        data += addLine(1, 'fi')
            + addLine(1, 'COMPREPLY=($(compgen -W "$words" -- $latest))')
            + addLine(1, 'return 0')
            + addLine(0, '}')
            + addLine(0, 'complete -F _dojo_completions dojo')
    
        return data
    }
    
    const prefix = 'complete -f -c dojo -n \'__fish_dojo_using_commands'
    
    function generateCommandChain(cmd: Command | null): string {
        let data = ''
        while (cmd !== null) {
            data = cmd.name().concat(` ${data}`)
            cmd = cmd.parent
        }
        return data.trimEnd()
    }
    
    function hasOptions(cmd: Command): boolean {
        return cmd.options.length > 0
    }
    
    function optionsToString(cmd: Command): string {
        return cmd.options.filter(opt => !opt.hidden).map(opt => {
            return `${prefix} ${computeHeight(cmd)} ${generateCommandChain(cmd)}' -a "${opt.short ?? ''} ${opt.long ?? ''}" -d "${opt.description}"`
        }).join('\n').concat('\n')
    }
    
    export function generateFishCompletion(root: Command): string {
        const commands = flatten(root)
    
        const data = fishFunction.concat(
            // add completions for options
            commands.filter(cmd => hasOptions(cmd)).map(cmd => optionsToString(cmd)).filter(str => str != '').join('')
        ).concat(
            // add completions for commands and subcommands
            commands.filter(
                cmd => !isLeaf(cmd)).map(
                    cmd => cmd.commands.map(subCmd => {
                        return `${prefix} ${computeHeight(cmd)} ${generateCommandChain(cmd)}' -a ${subCmd.name()} -d "${subCmd.description()}"`
                    }).join('\n').concat('\n')).join('')
        )
    
        return data
    }
    
    
    
    // The following code should create a bash completion automatically from the Commander
    // CLI library. The file should look something like that (it looks at the time
    // this comment is written).
    
    // #/usr/bin/env bash
    // function _dojo_completions()
    // {
    //     latest="${COMP_WORDS[$COMP_CWORD]}"
    //     if [ $COMP_CWORD -eq 3 ]
    //     then
    //         case "${COMP_WORDS[$COMP_CWORD - 3]}" in
    //             dojo)
    //                 case "${COMP_WORDS[$COMP_CWORD - 2]}" in
    //                     session)
    //                         case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                             login)
    //                                 words="-c --cli --help -h"
    //                             ;;
    //                             *)
    //                             ;;
    //                         esac
    //                         case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                             logout)
    //                                 words="-f --force --help -h"
    //                             ;;
    //                             *)
    //                             ;;
    //                         esac
    //                         case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                             test)
    //                                 words="--help -h"
    //                             ;;
    //                             *)
    //                             ;;
    //                         esac
    //                     ;;
    //                     *)
    //                     ;;
    //                 esac
    //                 case "${COMP_WORDS[$COMP_CWORD - 2]}" in
    //                     assignment)
    //                         case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                             create)
    //                                 words="-n --name -i --members_id -u --members_username -t --template -c --clone --help -h"
    //                             ;;
    //                             *)
    //                             ;;
    //                         esac
    //                         case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                             check)
    //                                 words="-p --path -v --verbose -w --super-verbose --help -h"
    //                             ;;
    //                             *)
    //                             ;;
    //                         esac
    //                         case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                             run)
    //                                 words="-p --path -v --verbose -w --super-verbose --help -h"
    //                             ;;
    //                             *)
    //                             ;;
    //                         esac
    //                         case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                             publish)
    //                                 words="-f --force --help -h"
    //                             ;;
    //                             *)
    //                             ;;
    //                         esac
    //                         case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                             unpublish)
    //                                 words="-f --force --help -h"
    //                             ;;
    //                             *)
    //                             ;;
    //                         esac
    //                     ;;
    //                     *)
    //                     ;;
    //                 esac
    //                 case "${COMP_WORDS[$COMP_CWORD - 2]}" in
    //                     exercise)
    //                         case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                             create)
    //                                 words="-a --assignment -i --members_id -u --members_username -c --clone --help -h"
    //                             ;;
    //                             *)
    //                             ;;
    //                         esac
    //                         case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                             run)
    //                                 words="-p --path -v --verbose -w --super-verbose --help -h"
    //                             ;;
    //                             *)
    //                             ;;
    //                         esac
    //                     ;;
    //                     *)
    //                     ;;
    //                 esac
    //             ;;
    //             *)
    //             ;;
    //         esac
    //     elif [ $COMP_CWORD -eq 2 ]
    //     then
    //         case "${COMP_WORDS[$COMP_CWORD - 2]}" in
    //             dojo)
    //                 case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                     session)
    //                         words="login logout test --help -h"
    //                     ;;
    //                     *)
    //                     ;;
    //                 esac
    //                 case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                     assignment)
    //                         words="create check run publish unpublish --help -h"
    //                     ;;
    //                     *)
    //                     ;;
    //                 esac
    //                 case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //                     exercise)
    //                         words="create run --help -h"
    //                     ;;
    //                     *)
    //                     ;;
    //                 esac
    //             ;;
    //             *)
    //             ;;
    //         esac
    //     elif [ $COMP_CWORD -eq 1 ]
    //     then
    //         case "${COMP_WORDS[$COMP_CWORD - 1]}" in
    //             dojo)
    //                 words="session assignment exercise -V --version -H --host --help -h"
    //             ;;
    //             *)
    //             ;;
    //         esac
    //     fi
    //     COMPREPLY=($(compgen -W "$words" -- $latest))
    //     return 0
    // }
    // complete -F _dojo_completions dojo