From 95cf201f4ce2eb76a7b4fadbc454079405755c38 Mon Sep 17 00:00:00 2001 From: Levi Neely <141506390+lneely@users.noreply.github.com> Date: Sat, 1 Aug 2026 13:07:43 +0200 Subject: [PATCH] remove inline autocomplete state machine from prompt input --- gui/main.qml | 190 +-------------------------------------------------- 1 file changed, 2 insertions(+), 188 deletions(-) diff --git a/gui/main.qml b/gui/main.qml index 30b7b04..de0a730 100644 --- a/gui/main.qml +++ b/gui/main.qml @@ -80,95 +80,6 @@ ApplicationWindow { { name: "help", desc: "Show help" } ] - // --- Inline autocomplete state machine --- - // States: none -> start -> autocompleting -> done (tab/esc/no-match) - property string _acBase: "" // text before the slash command (includes "/") - property string _acTyped: "" // what user typed after / - property var _acMatches: [] // matching options - property bool _acActive: false // in autocomplete mode - property int _acMatchIndex: 0 // which match is currently shown - property string _acType: "cmd" // "cmd", "model", or "backend" - - function acFindMatches(prefix, type) { - if (type === "model") { - var models = ollie.getAvailableModels(ollie.currentBackend || "") - var m = [] - for (var i = 0; i < models.length; ++i) { - if (models[i].toLowerCase().indexOf(prefix.toLowerCase()) >= 0) - m.push(models[i]) - } - return m - } else if (type === "backend") { - var bks = ollie.availableBackends - var m = [] - for (var j = 0; j < bks.length; ++j) { - if (bks[j].toLowerCase().indexOf(prefix.toLowerCase()) >= 0) - m.push(bks[j]) - } - return m - } else { - var m = [] - for (var k = 0; k < root.slashCommands.length; ++k) { - if (root.slashCommands[k].name.indexOf(prefix) >= 0) - m.push(root.slashCommands[k].name) - } - return m - } - } - - function acLCP(arr) { - if (arr.length === 0) return "" - if (arr.length === 1) return arr[0] - var lcp = arr[0] - for (var i = 1; i < arr.length; ++i) { - while (!arr[i].startsWith(lcp)) { - lcp = lcp.substring(0, lcp.length - 1) - if (lcp === "") return "" - } - } - return lcp - } - - function acEnter(prefix, type) { - _acActive = true - _acTyped = prefix - _acMatches = acFindMatches(prefix, type) - _acMatchIndex = 0 - if (_acMatches.length > 0) { - var lcp = acLCP(_acMatches) - if (lcp.length > prefix.length) { - promptInput.text = _acBase + lcp - promptInput.cursorPosition = promptInput.text.length - } - } else { - // No options — transition to done immediately - _acActive = false - _acBase = "" - _acTyped = "" - _acMatches = [] - } - } - - function acCycle() { - if (!_acActive || _acMatches.length <= 1) return - _acMatchIndex = (_acMatchIndex + 1) % _acMatches.length - var parts = promptInput.text.substring(promptInput.text.lastIndexOf("/") + 1).split(" ") - parts[0] = _acMatches[_acMatchIndex] - promptInput.text = _acBase + "/" + parts.join(" ") - promptInput.cursorPosition = promptInput.text.length - } - - function acCancel() { - if (!_acActive) return - promptInput.text = _acBase + _acTyped - promptInput.cursorPosition = promptInput.text.length - _acActive = false - _acBase = "" - _acTyped = "" - _acMatches = [] - } - - // Deferred scroll timer — fires once after model changes settle Timer { id: scrollTimer @@ -850,105 +761,8 @@ ApplicationWindow { property int _lastCursorPos: 0 onTextChanged: { - var oldText = _lastText - var newText = text - var cursorPos = cursorPosition - - // Check if we just completed a command name and added a space - if (_acActive && _acMatches.length > 0) { - var afterSlash = newText.substring(newText.lastIndexOf("/") + 1) - var parts = afterSlash.split(" ") - // If first part matches a known command exactly and there's a second part - if (parts.length >= 2) { - var cmdName = parts[0].toLowerCase() - if (cmdName === "model") { - // Switch to model arg completion — update base to include command - _acBase = newText.substring(0, newText.lastIndexOf("/") + 1) + parts[0] + " " - acEnter(parts.slice(1).join(" "), "model") - return - } else if (cmdName === "backend") { - // Switch to backend arg completion - _acBase = newText.substring(0, newText.lastIndexOf("/") + 1) + parts[0] + " " - acEnter(parts.slice(1).join(" "), "backend") - return - } - } - } - - if (!_acActive && newText.indexOf("/") >= 0) { - var slashPos = newText.lastIndexOf("/") - if (slashPos < cursorPos) { - var prefix = newText.substring(slashPos + 1, cursorPos) - if (prefix.length > 0 && prefix !== " ") { - _acBase = newText.substring(0, slashPos + 1) - acEnter(prefix, "cmd") - } - } - } else if (_acActive) { - // User is typing inside autocomplete — re-enter with updated prefix - var slashPos = newText.lastIndexOf("/") - var prefix = newText.substring(slashPos + 1, cursorPos) - if (prefix.length > 0 && prefix !== " ") { - _acBase = newText.substring(0, slashPos + 1) - acEnter(prefix, _acType) - } else { - acCancel() - } - } else if (newText.indexOf("/") < 0) { - // No slash at all — cancel any lingering state - acCancel() - } - - _lastText = newText - _lastCursorPos = cursorPos - } - - onCursorPositionChanged: { - if (!_acActive && text.indexOf("/") >= 0) { - var slashPos = text.lastIndexOf("/") - if (slashPos < cursorPosition) { - var prefix = text.substring(slashPos + 1, cursorPosition) - if (prefix.length > 0 && prefix !== " ") { - _acBase = text.substring(0, slashPos + 1) - acEnter(prefix, "cmd") - } - } - } else if (_acActive) { - var slashPos = text.lastIndexOf("/") - var prefix = text.substring(slashPos + 1, cursorPosition) - if (prefix.length > 0 && prefix !== " ") { - _acBase = text.substring(0, slashPos + 1) - acEnter(prefix, _acType) - } else { - acCancel() - } - } - } - - Keys.onPressed: function(event) { - if (_acActive) { - if (event.key === Qt.Key_Tab) { - acCycle() - event.accepted = true - } else if (event.key === Qt.Key_Escape) { - acCancel() - event.accepted = true - } else if (event.key === Qt.Key_Down) { - if (_acMatches.length > 1) { - acCycle() - event.accepted = true - } - } else if (event.key === Qt.Key_Up) { - if (_acMatches.length > 1) { - _acMatchIndex = (_acMatchIndex - 1 + _acMatches.length) % _acMatches.length - var parts = text.substring(text.lastIndexOf("/") + 1).split(" ") - parts[0] = _acMatches[_acMatchIndex] - text = _acBase + "/" + parts.join(" ") - cursorPosition = text.length - event.accepted = true - } - } - } + _lastText = text + _lastCursorPos = cursorPosition } Keys.onReturnPressed: function(event) {