about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMarcoPolo-PasTonMolo <marcopolopastonmolo@protonmail.com>2022-03-21 00:10:07 +0200
committerMarcoPolo-PasTonMolo <marcopolopastonmolo@protonmail.com>2022-03-21 13:46:50 +0200
commit06ef6842e8ff6b7a754c54f4af39775bc842612b (patch)
treeb811ac7e13551c8ca9fbfc072a2e7a5fc37acf34
parent09e7f63c790089acfe1fd39f686597891cada5a7 (diff)
downloadprofani-tty-06ef6842e8ff6b7a754c54f4af39775bc842612b.tar.gz
Add quote autocompletion for previous messages
Fixes https://github.com/profanity-im/profanity/issues/1649

Type `>` then press tab or shift tab to autocomplete previous messages,
then type your reply and send message.
Newlines are replaced with newline followed by `> `.
A newline is added at the end so that the user can immediately type a
message without manually adding a new line.
-rw-r--r--src/ui/chatwin.c4
-rw-r--r--src/ui/inputwin.c27
-rw-r--r--src/ui/mucwin.c3
-rw-r--r--src/ui/privwin.c3
-rw-r--r--src/ui/win_types.h1
-rw-r--r--src/ui/window.c23
-rw-r--r--src/ui/window.h2
-rw-r--r--src/ui/window_list.c22
-rw-r--r--src/ui/window_list.h2
-rw-r--r--tests/unittests/test_cmd_otr.c7
10 files changed, 93 insertions, 1 deletions
diff --git a/src/ui/chatwin.c b/src/ui/chatwin.c
index 0224d720..d02e4162 100644
--- a/src/ui/chatwin.c
+++ b/src/ui/chatwin.c
@@ -323,6 +323,7 @@ chatwin_incoming_msg(ProfChatWin* chatwin, ProfMessage* message, gboolean win_cr
     }
 
     wins_add_urls_ac(window, message);
+    wins_add_quotes_ac(window, message->plain);
 
     if (prefs_get_boolean(PREF_BEEP)) {
         beep();
@@ -346,6 +347,9 @@ chatwin_outgoing_msg(ProfChatWin* chatwin, const char* const message, char* id,
 {
     assert(chatwin != NULL);
 
+    ProfWin* window = (ProfWin*)chatwin;
+    wins_add_quotes_ac(window, message);
+
     char* enc_char;
     if (chatwin->outgoing_char) {
         enc_char = chatwin->outgoing_char;
diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c
index 9e34c0b6..d19d8719 100644
--- a/src/ui/inputwin.c
+++ b/src/ui/inputwin.c
@@ -558,6 +558,10 @@ _inp_rl_getc(FILE* stream)
     if (_inp_edited(ch)) {
         ProfWin* window = wins_get_current();
         cmd_ac_reset(window);
+
+        if ((window->type == WIN_CHAT || window->type == WIN_MUC || window->type == WIN_PRIVATE) && window->quotes_ac != NULL) {
+            autocomplete_reset(window->quotes_ac);
+        }
     }
     return ch;
 }
@@ -597,6 +601,17 @@ _inp_rl_tab_handler(int count, int key)
         }
     }
 
+    if (strncmp(rl_line_buffer, ">", 1) == 0) {
+        ProfWin* window = wins_get_current();
+        char* result = win_quote_autocomplete(window, rl_line_buffer, FALSE);
+        if (result) {
+            rl_replace_line(result, 1);
+            rl_point = rl_end;
+            free(result);
+            return 0;
+        }
+    }
+
     ProfWin* current = wins_get_current();
     if (current->type == WIN_MUC) {
         char* result = muc_autocomplete(current, rl_line_buffer, FALSE);
@@ -607,7 +622,6 @@ _inp_rl_tab_handler(int count, int key)
         }
     }
 
-
     return 0;
 }
 
@@ -629,6 +643,17 @@ _inp_rl_shift_tab_handler(int count, int key)
         }
     }
 
