-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
scripting: add mp.input #10282
scripting: add mp.input #10282
Conversation
I'm a big dummy. What does this actually do? Prompt users for textual input? |
Yes, scripts can let the user type textual input and process it. I wrote 4 scripts with it if you want some use cases:
Your own The original motivation for this was letting users search for keybindings they type in the stats keybinding page. |
Thanks, yeah that makes sense. I just wanted to make sure I had the correct idea in my mind. |
Forgive me if I'm wrong, but it seems like you would not be able to create more than a single input in each script since the response script-message is hard-coded. Might it not be more powerful (and more expected) if each call to I've created a similar but less powerful script that does something similar (mpv-user-input), so I'm curious how you're handling some of these problems. |
|
The purpose wasn't really for a single script to queue calls, it was to prevent multiple different scripts from interfering with each other. The idea being if a script makes an input request the user will be given the chance to answer, no matter what. I figured it would simplify things for script writers to have that guarantee. The queue code is very messy though, that whole script of mine is in need of a rewrite. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that any script can at any point in time just close the console or write to the log buffer while a different script is currently getting user input makes me wonder if there should be some sort of verification. But in practice that may not actually be a problem,
A queue like @CogentRedTester suggested seems like a good idea. Something simple like "if console currently open, add a table with parameters to queue." and then whenever the console gets closed have a "if something in queue, take first entry and run the get-input function with it" should work just fine.
Otherwise this looks good.
That whole "script gives suggestions to user and then processes input" thing sounds like it would pair well with the completion suggestions from my PR #10316.
It would require a few modifications to be well suited for that use case (option to keep displaying the suggestions until the user hits enter and option to choose between displaying as list or table), but that would prevent the log buffer from being spammed with completions (even if they are specific to that id) and they would be presented in a more readable manner.
It is intentional to allow everything to close the console to allow keybindings like
I think that you will normally call
I think you're confusing TAB completion with dmenu emulation. With dmenu you only care about the first entry to see which one matches what you typed, and the entries completely change on every character you type. |
You're right, I was thinking of TAB completion because the way I understood it was that when the user presses TAB, console sends a |
It does, but with "script gives suggestions to user and then processes input" it sounded like you were talking about the script I mentioned to select a playlist entry like with dmenu/autocompletion, as complete event handlers don't process anything after returning the suggestions. When there are multiple suggestions they are added to the log, no other PR is necessary for that. To clear the previous completions I just call |
This PR inspired me to do some much needed refactoring of my user-input script. I have come up with a much simpler queue implementation which can be seen in CogentRedTester/mpv-user-input#6. If you do decide to go in that direction you are free to use that approach. |
@guidocella: would you mind dusting this one off with a rebase and bringing it back up to date? I think this is a good feature, and I want to finally actually review it. Just a couple of points:
|
21d2129
to
81a3d1f
Compare
I had already updated this to use |
Oh and just in case you aren't already making this assumption, it's OK to error out if there's no actual mpv window (no idea if console magically handles that already or not). |
The console actually accepts input just fine without any mpv window. I specifically programmed my |
Oh nice, I didn't even know that. |
I don't think the queue commit is useful. It would become unclear (to the user) what's the destination of the next input. Is it a console command? input for some script which requested it while it was open? A previous script which expected one or more inputs? etc. There's only so much you can do when a singleton user-facing things is attempted to be used by more than one thing. I think the previous behavior where it errors (possibly with some indication of which error, possibly including an explicit identifiable case for "console in use") was better. This way the script can display some message like "Console is currently in use". |
I think that the prompt that each |
It's not only a "what's the destination" issue. It's a UX issue. Think about scenarios where this could happen, and then think whether such behavior does best for the user. Really, do try to list such scnarios. To me, the typical case of a script requesting user input in a prompt is in response to some user trigger, such pressing Now, let's assume the console is already open for some other script. Here's how we could get here: The user forgot it's already open, did their trigger and typed something and enter - which now went to the wrong script. Or they did see it's open, but thought their new trigger will now take over - and it didn't. They most certainly did not expect that the current new trigger will "kick in" only once the current console closes. It's just not how UI works. UI needs immediacy. User-trigger -> something happens right away (e.g. console opens and waits for input). I just can't think of scenarios where a "open console" queue (by two different scripts) would be useful. So it's additional code and complexity and potential bugs for no value that I can identify. |
Ignore my bad ideas. |
d279c68
to
e27c18a
Compare
What? log: function (message, style) {
mp.commandv("script-message-to", "console", "log", message, style || "");
},
log_error: function (message) {
mp.commandv("script-message-to", "console", "log", message, "", "");
}, what does log_error do, exactly? Looks like it does exactly like log when style is not provided? EDIT: unless the final empty argument is an indication that this is an error message? really? |
How do you want to indicate that it's an error message if you can't poss booleans with script-message? Make a new script-message? I based it on |
You can make the whole message argument a single JSON string of whatever sub-values you need. Or just drop the error API and let the user use style however they want. |
I restored the JSON, but users are can already use any style they want by calling the regular |
9e49311
to
68fe7a7
Compare
68fe7a7
to
c01a58e
Compare
Having two separate modes of operation is really not complex, even if we manage to reconcile the differences between console.lua and mp.input all this would buy us is moving some code to a different file and not having to manually restore the default prompt/id/history for the regular console operation. If desired, this can be done later. Complicating this PR that has been stalled for 2 years (if we include the months I worked on it before the opening a PR) further is suicide.
In pratice there is no reason to disable the console,
Fair enough, I will add them.
The difference is aesthetical, and console.lua also has logic not to reinsert the
No? Tab completion appends text, it doesn't replace it.
I lean more towards removing this, as closing the console without running a command and having it there when you re-open it can be annoying. But indeed this is easily replicated by adding the default text and cursor arguments.
Yes, unless you manually clear them. I did list example usages in the third comment of the PR. The log can be used as
Correct.
It doesn't. |
fc9823d
to
799b259
Compare
Added Edit: I also published guidocella/mpv-lrc@0179fd5 |
799b259
to
2d84f3a
Compare
Yes, we are on the same page. You may be right that it's too much for this PR, but I think it's worth keeping in mind for the future.
Oh sorry, seems I misunderstood how the tab completion works.
Good, that's what I was hoping. Now from what I understand of the code, the log buffers are unique to each id, however the If so, I think this is somewhat dangerous, all it takes is one script sending a log while another script is open to pollute the whole buffer. It also means you can't add a log while the input is closed. My immediate though about how to replicate While thinking about this issue I came up with a slightly different interface for the I was inspired by the -- This function creates a new input handler table.
-- All this function actually does is generate a new unique id, add it as a field to the table,
-- and add some methods to the table.
local repl = input.create_input_handler({
prompt = '> ',
opened = function() end,
edited = function() end,
submit = function() end,
complete = function() end,
default_text = '',
cursor_position = 1
})
-- This just calls the current `input.add_input` function using the options passed to `create_input_handler`.
-- If a table is passed to the function then fields from it will override the fields passed to `create_input_handler`,
-- this allows things like the default text or cursor position to be modified while maintaining the same histories/log/etc.
repl:activate({default_text = 'default', cursor_position = 3})
-- sends the log commands to `console.lua` along with the id of the created input.
repl:log(...)
repl:set_log({}) It's pretty simple, just a thin wrapper around the commands you've already got, but I think it makes things a little easier to reason about and removes the need for the script writer to handle IDs. It also opens the door in the future to store other things in the table, such as a I would be interested to hear your thoughts. |
2d84f3a
to
be9aeb5
Compare
You are only supposed to call
Changing the default text or cursor position already maintains the history and log. If you want to define default arguments and then change them, you can just store the default arguments in a variable and change some of them on each call without having to separate
These should be called in the
There is already nothing stopping us from adding variables to the |
be9aeb5
to
edac0dc
Compare
df528fd
to
89f5d0e
Compare
It's not yet merged (mpv-player/mpv#10282), but I used it for 2 years and got annoyed of using separate branches. If mp.input is not available, it downloads the first entry whose album matches like before.
89f5d0e
to
a8ca6be
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did only a little bit of testing but it worked just fine. The code additions overall look fine and it's actually not even that much considering the feature that's being added. We can always iron out some more things later as people start actually using it. Sorry for the huge delay on this one.
This lets scripts get textual input from the user using console.lua.
a8ca6be
to
1bfee4d
Compare
I added back the interface change, I removed that after a while because it continously caused conflicts. Any bikeshedding on the names before merging maybe as we can't just change them later? opened/closed can also be activated/deactivated or shown/hidden or enabled/disabled. |
I'm personally fine with the names as they are. |
Let's finally get this in. |
I misunderstood CogentRedTester's review in mpv-player#10282 (comment) 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) local sub = mp.get_property_native("track-list/" .. sub_indexes[tonumber(id)]) ... end, This commit avoids having to call tonumber(id).
I misunderstood CogentRedTester's review in mpv-player#10282 (comment) 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).
I misunderstood CogentRedTester's review in mpv-player#10282 (comment) 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).
I misunderstood CogentRedTester's review in mpv-player#10282 (comment) 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).
I misunderstood CogentRedTester's review in mpv-player#10282 (comment) 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).
I misunderstood CogentRedTester's review in mpv-player#10282 (comment) 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).
I misunderstood CogentRedTester's review in mpv-player#10282 (comment) 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).
I misunderstood CogentRedTester's review in #10282 (comment) 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 lets scripts get textual input from the user using console.lua.