summaryrefslogtreecommitdiff
path: root/usr.bin/tmux/status.c
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2021-06-10 07:50:05 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2021-06-10 07:50:05 +0000
commite57c1cfc9cc858401ca95380862658ad9602fa0a (patch)
tree76a650ed924b7f4bb031495e181c5a9712a90582 /usr.bin/tmux/status.c
parente910308f79db05ca4a614e1ca78dcb496518a306 (diff)
Add different command historys for different types of prompts
("command", "search" etc). From Anindya Mukherjee.
Diffstat (limited to 'usr.bin/tmux/status.c')
-rw-r--r--usr.bin/tmux/status.c188
1 files changed, 136 insertions, 52 deletions
diff --git a/usr.bin/tmux/status.c b/usr.bin/tmux/status.c
index 2e7b21a5685..6ee43499872 100644
--- a/usr.bin/tmux/status.c
+++ b/usr.bin/tmux/status.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: status.c,v 1.223 2021/06/10 07:38:28 nicm Exp $ */
+/* $OpenBSD: status.c,v 1.224 2021/06/10 07:50:04 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -33,9 +33,9 @@ static void status_message_callback(int, short, void *);
static void status_timer_callback(int, short, void *);
static char *status_prompt_find_history_file(void);
-static const char *status_prompt_up_history(u_int *);
-static const char *status_prompt_down_history(u_int *);
-static void status_prompt_add_history(const char *);
+static const char *status_prompt_up_history(u_int *, u_int);
+static const char *status_prompt_down_history(u_int *, u_int);
+static void status_prompt_add_history(const char *, u_int);
static char *status_prompt_complete(struct client *, const char *, u_int);
static char *status_prompt_complete_window_menu(struct client *,
@@ -49,10 +49,16 @@ struct status_prompt_menu {
char flag;
};
+static const char *prompt_type_strings[] = {
+ "command",
+ "search",
+ "target",
+ "window-target"
+};
+
/* Status prompt history. */
-#define PROMPT_HISTORY 100
-static char **status_prompt_hlist;
-static u_int status_prompt_hsize;
+char **status_prompt_hlist[PROMPT_NTYPES];
+u_int status_prompt_hsize[PROMPT_NTYPES];
/* Find the history file to load/save from/to. */
static char *
@@ -75,6 +81,28 @@ status_prompt_find_history_file(void)
return (path);
}
+/* Add loaded history item to the appropriate list. */
+static void
+status_prompt_add_typed_history(char *line)
+{
+ char *typestr;
+ enum prompt_type type = PROMPT_TYPE_INVALID;
+
+ typestr = strsep(&line, ":");
+ if (line != NULL)
+ type = status_prompt_type(typestr);
+ if (type == PROMPT_TYPE_INVALID) {
+ /*
+ * Invalid types are not expected, but this provides backward
+ * compatibility with old history files.
+ */
+ if (line != NULL)
+ *(--line) = ':';
+ status_prompt_add_history(typestr, PROMPT_TYPE_COMMAND);
+ } else
+ status_prompt_add_history(line, type);
+}
+
/* Load status prompt history from file. */
void
status_prompt_load_history(void)
@@ -102,12 +130,12 @@ status_prompt_load_history(void)
if (length > 0) {
if (line[length - 1] == '\n') {
line[length - 1] = '\0';
- status_prompt_add_history(line);
+ status_prompt_add_typed_history(line);
} else {
tmp = xmalloc(length + 1);
memcpy(tmp, line, length);
tmp[length] = '\0';
- status_prompt_add_history(tmp);
+ status_prompt_add_typed_history(tmp);
free(tmp);
}
}
@@ -120,7 +148,7 @@ void
status_prompt_save_history(void)
{
FILE *f;
- u_int i;
+ u_int i, type;
char *history_file;
if ((history_file = status_prompt_find_history_file()) == NULL)
@@ -135,9 +163,13 @@ status_prompt_save_history(void)
}
free(history_file);
- for (i = 0; i < status_prompt_hsize; i++) {
- fputs(status_prompt_hlist[i], f);
- fputc('\n', f);
+ for (type = 0; type < PROMPT_NTYPES; type++) {
+ for (i = 0; i < status_prompt_hsize[type]; i++) {
+ fputs(prompt_type_strings[type], f);
+ fputc(':', f);
+ fputs(status_prompt_hlist[type][i], f);
+ fputc('\n', f);
+ }
}
fclose(f);
@@ -545,7 +577,7 @@ status_message_redraw(struct client *c)
void
status_prompt_set(struct client *c, struct cmd_find_state *fs,
const char *msg, const char *input, prompt_input_cb inputcb,
- prompt_free_cb freecb, void *data, int flags)
+ prompt_free_cb freecb, void *data, int flags, enum prompt_type prompt_type)
{
struct format_tree *ft;
char *tmp;
@@ -581,9 +613,10 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs,
c->prompt_freecb = freecb;
c->prompt_data = data;
- c->prompt_hindex = 0;
+ memset(c->prompt_hindex, 0, sizeof c->prompt_hindex);
c->prompt_flags = flags;
+ c->prompt_type = prompt_type;
c->prompt_mode = PROMPT_ENTRY;
if (~flags & PROMPT_INCREMENTAL)
@@ -644,7 +677,7 @@ status_prompt_update(struct client *c, const char *msg, const char *input)
c->prompt_buffer = utf8_fromcstr(tmp);
c->prompt_index = utf8_strlen(c->prompt_buffer);
- c->prompt_hindex = 0;
+ memset(c->prompt_hindex, 0, sizeof c->prompt_hindex);
c->flags |= CLIENT_REDRAWSTATUS;
@@ -768,7 +801,7 @@ status_prompt_space(const struct utf8_data *ud)
}
/*
- * Translate key from emacs to vi. Return 0 to drop key, 1 to process the key
+ * Translate key from vi to emacs. Return 0 to drop key, 1 to process the key
* as an emacs key; return 2 to append to the buffer.
*/
static int
@@ -1222,7 +1255,8 @@ process_key:
goto changed;
case KEYC_UP:
case '\020': /* C-p */
- histstr = status_prompt_up_history(&c->prompt_hindex);
+ histstr = status_prompt_up_history(c->prompt_hindex,
+ c->prompt_type);
if (histstr == NULL)
break;
free(c->prompt_buffer);
@@ -1231,7 +1265,8 @@ process_key:
goto changed;
case KEYC_DOWN:
case '\016': /* C-n */
- histstr = status_prompt_down_history(&c->prompt_hindex);
+ histstr = status_prompt_down_history(c->prompt_hindex,
+ c->prompt_type);
if (histstr == NULL)
break;
free(c->prompt_buffer);
@@ -1259,7 +1294,7 @@ process_key:
case '\n':
s = utf8_tocstr(c->prompt_buffer);
if (*s != '\0')
- status_prompt_add_history(s);
+ status_prompt_add_history(s, c->prompt_type);
if (c->prompt_inputcb(c, c->prompt_data, s, 1) == 0)
status_prompt_clear(c);
free(s);
@@ -1348,54 +1383,78 @@ changed:
/* Get previous line from the history. */
static const char *
-status_prompt_up_history(u_int *idx)
+status_prompt_up_history(u_int *idx, u_int type)
{
/*
* History runs from 0 to size - 1. Index is from 0 to size. Zero is
* empty.
*/
- if (status_prompt_hsize == 0 || *idx == status_prompt_hsize)
+ if (status_prompt_hsize[type] == 0 ||
+ idx[type] == status_prompt_hsize[type])
return (NULL);
- (*idx)++;
- return (status_prompt_hlist[status_prompt_hsize - *idx]);
+ idx[type]++;
+ return (status_prompt_hlist[type][status_prompt_hsize[type] - idx[type]]);
}
/* Get next line from the history. */
static const char *
-status_prompt_down_history(u_int *idx)
+status_prompt_down_history(u_int *idx, u_int type)
{
- if (status_prompt_hsize == 0 || *idx == 0)
+ if (status_prompt_hsize[type] == 0 || idx[type] == 0)
return ("");
- (*idx)--;
- if (*idx == 0)
+ idx[type]--;
+ if (idx[type] == 0)
return ("");
- return (status_prompt_hlist[status_prompt_hsize - *idx]);
+ return (status_prompt_hlist[type][status_prompt_hsize[type] - idx[type]]);
}
/* Add line to the history. */
static void
-status_prompt_add_history(const char *line)
+status_prompt_add_history(const char *line, u_int type)
{
- size_t size;
-
- if (status_prompt_hsize > 0 &&
- strcmp(status_prompt_hlist[status_prompt_hsize - 1], line) == 0)
- return;
-
- if (status_prompt_hsize == PROMPT_HISTORY) {
- free(status_prompt_hlist[0]);
-
- size = (PROMPT_HISTORY - 1) * sizeof *status_prompt_hlist;
- memmove(&status_prompt_hlist[0], &status_prompt_hlist[1], size);
+ u_int i, oldsize, newsize, freecount, hlimit, new = 1;
+ size_t movesize;
+
+ oldsize = status_prompt_hsize[type];
+ if (oldsize > 0 &&
+ strcmp(status_prompt_hlist[type][oldsize - 1], line) == 0)
+ new = 0;
+
+ hlimit = options_get_number(global_options, "prompt-history-limit");
+ if (hlimit > oldsize) {
+ if (new == 0)
+ return;
+ newsize = oldsize + new;
+ } else {
+ newsize = hlimit;
+ freecount = oldsize + new - newsize;
+ if (freecount > oldsize)
+ freecount = oldsize;
+ if (freecount == 0)
+ return;
+ for (i = 0; i < freecount; i++)
+ free(status_prompt_hlist[type][i]);
+ movesize = (oldsize - freecount) *
+ sizeof *status_prompt_hlist[type];
+ if (movesize > 0) {
+ memmove(&status_prompt_hlist[type][0],
+ &status_prompt_hlist[type][freecount], movesize);
+ }
+ }
- status_prompt_hlist[status_prompt_hsize - 1] = xstrdup(line);
- return;
+ if (newsize == 0) {
+ free(status_prompt_hlist[type]);
+ status_prompt_hlist[type] = NULL;
+ } else if (newsize != oldsize) {
+ status_prompt_hlist[type] =
+ xreallocarray(status_prompt_hlist[type], newsize,
+ sizeof *status_prompt_hlist[type]);
}
- status_prompt_hlist = xreallocarray(status_prompt_hlist,
- status_prompt_hsize + 1, sizeof *status_prompt_hlist);
- status_prompt_hlist[status_prompt_hsize++] = xstrdup(line);
+ if (new == 1 && newsize > 0)
+ status_prompt_hlist[type][newsize - 1] = xstrdup(line);
+ status_prompt_hsize[type] = newsize;
}
/* Build completion list. */
@@ -1501,7 +1560,7 @@ status_prompt_menu_callback(__unused struct menu *menu, u_int idx, key_code key,
s = xstrdup(spm->list[idx]);
else
xasprintf(&s, "-%c%s", spm->flag, spm->list[idx]);
- if (c->prompt_flags & PROMPT_WINDOW) {
+ if (c->prompt_type == PROMPT_TYPE_WINDOW_TARGET) {
free(c->prompt_buffer);
c->prompt_buffer = utf8_fromcstr(s);
c->prompt_index = utf8_strlen(c->prompt_buffer);
@@ -1609,7 +1668,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
}
list = xreallocarray(list, size + 1, sizeof *list);
- if (c->prompt_flags & PROMPT_WINDOW) {
+ if (c->prompt_type == PROMPT_TYPE_WINDOW_TARGET) {
xasprintf(&tmp, "%d (%s)", wl->idx, wl->window->name);
xasprintf(&list[size++], "%d", wl->idx);
} else {
@@ -1717,10 +1776,12 @@ status_prompt_complete(struct client *c, const char *word, u_int offset)
u_int size = 0, i;
if (*word == '\0' &&
- ((c->prompt_flags & (PROMPT_TARGET|PROMPT_WINDOW)) == 0))
+ c->prompt_type != PROMPT_TYPE_TARGET &&
+ c->prompt_type != PROMPT_TYPE_WINDOW_TARGET)
return (NULL);
- if (((c->prompt_flags & (PROMPT_TARGET|PROMPT_WINDOW)) == 0) &&
+ if (c->prompt_type != PROMPT_TYPE_TARGET &&
+ c->prompt_type != PROMPT_TYPE_WINDOW_TARGET &&
strncmp(word, "-t", 2) != 0 &&
strncmp(word, "-s", 2) != 0) {
list = status_prompt_complete_list(&size, word, offset == 0);
@@ -1733,7 +1794,8 @@ status_prompt_complete(struct client *c, const char *word, u_int offset)
goto found;
}
- if (c->prompt_flags & (PROMPT_TARGET|PROMPT_WINDOW)) {
+ if (c->prompt_type == PROMPT_TYPE_TARGET ||
+ c->prompt_type == PROMPT_TYPE_WINDOW_TARGET) {
s = word;
flag = '\0';
} else {
@@ -1743,7 +1805,7 @@ status_prompt_complete(struct client *c, const char *word, u_int offset)
}
/* If this is a window completion, open the window menu. */
- if (c->prompt_flags & PROMPT_WINDOW) {
+ if (c->prompt_type == PROMPT_TYPE_WINDOW_TARGET) {
out = status_prompt_complete_window_menu(c, c->session, s,
offset, '\0');
goto found;
@@ -1793,3 +1855,25 @@ found:
}
return (out);
}
+
+/* Return the type of the prompt as an enum. */
+enum prompt_type
+status_prompt_type(const char *type)
+{
+ u_int i;
+
+ for (i = 0; i < PROMPT_NTYPES; i++) {
+ if (strcmp(type, status_prompt_type_string(i)) == 0)
+ return (i);
+ }
+ return (PROMPT_TYPE_INVALID);
+}
+
+/* Accessor for prompt_type_strings. */
+const char *
+status_prompt_type_string(u_int type)
+{
+ if (type >= PROMPT_NTYPES)
+ return ("invalid");
+ return (prompt_type_strings[type]);
+}