aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ask.140
-rw-r--r--ask.c104
2 files changed, 98 insertions, 46 deletions
diff --git a/ask.1 b/ask.1
index 3d262dd..9d7bff8 100644
--- a/ask.1
+++ b/ask.1
@@ -5,11 +5,10 @@
ask \- A tiny command line tool for getting user input
.SH SYNOPSIS
.B ask
-[\fI-hpqv\fR]
-[\fI--initial=initial\fR]
-[\fIprompt \fR
-[\fIinitial\fR
-[\fIoptions...\fR]]]
+[\fI-hPqvyn\fR]
+[\fI-q\fR |\fI--query=initial\fR]
+[[\fI-p\fR |\fI--prompt=\fR]\fIprompt \fR
+[\fIoptions...\fR]]
.SH DESCRIPTION
\fBask\fR is a tiny console application that displays a prompt, gets user input
(with line editing and fuzzy finding functionality), and prints the result to
@@ -20,7 +19,7 @@ standard output
When used with fuzzy finding, as soon as exactly one match is found, exit and
print it.
-.B \-p
+.B \-P
.B \--password
Use password mode, which does not print user input as it's being typed.
@@ -30,13 +29,27 @@ Print \fBask\fR's version and exit.
.B \-h
.B \--help
-Print ask's usage and exit.
+Print \fBask\fR's usage and exit.
-.B \--initial=initial
+.B \-q
+.B \--query=
If given, pre-populate the user input with this value.
-.B prompt
-If provided, display the given prompt in bold. (Default: "> ")
+.B \-p
+.B \--prompt=
+If provided, display the given prompt in bold. If the \fI-p\fR and
+\fI--prompt=\fR flags are not used, the first positional argument is used as
+the prompt, or \fB"> "\fR if there are no positional arguments.
+
+.B \-y
+.B \--yes
+Quickpick between "y" and "n" with "[Y/n]" appended to the prompt, exiting with
+success if "n" is not chosen.
+
+.B \-n
+.B \--no
+Quickpick between "y" and "n" with "[y/N]" appended to the prompt, exiting with
+failure if "y" is not chosen.
.B options...
If additional command line arguments are provided, or if any input is piped in,
@@ -56,13 +69,8 @@ Fuzzy find a file. (Equivalent of \fBrm "`ls | fzf --prompt='Delete file: '`"\fR
.TP
.B
-if test "`ask -q 'Do thing? [Y/n] ' '' Y N`" != N; then dothing; fi
+if ask -y 'Do thing? '; then dothing; fi
Ask user for confirmation (default: yes).
-.TP
-.B
-if test "`ask -q 'Do thing? [y/N] ' '' Y N`" = Y; then dothing; fi
-Ask user for confirmation (default: no).
-
.SH AUTHOR
Bruce Hill (bruce@bruce-hill.com)
diff --git a/ask.c b/ask.c
index 409161f..7ea4de5 100644
--- a/ask.c
+++ b/ask.c
@@ -1,12 +1,15 @@
/* ask - a simple command line asker
* Copyright 2019 Bruce Hill
* Released under the MIT License (see LICENSE for details)
- * Usage: ask [-q|--quickpick] [-p|--password] [-v|--version] [-h|--help] [--initial=initial] [prompt [options...]]
+ * Usage: ask [-Q|--quickpick] [-y|--yes] [-n|--no] [-p|--password]
+ * [-v|--version] [-h|--help] [-q |--query=initial] [[--prompt=]prompt [options...]]
* --password: password mode
* --quickpick: quickpick mode (exit when only one option remains)
* --version: print version and exit
* --help: print usage and exit
- * --initial: initial value to pre-populate user input
+ * --query: initial value to pre-populate user input
+ * --prompt: use the given prompt (displayed in bold)
+ * --yes: append "[Y/n]" to the prompt, use quickpick mode,
*/
#include <poll.h>
#include <stdio.h>
@@ -19,6 +22,7 @@
#include "bterm.h"
+#define ASK_VERSION "0.2"
#define LOWERCASE(c) ('A' <= (c) && (c) <= 'Z' ? ((c) + 'a' - 'A') : (c))
#define EQ(a, b) (case_sensitive ? (a) == (b) : LOWERCASE(a) == LOWERCASE(b))
#define PASSWORD "-\\|/"
@@ -125,7 +129,6 @@ static int draw_line(FILE *out, const char *line, const char *patt, int cursor)
*/
static char *get_input(FILE *in, FILE *out, const char *prompt, const char *initial, int nopts, char **opts)
{
- if (!prompt) prompt = "> ";
fprintf(out, "\033[K\033[0;1m%s\033[0m", prompt);
size_t cap = initial ? strlen(initial) + 100 : 100;
char *buf = memcheck(calloc(cap, 1));
@@ -184,7 +187,6 @@ static char *get_input(FILE *in, FILE *out, const char *prompt, const char *init
switch (key) {
case -1: case -2: case -3: goto skip_redraw;
case '\r':
- // TODO: support backslash-enter
goto finished;
case KEY_CTRL_C: case KEY_ESC:
free(buf);
@@ -295,28 +297,21 @@ static char *get_input(FILE *in, FILE *out, const char *prompt, const char *init
int main(int argc, char *argv[])
{
- FILE *tty_in = fopen("/dev/tty", "r");
- FILE *tty_out = fopen("/dev/tty", "w");
- struct termios orig_termios, bb_termios;
- tcgetattr(fileno(tty_out), &orig_termios);
- cfmakeraw(&bb_termios);
- if (tcsetattr(fileno(tty_out), TCSAFLUSH, &bb_termios) == -1)
- return 1;
-
- char *prompt = NULL, *initial = NULL;
- char **lines = NULL;
+ int yes = 0, no = 0;
+ char *prompt = NULL, *query = NULL;
+ char **opts = NULL;
size_t linescap = 0, linecap = 0;
- int nlines = 0;
+ int nopts = 0;
char *line = NULL;
struct pollfd pfd = {STDIN_FILENO, POLLIN, 0};
if (poll(&pfd, 1, 50) > 0) {
while ((getline(&line, &linecap, stdin)) >= 0) {
- if ((size_t)nlines >= linescap)
- lines = memcheck(realloc(lines, (linescap += 100)*sizeof(char*)));
+ if ((size_t)nopts >= linescap)
+ opts = memcheck(realloc(opts, (linescap += 100)*sizeof(char*)));
if (!line[0]) continue;
if (line[strlen(line)-1] == '\n')
line[strlen(line)-1] = '\0';
- lines[nlines++] = memcheck(strdup(line));
+ opts[nopts++] = memcheck(strdup(line));
}
}
int a = 1;
@@ -324,26 +319,41 @@ int main(int argc, char *argv[])
if (argv[a][0] == '-' && argv[a][1] != '-') {
for (char *p = &argv[a][1]; *p; p++) {
switch (*p) {
- case 'p': password = 1; break;
+ case 'P': password = 1; break;
case 'q': quickpick = 1; break;
case 'h': goto help_flag;
case 'v': goto version_flag;
+ case 'y': yes = 1; quickpick = 1; break;
+ case 'n': no = 1; quickpick = 1; break;
}
}
- } else if (strncmp(argv[a], "--initial=", strlen("--initial=")) == 0) {
- initial = &argv[a][strlen("--initial=")];
+ } else if (strcmp(argv[a], "-p") == 0) {
+ prompt = argv[++a];
+ } else if (strcmp(argv[a], "-q") == 0) {
+ query = argv[++a];
+ } else if (strncmp(argv[a], "--prompt=", strlen("--prompt=")) == 0) {
+ prompt = &argv[a][strlen("--prompt=")];
+ } else if (strncmp(argv[a], "--query=", strlen("--query=")) == 0) {
+ query = &argv[a][strlen("--query=")];
} else if (strcmp(argv[a], "--password") == 0) {
password = 1;
} else if (strcmp(argv[a], "--quickpick") == 0) {
quickpick = 1;
+ } else if (strcmp(argv[a], "--yes") == 0) {
+ yes = 1;
+ quickpick = 1;
+ } else if (strcmp(argv[a], "--no") == 0) {
+ no = 1;
+ quickpick = 1;
} else if (strcmp(argv[a], "--help") == 0) {
help_flag:
printf("ask - A simple command line input tool.\n"
- "Usage: ask [-q|--quickpick] [-p|--password] [-v|--version] [-h|--help] [--initial=initial] [prompt [options...]]\n");
+ "Usage: ask [-Q|--quickpick] [-P|--password] [-v|--version] [-h|--help] "
+ "[-y|--yes] [-n|--no] [-q |--query=query] [[-p |--prompt=]prompt [options...]]\n");
return 0;
} else if (strcmp(argv[a], "--version") == 0) {
version_flag:
- printf("ask v0.1\n");
+ printf("ask %s\n", ASK_VERSION);
return 0;
} else break;
++a;
@@ -351,12 +361,43 @@ int main(int argc, char *argv[])
if (!prompt && a < argc) prompt = argv[a++];
while (a < argc) {
- if ((size_t)nlines >= linescap)
- lines = memcheck(realloc(lines, (linescap += 100)*sizeof(char*)));
- lines[nlines++] = argv[a++];
+ if ((size_t)nopts >= linescap)
+ opts = memcheck(realloc(opts, (linescap += 100)*sizeof(char*)));
+ opts[nopts++] = argv[a++];
}
- char *output = get_input(tty_in, tty_out, prompt, initial, nlines, lines);
+ if (yes || no) {
+ if ((size_t)nopts + 4 >= linescap)
+ opts = memcheck(realloc(opts, (linescap += 4)*sizeof(char*)));
+ opts[nopts++] = "y";
+ opts[nopts++] = "n";
+ opts[nopts++] = "Y";
+ opts[nopts++] = "N";
+ }
+
+ if (yes) {
+ char *p2 = memcheck(calloc((prompt ? strlen(prompt) : 0)+5+1, sizeof(char)));
+ if (prompt) strcpy(p2, prompt);
+ strcat(p2, "[Y/n]");
+ prompt = p2;
+ } else if (no) {
+ char *p2 = memcheck(calloc((prompt ? strlen(prompt) : 0)+5+1, sizeof(char)));
+ if (prompt) strcpy(p2, prompt);
+ strcat(p2, "[y/N]");
+ prompt = p2;
+ }
+
+ if (!prompt) prompt = "> ";
+
+ FILE *tty_in = fopen("/dev/tty", "r");
+ FILE *tty_out = fopen("/dev/tty", "w");
+ struct termios orig_termios, bb_termios;
+ tcgetattr(fileno(tty_out), &orig_termios);
+ cfmakeraw(&bb_termios);
+ if (tcsetattr(fileno(tty_out), TCSAFLUSH, &bb_termios) == -1)
+ return 1;
+
+ char *output = get_input(tty_in, tty_out, prompt, query, nopts, opts);
fflush(tty_out);
tcsetattr(fileno(tty_out), TCSAFLUSH, &orig_termios);
@@ -365,13 +406,16 @@ int main(int argc, char *argv[])
fclose(tty_in);
tty_in = NULL;
+ // This doesn't free memory, but it doesn't need to because
+ // the program is exiting
if (!output) return 1;
fputs(output, stdout);
- free(output);
+ if (yes)
+ return strcmp(output, "n") == 0 && strcmp(output, "N") == 0;
+ if (no)
+ return strcmp(output, "y") != 0 && strcmp(output, "Y") != 0;
- // This doesn't free the memory in lines, but it doesn't need to because
- // the program is exiting
return 0;
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1