better usage message

more sensible output for "vips max" or "vips getpoint"
This commit is contained in:
John Cupitt 2014-02-20 19:52:36 +00:00
parent b80b503474
commit 3bceb5286b
4 changed files with 106 additions and 96 deletions

51
TODO
View File

@ -24,57 +24,6 @@
- try
$ vips getpoint
usage:
getpoint in out-array x y
read a point from an image
where:
in - Input image, input VipsImage
out-array - Array of output values, output VipsArrayDouble
x - Getpoint to read from, input gint
y - Getpoint to read from, input gint
$ vips max
usage:
max in out
find image maximum
where:
in - Input image, input VipsImage
out - Output value, output gdouble
optional arguments:
x - Horizontal position of maximum, output gint
y - Vertical position of maximum, output gint
size - Number of maximum values to find, input gint
out-array - Array of output values, output VipsArrayDouble
x-array - Array of horizontal positions, output VipsArrayInt
y-array - Array of vertical positions, output VipsArrayInt
don't list out-array or out as args in the usage line, since they don't need
an arg ... these args should be in a separate section, I guess?
put description first
should be:
$ vips getpoint
read a point from an image
usage:
getpoint in x y
prints:
out-array
where:
in - Input image, input VipsImage
out-array - Array of output values, output VipsArrayDouble
x - Getpoint to read from, input gint
y - Getpoint to read from, input gint
- need to do mosaicing
- now vips_linear() has uchar output, can we do something with orc?

View File

@ -304,6 +304,7 @@ typedef void *(*VipsArgumentClassMapFn)( VipsObjectClass *, GParamSpec *,
VipsArgumentClass *, void *a, void *b );
void *vips_argument_class_map( VipsObjectClass *object_class,
VipsArgumentClassMapFn fn, void *a, void *b );
gboolean vips_argument_class_needsstring( VipsArgumentClass *argument_class );
int vips_object_get_argument( VipsObject *object, const char *name,
GParamSpec **pspec,
VipsArgumentClass **argument_class,

View File

@ -472,6 +472,40 @@ vips_argument_class_map( VipsObjectClass *object_class,
return( NULL );
}
/* Does an vipsargument need an argument to write to? For example, an image
* output needs a filename, a double output just prints.
*/
gboolean
vips_argument_class_needsstring( VipsArgumentClass *argument_class )
{
GParamSpec *pspec = ((VipsArgument *) argument_class)->pspec;
GType otype;
VipsObjectClass *oclass;
if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) )
/* Bools, input or output, don't need args.
*/
return( FALSE );
if( argument_class->flags & VIPS_ARGUMENT_INPUT )
/* All other inputs need something.
*/
return( TRUE );
/* Just output objects.
*/
if( (otype = G_PARAM_SPEC_VALUE_TYPE( pspec )) &&
g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
(oclass = g_type_class_ref( otype )) )
/* For now, only vipsobject subclasses can ask for args.
*/
return( oclass->output_needs_arg );
else
return( FALSE );
}
/* Create a VipsArgumentInstance for each installed argument property. Ideally
* we'd do this during _init() but g_object_class_find_property() does not seem
* to work then :-( so we have to delay it until first access. See
@ -1766,8 +1800,6 @@ vips_object_argument_needsstring( VipsObject *object, const char *name )
GParamSpec *pspec;
VipsArgumentClass *argument_class;
VipsArgumentInstance *argument_instance;
GType otype;
VipsObjectClass *oclass;
#ifdef DEBUG
printf( "vips_object_argument_needsstring: %s\n", name );
@ -1777,27 +1809,7 @@ vips_object_argument_needsstring( VipsObject *object, const char *name )
&pspec, &argument_class, &argument_instance ) )
return( -1 );
if( G_IS_PARAM_SPEC_BOOLEAN( pspec ) )
/* Bools, input or output, don't need args.
*/
return( FALSE );
if( argument_class->flags & VIPS_ARGUMENT_INPUT )
/* All other inputs need something.
*/
return( TRUE );
/* Just output objects.
*/
if( (otype = G_PARAM_SPEC_VALUE_TYPE( pspec )) &&
g_type_is_a( otype, VIPS_TYPE_OBJECT ) &&
(oclass = g_type_class_ref( otype )) )
/* For now, only vipsobject subclasses can ask for args.
*/
return( oclass->output_needs_arg );
else
return( FALSE );
return( vips_argument_class_needsstring( argument_class ) );
}
static void

View File

