degesch: unfuck terminal attribute handling
This commit is contained in:
		
							
								
								
									
										135
									
								
								degesch.c
									
									
									
									
									
								
							
							
						
						
									
										135
									
								
								degesch.c
									
									
									
									
									
								
							@@ -21,23 +21,37 @@
 | 
				
			|||||||
/// Some arbitrary limit for the history file
 | 
					/// Some arbitrary limit for the history file
 | 
				
			||||||
#define HISTORY_LIMIT 10000
 | 
					#define HISTORY_LIMIT 10000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// String constants for all attributes we use for output
 | 
					#define ATTR_TABLE(XX)                                                         \
 | 
				
			||||||
#define ATTR_PROMPT    "attr_prompt"
 | 
						XX( PROMPT,    "prompt",    "Terminal attributes for the prompt"     )     \
 | 
				
			||||||
#define ATTR_RESET     "attr_reset"
 | 
						XX( RESET,     "reset",     "String to reset terminal attributes"    )     \
 | 
				
			||||||
#define ATTR_WARNING   "attr_warning"
 | 
						XX( WARNING,   "warning",   "Terminal attributes for warnings"       )     \
 | 
				
			||||||
#define ATTR_ERROR     "attr_error"
 | 
						XX( ERROR,     "error",     "Terminal attributes for errors"         )     \
 | 
				
			||||||
 | 
						XX( EXTERNAL,  "external",  "Terminal attributes for external lines" )     \
 | 
				
			||||||
 | 
						XX( TIMESTAMP, "timestamp", "Terminal attributes for timestamps"     )     \
 | 
				
			||||||
 | 
						XX( HIGHLIGHT, "highlight", "Terminal attributes for highlights"     )     \
 | 
				
			||||||
 | 
						XX( ACTION,    "action",    "Terminal attributes for user actions"   )     \
 | 
				
			||||||
 | 
						XX( JOIN,      "join",      "Terminal attributes for joins"          )     \
 | 
				
			||||||
 | 
						XX( PART,      "part",      "Terminal attributes for parts"          )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ATTR_EXTERNAL  "attr_external"
 | 
					enum
 | 
				
			||||||
