From 002a6ed15ba128b3999b3e12f519b4434587032f Mon Sep 17 00:00:00 2001 From: Jabber Developer Date: Thu, 30 Apr 2026 23:10:14 +0000 Subject: [PATCH] refactor(ai): flatten autocomplete into sequential prefix-matching chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the deeply nested conditional tree in _ai_autocomplete() with a flat sequential chain of autocomplete_param_with_*() calls. Each call tries a specific command prefix (e.g., "/ai set provider", "/ai start") and returns immediately on match — a common, reliable pattern for command-line tab completion. The previous design nested provider-name autocomplete inside g_strv_length() and g_strcmp0() checks, meaning /ai and /ai would never reach the subcommand matcher. The new flat structure ensures every prefix is tried in order, with the most specific prefixes first and the generic /ai subcommand fallback last. This pattern — sequential prefix matching with early return — is the standard approach for autocomplete dispatch: each handler owns its prefix, no shared state or argument parsing is needed, and adding a new subcommand is a single append to the chain. --- src/command/cmd_ac.c | 129 ++++++++++++++++++------------------------- 1 file changed, 53 insertions(+), 76 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 5c3b7486..6db15c90 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -4445,84 +4445,61 @@ static char* _ai_autocomplete(ProfWin* window, const char* const input, gboolean previous) { char* result = NULL; - gboolean parsed = FALSE; - auto_gcharv gchar** args = parse_args(input, 0, 3, &parsed); - - if (parsed) { - int num_args = g_strv_length(args); - - /* Top-level /ai autocomplete (e.g., /ai s -> /ai set) */ - if (num_args >= 1) { - if (g_strcmp0(args[0], "set") == 0) { - if (num_args >= 2) { - if (g_strcmp0(args[1], "provider") == 0) { - // /ai set provider - autocomplete provider names - result = autocomplete_param_with_func(input, "/ai set provider", ai_providers_find, previous, NULL); - if (result) { - return result; - } - } else if (g_strcmp0(args[1], "token") == 0) { - // /ai set token - autocomplete provider names - result = autocomplete_param_with_func(input, "/ai set token", ai_providers_find, previous, NULL); - if (result) { - return result; - } - } else if (g_strcmp0(args[1], "org") == 0) { - // /ai set org - autocomplete provider names - result = autocomplete_param_with_func(input, "/ai set org", ai_providers_find, previous, NULL); - if (result) { - return result; - } - } - } - // /ai set - autocomplete subcommands - result = autocomplete_param_with_ac(input, "/ai set", ai_set_subcommands_ac, TRUE, previous); - if (result) { - return result; - } - } else if (g_strcmp0(args[0], "remove") == 0) { - if (num_args >= 2 && g_strcmp0(args[1], "provider") == 0) { - // /ai remove provider - autocomplete provider names - result = autocomplete_param_with_func(input, "/ai remove provider", ai_providers_find, previous, NULL); - if (result) { - return result; - } - } else { - result = autocomplete_param_with_ac(input, "/ai remove", ai_remove_subcommands_ac, TRUE, previous); - if (result) { - return result; - } - } - } else if (g_strcmp0(args[0], "start") == 0) { - // /ai start [/] - autocomplete provider names - result = autocomplete_param_with_func(input, "/ai start", ai_providers_find, previous, NULL); - if (result) { - return result; - } - } else if (g_strcmp0(args[0], "clear") == 0) { - // /ai clear [] - autocomplete provider names - result = autocomplete_param_with_func(input, "/ai clear", ai_providers_find, previous, NULL); - if (result) { - return result; - } - } else if (g_strcmp0(args[0], "correct") == 0) { - // /ai correct - result = autocomplete_param_with_func(input, "/ai correct", ai_providers_find, previous, NULL); - if (result) { - return result; - } - } else if (g_strcmp0(args[0], "providers") == 0) { - // /ai providers - no subcommands - return NULL; - } - } - - result = autocomplete_param_with_ac(input, "/ai", ai_subcommands_ac, FALSE, previous); - if (result) { - return result; - } + /* Top-level /ai autocomplete (e.g., /ai s -> /ai set) */ + result = autocomplete_param_with_func(input, "/ai set provider", ai_providers_find, previous, NULL); + if (result) { + return result; } + // /ai set token - autocomplete provider names + result = autocomplete_param_with_func(input, "/ai set token", ai_providers_find, previous, NULL); + if (result) { + return result; + } + + // /ai set org - autocomplete provider names + result = autocomplete_param_with_func(input, "/ai set org", ai_providers_find, previous, NULL); + if (result) { + return result; + } + + // /ai set - autocomplete subcommands + result = autocomplete_param_with_ac(input, "/ai set", ai_set_subcommands_ac, TRUE, previous); + if (result) { + return result; + } + + // /ai remove provider - autocomplete provider names + result = autocomplete_param_with_func(input, "/ai remove provider", ai_providers_find, previous, NULL); + if (result) { + return result; + } + + result = autocomplete_param_with_ac(input, "/ai remove", ai_remove_subcommands_ac, TRUE, previous); + if (result) { + return result; + } + + // /ai start [/] - autocomplete provider names + result = autocomplete_param_with_func(input, "/ai start", ai_providers_find, previous, NULL); + if (result) { + return result; + } + + // /ai clear [] - autocomplete provider names + result = autocomplete_param_with_func(input, "/ai clear", ai_providers_find, previous, NULL); + if (result) { + return result; + } + + // /ai correct + result = autocomplete_param_with_func(input, "/ai correct", ai_providers_find, previous, NULL); + if (result) { + return result; + } + + result = autocomplete_param_with_ac(input, "/ai", ai_subcommands_ac, FALSE, previous); + return result; } \ No newline at end of file