fix(console): don't silently drop a filled param after an empty optional
The builder's "omit trailing optionals" loop stopped at the FIRST empty optional, which discarded any later field the user had filled — e.g. setban with bantime empty but absolute=true built `setban "ip" "add"`, dropping the typed `true`, and (worse) left Insert & run enabled so it ran a command that ignored the input. Include fields up to the last one that is filled or required; only genuinely trailing empty optionals are dropped. A gap (an empty field before a later filled one) keeps its placeholder and marks the command incomplete, so Insert & run disables and nothing typed is lost. Found by an adversarial pass over all 82 param templates. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1635,13 +1635,20 @@ void ConsoleTab::renderCommandDetail(const ConsoleCommandEntry& cmd, const char*
|
|||||||
if (a == std::string::npos) return std::string();
|
if (a == std::string::npos) return std::string();
|
||||||
return s.substr(a, s.find_last_not_of(" \t") - a + 1);
|
return s.substr(a, s.find_last_not_of(" \t") - a + 1);
|
||||||
};
|
};
|
||||||
|
// Include fields up to the last one that is filled OR required; trailing empty optionals are
|
||||||
|
// dropped. An empty field that must still be included (a blank required field, or a gap before a
|
||||||
|
// later filled field — positional args can't skip a middle slot) keeps its placeholder and marks
|
||||||
|
// the command incomplete, so Insert & run stays disabled and no typed value is silently lost.
|
||||||
|
int lastNeeded = -1;
|
||||||
|
for (size_t k = 0; k < specs.size() && k < 6; k++)
|
||||||
|
if (!trimStr(cmd_param_bufs_[k]).empty() || !specs[k].optional) lastNeeded = (int)k;
|
||||||
bool complete = specs.size() <= 6;
|
bool complete = specs.size() <= 6;
|
||||||
std::string built = cmd.name;
|
std::string built = cmd.name;
|
||||||
for (size_t k = 0, stop = 0; k < specs.size() && k < 6 && !stop; k++) {
|
for (int k = 0; k <= lastNeeded; k++) {
|
||||||
std::string val = trimStr(cmd_param_bufs_[k]);
|
std::string val = trimStr(cmd_param_bufs_[k]);
|
||||||
if (val.empty()) {
|
if (val.empty()) {
|
||||||
if (specs[k].optional) stop = 1; // omit this + trailing optionals
|
built += " " + specs[k].raw;
|
||||||
else { built += " " + specs[k].raw; complete = false; } // required placeholder
|
complete = false;
|
||||||
} else {
|
} else {
|
||||||
if (specs[k].type == "string" && val.front() != '"' && val.front() != '\'' &&
|
if (specs[k].type == "string" && val.front() != '"' && val.front() != '\'' &&
|
||||||
val.front() != '[' && val.front() != '{')
|
val.front() != '[' && val.front() != '{')
|
||||||
|
|||||||
Reference in New Issue
Block a user