This commit should remove any unexpected behaviour or crashes
that
may be caused by users passing unexpected values to mp.input functions.
String and numerical options are now explicitly converted to strings and
numbers. Values which should be tables are set to empty tables, and
warning messages are printed to inform the user.
Previously, completion responses from the same client would be displayed
even if the user had since changed the input, as long as a newer
complete event had already been sent. This meant that, if clients took a
sufficiently long time to return completions, then
console.lua would display completions for previous versions of the line
which were no longer valid.
This commit has the client send back the version of the line their
completions apply to, ensuring that `console.lua` displays the
correct 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.
This was a mistake. It's too situational and it's not worth complicating
the API and every mp.input client with it. It made some sense before I
implemented input.select() because you could use input.get() to input a
choice and validate it, but in general for input.get() clients it's
better to show an error with input.set_log() instead of adding new lines
to the log everytime. This is what e.g.
https://framagit.org/Midgard/mpv-subber/-/blob/master/subber.lua does.
So this is only marginally useful for REPL scripts that keep adding
lines to the log, and the only such scripts are commands.lua and my
lua-repl.lua. commands.lua never used it and I already removed it from
lua-repl.lua. Cloning all scripts in the wiki reveals that **nobody** is
using log_error(), confirming that it is safe to deprecate.
This commit modifies the log methods in mp.input to always send the id
of the latest `input.get()` request with log entries.
Previously, the log methods applied to whichever input request happened
to be open when the log message was received. Even when scripts used
these methods correctly, there was the risk of sending a log to the
wrong log buffer if the active input request changed while the log
message was in transit; a race condition.
Now the id of the latest `input.get()` request is sent alongside the log
messages, preventing data races between scripts while also preventing
those logs from being discarded.
It was previously possible for completion messages to be received by a
new input request, if one was created while the message was in transit.
Since it is trivial to avoid this by passing the script name and
existing handle_id value, we may as well do so and guarantee that there
will not be any data races.
This commit ensures that `input.terminate()` can only close input
requests made by the same script, and prevents any in-transit events
for old input requests from being processed.
Previously, there was no way to guarantee that the input request being
terminated was the one intended; the asynchronous nature of the API
meant that it was always possible (though unlikely) that another client
may have activated its own input request while the termination request
was in transit.
This commit removes the race condition between different scripts calling
`input.terminate()` by sending the script name alongside the termination
message.
In addition, when a script overwrites one of its own input requests,
there may be incoming events still in transit. Some of these events may
have a decent chance of calling `input.terminate()` if they are
processed (e.g., `submit`). This commit avoids this issue by only
processing `closed` requests once a new `input.get()` request is made.
This makes changes to mp.input and console.lua so that every input.get
request uses a unique script-message to handle input events.
Previously, making new input.get requests shortly after the termination
of a previous request made by the same script could cause a race
condition where the input handler was closed but the new request
was still being drawn in the UI. This was caused by the `closed` event
for the previous request being received only after the new request was
registered, hence closing the event handler for the new request instead.
In addition, this commit makes the behaviour of calling input.get while
another request is active more consistent. When a new request is
received it overwrites the in-progress request, sending a `closed`
event. However, previously, the `closed` event could not be sent if both
requests came from the same script, as the new request would have
overwritten the event handler. Now, the `closed` event is called
regardless of where the new request comes from.
Currently --osd-font is the default for select, and a monospace font is
the default for free-form text mode. We can also default to the
proportional --osd-font for mp.input.get clients that don't specify
completions and thus don't need alignment, which is most clients.
In builtin scripts, this is the case for filtering stats key bindings.
Let the complete callback return the character to append to the selected
completion.
I didn't want to document this because it's specifically meant for
properties and unlikely to be needed by other scripts, but silently
interpreting the 3rd return value can screw you over if you do something
like
return candidates, code:find('[%w_]*$')
I was doing this in my lua-repl script, and find() returns the end
position as the 2rd argument, this becomes the 3rd return value and gets
appended to completions. So you have to do
return candidates, code:find('[%w_]*$'), nil
Needed to split running commands out of console.lua.
Partially revert bede44618b. This was removed to allow nested
input.select() calls, but it is better to use the new keep_open flag for
this, because it avoids the flicker of console quickly closing and
reopening.
Unregistering the script message allows garbage collection of variables
defined in the scope that called mp.input, this is useful e.g. if you
were selecting from 10k history entries.
Currently using mp.input while the console is open doesn't do anything.
We can allow using mp.input multiple times in a row by keeping the
console open, and sending a closed event only when the previous calling
script is different from the current one. If it is the same, sending a
closed event would unregister the new input-event listener, so it is
just never sent in this case as there is no sane way to do it. This is
useful e.g. to try out select script bindings in the console, or to
switch to a different mp.input script binding with a key binding without
having to close the current one.
Calling input.select() again within input.select()'s submit handler
needs to be fixed separately because with select the console is
immediately closed on submit (367a6b561a), so input.lua receives submit,
requests a new selection, and receives closed wich unregisters the
handler of the new selection. Just not calling
mp.unregister_script_message("input-event") fixes it; its only purpose
was to allow garbage collection of variables defined in the scope using
mp.input.
Fixes#15795.
Pass everything in the tables passed by mp.input callers to console.lua
so new flags can be added without modifying these clients.
In Lua, callbacks have to be excluded from the argument tables to not
make utils.format_json() error, while with JSON.stringify they are
automatically omitted.
I misunderstood CogentRedTester's review in
https://github.com/mpv-player/mpv/pull/10282#discussion_r1428972352 as
referring to the cursor_position in mp.input's arguments instead of the
one received by the closed callback.
The cursor_position passed to input.get doesn't need to be converted to
a number because it was already JSON, while the cursor_position received
by the closed callback is currently a string, and we need to pass JSON
in input-event script messages to keep it as an integer to work around
mpv converting integer script message arguments to string.
This is more noticeable after implementing mp.input.select(): its submit
argument currently receives the selected index as a string, and this
makes Lua error if you use it as an index of a numerical table, e.g.:
submit = function (id)
mp.set_property(property, tracks[tonumber(id)].selected and "no"
or tracks[tonumber(id)].id)
...
end,
This commit avoids having to call tonumber(id).
This allows scripts to make the user choose from a list of entries by
typing part of their text and/or by navigating them with keybindings,
like dmenu or fzf.
Closes#13964.
When running the console in the terminal, style log lines with the same
escape sequences as msg.c.
mp.input can also specify terminal escape sequences, e.g. a script to
select a playlist entry can invert the color of the selection.
Also add a missing newline to help's error message.
This property was never encouraged. The manual even stated that "You
should avoid using it, unless you absolutely have to." Since we now have
user-data which is superior in every single way and replaces this,
delete this property. The manual also has threatened people for years
with the line "It's a makeshift solution which could go away any time
(for example, when a better solution becomes available)." We were nice
and deprecated it in 1d00aee8e1 for a
while to give script authors some time to update. Let's remove it for
good now.
This only existed as essentially a workaround for meson's behavior and
to maintain compatibility with the waf build. Since waf put everything
in a generated subdirectory, we had to put make a subdirectory called
"generated" in the source for meson so stuff could go to the right
place. Well now we don't need to do that anymore. Move the meson.build
files around so they go in the appropriate place in the subdirectory of
the source tree and change the paths of the headers accordingly. A
couple of important things to note.
1. mpv.com now gets made in build/player/mpv.com (necessary because of
a meson limitation)
2. The macos icon generation path is shortened to
TOOLS/osxbundle/icon.icns.inc.
This reverts:
3fb4140c lua/defaults: add user_data helpers
68a20e7a javascript/defaults: add user_data helpers
00510379 lua/js: fix user_data_del util function
As well as the lua/js parts of:
3ec2a098 docs: document new user-data property
user-data and its sub-properties can be set/get/observed/deleted
via the standard properties interface, so there's no need for
additional helpers specific to user-data, which only added maintenance
burden.
Commit 7f4841ff sorted the bindings so that if the same key was bound
more than once, then the newest binding takes priority (sorted last).
However, it got the comparison function wrong, which means the result
of the sort depended on the algorithm and not on the actual data, so
the priority for keys with more than one binding was still arbitraty.
Fix the sort function, and finally ensure that later binding acutally
override earlier bindings of the same key.
When utils.get_user_path was added, the expand-path command didn't
exist. Now it does, so remove the C code, make it a trivial wrapper.
Keep this function for backward compat to not break scripts, but
technically it's not required anymore.
The problem with the previous code - which used mp.get_user_path, is
that it returns a path even with --no-config, and even if the file
doesn't exist.
This is why we tested the "config" property, and also used
mp.utils.file_info to check that the file exists.
mp.find_config_file doesn't return a path with no-cofig and doesn't
return a path if the file doesn't exists. It's simpler and better.
mpv doesn't have other dot files in its config dir, and it also
shouldn't be "invisible".
The new name ~~/init.js now replaces ~~/.init.js
While mpv usually deprecates things before outright removing them,
in this case the old (dot) name is replaced without deprecation:
- It's a bad idea to execute hidden scripts, even if at a config dir,
and we don't want to do that for the next release cycle too.
- We warn if the old (dot) name exists and the new name doesn't,
which should be reasonably visible for affected users.
- It's likely niche enough to not cause too much pain.
If for some reason both names are needed, e.g. when using also an old
mpv versions, then the old name could be symlinked to the new one, or
simply have one line: `require("~~/init")` to load the new name, while
a new mpv version will load (only) the new name without warning.
The custom init script should be considered a configuration file, and
as such it should be ignored when the user wants vanilla mpv - and now
it is ignored with --no-config.
Previously, loading ~~/.init.js was inside a try block, in order to
quietly ignore errors if the file doesn't exist.
However, that also prevented any real errors from showing up even when
the file does exist, and the script continued as if everything is OK,
while in fact the custom init script didn't complete correctly.
Now we first check if the file exists, and then load it without
try/catch, so that any error shows up normally (and abort the script).
Previously, if a script bound the same key more than once to different
functions (without removing the older bindings first), then pressing
the key triggered any of the bound functions arbitrarily[1].
Now the newest binding for the same key is always the active one.
If the newest binding is then removed - the second-newest will become
active, etc. (same mechanism as before, except that the active key
was not always the newest).
[1] The order was implementation-defined, however `for (name in obj)'
happens to iterate. With mujs that's currently alhabetic order,
and name is from mp.add_[forced_]key_binding(key, name...)
or generated internally if name is not provided. So a binding with
higher alphabetic `name' value had priority over lower name value.
The idle-observers block has at least 3 function calls, and it was
entered every time the script went into idle, however, we can save these
calls by checking first that there are indeed such observers.
We now have at least 3 scripting APIs which are trivial wrappers
around properties: mp.get_mouse_pos, utils.getcwd, utils.getpid.
After some discussion on IRC it was decided that it's easier for us to
maintain them as trivial wrappers than to deprecate them and inflict
pain on users and script authors, so currently no plan to deprecate.
mp.get_mouse_pos() is undocumented and is no longer required - the
property can be used officially by any client now, however, osc.lua
uses it, and also some user scripts learnt to rely on it, so we keep
it - as a trivial wrapper around the new mouse-pos property.
The callback now gets an object argument with defer/cont functions.
Like the lua code, the behavior is that each hook event allows at
most one continue, but nothing enforces the order of continuations
if more hook events arrive before prior ones were continued - which
is possible now with the defer option, but wasn't possible before
(continuation was synchronous from the hook event handler).
Until now the 'update' method used mp.command_native with a hardcoded
list of key names.
Change it to use whatever keys the user set to this object, so that
we can remain oblivious to new keys which 'osd-overlay' may support.
This is how the lua code did it from the begining. We didn't, and now
we pay the price.
Note: could be implemented either as we have now (clone `this`
excluding the methods) or by moving the methods up the prototype chain
(i.e. class methods) so they don't get enumerated and use `this` as
the command object itself.
However, in the latter approach we'll have to save the values which we
change (name, res_x, res_y) and restore them after the command, so it's
simpler to just clone `this`.
Directories inside ~~/scripts/ are now loaded as scripts, so don't use
it also for modules. Now there are no default module paths.
To compensate, we now try to run ~~/.init.js right after defaults.js,
so the user may extend the js init procedure via this script, e.g. for
adding default paths to mp.module_paths .
This matches lua's 11b9315b but with the lagacy field names which the
js code used previously.
Currently the property always returns an object (with dummy/last/null
field values if there are no dimensions), but the code is ready for
a future case where it might return null if there are no dimensions - at
which case it will forward the null, breaking backward compatibility for
a better API.