|
|
|
@@ -259,7 +259,7 @@ struct input_vtable
|
|
|
|
XX (get_line) XX (clear_line) XX (insert) \
|
|
|
|
XX (get_line) XX (clear_line) XX (insert) \
|
|
|
|
XX (on_tty_resized) XX (on_tty_readable)
|
|
|
|
XX (on_tty_resized) XX (on_tty_readable)
|
|
|
|
|
|
|
|
|
|
|
|
// --- GNU Readline ------------------------------------------------------------
|
|
|
|
// ~~~ GNU Readline ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_READLINE
|
|
|
|
#ifdef HAVE_READLINE
|
|
|
|
|
|
|
|
|
|
|
|
@@ -728,7 +728,7 @@ input_rl_new (void)
|
|
|
|
#define input_new input_rl_new
|
|
|
|
#define input_new input_rl_new
|
|
|
|
#endif // HAVE_READLINE
|
|
|
|
#endif // HAVE_READLINE
|
|
|
|
|
|
|
|
|
|
|
|
// --- BSD Editline ------------------------------------------------------------
|
|
|
|
// ~~~ BSD Editline ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_EDITLINE
|
|
|
|
#ifdef HAVE_EDITLINE
|
|
|
|
|
|
|
|
|
|
|
|
@@ -761,6 +761,7 @@ struct input_el
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct input super; ///< Parent class
|
|
|
|
struct input super; ///< Parent class
|
|
|
|
EditLine *editline; ///< The EditLine object
|
|
|
|
EditLine *editline; ///< The EditLine object
|
|
|
|
|
|
|
|
FILE *null; ///< Output redirect
|
|
|
|
|
|
|
|
|
|
|
|
bool active; ///< Are we a thing?
|
|
|
|
bool active; ///< Are we a thing?
|
|
|
|
char *prompt; ///< The prompt we use
|
|
|
|
char *prompt; ///< The prompt we use
|
|
|
|
@@ -778,12 +779,12 @@ input_el__redisplay (void *input)
|
|
|
|
// See rl_redisplay(), however NetBSD editline's map.c v1.54 breaks VREPRINT
|
|
|
|
// See rl_redisplay(), however NetBSD editline's map.c v1.54 breaks VREPRINT
|
|
|
|
// so we bind redisplay somewhere else in app_editline_init()
|
|
|
|
// so we bind redisplay somewhere else in app_editline_init()
|
|
|
|
struct input_el *self = input;
|
|
|
|
struct input_el *self = input;
|
|
|
|
char x[] = { 'q' & 31, 0 };
|
|
|
|
wchar_t x[] = { L'q' & 31, 0 };
|
|
|
|
el_push (self->editline, x);
|
|
|
|
el_wpush (self->editline, x);
|
|
|
|
|
|
|
|
|
|
|
|
// We have to do this or it gets stuck and nothing is done
|
|
|
|
// We have to do this or it gets stuck and nothing is done
|
|
|
|
int count = 0;
|
|
|
|
int dummy_count = 0;
|
|
|
|
(void) el_wgets (self->editline, &count);
|
|
|
|
(void) el_wgets (self->editline, &dummy_count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
static char *
|
|
|
|
@@ -1026,18 +1027,50 @@ input_el__restore (struct input_el *self)
|
|
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// XXX: Editline keeping its own history position (look for "eventno" there).
|
|
|
|
|
|
|
|
// Invoking ed-next-history through our bind from app_editline_init() seems
|
|
|
|
|
|
|
|
// like the only viable hack to get consistent history behaviour.
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
|
|
input_el__bottom (struct input_el *self)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// First, we need to redirect output to avoid ringing the terminal bell.
|
|
|
|
|
|
|
|
FILE *out = NULL;
|
|
|
|
|
|
|
|
el_wget (self->editline, EL_GETFP, 1, &out);
|
|
|
|
|
|
|
|
el_wset (self->editline, EL_SETFP, 1, self->null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Invoke hist_get() to make the history pointer's cursor match "eventno".
|
|
|
|
|
|
|
|
int down = 1, dummy_count = 0;
|
|
|
|
|
|
|
|
el_wpush (self->editline, L"\x1bn");
|
|
|
|
|
|
|
|
(void) el_wgets (self->editline, &dummy_count);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// It doesn't seem like we can just retrieve the position.
|
|
|
|
|
|
|
|
HistEventW ev;
|
|
|
|
|
|
|
|
while (!history_w (self->current->history, &ev, H_PREV))
|
|
|
|
|
|
|
|
down++;
|
|
|
|
|
|
|
|
while (down--)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
el_wpush (self->editline, L"\x1bn");
|
|
|
|
|
|
|
|
(void) el_wgets (self->editline, &dummy_count);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
el_wset (self->editline, EL_SETFP, 1, out);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
input_el_buffer_switch (void *input, input_buffer_t input_buffer)
|
|
|
|
input_el_buffer_switch (void *input, input_buffer_t input_buffer)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct input_el *self = input;
|
|
|
|
struct input_el *self = input;
|
|
|
|
struct input_el_buffer *buffer = input_buffer;
|
|
|
|
struct input_el_buffer *buffer = input_buffer;
|
|
|
|
|
|
|
|
if (!self->active)
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (self->current)
|
|
|
|
if (self->current)
|
|
|
|
input_el__save_buffer (self, self->current);
|
|
|
|
input_el__save_buffer (self, self->current);
|
|
|
|
|
|
|
|
|
|
|
|
input_el__restore_buffer (self, buffer);
|
|
|
|
|
|
|
|
el_wset (self->editline, EL_HIST, history, buffer->history);
|
|
|
|
|
|
|
|
self->current = buffer;
|
|
|
|
self->current = buffer;
|
|
|
|
|
|
|
|
el_wset (self->editline, EL_HIST, history, buffer->history);
|
|
|
|
|
|
|
|
input_el__bottom (self);
|
|
|
|
|
|
|
|
input_el__restore_buffer (self, buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
@@ -1111,7 +1144,7 @@ input_el_on_tty_readable (void *input)
|
|
|
|
if (!buf || count-- <= 0)
|
|
|
|
if (!buf || count-- <= 0)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (count == 0 && buf[0] == ('D' - 0x40) /* hardcoded VEOF in editline */)
|
|
|
|
if (count == 0 && buf[0] == ('D' - 0x40) /* hardcoded VEOF in el_wgets() */)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
el_deletestr (self->editline, 1);
|
|
|
|
el_deletestr (self->editline, 1);
|
|
|
|
input_el__redisplay (self);
|
|
|
|
input_el__redisplay (self);
|
|
|
|
@@ -1131,6 +1164,7 @@ input_el_destroy (void *input)
|
|
|
|
free (iter->help);
|
|
|
|
free (iter->help);
|
|
|
|
ffi_closure_free (iter);
|
|
|
|
ffi_closure_free (iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose (self->null);
|
|
|
|
free (self->prompt);
|
|
|
|
free (self->prompt);
|
|
|
|
free (self);
|
|
|
|
free (self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -1144,6 +1178,7 @@ input_el_new (void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct input_el *self = xcalloc (1, sizeof *self);
|
|
|
|
struct input_el *self = xcalloc (1, sizeof *self);
|
|
|
|
self->super.vtable = &input_el_vtable;
|
|
|
|
self->super.vtable = &input_el_vtable;
|
|
|
|
|
|
|
|
self->null = fopen ("/dev/null", "w");
|
|
|
|
return &self->super;
|
|
|
|
return &self->super;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1160,7 +1195,7 @@ input_el_new (void)
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// The only exception is IRC identifiers.
|
|
|
|
// The only exception is IRC identifiers.
|
|
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// ~~~ Scripting support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
|
|
// We need a few reference countable objects with support for both strong
|
|
|
|
// We need a few reference countable objects with support for both strong
|
|
|
|
// and weak references (mainly used for scripted plugins).
|
|
|
|
// and weak references (mainly used for scripted plugins).
|
|
|
|
@@ -1272,7 +1307,7 @@ struct ispect_field
|
|
|
|
{ #field, offsetof (struct object, field), ISPECT_STR_MAP, \
|
|
|
|
{ #field, offsetof (struct object, field), ISPECT_STR_MAP, \
|
|
|
|
ISPECT_REF, g_##ref_type##_ispect, is_list },
|
|
|
|
ISPECT_REF, g_##ref_type##_ispect, is_list },
|
|
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// ~~~ Chat ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
|
|
struct user_channel
|
|
|
|
struct user_channel
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -1431,7 +1466,7 @@ channel_destroy (struct channel *self)
|
|
|
|
|
|
|
|
|
|
|
|
REF_COUNTABLE_METHODS (channel)
|
|
|
|
REF_COUNTABLE_METHODS (channel)
|
|
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// ~~~ Buffers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
|
|
enum formatter_item_type
|
|
|
|
enum formatter_item_type
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -1444,10 +1479,21 @@ enum formatter_item_type
|
|
|
|
FORMATTER_ITEM_IGNORE_ATTR ///< Un/set attribute ignoration
|
|
|
|
FORMATTER_ITEM_IGNORE_ATTR ///< Un/set attribute ignoration
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
TEXT_BOLD = 1 << 0,
|
|
|
|
|
|
|
|
TEXT_ITALIC = 1 << 1,
|
|
|
|
|
|
|
|
TEXT_UNDERLINE = 1 << 2,
|
|
|
|
|
|
|
|
TEXT_INVERSE = 1 << 3,
|
|
|
|
|
|
|
|
TEXT_BLINK = 1 << 4,
|
|
|
|
|
|
|
|
TEXT_CROSSED_OUT = 1 << 5,
|
|
|
|
|
|
|
|
TEXT_MONOSPACE = 1 << 6
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct formatter_item
|
|
|
|
struct formatter_item
|
|
|
|
{
|
|
|
|
{
|
|
|
|
enum formatter_item_type type : 16; ///< Type of this item
|
|
|
|
enum formatter_item_type type : 16; ///< Type of this item
|
|
|
|
int attribute : 16; ///< Attribute ID
|
|
|
|
int attribute : 16; ///< Attribute ID or a TEXT_* mask
|
|
|
|
int color; ///< Colour
|
|
|
|
int color; ///< Colour
|
|
|
|
char *text; ///< String
|
|
|
|
char *text; ///< String
|
|
|
|
};
|
|
|
|
};
|
|
|
|
@@ -1627,7 +1673,7 @@ buffer_destroy (struct buffer *self)
|
|
|
|
REF_COUNTABLE_METHODS (buffer)
|
|
|
|
REF_COUNTABLE_METHODS (buffer)
|
|
|
|
#define buffer_ref do_not_use_dangerous
|
|
|
|
#define buffer_ref do_not_use_dangerous
|
|
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// ~~~ Server ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
|
|
// The only real purpose of this is to abstract away TLS
|
|
|
|
// The only real purpose of this is to abstract away TLS
|
|
|
|
struct transport
|
|
|
|
struct transport
|
|
|
|
@@ -1903,7 +1949,7 @@ server_destroy (struct server *self)
|
|
|
|
REF_COUNTABLE_METHODS (server)
|
|
|
|
REF_COUNTABLE_METHODS (server)
|
|
|
|
#define server_ref do_not_use_dangerous
|
|
|
|
#define server_ref do_not_use_dangerous
|
|
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// ~~~ Scripting ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
|
|
struct plugin
|
|
|
|
struct plugin
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -2022,7 +2068,7 @@ struct completion_hook
|
|
|
|
struct completion *data, const char *word, struct strv *output);
|
|
|
|
struct completion *data, const char *word, struct strv *output);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// ~~~ Main context ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
|
|
struct app_context
|
|
|
|
struct app_context
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -2085,7 +2131,7 @@ struct app_context
|
|
|
|
bool in_bracketed_paste; ///< User is pasting some content
|
|
|
|
bool in_bracketed_paste; ///< User is pasting some content
|
|
|
|
struct str input_buffer; ///< Buffered pasted content
|
|
|
|
struct str input_buffer; ///< Buffered pasted content
|
|
|
|
|
|
|
|
|
|
|
|
bool running_backlog_helper; ///< Running a backlog helper
|
|
|
|
bool running_pager; ///< Running a pager for buffer history
|
|
|
|
bool running_editor; ///< Running editor for the input
|
|
|
|
bool running_editor; ///< Running editor for the input
|
|
|
|
char *editor_filename; ///< The file being edited by user
|
|
|
|
char *editor_filename; ///< The file being edited by user
|
|
|
|
int terminal_suspended; ///< Terminal suspension level
|
|
|
|
int terminal_suspended; ///< Terminal suspension level
|
|
|
|
@@ -2420,18 +2466,65 @@ static struct config_schema g_config_server[] =
|
|
|
|
{}
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static struct config_schema g_config_behaviour[] =
|
|
|
|
static struct config_schema g_config_general[] =
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
{ .name = "autosave",
|
|
|
|
|
|
|
|
.comment = "Save configuration automatically after each change",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
|
|
|
|
.default_ = "on" },
|
|
|
|
|
|
|
|
{ .name = "debug_mode",
|
|
|
|
|
|
|
|
.comment = "Produce some debugging output",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
|
|
|
|
.default_ = "off",
|
|
|
|
|
|
|
|
.on_change = on_config_debug_mode_change },
|
|
|
|
|
|
|
|
{ .name = "logging",
|
|
|
|
|
|
|
|
.comment = "Log buffer contents to file",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
|
|
|
|
.default_ = "off",
|
|
|
|
|
|
|
|
.on_change = on_config_logging_change },
|
|
|
|
|
|
|
|
{ .name = "plugin_autoload",
|
|
|
|
|
|
|
|
.comment = "Plugins to automatically load on start",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_STRING_ARRAY,
|
|
|
|
|
|
|
|
.validate = config_validate_nonjunk_string },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Buffer history:
|
|
|
|
|
|
|
|
{ .name = "backlog_limit",
|
|
|
|
|
|
|
|
.comment = "Maximum number of lines stored in the backlog",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_INTEGER,
|
|
|
|
|
|
|
|
.validate = config_validate_nonnegative,
|
|
|
|
|
|
|
|
.default_ = "1000",
|
|
|
|
|
|
|
|
.on_change = on_config_backlog_limit_change },
|
|
|
|
|
|
|
|
{ .name = "pager",
|
|
|
|
|
|
|
|
.comment = "Shell command to page buffer history (args: name [path])",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_STRING,
|
|
|
|
|
|
|
|
.default_ = "`name=$(echo \"$1\" | sed 's/[%?:.]/\\\\&/g'); "
|
|
|
|
|
|
|
|
"prompt='?f%F:'$name'. ?db- page %db?L of %D. .(?eEND:?PB%PB\\%..)'; "
|
|
|
|
|
|
|
|
"LESSSECURE=1 less +Gb -Ps\"$prompt\" \"${2:--R}\"`" },
|
|
|
|
|
|
|
|
{ .name = "pager_strip_formatting",
|
|
|
|
|
|
|
|
.comment = "Strip terminal formatting from pager input",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
|
|
|
|
.default_ = "off" },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Output adjustments:
|
|
|
|
|
|
|
|
{ .name = "beep_on_highlight",
|
|
|
|
|
|
|
|
.comment = "Ring the bell when highlighted or on a new invisible PM",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
|
|
|
|
.default_ = "on",
|
|
|
|
|
|
|
|
.on_change = on_config_beep_on_highlight_change },
|
|
|
|
|
|
|
|
{ .name = "date_change_line",
|
|
|
|
|
|
|
|
.comment = "Input to strftime(3) for the date change line",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_STRING,
|
|
|
|
|
|
|
|
.default_ = "\"%F\"" },
|
|
|
|
{ .name = "isolate_buffers",
|
|
|
|
{ .name = "isolate_buffers",
|
|
|
|
.comment = "Don't leak messages from the server and global buffers",
|
|
|
|
.comment = "Don't leak messages from the server and global buffers",
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
.default_ = "off",
|
|
|
|
.default_ = "off",
|
|
|
|
.on_change = on_config_isolate_buffers_change },
|
|
|
|
.on_change = on_config_isolate_buffers_change },
|
|
|
|
{ .name = "beep_on_highlight",
|
|
|
|
{ .name = "read_marker_char",
|
|
|
|
.comment = "Beep when highlighted or on a new invisible PM",
|
|
|
|
.comment = "The character to use for the read marker line",
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
.type = CONFIG_ITEM_STRING,
|
|
|
|
.default_ = "on",
|
|
|
|
.default_ = "\"-\"",
|
|
|
|
.on_change = on_config_beep_on_highlight_change },
|
|
|
|
.validate = config_validate_nonjunk_string },
|
|
|
|
{ .name = "show_all_prefixes",
|
|
|
|
{ .name = "show_all_prefixes",
|
|
|
|
.comment = "Show all prefixes in front of nicknames",
|
|
|
|
.comment = "Show all prefixes in front of nicknames",
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
@@ -2442,7 +2535,9 @@ static struct config_schema g_config_behaviour[] =
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
.default_ = "on",
|
|
|
|
.default_ = "on",
|
|
|
|
.on_change = on_config_word_wrapping_change },
|
|
|
|
.on_change = on_config_word_wrapping_change },
|
|
|
|
{ .name = "editor_command",
|
|
|
|
|
|
|
|
|
|
|
|
// User input:
|
|
|
|
|
|
|
|
{ .name = "editor",
|
|
|
|
.comment = "VIM: \"vim +%Bgo %F\", Emacs: \"emacs -nw +%L:%C %F\", "
|
|
|
|
.comment = "VIM: \"vim +%Bgo %F\", Emacs: \"emacs -nw +%L:%C %F\", "
|
|
|
|
"nano/micro/kakoune: \"nano/micro/kak +%L:%C %F\"",
|
|
|
|
"nano/micro/kakoune: \"nano/micro/kak +%L:%C %F\"",
|
|
|
|
.type = CONFIG_ITEM_STRING },
|
|
|
|
.type = CONFIG_ITEM_STRING },
|
|
|
|
@@ -2450,58 +2545,8 @@ static struct config_schema g_config_behaviour[] =
|
|
|
|
.comment = "Normalize newlines and quote the command prefix in pastes",
|
|
|
|
.comment = "Normalize newlines and quote the command prefix in pastes",
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
.default_ = "on" },
|
|
|
|
.default_ = "on" },
|
|
|
|
{ .name = "date_change_line",
|
|
|
|
|
|
|
|
.comment = "Input to strftime(3) for the date change line",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_STRING,
|
|
|
|
|
|
|
|
.default_ = "\"%F\"" },
|
|
|
|
|
|
|
|
{ .name = "read_marker_char",
|
|
|
|
|
|
|
|
.comment = "The character to use for the read marker line",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_STRING,
|
|
|
|
|
|
|
|
.default_ = "\"-\"",
|
|
|
|
|
|
|
|
.validate = config_validate_nonjunk_string },
|
|
|
|
|
|
|
|
{ .name = "logging",
|
|
|
|
|
|
|
|
.comment = "Log buffer contents to file",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
|
|
|
|
.default_ = "off",
|
|
|
|
|
|
|
|
.on_change = on_config_logging_change },
|
|
|
|
|
|
|
|
{ .name = "save_on_quit",
|
|
|
|
|
|
|
|
.comment = "Save configuration before quitting",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
|
|
|
|
.default_ = "on" },
|
|
|
|
|
|
|
|
{ .name = "debug_mode",
|
|
|
|
|
|
|
|
.comment = "Produce some debugging output",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
|
|
|
|
.default_ = "off",
|
|
|
|
|
|
|
|
.on_change = on_config_debug_mode_change },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ .name = "backlog_limit",
|
|
|
|
|
|
|
|
.comment = "Maximum number of lines stored in the backlog",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_INTEGER,
|
|
|
|
|
|
|
|
.validate = config_validate_nonnegative,
|
|
|
|
|
|
|
|
.default_ = "1000",
|
|
|
|
|
|
|
|
.on_change = on_config_backlog_limit_change },
|
|
|
|
|
|
|
|
{ .name = "backlog_helper",
|
|
|
|
|
|
|
|
.comment = "Shell command to page buffer history (args: name [path])",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_STRING,
|
|
|
|
|
|
|
|
.default_ = "`name=$(echo \"$1\" | sed 's/[%?:.]/\\\\&/g'); "
|
|
|
|
|
|
|
|
"prompt='?f%F:'$name'. ?db- page %db?L of %D. .(?eEND:?PB%PB\\%..)'; "
|
|
|
|
|
|
|
|
"LESSSECURE=1 less +Gb -Ps\"$prompt\" \"${2:--R}\"`" },
|
|
|
|
|
|
|
|
{ .name = "backlog_helper_strip_formatting",
|
|
|
|
|
|
|
|
.comment = "Strip formatting from backlog helper input",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_BOOLEAN,
|
|
|
|
|
|
|
|
.default_ = "off" },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ .name = "reconnect_delay_growing",
|
|
|
|
|
|
|
|
.comment = "Growing factor for reconnect delay",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_INTEGER,
|
|
|
|
|
|
|
|
.validate = config_validate_nonnegative,
|
|
|
|
|
|
|
|
.default_ = "2" },
|
|
|
|
|
|
|
|
{ .name = "reconnect_delay_max",
|
|
|
|
|
|
|
|
.comment = "Maximum reconnect delay in seconds",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_INTEGER,
|
|
|
|
|
|
|
|
.validate = config_validate_nonnegative,
|
|
|
|
|
|
|
|
.default_ = "600" },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Pan-server configuration:
|
|
|
|
{ .name = "autoaway_message",
|
|
|
|
{ .name = "autoaway_message",
|
|
|
|
.comment = "Automated away message",
|
|
|
|
.comment = "Automated away message",
|
|
|
|
.type = CONFIG_ITEM_STRING,
|
|
|
|
.type = CONFIG_ITEM_STRING,
|
|
|
|
@@ -2511,11 +2556,16 @@ static struct config_schema g_config_behaviour[] =
|
|
|
|
.type = CONFIG_ITEM_INTEGER,
|
|
|
|
.type = CONFIG_ITEM_INTEGER,
|
|
|
|
.validate = config_validate_nonnegative,
|
|
|
|
.validate = config_validate_nonnegative,
|
|
|
|
.default_ = "1800" },
|
|
|
|
.default_ = "1800" },
|
|
|
|
|
|
|
|
{ .name = "reconnect_delay_growing",
|
|
|
|
{ .name = "plugin_autoload",
|
|
|
|
.comment = "Growth factor for the reconnect delay",
|
|
|
|
.comment = "Plugins to automatically load on start",
|
|
|
|
.type = CONFIG_ITEM_INTEGER,
|
|
|
|
.type = CONFIG_ITEM_STRING_ARRAY,
|
|
|
|
.validate = config_validate_nonnegative,
|
|
|
|
.validate = config_validate_nonjunk_string },
|
|
|
|
.default_ = "2" },
|
|
|
|
|
|
|
|
{ .name = "reconnect_delay_max",
|
|
|
|
|
|
|
|
.comment = "Maximum reconnect delay in seconds",
|
|
|
|
|
|
|
|
.type = CONFIG_ITEM_INTEGER,
|
|
|
|
|
|
|
|
.validate = config_validate_nonnegative,
|
|
|
|
|
|
|
|
.default_ = "600" },
|
|
|
|
{}
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2531,9 +2581,9 @@ static struct config_schema g_config_attributes[] =
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
load_config_behaviour (struct config_item *subtree, void *user_data)
|
|
|
|
load_config_general (struct config_item *subtree, void *user_data)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
config_schema_apply_to_object (g_config_behaviour, subtree, user_data);
|
|
|
|
config_schema_apply_to_object (g_config_general, subtree, user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
@@ -2550,7 +2600,7 @@ register_config_modules (struct app_context *ctx)
|
|
|
|
config_register_module (config, "servers", NULL, NULL);
|
|
|
|
config_register_module (config, "servers", NULL, NULL);
|
|
|
|
config_register_module (config, "aliases", NULL, NULL);
|
|
|
|
config_register_module (config, "aliases", NULL, NULL);
|
|
|
|
config_register_module (config, "plugins", NULL, NULL);
|
|
|
|
config_register_module (config, "plugins", NULL, NULL);
|
|
|
|
config_register_module (config, "behaviour", load_config_behaviour, ctx);
|
|
|
|
config_register_module (config, "general", load_config_general, ctx);
|
|
|
|
config_register_module (config, "attributes", load_config_attributes, ctx);
|
|
|
|
config_register_module (config, "attributes", load_config_attributes, ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2785,24 +2835,13 @@ init_colors (struct app_context *ctx)
|
|
|
|
(config_item_get (ctx->config.root, "attributes", NULL));
|
|
|
|
(config_item_get (ctx->config.root, "attributes", NULL));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// ~~~ Attribute printer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
|
|
// A little tool that tries to make the most of the terminal's capabilities
|
|
|
|
// A little tool that tries to make the most of the terminal's capabilities
|
|
|
|
// to set up text attributes. It mostly targets just terminal emulators as that
|
|
|
|
// to set up text attributes. It mostly targets just terminal emulators as that
|
|
|
|
// is what people are using these days. At least no stupid ncurses limits us
|
|
|
|
// is what people are using these days. At least no stupid ncurses limits us
|
|
|
|
// with colour pairs.
|
|
|
|
// with colour pairs.
|
|
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
TEXT_BOLD = 1 << 0,
|
|
|
|
|
|
|
|
TEXT_ITALIC = 1 << 1,
|
|
|
|
|
|
|
|
TEXT_UNDERLINE = 1 << 2,
|
|
|
|
|
|
|
|
TEXT_INVERSE = 1 << 3,
|
|
|
|
|
|
|
|
TEXT_BLINK = 1 << 4,
|
|
|
|
|
|
|
|
TEXT_CROSSED_OUT = 1 << 5,
|
|
|
|
|
|
|
|
TEXT_MONOSPACE = 1 << 6
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct attr_printer
|
|
|
|
struct attr_printer
|
|
|
|
{
|
|
|
|
{
|
|
|
|
char **attrs; ///< Named attributes
|
|
|
|
char **attrs; ///< Named attributes
|
|
|
|
@@ -3776,7 +3815,7 @@ explode_text (struct exploder *self, const char *text)
|
|
|
|
if (!strchr ("\a\b\x0e\x0f\x1b" /* BEL BS SO SI ESC */, *p))
|
|
|
|
if (!strchr ("\a\b\x0e\x0f\x1b" /* BEL BS SO SI ESC */, *p))
|
|
|
|
str_append_c (&filtered, *p);
|
|
|
|
str_append_c (&filtered, *p);
|
|
|
|
|
|
|
|
|
|
|
|
size_t term_len = 0;
|
|
|
|
size_t term_len = 0, processed = 0, len;
|
|
|
|
char *term = iconv_xstrdup (self->ctx->term_from_utf8,
|
|
|
|
char *term = iconv_xstrdup (self->ctx->term_from_utf8,
|
|
|
|
filtered.str, filtered.len + 1, &term_len);
|
|
|
|
filtered.str, filtered.len + 1, &term_len);
|
|
|
|
str_free (&filtered);
|
|
|
|
str_free (&filtered);
|
|
|
|
@@ -3785,11 +3824,10 @@ explode_text (struct exploder *self, const char *text)
|
|
|
|
memset (&ps, 0, sizeof ps);
|
|
|
|
memset (&ps, 0, sizeof ps);
|
|
|
|
|
|
|
|
|
|
|
|
wchar_t wch;
|
|
|
|
wchar_t wch;
|
|
|
|
size_t len, processed = 0;
|
|
|
|
|
|
|
|
while ((len = mbrtowc (&wch, term + processed, term_len - processed, &ps)))
|
|
|
|
while ((len = mbrtowc (&wch, term + processed, term_len - processed, &ps)))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
hard_assert (len != (size_t) -2 && len != (size_t) -1);
|
|
|
|
hard_assert (len != (size_t) -2 && len != (size_t) -1);
|
|
|
|
processed += len;
|
|
|
|
hard_assert ((processed += len) <= term_len);
|
|
|
|
|
|
|
|
|
|
|
|
struct line_char *c = line_char_new (wch);
|
|
|
|
struct line_char *c = line_char_new (wch);
|
|
|
|
c->attrs = self->attrs;
|
|
|
|
c->attrs = self->attrs;
|
|
|
|
@@ -3924,7 +3962,7 @@ buffer_update_time (struct app_context *ctx, time_t now, FILE *stream,
|
|
|
|
|
|
|
|
|
|
|
|
char buf[64] = "";
|
|
|
|
char buf[64] = "";
|
|
|
|
const char *format =
|
|
|
|
const char *format =
|
|
|
|
get_config_string (ctx->config.root, "behaviour.date_change_line");
|
|
|
|
get_config_string (ctx->config.root, "general.date_change_line");
|
|
|
|
if (!strftime (buf, sizeof buf, format, ¤t))
|
|
|
|
if (!strftime (buf, sizeof buf, format, ¤t))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
print_error ("%s: %s", "strftime", strerror (errno));
|
|
|
|
print_error ("%s: %s", "strftime", strerror (errno));
|
|
|
|
@@ -4301,8 +4339,8 @@ buffer_print_read_marker (struct app_context *ctx, FILE *stream, int flush_opts)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct formatter f = formatter_make (ctx, NULL);
|
|
|
|
struct formatter f = formatter_make (ctx, NULL);
|
|
|
|
const int timestamp_width = 8; // hardcoded to %T right now, simple
|
|
|
|
const int timestamp_width = 8; // hardcoded to %T right now, simple
|
|
|
|
const char *marker_char = get_config_string (ctx->config.root,
|
|
|
|
const char *marker_char =
|
|
|
|
"behaviour.read_marker_char");
|
|
|
|
get_config_string (ctx->config.root, "general.read_marker_char");
|
|
|
|
|
|
|
|
|
|
|
|
// We could turn this off on FLUSH_OPT_NOWRAP, however our default pager
|
|
|
|
// We could turn this off on FLUSH_OPT_NOWRAP, however our default pager
|
|
|
|
// wraps lines for us even if we don't do it ourselves, and thus there's
|
|
|
|
// wraps lines for us even if we don't do it ourselves, and thus there's
|
|
|
|
@@ -4912,8 +4950,8 @@ static int64_t
|
|
|
|
irc_get_reconnect_delay (struct server *s)
|
|
|
|
irc_get_reconnect_delay (struct server *s)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int64_t delay = get_config_integer (s->config, "reconnect_delay");
|
|
|
|
int64_t delay = get_config_integer (s->config, "reconnect_delay");
|
|
|
|
int64_t delay_factor = get_config_integer (s->ctx->config.root,
|
|
|
|
int64_t delay_factor = get_config_integer
|
|
|
|
"behaviour.reconnect_delay_growing");
|
|
|
|
(s->ctx->config.root, "general.reconnect_delay_growing");
|
|
|
|
for (unsigned i = 0; i < s->reconnect_attempt; i++)
|
|
|
|
for (unsigned i = 0; i < s->reconnect_attempt; i++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (delay_factor && delay > INT64_MAX / delay_factor)
|
|
|
|
if (delay_factor && delay > INT64_MAX / delay_factor)
|
|
|
|
@@ -4921,8 +4959,8 @@ irc_get_reconnect_delay (struct server *s)
|
|
|
|
delay *= delay_factor;
|
|
|
|
delay *= delay_factor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int64_t delay_max = get_config_integer (s->ctx->config.root,
|
|
|
|
int64_t delay_max =
|
|
|
|
"behaviour.reconnect_delay_max");
|
|
|
|
get_config_integer (s->ctx->config.root, "general.reconnect_delay_max");
|
|
|
|
return MIN (delay, delay_max);
|
|
|
|
return MIN (delay, delay_max);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -10527,6 +10565,33 @@ lua_plugin_get_screen_size (lua_State *L)
|
|
|
|
return 2;
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
|
|
|
lua_plugin_measure (lua_State *L)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1));
|
|
|
|
|
|
|
|
const char *line = lua_plugin_check_utf8 (L, 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size_t term_len = 0, processed = 0, width = 0, len;
|
|
|
|
|
|
|
|
char *term = iconv_xstrdup (plugin->ctx->term_from_utf8,
|
|
|
|
|
|
|
|
(char *) line, strlen (line) + 1, &term_len);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mbstate_t ps;
|
|
|
|
|
|
|
|
memset (&ps, 0, sizeof ps);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
wchar_t wch;
|
|
|
|
|
|
|
|
while ((len = mbrtowc (&wch, term + processed, term_len - processed, &ps)))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
hard_assert (len != (size_t) -2 && len != (size_t) -1);
|
|
|
|
|
|
|
|
hard_assert ((processed += len) <= term_len);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int wch_width = wcwidth (wch);
|
|
|
|
|
|
|
|
width += MAX (0, wch_width);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
free (term);
|
|
|
|
|
|
|
|
lua_pushinteger (L, width);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
static int
|
|
|
|
lua_ctx_gc (lua_State *L)
|
|
|
|
lua_ctx_gc (lua_State *L)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -10547,6 +10612,7 @@ static luaL_Reg lua_plugin_library[] =
|
|
|
|
// And these are methods:
|
|
|
|
// And these are methods:
|
|
|
|
|
|
|
|
|
|
|
|
{ "get_screen_size", lua_plugin_get_screen_size },
|
|
|
|
{ "get_screen_size", lua_plugin_get_screen_size },
|
|
|
|
|
|
|
|
{ "measure", lua_plugin_measure },
|
|
|
|
{ "__gc", lua_ctx_gc },
|
|
|
|
{ "__gc", lua_ctx_gc },
|
|
|
|
{ NULL, NULL },
|
|
|
|
{ NULL, NULL },
|
|
|
|
};
|
|
|
|
};
|
|
|
|
@@ -10965,8 +11031,8 @@ plugin_unload (struct app_context *ctx, const char *name)
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
load_plugins (struct app_context *ctx)
|
|
|
|
load_plugins (struct app_context *ctx)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const char *plugins = get_config_string
|
|
|
|
const char *plugins =
|
|
|
|
(ctx->config.root, "behaviour.plugin_autoload");
|
|
|
|
get_config_string (ctx->config.root, "general.plugin_autoload");
|
|
|
|
if (plugins)
|
|
|
|
if (plugins)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct strv v = strv_make ();
|
|
|
|
struct strv v = strv_make ();
|
|
|
|
@@ -11332,6 +11398,8 @@ static bool
|
|
|
|
handle_command_set_assign
|
|
|
|
handle_command_set_assign
|
|
|
|
(struct app_context *ctx, struct strv *all, char *arguments)
|
|
|
|
(struct app_context *ctx, struct strv *all, char *arguments)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
hard_assert (all->len > 0);
|
|
|
|
|
|
|
|
|
|
|
|
char *op = cut_word (&arguments);
|
|
|
|
char *op = cut_word (&arguments);
|
|
|
|
bool add = false;
|
|
|
|
bool add = false;
|
|
|
|
bool remove = false;
|
|
|
|
bool remove = false;
|
|
|
|
@@ -11366,6 +11434,9 @@ handle_command_set_assign
|
|
|
|
free (key);
|
|
|
|
free (key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
config_item_destroy (new_);
|
|
|
|
config_item_destroy (new_);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (get_config_boolean (ctx->config.root, "general.autosave"))
|
|
|
|
|
|
|
|
save_configuration (ctx);
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -13206,8 +13277,7 @@ static struct strv
|
|
|
|
build_editor_command (struct app_context *ctx, const char *filename)
|
|
|
|
build_editor_command (struct app_context *ctx, const char *filename)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct strv argv = strv_make ();
|
|
|
|
struct strv argv = strv_make ();
|
|
|
|
const char *editor = get_config_string
|
|
|
|
const char *editor = get_config_string (ctx->config.root, "general.editor");
|
|
|
|
(ctx->config.root, "behaviour.editor_command");
|
|
|
|
|
|
|
|
if (!editor)
|
|
|
|
if (!editor)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const char *command;
|
|
|
|
const char *command;
|
|
|
|
@@ -13215,8 +13285,8 @@ build_editor_command (struct app_context *ctx, const char *filename)
|
|
|
|
&& !(command = getenv ("EDITOR")))
|
|
|
|
&& !(command = getenv ("EDITOR")))
|
|
|
|
command = "vi";
|
|
|
|
command = "vi";
|
|
|
|
|
|
|
|
|
|
|
|
// Although most visual editors support a "+LINE" argument (every
|
|
|
|
// Although most visual editors support a "+LINE" argument
|
|
|
|
// editor mentioned in the default value of behaviour.editor_command,
|
|
|
|
// (every editor mentioned in the default value of general.editor,
|
|
|
|
// plus vi, mcedit, vis, ...), it isn't particularly useful by itself.
|
|
|
|
// plus vi, mcedit, vis, ...), it isn't particularly useful by itself.
|
|
|
|
// We need to be able to specify the column number.
|
|
|
|
// We need to be able to specify the column number.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
@@ -13376,28 +13446,27 @@ input_editor_cleanup (struct app_context *ctx)
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
static void
|
|
|
|
launch_backlog_helper (struct app_context *ctx, int backlog_fd,
|
|
|
|
launch_pager (struct app_context *ctx,
|
|
|
|
const char *name, const char *path)
|
|
|
|
int fd, const char *name, const char *path)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
hard_assert (!ctx->running_backlog_helper);
|
|
|
|
hard_assert (!ctx->running_pager);
|
|
|
|
switch (spawn_helper_child (ctx))
|
|
|
|
switch (spawn_helper_child (ctx))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
case 0:
|
|
|
|
dup2 (backlog_fd, STDIN_FILENO);
|
|
|
|
dup2 (fd, STDIN_FILENO);
|
|
|
|
char *localized_name =
|
|
|
|
char *localized_name =
|
|
|
|
iconv_xstrdup (ctx->term_from_utf8, (char *) name, -1, NULL);
|
|
|
|
iconv_xstrdup (ctx->term_from_utf8, (char *) name, -1, NULL);
|
|
|
|
execl ("/bin/sh", "/bin/sh", "-c",
|
|
|
|
execl ("/bin/sh", "/bin/sh", "-c",
|
|
|
|
get_config_string (ctx->config.root, "behaviour.backlog_helper"),
|
|
|
|
get_config_string (ctx->config.root, "general.pager"),
|
|
|
|
PROGRAM_NAME, localized_name, path, NULL);
|
|
|
|
PROGRAM_NAME, localized_name, path, NULL);
|
|
|
|
print_error ("%s: %s",
|
|
|
|
print_error ("%s: %s", "Failed to launch pager", strerror (errno));
|
|
|
|
"Failed to launch backlog helper", strerror (errno));
|
|
|
|
|
|
|
|
_exit (EXIT_FAILURE);
|
|
|
|
_exit (EXIT_FAILURE);
|
|
|
|
case -1:
|
|
|
|
case -1:
|
|
|
|
log_global_error (ctx, "#s: #l",
|
|
|
|
log_global_error (ctx, "#s: #l",
|
|
|
|
"Failed to launch backlog helper", strerror (errno));
|
|
|
|
"Failed to launch pager", strerror (errno));
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
ctx->running_backlog_helper = true;
|
|
|
|
ctx->running_pager = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -13413,7 +13482,7 @@ display_backlog (struct app_context *ctx, int flush_opts)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!get_config_boolean (ctx->config.root,
|
|
|
|
if (!get_config_boolean (ctx->config.root,
|
|
|
|
"behaviour.backlog_helper_strip_formatting"))
|
|
|
|
"general.pager_strip_formatting"))
|
|
|
|
flush_opts |= FLUSH_OPT_RAW;
|
|
|
|
flush_opts |= FLUSH_OPT_RAW;
|
|
|
|
|
|
|
|
|
|
|
|
struct buffer *buffer = ctx->current_buffer;
|
|
|
|
struct buffer *buffer = ctx->current_buffer;
|
|
|
|
@@ -13433,7 +13502,7 @@ display_backlog (struct app_context *ctx, int flush_opts)
|
|
|
|
|
|
|
|
|
|
|
|
rewind (backlog);
|
|
|
|
rewind (backlog);
|
|
|
|
set_cloexec (fileno (backlog));
|
|
|
|
set_cloexec (fileno (backlog));
|
|
|
|
launch_backlog_helper (ctx, fileno (backlog), buffer->name, NULL);
|
|
|
|
launch_pager (ctx, fileno (backlog), buffer->name, NULL);
|
|
|
|
fclose (backlog);
|
|
|
|
fclose (backlog);
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -13477,7 +13546,7 @@ on_display_full_log (int count, int key, void *user_data)
|
|
|
|
(void) fflush (buffer->log_file);
|
|
|
|
(void) fflush (buffer->log_file);
|
|
|
|
|
|
|
|
|
|
|
|
set_cloexec (fileno (full_log));
|
|
|
|
set_cloexec (fileno (full_log));
|
|
|
|
launch_backlog_helper (ctx, fileno (full_log), buffer->name, path);
|
|
|
|
launch_pager (ctx, fileno (full_log), buffer->name, path);
|
|
|
|
fclose (full_log);
|
|
|
|
fclose (full_log);
|
|
|
|
free (path);
|
|
|
|
free (path);
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
@@ -13874,13 +13943,10 @@ on_editline_return (EditLine *editline, int key)
|
|
|
|
wchar_t *line = calloc (sizeof *info->buffer, len + 1);
|
|
|
|
wchar_t *line = calloc (sizeof *info->buffer, len + 1);
|
|
|
|
memcpy (line, info->buffer, sizeof *info->buffer * len);
|
|
|
|
memcpy (line, info->buffer, sizeof *info->buffer * len);
|
|
|
|
|
|
|
|
|
|
|
|
// XXX: Editline seems to remember its position in history,
|
|
|
|
|
|
|
|
// so it's not going to work as you'd expect it to
|
|
|
|
|
|
|
|
if (*line)
|
|
|
|
if (*line)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
HistEventW ev;
|
|
|
|
HistEventW ev;
|
|
|
|
history_w (self->current->history, &ev, H_ENTER, line);
|
|
|
|
history_w (self->current->history, &ev, H_ENTER, line);
|
|
|
|
print_debug ("history: %d %ls", ev.num, ev.str);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free (line);
|
|
|
|
free (line);
|
|
|
|
|
|
|
|
|
|
|
|
@@ -13892,6 +13958,7 @@ on_editline_return (EditLine *editline, int key)
|
|
|
|
|
|
|
|
|
|
|
|
el_cursor (editline, len - point);
|
|
|
|
el_cursor (editline, len - point);
|
|
|
|
el_wdeletestr (editline, len);
|
|
|
|
el_wdeletestr (editline, len);
|
|
|
|
|
|
|
|
input_el__bottom (self);
|
|
|
|
return CC_REFRESH;
|
|
|
|
return CC_REFRESH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -13940,7 +14007,7 @@ static const char *g_first_time_help[] =
|
|
|
|
"",
|
|
|
|
"",
|
|
|
|
"To get a list of all commands, type \x02/help\x02. To obtain",
|
|
|
|
"To get a list of all commands, type \x02/help\x02. To obtain",
|
|
|
|
"more information on a command or option, simply add it as",
|
|
|
|
"more information on a command or option, simply add it as",
|
|
|
|
"a parameter, e.g. \x02/help set\x02 or \x02/help behaviour.logging\x02.",
|
|
|
|
"a parameter, e.g. \x02/help set\x02 or \x02/help general.logging\x02.",
|
|
|
|
"",
|
|
|
|
"",
|
|
|
|
"To switch between buffers, press \x02"
|
|
|
|
"To switch between buffers, press \x02"
|
|
|
|
"F5/Ctrl-P\x02 or \x02" "F6/Ctrl-N\x02.",
|
|
|
|
"F5/Ctrl-P\x02 or \x02" "F6/Ctrl-N\x02.",
|
|
|
|
@@ -14147,8 +14214,8 @@ try_reap_child (struct app_context *ctx)
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (ctx->running_backlog_helper)
|
|
|
|
if (ctx->running_pager)
|
|
|
|
ctx->running_backlog_helper = false;
|
|
|
|
ctx->running_pager = false;
|
|
|
|
else if (!ctx->running_editor)
|
|
|
|
else if (!ctx->running_editor)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log_global_debug (ctx, "An unknown child has died");
|
|
|
|
log_global_debug (ctx, "An unknown child has died");
|
|
|
|
@@ -14265,7 +14332,7 @@ done:
|
|
|
|
static bool
|
|
|
|
static bool
|
|
|
|
insert_paste (struct app_context *ctx, char *paste, size_t len)
|
|
|
|
insert_paste (struct app_context *ctx, char *paste, size_t len)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (!get_config_boolean (ctx->config.root, "behaviour.process_pasted_text"))
|
|
|
|
if (!get_config_boolean (ctx->config.root, "general.process_pasted_text"))
|
|
|
|
return CALL_ (ctx->input, insert, paste);
|
|
|
|
return CALL_ (ctx->input, insert, paste);
|
|
|
|
|
|
|
|
|
|
|
|
// Without ICRNL, which Editline keeps but Readline doesn't,
|
|
|
|
// Without ICRNL, which Editline keeps but Readline doesn't,
|
|
|
|
@@ -14352,7 +14419,7 @@ reset_autoaway (struct app_context *ctx)
|
|
|
|
|
|
|
|
|
|
|
|
// And potentially start a new auto-away timer
|
|
|
|
// And potentially start a new auto-away timer
|
|
|
|
int64_t delay = get_config_integer
|
|
|
|
int64_t delay = get_config_integer
|
|
|
|
(ctx->config.root, "behaviour.autoaway_delay");
|
|
|
|
(ctx->config.root, "general.autoaway_delay");
|
|
|
|
if (delay)
|
|
|
|
if (delay)
|
|
|
|
poller_timer_set (&ctx->autoaway_tmr, delay * 1000);
|
|
|
|
poller_timer_set (&ctx->autoaway_tmr, delay * 1000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -14362,7 +14429,7 @@ on_autoaway_timer (struct app_context *ctx)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// An empty message would unset any away status, so let's ignore that
|
|
|
|
// An empty message would unset any away status, so let's ignore that
|
|
|
|
const char *message = get_config_string
|
|
|
|
const char *message = get_config_string
|
|
|
|
(ctx->config.root, "behaviour.autoaway_message");
|
|
|
|
(ctx->config.root, "general.autoaway_message");
|
|
|
|
if (!message || !*message)
|
|
|
|
if (!message || !*message)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -14719,9 +14786,6 @@ main (int argc, char *argv[])
|
|
|
|
|
|
|
|
|
|
|
|
CALL (ctx.input, stop);
|
|
|
|
CALL (ctx.input, stop);
|
|
|
|
|
|
|
|
|
|
|
|
if (get_config_boolean (ctx.config.root, "behaviour.save_on_quit"))
|
|
|
|
|
|
|
|
save_configuration (&ctx);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app_context_free (&ctx);
|
|
|
|
app_context_free (&ctx);
|
|
|
|
toggle_bracketed_paste (false);
|
|
|
|
toggle_bracketed_paste (false);
|
|
|
|
free_terminal ();
|
|
|
|
free_terminal ();
|
|
|
|
|