degesch: use libffi to unify input callbacks
And fuck you both, Readline and Editline.
This commit is contained in:
parent
3304b718aa
commit
584d2f0295
@ -39,7 +39,7 @@ include (AddThreads)
|
||||
|
||||
find_package (Curses)
|
||||
find_package (PkgConfig REQUIRED)
|
||||
pkg_check_modules (libssl REQUIRED libssl libcrypto)
|
||||
pkg_check_modules (dependencies REQUIRED libssl libcrypto libffi)
|
||||
pkg_check_modules (ncursesw ncursesw)
|
||||
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "BSD")
|
||||
@ -50,9 +50,9 @@ if ("${CMAKE_SYSTEM_NAME}" MATCHES "BSD")
|
||||
add_definitions (-D__BSD_VISIBLE=1 -D_BSD_SOURCE=1)
|
||||
endif ("${CMAKE_SYSTEM_NAME}" MATCHES "BSD")
|
||||
|
||||
list (APPEND project_libraries ${libssl_LIBRARIES})
|
||||
include_directories (${libssl_INCLUDE_DIRS})
|
||||
link_directories (${libssl_LIBRARY_DIRS})
|
||||
list (APPEND project_libraries ${dependencies_LIBRARIES})
|
||||
include_directories (${dependencies_INCLUDE_DIRS})
|
||||
link_directories (${dependencies_LIBRARY_DIRS})
|
||||
|
||||
# FIXME: other Lua versions may be acceptable, don't know yet
|
||||
pkg_search_module (lua lua53 lua5.3 lua-5.3 lua>=5.3)
|
||||
|
@ -10,7 +10,7 @@ All of them have these potentially interesting properties:
|
||||
|
||||
- full IPv6 support
|
||||
- TLS support, including client certificates
|
||||
- minimal dependencies
|
||||
- lean on dependencies (with the exception of 'degesch')
|
||||
- compact and arguably easy to hack on
|
||||
- permissive license
|
||||
|
||||
@ -66,9 +66,9 @@ support (even though socksify can add that easily to any program).
|
||||
Building
|
||||
--------
|
||||
Build dependencies: CMake, pkg-config, help2man, awk, sh, liberty (included) +
|
||||
Runtime dependencies: openssl, curses (degesch),
|
||||
readline >= 6.0 or libedit >= 2013-07-12 (degesch),
|
||||
lua >= 5.3 (degesch, optional)
|
||||
Runtime dependencies: openssl +
|
||||
Additionally for degesch: curses, libffi, lua >= 5.3 (optional),
|
||||
readline >= 6.0 or libedit >= 2013-07-12
|
||||
|
||||
$ git clone --recursive https://github.com/pjanouch/uirc3.git
|
||||
$ mkdir uirc3/build
|
||||
|
670
degesch.c
670
degesch.c
@ -68,6 +68,8 @@ enum
|
||||
#undef lines
|
||||
#undef columns
|
||||
|
||||
#include <ffi.h>
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
@ -134,6 +136,22 @@ input_buffer_destroy (struct input_buffer *self)
|
||||
free (self);
|
||||
}
|
||||
|
||||
typedef bool (*input_fn) (int count, int key, void *user_data);
|
||||
|
||||
struct input_fn_data
|
||||
{
|
||||
ffi_closure closure; ///< Closure
|
||||
|
||||
LIST_HEADER (struct input_fn_data)
|
||||
input_fn callback; ///< Real callback
|
||||
void *user_data; ///< Real callback user data
|
||||
|
||||
#ifdef HAVE_EDITLINE
|
||||
wchar_t *name; ///< Function name
|
||||
wchar_t *help; ///< Function help
|
||||
#endif // HAVE_EDITLINE
|
||||
};
|
||||
|
||||
struct input
|
||||
{
|
||||
bool active; ///< Are we a thing?
|
||||
@ -145,6 +163,7 @@ struct input
|
||||
#elif defined HAVE_EDITLINE
|
||||
EditLine *editline; ///< The EditLine object
|
||||
#endif // HAVE_EDITLINE
|
||||
struct input_fn_data *fns; ///< Functions
|
||||
|
||||
char *prompt; ///< The prompt we use
|
||||
int prompt_shown; ///< Whether the prompt is shown now
|
||||
@ -164,6 +183,14 @@ input_free (struct input *self)
|
||||
#ifdef HAVE_READLINE
|
||||
free (self->saved_line);
|
||||
#endif // HAVE_READLINE
|
||||
LIST_FOR_EACH (struct input_fn_data, iter, self->fns)
|
||||
{
|
||||
#ifdef HAVE_EDITLINE
|
||||
free (iter->name);
|
||||
free (iter->help);
|
||||
#endif // HAVE_EDITLINE
|
||||
ffi_closure_free (iter);
|
||||
}
|
||||
free (self->prompt);
|
||||
}
|
||||
|
||||
@ -279,6 +306,45 @@ input_get_content (struct input *self)
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static void
|
||||
input_closure_forwarder (ffi_cif *cif, void *ret, void **args, void *user_data)
|
||||
{
|
||||
(void) cif;
|
||||
|
||||
struct input_fn_data *data = user_data;
|
||||
if (!data->callback
|
||||
(*(int *) args[0], UNMETA (*(int *) args[1]), data->user_data))
|
||||
rl_ding ();
|
||||
*(int *) ret = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
input_add_fn (struct input *self,
|
||||
const char *name, const char *help, input_fn callback, void *user_data)
|
||||
{
|
||||
(void) help;
|
||||
|
||||
void *bound_fn = NULL;
|
||||
struct input_fn_data *data = ffi_closure_alloc (sizeof *data, &bound_fn);
|
||||
hard_assert (data);
|
||||
|
||||
static ffi_cif cif;
|
||||
static ffi_type *args[2] = { &ffi_type_sint, &ffi_type_sint };
|
||||
hard_assert (ffi_prep_cif
|
||||
(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, args) == FFI_OK);
|
||||
|
||||
data->prev = data->next = NULL;
|
||||
data->callback = callback;
|
||||
data->user_data = user_data;
|
||||
hard_assert (ffi_prep_closure_loc (&data->closure,
|
||||
&cif, input_closure_forwarder, data, bound_fn) == FFI_OK);
|
||||
|
||||
rl_add_defun (name, (rl_command_func_t *) bound_fn, -1);
|
||||
LIST_PREPEND (self->fns, data);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static int app_readline_init (void);
|
||||
static void on_readline_input (char *line);
|
||||
static char **app_readline_completion (const char *text, int start, int end);
|
||||
@ -603,6 +669,52 @@ input_get_content (struct input *self)
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static void
|
||||
input_closure_forwarder (ffi_cif *cif, void *ret, void **args, void *user_data)
|
||||
{
|
||||
(void) cif;
|
||||
|
||||
struct input_fn_data *data = user_data;
|
||||
*(unsigned char *) ret = data->callback
|
||||
(1, *(int *) args[1], data->user_data) ? CC_NORM : CC_ERROR;
|
||||
}
|
||||
|
||||
static wchar_t *
|
||||
ascii_to_wide (const char *ascii)
|
||||
{
|
||||
size_t len = strlen (ascii) + 1;
|
||||
wchar_t *wide = xcalloc (sizeof *wide, len);
|
||||
while (len--)
|
||||
hard_assert ((wide[len] = (unsigned char) ascii[len]) < 0x80);
|
||||
return wide;
|
||||
}
|
||||
|
||||
static void
|
||||
input_add_fn (struct input *self,
|
||||
const char *name, const char *help, input_fn callback, void *user_data)
|
||||
{
|
||||
void *bound_fn = NULL;
|
||||
struct input_fn_data *data = ffi_closure_alloc (sizeof *data, &bound_fn);
|
||||
hard_assert (data);
|
||||
|
||||
static ffi_cif cif;
|
||||
static ffi_type *args[2] = { &ffi_type_pointer, &ffi_type_sint };
|
||||
hard_assert (ffi_prep_cif
|
||||
(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_uchar, args) == FFI_OK);
|
||||
|
||||
data->user_data = user_data;
|
||||
data->callback = callback;
|
||||
data->name = ascii_to_wide (name);
|
||||
data->help = ascii_to_wide (help);
|
||||
hard_assert (ffi_prep_closure_loc (&data->closure,
|
||||
&cif, input_closure_forwarder, data, bound_fn) == FFI_OK);
|
||||
|
||||
el_wset (self->editline, EL_ADDFN, data->name, data->help, bound_fn);
|
||||
LIST_PREPEND (self->fns, data);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static void
|
||||
input_start (struct input *self, const char *program_name)
|
||||
{
|
||||
@ -11161,40 +11273,6 @@ resume_terminal (struct app_context *ctx)
|
||||
input_show (&ctx->input);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static void
|
||||
redraw_screen (struct app_context *ctx)
|
||||
{
|
||||
input_hide (&ctx->input);
|
||||
|
||||
// If by some circumstance we had the wrong idea
|
||||
input_on_terminal_resized (&ctx->input);
|
||||
update_screen_size ();
|
||||
|
||||
buffer_print_backlog (ctx, ctx->current_buffer);
|
||||
|
||||
input_show (&ctx->input);
|
||||
}
|
||||
|
||||
static bool
|
||||
jump_to_buffer (struct app_context *ctx, int n)
|
||||
{
|
||||
if (n < 0 || n > 9)
|
||||
return false;
|
||||
|
||||
// There's no buffer zero
|
||||
if (n == 0)
|
||||
n = 10;
|
||||
|
||||
if (ctx->last_buffer && buffer_get_index (ctx, ctx->current_buffer) == n)
|
||||
// Fast switching between two buffers
|
||||
buffer_activate (ctx, ctx->last_buffer);
|
||||
else if (!buffer_goto (ctx, n))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static pid_t
|
||||
spawn_helper_child (struct app_context *ctx)
|
||||
{
|
||||
@ -11222,69 +11300,20 @@ spawn_helper_child (struct app_context *ctx)
|
||||
}
|
||||
|
||||
static void
|
||||
launch_backlog_helper (struct app_context *ctx, int backlog_fd)
|
||||
redraw_screen (struct app_context *ctx)
|
||||
{
|
||||
hard_assert (!ctx->running_backlog_helper);
|
||||
switch (spawn_helper_child (ctx))
|
||||
{
|
||||
case 0:
|
||||
dup2 (backlog_fd, STDIN_FILENO);
|
||||
execl ("/bin/sh", "/bin/sh", "-c", get_config_string
|
||||
(ctx->config.root, "behaviour.backlog_helper"), NULL);
|
||||
print_error ("%s: %s",
|
||||
"Failed to launch backlog helper", strerror (errno));
|
||||
_exit (EXIT_FAILURE);
|
||||
case -1:
|
||||
log_global_error (ctx, "#s: #l",
|
||||
"Failed to launch backlog helper", strerror (errno));
|
||||
break;
|
||||
default:
|
||||
ctx->running_backlog_helper = true;
|
||||
}
|
||||
input_hide (&ctx->input);
|
||||
|
||||
// If by some circumstance we had the wrong idea
|
||||
input_on_terminal_resized (&ctx->input);
|
||||
update_screen_size ();
|
||||
|
||||
buffer_print_backlog (ctx, ctx->current_buffer);
|
||||
|
||||
input_show (&ctx->input);
|
||||
}
|
||||
|
||||
static void
|
||||
display_backlog (struct app_context *ctx)
|
||||
{
|
||||
FILE *backlog = tmpfile ();
|
||||
if (!backlog)
|
||||
{
|
||||
log_global_error (ctx, "#s: #l",
|
||||
"Failed to create a temporary file", strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
for (struct buffer_line *line = ctx->current_buffer->lines;
|
||||
line; line = line->next)
|
||||
buffer_line_write_to_backlog (ctx, line, backlog);
|
||||
|
||||
rewind (backlog);
|
||||
set_cloexec (fileno (backlog));
|
||||
launch_backlog_helper (ctx, fileno (backlog));
|
||||
fclose (backlog);
|
||||
}
|
||||
|
||||
static void
|
||||
display_full_log (struct app_context *ctx)
|
||||
{
|
||||
char *path = buffer_get_log_path (ctx->current_buffer);
|
||||
FILE *full_log = fopen (path, "rb");
|
||||
free (path);
|
||||
|
||||
if (!full_log)
|
||||
{
|
||||
log_global_error (ctx, "Failed to open log file for #s: #l",
|
||||
ctx->current_buffer->name, strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->current_buffer->log_file)
|
||||
fflush (ctx->current_buffer->log_file);
|
||||
|
||||
set_cloexec (fileno (full_log));
|
||||
launch_backlog_helper (ctx, fileno (full_log));
|
||||
fclose (full_log);
|
||||
}
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static bool
|
||||
dump_input_to_file (struct app_context *ctx, char *template, struct error **e)
|
||||
@ -11324,12 +11353,16 @@ try_dump_input_to_file (struct app_context *ctx)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
launch_input_editor (struct app_context *ctx)
|
||||
static bool
|
||||
on_edit_input (int count, int key, void *user_data)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
struct app_context *ctx = user_data;
|
||||
|
||||
char *filename;
|
||||
if (!(filename = try_dump_input_to_file (ctx)))
|
||||
return;
|
||||
return false;
|
||||
|
||||
const char *command;
|
||||
if (!(command = getenv ("VISUAL"))
|
||||
@ -11353,6 +11386,7 @@ launch_input_editor (struct app_context *ctx)
|
||||
ctx->running_editor = true;
|
||||
ctx->editor_filename = filename;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -11390,10 +11424,185 @@ input_editor_cleanup (struct app_context *ctx)
|
||||
ctx->running_editor = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static void
|
||||
launch_backlog_helper (struct app_context *ctx, int backlog_fd)
|
||||
{
|
||||
hard_assert (!ctx->running_backlog_helper);
|
||||
switch (spawn_helper_child (ctx))
|
||||
{
|
||||
case 0:
|
||||
dup2 (backlog_fd, STDIN_FILENO);
|
||||
execl ("/bin/sh", "/bin/sh", "-c", get_config_string
|
||||
(ctx->config.root, "behaviour.backlog_helper"), NULL);
|
||||
print_error ("%s: %s",
|
||||
"Failed to launch backlog helper", strerror (errno));
|
||||
_exit (EXIT_FAILURE);
|
||||
case -1:
|
||||
log_global_error (ctx, "#s: #l",
|
||||
"Failed to launch backlog helper", strerror (errno));
|
||||
break;
|
||||
default:
|
||||
ctx->running_backlog_helper = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
on_display_backlog (int count, int key, void *user_data)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
struct app_context *ctx = user_data;
|
||||
|
||||
FILE *backlog = tmpfile ();
|
||||
if (!backlog)
|
||||
{
|
||||
log_global_error (ctx, "#s: #l",
|
||||
"Failed to create a temporary file", strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
for (struct buffer_line *line = ctx->current_buffer->lines;
|
||||
line; line = line->next)
|
||||
buffer_line_write_to_backlog (ctx, line, backlog);
|
||||
|
||||
rewind (backlog);
|
||||
set_cloexec (fileno (backlog));
|
||||
launch_backlog_helper (ctx, fileno (backlog));
|
||||
fclose (backlog);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
on_display_full_log (int count, int key, void *user_data)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
struct app_context *ctx = user_data;
|
||||
|
||||
char *path = buffer_get_log_path (ctx->current_buffer);
|
||||
FILE *full_log = fopen (path, "rb");
|
||||
free (path);
|
||||
|
||||
if (!full_log)
|
||||
{
|
||||
log_global_error (ctx, "Failed to open log file for #s: #l",
|
||||
ctx->current_buffer->name, strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctx->current_buffer->log_file)
|
||||
fflush (ctx->current_buffer->log_file);
|
||||
|
||||
set_cloexec (fileno (full_log));
|
||||
launch_backlog_helper (ctx, fileno (full_log));
|
||||
fclose (full_log);
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static bool
|
||||
on_goto_buffer (int count, int key, void *user_data)
|
||||
{
|
||||
(void) count;
|
||||
struct app_context *ctx = user_data;
|
||||
|
||||
int n = key - '0';
|
||||
if (n < 0 || n > 9)
|
||||
return false;
|
||||
|
||||
// There's no buffer zero
|
||||
if (n == 0)
|
||||
n = 10;
|
||||
|
||||
if (!ctx->last_buffer || buffer_get_index (ctx, ctx->current_buffer) != n)
|
||||
return buffer_goto (ctx, n);
|
||||
|
||||
// Fast switching between two buffers
|
||||
buffer_activate (ctx, ctx->last_buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
on_previous_buffer (int count, int key, void *user_data)
|
||||
{
|
||||
(void) key;
|
||||
buffer_activate (user_data, buffer_previous (user_data, count));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
on_next_buffer (int count, int key, void *user_data)
|
||||
{
|
||||
(void) key;
|
||||
buffer_activate (user_data, buffer_next (user_data, count));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
on_switch_buffer (int count, int key, void *user_data)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
struct app_context *ctx = user_data;
|
||||
|
||||
if (!ctx->last_buffer)
|
||||
return false;
|
||||
buffer_activate (ctx, ctx->last_buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
on_redraw_screen (int count, int key, void *user_data)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
|
||||
redraw_screen (user_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
on_insert_attribute (int count, int key, void *user_data)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = user_data;
|
||||
ctx->awaiting_mirc_escape = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
on_start_paste_mode (int count, int key, void *user_data)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = user_data;
|
||||
ctx->in_bracketed_paste = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
bind_common_keys (struct app_context *ctx)
|
||||
{
|
||||
struct input *self = &ctx->input;
|
||||
#define XX(...) input_add_fn (self, __VA_ARGS__, ctx);
|
||||
XX ("previous-buffer", "Previous buffer", on_previous_buffer)
|
||||
XX ("next-buffer", "Next buffer", on_next_buffer)
|
||||
XX ("goto-buffer", "Go to buffer", on_goto_buffer)
|
||||
XX ("switch-buffer", "Switch buffer", on_switch_buffer)
|
||||
XX ("display-backlog", "Show backlog", on_display_backlog)
|
||||
XX ("display-full-log", "Show full log", on_display_full_log)
|
||||
XX ("edit-input", "Edit input", on_edit_input)
|
||||
XX ("redraw-screen", "Redraw screen", on_redraw_screen)
|
||||
XX ("insert-attribute", "mIRC formatting", on_insert_attribute)
|
||||
XX ("start-paste-mode", "Bracketed paste", on_start_paste_mode)
|
||||
#undef XX
|
||||
|
||||
input_bind_control (self, 'p', "previous-buffer");
|
||||
input_bind_control (self, 'n', "next-buffer");
|
||||
|
||||
@ -11406,12 +11615,9 @@ bind_common_keys (struct app_context *ctx)
|
||||
input_bind_meta (self, 'h', "display-full-log");
|
||||
input_bind_meta (self, 'e', "edit-input");
|
||||
|
||||
if (key_f5)
|
||||
input_bind (self, key_f5, "previous-buffer");
|
||||
if (key_f6)
|
||||
input_bind (self, key_f6, "next-buffer");
|
||||
if (key_ppage)
|
||||
input_bind (self, key_ppage, "display-backlog");
|
||||
if (key_f5) input_bind (self, key_f5, "previous-buffer");
|
||||
if (key_f6) input_bind (self, key_f6, "next-buffer");
|
||||
if (key_ppage) input_bind (self, key_ppage, "display-backlog");
|
||||
|
||||
if (clear_screen)
|
||||
input_bind_control (self, 'l', "redraw-screen");
|
||||
@ -11423,129 +11629,17 @@ bind_common_keys (struct app_context *ctx)
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
|
||||
static int
|
||||
on_readline_goto_buffer (int count, int key)
|
||||
{
|
||||
(void) count;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
if (!jump_to_buffer (ctx, UNMETA (key) - '0'))
|
||||
input_ding (&ctx->input);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
on_readline_previous_buffer (int count, int key)
|
||||
{
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
buffer_activate (ctx, buffer_previous (ctx, count));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
on_readline_next_buffer (int count, int key)
|
||||
{
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
buffer_activate (ctx, buffer_next (ctx, count));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
on_readline_switch_buffer (int count, int key)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
if (ctx->last_buffer)
|
||||
buffer_activate (ctx, ctx->last_buffer);
|
||||
else
|
||||
input_ding (&ctx->input);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
on_readline_display_backlog (int count, int key)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
display_backlog (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
on_readline_display_full_log (int count, int key)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
display_full_log (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
on_readline_edit_input (int count, int key)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
launch_input_editor (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
on_readline_redraw_screen (int count, int key)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
redraw_screen (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
on_readline_insert_attribute (int count, int key)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
ctx->awaiting_mirc_escape = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
on_readline_start_paste_mode (int count, int key)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
ctx->in_bracketed_paste = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
on_readline_return (int count, int key)
|
||||
{
|
||||
(void) count;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
|
||||
// Let readline pass the line to our input handler
|
||||
rl_done = 1;
|
||||
|
||||
// Hide the line, don't redisplay it
|
||||
struct app_context *ctx = g_ctx;
|
||||
input_hide (&ctx->input);
|
||||
input_restore (&ctx->input);
|
||||
return 0;
|
||||
@ -11602,18 +11696,7 @@ app_readline_init (void)
|
||||
// our dear user could potentionally rig things up in a way that might
|
||||
// result in some funny unspecified behaviour
|
||||
|
||||
rl_add_defun ("previous-buffer", on_readline_previous_buffer, -1);
|
||||
rl_add_defun ("next-buffer", on_readline_next_buffer, -1);
|
||||
rl_add_defun ("goto-buffer", on_readline_goto_buffer, -1);
|
||||
rl_add_defun ("switch-buffer", on_readline_switch_buffer, -1);
|
||||
rl_add_defun ("display-backlog", on_readline_display_backlog, -1);
|
||||
rl_add_defun ("display-full-log", on_readline_display_full_log, -1);
|
||||
rl_add_defun ("edit-input", on_readline_edit_input, -1);
|
||||
rl_add_defun ("redraw-screen", on_readline_redraw_screen, -1);
|
||||
rl_add_defun ("insert-attribute", on_readline_insert_attribute, -1);
|
||||
rl_add_defun ("start-paste-mode", on_readline_start_paste_mode, -1);
|
||||
rl_add_defun ("send-line", on_readline_return, -1);
|
||||
|
||||
bind_common_keys (ctx);
|
||||
|
||||
// Move native history commands
|
||||
@ -11636,113 +11719,6 @@ app_readline_init (void)
|
||||
|
||||
#ifdef HAVE_EDITLINE
|
||||
|
||||
static unsigned char
|
||||
on_editline_goto_buffer (EditLine *editline, int key)
|
||||
{
|
||||
(void) editline;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
if (!jump_to_buffer (ctx, key - '0'))
|
||||
return CC_ERROR;
|
||||
return CC_NORM;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
on_editline_previous_buffer (EditLine *editline, int key)
|
||||
{
|
||||
(void) editline;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
buffer_activate (ctx, buffer_previous (ctx, 1));
|
||||
return CC_NORM;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
on_editline_next_buffer (EditLine *editline, int key)
|
||||
{
|
||||
(void) editline;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
buffer_activate (ctx, buffer_next (ctx, 1));
|
||||
return CC_NORM;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
on_editline_switch_buffer (EditLine *editline, int key)
|
||||
{
|
||||
(void) editline;
|
||||
(void) key;
|
||||
|
||||
struct app_context *ctx = g_ctx;
|
||||
if (ctx->last_buffer)
|
||||
buffer_activate (ctx, ctx->last_buffer);
|
||||
else
|
||||
input_ding (&ctx->input);
|
||||
return CC_NORM;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
on_editline_display_backlog (EditLine *editline, int key)
|
||||
{
|
||||
(void) editline;
|
||||
(void) key;
|
||||
|
||||
display_backlog (g_ctx);
|
||||
return CC_NORM;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
on_editline_display_full_log (EditLine *editline, int key)
|
||||
{
|
||||
(void) editline;
|
||||
(void) key;
|
||||
|
||||
display_full_log (g_ctx);
|
||||
return CC_NORM;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
on_editline_edit_input (EditLine *editline, int key)
|
||||
{
|
||||
(void) editline;
|
||||
(void) key;
|
||||
|
||||
launch_input_editor (g_ctx);
|
||||
return CC_NORM;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
on_editline_redraw_screen (EditLine *editline, int key)
|
||||
{
|
||||
(void) editline;
|
||||
(void) key;
|
||||
|
||||
redraw_screen (g_ctx);
|
||||
return CC_NORM;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
on_editline_insert_attribute (EditLine *editline, int key)
|
||||
{
|
||||
(void) editline;
|
||||
(void) key;
|
||||
|
||||
g_ctx->awaiting_mirc_escape = true;
|
||||
return CC_NORM;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
on_editline_start_paste_mode (EditLine *editline, int key)
|
||||
{
|
||||
(void) editline;
|
||||
(void) key;
|
||||
|
||||
g_ctx->in_bracketed_paste = true;
|
||||
return CC_NORM;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
on_editline_complete (EditLine *editline, int key)
|
||||
{
|
||||
@ -11831,29 +11807,11 @@ on_editline_return (EditLine *editline, int key)
|
||||
static void
|
||||
app_editline_init (struct input *self)
|
||||
{
|
||||
#define XX(name, help, fn) { name, help, on_editline_ ## fn },
|
||||
|
||||
// el_set() leaks memory in 20150325 and other versions, we need wchar_t
|
||||
static const struct { const wchar_t *name; const wchar_t *help;
|
||||
unsigned char (*func) (EditLine *, int); } x[] =
|
||||
{
|
||||
XX( L"goto-buffer", L"Go to buffer", goto_buffer )
|
||||
XX( L"previous-buffer", L"Previous buffer", previous_buffer )
|
||||
XX( L"next-buffer", L"Next buffer", next_buffer )
|
||||
XX( L"switch-buffer", L"Switch buffer", switch_buffer )
|
||||
XX( L"display-backlog", L"Show backlog", display_backlog )
|
||||
XX( L"display-full-log", L"Show full log", display_full_log )
|
||||
XX( L"edit-input", L"Edit input", edit_input )
|
||||
XX( L"redraw-screen", L"Redraw screen", redraw_screen )
|
||||
XX( L"insert-attribute", L"mIRC formatting", insert_attribute )
|
||||
XX( L"start-paste-mode", L"Bracketed paste", start_paste_mode )
|
||||
XX( L"send-line", L"Send line", return )
|
||||
XX( L"complete", L"Complete word", complete )
|
||||
};
|
||||
for (size_t i = 0; i < N_ELEMENTS (x); i++)
|
||||
el_wset (self->editline, EL_ADDFN, x[i].name, x[i].help, x[i].func);
|
||||
|
||||
#undef XX
|
||||
el_wset (self->editline, EL_ADDFN,
|
||||
L"send-line", L"Send line", on_editline_return);
|
||||
el_wset (self->editline, EL_ADDFN,
|
||||
L"complete", L"Complete word", on_editline_complete);
|
||||
|
||||
bind_common_keys (g_ctx);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user