#define ATTR_TIMESTAMP "attr_timestamp"
 | 
					{
 | 
				
			||||||
#define ATTR_HIGHLIGHT "attr_highlight"
 | 
					#define XX(x, y, z) ATTR_ ## x,
 | 
				
			||||||
#define ATTR_ACTION    "attr_action"
 | 
						ATTR_TABLE (XX)
 | 
				
			||||||
#define ATTR_JOIN      "attr_join"
 | 
					#undef XX
 | 
				
			||||||
#define ATTR_PART      "attr_part"
 | 
						ATTR_COUNT
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *g_attr_table[ATTR_COUNT] =
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#define XX(x, y, z) [ATTR_ ## x] = "attr_" y,
 | 
				
			||||||
 | 
						ATTR_TABLE (XX)
 | 
				
			||||||
 | 
					#undef XX
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// User data for logger functions to enable formatted logging
 | 
					// User data for logger functions to enable formatted logging
 | 
				
			||||||
#define print_fatal_data    ATTR_ERROR
 | 
					#define print_fatal_data    ((void *) ATTR_ERROR)
 | 
				
			||||||
#define print_error_data    ATTR_ERROR
 | 
					#define print_error_data    ((void *) ATTR_ERROR)
 | 
				
			||||||
#define print_warning_data  ATTR_WARNING
 | 
					#define print_warning_data  ((void *) ATTR_WARNING)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#undef PROGRAM_NAME
 | 
					#undef PROGRAM_NAME
 | 
				
			||||||
@@ -89,17 +103,9 @@ static struct config_item g_config_table[] =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	{ "isolate_buffers", "off",   "Isolate global/server buffers"            },
 | 
						{ "isolate_buffers", "off",   "Isolate global/server buffers"            },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{ ATTR_PROMPT,       NULL,    "Terminal attributes for the prompt"       },
 | 
					#define XX(x, y, z) { "attr_" y, NULL, z },
 | 
				
			||||||
	{ ATTR_RESET,        NULL,    "String to reset terminal attributes"      },
 | 
						ATTR_TABLE (XX)
 | 
				
			||||||
	{ ATTR_WARNING,      NULL,    "Terminal attributes for warnings"         },
 | 
					#undef XX
 | 
				
			||||||
	{ ATTR_ERROR,        NULL,    "Terminal attributes for errors"           },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	{ ATTR_EXTERNAL,     NULL,    "Terminal attributes for external lines"   },
 | 
					 | 
				
			||||||
	{ ATTR_TIMESTAMP,    NULL,    "Terminal attributes for timestamps"       },
 | 
					 | 
				
			||||||
	{ ATTR_HIGHLIGHT,    NULL,    "Terminal attributes for highlights"       },
 | 
					 | 
				
			||||||
	{ ATTR_ACTION,       NULL,    "Terminal attributes for user actions"     },
 | 
					 | 
				
			||||||
	{ ATTR_JOIN,         NULL,    "Terminal attributes for joins"            },
 | 
					 | 
				
			||||||
	{ ATTR_PART,         NULL,    "Terminal attributes for parts"            },
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{ NULL,              NULL,    NULL                                       }
 | 
						{ NULL,              NULL,    NULL                                       }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -419,19 +425,12 @@ buffer_destroy (struct buffer *self)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum color_mode
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	COLOR_AUTO,                         ///< Autodetect if colours are available
 | 
					 | 
				
			||||||
	COLOR_ALWAYS,                       ///< Always use coloured output
 | 
					 | 
				
			||||||
	COLOR_NEVER                         ///< Never use coloured output
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct app_context
 | 
					struct app_context
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// Configuration:
 | 
						// Configuration:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct str_map config;              ///< User configuration
 | 
						struct str_map config;              ///< User configuration
 | 
				
			||||||
	enum color_mode color_mode;         ///< Colour output mode
 | 
						bool no_colors;                     ///< Colour output mode
 | 
				
			||||||
	bool reconnect;                     ///< Whether to reconnect on conn. fail.
 | 
						bool reconnect;                     ///< Whether to reconnect on conn. fail.
 | 
				
			||||||
	unsigned long reconnect_delay;      ///< Reconnect delay in seconds
 | 
						unsigned long reconnect_delay;      ///< Reconnect delay in seconds
 | 
				
			||||||
	bool isolate_buffers;               ///< Isolate global/server buffers
 | 
						bool isolate_buffers;               ///< Isolate global/server buffers
 | 
				
			||||||
@@ -724,7 +723,7 @@ get_attribute_printer (FILE *stream)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
vprint_attributed (struct app_context *ctx,
 | 
					vprint_attributed (struct app_context *ctx,
 | 
				
			||||||
	FILE *stream, const char *attribute, const char *fmt, va_list ap)
 | 
						FILE *stream, intptr_t attribute, const char *fmt, va_list ap)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	terminal_printer_fn printer = get_attribute_printer (stream);
 | 
						terminal_printer_fn printer = get_attribute_printer (stream);
 | 
				
			||||||
	if (!attribute)
 | 
						if (!attribute)
 | 
				
			||||||
@@ -732,7 +731,8 @@ vprint_attributed (struct app_context *ctx,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (printer)
 | 
						if (printer)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		const char *value = str_map_find (&ctx->config, attribute);
 | 
							const char *value = str_map_find
 | 
				
			||||||
 | 
								(&ctx->config, g_attr_table[attribute]);
 | 
				
			||||||
		tputs (value, 1, printer);
 | 
							tputs (value, 1, printer);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -740,14 +740,15 @@ vprint_attributed (struct app_context *ctx,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (printer)
 | 
						if (printer)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		const char *value = str_map_find (&ctx->config, ATTR_RESET);
 | 
							const char *value = str_map_find
 | 
				
			||||||
 | 
								(&ctx->config, g_attr_table[ATTR_RESET]);
 | 
				
			||||||
		tputs (value, 1, printer);
 | 
							tputs (value, 1, printer);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
print_attributed (struct app_context *ctx,
 | 
					print_attributed (struct app_context *ctx,
 | 
				
			||||||
	FILE *stream, const char *attribute, const char *fmt, ...)
 | 
						FILE *stream, intptr_t attribute, const char *fmt, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	va_list ap;
 | 
						va_list ap;
 | 
				
			||||||
	va_start (ap, fmt);
 | 
						va_start (ap, fmt);
 | 
				
			||||||
@@ -765,8 +766,8 @@ log_message_attributed (void *user_data, const char *quote, const char *fmt,
 | 
				
			|||||||
	if (g_ctx->readline_prompt_shown)
 | 
						if (g_ctx->readline_prompt_shown)
 | 
				
			||||||
		app_readline_hide (&state);
 | 
							app_readline_hide (&state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	print_attributed (g_ctx, stream, user_data, "%s", quote);
 | 
						print_attributed (g_ctx, stream, (intptr_t) user_data, "%s", quote);
 | 
				
			||||||
	vprint_attributed (g_ctx, stream, user_data, fmt, ap);
 | 
						vprint_attributed (g_ctx, stream, (intptr_t) user_data, fmt, ap);
 | 
				
			||||||
	fputs ("\n", stream);
 | 
						fputs ("\n", stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (g_ctx->readline_prompt_shown)
 | 
						if (g_ctx->readline_prompt_shown)
 | 
				
			||||||
@@ -779,42 +780,33 @@ init_colors (struct app_context *ctx)
 | 
				
			|||||||
	bool have_ti = init_terminal ();
 | 
						bool have_ti = init_terminal ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Use escape sequences from terminfo if possible, and SGR as a fallback
 | 
						// Use escape sequences from terminfo if possible, and SGR as a fallback
 | 
				
			||||||
#define INIT_ATTR(id, ti, vt100) \
 | 
					#define INIT_ATTR(id, ti) \
 | 
				
			||||||
	str_map_set (&ctx->config, (id), xstrdup (have_ti ? (ti) : (vt100)));
 | 
						str_map_set (&ctx->config, g_attr_table[id], xstrdup (have_ti ? (ti) : ""))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_ATTR (ATTR_PROMPT,    enter_bold_mode,            "\x1b[1m");
 | 
						INIT_ATTR (ATTR_PROMPT,    enter_bold_mode);
 | 
				
			||||||
	INIT_ATTR (ATTR_RESET,     exit_attribute_mode,        "\x1b[0m");
 | 
						INIT_ATTR (ATTR_RESET,     exit_attribute_mode);
 | 
				
			||||||
	INIT_ATTR (ATTR_WARNING,   g_terminal.color_set_fg[3], "\x1b[33m");
 | 
						INIT_ATTR (ATTR_WARNING,   g_terminal.color_set_fg[3]);
 | 
				
			||||||
	INIT_ATTR (ATTR_ERROR,     g_terminal.color_set_fg[1], "\x1b[31m");
 | 
						INIT_ATTR (ATTR_ERROR,     g_terminal.color_set_fg[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	INIT_ATTR (ATTR_EXTERNAL,  g_terminal.color_set_fg[7], "\x1b[37m");
 | 
						INIT_ATTR (ATTR_EXTERNAL,  g_terminal.color_set_fg[7]);
 | 
				
			||||||
	INIT_ATTR (ATTR_TIMESTAMP, g_terminal.color_set_fg[7], "\x1b[37m");
 | 
						INIT_ATTR (ATTR_TIMESTAMP, g_terminal.color_set_fg[7]);
 | 
				
			||||||
	INIT_ATTR (ATTR_ACTION,    g_terminal.color_set_fg[1], "\x1b[31m");
 | 
						INIT_ATTR (ATTR_ACTION,    g_terminal.color_set_fg[1]);
 | 
				
			||||||
	INIT_ATTR (ATTR_JOIN,      g_terminal.color_set_fg[2], "\x1b[32m");
 | 
						INIT_ATTR (ATTR_JOIN,      g_terminal.color_set_fg[2]);
 | 
				
			||||||
	INIT_ATTR (ATTR_PART,      g_terminal.color_set_fg[1], "\x1b[31m");
 | 
						INIT_ATTR (ATTR_PART,      g_terminal.color_set_fg[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *highlight = xstrdup_printf ("%s%s%s",
 | 
						char *highlight = xstrdup_printf ("%s%s%s",
 | 
				
			||||||
		g_terminal.color_set_fg[3],
 | 
							g_terminal.color_set_fg[3],
 | 
				
			||||||
		g_terminal.color_set_bg[5],
 | 
							g_terminal.color_set_bg[5],
 | 
				
			||||||
		enter_bold_mode);
 | 
							enter_bold_mode);
 | 
				
			||||||
	INIT_ATTR (ATTR_HIGHLIGHT, highlight,                  "\x1b[33;47;1m");
 | 
						INIT_ATTR (ATTR_HIGHLIGHT, highlight);
 | 
				
			||||||
	free (highlight);
 | 
						free (highlight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#undef INIT_ATTR
 | 
					#undef INIT_ATTR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (ctx->color_mode)
 | 
						if (ctx->no_colors)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	case COLOR_ALWAYS:
 | 
							g_terminal.stdout_is_tty = false;
 | 
				
			||||||
		g_terminal.stdout_is_tty = true;
 | 
							g_terminal.stderr_is_tty = false;
 | 
				
			||||||
		g_terminal.stderr_is_tty = true;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case COLOR_AUTO:
 | 
					 | 
				
			||||||
		if (!g_terminal.initialized)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
	case COLOR_NEVER:
 | 
					 | 
				
			||||||
			g_terminal.stdout_is_tty = false;
 | 
					 | 
				
			||||||
			g_terminal.stderr_is_tty = false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g_log_message_real = log_message_attributed;
 | 
						g_log_message_real = log_message_attributed;
 | 
				
			||||||
@@ -985,14 +977,15 @@ formatter_add_reset (struct formatter *self)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
formatter_add_attr (struct formatter *self, const char *attr_name)
 | 
					formatter_add_attr (struct formatter *self, int attr_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (self->ignore_new_attributes)
 | 
						if (self->ignore_new_attributes)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct formatter_item *item = formatter_add_blank (self);
 | 
						struct formatter_item *item = formatter_add_blank (self);
 | 
				
			||||||
	item->type = FORMATTER_ITEM_ATTR;
 | 
						item->type = FORMATTER_ITEM_ATTR;
 | 
				
			||||||
	item->data = xstrdup (str_map_find (&self->ctx->config, attr_name));
 | 
						item->data = xstrdup (str_map_find
 | 
				
			||||||
 | 
							(&self->ctx->config, g_attr_table[attr_id]));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@@ -1047,7 +1040,7 @@ restart:
 | 
				
			|||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case 'a':
 | 
						case 'a':
 | 
				
			||||||
		formatter_add_attr     (self, va_arg (*ap, const char *));
 | 
							formatter_add_attr     (self, va_arg (*ap, int));
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case 'c':
 | 
						case 'c':
 | 
				
			||||||
		formatter_add_fg_color (self, va_arg (*ap, int));
 | 
							formatter_add_fg_color (self, va_arg (*ap, int));
 | 
				
			||||||
@@ -1117,7 +1110,8 @@ formatter_flush (struct formatter *self, FILE *stream)
 | 
				
			|||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const char *attr_reset = str_map_find (&self->ctx->config, ATTR_RESET);
 | 
						const char *attr_reset = str_map_find
 | 
				
			||||||
 | 
							(&self->ctx->config, g_attr_table[ATTR_RESET]);
 | 
				
			||||||
	tputs (attr_reset, 1, printer);
 | 
						tputs (attr_reset, 1, printer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool is_attributed = false;
 | 
						bool is_attributed = false;
 | 
				
			||||||
@@ -2148,8 +2142,10 @@ refresh_prompt (struct app_context *ctx)
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// XXX: to be completely correct, we should use tputs, but we cannot
 | 
							// XXX: to be completely correct, we should use tputs, but we cannot
 | 
				
			||||||
		const char *prompt_attrs = str_map_find (&ctx->config, ATTR_PROMPT);
 | 
							const char *prompt_attrs = str_map_find
 | 
				
			||||||
		const char *reset_attrs  = str_map_find (&ctx->config, ATTR_RESET);
 | 
								(&ctx->config, g_attr_table[ATTR_PROMPT]);
 | 
				
			||||||
 | 
							const char *reset_attrs  = str_map_find
 | 
				
			||||||
 | 
								(&ctx->config, g_attr_table[ATTR_RESET]);
 | 
				
			||||||
		ctx->readline_prompt = xstrdup_printf ("%c%s%c%s%c%s%c",
 | 
							ctx->readline_prompt = xstrdup_printf ("%c%s%c%s%c%s%c",
 | 
				
			||||||
			RL_PROMPT_START_IGNORE, prompt_attrs, RL_PROMPT_END_IGNORE,
 | 
								RL_PROMPT_START_IGNORE, prompt_attrs, RL_PROMPT_END_IGNORE,
 | 
				
			||||||
			prompt.str,
 | 
								prompt.str,
 | 
				
			||||||
@@ -4553,6 +4549,7 @@ main (int argc, char *argv[])
 | 
				
			|||||||
		exit (EXIT_FAILURE);
 | 
							exit (EXIT_FAILURE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// FIXME: this overwrites all custom attribute settings
 | 
				
			||||||
	init_colors (&ctx);
 | 
						init_colors (&ctx);
 | 
				
			||||||
	init_poller_events (&ctx);
 | 
						init_poller_events (&ctx);
 | 
				
			||||||
	init_buffers (&ctx);
 | 
						init_buffers (&ctx);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user