From 39002ead801b619df7de8025905ada6952f8e882 Mon Sep 17 00:00:00 2001 From: NRK Date: Tue, 21 May 2024 23:25:01 +0000 Subject: [PATCH] WIP: add --list-options and zsh completion --- etc/_scrot | 26 +++++++++++++++++++ src/options.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 etc/_scrot diff --git a/etc/_scrot b/etc/_scrot new file mode 100644 index 0000000..7b7dc53 --- /dev/null +++ b/etc/_scrot @@ -0,0 +1,26 @@ +#compdef _scrot scrot + +function _scrot() { + local -a args + local list=$($~words[1] --list-options) 2>/dev/null + for ln in ${(f)list}; do + IFS=$'\t' local tokens=( ${=ln} ) + + local desc="[${tokens[4]}]" + + # TODO: complete argument as well + # local argtype=${tokens[3]%%:*} + # local argdesc=${tokens[3]#*:} + # case "$argtype" in + # R) ;; # Required + # O) ;; # Optional + # N) ;; # None + # esac + + if [ "${tokens[1]}" != " " ]; then + args+=( "-${tokens[1]}${desc}" ) + fi + args+=( "--${tokens[2]}${desc}" ) + done + _arguments "${args[@]}" +} diff --git a/src/options.c b/src/options.c index c6d56c1..55bea7d 100644 --- a/src/options.c +++ b/src/options.c @@ -305,8 +305,10 @@ void optionsParse(int argc, char *argv[]) enum { /* long opt only */ /* ensure these don't collude with single byte opts. */ OPT_FORMAT = UCHAR_MAX + 1, + OPT_LIST_OPTS, }; static const char stropts[] = "a:bC:cD:d:e:F:fhik::l:M:mn:opq:S:s::t:uvw:Z:z"; + // NOTE: make sure lopts and opt_description indexes are kept in sync static const struct option lopts[] = { {"autoselect", required_argument, NULL, 'a'}, {"border", no_argument, NULL, 'b'}, @@ -338,8 +340,44 @@ void optionsParse(int argc, char *argv[]) {"compression", required_argument, NULL, 'Z'}, {"silent", no_argument, NULL, 'z'}, {"format", required_argument, NULL, OPT_FORMAT}, + {"list-options", no_argument, NULL, OPT_LIST_OPTS}, {0} }; + static const char OPT_DEPRECATED[] = ""; + static const struct option_desc { + const char *description, *arg_description; + } opt_description[] = { + /* a */ { "autoselect provided region", "x,y,w,h" }, + /* b */ { "capture the window borders as well", "" }, + /* C */ { "capture specified window class", "NAME" }, + /* c */ { "display a countdown for delay", "" }, + /* D */ { "capture specified display", "DISPLAY" }, + /* d */ { "add delay before screenshot", "[b]SEC" }, + /* e */ { "execute command on saved image", "CMD" }, + /* F */ { "specify output file", "FILE" }, + /* f */ { "freeze the screen when -s is used", "" }, + /* h */ { "display help and exit", "" }, + /* i */ { "ignore keyboard", "" }, + /* k */ { "capture overlapped window and join them", "v|h" }, + /* l */ { "specify the style of the selection line", "STYLE" }, + /* M */ { "capture monitor", "NUM" }, + /* m */ { "capture all monitors", "" }, + /* n */ { OPT_DEPRECATED, OPT_DEPRECATED }, + /* o */ { "overwrite the output file if needed", "" }, + /* p */ { "capture the mouse pointer as well", "" }, + /* q */ { "image quality", "NUM" }, + /* S */ { OPT_DEPRECATED, OPT_DEPRECATED }, + /* s */ { "interactively select a region to capture", "OPTS" }, + /* t */ { "also generate a thumbnail", "% | WxH" }, + /* u */ { "capture the currently focused window", "" }, + /* u */ { "capture the currently focused window", "" }, + /* v */ { "output version and exit", "" }, + /* w */ { "X window ID to capture", "WID" }, + /* Z */ { "image compression level", "LVL" }, + /* z */ { "prevent beeping", "" }, + /* OPT_FORMAT */ { "specify output file format", "FMT" }, + /* OPT_LIST_OPTS */ { "list all options", "" }, + }; int optch; const char *errmsg; bool FFlagSet = false; @@ -464,6 +502,38 @@ void optionsParse(int argc, char *argv[]) case OPT_FORMAT: opt.format = optarg; break; + case OPT_LIST_OPTS: + for (size_t i = 0; i < ARRAY_COUNT(lopts) - 1; ++i) { + const struct option *o = &lopts[i]; + const struct option_desc *d = &opt_description[i]; + if (d->description == OPT_DEPRECATED) + continue; +#if 0 // human readable output + int n = 0; + if (o->val <= UCHAR_MAX) + n += printf("-%c, ", o->val); + n += printf("--%s", o->name); + if (o->has_arg == required_argument) + n += printf(" <%s>", d->arg_description); + else if (o->has_arg == optional_argument) + n += printf("[=%s]", d->arg_description); + for (; n >= 0 && n < 32; ++n) + putchar(' '); + printf("\t%s\n", d->description); +#else + printf("%c\t", o->val <= UCHAR_MAX ? o->val : ' '); + printf("%s\t", o->name); + if (o->has_arg == required_argument) + printf("R:%s\t", d->arg_description); + else if (o->has_arg == optional_argument) + printf("O:%s\t", d->arg_description); + else + printf("N:\t"); + printf("%s\n", d->description); +#endif + } + exit(EXIT_SUCCESS); + break; default: exit(EXIT_FAILURE); }