mirror of
				https://github.com/tmux/tmux.git
				synced 2025-10-26 12:27:15 +00:00 
			
		
		
		
	Merge branch 'master' into sixel
This commit is contained in:
		
							
								
								
									
										8
									
								
								cfg.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								cfg.c
									
									
									
									
									
								
							| @@ -184,9 +184,9 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags, | ||||
|  | ||||
| 	new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0); | ||||
| 	if (item != NULL) | ||||
| 		cmdq_insert_after(item, new_item0); | ||||
| 		new_item0 = cmdq_insert_after(item, new_item0); | ||||
| 	else | ||||
| 		cmdq_append(NULL, new_item0); | ||||
| 		new_item0 = cmdq_append(NULL, new_item0); | ||||
| 	cmd_list_free(pr->cmdlist); | ||||
|  | ||||
| 	if (new_item != NULL) | ||||
| @@ -230,9 +230,9 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path, | ||||
|  | ||||
| 	new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0); | ||||
| 	if (item != NULL) | ||||
| 		cmdq_insert_after(item, new_item0); | ||||
| 		new_item0 = cmdq_insert_after(item, new_item0); | ||||
| 	else | ||||
| 		cmdq_append(NULL, new_item0); | ||||
| 		new_item0 = cmdq_append(NULL, new_item0); | ||||
| 	cmd_list_free(pr->cmdlist); | ||||
|  | ||||
| 	if (new_item != NULL) | ||||
|   | ||||
| @@ -52,7 +52,7 @@ const struct cmd_entry cmd_move_pane_entry = { | ||||
| 	.args = { "bdhvp:l:s:t:", 0, 0 }, | ||||
| 	.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE, | ||||
|  | ||||
| 	.source = { 's', CMD_FIND_PANE, 0 }, | ||||
| 	.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED }, | ||||
| 	.target = { 't', CMD_FIND_PANE, 0 }, | ||||
|  | ||||
| 	.flags = 0, | ||||
|   | ||||
							
								
								
									
										26
									
								
								cmd-queue.c
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								cmd-queue.c
									
									
									
									
									
								
							| @@ -53,12 +53,16 @@ cmdq_get(struct client *c) | ||||