+    if (strncmp(rl_line_buffer, ">", 1) == 0) {
+        ProfWin* window = wins_get_current();
+        char* result = win_quote_autocomplete(window, rl_line_buffer, TRUE);
+        if (result) {
+            rl_replace_line(result, 1);
+            rl_point = rl_end;
+            free(result);
+            return 0;
+        }
+    }
+
     ProfWin* current = wins_get_current();
     if (current->type == WIN_MUC) {
         char* result = muc_autocomplete(current, rl_line_buffer, TRUE);
diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c
index 5bf21722..c5aed583 100644
--- a/src/ui/mucwin.c
+++ b/src/ui/mucwin.c
@@ -541,6 +541,8 @@ mucwin_outgoing_msg(ProfMucWin* mucwin, const char* const message, const char* c
     if (id) {
         _mucwin_set_last_message(mucwin, id, message);
     }
+
+    wins_add_quotes_ac(window, message);
 }
 
 void
@@ -576,6 +578,7 @@ mucwin_incoming_msg(ProfMucWin* mucwin, const ProfMessage* const message, GSList
 
     win_insert_last_read_position_marker((ProfWin*)mucwin, mucwin->roomjid);
     wins_add_urls_ac(window, message);
+    wins_add_quotes_ac(window, message->plain);
 
     if (g_slist_length(mentions) > 0) {
         _mucwin_print_mention(window, message->plain, message->from_jid->resourcepart, mynick, mentions, ch, flags);
diff --git a/src/ui/privwin.c b/src/ui/privwin.c
index 73ef61a0..20611ea4 100644
--- a/src/ui/privwin.c
+++ b/src/ui/privwin.c
@@ -82,6 +82,7 @@ privwin_incoming_msg(ProfPrivateWin* privatewin, ProfMessage* message)
     }
 
     wins_add_urls_ac(window, message);
+    wins_add_quotes_ac(window, message->plain);
 
     if (prefs_get_boolean(PREF_BEEP)) {
         beep();
@@ -99,6 +100,8 @@ privwin_outgoing_msg(ProfPrivateWin* privwin, const char* const message)
 {
     assert(privwin != NULL);
 
+    ProfWin* window = (ProfWin*)privwin;
+    wins_add_quotes_ac(window, message);
     win_print_outgoing((ProfWin*)privwin, "-", NULL, NULL, message);
 }
 
diff --git a/src/ui/win_types.h b/src/ui/win_types.h
index f2237a79..70d226b0 100644
--- a/src/ui/win_types.h
+++ b/src/ui/win_types.h
@@ -148,6 +148,7 @@ typedef struct prof_win_t
     win_type_t type;
     ProfLayout* layout;
     Autocomplete urls_ac;
+    Autocomplete quotes_ac;
 } ProfWin;
 
 typedef struct prof_console_win_t
diff --git a/src/ui/window.c b/src/ui/window.c
index 54932f21..516e2209 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -2020,3 +2020,26 @@ win_insert_last_read_position_marker(ProfWin* window, char* id)
 
     g_date_time_unref(time);
 }
+
+char*
+win_quote_autocomplete(ProfWin* window, const char* const input, gboolean previous)
+{
+    if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) {
+        return NULL;
+    }
+
+    char* result = autocomplete_complete(window->quotes_ac, input + 1, FALSE, previous);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    GString* replace_with = g_string_new("> ");
+    g_string_append(replace_with, result);
+    g_string_replace(replace_with, "\n", "\n> ", 0);
+    g_string_append(replace_with, "\n");
+
+    g_free(result);
+    result = replace_with->str;
+    g_string_free(replace_with, FALSE);
+    return result;
+}
diff --git a/src/ui/window.h b/src/ui/window.h
index 22a1db51..c7c2853e 100644
--- a/src/ui/window.h
+++ b/src/ui/window.h
@@ -93,4 +93,6 @@ void win_sub_page_up(ProfWin* window);
 void win_insert_last_read_position_marker(ProfWin* window, char* id);
 void win_remove_entry_message(ProfWin* window, const char* const id);
 
+char* win_quote_autocomplete(ProfWin* window, const char* const input, gboolean previous);
+
 #endif
diff --git a/src/ui/window_list.c b/src/ui/window_list.c
index 01379804..a6ebb5fe 100644
--- a/src/ui/window_list.c
+++ b/src/ui/window_list.c
@@ -554,6 +554,7 @@ wins_close_by_num(int i)
                     }
                 }
                 autocomplete_free(window->urls_ac);
+                autocomplete_free(window->quotes_ac);
                 break;
             }
             case WIN_MUC:
@@ -566,6 +567,7 @@ wins_close_by_num(int i)
                     g_date_time_unref(mucwin->last_msg_timestamp);
                 }
                 autocomplete_free(window->urls_ac);
+                autocomplete_free(window->quotes_ac);
                 break;
             }
             case WIN_PRIVATE:
@@ -574,6 +576,7 @@ wins_close_by_num(int i)
                 autocomplete_remove(wins_ac, privwin->fulljid);
                 autocomplete_remove(wins_close_ac, privwin->fulljid);
                 autocomplete_free(window->urls_ac);
+                autocomplete_free(window->quotes_ac);
                 break;
             }
             case WIN_XML:
@@ -646,6 +649,7 @@ wins_new_chat(const char* const barejid)
         }
     }
     newwin->urls_ac = autocomplete_new();
+    newwin->quotes_ac = autocomplete_new();
 
     return newwin;
 }
@@ -661,6 +665,7 @@ wins_new_muc(const char* const roomjid)
     autocomplete_add(wins_ac, roomjid);
     autocomplete_add(wins_close_ac, roomjid);
     newwin->urls_ac = autocomplete_new();
