Add basic console tab completion
This commit is contained in:
@@ -154,6 +154,7 @@ static inline void IConsoleResetHistoryPos()
|
||||
|
||||
static const char *IConsoleHistoryAdd(const char *cmd);
|
||||
static void IConsoleHistoryNavigate(int direction);
|
||||
static void IConsoleTabCompletion();
|
||||
|
||||
static const struct NWidgetPart _nested_console_window_widgets[] = {
|
||||
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_BACKGROUND), SetResize(1, 1),
|
||||
@@ -299,6 +300,10 @@ struct IConsoleWindow : Window
|
||||
IConsoleCmdExec("clear");
|
||||
break;
|
||||
|
||||
case WKC_TAB:
|
||||
IConsoleTabCompletion();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (_iconsole_cmdline.HandleKeyPress(key, keycode) != HKPR_NOT_HANDLED) {
|
||||
IConsoleWindow::scroll = 0;
|
||||
@@ -494,6 +499,69 @@ static void IConsoleHistoryNavigate(int direction)
|
||||
}
|
||||
}
|
||||
|
||||
static void IConsoleTabCompletion()
|
||||
{
|
||||
const char *input = _iconsole_cmdline.buf;
|
||||
|
||||
/* Strip all spaces at the beginning */
|
||||
while (IsWhitespace(*input)) input++;
|
||||
|
||||
/* Don't do tab completion for no input */
|
||||
if (StrEmpty(input)) return;
|
||||
|
||||
const char *cmdptr = input;
|
||||
for (; *cmdptr != '\0'; cmdptr++) {
|
||||
switch (*cmdptr) {
|
||||
case ' ':
|
||||
case '"':
|
||||
case '\\':
|
||||
// Give up
|
||||
return;
|
||||
}
|
||||
}
|
||||
size_t length = cmdptr - input;
|
||||
char *prefix = (char*)alloca(length + 1);
|
||||
strecpy(prefix, input, prefix + length);
|
||||
RemoveUnderscores(prefix);
|
||||
size_t prefix_length = strlen(prefix);
|
||||
|
||||
if (prefix_length == 0) return;
|
||||
|
||||
char buffer[4096];
|
||||
char *b = buffer;
|
||||
uint matches = 0;
|
||||
std::string common_prefix;
|
||||
for (const IConsoleCmd *cmd = _iconsole_cmds; cmd != nullptr; cmd = cmd->next) {
|
||||
if (strncmp(cmd->name, prefix, prefix_length) == 0) {
|
||||
if ((_settings_client.gui.console_show_unlisted || !cmd->unlisted) && (cmd->hook == nullptr || cmd->hook(false) != CHR_HIDE)) {
|
||||
if (matches == 0) {
|
||||
common_prefix = cmd->name;
|
||||
} else {
|
||||
const char *cp = common_prefix.c_str();
|
||||
const char *cmdp = cmd->name;
|
||||
while (true) {
|
||||
const char *end = cmdp;
|
||||
WChar a = Utf8Consume(cp);
|
||||
WChar b = Utf8Consume(cmdp);
|
||||
if (a == 0 || b == 0 || a != b) {
|
||||
common_prefix.resize(end - cmd->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
matches++;
|
||||
b += seprintf(b, lastof(buffer), "%s ", cmd->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matches > 0) {
|
||||
_iconsole_cmdline.Assign(common_prefix.c_str());
|
||||
if (matches > 1) {
|
||||
IConsolePrint(CC_WHITE, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the printing of text entered into the console or redirected there
|
||||
* by any other means. Text can be redirected to other clients in a network game
|
||||
|
Reference in New Issue
Block a user