Learn cvar and command names from the server for autocomplete

Send cvarlist and cmdlist on connect and merge the answer into the
autocomplete candidates. Number the server menu from 0, keep suggesting
sibling commands while the command name is typed, mask the password in
the startup line, ignore venv/, fix README claims.
This commit is contained in:
pfl
2026-09-16 18:25:48 +02:00
parent db123993c0
commit 3d1dc19d9b
6 changed files with 227 additions and 60 deletions
+35 -4
View File
@@ -40,6 +40,14 @@ GAME_CVARS = [
'g_quadHog',
'g_training',
'g_instagib',
'g_password',
'g_needpass',
'g_overtime',
'g_startingHealth',
'g_startingArmor',
'g_infiniteAmmo',
'g_loadout',
'sv_privatePassword',
]
# Map and rotation
@@ -92,6 +100,8 @@ QLX_CVARS = [
'qlx_serverBrandName',
'qlx_owner',
'qlx_redditAuth',
'qlx_plugins',
'qlx_pluginsPath',
]
# Bot cvars
@@ -151,9 +161,21 @@ COMMANDS = [
'scores',
# Info commands
'serverinfo',
'systeminfo',
'players',
'maplist',
'configstrings',
'cvarlist',
'cmdlist',
'dumpuser',
# Console
'exec',
'set',
'seta',
'sets',
'echo',
'clientkick',
'cp',
]
# Bot names for addbot command (complete list)
@@ -271,6 +293,9 @@ COMMAND_SIGNATURES = {
'sv_maxclients': '<1-64>',
'sv_hostname': '<name>',
'sv_fps': '<20|30|40|60|125>',
'g_password': '<password>',
'g_needpass': '<0|1>',
'sv_privatePassword': '<password>',
# Network
'net_port': '<port number>',
@@ -527,12 +552,18 @@ def fuzzy_match(query, candidates, max_results=5):
return [match for match, score in matches[:max_results]]
def autocomplete(partial, max_results=5):
def autocomplete(partial, learned_names=(), max_results=5):
"""
Autocomplete a partial cvar/command
Returns list of suggestions
Autocomplete a partial cvar/command name.
Candidates are the built-in lists plus the names learned from the server
(see lib/namelist.py); a learned name that is already built in is skipped.
"""
return fuzzy_match(partial, ALL_CVARS, max_results)
candidates = list(ALL_CVARS)
builtin_lower = {name.lower() for name in ALL_CVARS}
for name in sorted(learned_names):
if name.lower() not in builtin_lower:
candidates.append(name)
return fuzzy_match(partial, candidates, max_results)
def parse_signature(signature):