Skip to content
Snippets Groups Projects

Resolve "Add zsh, fish, and bash shell completion helper function generation as well as the related command"

1 unresolved thread
1 file
+ 36
64
Compare changes
  • Side-by-side
  • Inline
@@ -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, ';;')
}
Loading