From cc67d05855146c1895a1f1b622858534623c8592 Mon Sep 17 00:00:00 2001 From: John Hernandez <129467592+H3rnand3zzz@users.noreply.github.com> Date: Thu, 23 Nov 2023 14:31:02 +0100 Subject: [PATCH] Fix scrolling (work in progress, poc) Calculate amount of displayed lines in buffer to avoid overflow in the curses. It has a few issues to be resolved before eventual clean up and readiness status. Fix https://github.com/profanity-im/profanity/issues/1934 --- src/database.c | 6 ++++-- src/ui/buffer.c | 50 +++++++++++++++++++++++++++++++++---------------- src/ui/buffer.h | 1 + src/ui/window.c | 27 ++++++++++++++++---------- 4 files changed, 56 insertions(+), 28 deletions(-) diff --git a/src/database.c b/src/database.c index ce1d1d3d2..cde456a45 100644 --- a/src/database.c +++ b/src/database.c @@ -338,8 +338,8 @@ log_database_get_previous_chat(const gchar* const contact_barejid, const char* s GDateTime* now = g_date_time_new_now_local(); auto_gchar gchar* end_date_fmt = end_time ? end_time : g_date_time_format_iso8601(now); auto_sqlite gchar* query = sqlite3_mprintf("SELECT * FROM (" - "SELECT COALESCE(B.`message`, A.`message`) AS message, " - "A.`timestamp`, A.`from_jid`, A.`to_jid`, A.`type`, A.`encryption` FROM `ChatLogs` AS A " + "SELECT CONCAT_WS('-', COALESCE(B.`message`, A.`message`), A.`id`) AS message, " + "A.`timestamp`, A.`from_jid`, A.`to_jid`, A.`type`, A.`encryption`, A.`id` FROM `ChatLogs` AS A " "LEFT JOIN `ChatLogs` AS B ON (A.`replaced_by_db_id` = B.`id` AND A.`from_jid` = B.`from_jid`) " "WHERE (A.`replaces_db_id` IS NULL) " "AND ((A.`from_jid` = %Q AND A.`to_jid` = %Q) OR (A.`from_jid` = %Q AND A.`to_jid` = %Q)) " @@ -371,6 +371,8 @@ log_database_get_previous_chat(const gchar* const contact_barejid, const char* s char* to_jid = (char*)sqlite3_column_text(stmt, 3); char* type = (char*)sqlite3_column_text(stmt, 4); char* encryption = (char*)sqlite3_column_text(stmt, 5); + char* mid = (char*)sqlite3_column_text(stmt, 6); + log_warning(mid); ProfMessage* msg = message_init(); msg->from_jid = jid_create(from); diff --git a/src/ui/buffer.c b/src/ui/buffer.c index e14434c2b..1a45b0008 100644 --- a/src/ui/buffer.c +++ b/src/ui/buffer.c @@ -53,14 +53,17 @@ #include "ui/window.h" #include "ui/buffer.h" -#define BUFF_SIZE 200 +#define BUFF_SIZE 200 +#define BUFF_SIZE_LINES 500 struct prof_buff_t { GSList* entries; + int lines; }; static void _free_entry(ProfBuffEntry* entry); +static int _count_lines(const char* const message); ProfBuff buffer_create(void) @@ -96,14 +99,14 @@ buffer_append(ProfBuff buffer, const char* show_char, int pad_indent, GDateTime* e->from_jid = from_jid ? strdup(from_jid) : NULL; e->message = strdup(message); e->receipt = receipt; - if (id) { - e->id = strdup(id); - } else { - e->id = NULL; - } - - if (g_slist_length(buffer->entries) == BUFF_SIZE) { - _free_entry(buffer->entries->data); + e->id = id ? strdup(id) : NULL; + e->lines = _count_lines(message); + buffer->lines += e->lines; + + while (g_slist_length(buffer->entries) > 1 && (g_slist_length(buffer->entries) >= BUFF_SIZE || buffer->lines > BUFF_SIZE_LINES)) { + ProfBuffEntry* entry_to_delete = (ProfBuffEntry*)buffer->entries->data; + buffer->lines -= entry_to_delete->lines; + _free_entry(entry_to_delete); buffer->entries = g_slist_delete_link(buffer->entries, buffer->entries); } @@ -123,15 +126,15 @@ buffer_prepend(ProfBuff buffer, const char* show_char, int pad_indent, GDateTime e->from_jid = from_jid ? strdup(from_jid) : NULL; e->message = strdup(message); e->receipt = receipt; - if (id) { - e->id = strdup(id); - } else { - e->id = NULL; - } + e->id = id ? strdup(id) : NULL; + e->lines = _count_lines(message); + buffer->lines += e->lines; - if (g_slist_length(buffer->entries) == BUFF_SIZE) { + while (g_slist_length(buffer->entries) > 1 && (g_slist_length(buffer->entries) >= BUFF_SIZE || buffer->lines > BUFF_SIZE_LINES)) { GSList* last = g_slist_last(buffer->entries); - _free_entry(last->data); + ProfBuffEntry* entry_to_delete = (ProfBuffEntry*)last->data; + buffer->lines -= entry_to_delete->lines; + _free_entry(entry_to_delete); buffer->entries = g_slist_delete_link(buffer->entries, last); } @@ -145,6 +148,7 @@ buffer_remove_entry_by_id(ProfBuff buffer, const char* const id) while (entries) { ProfBuffEntry* entry = entries->data; if (entry->id && (g_strcmp0(entry->id, id) == 0)) { + buffer->lines -= entry->lines; _free_entry(entry); buffer->entries = g_slist_delete_link(buffer->entries, entries); break; @@ -157,6 +161,7 @@ void buffer_remove_entry(ProfBuff buffer, int entry) { GSList* node = g_slist_nth(buffer->entries, entry); + buffer->lines -= ((ProfBuffEntry*)(node->data))->lines; _free_entry(node->data); buffer->entries = g_slist_delete_link(buffer->entries, node); } @@ -201,6 +206,19 @@ buffer_get_entry_by_id(ProfBuff buffer, const char* const id) return NULL; } +static int +_count_lines(const char* const message) +{ + int lines = 0; + for (int i = 0; message[i]; i++) { + if (message[i] == '\n') { + lines++; + } + } + + return lines; +} + static void _free_entry(ProfBuffEntry* entry) { diff --git a/src/ui/buffer.h b/src/ui/buffer.h index 591c48812..eb2093e41 100644 --- a/src/ui/buffer.h +++ b/src/ui/buffer.h @@ -52,6 +52,7 @@ typedef struct prof_buff_entry_t // pointer because it could be a unicode symbol as well gchar* show_char; int pad_indent; + int lines; GDateTime* time; int flags; theme_item_t theme_item; diff --git a/src/ui/window.c b/src/ui/window.c index 348bfeaa6..a937fe08c 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -626,14 +626,14 @@ void win_page_up(ProfWin* window) { _reached_bottom_of_database = FALSE; - int rows = getmaxy(stdscr); - int y = getcury(window->layout->win); - int page_space = rows - 4; - int* page_start = &(window->layout->y_pos); + int page_space = getmaxy(stdscr) - 4; + int curses_lines_buffer_size = getcury(window->layout->win); + int* pos_in_curses_buffer = &(window->layout->y_pos); + log_warning("page_up-1; page_space=%d, curses_lines_buffer_size=%d, pos_in_curses_buffer=%d, buffer_size=%d", page_space, curses_lines_buffer_size, *pos_in_curses_buffer, buffer_size(window->layout->buffer)); - *page_start -= page_space; + *pos_in_curses_buffer -= page_space; - if (*page_start == -page_space && window->type == WIN_CHAT) { + if (*pos_in_curses_buffer == -page_space && window->type == WIN_CHAT) { ProfChatWin* chatwin = (ProfChatWin*)window; ProfBuffEntry* first_entry = buffer_size(window->layout->buffer) != 0 ? buffer_get_entry(window->layout->buffer, 0) : NULL; @@ -651,14 +651,15 @@ win_page_up(ProfWin* window) } // went past beginning, show first page - if (*page_start < 0) - *page_start = 0; + if (*pos_in_curses_buffer < 0) + *pos_in_curses_buffer = 0; + log_warning("page_up-2; page_space=%d, curses_lines_buffer_size=%d, pos_in_curses_buffer=%d, buffer_size=%d", page_space, curses_lines_buffer_size, *pos_in_curses_buffer, buffer_size(window->layout->buffer)); window->layout->paged = 1; win_update_virtual(window); // switch off page if last line and space line visible - if ((y) - *page_start == page_space) { + if ((curses_lines_buffer_size) - *pos_in_curses_buffer == page_space) { window->layout->paged = 0; } } @@ -671,6 +672,7 @@ win_page_down(ProfWin* window) int y = getcury(window->layout->win); int page_space = rows - 4; int* page_start = &(window->layout->y_pos); + log_warning("page_down-1; page_space=%d, lines_ncurses_buffered=%d, pos_in_buffer=%d, buffer_size=%d", page_space, y, *page_start, buffer_size(window->layout->buffer)); *page_start += page_space; @@ -698,6 +700,8 @@ win_page_down(ProfWin* window) else if (*page_start >= y) *page_start = y - page_space - 1; + log_warning("page_down-2; page_space=%d, lines_ncurses_buffered=%d, pos_in_buffer=%d, buffer_size=%d", page_space, y, *page_start, buffer_size(window->layout->buffer)); + window->layout->paged = 1; win_update_virtual(window); @@ -1490,7 +1494,10 @@ win_print_old_history(ProfWin* window, const ProfMessage* const message) buffer_prepend(window->layout->buffer, ch, 0, message->timestamp, flags, THEME_TEXT_HISTORY, display_name, NULL, message->plain, NULL, NULL); wins_add_urls_ac(window, message, TRUE); wins_add_quotes_ac(window, message->plain, TRUE); - _win_print_internal(window, ch, 0, message->timestamp, flags, THEME_TEXT_HISTORY, display_name, message->plain, NULL); + // window is getting redrawn later in the only place where this function is getting called `chatwin.c` + // thus it's getting printed again, so to reduce load, we can as well remove this line (but it's a subject for a different PR) + // it's to be removed after clean up + // _win_print_internal(window, ch, 0, message->timestamp, flags, THEME_TEXT_HISTORY, display_name, message->plain, NULL); inp_nonblocking(TRUE); g_date_time_unref(message->timestamp);