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
Add completions for mkvextract #3492
Conversation
Is that just a spurious error? I can't make sense of the message
|
@occivink: Yes, we've been having some trouble with travis lately. That test has nothing to do with your changes. Just ignore it for now. |
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -s V -l "version" -d "Show version information" | ||
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -s h -l "help" -d "Show help" | ||
# commands | ||
complete -f -c mkvextract -n "test (count (commandline -opc)) -lt 2" -a "tracks" -d "Extract tracks to external files" |
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.
Most of the time, commands support options also before subcommands, i.e. something like mkvextract --parse-fully tags
would also work. If that is the case here, just counting the number of tokens would break.
Can you confirm if it is?
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.
I can confirm it doesn't accept options before subcommands.
@@ -0,0 +1,47 @@ | |||
# Sample output of 'mkvmerge -i file.mkv' |
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.
Thank you for this.
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.
Well, thank you for working on fish.
# Chapters: 7 entires | ||
|
||
function __fish_print_mkvextract_attachments | ||
mkvmerge -i $argv | string match 'Attachment ID*' | string replace -r '.*?(\d+).*? type \'(.*?)\'.*?file name \'(.*?)\'' '$1:\t$3 ($2)' |
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.
If I'm reading this correctly, the completion itself has a trailing ":". Is that correct? Is "1:" really the expected argument?
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.
Yes, how it works is you actually specify
mkvextract tracks file.mkv 2:audio.aac 3:subtitles.ass
And the files audio.aac and subtitles.ass will be created. The name of the output file is up to the user, the completion only proposes available streams.
It's actually rather convenient that it doesn't automatically add a space if the completion ends in :
but that's not configurable, right? I would need that with completions ending in =
to make useful dynamic ones for mkvpropedit
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 3" -r -l "output-charset" -d "Outputs messages in specified charset" | ||
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 3" -r -s r -l "redirect-output" -d "Redirect all messages into a file" | ||
# command-specific options | ||
complete -f -c mkvextract -n "test (count (commandline -opc)) -ge 3; and contains -- (commandline -opc)[2] tracks" -r -s c -d "Convert text subtitles to a charset" |
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.
We'd usually write this test as __fish_seen_subcommand_from tracks
- that will also skip all options.
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.
I'll fix that
Somewhat offtopic, but do you know if |
Okay I realized that generic options can be specified before the mkv file (contrary to what the help says), which breaks the assumption made by: Tangentially, do you know of some non-trivial completions that are well implemented and that I could draw inspiration from? |
You don't want "actually a file". You want "a non-option after the command".
Our biggest and possibly best completion script is the one for git, and it does this: function __fish_git_needs_command
set cmd (commandline -opc)
if [ (count $cmd) -eq 1 ]
return 0
else
set -l skip_next 1
# Skip first word because it's "git" or a wrapper
for c in $cmd[2..-1]
test $skip_next -eq 0
and set skip_next 1
and continue
# git can only take a few options before a command, these are the ones mentioned in the "git" man page
# e.g. `git --follow log` is wrong, `git --help log` is okay (and `git --help log $branch` is superfluous but works)
# In case any other option is used before a command, we'll fail, but that's okay since it's invalid anyway
switch $c
# General options that can still take a command
case "--help" "-p" "--paginate" "--no-pager" "--bare" "--no-replace-objects" --{literal,glob,noglob,icase}-pathspecs --{exec-path,git-dir,work-tree,namespace}"=*"
continue
# General options with an argument we need to skip. The option=value versions have already been handled above
case --{exec-path,git-dir,work-tree,namespace}
set skip_next 0
continue
# General options that cause git to do something and exit - these behave like commands and everything after them is ignored
case "--version" --{html,man,info}-path
return 1
# We assume that any other token that's not an argument to a general option is a command
case "*"
echo $c
return 1
end
end
return 0
end
return 1
end to determine if a command has been given. As you can see, this also handles options that take arguments ( |
Okay that should fix all edge cases I was aware of. For example, I do
but it'd be nicer to just use the return code of the command. I couldn't find how to do that though. |
set -l matroska (__fish_mkvextract_find_matroska_in_args)
if test $status -eq 0 or even if set -l matroska (__fish_mkvextract_find_matroska_in_args) (of course, if you'd like to use it later, you'll need to save it to another variable) |
function __fish_print_mkvextract_attachments | ||
mkvmerge -i $argv | string match 'Attachment ID*' | string replace -r '.*?(\d+).*? type \'(.*?)\'.*?file name \'(.*?)\'' '$1:\t$3 ($2)' | ||
function __fish_mkvextract_find_matroska_in_args | ||
for c in (commandline -opc)[2..-1] |
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.
Of note is that this will fail if there is no second token (because of our annoying habit of failing invalid array indices).
This doesn't occur here because this is only ever called if there is already a subcommand, so there's no pressing need to change it.
Yet another question, it seems like paths starting with |
@occivink: Don't. We need a helper function to do that, because a few completions currently try via |
Okay thanks, I thought that there might have been a function to do that. |
@@ -8,7 +8,11 @@ | |||
# Chapters: 7 entires | |||
|
|||
function __fish_mkvextract_find_matroska_in_args | |||
for c in (commandline -opc)[2..-1] | |||
set -l cmd (commandline -opc) | |||
if test (count $cmd) -lt 3 |
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.
if not set -q cmd[3]
mkvmerge -i $matroska | string match 'Attachment ID*' | string replace -r '.*?(\d+).*? type \'(.*?)\'.*?file name \'(.*?)\'' '$1:\t$3 ($2)' | ||
if set -l matroska (__fish_mkvextract_find_matroska_in_args) | ||
if set -l info (mkvmerge -i $matroska) | ||
string match 'Attachment ID*' $info | string replace -r '.*?(\d+).*? type \'(.*?)\'.*?file name \'(.*?)\'' '$1:\t$3 ($2)' |
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.
Ideally, you'd guard the "$info" from being interpreted as options: string match 'Attachment ID*' -- $info
. Otherwise if a line is e.g. -r
, string will go into regex mode.
mkvmerge -i $matroska | string match 'Track ID*' | string replace -r '.*?(\d+): (.*)' '$1:\t$2' | ||
if set -l matroska (__fish_mkvextract_find_matroska_in_args) | ||
if set -l info (mkvmerge -i $matroska) | ||
string match 'Track ID*' $info | string replace -r '.*?(\d+): (.*)' '$1:\t$2' |
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.
Same.
Happy to comply, thanks for the tips. |
@occivink: Are you done here? |
Yes I am. |
Merged, thanks! |
Thanks for all the feedback. |
Mostly useful for the dynamic tracks and attachments completions.
Much like mkvextract, mkvmerge is part of mkvtoolnix so it should be okay to rely on it for completions.
I only did mkvextract because the others are much more complicated to provide useful completions for, but I might try to do them in the future.