WIP -- add simple bash completion support (#3131)
* add simple bash completion support * add "completions" subdir to meson * start extending completion to extra args * file complete for every arg after 1 * add completion for enums, file, ints, doubles * docs, try to improve directory completion though dir completion is not working correctly, I'm not sure why
This commit is contained in:
parent
7f352b3c9e
commit
e24cee4e22
@ -18,6 +18,7 @@ master
|
||||
- threadpools size dynamically with load
|
||||
- operations can hint threadpool size
|
||||
- support for N-colour ICC profiles
|
||||
- add bash completions for "vips"
|
||||
- fits load and allows many more bands
|
||||
- fits write doesn't duplicate header fields
|
||||
- add @wrap to vips_text()
|
||||
|
@ -83,6 +83,8 @@ libvips must have `build-essential`, `pkg-config`, `libglib2.0-dev`,
|
||||
`libexpat1-dev`. See the **Dependencies** section below for a full list
|
||||
of the libvips optional dependencies.
|
||||
|
||||
There are basic bash completions in `completions/`, see the README in there.
|
||||
|
||||
## Cheatsheet
|
||||
|
||||
```
|
||||
|
28
completions/README.md
Normal file
28
completions/README.md
Normal file
@ -0,0 +1,28 @@
|
||||
# Shell completions for vips
|
||||
|
||||
Basic shell completions for the `vips` program. Internally, these use the
|
||||
`-c` argument to `vips` to list argument options.
|
||||
|
||||
## Example
|
||||
|
||||
```
|
||||
$ vips relational<TAB>
|
||||
relational relational_const
|
||||
$ vips relational_const ~/pics/k2.<TAB>
|
||||
~/pics/k2.avif ~/pics/k2.hdr ~/pics/k2.pdf ~/pics/k2.tif
|
||||
~/pics/k2.bmp ~/pics/k2.heic ~/pics/k2.pfm ~/pics/k2.v
|
||||
~/pics/k2.csv ~/pics/k2.jp2 ~/pics/k2.pgm ~/pics/k2.vips
|
||||
~/pics/k2.fits ~/pics/k2.jpg ~/pics/k2.png ~/pics/k2.webp
|
||||
~/pics/k2.flif ~/pics/k2.jxl ~/pics/k2.ppm
|
||||
~/pics/k2.gif ~/pics/k2.pbm ~/pics/k2.ppt
|
||||
$ vips relational_const ~/pics/k2.jpg x.v less<TAB>
|
||||
less lesseq
|
||||
$ vips relational_const ~/pics/k2.jpg x.v lesseq 12
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
### `vips-completion.bash`
|
||||
|
||||
Usually copy to `/etc/bash_completion.d` to install, but it depends on your
|
||||
system.
|
43
completions/vips-completion.bash
Normal file
43
completions/vips-completion.bash
Normal file
@ -0,0 +1,43 @@
|
||||
#/usr/bin/env bash
|
||||
|
||||
# bash completions for the "vips" command
|
||||
|
||||
# copy to /etc/bash_completion.d to install
|
||||
|
||||
_vips_compgen_f()
|
||||
{
|
||||
COMPREPLY=($(compgen -f -- "${COMP_WORDS[-1]}"))
|
||||
|
||||
if [ ${#COMPREPLY[@]} = 1 ]; then
|
||||
local LASTCHAR=' '
|
||||
if [ -d "$COMPREPLY" ]; then
|
||||
LASTCHAR=/
|
||||
fi
|
||||
|
||||
COMPREPLY=$(printf %q%s "$COMPREPLY" "$LASTCHAR")
|
||||
else
|
||||
for ((i=0; i < ${#COMPREPLY[@]}; i++)); do
|
||||
if [ -d "${COMPREPLY[$i]}" ]; then
|
||||
COMPREPLY[$i]=${COMPREPLY[$i]}/
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
_vips_completions()
|
||||
{
|
||||
if [ ${#COMP_WORDS[@]} == "2" ]; then
|
||||
COMPREPLY=($(compgen -W "$(vips -c)" "${COMP_WORDS[1]}"))
|
||||
else
|
||||
local args=($(vips -c ${COMP_WORDS[1]}))
|
||||
local arg_type=${args[${#COMP_WORDS[@]}-3]}
|
||||
if [ $arg_type == "file" ]; then
|
||||
_vips_compgen_f
|
||||
elif [[ $arg_type = word:* ]]; then
|
||||
local options=$(echo $arg_type | sed 's/word://' | sed 's/|/ /g')
|
||||
COMPREPLY=($(compgen -W "${options[@]}" "${COMP_WORDS[-1]}"))
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
complete -F _vips_completions vips
|
@ -360,7 +360,6 @@ vips_operation_pspec_usage( VipsBuf *buf, GParamSpec *pspec )
|
||||
vips_buf_appendf( buf, "%s", _( "max" ) );
|
||||
vips_buf_appendf( buf, ": %d\n", pspec_int->maximum );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void *
|
||||
|
@ -33,6 +33,11 @@ loaded automatically.
|
||||
.B -v, --version
|
||||
Show VIPS version.
|
||||
|
||||
.TP
|
||||
.B -c NAME, --completion NAME
|
||||
Print completions for
|
||||
.B NAME
|
||||
|
||||
.SH COMMANDS
|
||||
|
||||
.TP
|
||||
@ -41,7 +46,7 @@ Execute a named operation, for example add.
|
||||
|
||||
.SH EXAMPLES
|
||||
|
||||
Run a vips8 operation. Operation options must follow the operation name.
|
||||
Run a vips operation. Operation options must follow the operation name.
|
||||
|
||||
$ vips insert lena.v lena2.v out.v 0 0 --background "128 0 0"
|
||||
|
||||
|
119
tools/vips.c
119
tools/vips.c
@ -45,6 +45,8 @@
|
||||
* 18/6/20 kleisauke
|
||||
* - avoid using vips7 symbols
|
||||
* - remove deprecated vips7 C++ generator
|
||||
* 1/11/22
|
||||
* - add "-c" flag
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -170,6 +172,119 @@ parse_main_option_list( const gchar *option_name, const gchar *value,
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
static void *
|
||||
list_operation( GType type, void *user_data )
|
||||
{
|
||||
VipsObjectClass *class = VIPS_OBJECT_CLASS( g_type_class_ref( type ) );
|
||||
|
||||
if( G_TYPE_IS_ABSTRACT( type ) )
|
||||
return( NULL );
|
||||
if( class->deprecated )
|
||||
return( NULL );
|
||||
if( VIPS_OPERATION_CLASS( class )->flags & VIPS_OPERATION_DEPRECATED )
|
||||
return( NULL );
|
||||
|
||||
printf( "%s\n", class->nickname );
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
static void *
|
||||
list_operation_arg( VipsObjectClass *object_class,
|
||||
GParamSpec *pspec, VipsArgumentClass *argument_class,
|
||||
void *_data1, void *_data2 )
|
||||
{
|
||||
GType type = G_PARAM_SPEC_VALUE_TYPE( pspec );
|
||||
|
||||
if( !(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) ||
|
||||
(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) )
|
||||
return( NULL );
|
||||
|
||||
/* We don't try to complete options, though maybe we should.
|
||||
*/
|
||||
if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) )
|
||||
return( NULL );
|
||||
|
||||
/* These are the pspecs that vips uses that have interesting values.
|
||||
*/
|
||||
if( G_IS_PARAM_SPEC_ENUM( pspec ) ) {
|
||||
GTypeClass *class = g_type_class_ref( type );
|
||||
|
||||
GEnumClass *genum;
|
||||
int i;
|
||||
|
||||
/* Should be impossible, no need to warn.
|
||||
*/
|
||||
if( !class )
|
||||
return( NULL );
|
||||
|
||||
genum = G_ENUM_CLASS( class );
|
||||
|
||||
printf( "word:" );
|
||||
|
||||
/* -1 since we always have a "last" member.
|
||||
*/
|
||||
for( i = 0; i < genum->n_values - 1; i++ ) {
|
||||
if( i > 0 )
|
||||
printf( "|" );
|
||||
printf( "%s", genum->values[i].value_nick );
|
||||
}
|
||||
|
||||
printf( "\n" );
|
||||
}
|
||||
else if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) )
|
||||
printf( "word:true|false\n" );
|
||||
else if( G_IS_PARAM_SPEC_DOUBLE( pspec ) ) {
|
||||
GParamSpecDouble *pspec_double = (GParamSpecDouble *) pspec;
|
||||
|
||||
printf( "word:%g\n", pspec_double->default_value );
|
||||
}
|
||||
else if( G_IS_PARAM_SPEC_INT( pspec ) ) {
|
||||
GParamSpecInt *pspec_int = (GParamSpecInt *) pspec;
|
||||
|
||||
printf( "word:%d\n", pspec_int->default_value );
|
||||
}
|
||||
else if( G_IS_PARAM_SPEC_OBJECT( pspec ) )
|
||||
/* Eg. an image input or output.
|
||||
*/
|
||||
printf( "file\n" );
|
||||
else
|
||||
/* We can offer no useful suggestion for eg. array_int etc.
|
||||
*/
|
||||
printf( "none\n" );
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_main_option_completion( const gchar *option_name, const gchar *value,
|
||||
gpointer data, GError **error )
|
||||
{
|
||||
VipsObjectClass *class;
|
||||
|
||||
if( value &&
|
||||
(class = (VipsObjectClass *) vips_type_map_all(
|
||||
g_type_from_name( "VipsOperation" ),
|
||||
test_nickname, (void *) value )) )
|
||||
vips_argument_class_map( class,
|
||||
(VipsArgumentClassMapFn) list_operation_arg,
|
||||
NULL, NULL );
|
||||
else if( value ) {
|
||||
vips_error( g_get_prgname(),
|
||||
_( "'%s' is not the name of a vips operation" ),
|
||||
value );
|
||||
vips_error_g( error );
|
||||
|
||||
return( FALSE );
|
||||
}
|
||||
else {
|
||||
vips_type_map_all( g_type_from_name( "VipsOperation" ),
|
||||
list_operation, NULL );
|
||||
}
|
||||
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
static GOptionEntry main_option[] = {
|
||||
{ "list", 'l', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
|
||||
(GOptionArgFunc) parse_main_option_list,
|
||||
@ -180,6 +295,10 @@ static GOptionEntry main_option[] = {
|
||||
N_( "PLUGIN" ) },
|
||||
{ "version", 'v', 0, G_OPTION_ARG_NONE, &main_option_version,
|
||||
N_( "print version" ), NULL },
|
||||
{ "completion", 'c', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
|
||||
(GOptionArgFunc) parse_main_option_completion,
|
||||
N_( "print completions" ),
|
||||
N_( "BASE-NAME" ) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user