diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | docs/perl.txt | 2 | ||||
-rw-r--r-- | src/fe-common/core/fe-messages.c | 16 | ||||
-rw-r--r-- | src/fe-common/core/formats.c | 2 | ||||
-rw-r--r-- | src/fe-common/core/formats.h | 5 | ||||
-rw-r--r-- | src/fe-common/core/hilight-text.c | 9 | ||||
-rw-r--r-- | src/fe-common/core/hilight-text.h | 2 | ||||
-rw-r--r-- | src/fe-text/gui-readline.c | 151 | ||||
-rw-r--r-- | src/fe-text/term-terminfo.c | 8 | ||||
-rw-r--r-- | src/fe-text/term.h | 2 | ||||
-rw-r--r-- | src/perl/perl-common.c | 3 | ||||
-rw-r--r-- | src/perl/perl-core.c | 17 |
13 files changed, 185 insertions, 34 deletions
diff --git a/Makefile.am b/Makefile.am index 6ca69fc7..75d502f1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,6 +2,7 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} # create default-config.h BUILT_SOURCES = default-config.h default-theme.h irssi-version.h +CLEANFILES = default-config.h default-theme.h @MAINTAINER_MODE_TRUE@.PHONY: irssi-version.h diff --git a/configure.ac b/configure.ac index 325b5e5d..c0efd5e3 100644 --- a/configure.ac +++ b/configure.ac @@ -659,6 +659,7 @@ AC_OUTPUT dnl ** for building from objdir old_dir=`pwd` && cd $srcdir && whole_dir=`pwd` && cd $old_dir if test "x$old_dir" != "x$whole_dir"; then + $LN_S $srcdir/irssi-version.h irssi-version.h if test "x$want_perl" != "xno"; then subdirfiles="" for i in $whole_dir/src/perl/common $whole_dir/src/perl/irc $whole_dir/src/perl/ui $whole_dir/src/perl/textui; do diff --git a/docs/perl.txt b/docs/perl.txt index 560fcaec..9688341f 100644 --- a/docs/perl.txt +++ b/docs/perl.txt @@ -10,7 +10,7 @@ INSTALL file for information about perl problems. --------------- Scripts are run with /SCRIPT LOAD command, or the default /RUN alias. -"/SCRIPT" shows list of running script, and /SCRIPT UNLOAD can unload +"/SCRIPT" shows list of running scripts, and /SCRIPT UNLOAD can unload scripts. Scripts should be placed to ~/.irssi/scripts/ or diff --git a/src/fe-common/core/fe-messages.c b/src/fe-common/core/fe-messages.c index d09c1b0b..e06a4571 100644 --- a/src/fe-common/core/fe-messages.c +++ b/src/fe-common/core/fe-messages.c @@ -175,6 +175,7 @@ static void sig_message_public(SERVER_REC *server, const char *msg, int for_me, print_channel, level; char *nickmode, *color, *freemsg = NULL; HILIGHT_REC *hilight; + int match_beg = 0, match_end = 0; /* NOTE: this may return NULL if some channel is just closed with /WINDOW CLOSE and server still sends the few last messages */ @@ -187,8 +188,8 @@ static void sig_message_public(SERVER_REC *server, const char *msg, nick_match_msg(chanrec, msg, server->nick) : nick_match_msg_everywhere(chanrec, msg, server->nick); hilight = for_me ? NULL : - hilight_match_nick(server, target, nick, address, MSGLEVEL_PUBLIC, msg); - color = (hilight == NULL) ? NULL : hilight_get_color(hilight); + hilight_match(server, target, nick, address, MSGLEVEL_PUBLIC, msg, &match_beg, &match_end); + color = (hilight == NULL || !hilight->nick) ? NULL : hilight_get_color(hilight); print_channel = chanrec == NULL || !window_item_is_active((WI_ITEM_REC *) chanrec); @@ -214,10 +215,13 @@ static void sig_message_public(SERVER_REC *server, const char *msg, if (printnick == NULL) printnick = nick; + TEXT_DEST_REC dest; + format_create_dest(&dest, server, target, level, NULL); + dest.hilight = hilight; + dest.match_beg = match_beg; + dest.match_end = match_end; if (color != NULL) { /* highlighted nick */ - TEXT_DEST_REC dest; - format_create_dest(&dest, server, target, level, NULL); hilight_update_text_dest(&dest,hilight); if (!print_channel) /* message to active channel in window */ printformat_dest(&dest, TXT_PUBMSG_HILIGHT, color, @@ -228,11 +232,11 @@ static void sig_message_public(SERVER_REC *server, const char *msg, nickmode); } else { if (!print_channel) - printformat(server, target, level, + printformat_dest(&dest, for_me ? TXT_PUBMSG_ME : TXT_PUBMSG, printnick, msg, nickmode); else - printformat(server, target, level, + printformat_dest(&dest, for_me ? TXT_PUBMSG_ME_CHANNEL : TXT_PUBMSG_CHANNEL, printnick, target, msg, nickmode); diff --git a/src/fe-common/core/formats.c b/src/fe-common/core/formats.c index ccf48394..b95b3966 100644 --- a/src/fe-common/core/formats.c +++ b/src/fe-common/core/formats.c @@ -416,6 +416,8 @@ void format_create_dest_tag(TEXT_DEST_REC *dest, void *server, dest->server_tag = server != NULL ? SERVER(server)->tag : server_tag; dest->target = target; dest->level = level; + dest->match_beg = 0; + dest->match_end = 0; dest->window = window != NULL ? window : window_find_closest(server, target, level); } diff --git a/src/fe-common/core/formats.h b/src/fe-common/core/formats.h index 07e1832c..a4b26852 100644 --- a/src/fe-common/core/formats.h +++ b/src/fe-common/core/formats.h @@ -45,6 +45,8 @@ struct _FORMAT_REC { #define PRINT_FLAG_SET_SERVERTAG 0x0010 #define PRINT_FLAG_UNSET_SERVERTAG 0x0020 +typedef struct _HILIGHT_REC HILIGHT_REC; + typedef struct _TEXT_DEST_REC { WINDOW_REC *window; SERVER_REC *server; @@ -52,6 +54,9 @@ typedef struct _TEXT_DEST_REC { const char *target; int level; + HILIGHT_REC *hilight; + int match_beg; + int match_end; int hilight_priority; char *hilight_color; int flags; diff --git a/src/fe-common/core/hilight-text.c b/src/fe-common/core/hilight-text.c index 9822de1e..2c0075ec 100644 --- a/src/fe-common/core/hilight-text.c +++ b/src/fe-common/core/hilight-text.c @@ -325,11 +325,10 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text, if (dest->level & MSGLEVEL_NOHILIGHT) return; - hilight_start = hilight_end = 0; - hilight = hilight_match(dest->server, dest->target, - NULL, NULL, dest->level, stripped, - &hilight_start, - &hilight_end); + hilight_start = dest->match_beg; + hilight_end = dest->match_end; + hilight = dest->hilight; + if (hilight == NULL) return; diff --git a/src/fe-common/core/hilight-text.h b/src/fe-common/core/hilight-text.h index 1692b8ab..3c897def 100644 --- a/src/fe-common/core/hilight-text.h +++ b/src/fe-common/core/hilight-text.h @@ -7,8 +7,6 @@ #include "formats.h" -typedef struct _HILIGHT_REC HILIGHT_REC; - struct _HILIGHT_REC { char *text; diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c index a8f3ba99..fcf152e8 100644 --- a/src/fe-text/gui-readline.c +++ b/src/fe-text/gui-readline.c @@ -37,6 +37,7 @@ #include "gui-windows.h" #include "utf8.h" +#include <string.h> #include <signal.h> typedef void (*ENTRY_REDIRECT_KEY_FUNC) (int key, void *data, SERVER_REC *server, WI_ITEM_REC *item); @@ -60,11 +61,21 @@ 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; static int paste_join_multiline; static int paste_timeout_id; +static int paste_use_bracketed_mode; +static int paste_bracketed_mode; +static int paste_was_bracketed_mode; + +/* Terminal sequences that surround the input when the terminal has the + * bracketed paste mode active. Fror more details see + * https://cirw.in/blog/bracketed-paste */ +static const unichar bp_start[] = { 0x1b, '[', '2', '0', '0', '~' }; +static const unichar bp_end[] = { 0x1b, '[', '2', '0', '1', '~' }; static void sig_input(void); @@ -247,9 +258,16 @@ static void paste_buffer_join_lines(GArray *buf) g_array_set_size(buf, dest - arr); } +static void paste_send_line(char *text) +{ + /* we need to get the current history every time because it might change between calls */ + command_history_add(command_history_current(active_win), text); + + signal_emit("send command", 3, text, active_win->active_server, active_win->active); +} + static void paste_send(void) { - HISTORY_REC *history; unichar *arr; GString *str; char out[10], *text; @@ -274,11 +292,7 @@ static void paste_send(void) } text = gui_entry_get_text(active_entry); - history = command_history_current(active_win); - command_history_add(history, text); - - signal_emit("send command", 3, text, - active_win->active_server, active_win->active); + paste_send_line(text); g_free(text); } @@ -286,12 +300,7 @@ static void paste_send(void) str = g_string_new(NULL); for (; i < paste_buffer->len; i++) { if (arr[i] == '\r' || arr[i] == '\n') { - history = command_history_current(active_win); - command_history_add(history, str->str); - - signal_emit("send command", 3, str->str, - active_win->active_server, - active_win->active); + paste_send_line(str->str); g_string_truncate(str, 0); } else if (active_entry->utf8) { out[g_unichar_to_utf8(arr[i], out)] = '\0'; @@ -305,7 +314,14 @@ static void paste_send(void) } } - gui_entry_set_text(active_entry, str->str); + if (paste_was_bracketed_mode) { + /* the text before the bracket end should be sent along with the rest */ + paste_send_line(str->str); + gui_entry_set_text(active_entry, ""); + } else { + gui_entry_set_text(active_entry, str->str); + } + g_string_free(str, TRUE); } @@ -321,6 +337,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 > 0) { + 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; @@ -615,6 +637,8 @@ static void key_delete_to_next_space(void) static gboolean paste_timeout(gpointer data) { + paste_was_bracketed_mode = paste_bracketed_mode; + if (paste_line_count == 0) { int i; @@ -633,6 +657,70 @@ static gboolean paste_timeout(gpointer data) return FALSE; } +static void paste_bracketed_end(int i, gboolean rest) +{ + unichar last_char; + + /* 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 - i - 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); + + last_char = g_array_index(paste_buffer, unichar, i - 1); + + if (paste_line_count > 0 && last_char != '\n' && last_char != '\r') { + /* there are newlines, but there's also stuff after the newline + * adjust line count to reflect this */ + paste_line_count++; + } + + /* decide what to do with the buffer */ + paste_timeout(NULL); + + paste_bracketed_mode = FALSE; +} + +static void paste_bracketed_middle() +{ + int i; + int marklen = G_N_ELEMENTS(bp_end); + int len = paste_buffer->len - marklen; + unichar *ptr = (unichar *) paste_buffer->data; + + if (len < 0) { + return; + } + + for (i = 0; i <= len; i++, ptr++) { + if (ptr[0] == bp_end[0] && memcmp(ptr, bp_end, sizeof(bp_end)) == 0) { + + /* if there are at least 6 bytes after the end, + * check for another start marker right afterwards */ + if (i <= (len - marklen) && + memcmp(ptr + marklen, bp_start, sizeof(bp_start)) == 0) { + + /* remove both markers*/ + g_array_remove_range(paste_buffer, i, marklen * 2); + len -= marklen * 2; + + /* go one step back */ + i--; + ptr--; + continue; + } + paste_bracketed_end(i, i != len); + break; + } + } +} + static void sig_input(void) { if (!active_entry) { @@ -646,21 +734,37 @@ static void sig_input(void) unichar key; term_gets(buffer, &line_count); key = g_array_index(buffer, unichar, 0); + /* Either Ctrl-k or Ctrl-c is pressed */ if (key == 11 || key == 3) paste_flush(key == 11); g_array_free(buffer, TRUE); } else { term_gets(paste_buffer, &paste_line_count); - if (paste_detect_time > 0 && paste_buffer->len >= 3) { + + /* use the bracketed paste mode to detect when the user pastes + * some text into the entry */ + if (paste_bracketed_mode) { + paste_bracketed_middle(); + + } else if (!paste_use_bracketed_mode && 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); + + /* handle single-line / small pastes here */ + paste_bracketed_middle(); + return; + } } g_array_set_size(paste_buffer, 0); paste_line_count = 0; @@ -668,6 +772,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; @@ -929,6 +1038,10 @@ static void setup_changed(void) paste_verify_line_count = settings_get_int("paste_verify_line_count"); paste_join_multiline = settings_get_bool("paste_join_multiline"); + paste_use_bracketed_mode = settings_get_bool("paste_use_bracketed_mode"); + + /* Enable the bracketed paste mode on demand */ + term_set_bracketed_paste_mode(paste_use_bracketed_mode); } void gui_readline_init(void) @@ -942,13 +1055,16 @@ 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; g_get_current_time(&last_keypress); input_listen_init(STDIN_FILENO); settings_add_str("history", "scroll_page_count", "/2"); settings_add_time("misc", "paste_detect_time", "5msecs"); + settings_add_bool("misc", "paste_use_bracketed_mode", FALSE); /* NOTE: function keys can generate at least 5 characters long keycodes. this must be larger to allow them to work. */ settings_add_int("misc", "paste_verify_line_count", 5); @@ -1021,6 +1137,8 @@ void gui_readline_init(void) key_bind("key", NULL, "meta-O-M", "return", (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); @@ -1116,6 +1234,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); @@ -1173,6 +1293,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(); diff --git a/src/fe-text/term-terminfo.c b/src/fe-text/term-terminfo.c index 27be904e..3582b9e4 100644 --- a/src/fe-text/term-terminfo.c +++ b/src/fe-text/term-terminfo.c @@ -710,3 +710,11 @@ void term_gets(GArray *buffer, int *line_count) } } } + +void term_set_bracketed_paste_mode(int enable) +{ + if (enable) + tputs("\e[?2004h", 0, term_putchar); + else + tputs("\e[?2004l", 0, term_putchar); +} diff --git a/src/fe-text/term.h b/src/fe-text/term.h index f0a76c42..5f0a799e 100644 --- a/src/fe-text/term.h +++ b/src/fe-text/term.h @@ -94,6 +94,8 @@ void term_refresh(TERM_WINDOW *window); void term_stop(void); +void term_set_bracketed_paste_mode(int enable); + /* keyboard input handling */ void term_set_input_type(int type); void term_gets(GArray *buffer, int *line_count); diff --git a/src/perl/perl-common.c b/src/perl/perl-common.c index d7a428e5..b641867f 100644 --- a/src/perl/perl-common.c +++ b/src/perl/perl-common.c @@ -246,10 +246,7 @@ char *perl_get_use_list(void) void irssi_callXS(void (*subaddr)(pTHX_ CV* cv), CV *cv, SV **mark) { - dSP; - PUSHMARK(mark); - PUTBACK; (*subaddr)(aTHX_ cv); } diff --git a/src/perl/perl-core.c b/src/perl/perl-core.c index 2f28c718..cb690906 100644 --- a/src/perl/perl-core.c +++ b/src/perl/perl-core.c @@ -82,16 +82,18 @@ static void perl_script_destroy(PERL_SCRIPT_REC *script) extern void boot_DynaLoader(pTHX_ CV* cv); #if PERL_STATIC_LIBS == 1 -extern void boot_Irssi(CV *cv); +extern void boot_Irssi(pTHX_ CV *cv); XS(boot_Irssi_Core) { dXSARGS; + PERL_UNUSED_VAR(items); irssi_callXS(boot_Irssi, cv, mark); irssi_boot(Irc); irssi_boot(UI); irssi_boot(TextUI); + /* Make sure to keep this in line with perl_scripts_deinit below. */ XSRETURN_YES; } #endif @@ -123,7 +125,7 @@ void perl_scripts_init(void) perl_parse(my_perl, xs_init, G_N_ELEMENTS(perl_args), perl_args, NULL); #if PERL_STATIC_LIBS == 1 - perl_eval_pv("Irssi::Core::boot_Irssi_Core();", TRUE); + perl_eval_pv("Irssi::Core::->boot_Irssi_Core(0.9);", TRUE); #endif perl_common_start(); @@ -155,6 +157,17 @@ void perl_scripts_deinit(void) /* Unload all perl libraries loaded with dynaloader */ perl_eval_pv("foreach my $lib (@DynaLoader::dl_modules) { if ($lib =~ /^Irssi\\b/) { $lib .= '::deinit();'; eval $lib; } }", TRUE); +#if PERL_STATIC_LIBS == 1 + /* If perl is statically built we should manually deinit the modules + which are booted in boot_Irssi_Core above */ + perl_eval_pv("foreach my $lib (qw(" + "Irssi" " " + "Irssi::Irc" " " + "Irssi::UI" " " + "Irssi::TextUI" + ")) { eval $lib . '::deinit();'; }", TRUE); +#endif + /* We could unload all libraries .. but this crashes with some libraries, probably because we don't call some deinit function.. Anyway, this would free some memory with /SCRIPT RESET, but it |