1
0
mirror of https://github.com/weechat/weechat.git synced 2026-07-03 16:23:14 +02:00

core: add support of terminal "bracketed paste mode" (task #11316)

This commit is contained in:
Sebastien Helleu
2012-03-04 10:32:55 +01:00
parent d43e9c11e5
commit 152394689a
32 changed files with 580 additions and 199 deletions
+10 -2
View File
@@ -2393,6 +2393,12 @@ COMMAND_CALLBACK(input)
gui_input_undo (buffer);
else if (string_strcasecmp (argv[1], "redo") == 0)
gui_input_redo (buffer);
else if (string_strcasecmp (argv[1], "paste_start") == 0)
gui_key_paste_bracketed_start ();
else if (string_strcasecmp (argv[1], "paste_stop") == 0)
{
/* do nothing here */
}
}
return WEECHAT_RC_OK;
@@ -5762,7 +5768,9 @@ command_init ()
" switch_active_buffer: switch to next merged buffer\n"
" switch_active_buffer_previous: switch to previous "
"merged buffer\n"
" insert: insert text in command line\n\n"
" insert: insert text in command line\n"
" paste_start: start paste (bracketed paste mode)\n"
" paste_stop: stop paste (bracketed paste mode)\n\n"
"This command is used by key bindings or plugins."),
"return|complete_next|complete_previous|search_text|"
"search_switch_case|search_previous|search_next|search_stop|"
@@ -5778,7 +5786,7 @@ command_init ()
"jump_next_visited_buffer|hotlist_clear|grab_key|"
"grab_key_command|grab_mouse|grab_mouse_area|set_unread|"
"set_unread_current_buffer|switch_active_buffer|"
"switch_active_buffer_previous|insert",
"switch_active_buffer_previous|insert|paste_start|paste_stop",
&command_input, NULL);
hook_command (NULL, "key",
N_("bind/unbind keys"),
+28 -2
View File
@@ -83,6 +83,7 @@ struct t_config_option *config_look_bar_more_left;
struct t_config_option *config_look_bar_more_right;
struct t_config_option *config_look_bar_more_up;
struct t_config_option *config_look_bar_more_down;
struct t_config_option *config_look_bracketed_paste_mode;
struct t_config_option *config_look_buffer_notify_default;
struct t_config_option *config_look_buffer_time_format;
struct t_config_option *config_look_color_basic_force_bold;
@@ -311,6 +312,22 @@ config_change_buffer_content (void *data, struct t_config_option *option)
gui_current_window->refresh_needed = 1;
}
/*
* config_change_bracketed_paste_mode: called when bracketed paste mode is
* changed
*/
void
config_change_bracketed_paste_mode (void *data, struct t_config_option *option)
{
/* make C compiler happy */
(void) data;
(void) option;
if (gui_ok)
gui_window_set_bracketed_paste_mode (CONFIG_BOOLEAN(config_look_bracketed_paste_mode));
}
/*
* config_change_mouse: called when mouse state is changed
*/
@@ -1682,6 +1699,15 @@ config_weechat_init_options ()
N_("string displayed when bar can be scrolled down "
"(for bars with filling different from \"horizontal\")"),
NULL, 0, 0, "++", NULL, 0, NULL, NULL, &config_change_buffer_content, NULL, NULL, NULL);
config_look_bracketed_paste_mode = config_file_new_option (
weechat_config_file, ptr_section,
"bracketed_paste_mode", "boolean",
N_("enable terminal \"bracketed paste mode\" (not supported in all "
"terminals/multiplexers): in this mode, pasted text is bracketed "
"with control sequences so that WeeChat can differentiate pasted "
"text from typed-in text \"(ESC[200~\", followed by the pasted text, "
"followed by \"ESC[201~\")"),
NULL, 0, 0, "off", NULL, 0, NULL, NULL, &config_change_bracketed_paste_mode, NULL, NULL, NULL);
config_look_buffer_notify_default = config_file_new_option (
weechat_config_file, ptr_section,
"buffer_notify_default", "integer",
@@ -1960,8 +1986,8 @@ config_weechat_init_options ()
weechat_config_file, ptr_section,
"paste_max_lines", "integer",
N_("max number of lines for paste without asking user "
"(0 = disable this feature)"),
NULL, 0, INT_MAX, "3", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
"(-1 = disable this feature)"),
NULL, -1, INT_MAX, "3", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
config_look_prefix[GUI_CHAT_PREFIX_ERROR] = config_file_new_option (
weechat_config_file, ptr_section,
"prefix_error", "string",
+1
View File
@@ -108,6 +108,7 @@ extern struct t_config_option *config_look_bar_more_left;
extern struct t_config_option *config_look_bar_more_right;
extern struct t_config_option *config_look_bar_more_up;
extern struct t_config_option *config_look_bar_more_down;
extern struct t_config_option *config_look_bracketed_paste_mode;
extern struct t_config_option *config_look_buffer_notify_default;
extern struct t_config_option *config_look_buffer_time_format;
extern struct t_config_option *config_look_command_chars;
+48 -22
View File
@@ -208,6 +208,8 @@ gui_key_default_bindings (int context)
BIND(/* m-> */ "meta->", "/input jump_next_visited_buffer");
BIND(/* m-/ */ "meta-/", "/input jump_last_buffer_displayed");
BIND(/* m-m */ "meta-m", "/mute mouse toggle");
BIND(/* start paste */ "meta2-200~", "/input paste_start");
BIND(/* end paste */ "meta2-201~", "/input paste_stop");
/* bind meta-j + {01..99} to switch to buffers # > 10 */
for (i = 1; i < 100; i++)
@@ -288,9 +290,9 @@ gui_key_default_bindings (int context)
*/
void
gui_key_flush ()
gui_key_flush (int ignore_bracketed)
{
int i, key, insert_ok;
int i, j, key, insert_ok;
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;
@@ -450,6 +452,36 @@ gui_key_flush ()
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)
{
/* 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_key_buffer_reset ();
@@ -463,7 +495,8 @@ gui_key_flush ()
int
gui_key_read_cb (void *data, int fd)
{
int ret, i, accept_paste, cancel_paste, text_added_to_buffer, paste_lines;
int ret, i, accept_paste, cancel_paste, text_added_to_buffer;
int ignore_bracketed_paste;
unsigned char buffer[4096];
/* make C compiler happy */
@@ -473,6 +506,7 @@ gui_key_read_cb (void *data, int fd)
accept_paste = 0;
cancel_paste = 0;
text_added_to_buffer = 0;
ignore_bracketed_paste = 0;
if (gui_key_paste_pending)
{
@@ -512,10 +546,13 @@ gui_key_read_cb (void *data, int fd)
for (i = 0; i < ret; i++)
{
/* add all chars (ignore a '\n' after a '\r') */
/*
* add all chars, but ignore a newline ('\r' or '\n') after
* another one)
*/
if ((i == 0)
|| (buffer[i] != '\n')
|| (buffer[i - 1] != '\r'))
|| ((buffer[i] != '\r') && (buffer[i] != '\n'))
|| ((buffer[i - 1] != '\r') && (buffer[i - 1] != '\n')))
{
gui_key_buffer_add (buffer[i]);
}
@@ -528,7 +565,10 @@ gui_key_read_cb (void *data, int fd)
{
/* user is ok for pasting text, let's paste! */
if (accept_paste)
{
gui_key_paste_accept ();
ignore_bracketed_paste = 1;
}
/* user doesn't want to paste text: clear whole buffer! */
else if (cancel_paste)
gui_key_paste_cancel ();
@@ -536,23 +576,9 @@ gui_key_read_cb (void *data, int fd)
gui_input_text_changed_modifier_and_signal (gui_current_window->buffer, 0);
}
else
{
/*
* detect user paste or large amount of text
* if so, ask user what to do
*/
if (CONFIG_INTEGER(config_look_paste_max_lines) > 0)
{
paste_lines = gui_key_get_paste_lines ();
if (paste_lines > CONFIG_INTEGER(config_look_paste_max_lines))
{
gui_key_paste_pending = 1;
gui_input_paste_pending_signal ();
}
}
}
gui_key_paste_check (0);
gui_key_flush ();
gui_key_flush (ignore_bracketed_paste);
return WEECHAT_RC_OK;
}
+5
View File
@@ -177,6 +177,8 @@ gui_main_init ()
gui_mouse_enable ();
else
gui_mouse_disable ();
gui_window_set_bracketed_paste_mode (CONFIG_BOOLEAN(config_look_bracketed_paste_mode));
}
/*
@@ -401,6 +403,9 @@ gui_main_end (int clean_exit)
gui_main_refreshs ();
}
/* disable bracketed paste mode */
gui_window_set_bracketed_paste_mode (0);
/* disable mouse */
gui_mouse_disable ();
+22
View File
@@ -2273,6 +2273,28 @@ gui_window_send_clipboard (const char *storage_unit, const char *text)
}
}
/*
* gui_window_set_bracketed_paste_mode: enable/disable bracketed paste mode
*/
void
gui_window_set_bracketed_paste_mode (int enable)
{
char *envterm, *envtmux;
int tmux, screen;
envtmux = getenv ("TMUX");
tmux = (envtmux && envtmux[0]);
envterm = getenv ("TERM");
screen = (envterm && (strncmp (envterm, "screen", 6) == 0) && !tmux);
fprintf (stderr, "%s\033[?2004%s%s",
(screen) ? "\033P" : "",
(enable) ? "h" : "l",
(screen) ? "\033\\" : "");
}
/*
* gui_window_move_cursor: move cursor on screen (for cursor mode)
*/
+12
View File
@@ -866,6 +866,18 @@ gui_window_send_clipboard (const char *storage_unit, const char *text)
/* TODO: write this function for Gtk */
}
/*
* gui_window_set_bracketed_paste_mode: enable/disable bracketed paste mode
*/
void
gui_window_set_bracketed_paste_mode (int enable)
{
(void) enable;
/* TODO: write this function for Gtk */
}
/*
* gui_window_move_cursor: move cursor on screen (for cursor mode)
*/
+10 -12
View File
@@ -586,9 +586,8 @@ char *
gui_bar_item_default_input_paste (void *data, struct t_gui_bar_item *item,
struct t_gui_window *window)
{
char *text_paste_pending = N_("%sPaste %d lines ? [ctrl-Y] Yes [ctrl-N] No");
char *ptr_message, *buf;
int length;
char buf[1024];
int lines;
/* make C compiler happy */
(void) data;
@@ -600,15 +599,14 @@ gui_bar_item_default_input_paste (void *data, struct t_gui_bar_item *item,
if (!gui_key_paste_pending)
return NULL;
ptr_message = _(text_paste_pending);
length = strlen (ptr_message) + 16 + 1;
buf = malloc (length);
if (buf)
snprintf (buf, length, ptr_message,
gui_color_get_custom (gui_color_get_name (CONFIG_COLOR(config_color_input_actions))),
gui_key_get_paste_lines ());
return buf;
lines = gui_key_get_paste_lines ();
snprintf (buf, sizeof (buf),
NG_("%sPaste %d line ? [ctrl-Y] Yes [ctrl-N] No",
"%sPaste %d lines ? [ctrl-Y] Yes [ctrl-N] No",
lines),
gui_color_get_custom (gui_color_get_name (CONFIG_COLOR(config_color_input_actions))),
lines);
return strdup (buf);
}
/*
+100 -6
View File
@@ -32,6 +32,7 @@
#include <time.h>
#include "../core/weechat.h"
#include "../core/wee-config.h"
#include "../core/wee-hashtable.h"
#include "../core/wee-hdata.h"
#include "../core/wee-hook.h"
@@ -83,6 +84,7 @@ 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 */
int gui_key_paste_lines = 0; /* number of lines for pending paste */
time_t gui_key_last_activity_time = 0; /* last activity time (key) */
@@ -1396,6 +1398,50 @@ gui_key_buffer_add (unsigned char key)
}
}
/*
* gui_key_paste_start: start paste of text
*/
void
gui_key_paste_start ()
{
/* 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] == '~'))
{
gui_key_buffer_size -= 6;
}
/* remove final newline if there is only one line to paste */
if ((gui_key_paste_lines <= 1)
&& (gui_key_buffer_size > 0)
&& ((gui_key_buffer[gui_key_buffer_size - 1] == '\r')
|| (gui_key_buffer[gui_key_buffer_size - 1] == '\n')))
{
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)
*/
void
gui_key_paste_bracketed_start ()
{
gui_key_paste_bracketed = 1;
}
/*
* gui_key_get_paste_lines: return real number of lines in buffer
* if last key is not Return, then this is lines + 1
@@ -1405,14 +1451,58 @@ gui_key_buffer_add (unsigned char key)
int
gui_key_get_paste_lines ()
{
if ((gui_key_buffer_size > 0)
&& (gui_key_buffer[gui_key_buffer_size - 1] != '\r')
&& (gui_key_buffer[gui_key_buffer_size - 1] != '\n'))
int length;
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] == '~'))
{
length -= 6;
}
if ((length > 0)
&& (gui_key_buffer[length - 1] != '\r')
&& (gui_key_buffer[length - 1] != '\n'))
{
return gui_key_paste_lines + 1;
}
return gui_key_paste_lines;
return (gui_key_paste_lines > 0) ? gui_key_paste_lines : 1;
}
/*
* gui_key_paste_check: check pasted lines: if more than N lines, then enable
* paste mode and ask confirmation to user
* (ctrl-Y=paste, ctrl-N=cancel)
* (N is option weechat.look.paste_max_lines)
* return 1 if paste mode has been enabled, 0 otherwise
*/
int
gui_key_paste_check (int bracketed_paste)
{
int max_lines;
max_lines = CONFIG_INTEGER(config_look_paste_max_lines);
if (max_lines >= 0)
{
if (!bracketed_paste && (max_lines == 0))
max_lines = 1;
if (gui_key_get_paste_lines () > max_lines)
{
/* ask user what to do */
gui_key_paste_start ();
return 1;
}
}
return 0;
}
/*
@@ -1422,8 +1512,12 @@ gui_key_get_paste_lines ()
void
gui_key_paste_accept ()
{
/* add final '\n' if there is not in pasted text */
if ((gui_key_buffer_size > 0)
/*
* add final newline if there is not in pasted text
* (for at least 2 lines pasted)
*/
if ((gui_key_get_paste_lines () > 1)
&& (gui_key_buffer_size > 0)
&& (gui_key_buffer[gui_key_buffer_size - 1] != '\r')
&& (gui_key_buffer[gui_key_buffer_size - 1] != '\n'))
{
+4
View File
@@ -75,6 +75,7 @@ extern int gui_key_grab_count;
extern int *gui_key_buffer;
extern int gui_key_buffer_size;
extern int gui_key_paste_pending;
extern int gui_key_paste_bracketed;
extern time_t gui_key_last_activity_time;
/* key functions */
@@ -109,7 +110,10 @@ 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 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_accept ();
extern void gui_key_paste_cancel ();
extern void gui_key_end ();
+1
View File
@@ -240,6 +240,7 @@ extern void gui_window_refresh_screen (int full_refresh);
extern void gui_window_set_title (const char *title);
extern void gui_window_send_clipboard (const char *storage_unit,
const char *text);
extern void gui_window_set_bracketed_paste_mode (int enable);
extern void gui_window_move_cursor ();
extern void gui_window_term_display_infos ();
extern void gui_window_objects_print_log (struct t_gui_window *window);