mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 01:34:18 +00: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:
		
							
								
								
									
										266
									
								
								status.c
									
									
									
									
									
								
							
							
						
						
									
										266
									
								
								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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								xasprintf(&tmp, ":%d", wl->idx);
 | 
				
			||||||
 | 
								if (strncmp(tmp, s, strlen(s)) == 0) {
 | 
				
			||||||
 | 
									list = xreallocarray(list, size + 1,
 | 
				
			||||||
 | 
									    sizeof *list);
 | 
				
			||||||
 | 
									list[size++] = tmp;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								free(tmp);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							RB_FOREACH(s_loop, sessions, &sessions) {
 | 
				
			||||||
 | 
								RB_FOREACH(wl, winlinks, &s_loop->windows) {
 | 
				
			||||||
 | 
									w = wl->window;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									xasprintf(&tmp, "%s:%s", s_loop->name, w->name);
 | 
				
			||||||
 | 
									if (strncmp(tmp, s, strlen(s)) == 0) {
 | 
				
			||||||
 | 
										list = xreallocarray(list, size + 1,
 | 
				
			||||||
 | 
										    sizeof *list);
 | 
				
			||||||
 | 
										list[size++] = tmp;
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									free(tmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									xasprintf(&tmp, "%s:%d", s_loop->name, wl->idx);
 | 
				
			||||||
 | 
									if (strncmp(tmp, s, strlen(s)) == 0) {
 | 
				
			||||||
 | 
										list = xreallocarray(list, size + 1,
 | 
				
			||||||
 | 
										    sizeof *list);
 | 
				
			||||||
 | 
										list[size++] = tmp;
 | 
				
			||||||
 | 
										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;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If an exact match, return it, with a trailing space. */
 | 
						for (i = 0; i < size; i++)
 | 
				
			||||||
	if (ARRAY_LENGTH(&list) == 1) {
 | 
							free((void *)list[i]);
 | 
				
			||||||
		xasprintf(&s2, "%s ", ARRAY_FIRST(&list));
 | 
					 | 
				
			||||||
		ARRAY_FREE(&list);
 | 
					 | 
				
			||||||
		return (s2);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Now loop through the list and find the longest common prefix. */
 | 
					found:
 | 
				
			||||||
	prefix = xstrdup(ARRAY_FIRST(&list));
 | 
						free(copy);
 | 
				
			||||||
	for (i = 1; i < ARRAY_LENGTH(&list); i++) {
 | 
						free(list);
 | 
				
			||||||
		s = ARRAY_ITEM(&list, i);
 | 
						return (out);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		j = strlen(s);
 | 
					 | 
				
			||||||
		if (j > strlen(prefix))
 | 
					 | 
				
			||||||
			j = strlen(prefix);
 | 
					 | 
				
			||||||
		for (; j > 0; j--) {
 | 
					 | 
				
			||||||
			if (prefix[j - 1] != s[j - 1])
 | 
					 | 
				
			||||||
				prefix[j - 1] = '\0';
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ARRAY_FREE(&list);
 | 
					 | 
				
			||||||
	return (prefix);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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.
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user