From c72f2add2598e6aedc11fb0bebe12f73c53b1a1f Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Wed, 18 Feb 2026 17:38:27 +1030 Subject: [PATCH] mp.input: allow async completions Previously, it was impossible to generate a list of completions for an `input.get()` request asynchronously, as the values had to be returned by the callback function. This commit provides a way to send completions asynchronously by passing a second argument to the complete callback; a function which can be passed the return values to respond to the complete event. --- DOCS/man/lua.rst | 17 ++++++++++++----- player/javascript/defaults.js | 29 ++++++++++++++++++----------- player/lua/input.lua | 24 ++++++++++++++++-------- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/DOCS/man/lua.rst b/DOCS/man/lua.rst index 631ffd97c8..79ebb3dfc7 100644 --- a/DOCS/man/lua.rst +++ b/DOCS/man/lua.rst @@ -946,14 +946,21 @@ REPL. ``complete`` A callback invoked when the user edits the text or moves the cursor. The - first argument is the text before the cursor. The callback should return - a table of the string candidate completion values and the 1-based cursor + first argument is the text before the cursor, and the second argument is + a response function which can be called to present completion values to + the user. + + The first argument to the response function is a table of the string + candidate completion values, and the second argument is the 1-based cursor position from which the completion starts. console will show the completions that fuzzily match the text between this position and the - cursor and allow selecting them. + cursor, which the user can select with ``TAB``. The completions will only + be shown to the user if the text before the cursor has not since changed. + The response function should be called with an empty table if there are no + completion values to display. - The third and optional return value is a string that will be appended to - the input line without displaying it in the completions. + The third and optional argument to the response function is a string that + will be appended to the input line without displaying it in the completions. ``autoselect_completion`` Whether to automatically select the first completion on submit if one diff --git a/player/javascript/defaults.js b/player/javascript/defaults.js index cd8d1a9ef9..0d1c520ed1 100644 --- a/player/javascript/defaults.js +++ b/player/javascript/defaults.js @@ -662,26 +662,33 @@ function register_event_handler(t) { latest_handler_id = handler_id; mp.register_script_message(handler_id, function (type, args) { - if (latest_handler_id !== handler_id && type !== "closed") + if (type == "closed") + mp.unregister_script_message(handler_id); + + if (!t[type] || (latest_handler_id !== handler_id && type !== "closed")) return; - if (t[type]) { - args = args ? JSON.parse(args) : []; - var result = t[type].apply(null, args); + args = args ? JSON.parse(args) : []; + + if (type == "complete") { + var complete = function(completions, completion_pos, completion_append) { + if (completions == undefined) + return; - if (type == "complete" && result) { mp.commandv("script-message-to", "console", "complete", JSON.stringify({ client_name: mp.script_name, handler_id: handler_id, - list: result[0], - start_pos: result[1], - append: result[2] || "", + list: completions, + start_pos: completion_pos, + append: completion_append || "", })); } - } - if (type == "closed") - mp.unregister_script_message(handler_id); + args[1] = complete; + complete.apply(null, t[type].apply(null, args)); + } else { + t[type].apply(null, args) + } }) return handler_id; diff --git a/player/lua/input.lua b/player/lua/input.lua index 06fa7dfc0f..eb93fbb7b5 100644 --- a/player/lua/input.lua +++ b/player/lua/input.lua @@ -40,16 +40,23 @@ local function register_event_handler(t) latest_handler_id = handler_id mp.register_script_message(handler_id, function (type, args) + if type == "closed" then + mp.unregister_script_message(handler_id) + end + -- do not process events (other than closed) for an input that has been overwritten - if latest_handler_id ~= handler_id and type ~= "closed" then + if not t[type] or (latest_handler_id ~= handler_id and type ~= "closed") then return end - if t[type] then - local completions, completion_pos, completion_append = - t[type](unpack(utils.parse_json(args or "") or {})) + args = utils.parse_json(args or "") or {} + + if type == "complete" then + local function complete(completions, completion_pos, completion_append) + if not completions then + return + end - if type == "complete" and completions then mp.commandv("script-message-to", "console", "complete", utils.format_json({ client_name = mp.get_script_name(), handler_id = handler_id, @@ -58,10 +65,11 @@ local function register_event_handler(t) append = completion_append or "", })) end - end - if type == "closed" then - mp.unregister_script_message(handler_id) + args[2] = complete + complete(t[type](unpack(args))) + else + t[type](unpack(args)) end end)