@ -119,30 +119,67 @@ vips_operation_dispose( GObject *gobject )
G_OBJECT_CLASS( vips_operation_parent_class )->dispose( gobject );
}
/* What to show about the argument.
/* Three basic types of command-line argument.
*
* INPUTS: things like an input image, there is a filename argument on the
* command-line which is used to construct the operation argument.
*
* NOARG_OUTPUT: things like the result of VipsMax, there's no correspondiong
* command-line argument, we just print the value.
*
* OPTIONS: optional arguments.
*
* NONE: hide this thing.
*/
typedef enum {
USAGE_INPUTS,
USAGE_NOARG_OUTPUT,
USAGE_OPTIONS,
USAGE_NONE
} UsageType;
typedef struct {
char *message; /* header message on first print */
gboolean required; /* show required args or optional */
gboolean oftype; /* "is of type" message */
UsageType type; /* Type of arg to select */
gboolean oftype; /* Show as "of type" */
int n; /* Arg number */
} VipsOperationClassUsage;
/* Put an arg into one the categories above.
*/
static UsageType
vips_operation_class_usage_classify( VipsArgumentClass *argument_class )
{
if( !(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) ||
(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) )
return( USAGE_NONE );
if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) )
return( USAGE_OPTIONS );
if( vips_argument_class_needsstring( argument_class ) )
return( USAGE_INPUTS );
if( (argument_class->flags & VIPS_ARGUMENT_OUTPUT) &&
!vips_argument_class_needsstring( argument_class ) )
return( USAGE_NOARG_OUTPUT );
return( USAGE_NONE );
}
static void *
vips_operation_class_usage_arg( VipsObjectClass *object_class,
GParamSpec *pspec, VipsArgumentClass *argument_class,
VipsBuf *buf, VipsOperationClassUsage *usage )
{
/* Only show construct args ... others are internal.
*/
if( usage->required ==
((argument_class->flags & VIPS_ARGUMENT_REQUIRED) != 0) &&
(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
!(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) ) {
if( usage->message && usage->n == 0 )
if( usage->type ==
vips_operation_class_usage_classify( argument_class ) ) {
if( usage->message &&
usage->n == 0 )
vips_buf_appendf( buf, "%s\n", usage->message );
if( usage->oftype ) {
if( usage->oftype )
vips_buf_appendf( buf, " %-12s - %s, %s %s\n",
g_param_spec_get_name( pspec ),
g_param_spec_get_blurb( pspec ),
@ -150,11 +187,11 @@ vips_operation_class_usage_arg( VipsObjectClass *object_class,
_( "input" ) : _( "output" ),
g_type_name(
G_PARAM_SPEC_VALUE_TYPE( pspec ) ) );
}
else {
if( usage->n > 0 )
vips_buf_appends( buf, " " );
vips_buf_appends( buf, g_param_spec_get_name( pspec ) );
if( usage->n > 0 )
vips_buf_appends( buf, " " );
vips_buf_appends( buf,
g_param_spec_get_name( pspec ) );
}
usage->n += 1;
@ -170,11 +207,14 @@ vips_operation_usage( VipsOperationClass *class, VipsBuf *buf )
VipsOperationClassUsage usage;
vips_buf_appendf( buf, "%s\n", object_class->description );
vips_buf_appendf( buf, "usage:\n" );
/* First pass through args: show the required names.
*/
vips_buf_appendf( buf, " %s ", object_class->nickname );
usage.message = NULL;
usage.required = TRUE;
usage.type = USAGE_INPUTS;
usage.oftype = FALSE;
usage.n = 0;
vips_argument_class_map( object_class,
@ -182,12 +222,21 @@ vips_operation_usage( VipsOperationClass *class, VipsBuf *buf )
buf, &usage );
vips_buf_appends( buf, "\n" );
vips_buf_appendf( buf, "%s\n", object_class->description );
/* Show required types.
*/
usage.message = "where:";
usage.required = TRUE;
usage.type = USAGE_INPUTS;
usage.oftype = TRUE;
usage.n = 0;
vips_argument_class_map( object_class,
(VipsArgumentClassMapFn) vips_operation_class_usage_arg,
buf, &usage );
/* Show outputs with no input arg (eg. output maximum value for
* vips_max()).
*/
usage.message = "outputs:";
usage.type = USAGE_NOARG_OUTPUT;
usage.oftype = TRUE;
usage.n = 0;
vips_argument_class_map( object_class,
@ -197,7 +246,7 @@ vips_operation_usage( VipsOperationClass *class, VipsBuf *buf )
/* Show optional args.
*/
usage.message = "optional arguments:";
usage.required = FALSE;
usage.type = USAGE_OPTIONS;
usage.oftype = TRUE;
usage.n = 0;
vips_argument_class_map( object_class,
@ -367,8 +416,7 @@ vips_operation_class_print_usage( VipsOperationClass *operation_class )
VipsBuf buf = VIPS_BUF_STATIC( str );
operation_class->usage( operation_class, &buf );
printf( "%s", _( "usage:" ) );
printf( "\n%s", vips_buf_all( &buf ) );
printf( "%s", vips_buf_all( &buf ) );
}
VipsOperation *