mirror of
https://github.com/mpv-player/mpv
synced 2025-04-24 12:24:21 +00:00
scripting: add mp.input
This lets scripts get textual input from the user using console.lua.
This commit is contained in:
parent
2dd3951a9c
commit
871f7a152a
@ -36,6 +36,7 @@ Interface changes
|
|||||||
- `--screenshot-avif-opts` defaults to lossless screenshot
|
- `--screenshot-avif-opts` defaults to lossless screenshot
|
||||||
- rename key `MP_KEY_BACK` to `MP_KEY_GO_BACK`
|
- rename key `MP_KEY_BACK` to `MP_KEY_GO_BACK`
|
||||||
- add `--sub-filter-sdh-enclosures` option
|
- add `--sub-filter-sdh-enclosures` option
|
||||||
|
- added the `mp.input` scripting API to query the user for textual input
|
||||||
--- mpv 0.37.0 ---
|
--- mpv 0.37.0 ---
|
||||||
- `--save-position-on-quit` and its associated commands now store state files
|
- `--save-position-on-quit` and its associated commands now store state files
|
||||||
in %LOCALAPPDATA% instead of %APPDATA% directory by default on Windows.
|
in %LOCALAPPDATA% instead of %APPDATA% directory by default on Windows.
|
||||||
|
@ -27,16 +27,17 @@ otherwise, the documented Lua options, script directories, loading, etc apply to
|
|||||||
JavaScript files too.
|
JavaScript files too.
|
||||||
|
|
||||||
Script initialization and lifecycle is the same as with Lua, and most of the Lua
|
Script initialization and lifecycle is the same as with Lua, and most of the Lua
|
||||||
functions at the modules ``mp``, ``mp.utils``, ``mp.msg`` and ``mp.options`` are
|
functions in the modules ``mp``, ``mp.utils``, ``mp.msg``, ``mp.options`` and
|
||||||
available to JavaScript with identical APIs - including running commands,
|
``mp.input`` are available to JavaScript with identical APIs - including running
|
||||||
getting/setting properties, registering events/key-bindings/hooks, etc.
|
commands, getting/setting properties, registering events/key-bindings/hooks,
|
||||||
|
etc.
|
||||||
|
|
||||||
Differences from Lua
|
Differences from Lua
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
No need to load modules. ``mp``, ``mp.utils``, ``mp.msg`` and ``mp.options``
|
No need to load modules. ``mp``, ``mp.utils``, ``mp.msg``, ``mp.options`` and
|
||||||
are preloaded, and you can use e.g. ``var cwd = mp.utils.getcwd();`` without
|
``mp.input`` are preloaded, and you can use e.g. ``var cwd =
|
||||||
prior setup.
|
mp.utils.getcwd();`` without prior setup.
|
||||||
|
|
||||||
Errors are slightly different. Where the Lua APIs return ``nil`` for error,
|
Errors are slightly different. Where the Lua APIs return ``nil`` for error,
|
||||||
the JavaScript ones return ``undefined``. Where Lua returns ``something, error``
|
the JavaScript ones return ``undefined``. Where Lua returns ``something, error``
|
||||||
@ -195,6 +196,16 @@ meta-paths like ``~~/foo`` (other JS file functions do expand meta paths).
|
|||||||
``mp.options.read_options(obj [, identifier [, on_update]])`` (types:
|
``mp.options.read_options(obj [, identifier [, on_update]])`` (types:
|
||||||
string/boolean/number)
|
string/boolean/number)
|
||||||
|
|
||||||
|
``mp.input.get(obj)`` (LE)
|
||||||
|
|
||||||
|
``mp.input.terminate()``
|
||||||
|
|
||||||
|
``mp.input.log(message, style)``
|
||||||
|
|
||||||
|
``mp.input.log_error(message)``
|
||||||
|
|
||||||
|
``mp.input.set_log(log)``
|
||||||
|
|
||||||
Additional utilities
|
Additional utilities
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
@ -862,6 +862,88 @@ strictly part of the guaranteed API.
|
|||||||
Turn the given value into a string. Formats tables and their contents. This
|
Turn the given value into a string. Formats tables and their contents. This
|
||||||
doesn't do anything special; it is only needed because Lua is terrible.
|
doesn't do anything special; it is only needed because Lua is terrible.
|
||||||
|
|
||||||
|
mp.input functions
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
This module lets scripts get textual input from the user using the console
|
||||||
|
REPL.
|
||||||
|
|
||||||
|
``input.get(table)``
|
||||||
|
Show the console to let the user enter text.
|
||||||
|
|
||||||
|
The following entries of ``table`` are read:
|
||||||
|
|
||||||
|
``prompt``
|
||||||
|
The string to be displayed before the input field.
|
||||||
|
|
||||||
|
``submit``
|
||||||
|
A callback invoked when the user presses Enter. The first argument is
|
||||||
|
the text in the console. You can close the console from within the
|
||||||
|
callback by calling ``input.terminate()``. If you don't, the console
|
||||||
|
stays open and the user can input more text.
|
||||||
|
|
||||||
|
``opened``
|
||||||
|
A callback invoked when the console is shown. This can be used to
|
||||||
|
present a list of options with ``input.set_log()``.
|
||||||
|
|
||||||
|
``edited``
|
||||||
|
A callback invoked when the text changes. This can be used to filter a
|
||||||
|
list of options based on what the user typed with ``input.set_log()``,
|
||||||
|
like dmenu does. The first argument is the text in the console.
|
||||||
|
|
||||||
|
``complete``
|
||||||
|
A callback invoked when the user presses TAB. 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 position from which
|
||||||
|
the completion starts. console.lua will filter the suggestions beginning
|
||||||
|
with the the text between this position and the cursor, sort them
|
||||||
|
alphabetically, insert their longest common prefix, and show them when
|
||||||
|
there are multiple ones.
|
||||||
|
|
||||||
|
``closed``
|
||||||
|
A callback invoked when the console is hidden, either because
|
||||||
|
``input.terminate()`` was invoked from the other callbacks, or because
|
||||||
|
the user closed it with a key binding. The first argument is the text in
|
||||||
|
the console, and the second argument is the cursor position.
|
||||||
|
|
||||||
|
``default_text``
|
||||||
|
A string to pre-fill the input field with.
|
||||||
|
|
||||||
|
``cursor_position``
|
||||||
|
The initial cursor position, starting from 1.
|
||||||
|
|
||||||
|
``id``
|
||||||
|
An identifier that determines which input history and log buffer to use
|
||||||
|
among the ones stored for ``input.get()`` calls. The input histories
|
||||||
|
and logs are stored in memory and do not persist across different mpv
|
||||||
|
invocations. Defaults to the calling script name with ``prompt``
|
||||||
|
appended.
|
||||||
|
|
||||||
|
``input.terminate()``
|
||||||
|
Close the console.
|
||||||
|
|
||||||
|
``input.log(message, style)``
|
||||||
|
Add a line to the log buffer. ``style`` can contain additional ASS tags to
|
||||||
|
apply to ``message``.
|
||||||
|
|
||||||
|
``input.log_error(message)``
|
||||||
|
Helper to add a line to the log buffer with the same color as the one the
|
||||||
|
console uses for errors. Useful when the user submits invalid input.
|
||||||
|
|
||||||
|
``input.set_log(log)``
|
||||||
|
Replace the entire log buffer.
|
||||||
|
|
||||||
|
``log`` is a table of strings, or tables with ``text`` and ``style`` keys.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
input.set_log({
|
||||||
|
"regular text",
|
||||||
|
{ style = "{\\c&H7a77f2&}", text = "error text" }
|
||||||
|
})
|
||||||
|
|
||||||
Events
|
Events
|
||||||
------
|
------
|
||||||
|
|
||||||
|
@ -642,6 +642,53 @@ function read_options(opts, id, on_update, conf_override) {
|
|||||||
|
|
||||||
mp.options = { read_options: read_options };
|
mp.options = { read_options: read_options };
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* input
|
||||||
|
*********************************************************************/
|
||||||
|
mp.input = {
|
||||||
|
get: function(t) {
|
||||||
|
mp.commandv("script-message-to", "console", "get-input", mp.script_name,
|
||||||
|
JSON.stringify({
|
||||||
|
prompt: t.prompt,
|
||||||
|
default_text: t.default_text,
|
||||||
|
cursor_position: t.cursor_position,
|
||||||
|
id: t.id,
|
||||||
|
}));
|
||||||
|
|
||||||
|
mp.register_script_message("input-event", function (type, text, cursor_position) {
|
||||||
|
if (t[type]) {
|
||||||
|
var result = t[type](text, cursor_position);
|
||||||
|
|
||||||
|
if (type == "complete" && result) {
|
||||||
|
mp.commandv("script-message-to", "console", "complete",
|
||||||
|
JSON.stringify(result[0]), result[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == "closed") {
|
||||||
|
mp.unregister_script_message("input-event");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
terminate: function () {
|
||||||
|
mp.commandv("script-message-to", "console", "disable");
|
||||||
|
},
|
||||||
|
log: function (message, style) {
|
||||||
|
mp.commandv("script-message-to", "console", "log",
|
||||||
|
JSON.stringify({ text: message, style: style }));
|
||||||
|
},
|
||||||
|
log_error: function (message) {
|
||||||
|
mp.commandv("script-message-to", "console", "log",
|
||||||
|
JSON.stringify({ text: message, error: true }));
|
||||||
|
},
|
||||||
|
set_log: function (log) {
|
||||||
|
mp.commandv("script-message-to", "console", "set-log",
|
||||||
|
JSON.stringify(log));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* various
|
* various
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
@ -60,6 +60,9 @@ static const char * const builtin_lua_scripts[][2] = {
|
|||||||
},
|
},
|
||||||
{"mp.assdraw",
|
{"mp.assdraw",
|
||||||
# include "player/lua/assdraw.lua.inc"
|
# include "player/lua/assdraw.lua.inc"
|
||||||
|
},
|
||||||
|
{"mp.input",
|
||||||
|
# include "player/lua/input.lua.inc"
|
||||||
},
|
},
|
||||||
{"mp.options",
|
{"mp.options",
|
||||||
# include "player/lua/options.lua.inc"
|
# include "player/lua/options.lua.inc"
|
||||||
|
@ -82,11 +82,17 @@ local insert_mode = false
|
|||||||
local pending_update = false
|
local pending_update = false
|
||||||
local line = ''
|
local line = ''
|
||||||
local cursor = 1
|
local cursor = 1
|
||||||
local history = {}
|
local default_prompt = '>'
|
||||||
|
local prompt = default_prompt
|
||||||
|
local default_id = 'default'
|
||||||
|
local id = default_id
|
||||||
|
local histories = {[id] = {}}
|
||||||
|
local history = histories[id]
|
||||||
local history_pos = 1
|
local history_pos = 1
|
||||||
local log_buffer = {}
|
local log_buffers = {[id] = {}}
|
||||||
local key_bindings = {}
|
local key_bindings = {}
|
||||||
local global_margins = { t = 0, b = 0 }
|
local global_margins = { t = 0, b = 0 }
|
||||||
|
local input_caller
|
||||||
|
|
||||||
local suggestion_buffer = {}
|
local suggestion_buffer = {}
|
||||||
local selected_suggestion_index
|
local selected_suggestion_index
|
||||||
@ -94,6 +100,8 @@ local completion_start_position
|
|||||||
local completion_append
|
local completion_append
|
||||||
local file_commands = {}
|
local file_commands = {}
|
||||||
local path_separator = platform == 'windows' and '\\' or '/'
|
local path_separator = platform == 'windows' and '\\' or '/'
|
||||||
|
local completion_old_line
|
||||||
|
local completion_old_cursor
|
||||||
|
|
||||||
local update_timer = nil
|
local update_timer = nil
|
||||||
update_timer = mp.add_periodic_timer(0.05, function()
|
update_timer = mp.add_periodic_timer(0.05, function()
|
||||||
@ -190,6 +198,7 @@ end
|
|||||||
|
|
||||||
-- Add a line to the log buffer (which is limited to 100 lines)
|
-- Add a line to the log buffer (which is limited to 100 lines)
|
||||||
function log_add(style, text)
|
function log_add(style, text)
|
||||||
|
local log_buffer = log_buffers[id]
|
||||||
log_buffer[#log_buffer + 1] = { style = style, text = text }
|
log_buffer[#log_buffer + 1] = { style = style, text = text }
|
||||||
if #log_buffer > 100 then
|
if #log_buffer > 100 then
|
||||||
table.remove(log_buffer, 1)
|
table.remove(log_buffer, 1)
|
||||||
@ -321,7 +330,7 @@ local function print_to_terminal()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local log = ''
|
local log = ''
|
||||||
for _, log_line in ipairs(log_buffer) do
|
for _, log_line in ipairs(log_buffers[id]) do
|
||||||
log = log .. log_line.text
|
log = log .. log_line.text
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -337,8 +346,9 @@ local function print_to_terminal()
|
|||||||
after_cur = ' '
|
after_cur = ' '
|
||||||
end
|
end
|
||||||
|
|
||||||
mp.osd_message(log .. suggestions .. '> ' .. before_cur .. '\027[7m' ..
|
mp.osd_message(log .. suggestions .. prompt .. ' ' .. before_cur ..
|
||||||
after_cur:sub(1, 1) .. '\027[0m' .. after_cur:sub(2), 999)
|
'\027[7m' .. after_cur:sub(1, 1) .. '\027[0m' ..
|
||||||
|
after_cur:sub(2), 999)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Render the REPL and console as an ASS OSD
|
-- Render the REPL and console as an ASS OSD
|
||||||
@ -407,6 +417,7 @@ function update()
|
|||||||
local suggestion_ass = style .. styles.suggestion .. suggestions
|
local suggestion_ass = style .. styles.suggestion .. suggestions
|
||||||
|
|
||||||
local log_ass = ''
|
local log_ass = ''
|
||||||
|
local log_buffer = log_buffers[id]
|
||||||
local log_messages = #log_buffer
|
local log_messages = #log_buffer
|
||||||
local log_max_lines = math.max(0, lines_max - rows)
|
local log_max_lines = math.max(0, lines_max - rows)
|
||||||
if log_max_lines < log_messages then
|
if log_max_lines < log_messages then
|
||||||
@ -423,7 +434,7 @@ function update()
|
|||||||
if #suggestions > 0 then
|
if #suggestions > 0 then
|
||||||
ass:append(suggestion_ass .. '\\N')
|
ass:append(suggestion_ass .. '\\N')
|
||||||
end
|
end
|
||||||
ass:append(style .. '> ' .. before_cur)
|
ass:append(style .. ass_escape(prompt) .. ' ' .. before_cur)
|
||||||
ass:append(cglyph)
|
ass:append(cglyph)
|
||||||
ass:append(style .. after_cur)
|
ass:append(style .. after_cur)
|
||||||
|
|
||||||
@ -432,7 +443,7 @@ function update()
|
|||||||
ass:new_event()
|
ass:new_event()
|
||||||
ass:an(1)
|
ass:an(1)
|
||||||
ass:pos(2, screeny - 2 - global_margins.b * screeny)
|
ass:pos(2, screeny - 2 - global_margins.b * screeny)
|
||||||
ass:append(style .. '{\\alpha&HFF&}> ' .. before_cur)
|
ass:append(style .. '{\\alpha&HFF&}' .. ass_escape(prompt) .. ' ' .. before_cur)
|
||||||
ass:append(cglyph)
|
ass:append(cglyph)
|
||||||
ass:append(style .. '{\\alpha&HFF&}' .. after_cur)
|
ass:append(style .. '{\\alpha&HFF&}' .. after_cur)
|
||||||
|
|
||||||
@ -446,12 +457,28 @@ function set_active(active)
|
|||||||
repl_active = true
|
repl_active = true
|
||||||
insert_mode = false
|
insert_mode = false
|
||||||
mp.enable_key_bindings('console-input', 'allow-hide-cursor+allow-vo-dragging')
|
mp.enable_key_bindings('console-input', 'allow-hide-cursor+allow-vo-dragging')
|
||||||
mp.enable_messages('terminal-default')
|
|
||||||
define_key_bindings()
|
define_key_bindings()
|
||||||
|
|
||||||
|
if not input_caller then
|
||||||
|
prompt = default_prompt
|
||||||
|
id = default_id
|
||||||
|
history = histories[id]
|
||||||
|
history_pos = #history + 1
|
||||||
|
mp.enable_messages('terminal-default')
|
||||||
|
end
|
||||||
else
|
else
|
||||||
repl_active = false
|
repl_active = false
|
||||||
|
suggestion_buffer = {}
|
||||||
undefine_key_bindings()
|
undefine_key_bindings()
|
||||||
mp.enable_messages('silent:terminal-default')
|
mp.enable_messages('silent:terminal-default')
|
||||||
|
|
||||||
|
if input_caller then
|
||||||
|
mp.commandv('script-message-to', input_caller, 'input-event',
|
||||||
|
'closed', line, cursor)
|
||||||
|
input_caller = nil
|
||||||
|
line = ''
|
||||||
|
cursor = 1
|
||||||
|
end
|
||||||
collectgarbage()
|
collectgarbage()
|
||||||
end
|
end
|
||||||
update()
|
update()
|
||||||
@ -513,6 +540,16 @@ function len_utf8(str)
|
|||||||
return len
|
return len
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function handle_edit()
|
||||||
|
suggestion_buffer = {}
|
||||||
|
update()
|
||||||
|
|
||||||
|
if input_caller then
|
||||||
|
mp.commandv('script-message-to', input_caller, 'input-event', 'edited',
|
||||||
|
line)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Insert a character at the current cursor position (any_unicode)
|
-- Insert a character at the current cursor position (any_unicode)
|
||||||
function handle_char_input(c)
|
function handle_char_input(c)
|
||||||
if insert_mode then
|
if insert_mode then
|
||||||
@ -521,8 +558,7 @@ function handle_char_input(c)
|
|||||||
line = line:sub(1, cursor - 1) .. c .. line:sub(cursor)
|
line = line:sub(1, cursor - 1) .. c .. line:sub(cursor)
|
||||||
end
|
end
|
||||||
cursor = cursor + #c
|
cursor = cursor + #c
|
||||||
suggestion_buffer = {}
|
handle_edit()
|
||||||
update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Remove the character behind the cursor (Backspace)
|
-- Remove the character behind the cursor (Backspace)
|
||||||
@ -531,16 +567,14 @@ function handle_backspace()
|
|||||||
local prev = prev_utf8(line, cursor)
|
local prev = prev_utf8(line, cursor)
|
||||||
line = line:sub(1, prev - 1) .. line:sub(cursor)
|
line = line:sub(1, prev - 1) .. line:sub(cursor)
|
||||||
cursor = prev
|
cursor = prev
|
||||||
suggestion_buffer = {}
|
handle_edit()
|
||||||
update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Remove the character in front of the cursor (Del)
|
-- Remove the character in front of the cursor (Del)
|
||||||
function handle_del()
|
function handle_del()
|
||||||
if cursor > line:len() then return end
|
if cursor > line:len() then return end
|
||||||
line = line:sub(1, cursor - 1) .. line:sub(next_utf8(line, cursor))
|
line = line:sub(1, cursor - 1) .. line:sub(next_utf8(line, cursor))
|
||||||
suggestion_buffer = {}
|
handle_edit()
|
||||||
update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Toggle insert mode (Ins)
|
-- Toggle insert mode (Ins)
|
||||||
@ -568,8 +602,7 @@ function clear()
|
|||||||
cursor = 1
|
cursor = 1
|
||||||
insert_mode = false
|
insert_mode = false
|
||||||
history_pos = #history + 1
|
history_pos = #history + 1
|
||||||
suggestion_buffer = {}
|
handle_edit()
|
||||||
update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Close the REPL if the current line is empty, otherwise delete the next
|
-- Close the REPL if the current line is empty, otherwise delete the next
|
||||||
@ -642,13 +675,17 @@ end
|
|||||||
|
|
||||||
-- Run the current command and clear the line (Enter)
|
-- Run the current command and clear the line (Enter)
|
||||||
function handle_enter()
|
function handle_enter()
|
||||||
if line == '' then
|
if line == '' and input_caller == nil then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if history[#history] ~= line then
|
if history[#history] ~= line and line ~= '' then
|
||||||
history_add(line)
|
history_add(line)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if input_caller then
|
||||||
|
mp.commandv('script-message-to', input_caller, 'input-event', 'submit',
|
||||||
|
line)
|
||||||
|
else
|
||||||
-- match "help [<text>]", return <text> or "", strip all whitespace
|
-- match "help [<text>]", return <text> or "", strip all whitespace
|
||||||
local help = line:match('^%s*help%s+(.-)%s*$') or
|
local help = line:match('^%s*help%s+(.-)%s*$') or
|
||||||
(line:match('^%s*help$') and '')
|
(line:match('^%s*help$') and '')
|
||||||
@ -657,6 +694,7 @@ function handle_enter()
|
|||||||
else
|
else
|
||||||
mp.command(line)
|
mp.command(line)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
clear()
|
clear()
|
||||||
end
|
end
|
||||||
@ -1025,6 +1063,14 @@ function complete(backwards)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if input_caller then
|
||||||
|
completion_old_line = line
|
||||||
|
completion_old_cursor = cursor
|
||||||
|
mp.commandv('script-message-to', input_caller, 'input-event',
|
||||||
|
'complete', line:sub(1, cursor - 1))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local before_cur = line:sub(1, cursor - 1)
|
local before_cur = line:sub(1, cursor - 1)
|
||||||
local after_cur = line:sub(cursor)
|
local after_cur = line:sub(cursor)
|
||||||
|
|
||||||
@ -1111,8 +1157,7 @@ function del_word()
|
|||||||
before_cur = before_cur:gsub('[^%s]+%s*$', '', 1)
|
before_cur = before_cur:gsub('[^%s]+%s*$', '', 1)
|
||||||
line = before_cur .. after_cur
|
line = before_cur .. after_cur
|
||||||
cursor = before_cur:len() + 1
|
cursor = before_cur:len() + 1
|
||||||
suggestion_buffer = {}
|
handle_edit()
|
||||||
update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Delete from the cursor to the end of the word (Ctrl+Del)
|
-- Delete from the cursor to the end of the word (Ctrl+Del)
|
||||||
@ -1124,28 +1169,25 @@ function del_next_word()
|
|||||||
|
|
||||||
after_cur = after_cur:gsub('^%s*[^%s]+', '', 1)
|
after_cur = after_cur:gsub('^%s*[^%s]+', '', 1)
|
||||||
line = before_cur .. after_cur
|
line = before_cur .. after_cur
|
||||||
suggestion_buffer = {}
|
handle_edit()
|
||||||
update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Delete from the cursor to the end of the line (Ctrl+K)
|
-- Delete from the cursor to the end of the line (Ctrl+K)
|
||||||
function del_to_eol()
|
function del_to_eol()
|
||||||
line = line:sub(1, cursor - 1)
|
line = line:sub(1, cursor - 1)
|
||||||
suggestion_buffer = {}
|
handle_edit()
|
||||||
update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Delete from the cursor back to the start of the line (Ctrl+U)
|
-- Delete from the cursor back to the start of the line (Ctrl+U)
|
||||||
function del_to_start()
|
function del_to_start()
|
||||||
line = line:sub(cursor)
|
line = line:sub(cursor)
|
||||||
cursor = 1
|
cursor = 1
|
||||||
suggestion_buffer = {}
|
handle_edit()
|
||||||
update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Empty the log buffer of all messages (Ctrl+L)
|
-- Empty the log buffer of all messages (Ctrl+L)
|
||||||
function clear_log_buffer()
|
function clear_log_buffer()
|
||||||
log_buffer = {}
|
log_buffers[id] = {}
|
||||||
update()
|
update()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1212,8 +1254,7 @@ function paste(clip)
|
|||||||
local after_cur = line:sub(cursor)
|
local after_cur = line:sub(cursor)
|
||||||
line = before_cur .. text .. after_cur
|
line = before_cur .. text .. after_cur
|
||||||
cursor = cursor + text:len()
|
cursor = cursor + text:len()
|
||||||
suggestion_buffer = {}
|
handle_edit()
|
||||||
update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- List of input bindings. This is a weird mashup between common GUI text-input
|
-- List of input bindings. This is a weird mashup between common GUI text-input
|
||||||
@ -1318,11 +1359,95 @@ mp.add_key_binding(nil, 'enable', function()
|
|||||||
set_active(true)
|
set_active(true)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
mp.register_script_message('disable', function()
|
||||||
|
set_active(false)
|
||||||
|
end)
|
||||||
|
|
||||||
-- Add a script-message to show the REPL and fill it with the provided text
|
-- Add a script-message to show the REPL and fill it with the provided text
|
||||||
mp.register_script_message('type', function(text, cursor_pos)
|
mp.register_script_message('type', function(text, cursor_pos)
|
||||||
show_and_type(text, cursor_pos)
|
show_and_type(text, cursor_pos)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
mp.register_script_message('get-input', function (script_name, args)
|
||||||
|
if repl_active then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
input_caller = script_name
|
||||||
|
args = utils.parse_json(args)
|
||||||
|
prompt = args.prompt or default_prompt
|
||||||
|
line = args.default_text or ''
|
||||||
|
cursor = tonumber(args.cursor_position) or line:len() + 1
|
||||||
|
id = args.id or script_name .. prompt
|
||||||
|
if histories[id] == nil then
|
||||||
|
histories[id] = {}
|
||||||
|
log_buffers[id] = {}
|
||||||
|
end
|
||||||
|
history = histories[id]
|
||||||
|
history_pos = #history + 1
|
||||||
|
|
||||||
|
set_active(true)
|
||||||
|
mp.commandv('script-message-to', input_caller, 'input-event', 'opened')
|
||||||
|
end)
|
||||||
|
|
||||||
|
mp.register_script_message('log', function (message)
|
||||||
|
-- input.get's edited handler is invoked after submit, so avoid modifying
|
||||||
|
-- the default log.
|
||||||
|
if input_caller == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
message = utils.parse_json(message)
|
||||||
|
|
||||||
|
log_add(message.error and styles.error or message.style or '',
|
||||||
|
message.text .. '\n')
|
||||||
|
end)
|
||||||
|
|
||||||
|
mp.register_script_message('set-log', function (log)
|
||||||
|
if input_caller == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
log = utils.parse_json(log)
|
||||||
|
log_buffers[id] = {}
|
||||||
|
|
||||||
|
for i = 1, #log do
|
||||||
|
if type(log[i]) == 'table' then
|
||||||
|
log[i].text = log[i].text .. '\n'
|
||||||
|
log_buffers[id][i] = log[i]
|
||||||
|
else
|
||||||
|
log_buffers[id][i] = {
|
||||||
|
style = '',
|
||||||
|
text = log[i] .. '\n',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
update()
|
||||||
|
end)
|
||||||
|
|
||||||
|
mp.register_script_message('complete', function(list, start_pos)
|
||||||
|
if line ~= completion_old_line or cursor ~= completion_old_cursor then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local completions, prefix = complete_match(line:sub(start_pos, cursor),
|
||||||
|
utils.parse_json(list))
|
||||||
|
local before_cur = line:sub(1, start_pos - 1) .. prefix
|
||||||
|
local after_cur = line:sub(cursor)
|
||||||
|
cursor = before_cur:len() + 1
|
||||||
|
line = before_cur .. after_cur
|
||||||
|
|
||||||
|
if #completions > 1 then
|
||||||
|
suggestion_buffer = completions
|
||||||
|
selected_suggestion_index = 0
|
||||||
|
completion_start_position = start_pos
|
||||||
|
completion_append = ''
|
||||||
|
end
|
||||||
|
|
||||||
|
update()
|
||||||
|
end)
|
||||||
|
|
||||||
-- Redraw the REPL when the OSD size changes. This is needed because the
|
-- Redraw the REPL when the OSD size changes. This is needed because the
|
||||||
-- PlayRes of the OSD will need to be adjusted.
|
-- PlayRes of the OSD will need to be adjusted.
|
||||||
mp.observe_property('osd-width', 'native', update)
|
mp.observe_property('osd-width', 'native', update)
|
||||||
|
66
player/lua/input.lua
Normal file
66
player/lua/input.lua
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
--[[
|
||||||
|
This file is part of mpv.
|
||||||
|
|
||||||
|
mpv is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
mpv is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
]]
|
||||||
|
|
||||||
|
local utils = require "mp.utils"
|
||||||
|
local input = {}
|
||||||
|
|
||||||
|
function input.get(t)
|
||||||
|
mp.commandv("script-message-to", "console", "get-input",
|
||||||
|
mp.get_script_name(), utils.format_json({
|
||||||
|
prompt = t.prompt,
|
||||||
|
default_text = t.default_text,
|
||||||
|
cursor_position = t.cursor_position,
|
||||||
|
id = t.id,
|
||||||
|
}))
|
||||||
|
|
||||||
|
mp.register_script_message("input-event", function (type, text, cursor_position)
|
||||||
|
if t[type] then
|
||||||
|
local suggestions, completion_start_position = t[type](text, cursor_position)
|
||||||
|
|
||||||
|
if type == "complete" and suggestions then
|
||||||
|
mp.commandv("script-message-to", "console", "complete",
|
||||||
|
utils.format_json(suggestions), completion_start_position)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if type == "closed" then
|
||||||
|
mp.unregister_script_message("input-event")
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.terminate()
|
||||||
|
mp.commandv("script-message-to", "console", "disable")
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.log(message, style)
|
||||||
|
mp.commandv("script-message-to", "console", "log",
|
||||||
|
utils.format_json({ text = message, style = style }))
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.log_error(message)
|
||||||
|
mp.commandv("script-message-to", "console", "log",
|
||||||
|
utils.format_json({ text = message, error = true }))
|
||||||
|
end
|
||||||
|
|
||||||
|
function input.set_log(log)
|
||||||
|
mp.commandv("script-message-to", "console", "set-log", utils.format_json(log))
|
||||||
|
end
|
||||||
|
|
||||||
|
return input
|
@ -1,5 +1,6 @@
|
|||||||
lua_files = ['defaults.lua', 'assdraw.lua', 'options.lua', 'osc.lua',
|
lua_files = ['defaults.lua', 'assdraw.lua', 'options.lua', 'osc.lua',
|
||||||
'ytdl_hook.lua', 'stats.lua', 'console.lua', 'auto_profiles.lua']
|
'ytdl_hook.lua', 'stats.lua', 'console.lua', 'auto_profiles.lua',
|
||||||
|
'input.lua']
|
||||||
foreach file: lua_files
|
foreach file: lua_files
|
||||||
lua_file = custom_target(file,
|
lua_file = custom_target(file,
|
||||||
input: join_paths(source_root, 'player', 'lua', file),
|
input: join_paths(source_root, 'player', 'lua', file),
|
||||||
|
Loading…
Reference in New Issue
Block a user