=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/status.c,v retrieving revision 1.223 retrieving revision 1.224 diff -u -r1.223 -r1.224 --- src/usr.bin/tmux/status.c 2021/06/10 07:38:28 1.223 +++ src/usr.bin/tmux/status.c 2021/06/10 07:50:04 1.224 @@ -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 @@ -33,9 +33,9 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ } /* - * 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 @@ 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 @@ 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 @@ 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 @@ /* 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; + u_int i, oldsize, newsize, freecount, hlimit, new = 1; + size_t movesize; - if (status_prompt_hsize > 0 && - strcmp(status_prompt_hlist[status_prompt_hsize - 1], line) == 0) - return; + oldsize = status_prompt_hsize[type]; + if (oldsize > 0 && + strcmp(status_prompt_hlist[type][oldsize - 1], line) == 0) + new = 0; - if (status_prompt_hsize == PROMPT_HISTORY) { - free(status_prompt_hlist[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); + } + } - size = (PROMPT_HISTORY - 1) * sizeof *status_prompt_hlist; - memmove(&status_prompt_hlist[0], &status_prompt_hlist[1], size); - - 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ } /* 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; @@ -1792,4 +1854,26 @@ free(list); } 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]); }