Implemented basic Tab-autocompletion for agent console.

This commit is contained in:
Jakob Friedl
2025-10-03 09:59:50 +02:00
parent 56153b3441
commit ae09e4e7e3
3 changed files with 68 additions and 3 deletions

View File

@@ -4,5 +4,5 @@
--opt:size
--passL:"-s" # Strip symbols, such as sensitive function names
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
-d:MODULES="12"
-d:MODULES="255"
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"

View File

@@ -60,6 +60,9 @@ proc Console*(agent: UIAgent): ConsoleComponent =
#[
Text input callback function for managing console history and autocompletion
]#
var currentCompletionIndex: int = -1
var lastMatches: seq[string] = @[]
proc callback(data: ptr ImGuiInputTextCallbackData): cint {.cdecl.} =
let component = cast[ConsoleComponent](data.UserData)
@@ -108,8 +111,61 @@ proc callback(data: ptr ImGuiInputTextCallbackData): cint {.cdecl.} =
return 0
of ImGui_InputTextFlags_CallbackCompletion.int32:
# Handle Tab-autocompletion
discard
# Handle Tab-autocompletion for agent commands
let commands = getCommands(component.agent.modules).mapIt(it.name & " ") & @["help "]
# Get the word to complete
let inputEndPos = data.CursorPos
var inputStartPos = inputEndPos
while inputStartPos > 0:
let c = cast[ptr UncheckedArray[char]](data.Buf)[inputStartPos - 1]
if c in [' ', '\t', ',', ';']:
break
dec inputStartPos
let inputLen = inputEndPos - inputStartPos
var currentWord = newString(inputLen)
for i in 0..<inputLen:
currentWord[i] = cast[ptr UncheckedArray[char]](data.Buf)[inputStartPos + i]
# Check for matches
var matches: seq[string] = @[]
for cmd in commands:
if cmd.toLowerAscii().startsWith(currentWord.toLowerAscii()):
matches.add(cmd)
# No matching commands found
if matches.len() == 0:
return 0
elif matches.len() == 1:
data.ImGuiInputTextCallbackData_DeleteChars(inputStartPos.cint, inputLen.cint)
data.ImGuiInputTextCallbackData_InsertChars(data.CursorPos, matches[0].cstring, nil)
# More than 1 matching command -> complete common prefix
else:
var prefixLen = inputLen
while prefixLen < matches[0].len():
let c = matches[0][prefixLen]
var allMatch = true
for i in 1 ..< matches.len():
if prefixLen >= matches[i].len() or matches[i][prefixLen] != c:
allMatch = false
break
if not allMatch:
break
inc prefixLen
if prefixLen > inputLen:
data.ImGuiInputTextCallbackData_DeleteChars(inputStartPos.cint, inputLen.cint)
data.ImGuiInputTextCallbackData_InsertChars(data.CursorPos, matches[0][0..<prefixLen].cstring, nil)
return 0
else: discard

View File

@@ -82,3 +82,12 @@ proc getModules*(modules: uint32 = 0): seq[Module] =
for m in manager.modules:
if (modules and cast[uint32](m.moduleType)) == cast[uint32](m.moduleType):
result.add(m)
proc getCommands*(modules: uint32 = 0): seq[Command] =
if modules == 0:
for m in manager.modules:
result.add(m.commands)
else:
for m in manager.modules:
if (modules and cast[uint32](m.moduleType)) == cast[uint32](m.moduleType):
result.add(m.commands)