mirror of
https://github.com/tmux/tmux.git
synced 2025-09-01 20:57:00 +00:00
Add different command historys for different types of prompts
("command", "search" etc). From Anindya Mukherjee.
This commit is contained in:
184
status.c
184
status.c
@ -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;
|
||||
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]);
|
||||
|
||||
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;
|
||||
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 = xreallocarray(status_prompt_hlist,
|
||||
status_prompt_hsize + 1, sizeof *status_prompt_hlist);
|
||||
status_prompt_hlist[status_prompt_hsize++] = xstrdup(line);
|
||||
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]);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
Reference in New Issue
Block a user