summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--configure.ac1
-rw-r--r--docs/perl.txt2
-rw-r--r--src/fe-common/core/fe-messages.c16
-rw-r--r--src/fe-common/core/formats.c2
-rw-r--r--src/fe-common/core/formats.h5
-rw-r--r--src/fe-common/core/hilight-text.c9
-rw-r--r--src/fe-common/core/hilight-text.h2
-rw-r--r--src/fe-text/gui-readline.c151
-rw-r--r--src/fe-text/term-terminfo.c8
-rw-r--r--src/fe-text/term.h2
-rw-r--r--src/perl/perl-common.c3
-rw-r--r--src/perl/perl-core.c17
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