| } | ||||
|  | ||||
| /* Append an item. */ | ||||
| void | ||||
| struct cmdq_item * | ||||
| cmdq_append(struct client *c, struct cmdq_item *item) | ||||
| { | ||||
| 	struct cmdq_list	*queue = cmdq_get(c); | ||||
| 	struct cmdq_item	*next; | ||||
|  | ||||
| 	TAILQ_FOREACH(next, queue, entry) { | ||||
| 		log_debug("%s %s: queue %s (%u)", __func__, cmdq_name(c), | ||||
| 		    next->name, next->group); | ||||
| 	} | ||||
| 	do { | ||||
| 		next = item->next; | ||||
| 		item->next = NULL; | ||||
| @@ -73,16 +77,21 @@ cmdq_append(struct client *c, struct cmdq_item *item) | ||||
|  | ||||
| 		item = next; | ||||
| 	} while (item != NULL); | ||||
| 	return (TAILQ_LAST(queue, cmdq_list)); | ||||
| } | ||||
|  | ||||
| /* Insert an item. */ | ||||
| void | ||||
| struct cmdq_item * | ||||
| cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item) | ||||
| { | ||||
| 	struct client		*c = after->client; | ||||
| 	struct cmdq_list	*queue = after->queue; | ||||
| 	struct cmdq_item	*next; | ||||
|  | ||||
| 	TAILQ_FOREACH(next, queue, entry) { | ||||
| 		log_debug("%s %s: queue %s (%u)", __func__, cmdq_name(c), | ||||
| 		    next->name, next->group); | ||||
| 	} | ||||
| 	do { | ||||
| 		next = item->next; | ||||
| 		item->next = after->next; | ||||
| @@ -100,6 +109,7 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item) | ||||
| 		after = item; | ||||
| 		item = next; | ||||
| 	} while (item != NULL); | ||||
| 	return (after); | ||||
| } | ||||
|  | ||||
| /* Insert a hook. */ | ||||
| @@ -143,11 +153,10 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item, | ||||
|  | ||||
| 		new_item = cmdq_get_command(cmdlist, fs, NULL, CMDQ_NOHOOKS); | ||||
| 		cmdq_format(new_item, "hook", "%s", name); | ||||
| 		if (item != NULL) { | ||||
| 			cmdq_insert_after(item, new_item); | ||||
| 			item = new_item; | ||||
| 		} else | ||||
| 			cmdq_append(NULL, new_item); | ||||
| 		if (item != NULL) | ||||
| 			item = cmdq_insert_after(item, new_item); | ||||
| 		else | ||||
| 			item = cmdq_append(NULL, new_item); | ||||
|  | ||||
| 		a = options_array_next(a); | ||||
| 	} | ||||
| @@ -542,6 +551,9 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...) | ||||
| 			msg = utf8_sanitize(tmp); | ||||
| 			free(tmp); | ||||
| 		} | ||||
| 		if (c->flags & CLIENT_CONTROL) | ||||
| 			file_print(c, "%s\n", msg); | ||||
| 		else | ||||
| 			file_error(c, "%s\n", msg); | ||||
| 		c->retval = 1; | ||||
| 	} else { | ||||
|   | ||||
| @@ -113,6 +113,7 @@ cmd_source_file_done(struct client *c, const char *path, int error, | ||||
| static void | ||||
| cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path) | ||||
| { | ||||
| 	log_debug("%s: %s", __func__, path); | ||||
| 	cdata->files = xreallocarray(cdata->files, cdata->nfiles + 1, | ||||
| 	    sizeof *cdata->files); | ||||
| 	cdata->files[cdata->nfiles++] = xstrdup(path); | ||||
| @@ -123,7 +124,6 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item) | ||||
| { | ||||
| 	struct args			*args = self->args; | ||||
| 	struct cmd_source_file_data	*cdata; | ||||
| 	int				 flags = 0; | ||||
| 	struct client			*c = item->client; | ||||
| 	enum cmd_retval			 retval = CMD_RETURN_NORMAL; | ||||
| 	char				*pattern, *cwd; | ||||
| @@ -159,7 +159,7 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item) | ||||
|  | ||||
| 		if ((result = glob(pattern, 0, NULL, &g)) != 0) { | ||||
| 			if (result != GLOB_NOMATCH || | ||||
| 			    (~flags & CMD_PARSE_QUIET)) { | ||||
| 			    (~cdata->flags & CMD_PARSE_QUIET)) { | ||||
| 				if (result == GLOB_NOMATCH) | ||||
| 					error = strerror(ENOENT); | ||||
| 				else if (result == GLOB_NOSPACE) | ||||
|   | ||||
							
								
								
									
										2
									
								
								cmd.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								cmd.c
									
									
									
									
									
								
							| @@ -660,7 +660,7 @@ char * | ||||
| cmd_template_replace(const char *template, const char *s, int idx) | ||||
| { | ||||
| 	char		 ch, *buf; | ||||
| 	const char	*ptr, *cp, quote[] = "\"\\$;"; | ||||
| 	const char	*ptr, *cp, quote[] = "\"\\$;~"; | ||||
| 	int		 replaced, quoted; | ||||
| 	size_t		 len; | ||||
|  | ||||
|   | ||||
| @@ -849,8 +849,10 @@ format_trim_left(const char *expanded, u_int limit) | ||||
| 					out += ud.size; | ||||
| 				} | ||||
| 				width += ud.width; | ||||
| 			} else | ||||
| 			} else { | ||||
| 				cp -= ud.have; | ||||
| 				cp++; | ||||
| 			} | ||||
| 		} else if (*cp > 0x1f && *cp < 0x7f) { | ||||
| 			if (width + 1 <= limit) | ||||
| 				*out++ = *cp; | ||||
| @@ -896,8 +898,10 @@ format_trim_right(const char *expanded, u_int limit) | ||||
| 					out += ud.size; | ||||
| 				} | ||||
| 				width += ud.width; | ||||
| 			} else | ||||
| 			} else { | ||||
| 				cp -= ud.have; | ||||
| 				cp++; | ||||
| 			} | ||||
| 		} else if (*cp > 0x1f && *cp < 0x7f) { | ||||
| 			if (width >= skip) | ||||
| 				*out++ = *cp; | ||||
|   | ||||
							
								
								
									
										220
									
								
								format.c
									
									
									
									
									
								
							
							
						
						
									
										220
									
								
								format.c
									
									
									
									
									
								
							| @@ -456,6 +456,35 @@ format_cb_pid(__unused struct format_tree *ft, struct format_entry *fe) | ||||
| 	xasprintf(&fe->value, "%ld", (long)getpid()); | ||||
| } | ||||
|  | ||||
| /* Callback for session_attached_list. */ | ||||
| static void | ||||
| format_cb_session_attached_list(struct format_tree *ft, struct format_entry *fe) | ||||
| { | ||||
| 	struct session	*s = ft->s; | ||||
| 	struct client	*loop; | ||||
| 	struct evbuffer	*buffer; | ||||
| 	int		 size; | ||||
|  | ||||
| 	if (s == NULL) | ||||
| 		return; | ||||
|  | ||||
| 	buffer = evbuffer_new(); | ||||
| 	if (buffer == NULL) | ||||
| 		fatalx("out of memory"); | ||||
|  | ||||
| 	TAILQ_FOREACH(loop, &clients, entry) { | ||||
| 		if (loop->session == s) { | ||||
| 			if (EVBUFFER_LENGTH(buffer) > 0) | ||||
| 				evbuffer_add(buffer, ",", 1); | ||||
| 			evbuffer_add_printf(buffer, "%s", loop->name); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if ((size = EVBUFFER_LENGTH(buffer)) != 0) | ||||
| 		xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer)); | ||||
| 	evbuffer_free(buffer); | ||||
| } | ||||
|  | ||||
| /* Callback for session_alerts. */ | ||||
| static void | ||||
| format_cb_session_alerts(struct format_tree *ft, struct format_entry *fe) | ||||
| @@ -528,6 +557,128 @@ format_cb_window_stack_index(struct format_tree *ft, struct format_entry *fe) | ||||
| 		fe->value = xstrdup("0"); | ||||
| } | ||||
|  | ||||
| /* Callback for window_linked_sessions_list. */ | ||||
| static void | ||||
| format_cb_window_linked_sessions_list(struct format_tree *ft, | ||||
|     struct format_entry *fe) | ||||
| { | ||||
| 	struct window	*w = ft->wl->window; | ||||
| 	struct winlink	*wl; | ||||
| 	struct evbuffer	*buffer; | ||||
| 	int		 size; | ||||
|  | ||||
| 	buffer = evbuffer_new(); | ||||
| 	if (buffer == NULL) | ||||
| 		fatalx("out of memory"); | ||||
|  | ||||
| 	TAILQ_FOREACH(wl, &w->winlinks, wentry) { | ||||
| 		if (EVBUFFER_LENGTH(buffer) > 0) | ||||
| 			evbuffer_add(buffer, ",", 1); | ||||
| 		evbuffer_add_printf(buffer, "%s", wl->session->name); | ||||
| 	} | ||||
|  | ||||
| 	if ((size = EVBUFFER_LENGTH(buffer)) != 0) | ||||
| 		xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer)); | ||||
| 	evbuffer_free(buffer); | ||||
| } | ||||
|  | ||||
| /* Callback for window_active_sessions. */ | ||||
| static void | ||||
| format_cb_window_active_sessions(struct format_tree *ft, | ||||
|     struct format_entry *fe) | ||||
| { | ||||
| 	struct window	*w = ft->wl->window; | ||||
| 	struct winlink	*wl; | ||||
| 	u_int		 n = 0; | ||||
|  | ||||
| 	TAILQ_FOREACH(wl, &w->winlinks, wentry) { | ||||
| 		if (wl->session->curw == wl) | ||||
| 			n++; | ||||
| 	} | ||||
|  | ||||
| 	xasprintf(&fe->value, "%u", n); | ||||
| } | ||||
|  | ||||
| /* Callback for window_active_sessions_list. */ | ||||
| static void | ||||
| format_cb_window_active_sessions_list(struct format_tree *ft, | ||||
|     struct format_entry *fe) | ||||
| { | ||||
| 	struct window	*w = ft->wl->window; | ||||
| 	struct winlink	*wl; | ||||
| 	struct evbuffer	*buffer; | ||||
| 	int		 size; | ||||
|  | ||||
| 	buffer = evbuffer_new(); | ||||
| 	if (buffer == NULL) | ||||
| 		fatalx("out of memory"); | ||||
|  | ||||
| 	TAILQ_FOREACH(wl, &w->winlinks, wentry) { | ||||
| 		if (wl->session->curw == wl) { | ||||
| 			if (EVBUFFER_LENGTH(buffer) > 0) | ||||
| 				evbuffer_add(buffer, ",", 1); | ||||
| 			evbuffer_add_printf(buffer, "%s", wl->session->name); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if ((size = EVBUFFER_LENGTH(buffer)) != 0) | ||||
| 		xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer)); | ||||
| 	evbuffer_free(buffer); | ||||
| } | ||||
|  | ||||
| /* Callback for window_active_clients. */ | ||||
| static void | ||||
| format_cb_window_active_clients(struct format_tree *ft, struct format_entry *fe) | ||||
| { | ||||
| 	struct window	*w = ft->wl->window; | ||||
| 	struct client	*loop; | ||||
| 	struct session	*client_session; | ||||
| 	u_int		 n = 0; | ||||
|  | ||||
| 	TAILQ_FOREACH(loop, &clients, entry) { | ||||
| 		client_session = loop->session; | ||||
| 		if (client_session == NULL) | ||||
| 			continue; | ||||
|  | ||||
| 		if (w == client_session->curw->window) | ||||
| 			n++; | ||||
| 	} | ||||
|  | ||||
| 	xasprintf(&fe->value, "%u", n); | ||||
| } | ||||
|  | ||||
| /* Callback for window_active_clients_list. */ | ||||
| static void | ||||
| format_cb_window_active_clients_list(struct format_tree *ft, | ||||
|     struct format_entry *fe) | ||||
| { | ||||
| 	struct window	*w = ft->wl->window; | ||||
| 	struct client	*loop; | ||||
| 	struct session	*client_session; | ||||
| 	struct evbuffer	*buffer; | ||||
| 	int		 size; | ||||
|  | ||||
| 	buffer = evbuffer_new(); | ||||
| 	if (buffer == NULL) | ||||
| 		fatalx("out of memory"); | ||||
|  | ||||
| 	TAILQ_FOREACH(loop, &clients, entry) { | ||||
| 		client_session = loop->session; | ||||
| 		if (client_session == NULL) | ||||
| 			continue; | ||||
|  | ||||
| 		if (w == client_session->curw->window) { | ||||
| 			if (EVBUFFER_LENGTH(buffer) > 0) | ||||
| 				evbuffer_add(buffer, ",", 1); | ||||
| 			evbuffer_add_printf(buffer, "%s", loop->name); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if ((size = EVBUFFER_LENGTH(buffer)) != 0) | ||||
| 		xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer)); | ||||
| 	evbuffer_free(buffer); | ||||
| } | ||||
|  | ||||
| /* Callback for window_layout. */ | ||||
| static void | ||||
| format_cb_window_layout(struct format_tree *ft, struct format_entry *fe) | ||||
| @@ -677,11 +828,52 @@ format_cb_session_group_list(struct format_tree *ft, struct format_entry *fe) | ||||
| 	buffer = evbuffer_new(); | ||||
| 	if (buffer == NULL) | ||||
| 		fatalx("out of memory"); | ||||
|  | ||||
| 	TAILQ_FOREACH(loop, &sg->sessions, gentry) { | ||||
| 		if (EVBUFFER_LENGTH(buffer) > 0) | ||||
| 			evbuffer_add(buffer, ",", 1); | ||||
| 		evbuffer_add_printf(buffer, "%s", loop->name); | ||||
| 	} | ||||
|  | ||||
| 	if ((size = EVBUFFER_LENGTH(buffer)) != 0) | ||||
| 		xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer)); | ||||
| 	evbuffer_free(buffer); | ||||
| } | ||||
|  | ||||
| /* Callback for session_group_attached_list. */ | ||||
| static void | ||||
| format_cb_session_group_attached_list(struct format_tree *ft, | ||||
|     struct format_entry *fe) | ||||
| { | ||||
| 	struct session		*s = ft->s, *client_session, *session_loop; | ||||
| 	struct session_group	*sg; | ||||
| 	struct client		*loop; | ||||
| 	struct evbuffer		*buffer; | ||||
| 	int			 size; | ||||
|  | ||||
| 	if (s == NULL) | ||||
| 		return; | ||||
| 	sg = session_group_contains(s); | ||||
| 	if (sg == NULL) | ||||
| 		return; | ||||
|  | ||||
| 	buffer = evbuffer_new(); | ||||
| 	if (buffer == NULL) | ||||
| 		fatalx("out of memory"); | ||||
|  | ||||
| 	TAILQ_FOREACH(loop, &clients, entry) { | ||||
| 		client_session = loop->session; | ||||
| 		if (client_session == NULL) | ||||
| 			continue; | ||||
| 		TAILQ_FOREACH(session_loop, &sg->sessions, gentry) { | ||||
| 			if (session_loop == client_session){ | ||||
| 				if (EVBUFFER_LENGTH(buffer) > 0) | ||||
| 					evbuffer_add(buffer, ",", 1); | ||||
| 				evbuffer_add_printf(buffer, "%s", loop->name); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if ((size = EVBUFFER_LENGTH(buffer)) != 0) | ||||
| 		xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer)); | ||||
| 	evbuffer_free(buffer); | ||||
| @@ -974,12 +1166,12 @@ format_each(struct format_tree *ft, void (*cb)(const char *, const char *, | ||||
|     void *), void *arg) | ||||
| { | ||||
| 	struct format_entry	*fe; | ||||
| 	static char		 s[64]; | ||||
| 	char			 s[64]; | ||||
|  | ||||
| 	RB_FOREACH(fe, format_entry_tree, &ft->tree) { | ||||
| 		if (fe->t != 0) { | ||||
| 			xsnprintf(s, sizeof s, "%lld", (long long)fe->t); | ||||
| 			cb(fe->key, fe->value, s); | ||||
| 			cb(fe->key, s, arg); | ||||
| 		} else { | ||||
| 			if (fe->value == NULL && fe->cb != NULL) { | ||||
| 				fe->cb(ft, fe); | ||||
| @@ -1022,8 +1214,7 @@ format_add(struct format_tree *ft, const char *key, const char *fmt, ...) | ||||
| static void | ||||
| format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv) | ||||
| { | ||||
| 	struct format_entry	*fe; | ||||
| 	struct format_entry	*fe_now; | ||||
| 	struct format_entry	*fe, *fe_now; | ||||
|  | ||||
| 	fe = xmalloc(sizeof *fe); | ||||
| 	fe->key = xstrdup(key); | ||||
| @@ -2141,8 +2332,14 @@ format_defaults_session(struct format_tree *ft, struct session *s) | ||||
| 		format_add(ft, "session_group", "%s", sg->name); | ||||
| 		format_add(ft, "session_group_size", "%u", | ||||
| 		    session_group_count (sg)); | ||||
| 		format_add(ft, "session_group_attached", "%u", | ||||
| 		    session_group_attached_count (sg)); | ||||
| 		format_add(ft, "session_group_many_attached", "%u", | ||||
| 		    session_group_attached_count (sg) > 1); | ||||
| 		format_add_cb(ft, "session_group_list", | ||||
| 		    format_cb_session_group_list); | ||||
| 		format_add_cb(ft, "session_group_attached_list", | ||||
| 		    format_cb_session_group_attached_list); | ||||
| 	} | ||||
|  | ||||
| 	format_add_tv(ft, "session_created", &s->creation_time); | ||||
| @@ -2151,6 +2348,8 @@ format_defaults_session(struct format_tree *ft, struct session *s) | ||||
|  | ||||
| 	format_add(ft, "session_attached", "%u", s->attached); | ||||
| 	format_add(ft, "session_many_attached", "%d", s->attached > 1); | ||||
| 	format_add_cb(ft, "session_attached_list", | ||||
| 	    format_cb_session_attached_list); | ||||
|  | ||||
| 	format_add_cb(ft, "session_alerts", format_cb_session_alerts); | ||||
| 	format_add_cb(ft, "session_stack", format_cb_session_stack); | ||||
| @@ -2265,6 +2464,14 @@ format_defaults_winlink(struct format_tree *ft, struct winlink *wl) | ||||
| 	format_add_cb(ft, "window_stack_index", format_cb_window_stack_index); | ||||
| 	format_add(ft, "window_flags", "%s", window_printable_flags(wl)); | ||||
| 	format_add(ft, "window_active", "%d", wl == s->curw); | ||||
| 	format_add_cb(ft, "window_active_sessions", | ||||
| 	    format_cb_window_active_sessions); | ||||
| 	format_add_cb(ft, "window_active_sessions_list", | ||||
| 	    format_cb_window_active_sessions_list); | ||||
| 	format_add_cb(ft, "window_active_clients", | ||||
| 	    format_cb_window_active_clients); | ||||
| 	format_add_cb(ft, "window_active_clients_list", | ||||
| 	    format_cb_window_active_clients_list); | ||||
|  | ||||
| 	format_add(ft, "window_start_flag", "%d", | ||||
| 	    !!(wl == RB_MIN(winlinks, &s->windows))); | ||||
| @@ -2285,6 +2492,11 @@ format_defaults_winlink(struct format_tree *ft, struct winlink *wl) | ||||
| 	format_add(ft, "window_last_flag", "%d", | ||||
| 	    !!(wl == TAILQ_FIRST(&s->lastw))); | ||||
| 	format_add(ft, "window_linked", "%d", session_is_linked(s, wl->window)); | ||||
|  | ||||
| 	format_add_cb(ft, "window_linked_sessions_list", | ||||
| 	    format_cb_window_linked_sessions_list); | ||||
| 	format_add(ft, "window_linked_sessions", "%u", | ||||
| 	    wl->window->references); | ||||
| } | ||||
|  | ||||
| /* Set default format keys for a window pane. */ | ||||
|   | ||||
| @@ -85,6 +85,14 @@ key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2) | ||||
| 	return (0); | ||||
| } | ||||
|  | ||||
| static void | ||||
| key_bindings_free(struct key_table *table, struct key_binding *bd) | ||||
| { | ||||
| 	RB_REMOVE(key_bindings, &table->key_bindings, bd); | ||||
| 	cmd_list_free(bd->cmdlist); | ||||
| 	free(bd); | ||||
| } | ||||
|  | ||||
| struct key_table * | ||||
| key_bindings_get_table(const char *name, int create) | ||||
| { | ||||
| @@ -126,11 +134,8 @@ key_bindings_unref_table(struct key_table *table) | ||||
| 	if (--table->references != 0) | ||||
| 		return; | ||||
|  | ||||
| 	RB_FOREACH_SAFE(bd, key_bindings, &table->key_bindings, bd1) { | ||||
| 		RB_REMOVE(key_bindings, &table->key_bindings, bd); | ||||
| 		cmd_list_free(bd->cmdlist); | ||||
| 		free(bd); | ||||
| 	} | ||||
| 	RB_FOREACH_SAFE(bd, key_bindings, &table->key_bindings, bd1) | ||||
| 		key_bindings_free(table, bd); | ||||
|  | ||||
| 	free((void *)table->name); | ||||
| 	free(table); | ||||
| @@ -162,17 +167,13 @@ key_bindings_add(const char *name, key_code key, int repeat, | ||||
|     struct cmd_list *cmdlist) | ||||
| { | ||||
| 	struct key_table	*table; | ||||
| 	struct key_binding	 bd_find, *bd; | ||||
| 	struct key_binding	*bd; | ||||
|  | ||||
| 	table = key_bindings_get_table(name, 1); | ||||
|  | ||||
| 	bd_find.key = (key & ~KEYC_XTERM); | ||||
| 	bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); | ||||
| 	if (bd != NULL) { | ||||
| 		RB_REMOVE(key_bindings, &table->key_bindings, bd); | ||||
| 		cmd_list_free(bd->cmdlist); | ||||
| 		free(bd); | ||||
| 	} | ||||
| 	bd = key_bindings_get(table, key & ~KEYC_XTERM); | ||||
| 	if (bd != NULL) | ||||
| 		key_bindings_free(table, bd); | ||||
|  | ||||
| 	bd = xcalloc(1, sizeof *bd); | ||||
| 	bd->key = key; | ||||
| @@ -187,20 +188,16 @@ void | ||||
| key_bindings_remove(const char *name, key_code key) | ||||
| { | ||||
| 	struct key_table	*table; | ||||
| 	struct key_binding	 bd_find, *bd; | ||||
| 	struct key_binding	*bd; | ||||
|  | ||||
| 	table = key_bindings_get_table(name, 0); | ||||
| 	if (table == NULL) | ||||
| 		return; | ||||
|  | ||||
| 	bd_find.key = (key & ~KEYC_XTERM); | ||||
| 	bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); | ||||
| 	bd = key_bindings_get(table, key & ~KEYC_XTERM); | ||||
| 	if (bd == NULL) | ||||
| 		return; | ||||
|  | ||||
| 	RB_REMOVE(key_bindings, &table->key_bindings, bd); | ||||
| 	cmd_list_free(bd->cmdlist); | ||||
| 	free(bd); | ||||
| 	key_bindings_free(table, bd); | ||||
|  | ||||
| 	if (RB_EMPTY(&table->key_bindings)) { | ||||
| 		RB_REMOVE(key_tables, &key_tables, table); | ||||
| @@ -520,8 +517,8 @@ key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item, | ||||
| 			new_item->shared->flags |= CMDQ_SHARED_REPEAT; | ||||
| 	} | ||||
| 	if (item != NULL) | ||||
| 		cmdq_insert_after(item, new_item); | ||||
| 		new_item = cmdq_insert_after(item, new_item); | ||||
| 	else | ||||
| 		cmdq_append(c, new_item); | ||||
| 		new_item = cmdq_append(c, new_item); | ||||
| 	return (new_item); | ||||
| } | ||||
|   | ||||
							
								
								
									
										4
									
								
								notify.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								notify.c
									
									
									
									
									
								
							| @@ -89,9 +89,7 @@ notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne) | ||||
| 		new_item = cmdq_get_command(cmdlist, &fs, NULL, CMDQ_NOHOOKS); | ||||
| 		cmdq_format(new_item, "hook", "%s", ne->name); | ||||
| 		notify_hook_formats(new_item, s, w, ne->pane); | ||||
|  | ||||
| 		cmdq_insert_after(item, new_item); | ||||
| 		item = new_item; | ||||
| 		item = cmdq_insert_after(item, new_item); | ||||
|  | ||||
| 		a = options_array_next(a); | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										13
									
								
								session.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								session.c
									
									
									
									
									
								
							| @@ -572,6 +572,19 @@ session_group_count(struct session_group *sg) | ||||
| 	return (n); | ||||
| } | ||||
|  | ||||
| /* Count number of clients attached to sessions in session group. */ | ||||
| u_int | ||||
| session_group_attached_count(struct session_group *sg) | ||||
| { | ||||
| 	struct session	*s; | ||||
| 	u_int		 n; | ||||
|  | ||||
| 	n = 0; | ||||
| 	TAILQ_FOREACH(s, &sg->sessions, gentry) | ||||
| 		n += s->attached; | ||||
| 	return (n); | ||||
| } | ||||
|  | ||||
| /* Synchronize a session to its session group. */ | ||||
| void | ||||
| session_group_synchronize_to(struct session *s) | ||||
|   | ||||
							
								
								
									
										5
									
								
								spawn.c
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								spawn.c
									
									
									
									
									
								
							| @@ -78,6 +78,8 @@ spawn_log(const char *from, struct spawn_context *sc) | ||||
