xF: deduplicate transcript logic
After the last commit it got a bit ridiculous.
This commit is contained in:
@@ -83,7 +83,7 @@ struct buffer_line
|
||||
bool is_unimportant;
|
||||
bool is_highlight;
|
||||
enum relay_rendition rendition;
|
||||
uint64_t when; ///< Unix timestamp in milliseconds
|
||||
uint64_t when; ///< Unix timestamp in ms, for log = 0
|
||||
struct buffer_line_item *items;
|
||||
struct buffer_line_item *items_tail;
|
||||
|
||||
@@ -2687,6 +2687,15 @@ app_make_line_timestamp (const struct buffer_line *line)
|
||||
static void
|
||||
app_wrap_buffer_line_to_width (struct buffer_line *line, int width)
|
||||
{
|
||||
if (!line->when)
|
||||
{
|
||||
struct widget *padding = app_padding (ATTRIBUTE_NORMAL, 0.25);
|
||||
int available = MAX (0, width - 2 * padding->width);
|
||||
app_wrap_buffer_line (line, available, available);
|
||||
widget_destroy (padding);
|
||||
return;
|
||||
}
|
||||
|
||||
struct widget *timestamp = app_make_line_timestamp (line);
|
||||
struct widget *time_padding = app_padding (ATTRIBUTE_TIMESTAMP, 0.25);
|
||||
struct widget *mark = app_make_mark (line);
|
||||
@@ -2704,15 +2713,6 @@ app_wrap_buffer_line_to_width (struct buffer_line *line, int width)
|
||||
widget_destroy (padding);
|
||||
}
|
||||
|
||||
static void
|
||||
app_wrap_log_line_to_width (struct buffer_line *line, int width)
|
||||
{
|
||||
struct widget *padding = app_padding (ATTRIBUTE_NORMAL, 0.25);
|
||||
int available = MAX (0, width - 2 * padding->width);
|
||||
app_wrap_buffer_line (line, available, available);
|
||||
widget_destroy (padding);
|
||||
}
|
||||
|
||||
static int
|
||||
app_wrapped_line_height (const struct buffer_line *line)
|
||||
{
|
||||
@@ -2732,11 +2732,24 @@ app_buffer_line_height (struct buffer_line *line)
|
||||
static struct widget *
|
||||
app_make_line (struct buffer_line *line)
|
||||
{
|
||||
struct layout rows = {};
|
||||
if (!line->when)
|
||||
{
|
||||
for (size_t i = 0; i < line->wraps_len; i++)
|
||||
{
|
||||
struct layout row = {};
|
||||
app_push (&row, app_padding (ATTRIBUTE_NORMAL, 0.25));
|
||||
app_append_line_span (&row, 0, line, &line->wraps[i]);
|
||||
app_push (&row, app_padding (ATTRIBUTE_NORMAL, 0.25));
|
||||
app_push (&rows, xui_hbox (row.head));
|
||||
}
|
||||
return xui_vbox (rows.head);
|
||||
}
|
||||
|
||||
// XXX: We still use too much ATTRIBUTE_NORMAL, which basically names
|
||||
// the <-1, -1> colour pair. We don't use it with line items as a default
|
||||
// because then links attribute application would get blocked.
|
||||
chtype base = line->leaked ? g_attrs[ATTRIBUTE_EXTERNAL].attrs : 0;
|
||||
struct layout rows = {};
|
||||
for (size_t i = 0; i < line->wraps_len; i++)
|
||||
{
|
||||
struct layout row = {};
|
||||
@@ -2794,19 +2807,50 @@ app_make_read_marker (void)
|
||||
return marker;
|
||||
}
|
||||
|
||||
static struct widget *
|
||||
app_make_log_line (const struct buffer_line *line)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
enum transcript_visit_kind { VISIT_LINE, VISIT_READ, VISIT_DATE };
|
||||
|
||||
typedef void (*transcript_visit_fn)
|
||||
(enum transcript_visit_kind, struct buffer_line *, time_t, int, void *);
|
||||
|
||||
static void
|
||||
app_walk_transcript (time_t now, transcript_visit_fn visit, void *user_data)
|
||||
{
|
||||
struct layout rows = {};
|
||||
for (size_t i = 0; i < line->wraps_len; i++)
|
||||
if (g.log.visible)
|
||||
{
|
||||
struct layout row = {};
|
||||
app_push (&row, app_padding (ATTRIBUTE_NORMAL, 0.25));
|
||||
app_append_line_span (&row, 0, line, &line->wraps[i]);
|
||||
app_push (&row, app_padding (ATTRIBUTE_NORMAL, 0.25));
|
||||
app_push (&rows, xui_hbox (row.head));
|
||||
for (size_t i = 0; i < g.log.lines_len; i++)
|
||||
visit (VISIT_LINE, g.log.lines[i], 0,
|
||||
app_wrapped_line_height (g.log.lines[i]), user_data);
|
||||
return;
|
||||
}
|
||||
return xui_vbox (rows.head);
|
||||
|
||||
struct buffer *b = g.buffer_current;
|
||||
if (!b)
|
||||
return;
|
||||
|
||||
uint64_t unread = (uint64_t) b->new_messages + b->new_unimportant_messages;
|
||||
const struct buffer_line *marker_before = NULL;
|
||||
for (const struct buffer_line *line = b->lines_tail;
|
||||
line && unread--; line = line->prev)
|
||||
marker_before = line;
|
||||
|
||||
struct tm last_date = {};
|
||||
bool have_last_date = false;
|
||||
LIST_FOR_EACH (struct buffer_line, line, b->lines)
|
||||
{
|
||||
if (line == marker_before)
|
||||
visit (VISIT_READ, NULL, line->when, READ_MARKER_HEIGHT, user_data);
|
||||
if (!buffer_line_is_visible (b, line))
|
||||
continue;
|
||||
|
||||
time_t when = line->when / 1000;
|
||||
if (app_date_changed (when, &last_date, &have_last_date))
|
||||
visit (VISIT_DATE, line, when, g_xui.vunit, user_data);
|
||||
visit (VISIT_LINE, line, when, app_wrapped_line_height (line), user_data);
|
||||
}
|
||||
if (have_last_date && app_date_changed (now, &last_date, &have_last_date))
|
||||
visit (VISIT_DATE, NULL, now, g_xui.vunit, user_data);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@@ -2823,8 +2867,7 @@ struct transcript_slice
|
||||
static struct transcript_slice
|
||||
app_make_transcript_slice (void)
|
||||
{
|
||||
struct app_scroll_view view =
|
||||
app_scroll_view (WIDGET_TRANSCRIPT_SCROLLBAR);
|
||||
struct app_scroll_view view = app_scroll_view (WIDGET_TRANSCRIPT_SCROLLBAR);
|
||||
int viewport = app_viewport_height ();
|
||||
int view_top = app_scroll_view_origin (&view);
|
||||
return (struct transcript_slice)
|
||||
@@ -2854,113 +2897,79 @@ app_transcript_slice_offset (const struct transcript_slice *slice)
|
||||
return slice->first_y < 0 ? 0 : slice->first_y - slice->view_top;
|
||||
}
|
||||
|
||||
static int
|
||||
app_append_log_rows (struct layout *rows)
|
||||
{
|
||||
struct transcript_slice slice = app_make_transcript_slice ();
|
||||
for (size_t i = 0; i < g.log.lines_len; i++)
|
||||
{
|
||||
struct buffer_line *line = g.log.lines[i];
|
||||
if (app_transcript_row_is_visible
|
||||
(&slice, app_wrapped_line_height (line)))
|
||||
app_push (rows, app_make_log_line (line));
|
||||
}
|
||||
return app_transcript_slice_offset (&slice);
|
||||
}
|
||||
|
||||
static int
|
||||
app_append_buffer_rows (struct layout *rows, time_t now)
|
||||
{
|
||||
struct buffer *b = g.buffer_current;
|
||||
if (!b)
|
||||
return 0;
|
||||
|
||||
uint64_t unread = (uint64_t) b->new_messages + b->new_unimportant_messages;
|
||||
const struct buffer_line *marker_before = NULL;
|
||||
for (const struct buffer_line *line = b->lines_tail;
|
||||
line && unread--; line = line->prev)
|
||||
marker_before = line;
|
||||
|
||||
struct transcript_slice slice = app_make_transcript_slice ();
|
||||
struct tm last_date = {};
|
||||
bool have_last_date = false;
|
||||
LIST_FOR_EACH (struct buffer_line, line, b->lines)
|
||||
{
|
||||
if (line == marker_before
|
||||
&& app_transcript_row_is_visible (&slice, READ_MARKER_HEIGHT))
|
||||
app_push (rows, app_make_read_marker ());
|
||||
if (!buffer_line_is_visible (b, line))
|
||||
continue;
|
||||
|
||||
time_t when = line->when / 1000;
|
||||
if (app_date_changed (when, &last_date, &have_last_date)
|
||||
&& app_transcript_row_is_visible (&slice, g_xui.vunit))
|
||||
app_push (rows, app_make_date_change_marker (when));
|
||||
if (app_transcript_row_is_visible
|
||||
(&slice, app_wrapped_line_height (line)))
|
||||
app_push (rows, app_make_line (line));
|
||||
}
|
||||
if (have_last_date && app_date_changed (now, &last_date, &have_last_date)
|
||||
&& app_transcript_row_is_visible (&slice, g_xui.vunit))
|
||||
app_push (rows, app_make_date_change_marker (now));
|
||||
return app_transcript_slice_offset (&slice);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
struct transcript_layout_ctx
|
||||
{
|
||||
struct transcript_slice slice;
|
||||
struct layout rows;
|
||||
};
|
||||
|
||||
static void
|
||||
transcript_layout_visit (enum transcript_visit_kind kind,
|
||||
struct buffer_line *line, time_t when, int height, void *user_data)
|
||||
{
|
||||
struct transcript_layout_ctx *c = user_data;
|
||||
if (!app_transcript_row_is_visible (&c->slice, height))
|
||||
return;
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
break; case VISIT_LINE:
|
||||
app_push (&c->rows, app_make_line (line));
|
||||
break; case VISIT_READ:
|
||||
app_push (&c->rows, app_make_read_marker ());
|
||||
break; case VISIT_DATE:
|
||||
app_push (&c->rows, app_make_date_change_marker (when));
|
||||
}
|
||||
}
|
||||
|
||||
static struct widget *
|
||||
app_make_transcript (time_t now)
|
||||
{
|
||||
struct layout rows = {};
|
||||
int offset = g.log.visible
|
||||
? app_append_log_rows (&rows)
|
||||
: app_append_buffer_rows (&rows, now);
|
||||
struct transcript_layout_ctx ctx =
|
||||
{ .slice = app_make_transcript_slice () };
|
||||
app_walk_transcript (now, transcript_layout_visit, &ctx);
|
||||
|
||||
struct widget *transcript = xui_vbox (rows.head);
|
||||
struct widget *transcript = xui_vbox (ctx.rows.head);
|
||||
transcript->on_allocated = app_on_viewport_allocated;
|
||||
transcript->widget_id = WIDGET_TRANSCRIPT;
|
||||
transcript->userdata = offset;
|
||||
transcript->userdata = app_transcript_slice_offset (&ctx.slice);
|
||||
transcript->width = transcript->height = -1;
|
||||
return transcript;
|
||||
}
|
||||
|
||||
struct transcript_height_ctx
|
||||
{
|
||||
int width;
|
||||
uint64_t height;
|
||||
};
|
||||
|
||||
static void
|
||||
transcript_height_visit (enum transcript_visit_kind kind,
|
||||
struct buffer_line *line, time_t when, int height, void *user_data)
|
||||
{
|
||||
struct transcript_height_ctx *c = user_data;
|
||||
switch (kind)
|
||||
{
|
||||
break; case VISIT_LINE:
|
||||
app_wrap_buffer_line_to_width (line, c->width);
|
||||
c->height += app_wrapped_line_height (line);
|
||||
break; default:
|
||||
c->height += height;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
app_transcript_height_at (int width, time_t now)
|
||||
{
|
||||
uint64_t height = 0;
|
||||
if (g.log.visible)
|
||||
{
|
||||
for (size_t i = 0; i < g.log.lines_len; i++)
|
||||
{
|
||||
app_wrap_log_line_to_width (g.log.lines[i], width);
|
||||
height += app_wrapped_line_height (g.log.lines[i]);
|
||||
}
|
||||
return MIN ((uint64_t) INT_MAX, height);
|
||||
}
|
||||
|
||||
struct buffer *buffer = g.buffer_current;
|
||||
if (!buffer)
|
||||
return 0;
|
||||
|
||||
height = buffer_has_read_marker (buffer) ? READ_MARKER_HEIGHT : 0;
|
||||
|
||||
struct tm last_date = {};
|
||||
bool have_last_date = false;
|
||||
LIST_FOR_EACH (struct buffer_line, line, buffer->lines)
|
||||
{
|
||||
if (!buffer_line_is_visible (buffer, line))
|
||||
continue;
|
||||
|
||||
if (app_date_changed (line->when / 1000, &last_date, &have_last_date))
|
||||
height += g_xui.vunit;
|
||||
app_wrap_buffer_line_to_width (line, width);
|
||||
height += app_wrapped_line_height (line);
|
||||
}
|
||||
if (have_last_date && app_date_changed (now, &last_date, &have_last_date))
|
||||
height += g_xui.vunit;
|
||||
return MIN ((uint64_t) INT_MAX, height);
|
||||
struct transcript_height_ctx ctx = { .width = width, .height = 0 };
|
||||
app_walk_transcript (now, transcript_height_visit, &ctx);
|
||||
return MIN ((uint64_t) INT_MAX, ctx.height);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static struct widget *
|
||||
app_make_middle (void)
|
||||
{
|
||||
@@ -3507,52 +3516,6 @@ app_external_editor_make_file (const char *template_name, const char *contents,
|
||||
return template;
|
||||
}
|
||||
|
||||
static void
|
||||
app_external_editor_append_line (struct str *output,
|
||||
const struct buffer_line *line, bool decorated)
|
||||
{
|
||||
if (decorated)
|
||||
{
|
||||
str_append (output, app_format_line_timestamp (line));
|
||||
str_append (output, app_line_mark (line->rendition));
|
||||
}
|
||||
LIST_FOR_EACH (struct buffer_line_item, item, line->items)
|
||||
str_append (output, item->text);
|
||||
str_append_c (output, '\n');
|
||||
}
|
||||
|
||||
static struct str
|
||||
app_external_editor_make_transcript (void)
|
||||
{
|
||||
struct str transcript = str_make ();
|
||||
if (g.log.visible)
|
||||
{
|
||||
for (size_t i = 0; i < g.log.lines_len; i++)
|
||||
app_external_editor_append_line
|
||||
(&transcript, g.log.lines[i], false);
|
||||
return transcript;
|
||||
}
|
||||
|
||||
struct buffer *buffer = g.buffer_current;
|
||||
struct tm last_date = {};
|
||||
bool have_last_date = false;
|
||||
LIST_FOR_EACH (struct buffer_line, line, buffer->lines)
|
||||
{
|
||||
if (!buffer_line_is_visible (buffer, line))
|
||||
continue;
|
||||
|
||||
time_t when = line->when / 1000;
|
||||
if (app_date_changed (when, &last_date, &have_last_date))
|
||||
str_append_printf (&transcript, "%s\n", app_format_date (when));
|
||||
app_external_editor_append_line (&transcript, line, true);
|
||||
}
|
||||
|
||||
time_t now = time (NULL);
|
||||
if (have_last_date && app_date_changed (now, &last_date, &have_last_date))
|
||||
str_append_printf (&transcript, "%s\n", app_format_date (now));
|
||||
return transcript;
|
||||
}
|
||||
|
||||
static void
|
||||
app_external_editor_process_file (void)
|
||||
{
|
||||
@@ -3678,6 +3641,29 @@ app_external_editor_launch (struct error **e)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
transcript_text_visit (enum transcript_visit_kind kind,
|
||||
struct buffer_line *line, time_t when, int height, void *user_data)
|
||||
{
|
||||
struct str *s = user_data;
|
||||
switch (kind)
|
||||
{
|
||||
break; case VISIT_LINE:
|
||||
if (when)
|
||||
{
|
||||
str_append (s, app_format_line_timestamp (line));
|
||||
str_append (s, app_line_mark (line->rendition));
|
||||
}
|
||||
LIST_FOR_EACH (struct buffer_line_item, item, line->items)
|
||||
str_append (s, item->text);
|
||||
str_append_c (s, '\n');
|
||||
break; case VISIT_READ:
|
||||
str_append (s, "---\n");
|
||||
break; case VISIT_DATE:
|
||||
str_append_printf (s, "%s\n", app_format_date (when));
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
app_launch_external_editor (bool view_transcript)
|
||||
{
|
||||
@@ -3689,9 +3675,10 @@ app_launch_external_editor (bool view_transcript)
|
||||
const char *template_name = "input.XXXXXX.txt";
|
||||
if (view_transcript)
|
||||
{
|
||||
struct str transcript = app_external_editor_make_transcript ();
|
||||
contents_len = transcript.len;
|
||||
contents = str_steal (&transcript);
|
||||
struct str text = str_make ();
|
||||
app_walk_transcript (time (NULL), transcript_text_visit, &text);
|
||||
contents_len = text.len;
|
||||
contents = str_steal (&text);
|
||||
template_name = "transcript.XXXXXX.txt";
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user