about summary refs log tree commit diff stats
path: root/src/ui/inputwin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/inputwin.c')
-rw-r--r--src/ui/inputwin.c220
1 files changed, 122 insertions, 98 deletions
diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c
index a6877a86..85ddc79a 100644
--- a/src/ui/inputwin.c
+++ b/src/ui/inputwin.c
@@ -50,6 +50,7 @@
 #include "config/accounts.h"
 #include "config/preferences.h"
 #include "config/theme.h"
+#include "tools/history.h"
 #include "log.h"
 #include "muc.h"
 #include "profanity.h"
@@ -72,17 +73,25 @@
 #define KEY_CTRL_U 0025
 #define KEY_CTRL_W 0027
 
+#define MAX_HISTORY 100
+#define INP_WIN_MAX 1000
+
 static WINDOW *inp_win;
+static History history;
+
+static char input[INP_WIN_MAX];
+static int input_len_bytes;
+
 static int pad_start = 0;
 static int rows, cols;
 
-static int _handle_edit(int result, const wint_t ch, char *input, int *size);
-static int _handle_alt_key(char *input, int *size, int key);
-static void _handle_backspace(int display_size, int inp_x, int *size, char *input);
+static int _handle_edit(int key_type, const wint_t ch);
+static int _handle_alt_key(int key);
+static void _handle_backspace(void);
 static int _printable(const wint_t ch);
 static void _clear_input(void);
-static void _go_to_end(int display_size);
-static void _delete_previous_word(char *input, int *size);
+static void _go_to_end(void);
+static void _delete_previous_word(void);
 
 void
 create_input_window(void)
@@ -98,6 +107,7 @@ create_input_window(void)
     keypad(inp_win, TRUE);
     wmove(inp_win, 0, 0);
     _inp_win_update_virtual();
+    history = history_new(MAX_HISTORY);
 }
 
 void
@@ -131,38 +141,34 @@ inp_block(void)
     wtimeout(inp_win, -1);
 }
 
