Show completion options for tune params in console

Currently supports `tune`, `tune_reset` and `toggle_tune`.

For `tune_zone` the tune name is the second argument, so this is more difficult to handle.
This commit is contained in:
Robert Müller 2022-08-09 18:03:04 +02:00
parent 6af8f46526
commit 33bb576202
2 changed files with 105 additions and 31 deletions

View file

@ -76,6 +76,13 @@ void CConsoleLogger::OnConsoleDeletion()
m_pConsole = nullptr; m_pConsole = nullptr;
} }
// TODO: support "tune_zone", which has tuning as second argument
static const char *gs_apTuningCommands[] = {"tune ", "tune_reset ", "toggle_tune "};
static bool IsTuningCommandPrefix(const char *pStr)
{
return std::any_of(std::begin(gs_apTuningCommands), std::end(gs_apTuningCommands), [pStr](auto *pCmd) { return str_startswith_nocase(pStr, pCmd); });
}
CGameConsole::CInstance::CInstance(int Type) CGameConsole::CInstance::CInstance(int Type)
{ {
m_pHistoryEntry = 0x0; m_pHistoryEntry = 0x0;
@ -95,6 +102,8 @@ CGameConsole::CInstance::CInstance(int Type)
m_aCompletionBuffer[0] = 0; m_aCompletionBuffer[0] = 0;
m_CompletionChosen = -1; m_CompletionChosen = -1;
m_aCompletionBufferArgument[0] = 0;
m_CompletionChosenArgument = -1;
Reset(); Reset();
m_aUser[0] = '\0'; m_aUser[0] = '\0';
@ -171,6 +180,26 @@ void CGameConsole::CInstance::PossibleCommandsCompleteCallback(int Index, const
pInstance->m_Input.Set(pStr); pInstance->m_Input.Set(pStr);
} }
void CGameConsole::CInstance::PossibleArgumentsCompleteCallback(int Index, const char *pStr, void *pUser)
{
CGameConsole::CInstance *pInstance = (CGameConsole::CInstance *)pUser;
if(pInstance->m_CompletionChosenArgument == Index)
{
// get command
char aBuf[512];
const char *pSrc = pInstance->GetString();
size_t i = 0;
for(; i < sizeof(aBuf) - 2 && pSrc[i] && pSrc[i] != ' '; i++)
aBuf[i] = pSrc[i];
aBuf[i++] = ' ';
aBuf[i] = '\0';
// append argument
str_append(aBuf, pStr, sizeof(aBuf));
pInstance->m_Input.Set(aBuf);
}
}
void CGameConsole::CInstance::OnInput(IInput::CEvent Event) void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
{ {
bool Handled = false; bool Handled = false;
@ -331,9 +360,11 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
} }
else if(Event.m_Key == KEY_TAB) else if(Event.m_Key == KEY_TAB)
{ {
const int Direction = m_pGameConsole->m_pClient->Input()->KeyIsPressed(KEY_LSHIFT) || m_pGameConsole->m_pClient->Input()->KeyIsPressed(KEY_RSHIFT) ? -1 : 1;
// command completion
if(m_Type == CGameConsole::CONSOLETYPE_LOCAL || m_pGameConsole->Client()->RconAuthed()) if(m_Type == CGameConsole::CONSOLETYPE_LOCAL || m_pGameConsole->Client()->RconAuthed())
{ {
const int Direction = m_pGameConsole->m_pClient->Input()->KeyIsPressed(KEY_LSHIFT) || m_pGameConsole->m_pClient->Input()->KeyIsPressed(KEY_RSHIFT) ? -1 : 1;
const bool UseTempCommands = m_Type == CGameConsole::CONSOLETYPE_REMOTE && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands(); const bool UseTempCommands = m_Type == CGameConsole::CONSOLETYPE_REMOTE && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands();
const int CompletionEnumerationCount = m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, UseTempCommands); const int CompletionEnumerationCount = m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, UseTempCommands);
if(CompletionEnumerationCount) if(CompletionEnumerationCount)
@ -349,6 +380,28 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
Reset(); Reset();
} }
} }
// argument completion (tuning, ...)
if(m_Type == CGameConsole::CONSOLETYPE_REMOTE && m_pGameConsole->Client()->RconAuthed())
{
const bool TuningCompletion = IsTuningCommandPrefix(GetString());
if(TuningCompletion)
{
int CompletionEnumerationCount = m_pGameConsole->m_pClient->m_aTuning[g_Config.m_ClDummy].PossibleTunings(m_aCompletionBufferArgument);
if(CompletionEnumerationCount)
{
if(m_CompletionChosenArgument == -1 && Direction < 0)
m_CompletionChosenArgument = 0;
m_CompletionChosenArgument = (m_CompletionChosenArgument + Direction + CompletionEnumerationCount) % CompletionEnumerationCount;
m_pGameConsole->m_pClient->m_aTuning[g_Config.m_ClDummy].PossibleTunings(m_aCompletionBufferArgument, PossibleArgumentsCompleteCallback, this);
}
else if(m_CompletionChosenArgument != -1)
{
m_CompletionChosenArgument = -1;
Reset();
}
}
}
} }
else if(Event.m_Key == KEY_PAGEUP) else if(Event.m_Key == KEY_PAGEUP)
{ {
@ -386,6 +439,15 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
m_CompletionChosen = -1; m_CompletionChosen = -1;
str_copy(m_aCompletionBuffer, m_Input.GetString()); str_copy(m_aCompletionBuffer, m_Input.GetString());
for(const auto *pCmd : gs_apTuningCommands)
{
if(str_startswith_nocase(m_Input.GetString(), pCmd))
{
m_CompletionChosenArgument = -1;
str_copy(m_aCompletionBufferArgument, &m_Input.GetString()[str_length(pCmd)]);
}
}
Reset(); Reset();
} }
@ -393,10 +455,10 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event)
{ {
char aBuf[sizeof(m_aCommandName)] = {0}; char aBuf[sizeof(m_aCommandName)] = {0};
const char *pSrc = GetString(); const char *pSrc = GetString();
int i = 0; size_t i = 0;
for(; i < (int)sizeof(aBuf) - 1 && *pSrc && *pSrc != ' '; i++, pSrc++) for(; i < sizeof(aBuf) - 1 && pSrc[i] && pSrc[i] != ' '; i++)
aBuf[i] = *pSrc; aBuf[i] = pSrc[i];
aBuf[i] = 0; aBuf[i] = '\0';
const IConsole::CCommandInfo *pCommand = m_pGameConsole->m_pConsole->GetCommandInfo(aBuf, m_CompletionFlagmask, const IConsole::CCommandInfo *pCommand = m_pGameConsole->m_pConsole->GetCommandInfo(aBuf, m_CompletionFlagmask,
m_Type != CGameConsole::CONSOLETYPE_LOCAL && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands()); m_Type != CGameConsole::CONSOLETYPE_LOCAL && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands());
@ -468,7 +530,7 @@ static float ConsoleScaleFunc(float t)
return sinf(acosf(1.0f - t)); return sinf(acosf(1.0f - t));
} }
struct CRenderInfo struct CCompletionOptionRenderInfo
{ {
CGameConsole *m_pSelf; CGameConsole *m_pSelf;
CTextCursor m_Cursor; CTextCursor m_Cursor;
@ -481,7 +543,7 @@ struct CRenderInfo
void CGameConsole::PossibleCommandsRenderCallback(int Index, const char *pStr, void *pUser) void CGameConsole::PossibleCommandsRenderCallback(int Index, const char *pStr, void *pUser)
{ {
CRenderInfo *pInfo = static_cast<CRenderInfo *>(pUser); CCompletionOptionRenderInfo *pInfo = static_cast<CCompletionOptionRenderInfo *>(pUser);
if(pInfo->m_EnumCount == pInfo->m_WantedCompletion) if(pInfo->m_EnumCount == pInfo->m_WantedCompletion)
{ {
@ -616,15 +678,8 @@ void CGameConsole::OnRender()
float x = 3; float x = 3;
float y = ConsoleHeight - RowHeight - 5.0f; float y = ConsoleHeight - RowHeight - 5.0f;
CRenderInfo Info; const float InitialX = x;
Info.m_pSelf = this; const float InitialY = y;
Info.m_WantedCompletion = pConsole->m_CompletionChosen;
Info.m_EnumCount = 0;
Info.m_Offset = pConsole->m_CompletionRenderOffset;
Info.m_Width = Screen.w;
Info.m_pCurrentCmd = pConsole->m_aCompletionBuffer;
TextRender()->SetCursor(&Info.m_Cursor, x + Info.m_Offset, y + RowHeight + 2.0f, FontSize, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
Info.m_Cursor.m_LineWidth = std::numeric_limits<float>::max();
// render prompt // render prompt
CTextCursor Cursor; CTextCursor Cursor;
@ -704,24 +759,40 @@ void CGameConsole::OnRender()
Input()->SetEditingPosition(Marker.m_X, Marker.m_Y + Marker.m_FontSize); Input()->SetEditingPosition(Marker.m_X, Marker.m_Y + Marker.m_FontSize);
// render possible commands // render possible commands
if(m_ConsoleType == CONSOLETYPE_LOCAL || Client()->RconAuthed()) if((m_ConsoleType == CONSOLETYPE_LOCAL || Client()->RconAuthed()) && pConsole->m_Input.GetString()[0])
{ {
if(pConsole->m_Input.GetString()[0] != 0) CCompletionOptionRenderInfo Info;
{ Info.m_pSelf = this;
m_pConsole->PossibleCommands(pConsole->m_aCompletionBuffer, pConsole->m_CompletionFlagmask, m_ConsoleType != CGameConsole::CONSOLETYPE_LOCAL && Client()->RconAuthed() && Client()->UseTempRconCommands(), PossibleCommandsRenderCallback, &Info); Info.m_WantedCompletion = pConsole->m_CompletionChosen;
pConsole->m_CompletionRenderOffset = Info.m_Offset; Info.m_EnumCount = 0;
Info.m_Offset = pConsole->m_CompletionRenderOffset;
Info.m_Width = Screen.w;
Info.m_pCurrentCmd = pConsole->m_aCompletionBuffer;
TextRender()->SetCursor(&Info.m_Cursor, InitialX + Info.m_Offset, InitialY + RowHeight + 2.0f, FontSize, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
Info.m_Cursor.m_LineWidth = std::numeric_limits<float>::max();
m_pConsole->PossibleCommands(Info.m_pCurrentCmd, pConsole->m_CompletionFlagmask, m_ConsoleType != CGameConsole::CONSOLETYPE_LOCAL && Client()->RconAuthed() && Client()->UseTempRconCommands(), PossibleCommandsRenderCallback, &Info);
pConsole->m_CompletionRenderOffset = Info.m_Offset;
if(Info.m_EnumCount <= 0) if(Info.m_EnumCount <= 0 && pConsole->m_IsCommand)
{
const bool TuningCompletion = IsTuningCommandPrefix(Info.m_pCurrentCmd);
if(TuningCompletion)
{ {
if(pConsole->m_IsCommand) Info.m_WantedCompletion = pConsole->m_CompletionChosenArgument;
{ Info.m_EnumCount = 0;
char aBuf[512]; Info.m_pCurrentCmd = pConsole->m_aCompletionBufferArgument;
str_format(aBuf, sizeof(aBuf), "Help: %s ", pConsole->m_aCommandHelp); m_pClient->m_aTuning[g_Config.m_ClDummy].PossibleTunings(Info.m_pCurrentCmd, PossibleCommandsRenderCallback, &Info);
TextRender()->TextEx(&Info.m_Cursor, aBuf, -1); pConsole->m_CompletionRenderOffset = Info.m_Offset;
TextRender()->TextColor(0.75f, 0.75f, 0.75f, 1); }
str_format(aBuf, sizeof(aBuf), "Usage: %s %s", pConsole->m_aCommandName, pConsole->m_aCommandParams);
TextRender()->TextEx(&Info.m_Cursor, aBuf, -1); if(Info.m_EnumCount <= 0 && pConsole->m_IsCommand)
} {
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "Help: %s ", pConsole->m_aCommandHelp);
TextRender()->TextEx(&Info.m_Cursor, aBuf, -1);
TextRender()->TextColor(0.75f, 0.75f, 0.75f, 1);
str_format(aBuf, sizeof(aBuf), "Usage: %s %s", pConsole->m_aCommandName, pConsole->m_aCommandParams);
TextRender()->TextEx(&Info.m_Cursor, aBuf, -1);
} }
} }
} }

View file

@ -46,6 +46,8 @@ class CGameConsole : public CComponent
char m_aCompletionBuffer[128]; char m_aCompletionBuffer[128];
int m_CompletionChosen; int m_CompletionChosen;
char m_aCompletionBufferArgument[128];
int m_CompletionChosenArgument;
int m_CompletionFlagmask; int m_CompletionFlagmask;
float m_CompletionRenderOffset; float m_CompletionRenderOffset;
@ -73,6 +75,7 @@ class CGameConsole : public CComponent
const char *GetString() const { return m_Input.GetString(); } const char *GetString() const { return m_Input.GetString(); }
static void PossibleCommandsCompleteCallback(int Index, const char *pStr, void *pUser); static void PossibleCommandsCompleteCallback(int Index, const char *pStr, void *pUser);
static void PossibleArgumentsCompleteCallback(int Index, const char *pStr, void *pUser);
}; };
class IConsole *m_pConsole; class IConsole *m_pConsole;