From d6a9e1dca19a26e432f404a64e9667faf68c0c95 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch 
Date: Sun, 10 Apr 2016 22:13:53 +0200
Subject: degesch: customizable date change messages
Now also in the backlog.
---
 degesch.c | 80 ++++++++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 54 insertions(+), 26 deletions(-)
diff --git a/degesch.c b/degesch.c
index 737cada..e1f9801 100644
--- a/degesch.c
+++ b/degesch.c
@@ -22,6 +22,7 @@
 #define ATTR_TABLE(XX)                                                         \
 	XX( PROMPT,      "prompt",      "Terminal attrs for the prompt"       )    \
 	XX( RESET,       "reset",       "String to reset terminal attributes" )    \
+	XX( DATE_CHANGE, "date_change", "Terminal attrs for date change"      )    \
 	XX( READ_MARKER, "read_marker", "Terminal attrs for the read marker"  )    \
 	XX( WARNING,     "warning",     "Terminal attrs for warnings"         )    \
 	XX( ERROR,       "error",       "Terminal attrs for errors"           )    \
@@ -2317,6 +2318,10 @@ static struct config_schema g_config_behaviour[] =
 	  .type      = CONFIG_ITEM_BOOLEAN,
 	  .default_  = "on",
 	  .on_change = on_config_word_wrapping_change },
+	{ .name      = "date_change_line",
+	  .comment   = "Input to strftime(3) for the date change line",
+	  .type      = CONFIG_ITEM_STRING,
+	  .default_  = "\"%F\"" },
 	{ .name      = "logging",
 	  .comment   = "Log buffer contents to file",
 	  .type      = CONFIG_ITEM_BOOLEAN,
@@ -2612,6 +2617,7 @@ init_colors (struct app_context *ctx)
 
 	INIT_ATTR (PROMPT,      enter_bold_mode);
 	INIT_ATTR (RESET,       exit_attribute_mode);
+	INIT_ATTR (DATE_CHANGE, enter_bold_mode);
 	INIT_ATTR (READ_MARKER, g_terminal.color_set_fg[COLOR_MAGENTA]);
 	INIT_ATTR (WARNING,     g_terminal.color_set_fg[COLOR_YELLOW]);
 	INIT_ATTR (ERROR,       g_terminal.color_set_fg[COLOR_RED]);
@@ -3650,7 +3656,8 @@ on_config_backlog_limit_change (struct config_item *item)
 }
 
 static void
-buffer_update_time (struct app_context *ctx, time_t now)
+buffer_update_time (struct app_context *ctx, time_t now, FILE *stream,
+	int flush_opts)
 {
 	struct tm last, current;
 	if (!localtime_r (&ctx->last_displayed_msg_time, &last)
@@ -3667,10 +3674,22 @@ buffer_update_time (struct app_context *ctx, time_t now)
 	 && last.tm_mday == current.tm_mday)
 		return;
 
-	char buf[32] = "";
-	if (soft_assert (strftime (buf, sizeof buf, "%F", ¤t)))
-		print_status ("%s", buf);
-	// Else the buffer was too small, which is pretty weird
+	char buf[64] = "";
+	const char *format =
+		get_config_string (ctx->config.root, "behaviour.date_change_line");
+	if (!strftime (buf, sizeof buf, format, ¤t))
+	{
+		print_error ("%s: %s", "strftime", strerror (errno));
+		return;
+	}
+
+	struct formatter f;
+	formatter_init (&f, ctx, NULL);
+	formatter_add (&f, "#a#s\n", ATTR_DATE_CHANGE, buf);
+	formatter_flush (&f, stream, flush_opts);
+	// Flush the trailing formatting reset item
+	fflush (stream);
+	formatter_free (&f);
 }
 
 static void
@@ -3691,15 +3710,12 @@ buffer_line_flush (struct buffer_line *line, struct formatter *f, FILE *output,
 }
 
 static void
