mirror of
				https://github.com/tmux/tmux.git
				synced 2025-10-26 12:27:15 +00:00 
			
		
		
		
	Add a per-client log of status line messages displayed while that client
exists. A new message-limit session option sets the maximum number of entries and a command, show-messages, shows the log (bound to ~ by default). This (and prompt history) might be better as a single global log but until there are global options it is easier for them to be per client.
This commit is contained in:
		
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -22,7 +22,7 @@ SRCS=	attributes.c cfg.c client.c clock.c \ | ||||
| 	cmd-select-layout.c cmd-select-pane.c \ | ||||
| 	cmd-select-prompt.c cmd-select-window.c cmd-send-keys.c \ | ||||
| 	cmd-send-prefix.c cmd-server-info.c cmd-set-buffer.c cmd-set-option.c \ | ||||
| 	cmd-set-window-option.c cmd-show-buffer.c \ | ||||
| 	cmd-set-window-option.c cmd-show-buffer.c cmd-show-messages.c \ | ||||
| 	cmd-show-options.c cmd-show-window-options.c cmd-source-file.c \ | ||||
| 	cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \ | ||||
| 	cmd-run-shell.c cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \ | ||||
|   | ||||
| @@ -67,6 +67,7 @@ const struct set_option_entry set_option_table[] = { | ||||
| 	{ "message-attr", SET_OPTION_ATTRIBUTES, 0, 0, NULL }, | ||||
| 	{ "message-bg", SET_OPTION_COLOUR, 0, 0, NULL }, | ||||
| 	{ "message-fg", SET_OPTION_COLOUR, 0, 0, NULL }, | ||||
| 	{ "message-limit", SET_OPTION_NUMBER, 0, INT_MAX, NULL }, | ||||
| 	{ "mouse-select-pane", SET_OPTION_FLAG, 0, 0, NULL }, | ||||
| 	{ "prefix", SET_OPTION_KEYS, 0, 0, NULL }, | ||||
| 	{ "repeat-time", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL }, | ||||
|   | ||||
							
								
								
									
										65
									
								
								cmd-show-messages.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								cmd-show-messages.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| /* $OpenBSD$ */ | ||||
|  | ||||
| /* | ||||
|  * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net> | ||||
|  * | ||||
|  * Permission to use, copy, modify, and distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER | ||||
|  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | ||||
|  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include <sys/types.h> | ||||
|  | ||||
| #include <string.h> | ||||
| #include <time.h> | ||||
|  | ||||
| #include "tmux.h" | ||||
|  | ||||
| /* | ||||
|  * Show client message log. | ||||
|  */ | ||||
|  | ||||
| int	cmd_show_messages_exec(struct cmd *, struct cmd_ctx *); | ||||
|  | ||||
| const struct cmd_entry cmd_show_messages_entry = { | ||||
| 	"show-messages", "showmsgs", | ||||
| 	CMD_TARGET_CLIENT_USAGE, | ||||
| 	0, "", | ||||
| 	cmd_target_init, | ||||
| 	cmd_target_parse, | ||||
| 	cmd_show_messages_exec, | ||||
| 	cmd_target_free, | ||||
| 	cmd_target_print | ||||
| }; | ||||
|  | ||||
| int | ||||
| cmd_show_messages_exec(struct cmd *self, struct cmd_ctx *ctx) | ||||
| { | ||||
| 	struct cmd_target_data		*data = self->data; | ||||
| 	struct client			*c; | ||||
| 	struct message_entry		*msg; | ||||
| 	char				*tim; | ||||
| 	u_int				 i; | ||||
|  | ||||
| 	if ((c = cmd_find_client(ctx, data->target)) == NULL) | ||||
| 		return (-1); | ||||
|  | ||||
| 	for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { | ||||
| 		msg = &ARRAY_ITEM(&c->message_log, i); | ||||
|  | ||||
| 		tim = ctime(&msg->msg_time); | ||||
| 		*strchr(tim, '\n') = '\0'; | ||||
| 		 | ||||
| 		ctx->print(ctx, "%s %s", tim, msg->msg); | ||||
| 	} | ||||
|  | ||||
| 	return (0); | ||||
| } | ||||
							
								
								
									
										1
									
								
								cmd.c
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								cmd.c
									
									
									
									
									
								
							| @@ -95,6 +95,7 @@ const struct cmd_entry *cmd_table[] = { | ||||
| 	&cmd_set_window_option_entry, | ||||
| 	&cmd_show_buffer_entry, | ||||
| 	&cmd_show_environment_entry, | ||||
| 	&cmd_show_messages_entry, | ||||
| 	&cmd_show_options_entry, | ||||
| 	&cmd_show_window_options_entry, | ||||
| 	&cmd_source_file_entry, | ||||
|   | ||||
| @@ -105,8 +105,8 @@ key_bindings_init(void) | ||||
| 		{ ' ',			  0, &cmd_next_layout_entry }, | ||||
| 		{ '!', 			  0, &cmd_break_pane_entry }, | ||||
| 		{ '"', 			  0, &cmd_split_window_entry },	 | ||||
| 		{ '%', 			  0, &cmd_split_window_entry },	 | ||||
| 		{ '#', 			  0, &cmd_list_buffers_entry }, | ||||
| 		{ '%', 			  0, &cmd_split_window_entry },	 | ||||
| 		{ '&', 			  0, &cmd_confirm_before_entry }, | ||||
| 		{ ',', 			  0, &cmd_command_prompt_entry }, | ||||
| 		{ '-', 			  0, &cmd_delete_buffer_entry }, | ||||
| @@ -123,13 +123,15 @@ key_bindings_init(void) | ||||
| 		{ '9', 			  0, &cmd_select_window_entry }, | ||||
| 		{ ':', 			  0, &cmd_command_prompt_entry }, | ||||
| 		{ '?', 			  0, &cmd_list_keys_entry }, | ||||
| 		{ 'D',			  0, &cmd_choose_client_entry }, | ||||
| 		{ '[', 			  0, &cmd_copy_mode_entry }, | ||||
| 		{ '\'',			  0, &cmd_select_prompt_entry }, | ||||
| 		{ '\002', /* C-b */	  0, &cmd_send_prefix_entry }, | ||||
| 		{ '\017', /* C-o */	  0, &cmd_rotate_window_entry }, | ||||
| 		{ '\032', /* C-z */	  0, &cmd_suspend_client_entry }, | ||||
| 		{ ']', 			  0, &cmd_paste_buffer_entry }, | ||||
| 		{ 'c', 			  0, &cmd_new_window_entry }, | ||||
| 		{ 'd', 			  0, &cmd_detach_client_entry }, | ||||
| 		{ 'D',			  0, &cmd_choose_client_entry }, | ||||
| 		{ 'f', 			  0, &cmd_command_prompt_entry }, | ||||
| 		{ 'i',			  0, &cmd_display_message_entry }, | ||||
| 		{ 'l', 			  0, &cmd_last_window_entry }, | ||||
| @@ -144,13 +146,14 @@ key_bindings_init(void) | ||||
| 		{ 'x', 			  0, &cmd_confirm_before_entry }, | ||||
| 		{ '{',			  0, &cmd_swap_pane_entry }, | ||||
| 		{ '}',			  0, &cmd_swap_pane_entry }, | ||||
| 		{ '\002', /* C-b */	  0, &cmd_send_prefix_entry }, | ||||
| 		{ '~',			  0, &cmd_show_messages_entry }, | ||||
| 		{ '1' | KEYC_ESCAPE,	  0, &cmd_select_layout_entry }, | ||||
| 		{ '2' | KEYC_ESCAPE,	  0, &cmd_select_layout_entry }, | ||||
| 		{ '3' | KEYC_ESCAPE,	  0, &cmd_select_layout_entry }, | ||||
| 		{ '4' | KEYC_ESCAPE,	  0, &cmd_select_layout_entry }, | ||||
| 		{ KEYC_PPAGE, 		  0, &cmd_copy_mode_entry }, | ||||
| 		{ 'n' | KEYC_ESCAPE, 	  0, &cmd_next_window_entry }, | ||||
| 		{ 'o' | KEYC_ESCAPE,	  0, &cmd_rotate_window_entry }, | ||||
| 		{ 'p' | KEYC_ESCAPE, 	  0, &cmd_previous_window_entry }, | ||||
| 		{ KEYC_UP, 		  0, &cmd_up_pane_entry }, | ||||
| 		{ KEYC_DOWN, 		  0, &cmd_down_pane_entry }, | ||||
| @@ -162,8 +165,6 @@ key_bindings_init(void) | ||||
| 		{ KEYC_DOWN | KEYC_CTRL,  1, &cmd_resize_pane_entry },	 | ||||
| 		{ KEYC_LEFT | KEYC_CTRL,  1, &cmd_resize_pane_entry }, | ||||
| 		{ KEYC_RIGHT | KEYC_CTRL, 1, &cmd_resize_pane_entry }, | ||||
| 		{ 'o' | KEYC_ESCAPE,	  0, &cmd_rotate_window_entry }, | ||||
| 		{ '\017', /* C-o */	  0, &cmd_rotate_window_entry }, | ||||
| 	}; | ||||
| 	u_int		 i; | ||||
| 	struct cmd	*cmd; | ||||
|   | ||||
| @@ -80,6 +80,7 @@ server_client_create(int fd) | ||||
| 	job_tree_init(&c->status_jobs); | ||||
|  | ||||
| 	c->message_string = NULL; | ||||
| 	ARRAY_INIT(&c->message_log); | ||||
|  | ||||
| 	c->prompt_string = NULL; | ||||
| 	c->prompt_buffer = NULL; | ||||
| @@ -101,6 +102,7 @@ server_client_create(int fd) | ||||
| void | ||||
| server_client_lost(struct client *c) | ||||
| { | ||||
| 	struct message_entry	*msg; | ||||
| 	u_int			 i; | ||||
|  | ||||
| 	for (i = 0; i < ARRAY_LENGTH(&clients); i++) { | ||||
| @@ -129,6 +131,11 @@ server_client_lost(struct client *c) | ||||
| 	if (c->message_string != NULL) | ||||
| 		xfree(c->message_string); | ||||
| 	evtimer_del(&c->message_timer); | ||||
| 	for (i = 0; i < ARRAY_LENGTH(&c->message_log); i++) { | ||||
| 		msg = &ARRAY_ITEM(&c->message_log, i); | ||||
| 		xfree(msg->msg); | ||||
| 	} | ||||
| 	ARRAY_FREE(&c->message_log); | ||||
|  | ||||
| 	if (c->prompt_string != NULL) | ||||
| 		xfree(c->prompt_string); | ||||
|   | ||||
							
								
								
									
										18
									
								
								status.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								status.c
									
									
									
									
									
								
							| @@ -567,8 +567,11 @@ void printflike2 | ||||
| status_message_set(struct client *c, const char *fmt, ...) | ||||
| { | ||||
| 	struct timeval		 tv; | ||||
| 	struct session		*s = c->session; | ||||
| 	struct message_entry	*msg; | ||||
| 	va_list			 ap; | ||||
| 	int			 delay; | ||||
| 	u_int			 i, limit; | ||||
|  | ||||
| 	status_prompt_clear(c); | ||||
| 	status_message_clear(c); | ||||
| @@ -577,6 +580,21 @@ status_message_set(struct client *c, const char *fmt, ...) | ||||
| 	xvasprintf(&c->message_string, fmt, ap); | ||||
| 	va_end(ap); | ||||
|  | ||||
| 	ARRAY_EXPAND(&c->message_log, 1); | ||||
| 	msg = &ARRAY_LAST(&c->message_log); | ||||
| 	msg->msg_time = time(NULL); | ||||
| 	msg->msg = xstrdup(c->message_string); | ||||
|  | ||||
| 	if (s == NULL) | ||||
| 		limit = 0; | ||||
| 	else | ||||
| 		limit = options_get_number(&s->options, "message-limit"); | ||||
| 	for (i = ARRAY_LENGTH(&c->message_log); i > limit; i--) { | ||||
| 		msg = &ARRAY_ITEM(&c->message_log, i - 1); | ||||
| 		xfree(msg->msg); | ||||
| 		ARRAY_REMOVE(&c->message_log, i - 1); | ||||
| 	} | ||||
|  | ||||
| 	delay = options_get_number(&c->session->options, "display-time"); | ||||
| 	tv.tv_sec = delay / 1000; | ||||
| 	tv.tv_usec = (delay % 1000) * 1000L; | ||||
|   | ||||
							
								
								
									
										14
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								tmux.1
									
									
									
									
									
								
							| @@ -454,6 +454,16 @@ with | ||||
| .D1 (alias: Ic rename ) | ||||
| Rename the session to | ||||
| .Ar new-name . | ||||
| .It Xo Ic show-messages  | ||||
| .Op Fl t Ar target-client | ||||
| .Xc | ||||
| .D1 (alias: Ic showmsgs ) | ||||
| Any messages displayed on the status line are saved in a per-client message | ||||
| log, up to a maximum of the limit set by the | ||||
| .Ar message-limit | ||||
| session option for the session attached to that client. | ||||
| This command displays the log for | ||||
| .Ar target-client . | ||||
| .It Ic source-file Ar path | ||||
| .D1 (alias: Ic source ) | ||||
| Execute commands from | ||||
| @@ -1373,6 +1383,10 @@ from the 256-colour palette, or | ||||
| .Ic default . | ||||
| .It Ic message-fg Ar colour | ||||
| Set status line message foreground colour. | ||||
| .It Ic message-limit Ar number | ||||
| Set the number of error or information messages to save in the message log for | ||||
| each client. | ||||
| The default is 20. | ||||
| .It Xo Ic mouse-select-pane | ||||
| .Op Ic on | off | ||||
| .Xc | ||||
|   | ||||
							
								
								
									
										1
									
								
								tmux.c
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								tmux.c
									
									
									
									
									
								
							| @@ -332,6 +332,7 @@ main(int argc, char **argv) | ||||
| 	options_set_number(so, "message-attr", 0); | ||||
| 	options_set_number(so, "message-bg", 3); | ||||
| 	options_set_number(so, "message-fg", 0); | ||||
| 	options_set_number(so, "message-limit", 20); | ||||
| 	options_set_number(so, "mouse-select-pane", 0); | ||||
| 	options_set_number(so, "repeat-time", 500); | ||||
| 	options_set_number(so, "set-remain-on-exit", 0); | ||||
|   | ||||
							
								
								
									
										8
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								tmux.h
									
									
									
									
									
								
							| @@ -1041,6 +1041,12 @@ struct mouse_event { | ||||
| 	u_char	y; | ||||
| }; | ||||
|  | ||||
| /* Saved message entry. */ | ||||
| struct message_entry { | ||||
| 	char   *msg; | ||||
| 	time_t	msg_time; | ||||
| }; | ||||
|  | ||||
| /* Client connection. */ | ||||
| struct client { | ||||
| 	struct imsgbuf	 ibuf; | ||||
| @@ -1077,6 +1083,7 @@ struct client { | ||||
|  | ||||
| 	char		*message_string; | ||||
| 	struct event	 message_timer; | ||||
| 	ARRAY_DECL(, struct message_entry) message_log; | ||||
|  | ||||
| 	char		*prompt_string; | ||||
| 	char		*prompt_buffer; | ||||
| @@ -1481,6 +1488,7 @@ extern const struct cmd_entry cmd_set_option_entry; | ||||
| extern const struct cmd_entry cmd_set_window_option_entry; | ||||
| extern const struct cmd_entry cmd_show_buffer_entry; | ||||
| extern const struct cmd_entry cmd_show_environment_entry; | ||||
| extern const struct cmd_entry cmd_show_messages_entry; | ||||
| extern const struct cmd_entry cmd_show_options_entry; | ||||
| extern const struct cmd_entry cmd_show_window_options_entry; | ||||
| extern const struct cmd_entry cmd_source_file_entry; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Nicholas Marriott
					Nicholas Marriott