+    newwin->quotes_ac = autocomplete_new();
 
     return newwin;
 }
@@ -688,6 +693,7 @@ wins_new_private(const char* const fulljid)
     autocomplete_add(wins_ac, fulljid);
     autocomplete_add(wins_close_ac, fulljid);
     newwin->urls_ac = autocomplete_new();
+    newwin->quotes_ac = autocomplete_new();
 
     return newwin;
 }
@@ -1299,6 +1305,14 @@ wins_add_urls_ac(const ProfWin* const win, const ProfMessage* const message)
     g_regex_unref(regex);
 }
 
+void
+wins_add_quotes_ac(const ProfWin* const win, const char* const message)
+{
+    autocomplete_add_reverse(win->quotes_ac, message);
+    // for people who run profanity a long time, we don't want to waste a lot of memory
+    autocomplete_remove_older_than_max_reverse(win->quotes_ac, 20);
+}
+
 char*
 wins_get_url(const char* const search_str, gboolean previous, void* context)
 {
@@ -1306,3 +1320,11 @@ wins_get_url(const char* const search_str, gboolean previous, void* context)
 
     return autocomplete_complete(win->urls_ac, search_str, FALSE, previous);
 }
+
+char*
+wins_get_quote(const char* const search_str, gboolean previous, void* context)
+{
+    ProfWin* win = (ProfWin*)context;
+
+    return autocomplete_complete(win->quotes_ac, search_str, FALSE, previous);
+}
diff --git a/src/ui/window_list.h b/src/ui/window_list.h
index 06ae6d7e..bcb18d14 100644
--- a/src/ui/window_list.h
+++ b/src/ui/window_list.h
@@ -102,5 +102,7 @@ void win_close_reset_search_attempts(void);
 
 void wins_add_urls_ac(const ProfWin* const win, const ProfMessage* const message);
 char* wins_get_url(const char* const search_str, gboolean previous, void* context);
+void wins_add_quotes_ac(const ProfWin* const win, const char* const message);
+char* wins_get_quote(const char* const search_str, gboolean previous, void* context);
 
 #endif
diff --git a/tests/unittests/test_cmd_otr.c b/tests/unittests/test_cmd_otr.c
index 0aca077c..7dcc1767 100644
--- a/tests/unittests/test_cmd_otr.c
+++ b/tests/unittests/test_cmd_otr.c
@@ -271,6 +271,7 @@ test_cmd_otr_theirfp_from_wintype(win_type_t wintype)
     window.type = wintype;
     window.layout = NULL;
     window.urls_ac = NULL;
+    window.quotes_ac = NULL;
 
     will_return(connection_get_status, JABBER_CONNECTED);
 
@@ -308,6 +309,7 @@ cmd_otr_theirfp_shows_message_when_non_otr_chat_window(void** state)
     window.type = WIN_CHAT;
     window.layout = NULL;
     window.urls_ac = NULL;
+    window.quotes_ac = NULL;
     ProfChatWin chatwin;
     chatwin.window = window;
     chatwin.memcheck = PROFCHATWIN_MEMCHECK;
@@ -337,6 +339,7 @@ cmd_otr_theirfp_shows_fingerprint(void** state)
     window.type = WIN_CHAT;
     window.layout = NULL;
     window.urls_ac = NULL;
+    window.quotes_ac = NULL;
     ProfChatWin chatwin;
     chatwin.window = window;
     chatwin.barejid = recipient;
@@ -365,6 +368,7 @@ test_cmd_otr_start_from_wintype(win_type_t wintype)
     window.type = wintype;
     window.layout = NULL;
     window.urls_ac = NULL;
+    window.quotes_ac = NULL;
 
     will_return(connection_get_status, JABBER_CONNECTED);
 
@@ -404,6 +408,7 @@ cmd_otr_start_shows_message_when_already_started(void** state)
     window.type = WIN_CHAT;
     window.layout = NULL;
     window.urls_ac = NULL;
+    window.quotes_ac = NULL;
     ProfChatWin chatwin;
     chatwin.window = window;
     chatwin.barejid = recipient;
@@ -430,6 +435,7 @@ cmd_otr_start_shows_message_when_no_key(void** state)
     window.type = WIN_CHAT;
     window.layout = NULL;
     window.urls_ac = NULL;
+    window.quotes_ac = NULL;
     ProfChatWin chatwin;
     chatwin.window = window;
     chatwin.barejid = recipient;
@@ -454,6 +460,7 @@ cmd_otr_start_sends_otr_query_message_to_current_recipeint(void** state)
     window.type = WIN_CHAT;
     window.layout = NULL;
     window.urls_ac = NULL;
+    window.quotes_ac = NULL;
     ProfChatWin chatwin;
     chatwin.window = window;
     chatwin.barejid = recipient;