| struct winlink * | ||||
| spawn_window(struct spawn_context *sc, char **cause) | ||||
| { | ||||
| 	struct cmdq_item	*item = sc->item; | ||||
| 	struct client		*c = item->client; | ||||
| 	struct session		*s = sc->s; | ||||
| 	struct window		*w; | ||||
| 	struct window_pane	*wp; | ||||
| @@ -180,7 +182,8 @@ spawn_window(struct spawn_context *sc, char **cause) | ||||
| 	/* Set the name of the new window. */ | ||||
| 	if (~sc->flags & SPAWN_RESPAWN) { | ||||
| 		if (sc->name != NULL) { | ||||
| 			w->name = xstrdup(sc->name); | ||||
| 			w->name = format_single(item, sc->name, c, s, NULL, | ||||
| 			    NULL); | ||||
| 			options_set_number(w->options, "automatic-rename", 0); | ||||
| 		} else | ||||
| 			w->name = xstrdup(default_window_name(w)); | ||||
|   | ||||
							
								
								
									
										51
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								tmux.1
									
									
									
									
									
								
							| @@ -938,7 +938,9 @@ If | ||||
| is specified, any other clients attached to the session are detached. | ||||
| If | ||||
| .Fl x | ||||
| is given, send SIGHUP to the parent process of the client as well as | ||||
| is given, send | ||||
| .Dv SIGHUP | ||||
| to the parent process of the client as well as | ||||
| detaching the client, typically causing it to exit. | ||||
| .Fl r | ||||
| signifies the client is read-only (only keys bound to the | ||||
| @@ -989,7 +991,9 @@ option kills all but the client given with | ||||
| .Fl t . | ||||
| If | ||||
| .Fl P | ||||
| is given, send SIGHUP to the parent process of the client, typically causing it | ||||
| is given, send | ||||
| .Dv SIGHUP | ||||
| to the parent process of the client, typically causing it | ||||
| to exit. | ||||
| With | ||||
| .Fl E , | ||||
| @@ -4316,10 +4320,14 @@ The following variables are available, where appropriate: | ||||
| .It Li "session_activity" Ta "" Ta "Time of session last activity" | ||||
| .It Li "session_alerts" Ta "" Ta "List of window indexes with alerts" | ||||
| .It Li "session_attached" Ta "" Ta "Number of clients session is attached to" | ||||
| .It Li "session_attached_list" Ta "" Ta "List of clients session is attached to" | ||||
| .It Li "session_created" Ta "" Ta "Time session created" | ||||
| .It Li "session_format" Ta "" Ta "1 if format is for a session" | ||||
| .It Li "session_group" Ta "" Ta "Name of session group" | ||||
| .It Li "session_group_attached" Ta "" Ta "Number of clients sessions in group are attached to" | ||||
| .It Li "session_group_attached_list" Ta "" Ta "List of clients sessions in group are attached to" | ||||
| .It Li "session_group_list" Ta "" Ta "List of sessions in group" | ||||
| .It Li "session_group_many_attached" Ta "" Ta "1 if multiple clients attached to sessions in group" | ||||
| .It Li "session_group_size" Ta "" Ta "Size of session group" | ||||
| .It Li "session_grouped" Ta "" Ta "1 if session in a group" | ||||
| .It Li "session_id" Ta "" Ta "Unique session ID" | ||||
| @@ -4332,6 +4340,10 @@ The following variables are available, where appropriate: | ||||
| .It Li "start_time" Ta "" Ta "Server start time" | ||||
| .It Li "version" Ta "" Ta "Server version" | ||||
| .It Li "window_active" Ta "" Ta "1 if window active" | ||||
| .It Li "window_active_clients" Ta "" Ta "Number of clients viewing this window" | ||||
| .It Li "window_active_clients_list" Ta "" Ta "List of clients viewing this window" | ||||
| .It Li "window_active_sessions" Ta "" Ta "Number of sessions on which this window is active" | ||||
| .It Li "window_active_sessions_list" Ta "" Ta "List of sessions on which this window is active" | ||||
| .It Li "window_activity" Ta "" Ta "Time of window last activity" | ||||
| .It Li "window_activity_flag" Ta "" Ta "1 if window has activity" | ||||
| .It Li "window_bell_flag" Ta "" Ta "1 if window has bell" | ||||
| @@ -4347,6 +4359,8 @@ The following variables are available, where appropriate: | ||||
| .It Li "window_last_flag" Ta "" Ta "1 if window is the last used" | ||||
| .It Li "window_layout" Ta "" Ta "Window layout description, ignoring zoomed window panes" | ||||
| .It Li "window_linked" Ta "" Ta "1 if window is linked across sessions" | ||||
| .It Li "window_linked_sessions" Ta "" Ta "Number of sessions this window is linked to" | ||||
| .It Li "window_linked_sessions_list" Ta "" Ta "List of sessions this window is linked to" | ||||
| .It Li "window_marked_flag" Ta "" Ta "1 if window contains the marked pane" | ||||
| .It Li "window_name" Ta "#W" Ta "Name of window" | ||||
| .It Li "window_offset_x" Ta "" Ta "X offset into window if larger than client" | ||||
| @@ -4367,7 +4381,7 @@ interface, for example | ||||
| .Ic status-style | ||||
| for the status line. | ||||
| In addition, embedded styles may be specified in format options, such as | ||||
| .Ic status-left-format , | ||||
| .Ic status-left , | ||||
| by enclosing them in | ||||
| .Ql #[ | ||||
| and | ||||
| @@ -5145,6 +5159,37 @@ channel are made to wait until the channel is unlocked with | ||||
| .Ic wait-for | ||||
| .Fl U . | ||||
| .El | ||||
| .Sh EXIT MESSAGES | ||||
| When a | ||||
| .Nm | ||||
| client detaches, it prints a message. | ||||
| This may be one of: | ||||
| .Bl -tag -width Ds | ||||
| .It [detached (from session ...)] | ||||
| The client was detached normally. | ||||
| .It [detached and SIGHUP] | ||||
| The client was detached and its parent sent the | ||||
| .Dv SIGHUP | ||||
| signal (for example with | ||||
| .Ic detach-client | ||||
| .Fl P ) . | ||||
| .It [lost tty] | ||||
| The client's | ||||
| .Xr tty 4 | ||||
| or | ||||
| .Xr pty 4 | ||||
| was unexpectedly destroyed. | ||||
| .It [terminated] | ||||
| The client was killed with | ||||
| .Dv SIGTERM . | ||||
| .It [exited] | ||||
| The server exited when it had no sessions. | ||||
| .It [server exited] | ||||
| The server exited when it received | ||||
| .Dv SIGTERM . | ||||
| .It [server exited unexpectedly] | ||||
| The server crashed or otherwise exited without telling the client the reason. | ||||
| .El | ||||
| .Sh TERMINFO EXTENSIONS | ||||
| .Nm | ||||
| understands some unofficial extensions to | ||||
|   | ||||
							
								
								
									
										8
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								tmux.h
									
									
									
									
									
								
							| @@ -1620,7 +1620,8 @@ struct client { | ||||
| #define CLIENT_NOSIZEFLAGS	\ | ||||
| 	(CLIENT_DEAD|		\ | ||||
| 	 CLIENT_SUSPENDED|	\ | ||||
| 	 CLIENT_DETACHING) | ||||
| 	 CLIENT_DETACHING|	\ | ||||
| 	 CLIENT_READONLY) | ||||
| 	int		 flags; | ||||
| 	struct key_table *keytable; | ||||
|  | ||||
| @@ -2157,8 +2158,8 @@ struct cmdq_item *cmdq_get_command(struct cmd_list *, struct cmd_find_state *, | ||||
| #define cmdq_get_callback(cb, data) cmdq_get_callback1(#cb, cb, data) | ||||
| struct cmdq_item *cmdq_get_callback1(const char *, cmdq_cb, void *); | ||||
| struct cmdq_item *cmdq_get_error(const char *); | ||||
| void		 cmdq_insert_after(struct cmdq_item *, struct cmdq_item *); | ||||
| void		 cmdq_append(struct client *, struct cmdq_item *); | ||||
| struct cmdq_item *cmdq_insert_after(struct cmdq_item *, struct cmdq_item *); | ||||
| struct cmdq_item *cmdq_append(struct client *, struct cmdq_item *); | ||||
| void		 cmdq_insert_hook(struct session *, struct cmdq_item *, | ||||
| 		     struct cmd_find_state *, const char *, ...); | ||||
| void		 cmdq_continue(struct cmdq_item *); | ||||
| @@ -2714,6 +2715,7 @@ void		 session_group_add(struct session_group *, struct session *); | ||||
| void		 session_group_synchronize_to(struct session *); | ||||
| void		 session_group_synchronize_from(struct session *); | ||||
| u_int		 session_group_count(struct session_group *); | ||||
| u_int		 session_group_attached_count(struct session_group *); | ||||
| void		 session_renumber_windows(struct session *); | ||||
|  | ||||
| /* utf8.c */ | ||||
|   | ||||
							
								
								
									
										393
									
								
								window-copy.c
									
									
									
									
									
								
							
							
						
						
									
										393
									
								
								window-copy.c
									
									
									
									
									
								
							| @@ -19,6 +19,7 @@ | ||||
| #include <sys/types.h> | ||||
|  | ||||
| #include <ctype.h> | ||||
| #include <regex.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| @@ -57,18 +58,29 @@ static int	window_copy_search_lr(struct grid *, struct grid *, u_int *, | ||||
| 		    u_int, u_int, u_int, int); | ||||
| static int	window_copy_search_rl(struct grid *, struct grid *, u_int *, | ||||
| 		    u_int, u_int, u_int, int); | ||||
| static int	window_copy_search_lr_regex(struct grid *, struct grid *, | ||||
| 		    u_int *, u_int *, u_int, u_int, u_int, int); | ||||
| static int	window_copy_search_rl_regex(struct grid *, struct grid *, | ||||
| 		    u_int *, u_int *, u_int, u_int, u_int, int); | ||||
| static int	window_copy_last_regex(struct grid *gd, u_int py, u_int first, | ||||
| 		    u_int last, u_int len, u_int *ppx, u_int *psx, | ||||
| 		    const char *buf, const regex_t *preg, int eflags); | ||||
| static char    *window_copy_stringify(struct grid *, u_int, u_int, u_int, | ||||
| 		    char *, u_int *); | ||||
| static void	window_copy_cstrtocellpos(struct grid *, u_int, u_int *, u_int *, | ||||
| 		    const char *str); | ||||
| static int	window_copy_search_marks(struct window_mode_entry *, | ||||
| 		    struct screen *); | ||||
| 		    struct screen *, int); | ||||
| static void	window_copy_clear_marks(struct window_mode_entry *); | ||||
| static void	window_copy_move_left(struct screen *, u_int *, u_int *, int); | ||||
| static void	window_copy_move_right(struct screen *, u_int *, u_int *, int); | ||||
| static int	window_copy_is_lowercase(const char *); | ||||
| static int	window_copy_search_jump(struct window_mode_entry *, | ||||
| 		    struct grid *, struct grid *, u_int, u_int, u_int, int, int, | ||||
| 		    int); | ||||
| static int	window_copy_search(struct window_mode_entry *, int); | ||||
| static int	window_copy_search_up(struct window_mode_entry *); | ||||
| static int	window_copy_search_down(struct window_mode_entry *); | ||||
| 		    int, int); | ||||
| static int	window_copy_search(struct window_mode_entry *, int, int); | ||||
| static int	window_copy_search_up(struct window_mode_entry *, int); | ||||
| static int	window_copy_search_down(struct window_mode_entry *, int); | ||||
| static void	window_copy_goto_line(struct window_mode_entry *, const char *); | ||||
| static void	window_copy_update_cursor(struct window_mode_entry *, u_int, | ||||
| 		    u_int); | ||||
| @@ -622,7 +634,7 @@ window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy) | ||||
| 	screen_write_stop(&ctx); | ||||
|  | ||||
| 	if (search) | ||||
| 		window_copy_search_marks(wme, NULL); | ||||
| 		window_copy_search_marks(wme, NULL, 1); | ||||
| 	data->searchx = data->cx; | ||||
| 	data->searchy = data->cy; | ||||
| 	data->searcho = data->oy; | ||||
| @@ -1458,10 +1470,10 @@ window_copy_cmd_search_again(struct window_copy_cmd_state *cs) | ||||
|  | ||||
| 	if (data->searchtype == WINDOW_COPY_SEARCHUP) { | ||||
| 		for (; np != 0; np--) | ||||
| 			window_copy_search_up(wme); | ||||
| 			window_copy_search_up(wme, 1); | ||||
| 	} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) { | ||||
| 		for (; np != 0; np--) | ||||
| 			window_copy_search_down(wme); | ||||
| 			window_copy_search_down(wme, 1); | ||||
| 	} | ||||
| 	return (WINDOW_COPY_CMD_NOTHING); | ||||
| } | ||||
| @@ -1475,10 +1487,10 @@ window_copy_cmd_search_reverse(struct window_copy_cmd_state *cs) | ||||
|  | ||||
| 	if (data->searchtype == WINDOW_COPY_SEARCHUP) { | ||||
| 		for (; np != 0; np--) | ||||
| 			window_copy_search_down(wme); | ||||
| 			window_copy_search_down(wme, 1); | ||||
| 	} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) { | ||||
| 		for (; np != 0; np--) | ||||
| 			window_copy_search_up(wme); | ||||
| 			window_copy_search_up(wme, 1); | ||||
| 	} | ||||
| 	return (WINDOW_COPY_CMD_NOTHING); | ||||
| } | ||||
| @@ -1696,7 +1708,7 @@ window_copy_cmd_search_backward(struct window_copy_cmd_state *cs) | ||||
| 	if (data->searchstr != NULL) { | ||||
| 		data->searchtype = WINDOW_COPY_SEARCHUP; | ||||
| 		for (; np != 0; np--) | ||||
| 			window_copy_search_up(wme); | ||||
| 			window_copy_search_up(wme, 1); | ||||
| 	} | ||||
| 	return (WINDOW_COPY_CMD_NOTHING); | ||||
| } | ||||
| @@ -1731,7 +1743,7 @@ window_copy_cmd_search_forward(struct window_copy_cmd_state *cs) | ||||
| 	if (data->searchstr != NULL) { | ||||
| 		data->searchtype = WINDOW_COPY_SEARCHDOWN; | ||||
| 		for (; np != 0; np--) | ||||
| 			window_copy_search_down(wme); | ||||
| 			window_copy_search_down(wme, 1); | ||||
| 	} | ||||
| 	return (WINDOW_COPY_CMD_NOTHING); | ||||
| } | ||||
| @@ -1767,7 +1779,7 @@ window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs) | ||||
| 		data->searchtype = WINDOW_COPY_SEARCHUP; | ||||
| 		free(data->searchstr); | ||||
| 		data->searchstr = xstrdup(argument); | ||||
| 		if (!window_copy_search_up(wme)) { | ||||
| 		if (!window_copy_search_up(wme, 0)) { | ||||
| 			window_copy_clear_marks(wme); | ||||
| 			return (WINDOW_COPY_CMD_REDRAW); | ||||
| 		} | ||||
| @@ -1776,7 +1788,7 @@ window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs) | ||||
| 		data->searchtype = WINDOW_COPY_SEARCHDOWN; | ||||
| 		free(data->searchstr); | ||||
| 		data->searchstr = xstrdup(argument); | ||||
| 		if (!window_copy_search_down(wme)) { | ||||
| 		if (!window_copy_search_down(wme, 0)) { | ||||
| 			window_copy_clear_marks(wme); | ||||
| 			return (WINDOW_COPY_CMD_REDRAW); | ||||
| 		} | ||||
| @@ -1816,7 +1828,7 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs) | ||||
| 		data->searchtype = WINDOW_COPY_SEARCHDOWN; | ||||
| 		free(data->searchstr); | ||||
| 		data->searchstr = xstrdup(argument); | ||||
| 		if (!window_copy_search_down(wme)) { | ||||
| 		if (!window_copy_search_down(wme, 0)) { | ||||
| 			window_copy_clear_marks(wme); | ||||
| 			return (WINDOW_COPY_CMD_REDRAW); | ||||
| 		} | ||||
| @@ -1825,7 +1837,7 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs) | ||||
| 		data->searchtype = WINDOW_COPY_SEARCHUP; | ||||
| 		free(data->searchstr); | ||||
| 		data->searchstr = xstrdup(argument); | ||||
| 		if (!window_copy_search_up(wme)) { | ||||
| 		if (!window_copy_search_up(wme, 0)) { | ||||
| 			window_copy_clear_marks(wme); | ||||
| 			return (WINDOW_COPY_CMD_REDRAW); | ||||
| 		} | ||||
| @@ -2152,6 +2164,297 @@ window_copy_search_rl(struct grid *gd, | ||||
| 	return (0); | ||||
| } | ||||
|  | ||||
| static int | ||||
| window_copy_search_lr_regex(struct grid *gd, struct grid *sgd, | ||||
|     u_int *ppx, u_int *psx, u_int py, u_int first, u_int last, int cis) | ||||
| { | ||||
| 	int			cflags = REG_EXTENDED, eflags = 0; | ||||
| 	u_int			endline, foundx, foundy, len, pywrap, size = 1; | ||||
| 	u_int			ssize = 1; | ||||
| 	char		       *buf, *sbuf; | ||||
| 	regex_t			reg; | ||||
| 	regmatch_t		regmatch; | ||||
| 	struct grid_line       *gl; | ||||
|  | ||||
| 	/* | ||||
| 	 * This can happen during search if the last match was the last | ||||
| 	 * character on a line. | ||||
| 	 */ | ||||
| 	if (first >= last) | ||||
| 		return (0); | ||||
|  | ||||
| 	sbuf = xmalloc(ssize); | ||||
| 	sbuf[0] = '\0'; | ||||
| 	sbuf = window_copy_stringify(sgd, 0, 0, sgd->sx, sbuf, &ssize); | ||||
| 	if (sbuf == NULL) | ||||
| 		return (0); | ||||
|  | ||||
| 	/* Set flags for regex search. */ | ||||
| 	if (cis) | ||||
| 		cflags |= REG_ICASE; | ||||
| 	if (regcomp(®, sbuf, cflags) != 0) { | ||||
| 		free(sbuf); | ||||
| 		return (0); | ||||
| 	} | ||||
| 	if (first != 0) | ||||
| 		eflags |= REG_NOTBOL; | ||||
|  | ||||
| 	/* Need to look at the entire string. */ | ||||
| 	buf = xmalloc(size); | ||||
| 	buf[0] = '\0'; | ||||
| 	buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size); | ||||
| 	len = gd->sx - first; | ||||
| 	endline = gd->hsize + gd->sy - 1; | ||||
| 	pywrap = py; | ||||
| 	while (buf != NULL && pywrap <= endline) { | ||||
| 		gl = grid_get_line(gd, pywrap); | ||||
| 		if (~gl->flags & GRID_LINE_WRAPPED) | ||||
| 			break; | ||||
| 		pywrap++; | ||||
| 		buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size); | ||||
| 		len += gd->sx; | ||||
| 	} | ||||
|  | ||||
| 	if (regexec(®, buf, 1, ®match, eflags) == 0) { | ||||
| 		foundx = first; | ||||
| 		foundy = py; | ||||
| 		window_copy_cstrtocellpos(gd, len, &foundx, &foundy, | ||||
| 		    buf + regmatch.rm_so); | ||||
| 		if (foundy == py && foundx < last) { | ||||
| 			*ppx = foundx; | ||||
| 			len -= foundx - first; | ||||
| 			window_copy_cstrtocellpos(gd, len, &foundx, &foundy, | ||||
| 			    buf + regmatch.rm_eo); | ||||
| 			*psx = foundx; | ||||
| 			while (foundy > py) { | ||||
| 				*psx += gd->sx; | ||||
| 				foundy--; | ||||
| 			} | ||||
| 			*psx -= *ppx; | ||||
| 			regfree(®); | ||||
| 			free(sbuf); | ||||
| 			free(buf); | ||||
| 			return (1); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	regfree(®); | ||||
| 	free(sbuf); | ||||
| 	free(buf); | ||||
| 	*ppx = 0; | ||||
| 	*psx = 0; | ||||
| 	return (0); | ||||
| } | ||||
|  | ||||
| static int | ||||
| window_copy_search_rl_regex(struct grid *gd, struct grid *sgd, | ||||
|     u_int *ppx, u_int *psx, u_int py, u_int first, u_int last, int cis) | ||||
| { | ||||
| 	int			cflags = REG_EXTENDED, eflags = 0; | ||||
| 	u_int			endline, len, pywrap, size = 1, ssize = 1; | ||||
| 	char		       *buf, *sbuf; | ||||
| 	regex_t			reg; | ||||
| 	struct grid_line       *gl; | ||||
|  | ||||
| 	sbuf = xmalloc(ssize); | ||||
| 	sbuf[0] = '\0'; | ||||
| 	sbuf = window_copy_stringify(sgd, 0, 0, sgd->sx, sbuf, &ssize); | ||||
| 	if (sbuf == NULL) | ||||
| 		return (0); | ||||
|  | ||||
| 	/* Set flags for regex search. */ | ||||
| 	if (cis) | ||||
| 		cflags |= REG_ICASE; | ||||
| 	if (regcomp(®, sbuf, cflags) != 0) { | ||||
| 		free(sbuf); | ||||
| 		return (0); | ||||
| 	} | ||||
| 	if (first != 0) | ||||
| 		eflags |= REG_NOTBOL; | ||||
|  | ||||
| 	/* Need to look at the entire string. */ | ||||
| 	buf = xmalloc(size); | ||||
| 	buf[0] = '\0'; | ||||
| 	buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size); | ||||
| 	len = gd->sx - first; | ||||
| 	endline = gd->hsize + gd->sy - 1; | ||||
| 	pywrap = py; | ||||
| 	while (buf != NULL && (pywrap <= endline)) { | ||||
| 		gl = grid_get_line(gd, pywrap); | ||||
| 		if (~gl->flags & GRID_LINE_WRAPPED) | ||||
| 			break; | ||||
| 		pywrap++; | ||||
| 		buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size); | ||||
| 		len += gd->sx; | ||||
| 	} | ||||
|  | ||||
| 	if (window_copy_last_regex(gd, py, first, last, len, ppx, psx, buf, | ||||
| 	    ®, eflags)) | ||||
| 	{ | ||||
| 		regfree(®); | ||||
| 		free(sbuf); | ||||
| 		free(buf); | ||||
| 		return (1); | ||||
| 	} | ||||
|  | ||||
| 	regfree(®); | ||||
| 	free(sbuf); | ||||
| 	free(buf); | ||||
| 	*ppx = 0; | ||||
| 	*psx = 0; | ||||
| 	return (0); | ||||
| } | ||||
|  | ||||
| /* Find last match in given range. */ | ||||
| static int | ||||
| window_copy_last_regex(struct grid *gd, u_int py, u_int first, u_int last, | ||||
|     u_int len, u_int *ppx, u_int *psx, const char *buf, const regex_t *preg, | ||||
|     int eflags) | ||||
| { | ||||
| 	u_int		foundx, foundy, oldx, px = 0, savepx, savesx = 0; | ||||
| 	regmatch_t	regmatch; | ||||
|  | ||||
| 	foundx = first; | ||||
| 	foundy = py; | ||||
| 	oldx = first; | ||||
| 	while (regexec(preg, buf + px, 1, ®match, eflags) == 0) { | ||||
| 		window_copy_cstrtocellpos(gd, len, &foundx, &foundy, | ||||
| 		    buf + px + regmatch.rm_so); | ||||
| 		if (foundy > py || foundx >= last) | ||||
| 			break; | ||||
| 		len -= foundx - oldx; | ||||
| 		savepx = foundx; | ||||
| 		window_copy_cstrtocellpos(gd, len, &foundx, &foundy, | ||||
| 		    buf + px + regmatch.rm_eo); | ||||
| 		if (foundy > py || foundx >= last) { | ||||
| 			*ppx = savepx; | ||||
| 			*psx = foundx; | ||||
| 			while (foundy > py) { | ||||
| 				*psx += gd->sx; | ||||
| 				foundy--; | ||||
| 			} | ||||
| 			*psx -= *ppx; | ||||
| 			return (1); | ||||
| 		} else { | ||||
| 			savesx = foundx - savepx; | ||||
| 			len -= savesx; | ||||
| 			oldx = foundx; | ||||
| 		} | ||||
| 		px += regmatch.rm_eo; | ||||
| 	} | ||||
|  | ||||
| 	if (savesx > 0) { | ||||
| 		*ppx = savepx; | ||||
| 		*psx = savesx; | ||||
| 		return (1); | ||||
| 	} else { | ||||
| 		*ppx = 0; | ||||
| 		*psx = 0; | ||||
| 		return (0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* Stringify line and append to input buffer. Caller frees. */ | ||||
| static char * | ||||
| window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last, | ||||
|     char *buf, u_int *size) | ||||
| { | ||||
| 	u_int			ax, bx, newsize; | ||||
| 	struct grid_cell	gc; | ||||
|  | ||||
| 	bx = *size - 1; | ||||
| 	newsize = *size; | ||||
| 	for (ax = first; ax < last; ax++) { | ||||
| 		grid_get_cell(gd, ax, py, &gc); | ||||
| 		newsize += gc.data.size; | ||||
| 		buf = xrealloc(buf, newsize); | ||||
| 		memcpy(buf + bx, gc.data.data, gc.data.size); | ||||
| 		bx += gc.data.size; | ||||
| 	} | ||||
|  | ||||
| 	buf[newsize - 1] = '\0'; | ||||
| 	*size = newsize; | ||||
| 	return (buf); | ||||
| } | ||||
|  | ||||
| /* Map start of C string containing UTF-8 data to grid cell position. */ | ||||
| static void | ||||
| window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy, | ||||
|     const char *str) | ||||
| { | ||||
| 	u_int			cell, ccell, px, pywrap; | ||||
| 	int			match; | ||||
| 	const char	       *cstr; | ||||
| 	char		       *celldata, **cells; | ||||
| 	struct grid_cell	gc; | ||||
|  | ||||
| 	/* Set up staggered array of cell contents. This speeds up search. */ | ||||
| 	cells = xreallocarray(NULL, ncells, sizeof cells[0]); | ||||
|  | ||||
| 	/* Populate the array of cell data. */ | ||||
| 	cell = 0; | ||||
| 	px = *ppx; | ||||
| 	pywrap = *ppy; | ||||
| 	while (cell < ncells) { | ||||
| 		grid_get_cell(gd, px, pywrap, &gc); | ||||
| 		celldata = xmalloc(gc.data.size + 1); | ||||
| 		memcpy(celldata, gc.data.data, gc.data.size); | ||||
| 		celldata[gc.data.size] = '\0'; | ||||
| 		cells[cell] = celldata; | ||||
| 		cell++; | ||||
| 		px = (px + 1) % gd->sx; | ||||
| 		if (px == 0) | ||||
| 			pywrap++; | ||||
| 	} | ||||
|  | ||||
| 	/* Locate starting cell. */ | ||||
| 	cell = 0; | ||||
| 	while (cell < ncells) { | ||||
| 		ccell = cell; | ||||
| 		cstr = str; | ||||
| 		match = 1; | ||||
| 		while (ccell < ncells) { | ||||
| 			/* Anchor found to the end. */ | ||||
| 			if (*cstr == '\0') { | ||||
| 				match = 0; | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 			celldata = cells[ccell]; | ||||
| 			while (*celldata != '\0' && *cstr != '\0') { | ||||
| 				if (*celldata++ != *cstr++) { | ||||
| 					match = 0; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if (!match) | ||||
| 				break; | ||||
| 			ccell++; | ||||
| 		} | ||||
|  | ||||
| 		if (match) | ||||
| 			break; | ||||
| 		cell++; | ||||
| 	} | ||||
|  | ||||
| 	/* If not found this will be one past the end. */ | ||||
| 	px = *ppx + cell; | ||||
| 	pywrap = *ppy; | ||||
| 	while (px >= gd->sx) { | ||||
| 		px -= gd->sx; | ||||
| 		pywrap++; | ||||
| 	} | ||||
|  | ||||
| 	*ppx = px; | ||||
| 	*ppy = pywrap; | ||||
|  | ||||
| 	/* Free cell data. */ | ||||
| 	for (cell = 0; cell < ncells; cell++) | ||||
| 		free(cells[cell]); | ||||
| 	free(cells); | ||||
| } | ||||
|  | ||||
| static void | ||||
| window_copy_move_left(struct screen *s, u_int *fx, u_int *fy, int wrapflag) | ||||
| { | ||||
| @@ -2206,24 +2509,31 @@ window_copy_is_lowercase(const char *ptr) | ||||
| static int | ||||
| window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd, | ||||
|     struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap, | ||||
|     int direction) | ||||
|     int direction, int regex) | ||||
| { | ||||
| 	u_int	i, px; | ||||
| 	int	found; | ||||
| 	u_int	i, px, sx; | ||||
| 	int	found = 0; | ||||
|  | ||||
| 	found = 0; | ||||
| 	if (direction) { | ||||
| 		for (i = fy; i <= endline; i++) { | ||||
| 			found = window_copy_search_lr(gd, sgd, &px, i, fx, | ||||
| 			    gd->sx, cis); | ||||
| 			if (regex) | ||||
| 				found = window_copy_search_lr_regex(gd, sgd, | ||||
| 				    &px, &sx, i, fx, gd->sx, cis); | ||||
| 			else | ||||
| 				found = window_copy_search_lr(gd, sgd, | ||||
| 				    &px, i, fx, gd->sx, cis); | ||||
| 			if (found) | ||||
| 				break; | ||||
| 			fx = 0; | ||||
| 		} | ||||
| 	} else { | ||||
| 		for (i = fy + 1; endline < i; i--) { | ||||
| 			found = window_copy_search_rl(gd, sgd, &px, i - 1, 0, | ||||
| 			    fx + 1, cis); | ||||
| 			if (regex) | ||||
| 				found = window_copy_search_rl_regex(gd, sgd, | ||||
| 				    &px, &sx, i - 1, 0, fx + 1, cis); | ||||
| 			else | ||||
| 				found = window_copy_search_rl(gd, sgd, | ||||
| 				    &px, i - 1, 0, fx + 1, cis); | ||||
| 			if (found) { | ||||
| 				i--; | ||||
| 				break; | ||||
| @@ -2240,7 +2550,7 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd, | ||||
| 		return (window_copy_search_jump(wme, gd, sgd, | ||||
| 		    direction ? 0 : gd->sx - 1, | ||||
| 		    direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0, | ||||
| 		    direction)); | ||||
| 		    direction, regex)); | ||||
| 	} | ||||
| 	return (0); | ||||
| } | ||||
| @@ -2250,7 +2560,7 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd, | ||||
|  * down. | ||||
|  */ | ||||
| static int | ||||
| window_copy_search(struct window_mode_entry *wme, int direction) | ||||
| window_copy_search(struct window_mode_entry *wme, int direction, int regex) | ||||
| { | ||||
| 	struct window_pane		*wp = wme->wp; | ||||
| 	struct window_copy_mode_data	*data = wme->data; | ||||
| @@ -2281,10 +2591,11 @@ window_copy_search(struct window_mode_entry *wme, int direction) | ||||
| 		window_copy_move_left(s, &fx, &fy, wrapflag); | ||||
| 		endline = 0; | ||||
| 	} | ||||
| 	found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis, | ||||
| 	    wrapflag, direction); | ||||
|  | ||||
| 	if (window_copy_search_marks(wme, &ss)) | ||||
| 	found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis, | ||||
| 	    wrapflag, direction, regex); | ||||
|  | ||||
| 	if (window_copy_search_marks(wme, &ss, regex)) | ||||
| 		window_copy_redraw_screen(wme); | ||||
|  | ||||
| 	screen_free(&ss); | ||||
| @@ -2292,7 +2603,8 @@ window_copy_search(struct window_mode_entry *wme, int direction) | ||||
| } | ||||
|  | ||||
| static int | ||||
| window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp) | ||||
| window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, | ||||
|     int regex) | ||||
| { | ||||
| 	struct window_copy_mode_data	*data = wme->data; | ||||
| 	struct screen			*s = data->backing, ss; | ||||
| @@ -2320,10 +2632,19 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp) | ||||
| 	for (py = 0; py < gd->hsize + gd->sy; py++) { | ||||
| 		px = 0; | ||||
| 		for (;;) { | ||||
| 			found = window_copy_search_lr(gd, ssp->grid, &px, py, | ||||
| 			    px, gd->sx, cis); | ||||
| 			if (regex) { | ||||
| 				found = window_copy_search_lr_regex(gd, | ||||
| 					    ssp->grid, &px, &width, py, px, | ||||
| 					    gd->sx, cis); | ||||
| 				if (!found) | ||||
| 					break; | ||||
| 			} | ||||
| 			else { | ||||
| 				found = window_copy_search_lr(gd, ssp->grid, | ||||
| 						&px, py, px, gd->sx, cis); | ||||
| 				if (!found) | ||||
| 					break; | ||||
| 			} | ||||
|  | ||||
| 			nfound++; | ||||
| 			if (px == data->cx && py == gd->hsize + data->cy - data->oy) | ||||
| @@ -2357,15 +2678,15 @@ window_copy_clear_marks(struct window_mode_entry *wme) | ||||
| } | ||||
|  | ||||
| static int | ||||
| window_copy_search_up(struct window_mode_entry *wme) | ||||
| window_copy_search_up(struct window_mode_entry *wme, int regex) | ||||
| { | ||||
| 	return (window_copy_search(wme, 0)); | ||||
| 	return (window_copy_search(wme, 0, regex)); | ||||
| } | ||||
|  | ||||
| static int | ||||
| window_copy_search_down(struct window_mode_entry *wme) | ||||
| window_copy_search_down(struct window_mode_entry *wme, int regex) | ||||
| { | ||||
| 	return (window_copy_search(wme, 1)); | ||||
| 	return (window_copy_search(wme, 1, regex)); | ||||
| } | ||||
|  | ||||
| static void | ||||
|   | ||||
| @@ -33,7 +33,7 @@ static void		 window_tree_key(struct window_mode_entry *, | ||||
| 			     struct client *, struct session *, | ||||
| 			     struct winlink *, key_code, struct mouse_event *); | ||||
|  | ||||
| #define WINDOW_TREE_DEFAULT_COMMAND "switch-client -t '%%'" | ||||
| #define WINDOW_TREE_DEFAULT_COMMAND "switch-client -Zt '%%'" | ||||
|  | ||||
| #define WINDOW_TREE_DEFAULT_FORMAT \ | ||||
| 	"#{?pane_format," \ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Nicholas Marriott
					Nicholas Marriott