diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c index 37487b5c..61cdad1a 100644 --- a/src/fe-text/gui-readline.c +++ b/src/fe-text/gui-readline.c @@ -61,6 +61,7 @@ static int paste_detect_time, paste_verify_line_count; static char *paste_entry; static int paste_entry_pos; static GArray *paste_buffer; +static GArray *paste_buffer_rest; static char *paste_old_prompt; static int paste_prompt, paste_line_count; @@ -246,7 +247,7 @@ static void paste_buffer_join_lines(GArray *buf) last_lf = FALSE; if (++line_len >= 400 && last_lf_pos != NULL) { memmove(last_lf_pos+1, last_lf_pos, - dest - last_lf_pos); + (dest - last_lf_pos) * sizeof(unichar)); *last_lf_pos = '\n'; last_lf_pos = NULL; line_len = 0; dest++; @@ -331,6 +332,12 @@ static void paste_flush(int send) paste_send(); g_array_set_size(paste_buffer, 0); + /* re-add anything that may have been after the bracketed paste end */ + if (paste_buffer_rest->len) { + g_array_append_vals(paste_buffer, paste_buffer_rest->data, paste_buffer_rest->len); + g_array_set_size(paste_buffer_rest, 0); + } + gui_entry_set_prompt(active_entry, paste_old_prompt == NULL ? "" : paste_old_prompt); g_free(paste_old_prompt); paste_old_prompt = NULL; @@ -643,6 +650,26 @@ static gboolean paste_timeout(gpointer data) return FALSE; } +static void paste_bracketed_end(int i, gboolean rest) +{ + /* if there's stuff after the end bracket, save it for later */ + if (rest) { + unichar *start = ((unichar *) paste_buffer->data) + i + G_N_ELEMENTS(bp_end); + int len = paste_buffer->len - G_N_ELEMENTS(bp_end); + + g_array_set_size(paste_buffer_rest, 0); + g_array_append_vals(paste_buffer_rest, start, len); + } + + /* remove the rest, including the trailing sequence chars */ + g_array_set_size(paste_buffer, i); + + /* decide what to do with the buffer */ + paste_timeout(NULL); + + paste_bracketed_mode = FALSE; +} + static void sig_input(void) { if (!active_entry) { @@ -665,37 +692,38 @@ static void sig_input(void) /* use the bracketed paste mode to detect when the user pastes * some text into the entry */ - if (paste_use_bracketed_mode != FALSE && paste_buffer->len > 12) { - /* try to find the start/end sequence, we know that we - * either find those at the start/end of the buffer or - * we don't find those at all. */ - int seq_start = !memcmp(paste_buffer->data, bp_start, sizeof(bp_start)), - seq_end = !memcmp(paste_buffer->data + paste_buffer->len * g_array_get_element_size(paste_buffer) - sizeof(bp_end), bp_end, sizeof(bp_end)); + if (paste_bracketed_mode) { + int i; + int len = paste_buffer->len - G_N_ELEMENTS(bp_end); + unichar *ptr = (unichar *) paste_buffer->data; - if (seq_start) { - paste_bracketed_mode = TRUE; - /* remove the leading sequence chars */ - g_array_remove_range(paste_buffer, 0, 6); + if (len <= 0) { + return; } - if (seq_end) { - paste_bracketed_mode = FALSE; - /* remove the trailing sequence chars */ - g_array_set_size(paste_buffer, paste_buffer->len - 6); - /* decide what to do with the buffer */ - paste_timeout(NULL); + for (i = 0; i <= len; i++, ptr++) { + if (ptr[0] == bp_end[0] && !memcmp(ptr, bp_end, sizeof(bp_end))) { + paste_bracketed_end(i, i != len); + break; + } } } else if (paste_detect_time > 0 && paste_buffer->len >= 3) { if (paste_timeout_id != -1) g_source_remove(paste_timeout_id); paste_timeout_id = g_timeout_add(paste_detect_time, paste_timeout, NULL); - } else { + } else if (!paste_bracketed_mode) { int i; for (i = 0; i < paste_buffer->len; i++) { unichar key = g_array_index(paste_buffer, unichar, i); signal_emit("gui key pressed", 1, GINT_TO_POINTER(key)); + + if (paste_bracketed_mode) { + /* just enabled by the signal, remove what was processed so far */ + g_array_remove_range(paste_buffer, 0, i + 1); + return; + } } g_array_set_size(paste_buffer, 0); paste_line_count = 0; @@ -703,6 +731,11 @@ static void sig_input(void) } } +static void key_paste_start(void) +{ + paste_bracketed_mode = TRUE; +} + time_t get_idle_time(void) { return last_keypress.tv_sec; @@ -981,6 +1014,7 @@ void gui_readline_init(void) paste_entry = NULL; paste_entry_pos = 0; paste_buffer = g_array_new(FALSE, FALSE, sizeof(unichar)); + paste_buffer_rest = g_array_new(FALSE, FALSE, sizeof(unichar)); paste_old_prompt = NULL; paste_timeout_id = -1; paste_bracketed_mode = FALSE; @@ -1060,6 +1094,8 @@ void gui_readline_init(void) key_bind("key", NULL, "meta2-5F", "cend", (SIGNAL_FUNC) key_combo); key_bind("key", NULL, "meta2-1;5F", "cend", (SIGNAL_FUNC) key_combo); + key_bind("paste_start", "Bracketed paste start", "meta2-200~", "paste_start", (SIGNAL_FUNC) key_paste_start); + /* cursor movement */ key_bind("backward_character", "Move the cursor a character backward", "left", NULL, (SIGNAL_FUNC) key_backward_character); key_bind("forward_character", "Move the cursor a character forward", "right", NULL, (SIGNAL_FUNC) key_forward_character); @@ -1155,6 +1191,8 @@ void gui_readline_deinit(void) key_configure_freeze(); + key_unbind("paste_start", (SIGNAL_FUNC) key_paste_start); + key_unbind("backward_character", (SIGNAL_FUNC) key_backward_character); key_unbind("forward_character", (SIGNAL_FUNC) key_forward_character); key_unbind("backward_word", (SIGNAL_FUNC) key_backward_word); @@ -1212,6 +1250,7 @@ void gui_readline_deinit(void) key_unbind("stop_irc", (SIGNAL_FUNC) key_sig_stop); keyboard_destroy(keyboard); g_array_free(paste_buffer, TRUE); + g_array_free(paste_buffer_rest, TRUE); key_configure_thaw();