Implement command usages

This commit is contained in:
Chipmunk 2023-09-03 18:08:44 -04:00
parent 9f9abb2831
commit a5453f4666
2 changed files with 83 additions and 1 deletions

View file

@ -147,7 +147,7 @@ class CommandDispatcher {
if (child.redirect != null) {
const childContext = new CommandContextBuilder(this, source, child.redirect, reader.cursor)
const parse = this.#parseNodes(child.redirect, reader, childContext)
context.withChild(parse.context())
context.withChild(parse.context)
return new ParseResults(context, parse.reader, parse.exceptions)
} else {
const parse = this.#parseNodes(child, reader, context)
@ -176,6 +176,84 @@ class CommandDispatcher {
return new ParseResults(contextSoFar, originalReader, errors == null ? new Map() : errors)
}
getAllUsage (node, source, restricted) {
const result = []
this.#getAllUsage(node, source, result, '', restricted)
return result
}
#getAllUsage (node, source, result, prefix, restricted) {
if (restricted && !node.canUse(source)) return
if (node.command != null) result.push(prefix)
if (node.redirect != null) {
const redirect = node.redirect === this.root ? '...' : '-> ' + node.redirect.getUsageText()
result.push(prefix.length === 0 ? node.getUsageText() + CommandDispatcher.ARGUMENT_SEPARATOR + redirect : prefix + CommandDispatcher.ARGUMENT_SEPARATOR + redirect)
} else if (node.getChildren().length !== 0) {
for (const child of node.getChildren()) {
this.#getAllUsage(child, source, result, prefix.length === 0 ? child.getUsageText() : prefix + CommandDispatcher.ARGUMENT_SEPARATOR + child.getUsageText(), restricted)
}
}
}
getSmartUsage (node, source) {
const result = new Map()
const optional = node.command != null
for (const child of node.getChildren()) {
const usage = this.#getSmartUsage(child, source, optional, false)
if (usage != null) result.set(child, usage)
}
return result
}
#getSmartUsage (node, source, optional, deep) {
if (!node.canUse(source)) return
const self = optional ? USAGE_OPTIONAL_OPEN + node.getUsageText() + USAGE_OPTIONAL_CLOSE : node.getUsageText()
const childOptional = node.command != null
const open = childOptional ? USAGE_OPTIONAL_OPEN : USAGE_REQUIRED_OPEN
const close = childOptional ? USAGE_OPTIONAL_CLOSE : USAGE_REQUIRED_CLOSE
if (!deep) {
if (node.redirect != null) {
const redirect = node.redirect === this.root ? '...' : '-> ' + node.redirect.getUsageText()
return self + CommandDispatcher.ARGUMENT_SEPARATOR + redirect
} else {
const children = node.getChildren().filter(c => c.canUse(source))
if (children.length === 1) {
const usage = this.#getSmartUsage(children[0], source, childOptional, childOptional)
if (usage != null) return self + CommandDispatcher.ARGUMENT_SEPARATOR + usage
} else if (children.length > 1) {
const childUsage = new Set()
for (const child of children) {
const usage = this.#getSmartUsage(child, source, childOptional, true)
if (usage != null) childUsage.add(usage)
}
if (childUsage.length === 1) {
const usage = childUsage.values().next().value
return self + CommandDispatcher.ARGUMENT_SEPARATOR + (childOptional ? USAGE_OPTIONAL_OPEN + usage + USAGE_OPTIONAL_CLOSE : usage)
} else if (childUsage.length > 1) {
let string = open
let count = 0
for (const child of children) {
if (count > 0) string += USAGE_OR
string += child.getUsageText()
count++
}
if (count > 0) {
string += close
return self + CommandDispatcher.ARGUMENT_SEPARATOR + string
}
}
}
}
}
return self
}
async getCompletionSuggestions (parse, cursor = parse.reader.getTotalLength()) {
const context = parse.context

View file

@ -44,6 +44,10 @@ class CommandContext {
return argument.result
}
hasNodes () {
return this.nodes.length !== 0
}
}
module.exports = CommandContext