-wint_t
-inp_get_char(char *input, int *size, int *result)
+char *
+inp_read(int *key_type, wint_t *ch)
 {
-    wint_t ch;
-    int display_size = 0;
-
-    if (*size != 0) {
-        display_size = g_utf8_strlen(input, *size);
-    }
+    int display_size = utf8_display_len(input);
 
     // echo off, and get some more input
     noecho();
-    *result = wget_wch(inp_win, &ch);
+    *key_type = wget_wch(inp_win, ch);
 
     gboolean in_command = FALSE;
     if ((display_size > 0 && input[0] == '/') ||
-            (display_size == 0 && ch == '/')) {
+            (display_size == 0 && *ch == '/')) {
         in_command = TRUE;
     }
 
-    if (*result == ERR) {
+    if (*key_type == ERR) {
         prof_handle_idle();
     }
-    if ((*result != ERR) && (*result != KEY_CODE_YES) && !in_command && _printable(ch)) {
+    if ((*key_type != ERR) && (*key_type != KEY_CODE_YES) && !in_command && _printable(*ch)) {
         prof_handle_activity();
     }
 
     // if it wasn't an arrow key etc
-    if (!_handle_edit(*result, ch, input, size)) {
-        if (_printable(ch) && *result != KEY_CODE_YES) {
-            if (*size >= INP_WIN_MAX) {
-                return ERR;
+    if (!_handle_edit(*key_type, *ch)) {
+        if (_printable(*ch) && *key_type != KEY_CODE_YES) {
+            if (input_len_bytes >= INP_WIN_MAX) {
+                *ch = ERR;
+                return NULL;
             }
 
             int inp_x = getcurx(inp_win);
@@ -170,11 +176,11 @@ inp_get_char(char *input, int *size, int *result)
             // handle insert if not at end of input
             if (inp_x < display_size) {
                 char bytes[MB_CUR_MAX];
-                size_t utf_len = wcrtomb(bytes, ch, NULL);
+                size_t utf_len = wcrtomb(bytes, *ch, NULL);
 
                 char *next_ch = g_utf8_offset_to_pointer(input, inp_x);
                 char *offset;
-                for (offset = &input[*size - 1]; offset >= next_ch; offset--) {
+                for (offset = &input[input_len_bytes - 1]; offset >= next_ch; offset--) {
                     *(offset + utf_len) = *offset;
                 }
                 int i;
@@ -182,8 +188,8 @@ inp_get_char(char *input, int *size, int *result)
                      *(next_ch + i) = bytes[i];
                 }
 
-                *size += utf_len;
-                input[*size] = '\0';
+                input_len_bytes += utf_len;
+                input[input_len_bytes] = '\0';
                 waddstr(inp_win, next_ch);
                 wmove(inp_win, 0, inp_x + 1);
 
@@ -195,15 +201,15 @@ inp_get_char(char *input, int *size, int *result)
             // otherwise just append
             } else {
                 char bytes[MB_CUR_MAX+1];
-                size_t utf_len = wcrtomb(bytes, ch, NULL);
+                size_t utf_len = wcrtomb(bytes, *ch, NULL);
 
                 // wcrtomb can return (size_t) -1
                 if (utf_len < MB_CUR_MAX) {
                     int i;
                     for (i = 0 ; i < utf_len; i++) {
-                        input[(*size)++] = bytes[i];
+                        input[input_len_bytes++] = bytes[i];
                     }
-                    input[*size] = '\0';
+                    input[input_len_bytes] = '\0';
 
                     bytes[utf_len] = '\0';
                     waddstr(inp_win, bytes);
@@ -225,7 +231,13 @@ inp_get_char(char *input, int *size, int *result)
 
     echo();
 
-    return ch;
+    if (*ch == '\n') {
+        input[input_len_bytes] = '\0';
+        input_len_bytes = 0;
+        return strdup(input);
+    } else {
+        return NULL;
+    }
 }
 
 void
@@ -248,16 +260,14 @@ inp_put_back(void)
 }
 
 void
-inp_replace_input(char *input, const char * const new_input, int *size)
+inp_replace_input(const char * const new_input)
 {
-    int display_size;
     strncpy(input, new_input, INP_WIN_MAX);
-    *size = strlen(input);
-    display_size = g_utf8_strlen(input, *size);
+    input_len_bytes = strlen(input);
     inp_win_reset();
-    input[*size] = '\0';
+    input[input_len_bytes] = '\0';
     waddstr(inp_win, input);
-    _go_to_end(display_size);
+    _go_to_end();
 }
 
 void
@@ -268,6 +278,12 @@ inp_win_reset(void)
     _inp_win_update_virtual();
 }
 
+void
+inp_history_append(char *inp)
+{
+    history_append(history, inp);
+}
+
 static void
 _clear_input(void)
 {
@@ -281,23 +297,17 @@ _clear_input(void)
  * return 0 if it wasn't
  */
 static int
-_handle_edit(int result, const wint_t ch, char *input, int *size)
+_handle_edit(int key_type, const wint_t ch)
 {
     char *prev = NULL;
     char *next = NULL;
-    int inp_x = 0;
+    int inp_x = getcurx(inp_win);
     int next_ch;
-    int display_size = 0;
-
-    if (*size != 0) {
-        display_size = g_utf8_strlen(input, *size);
-    }
-
-    inp_x = getcurx(inp_win);
+    int display_size = utf8_display_len(input);
 
     // CTRL-LEFT
-    if ((result == KEY_CODE_YES) && (ch == 547 || ch == 545 || ch == 544 || ch == 540 || ch == 539) && (inp_x > 0)) {
-        input[*size] = '\0';
+    if ((key_type == KEY_CODE_YES) && (ch == 547 || ch == 545 || ch == 544 || ch == 540 || ch == 539) && (inp_x > 0)) {
+        input[input_len_bytes] = '\0';
         gchar *curr_ch = g_utf8_offset_to_pointer(input, inp_x);
         curr_ch = g_utf8_find_prev_char(input, curr_ch);
         gchar *prev_ch;
@@ -346,8 +356,8 @@ _handle_edit(int result, const wint_t ch, char *input, int *size)
         return 1;
 
     // CTRL-RIGHT
-    } else if ((result == KEY_CODE_YES) && (ch == 562 || ch == 560 || ch == 555 || ch == 559 || ch == 554) && (inp_x < display_size)) {
-        input[*size] = '\0';
+    } else if ((key_type == KEY_CODE_YES) && (ch == 562 || ch == 560 || ch == 555 || ch == 559 || ch == 554) && (inp_x < display_size)) {
+        input[input_len_bytes] = '\0';
         gchar *curr_ch = g_utf8_offset_to_pointer(input, inp_x);
         gchar *next_ch = g_utf8_find_next_char(curr_ch, NULL);
         gunichar curr_uni;
@@ -389,12 +399,12 @@ _handle_edit(int result, const wint_t ch, char *input, int *size)
         return 1;
 
     // ALT-LEFT
-    } else if ((result == KEY_CODE_YES) && (ch == 537 || ch == 542)) {
+    } else if ((key_type == KEY_CODE_YES) && (ch == 537 || ch == 542)) {
         ui_previous_win();
         return 1;
 
     // ALT-RIGHT
-    } else if ((result == KEY_CODE_YES) && (ch == 552 || ch == 557)) {
+    } else if ((key_type == KEY_CODE_YES) && (ch == 552 || ch == 557)) {
         ui_next_win();
         return 1;
 
@@ -406,34 +416,34 @@ _handle_edit(int result, const wint_t ch, char *input, int *size)
             // check for ALT-key
             next_ch = wgetch(inp_win);
             if (next_ch != ERR) {
-                return _handle_alt_key(input, size, next_ch);
+                return _handle_alt_key(next_ch);
             } else {
-                *size = 0;
+                input_len_bytes = 0;
                 inp_win_reset();
                 return 1;
             }
 
         case 127:
-            _handle_backspace(display_size, inp_x, size, input);
+            _handle_backspace();
             return 1;
         case KEY_BACKSPACE:
-            if (result != KEY_CODE_YES) {
+            if (key_type != KEY_CODE_YES) {
                 return 0;
             }
-            _handle_backspace(display_size, inp_x, size, input);
+            _handle_backspace();
             return 1;
 
         case KEY_DC: // DEL
-            if (result != KEY_CODE_YES) {
+            if (key_type != KEY_CODE_YES) {
                 return 0;
             }
         case KEY_CTRL_D:
             if (inp_x == display_size-1) {
                 gchar *start = g_utf8_substring(input, 0, inp_x);
-                for (*size = 0; *size < strlen(start); (*size)++) {
-                    input[*size] = start[*size];
+                for (input_len_bytes = 0; input_len_bytes < strlen(start); input_len_bytes++) {
+                    input[input_len_bytes] = start[input_len_bytes];
                 }
-                input[*size] = '\0';
+                input[input_len_bytes] = '\0';
 
                 g_free(start);
 
@@ -441,14 +451,14 @@ _handle_edit(int result, const wint_t ch, char *input, int *size)
                 waddstr(inp_win, input);
             } else if (inp_x < display_size-1) {
                 gchar *start = g_utf8_substring(input, 0, inp_x);
-                gchar *end = g_utf8_substring(input, inp_x+1, *size);
+                gchar *end = g_utf8_substring(input, inp_x+1, input_len_bytes);
                 GString *new = g_string_new(start);
                 g_string_append(new, end);
 
-                for (*size = 0; *size < strlen(new->str); (*size)++) {
-                    input[*size] = new->str[*size];
+                for (input_len_bytes = 0; input_len_bytes < strlen(new->str); input_len_bytes++) {
+                    input[input_len_bytes] = new->str[input_len_bytes];
                 }
-                input[*size] = '\0';
+                input[input_len_bytes] = '\0';
 
                 g_free(start);
                 g_free(end);
@@ -461,7 +471,7 @@ _handle_edit(int result, const wint_t ch, char *input, int *size)
             return 1;
 
         case KEY_LEFT:
-            if (result != KEY_CODE_YES) {
+            if (key_type != KEY_CODE_YES) {
                 return 0;
             }
         case KEY_CTRL_B:
@@ -477,7 +487,7 @@ _handle_edit(int result, const wint_t ch, char *input, int *size)
             return 1;
 
         case KEY_RIGHT:
-            if (result != KEY_CODE_YES) {
+            if (key_type != KEY_CODE_YES) {
                 return 0;
             }
         case KEY_CTRL_F:
@@ -493,33 +503,35 @@ _handle_edit(int result, const wint_t ch, char *input, int *size)
             return 1;
 
         case KEY_UP:
-            if (result != KEY_CODE_YES) {
+            if (key_type != KEY_CODE_YES) {
                 return 0;
             }
         case KEY_CTRL_P:
-            prev = cmd_history_previous(input, size);
+            input[input_len_bytes] = '\0';
+            prev = history_previous(history, input);
             if (prev) {
-                inp_replace_input(input, prev, size);
+                inp_replace_input(prev);
             }
             return 1;
 
         case KEY_DOWN:
-            if (result != KEY_CODE_YES) {
+            if (key_type != KEY_CODE_YES) {
                 return 0;
             }
         case KEY_CTRL_N:
-            next = cmd_history_next(input, size);
+            input[input_len_bytes] = '\0';
+            next = history_next(history, input);
             if (next) {
-                inp_replace_input(input, next, size);
-            } else if (*size != 0) {
-                input[*size] = '\0';
-                cmd_history_append(input);
-                inp_replace_input(input, "", size);
+                inp_replace_input(next);
+            } else if (input_len_bytes != 0) {
+                input[input_len_bytes] = '\0';
+                history_append(history, input);
+                inp_replace_input("");
             }
             return 1;
 
         case KEY_HOME:
-            if (result != KEY_CODE_YES) {
+            if (key_type != KEY_CODE_YES) {
                 return 0;
             }
         case KEY_CTRL_A:
@@ -529,31 +541,40 @@ _handle_edit(int result, const wint_t ch, char *input, int *size)
             return 1;
 
         case KEY_END:
-            if (result != KEY_CODE_YES) {
+            if (key_type != KEY_CODE_YES) {
                 return 0;
             }
         case KEY_CTRL_E:
-            _go_to_end(display_size);
+            _go_to_end();
             return 1;
 
         case 9: // tab
-            if (*size != 0) {
+            if (input_len_bytes != 0) {
+                input[input_len_bytes] = '\0';
                 if ((strncmp(input, "/", 1) != 0) && (ui_current_win_type() == WIN_MUC)) {
-                    muc_autocomplete(input, size);
+                    char *result = muc_autocomplete(input);
+                    if (result) {
+                        inp_replace_input(result);
+                        free(result);
+                    }
                 } else if (strncmp(input, "/", 1) == 0) {
-                    cmd_autocomplete(input, size);
+                    char *result = cmd_autocomplete(input);
+                    if (result) {
+                        inp_replace_input(result);
+                        free(result);
+                    }
                 }
             }
             return 1;
 
         case KEY_CTRL_W:
-            _delete_previous_word(input, size);
+            _delete_previous_word();
             return 1;
             break;
 
         case KEY_CTRL_U:
             while (getcurx(inp_win) > 0) {
-                _delete_previous_word(input, size);
+                _delete_previous_word();
             }
             return 1;
             break;
@@ -565,18 +586,20 @@ _handle_edit(int result, const wint_t ch, char *input, int *size)
 }
 
 static void
-_handle_backspace(int display_size, int inp_x, int *size, char *input)
+_handle_backspace(void)
 {
+    int inp_x = getcurx(inp_win);
+    int display_size = utf8_display_len(input);
     roster_reset_search_attempts();
     if (display_size > 0) {
 
         // if at end, delete last char
         if (inp_x >= display_size) {
             gchar *start = g_utf8_substring(input, 0, inp_x-1);
-            for (*size = 0; *size < strlen(start); (*size)++) {
-                input[*size] = start[*size];
+            for (input_len_bytes = 0; input_len_bytes < strlen(start); input_len_bytes++) {
+                input[input_len_bytes] = start[input_len_bytes];
             }
-            input[*size] = '\0';
+            input[input_len_bytes] = '\0';
 
             g_free(start);
 
@@ -587,14 +610,14 @@ _handle_backspace(int display_size, int inp_x, int *size, char *input)
         // if in middle, delete and shift chars left
         } else if (inp_x > 0 && inp_x < display_size) {
             gchar *start = g_utf8_substring(input, 0, inp_x - 1);
-            gchar *end = g_utf8_substring(input, inp_x, *size);
+            gchar *end = g_utf8_substring(input, inp_x, input_len_bytes);
             GString *new = g_string_new(start);
             g_string_append(new, end);
 
-            for (*size = 0; *size < strlen(new->str); (*size)++) {
-                input[*size] = new->str[*size];
+            for (input_len_bytes = 0; input_len_bytes < strlen(new->str); input_len_bytes++) {
+                input[input_len_bytes] = new->str[input_len_bytes];
             }
-            input[*size] = '\0';
+            input[input_len_bytes] = '\0';
 
             g_free(start);
             g_free(end);
@@ -619,7 +642,7 @@ _handle_backspace(int display_size, int inp_x, int *size, char *input)
 }
 
 static int
-_handle_alt_key(char *input, int *size, int key)
+_handle_alt_key(int key)
 {
     switch (key)
     {
@@ -661,7 +684,7 @@ _handle_alt_key(char *input, int *size, int key)
             break;
         case 263:
         case 127:
-            _delete_previous_word(input, size);
+            _delete_previous_word();
             break;
         default:
             break;
@@ -670,12 +693,12 @@ _handle_alt_key(char *input, int *size, int key)
 }
 
 static void
-_delete_previous_word(char *input, int *size)
+_delete_previous_word(void)
 {
     int end_del = getcurx(inp_win);
     int start_del = end_del;
 
-    input[*size] = '\0';
+    input[input_len_bytes] = '\0';
     gchar *curr_ch = g_utf8_offset_to_pointer(input, end_del);
     curr_ch = g_utf8_find_prev_char(input, curr_ch);
     gchar *prev_ch;
@@ -721,8 +744,8 @@ _delete_previous_word(char *input, int *size)
         input[strlen(start_string)+i] = end_string[i];
     }
 
-    *size = strlen(start_string)+i;
-    input[*size] = '\0';
+    input_len_bytes = strlen(start_string)+i;
+    input[input_len_bytes] = '\0';
 
     _clear_input();
     waddstr(inp_win, input);
@@ -740,8 +763,9 @@ _delete_previous_word(char *input, int *size)
 }
 
 static void
-_go_to_end(int display_size)
+_go_to_end(void)
 {
+    int display_size = utf8_display_len(input);
     wmove(inp_win, 0, display_size);
     if (display_size > cols-2) {
         pad_start = display_size - cols + 1;