mirror of
https://github.com/tmate-io/tmate.git
synced 2024-12-02 04:53:10 +01:00
Remove ARRAY_* from history and expand completion to complete a) layout
names and b) targets beginning with -t or -s.
This commit is contained in:
parent
31b1ab4852
commit
0b39e6427f
256
status.c
256
status.c
@ -45,10 +45,15 @@ void status_message_callback(int, short, void *);
|
|||||||
const char *status_prompt_up_history(u_int *);
|
const char *status_prompt_up_history(u_int *);
|
||||||
const char *status_prompt_down_history(u_int *);
|
const char *status_prompt_down_history(u_int *);
|
||||||
void status_prompt_add_history(const char *);
|
void status_prompt_add_history(const char *);
|
||||||
char *status_prompt_complete(const char *);
|
|
||||||
|
const char **status_prompt_complete_list(u_int *, const char *);
|
||||||
|
char *status_prompt_complete_prefix(const char **, u_int);
|
||||||
|
char *status_prompt_complete(struct session *, const char *);
|
||||||
|
|
||||||
/* Status prompt history. */
|
/* Status prompt history. */
|
||||||
ARRAY_DECL(, char *) status_prompt_history = ARRAY_INITIALIZER;
|
#define PROMPT_HISTORY 100
|
||||||
|
char **status_prompt_hlist;
|
||||||
|
u_int status_prompt_hsize;
|
||||||
|
|
||||||
/* Status output tree. */
|
/* Status output tree. */
|
||||||
RB_GENERATE(status_out_tree, status_out, entry, status_out_cmp);
|
RB_GENERATE(status_out_tree, status_out, entry, status_out_cmp);
|
||||||
@ -977,7 +982,7 @@ status_prompt_key(struct client *c, int key)
|
|||||||
word[last - first] = '\0';
|
word[last - first] = '\0';
|
||||||
|
|
||||||
/* And try to complete it. */
|
/* And try to complete it. */
|
||||||
if ((s = status_prompt_complete(word)) == NULL)
|
if ((s = status_prompt_complete(sess, word)) == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Trim out word. */
|
/* Trim out word. */
|
||||||
@ -1235,114 +1240,235 @@ status_prompt_key(struct client *c, int key)
|
|||||||
const char *
|
const char *
|
||||||
status_prompt_up_history(u_int *idx)
|
status_prompt_up_history(u_int *idx)
|
||||||
{
|
{
|
||||||
u_int size;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* History runs from 0 to size - 1.
|
* History runs from 0 to size - 1. Index is from 0 to size. Zero is
|
||||||
*
|
* empty.
|
||||||
* Index is from 0 to size. Zero is empty.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
size = ARRAY_LENGTH(&status_prompt_history);
|
if (status_prompt_hsize == 0 || *idx == status_prompt_hsize)
|
||||||
if (size == 0 || *idx == size)
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
(*idx)++;
|
(*idx)++;
|
||||||
return (ARRAY_ITEM(&status_prompt_history, size - *idx));
|
return (status_prompt_hlist[status_prompt_hsize - *idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get next line from the history. */
|
/* Get next line from the history. */
|
||||||
const char *
|
const char *
|
||||||
status_prompt_down_history(u_int *idx)
|
status_prompt_down_history(u_int *idx)
|
||||||
{
|
{
|
||||||
u_int size;
|
if (status_prompt_hsize == 0 || *idx == 0)
|
||||||
|
|
||||||
size = ARRAY_LENGTH(&status_prompt_history);
|
|
||||||
if (size == 0 || *idx == 0)
|
|
||||||
return ("");
|
return ("");
|
||||||
(*idx)--;
|
(*idx)--;
|
||||||
if (*idx == 0)
|
if (*idx == 0)
|
||||||
return ("");
|
return ("");
|
||||||
return (ARRAY_ITEM(&status_prompt_history, size - *idx));
|
return (status_prompt_hlist[status_prompt_hsize - *idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add line to the history. */
|
/* Add line to the history. */
|
||||||
void
|
void
|
||||||
status_prompt_add_history(const char *line)
|
status_prompt_add_history(const char *line)
|
||||||
{
|
{
|
||||||
u_int size;
|
size_t size;
|
||||||
|
|
||||||
size = ARRAY_LENGTH(&status_prompt_history);
|
if (status_prompt_hsize > 0 &&
|
||||||
if (size > 0 && strcmp(ARRAY_LAST(&status_prompt_history), line) == 0)
|
strcmp(status_prompt_hlist[status_prompt_hsize - 1], line) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (size == PROMPT_HISTORY) {
|
if (status_prompt_hsize == PROMPT_HISTORY) {
|
||||||
free(ARRAY_FIRST(&status_prompt_history));
|
free(status_prompt_hlist[0]);
|
||||||
ARRAY_REMOVE(&status_prompt_history, 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
ARRAY_ADD(&status_prompt_history, xstrdup(line));
|
status_prompt_hlist = xreallocarray(status_prompt_hlist,
|
||||||
|
status_prompt_hsize + 1, sizeof *status_prompt_hlist);
|
||||||
|
status_prompt_hlist[status_prompt_hsize++] = xstrdup(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build completion list. */
|
||||||
|
const char **
|
||||||
|
status_prompt_complete_list(u_int *size, const char *s)
|
||||||
|
{
|
||||||
|
const char **list = NULL, **layout;
|
||||||
|
const struct cmd_entry **cmdent;
|
||||||
|
const struct options_table_entry *oe;
|
||||||
|
const char *layouts[] = {
|
||||||
|
"even-horizontal", "even-vertical", "main-horizontal",
|
||||||
|
"main-vertical", "tiled", NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
*size = 0;
|
||||||
|
for (cmdent = cmd_table; *cmdent != NULL; cmdent++) {
|
||||||
|
if (strncmp((*cmdent)->name, s, strlen(s)) == 0) {
|
||||||
|
list = xreallocarray(list, (*size) + 1, sizeof *list);
|
||||||
|
list[(*size)++] = (*cmdent)->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (oe = server_options_table; oe->name != NULL; oe++) {
|
||||||
|
if (strncmp(oe->name, s, strlen(s)) == 0) {
|
||||||
|
list = xreallocarray(list, (*size) + 1, sizeof *list);
|
||||||
|
list[(*size)++] = oe->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (oe = session_options_table; oe->name != NULL; oe++) {
|
||||||
|
if (strncmp(oe->name, s, strlen(s)) == 0) {
|
||||||
|
list = xreallocarray(list, (*size) + 1, sizeof *list);
|
||||||
|
list[(*size)++] = oe->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (oe = window_options_table; oe->name != NULL; oe++) {
|
||||||
|
if (strncmp(oe->name, s, strlen(s)) == 0) {
|
||||||
|
list = xreallocarray(list, (*size) + 1, sizeof *list);
|
||||||
|
list[(*size)++] = oe->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (layout = layouts; *layout != NULL; layout++) {
|
||||||
|
if (strncmp(*layout, s, strlen(s)) == 0) {
|
||||||
|
list = xreallocarray(list, (*size) + 1, sizeof *list);
|
||||||
|
list[(*size)++] = *layout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find longest prefix. */
|
||||||
|
char *
|
||||||
|
status_prompt_complete_prefix(const char **list, u_int size)
|
||||||
|
{
|
||||||
|
char *out;
|
||||||
|
u_int i;
|
||||||
|
size_t j;
|
||||||
|
|
||||||
|
out = xstrdup(list[0]);
|
||||||
|
for (i = 1; i < size; i++) {
|
||||||
|
j = strlen(list[i]);
|
||||||
|
if (j > strlen(out))
|
||||||
|
j = strlen(out);
|
||||||
|
for (; j > 0; j--) {
|
||||||
|
if (out[j - 1] != list[i][j - 1])
|
||||||
|
out[j - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Complete word. */
|
/* Complete word. */
|
||||||
char *
|
char *
|
||||||
status_prompt_complete(const char *s)
|
status_prompt_complete(struct session *sess, const char *s)
|
||||||
{
|
{
|
||||||
const struct cmd_entry **cmdent;
|
const char **list = NULL, *colon;
|
||||||
const struct options_table_entry *oe;
|
u_int size = 0, i;
|
||||||
ARRAY_DECL(, const char *) list;
|
struct session *s_loop;
|
||||||
char *prefix, *s2;
|
struct winlink *wl;
|
||||||
u_int i;
|
struct window *w;
|
||||||
size_t j;
|
char *copy, *out, *tmp;
|
||||||
|
|
||||||
if (*s == '\0')
|
if (*s == '\0')
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
out = NULL;
|
||||||
|
|
||||||
/* First, build a list of all the possible matches. */
|
if (strncmp(s, "-t", 2) != 0 && strncmp(s, "-s", 2) != 0) {
|
||||||
ARRAY_INIT(&list);
|
list = status_prompt_complete_list(&size, s);
|
||||||
for (cmdent = cmd_table; *cmdent != NULL; cmdent++) {
|
if (size == 0)
|
||||||
if (strncmp((*cmdent)->name, s, strlen(s)) == 0)
|
out = NULL;
|
||||||
ARRAY_ADD(&list, (*cmdent)->name);
|
else if (size == 1)
|
||||||
|
xasprintf(&out, "%s ", list[0]);
|
||||||
|
else
|
||||||
|
out = status_prompt_complete_prefix(list, size);
|
||||||
|
free(list);
|
||||||
|
return (out);
|
||||||
}
|
}
|
||||||
for (oe = server_options_table; oe->name != NULL; oe++) {
|
copy = xstrdup(s);
|
||||||
if (strncmp(oe->name, s, strlen(s)) == 0)
|
|
||||||
ARRAY_ADD(&list, oe->name);
|
colon = ":";
|
||||||
|
if (copy[strlen(copy) - 1] == ':')
|
||||||
|
copy[strlen(copy) - 1] = '\0';
|
||||||
|
else
|
||||||
|
colon = "";
|
||||||
|
s = copy + 2;
|
||||||
|
|
||||||
|
RB_FOREACH(s_loop, sessions, &sessions) {
|
||||||
|
if (strncmp(s_loop->name, s, strlen(s)) == 0) {
|
||||||
|
list = xreallocarray(list, size + 2, sizeof *list);
|
||||||
|
list[size++] = s_loop->name;
|
||||||
}
|
}
|
||||||
for (oe = session_options_table; oe->name != NULL; oe++) {
|
|
||||||
if (strncmp(oe->name, s, strlen(s)) == 0)
|
|
||||||
ARRAY_ADD(&list, oe->name);
|
|
||||||
}
|
}
|
||||||
for (oe = window_options_table; oe->name != NULL; oe++) {
|
if (size == 1) {
|
||||||
if (strncmp(oe->name, s, strlen(s)) == 0)
|
out = xstrdup(list[0]);
|
||||||
ARRAY_ADD(&list, oe->name);
|
if (session_find(list[0]) != NULL)
|
||||||
|
colon = ":";
|
||||||
|
} else if (size != 0)
|
||||||
|
out = status_prompt_complete_prefix(list, size);
|
||||||
|
if (out != NULL) {
|
||||||
|
xasprintf(&tmp, "-%c%s%s", copy[1], out, colon);
|
||||||
|
out = tmp;
|
||||||
|
goto found;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If none, bail now. */
|
colon = "";
|
||||||
if (ARRAY_LENGTH(&list) == 0) {
|
if (*s == ':') {
|
||||||
ARRAY_FREE(&list);
|
RB_FOREACH(wl, winlinks, &sess->windows) {
|
||||||
return (NULL);
|
xasprintf(&tmp, ":%s", wl->window->name);
|
||||||
|
if (strncmp(tmp, s, strlen(s)) == 0){
|
||||||
|
list = xreallocarray(list, size + 1,
|
||||||
|
sizeof *list);
|
||||||
|
list[size++] = tmp;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
/* If an exact match, return it, with a trailing space. */
|
xasprintf(&tmp, ":%d", wl->idx);
|
||||||
if (ARRAY_LENGTH(&list) == 1) {
|
if (strncmp(tmp, s, strlen(s)) == 0) {
|
||||||
xasprintf(&s2, "%s ", ARRAY_FIRST(&list));
|
list = xreallocarray(list, size + 1,
|
||||||
ARRAY_FREE(&list);
|
sizeof *list);
|
||||||
return (s2);
|
list[size++] = tmp;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RB_FOREACH(s_loop, sessions, &sessions) {
|
||||||
|
RB_FOREACH(wl, winlinks, &s_loop->windows) {
|
||||||
|
w = wl->window;
|
||||||
|
|
||||||
/* Now loop through the list and find the longest common prefix. */
|
xasprintf(&tmp, "%s:%s", s_loop->name, w->name);
|
||||||
prefix = xstrdup(ARRAY_FIRST(&list));
|
if (strncmp(tmp, s, strlen(s)) == 0) {
|
||||||
for (i = 1; i < ARRAY_LENGTH(&list); i++) {
|
list = xreallocarray(list, size + 1,
|
||||||
s = ARRAY_ITEM(&list, i);
|
sizeof *list);
|
||||||
|
list[size++] = tmp;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
j = strlen(s);
|
xasprintf(&tmp, "%s:%d", s_loop->name, wl->idx);
|
||||||
if (j > strlen(prefix))
|
if (strncmp(tmp, s, strlen(s)) == 0) {
|
||||||
j = strlen(prefix);
|
list = xreallocarray(list, size + 1,
|
||||||
for (; j > 0; j--) {
|
sizeof *list);
|
||||||
if (prefix[j - 1] != s[j - 1])
|
list[size++] = tmp;
|
||||||
prefix[j - 1] = '\0';
|
continue;
|
||||||
|
}
|
||||||
|
free(tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (size == 1) {
|
||||||
|
out = xstrdup(list[0]);
|
||||||
|
colon = " ";
|
||||||
|
} else if (size != 0)
|
||||||
|
out = status_prompt_complete_prefix(list, size);
|
||||||
|
if (out != NULL) {
|
||||||
|
xasprintf(&tmp, "-%c%s%s", copy[1], out, colon);
|
||||||
|
out = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
ARRAY_FREE(&list);
|
for (i = 0; i < size; i++)
|
||||||
return (prefix);
|
free((void *)list[i]);
|
||||||
|
|
||||||
|
found:
|
||||||
|
free(copy);
|
||||||
|
free(list);
|
||||||
|
return (out);
|
||||||
}
|
}
|
||||||
|
3
tmux.h
3
tmux.h
@ -43,9 +43,6 @@ extern char **environ;
|
|||||||
/* Default global configuration file. */
|
/* Default global configuration file. */
|
||||||
#define TMUX_CONF "/etc/tmux.conf"
|
#define TMUX_CONF "/etc/tmux.conf"
|
||||||
|
|
||||||
/* Default prompt history length. */
|
|
||||||
#define PROMPT_HISTORY 100
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Minimum layout cell size, NOT including separator line. The scroll region
|
* Minimum layout cell size, NOT including separator line. The scroll region
|
||||||
* cannot be one line in height so this must be at least two.
|
* cannot be one line in height so this must be at least two.
|
||||||
|
Loading…
Reference in New Issue
Block a user