diff options
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/curses/gui-curses-key.c | 351 | ||||
-rw-r--r-- | src/gui/gui-key.c | 172 | ||||
-rw-r--r-- | src/gui/gui-key.h | 13 |
3 files changed, 339 insertions, 197 deletions
diff --git a/src/gui/curses/gui-curses-key.c b/src/gui/curses/gui-curses-key.c index 1f06e8d33..b74c19f4f 100644 --- a/src/gui/curses/gui-curses-key.c +++ b/src/gui/curses/gui-curses-key.c @@ -290,202 +290,189 @@ gui_key_default_bindings (int context) */ void -gui_key_flush (int ignore_bracketed) +gui_key_flush (int paste) { - int i, j, key, insert_ok; + int i, key, last_key_used, insert_ok, undo_done; static char key_str[64] = { '\0' }; static int length_key_str = 0; char key_temp[2], *key_utf, *input_old, *ptr_char, *next_char, *ptr_error; char utf_partial_char[16]; + /* if paste pending or bracketed paste detected, just return */ + if (gui_key_paste_pending || gui_key_paste_bracketed) + return; + + /* if buffer is empty, just return */ + if (gui_key_buffer_size == 0) + return; + /* * if there's no paste pending, then we use buffer and do actions * according to keys */ - if (!gui_key_paste_pending) + gui_key_last_activity_time = time (NULL); + last_key_used = -1; + undo_done = 0; + for (i = 0; i < gui_key_buffer_size; i++) { - if (gui_key_buffer_size > 0) - gui_key_last_activity_time = time (NULL); + key = gui_key_buffer[i]; + insert_ok = 1; + utf_partial_char[0] = '\0'; - for (i = 0; i < gui_key_buffer_size; i++) + if (gui_mouse_event_pending || (key < 32) || (key == 127)) { - key = gui_key_buffer[i]; - insert_ok = 1; - utf_partial_char[0] = '\0'; - - if (gui_mouse_event_pending || (key < 32) || (key == 127)) + if (gui_mouse_event_pending) { - if (gui_mouse_event_pending) - { - insert_ok = 0; - key_str[0] = (char)key; - key_str[1] = '\0'; - length_key_str = 1; - } - else if (key < 32) - { - insert_ok = 0; - key_str[0] = '\x01'; - key_str[1] = (char)key + '@'; - key_str[2] = '\0'; - length_key_str = 2; - } - else if (key == 127) - { - key_str[0] = '\x01'; - key_str[1] = '?'; - key_str[2] = '\0'; - length_key_str = 2; - } + insert_ok = 0; + key_str[0] = (char)key; + key_str[1] = '\0'; + length_key_str = 1; } - else + else if (key < 32) { - if (local_utf8) + insert_ok = 0; + key_str[0] = '\x01'; + key_str[1] = (char)key + '@'; + key_str[2] = '\0'; + length_key_str = 2; + } + else if (key == 127) + { + key_str[0] = '\x01'; + key_str[1] = '?'; + key_str[2] = '\0'; + length_key_str = 2; + } + } + else + { + if (local_utf8) + { + key_str[length_key_str] = (char)key; + key_str[length_key_str + 1] = '\0'; + length_key_str++; + + /* + * replace invalid chars by "?", but NOT last char of + * string, if it is incomplete UTF-8 char (another char + * will be added to the string on next iteration) + */ + ptr_char = key_str; + while (ptr_char && ptr_char[0]) { - key_str[length_key_str] = (char)key; - key_str[length_key_str + 1] = '\0'; - length_key_str++; - - /* - * replace invalid chars by "?", but NOT last char of - * string, if it is incomplete UTF-8 char (another char - * will be added to the string on next iteration) - */ - ptr_char = key_str; - while (ptr_char && ptr_char[0]) + (void) utf8_is_valid (ptr_char, &ptr_error); + if (!ptr_error) + break; + next_char = utf8_next_char (ptr_error); + if (next_char && next_char[0]) { - (void) utf8_is_valid (ptr_char, &ptr_error); - if (!ptr_error) - break; - next_char = utf8_next_char (ptr_error); - if (next_char && next_char[0]) - { - ptr_char = ptr_error; - while (ptr_char < next_char) - { - ptr_char[0] = '?'; - ptr_char++; - } - } - else + ptr_char = ptr_error; + while (ptr_char < next_char) { - strcpy (utf_partial_char, ptr_char); - ptr_char[0] = '\0'; - break; + ptr_char[0] = '?'; + ptr_char++; } - ptr_char = next_char; } - } - else - { - /* convert input to UTF-8 */ - key_temp[0] = (char) key; - key_temp[1] = '\0'; - key_utf = string_iconv_to_internal (NULL, key_temp); - strcat (key_str, key_utf); + else + { + strcpy (utf_partial_char, ptr_char); + ptr_char[0] = '\0'; + break; + } + ptr_char = next_char; } } - - if (key_str[0]) + else { - hook_signal_send ("key_pressed", - WEECHAT_HOOK_SIGNAL_STRING, key_str); + /* convert input to UTF-8 */ + key_temp[0] = (char)key; + key_temp[1] = '\0'; + key_utf = string_iconv_to_internal (NULL, key_temp); + strcat (key_str, key_utf); + } + } - if (gui_current_window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED) - input_old = (gui_current_window->buffer->input_buffer) ? - strdup (gui_current_window->buffer->input_buffer) : strdup (""); - else - input_old = NULL; + if (key_str[0]) + { + hook_signal_send ("key_pressed", + WEECHAT_HOOK_SIGNAL_STRING, key_str); - if ((gui_key_pressed (key_str) != 0) && (insert_ok) - && (!gui_cursor_mode)) - { + if (gui_current_window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED) + input_old = (gui_current_window->buffer->input_buffer) ? + strdup (gui_current_window->buffer->input_buffer) : strdup (""); + else + input_old = NULL; + + if ((gui_key_pressed (key_str) != 0) && (insert_ok) + && (!gui_cursor_mode)) + { + if (!paste || !undo_done) gui_buffer_undo_snap (gui_current_window->buffer); - gui_input_insert_string (gui_current_window->buffer, - key_str, -1); - if (gui_current_window->buffer->completion) - gui_completion_stop (gui_current_window->buffer->completion, 0); - gui_input_text_changed_modifier_and_signal (gui_current_window->buffer, 1); - } + gui_input_insert_string (gui_current_window->buffer, + key_str, -1); + if (gui_current_window->buffer->completion) + gui_completion_stop (gui_current_window->buffer->completion, 0); + gui_input_text_changed_modifier_and_signal (gui_current_window->buffer, + (!paste || !undo_done) ? 1 : 0); + undo_done = 1; + } - /* incremental text search in buffer */ - if ((gui_current_window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED) - && ((input_old == NULL) - || (gui_current_window->buffer->input_buffer == NULL) - || (strcmp (input_old, gui_current_window->buffer->input_buffer) != 0))) + /* incremental text search in buffer */ + if ((gui_current_window->buffer->text_search != GUI_TEXT_SEARCH_DISABLED) + && ((input_old == NULL) + || (gui_current_window->buffer->input_buffer == NULL) + || (strcmp (input_old, gui_current_window->buffer->input_buffer) != 0))) + { + /* + * if current input is longer than old input, and that + * beginning of current input is exactly equal to old input, + * then do nothing (search will not find any result and can + * take some time on buffer with many lines..) + */ + if (!gui_current_window->buffer->text_search_found + && (input_old != NULL) + && (input_old[0]) + && (gui_current_window->buffer->input_buffer != NULL) + && (gui_current_window->buffer->input_buffer[0]) + && (strlen (gui_current_window->buffer->input_buffer) > strlen (input_old)) + && (strncmp (gui_current_window->buffer->input_buffer, input_old, + strlen (input_old)) == 0)) { /* - * if current input is longer than old input, and that - * beginning of current input is exactly equal to old input, - * then do nothing (search will not find any result and can - * take some time on buffer with many lines..) + * do not search text in buffer, just alert about text not + * found */ - if (!gui_current_window->buffer->text_search_found - && (input_old != NULL) - && (input_old[0]) - && (gui_current_window->buffer->input_buffer != NULL) - && (gui_current_window->buffer->input_buffer[0]) - && (strlen (gui_current_window->buffer->input_buffer) > strlen (input_old)) - && (strncmp (gui_current_window->buffer->input_buffer, input_old, - strlen (input_old)) == 0)) - { - /* - * do not search text in buffer, just alert about text not - * found - */ - if (CONFIG_BOOLEAN(config_look_search_text_not_found_alert)) - printf ("\a"); - } - else - { - gui_window_search_restart (gui_current_window); - } + if (CONFIG_BOOLEAN(config_look_search_text_not_found_alert)) + printf ("\a"); } - - if (input_old) - free (input_old); - } - - /* prepare incomplete UTF-8 char for next iteration */ - if (utf_partial_char[0]) - strcpy (key_str, utf_partial_char); - else - key_str[0] = '\0'; - length_key_str = strlen (key_str); - - /* - * bracketed paste detected (ESC[200~ + text + ESC[201~): - * the ESC[200~ has been found and will be removed immediately, - * the ESC[201~ should be found/removed later) - */ - if (gui_key_paste_bracketed) - { - gui_key_paste_bracketed = 0; - - if (!ignore_bracketed) + else { - /* check for large paste */ - if (gui_key_paste_check (1)) - { - /* - * paste mode has been enabled (ask to user what do to), - * then remove the ESC[200~ from beginning of buffer, - * stop reading buffer immediately and return - */ - i++; - for (j = 0; j < gui_key_buffer_size - i; j++) - { - gui_key_buffer[j] = gui_key_buffer[j + i]; - } - gui_key_buffer_size -= i; - return; - } + gui_window_search_restart (gui_current_window); } } + + if (input_old) + free (input_old); } - gui_key_buffer_reset (); + /* prepare incomplete UTF-8 char for next iteration */ + if (utf_partial_char[0]) + strcpy (key_str, utf_partial_char); + else + key_str[0] = '\0'; + length_key_str = strlen (key_str); + + /* set last key used in buffer if combo buffer is empty */ + if (!gui_key_combo_buffer[0]) + last_key_used = i; } + + if (last_key_used == gui_key_buffer_size - 1) + gui_key_buffer_reset (); + else if (last_key_used >= 0) + gui_key_buffer_remove (0, last_key_used + 1); + + gui_key_combo_buffer[0] = '\0'; } /* @@ -495,8 +482,7 @@ gui_key_flush (int ignore_bracketed) int gui_key_read_cb (void *data, int fd) { - int ret, i, accept_paste, cancel_paste, text_added_to_buffer; - int ignore_bracketed_paste; + int ret, i, accept_paste, cancel_paste, text_added_to_buffer, pos; unsigned char buffer[4096]; /* make C compiler happy */ @@ -506,7 +492,6 @@ gui_key_read_cb (void *data, int fd) accept_paste = 0; cancel_paste = 0; text_added_to_buffer = 0; - ignore_bracketed_paste = 0; ret = read (STDIN_FILENO, buffer, sizeof (buffer)); if (ret == 0) @@ -542,11 +527,6 @@ gui_key_read_cb (void *data, int fd) /* ctrl-N: cancel paste */ cancel_paste = 1; } - else - { - gui_key_buffer_add (buffer[i]); - text_added_to_buffer = 1; - } } else { @@ -562,7 +542,6 @@ gui_key_read_cb (void *data, int fd) { /* user is ok for pasting text, let's paste! */ gui_key_paste_accept (); - ignore_bracketed_paste = 1; } else if (cancel_paste) { @@ -576,9 +555,43 @@ gui_key_read_cb (void *data, int fd) } } else - gui_key_paste_check (0); + { + if (!gui_key_paste_bracketed) + { + pos = gui_key_buffer_search (0, -1, GUI_KEY_BRACKETED_PASTE_START); + if (pos >= 0) + { + gui_key_buffer_remove (pos, GUI_KEY_BRACKETED_PASTE_LENGTH); + gui_key_paste_bracketed_start (); + } + } - gui_key_flush (ignore_bracketed_paste); + if (!gui_key_paste_bracketed) + gui_key_paste_check (0); + } + + gui_key_flush ((accept_paste) ? 1 : 0); + + if (gui_key_paste_bracketed) + { + pos = gui_key_buffer_search (0, -1, GUI_KEY_BRACKETED_PASTE_END); + if (pos >= 0) + { + /* remove the code for end of bracketed paste (ESC[201~) */ + gui_key_buffer_remove (pos, GUI_KEY_BRACKETED_PASTE_LENGTH); + + /* remove final newline (if needed) */ + gui_key_paste_remove_newline (); + + /* stop bracketed mode */ + gui_key_paste_bracketed_timer_remove (); + gui_key_paste_bracketed_stop (); + + /* if paste confirmation not displayed, flush buffer now */ + if (!gui_key_paste_pending) + gui_key_flush (1); + } + } return WEECHAT_RC_OK; } diff --git a/src/gui/gui-key.c b/src/gui/gui-key.c index 4882860b4..e505e868c 100644 --- a/src/gui/gui-key.c +++ b/src/gui/gui-key.c @@ -85,6 +85,8 @@ int gui_key_buffer_size = 0; /* input buffer size in bytes */ int gui_key_paste_pending = 0; /* 1 is big paste was detected and */ /* WeeChat is asking user what to do */ int gui_key_paste_bracketed = 0; /* bracketed paste mode detected */ +struct t_hook *gui_key_paste_bracketed_timer = NULL; + /* timer for bracketed paste */ int gui_key_paste_lines = 0; /* number of lines for pending paste */ time_t gui_key_last_activity_time = 0; /* last activity time (key) */ @@ -1399,25 +1401,75 @@ gui_key_buffer_add (unsigned char key) } /* - * gui_key_paste_start: start paste of text + * gui_key_buffer_search: search a string in gui_key_buffer (array of integers) + * start_index must be >= 0 + * if max_index is negative, the search is until end of buffer + * return index for string found in gui_key_buffer + * (not from "start_index" but from beginning of gui_key_buffer) + * or -1 if string is not found + */ + +int +gui_key_buffer_search (int start_index, int max_index, const char *string) +{ + int i, j, length, found; + + if ((gui_key_buffer_size == 0) || !string || !string[0]) + return -1; + + length = strlen (string); + + if (gui_key_buffer_size < length) + return -1; + + if (max_index < 0) + max_index = gui_key_buffer_size - length; + else if (max_index > gui_key_buffer_size - length) + max_index = gui_key_buffer_size - length; + + for (i = start_index; i <= max_index; i++) + { + found = 1; + for (j = 0; j < length; j++) + { + if (gui_key_buffer[i + j] != string[j]) + { + found = 0; + break; + } + } + if (found) + return i; + } + + /* string not found */ + return -1; +} + +/* + * gui_key_buffer_remove: remove some chars from gui_key_buffer */ void -gui_key_paste_start () +gui_key_buffer_remove (int index, int number) { - /* remove the "ESC[201~" at the end of buffer (end of bracketed paste) */ - if ((gui_key_buffer_size >= 6) - && (gui_key_buffer[gui_key_buffer_size - 6] == '\x1B') - && (gui_key_buffer[gui_key_buffer_size- 5] == '[') - && (gui_key_buffer[gui_key_buffer_size - 4] == '2') - && (gui_key_buffer[gui_key_buffer_size - 3] == '0') - && (gui_key_buffer[gui_key_buffer_size - 2] == '1') - && (gui_key_buffer[gui_key_buffer_size - 1] == '~')) + int i; + + for (i = index; i < gui_key_buffer_size - number; i++) { - gui_key_buffer_size -= 6; + gui_key_buffer[i] = gui_key_buffer[i + number]; } + gui_key_buffer_size -= number; +} - /* remove final newline if there is only one line to paste */ +/* + * gui_key_paste_remove_newline: remove final newline at enf of paste if there + * is only one line to paste + */ + +void +gui_key_paste_remove_newline () +{ if ((gui_key_paste_lines <= 1) && (gui_key_buffer_size > 0) && ((gui_key_buffer[gui_key_buffer_size - 1] == '\r') @@ -1426,20 +1478,18 @@ gui_key_paste_start () gui_key_buffer_size--; gui_key_paste_lines = 0; } - - gui_key_paste_pending = 1; - gui_input_paste_pending_signal (); } /* - * gui_key_paste_bracket_start: start bracketed paste of text - * (ESC[200~ detected) + * gui_key_paste_start: start paste of text */ void -gui_key_paste_bracketed_start () +gui_key_paste_start () { - gui_key_paste_bracketed = 1; + gui_key_paste_remove_newline (); + gui_key_paste_pending = 1; + gui_input_paste_pending_signal (); } /* @@ -1455,15 +1505,11 @@ gui_key_get_paste_lines () length = gui_key_buffer_size; - if ((length >= 6) - && (gui_key_buffer[length - 6] == '\x1B') - && (gui_key_buffer[length- 5] == '[') - && (gui_key_buffer[length - 4] == '2') - && (gui_key_buffer[length - 3] == '0') - && (gui_key_buffer[length - 2] == '1') - && (gui_key_buffer[length - 1] == '~')) + if (length >= GUI_KEY_BRACKETED_PASTE_LENGTH) { - length -= 6; + if (gui_key_buffer_search (length - GUI_KEY_BRACKETED_PASTE_LENGTH, -1, + GUI_KEY_BRACKETED_PASTE_END) >= 0) + length -= GUI_KEY_BRACKETED_PASTE_LENGTH; } if ((length > 0) @@ -1506,6 +1552,78 @@ gui_key_paste_check (int bracketed_paste) } /* + * gui_key_paste_bracketed_timer_cb: callback for bracketed paste timer + */ + +int +gui_key_paste_bracketed_timer_cb (void *data, int remaining_calls) +{ + /* make C compiler happy */ + (void) data; + (void) remaining_calls; + + gui_key_paste_bracketed_timer = NULL; + + if (gui_key_paste_bracketed) + gui_key_paste_bracketed_stop (); + + return WEECHAT_RC_OK; +} + +/* + * gui_key_paste_bracketed_timer_remove: remove timer for bracketed paste + */ + +void +gui_key_paste_bracketed_timer_remove () +{ + if (gui_key_paste_bracketed_timer) + { + unhook (gui_key_paste_bracketed_timer); + gui_key_paste_bracketed_timer = NULL; + } +} + +/* + * gui_key_paste_bracketed_timer_add: add timer for bracketed paste + */ + +void +gui_key_paste_bracketed_timer_add () +{ + gui_key_paste_bracketed_timer_remove (); + gui_key_paste_bracketed_timer = hook_timer (NULL, + CONFIG_INTEGER(config_look_paste_bracketed_timer_delay) * 1000, + 0, 1, + &gui_key_paste_bracketed_timer_cb, NULL); +} + +/* + * gui_key_paste_bracketed_start: start bracketed paste of text + * (ESC[200~ detected) + */ + +void +gui_key_paste_bracketed_start () +{ + gui_key_paste_bracketed = 1; + gui_key_paste_bracketed_timer_add (); +} + +/* + * gui_key_paste_bracketed_stop: stop bracketed paste of text + * (ESC[201~ detected or timeout while waiting for + * this code) + */ + +void +gui_key_paste_bracketed_stop () +{ + gui_key_paste_check (1); + gui_key_paste_bracketed = 0; +} + +/* * gui_key_paste_accept: accept paste from user */ diff --git a/src/gui/gui-key.h b/src/gui/gui-key.h index c418e8499..373d033e5 100644 --- a/src/gui/gui-key.h +++ b/src/gui/gui-key.h @@ -26,6 +26,10 @@ struct t_hashtable; #define GUI_KEY_GRAB_DELAY_DEFAULT 500 +#define GUI_KEY_BRACKETED_PASTE_START "\x1B[200~" +#define GUI_KEY_BRACKETED_PASTE_END "\x1B[201~" +#define GUI_KEY_BRACKETED_PASTE_LENGTH 6 + enum t_gui_key_context { GUI_KEY_CONTEXT_DEFAULT = 0, @@ -110,10 +114,17 @@ extern void gui_key_free_all (struct t_gui_key **keys, int *keys_count); extern void gui_key_buffer_reset (); extern void gui_key_buffer_add (unsigned char key); +extern int gui_key_buffer_search (int start_index, int max_index, + const char *string); +extern void gui_key_buffer_remove (int index, int number); +extern void gui_key_paste_remove_newline (); extern void gui_key_paste_start (); -extern void gui_key_paste_bracketed_start (); extern int gui_key_get_paste_lines (); extern int gui_key_paste_check (int bracketed_paste); +extern void gui_key_paste_bracketed_timer_remove (); +extern void gui_key_paste_bracketed_timer_add (); +extern void gui_key_paste_bracketed_start (); +extern void gui_key_paste_bracketed_stop (); extern void gui_key_paste_accept (); extern void gui_key_paste_cancel (); extern void gui_key_end (); |