diff --git a/NodeApp/src/helpers/AutoCompletionHelper.ts b/NodeApp/src/helpers/AutoCompletionHelper.ts index bb46c1e6eecbdad4538303f5e5bf01c01a60fed1..34c5d7e3d7196fcbd382291a3f16c11237400ed5 100644 --- a/NodeApp/src/helpers/AutoCompletionHelper.ts +++ b/NodeApp/src/helpers/AutoCompletionHelper.ts @@ -79,88 +79,62 @@ import { writeFileSync } from 'fs'; // return 0 // } -interface CmdNode { - readonly name: string; - readonly children: Array<CmdNode>; - readonly parent?: string; +function isLeaf(cmd: Command): boolean { + return cmd.commands.length == 0 } -function createCmdNode(name: string, children: Array<CmdNode>, parent?: string): CmdNode { - return { - name, - children, - parent - }; -} - -function isLeaf(tree: CmdNode): boolean { - return tree.children === undefined || tree.children.length == 0 -} - -function isRoot(tree: CmdNode): boolean { - return tree.parent === undefined -} - -function search(tree: CmdNode, cmdName: string): Array<CmdNode> { - if (isLeaf(tree)) { - if (tree.name != cmdName) { +function search(cmd: Command, cmdName: string): Array<Command> { + if (isLeaf(cmd)) { + if (cmd.name() != cmdName) { return [] } else { - return [tree] + return [cmd] } - } else if (tree.name == cmdName) { - return tree.children.flatMap(st => search(st, cmdName)).concat(tree) + } else if (cmd.name() == cmdName) { + return cmd.commands.flatMap(st => search(st, cmdName)).concat(cmd) } else { - return tree.children.flatMap(st => search(st, cmdName)) + return cmd.commands.flatMap(st => search(st, cmdName)) } } -function flatten(tree: CmdNode): Array<CmdNode> { - if (isLeaf(tree)) { - return [tree] +function flatten(cmd: Command): Array<Command> { + if (isLeaf(cmd)) { + return [cmd] } else { - return tree.children + return cmd.commands .map(child => flatten(child)) - .reduce((acc, cmd) => acc.concat(cmd), [tree]) + .reduce((acc, cmd) => acc.concat(cmd), [cmd]) } } -function printWordsGrandParents(node: CmdNode): string { +function addWordsGrandParents(cmd: Command): string { let parentWords = "" let ident = 3 - if (node.parent !== undefined) { + if (cmd.parent !== null) { parentWords += openCase(ident, 'grand_parent') ident += 1 - parentWords += addLine(ident, `${node.parent})`) + parentWords += addLine(ident, `${cmd.parent.name()})`) ident += 1 } - parentWords += addLine(ident, `words="${node.children.map(c => c.name).join(" ")} --help -h"`) + parentWords += addLine(ident, `words="${commandsAndOptionsToString(cmd)}"`) ident -= 1 parentWords += addLine(ident, ';;') - if (node.parent !== undefined) { + if (cmd.parent !== null) { ident -= 1 parentWords += `${closeCase(ident)}` } return parentWords } -function getOptions(cmd: Command): Array<CmdNode> { +function getOptions(cmd: Command): string { // we remove <args>, [command], and , from option lines return cmd.options.filter(opt => !opt.hidden).map(opt => - createCmdNode(opt.flags.replace(/<.*?>/, '').replace(/\[.*?\]/, '').replace(',', '').trimEnd(), [], cmd.name()) - ) + opt.flags.replace(/<.*?>/, '').replace(/\[.*?\]/, '').replace(',', '').trimEnd() + ).join(" ") } -function getSubCmdNode(cmd: Command, parent: Command): CmdNode { - if (cmd.commands.length > 0) { - return createCmdNode(cmd.name(), cmd.commands.map(subCmd => getSubCmdNode(subCmd, cmd)).concat(getOptions(cmd)), parent.name()) - } else { - return createCmdNode(cmd.name(), getOptions(cmd), parent.name()) - } -} - -function buildCmdNode(root: Command): CmdNode { - return createCmdNode(root.name(), root.commands.map(subCmd => getSubCmdNode(subCmd, root)).concat(getOptions(root))) +function commandsAndOptionsToString(cmd: Command): string { + return cmd.commands.map(c => c.name()).join(" ").concat(' ' + getOptions(cmd)).trim().concat(' --help -h').trim() } function openCase(identLevel: number, pattern: string): string { @@ -210,12 +184,11 @@ end ` export function getFishCompletion(root: Command, filename: string) { - const tree = buildCmdNode(root) - const commands = Array.from(new Set(flatten(tree).filter(cmd => !isLeaf(cmd)).map(cmd => cmd.name))).map(name => search(tree, name)) + const commands = Array.from(new Set(flatten(root).filter(cmd => !isLeaf(cmd)).map(cmd => cmd.name()))).map(name => search(root, name)) let data = fishFunctions for (const node of commands) { const cmd = node[0] - data += addLine(0, `complete -f -c dojo -n __fish_dojo_needs_command ${cmd.name} -a "${cmd.children.map(c => c.name).join(" ")} --help -h"`) + data += addLine(0, `complete -f -c dojo -n __fish_dojo_needs_command ${cmd.name()} -a "${commandsAndOptionsToString(cmd)}"`) } @@ -224,22 +197,21 @@ export function getFishCompletion(root: Command, filename: string) { export function getBashCompletion(root: Command, filename: string) { - const tree = buildCmdNode(root) - let data = `${addLine(0, '#/usr/bin/env bash\nfunction _dojo_completions()')}` + `${addLine(0, '{')}${addLine(1, 'latest="${COMP_WORDS[$COMP_CWORD]}"')}` + `${addLine(1, 'parent="${COMP_WORDS[$COMP_CWORD - 1]}"')}` + `${addLine(1, 'grand_parent="${COMP_WORDS[$COMP_CWORD - 2]}"')}` - + `${addLine(1, 'words=""')}${openCase(1, "parent")}` - const commands = Array.from(new Set(flatten(tree).filter(cmd => !isLeaf(cmd)).map(cmd => cmd.name))).map(name => search(tree, name)) - for (const node of commands) { - const cmd = node[0] - data += addLine(2, `${cmd.name})`) - if (cmd !== undefined && node.length == 1) { - data += addLine(3, `words="${cmd.children.map(c => c.name).join(" ")} --help -h"`) - } else if (cmd !== undefined && node.length > 1) { - node.forEach(n => data += printWordsGrandParents(n)) + + `${addLine(1, 'words=""')}` + + `${openCase(1, "parent")}` + const commands = Array.from(new Set(flatten(root).map(cmd => cmd.name()))).map(name => search(root, name)) + for (const cmdNode of commands) { + const cmd = cmdNode[0] + data += addLine(2, `${cmd.name()})`) + if (cmd !== undefined && cmdNode.length == 1) { + data += addLine(3, `words="${commandsAndOptionsToString(cmd)}"`) + } else if (cmd !== undefined && cmdNode.length > 1) { + cmdNode.forEach(n => data += addWordsGrandParents(n)) } data += addLine(2, ';;') }