-buffer_line_display (struct app_context *ctx,
-	struct buffer_line *line, bool is_external)
+buffer_line_write_time (struct formatter *f, struct buffer_line *line,
+	FILE *stream, int flush_opts)
 {
 	// Normal timestamps don't include the date, this way the user won't be
 	// confused as to when an event has happened
-	buffer_update_time (ctx, line->when);
-
-	struct formatter f;
-	formatter_init (&f, ctx, NULL);
+	buffer_update_time (f->ctx, line->when, stream, flush_opts);
 
 	struct tm current;
 	char buf[9];
@@ -3708,7 +3724,18 @@ buffer_line_display (struct app_context *ctx,
 	else if (!strftime (buf, sizeof buf, "%T", ¤t))
 		print_error ("%s: %s", "strftime", "buffer too small");
 	else
-		formatter_add (&f, "#a#s#r ", ATTR_TIMESTAMP, buf);
+		formatter_add (f, "#a#s#r ", ATTR_TIMESTAMP, buf);
+}
+
+static void
+buffer_line_display (struct app_context *ctx,
+	struct buffer_line *line, bool is_external)
+{
+	CALL (ctx->input, hide);
+
+	struct formatter f;
+	formatter_init (&f, ctx, NULL);
+	buffer_line_write_time (&f, line, stdout, 0);
 
 	// Ignore all formatting for messages coming from other buffers, that is
 	// either from the global or server buffer.  Instead print them in grey.
@@ -3717,11 +3744,10 @@ buffer_line_display (struct app_context *ctx,
 		formatter_add (&f, "#a", ATTR_EXTERNAL);
 		FORMATTER_ADD_ITEM (&f, IGNORE_ATTR, .attribute = 1);
 	}
-
-	CALL (ctx->input, hide);
 	buffer_line_flush (line, &f, stdout, 0);
 	// Flush the trailing formatting reset item
 	fflush (stdout);
+
 	CALL (ctx->input, show);
 }
 
@@ -3731,16 +3757,7 @@ buffer_line_write_to_backlog (struct app_context *ctx,
 {
 	struct formatter f;
 	formatter_init (&f, ctx, NULL);
-
-	struct tm current;
-	char buf[20];
-	if (!localtime_r (&line->when, ¤t))
-		print_error ("%s: %s", "localtime_r", strerror (errno));
-	else if (!strftime (buf, sizeof buf, "%F %T", ¤t))
-		print_error ("%s: %s", "strftime", "buffer too small");
-	else
-		formatter_add (&f, "#a#s#r ", ATTR_TIMESTAMP, buf);
-
+	buffer_line_write_time (&f, line, log_file, flush_opts);
 	buffer_line_flush (line, &f, log_file, flush_opts);
 }
 
@@ -4048,6 +4065,10 @@ buffer_print_backlog (struct app_context *ctx, struct buffer *buffer)
 			tputs (tparm (cursor_address, g_terminal.lines - 1,
 				0, 0, 0, 0, 0, 0, 0, 0), 1, printer);
 		fflush (stdout);
+
+		// We should update "last_displayed_msg_time" here just to be sure
+		// that the first date marker, if necessary, is shown, but in practice
+		// the value should always be from today when this function is called
 	}
 	else
 	{
@@ -4073,7 +4094,7 @@ buffer_print_backlog (struct app_context *ctx, struct buffer *buffer)
 	}
 
 	// So that it is obvious if the last line in the buffer is not from today
-	buffer_update_time (ctx, time (NULL));
+	buffer_update_time (ctx, time (NULL), stdout, 0);
 
 	refresh_prompt (ctx);
 	CALL (ctx->input, show);
@@ -12179,6 +12200,9 @@ display_backlog (struct app_context *ctx, int flush_opts)
 		buffer_line_write_to_backlog (ctx, line, backlog, flush_opts);
 	}
 
+	// So that it is obvious if the last line in the buffer is not from today
+	buffer_update_time (ctx, time (NULL), backlog, flush_opts);
+
 	rewind (backlog);
 	set_cloexec (fileno (backlog));
 	launch_backlog_helper (ctx, fileno (backlog));
@@ -13126,7 +13150,11 @@ static void
 on_date_change_timer (struct app_context *ctx)
 {
 	if (ctx->terminal_suspended <= 0)
-		buffer_update_time (ctx, time (NULL));
+	{
+		CALL (ctx->input, hide);
+		buffer_update_time (ctx, time (NULL), stdout, 0);
+		CALL (ctx->input, show);
+	}
 	rearm_date_change_timer (ctx);
 }
 
-- 
cgit v1.2.3-70-g09d2