degesch: steady progress
I'm sorry, I can't do reasonable commit messages in this stage of development. It's all a total mess slowly converging to an alpha version.
This commit is contained in:
parent
3864cca21d
commit
3df841f088
295
degesch.c
295
degesch.c
|
@ -44,11 +44,18 @@
|
||||||
|
|
||||||
#include <curses.h>
|
#include <curses.h>
|
||||||
#include <term.h>
|
#include <term.h>
|
||||||
|
|
||||||
|
// Literally cancer
|
||||||
|
#undef lines
|
||||||
|
#undef columns
|
||||||
|
|
||||||
#include <readline/readline.h>
|
#include <readline/readline.h>
|
||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
|
|
||||||
// --- Configuration (application-specific) ------------------------------------
|
// --- Configuration (application-specific) ------------------------------------
|
||||||
|
|
||||||
|
// TODO: reject all junk present in the configuration; there can be newlines
|
||||||
|
|
||||||
static struct config_item g_config_table[] =
|
static struct config_item g_config_table[] =
|
||||||
{
|
{
|
||||||
{ ATTR_PROMPT, NULL, "Terminal attributes for the prompt" },
|
{ ATTR_PROMPT, NULL, "Terminal attributes for the prompt" },
|
||||||
|
@ -81,6 +88,9 @@ static struct config_item g_config_table[] =
|
||||||
|
|
||||||
// --- Application data --------------------------------------------------------
|
// --- Application data --------------------------------------------------------
|
||||||
|
|
||||||
|
// All text stored in our data structures is encoded in UTF-8.
|
||||||
|
// Or at least should be.
|
||||||
|
|
||||||
/// Shorthand to set an error and return failure from the function
|
/// Shorthand to set an error and return failure from the function
|
||||||
#define FAIL(...) \
|
#define FAIL(...) \
|
||||||
BLOCK_START \
|
BLOCK_START \
|
||||||
|
@ -97,23 +107,47 @@ enum buffer_line_flags
|
||||||
|
|
||||||
enum buffer_line_type
|
enum buffer_line_type
|
||||||
{
|
{
|
||||||
BUFFER_LINE_TEXT, ///< PRIVMSG
|
BUFFER_LINE_PRIVMSG, ///< PRIVMSG
|
||||||
|
BUFFER_LINE_ACTION, ///< PRIVMSG ACTION
|
||||||
BUFFER_LINE_NOTICE, ///< NOTICE
|
BUFFER_LINE_NOTICE, ///< NOTICE
|
||||||
BUFFER_LINE_STATUS ///< JOIN, PART, QUIT
|
BUFFER_LINE_JOIN, ///< JOIN
|
||||||
|
BUFFER_LINE_PART, ///< PART
|
||||||
|
BUFFER_LINE_KICK, ///< KICK
|
||||||
|
BUFFER_LINE_QUIT, ///< QUIT
|
||||||
|
BUFFER_LINE_STATUS ///< Whatever status messages
|
||||||
};
|
};
|
||||||
|
|
||||||
struct buffer_line
|
struct buffer_line
|
||||||
{
|
{
|
||||||
LIST_HEADER (struct buffer_line)
|
LIST_HEADER (struct buffer_line)
|
||||||
|
|
||||||
|
// We use the "type" and "flags" mostly just as formatting hints
|
||||||
|
|
||||||
enum buffer_line_type type; ///< Type of the event
|
enum buffer_line_type type; ///< Type of the event
|
||||||
int flags; ///< Flags
|
int flags; ///< Flags
|
||||||
|
|
||||||
time_t when; ///< Time of the event
|
time_t when; ///< Time of the event
|
||||||
char *origin; ///< Name of the origin
|
char *who; ///< Name of the origin or NULL (user)
|
||||||
char *text; ///< The text of the message
|
char *object; ///< Text of message, object of action
|
||||||
|
char *reason; ///< Reason for PART, KICK, QUIT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct buffer_line *
|
||||||
|
buffer_line_new (void)
|
||||||
|
{
|
||||||
|
struct buffer_line *self = xcalloc (1, sizeof *self);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buffer_line_destroy (struct buffer_line *self)
|
||||||
|
{
|
||||||
|
free (self->who);
|
||||||
|
free (self->object);
|
||||||
|
free (self->reason);
|
||||||
|
free (self);
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
struct nick_info
|
struct nick_info
|
||||||
|
@ -143,6 +177,9 @@ enum buffer_type
|
||||||
BUFFER_PM ///< Private messages (query)
|
BUFFER_PM ///< Private messages (query)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: now I can't just print messages with print_status() etc.,
|
||||||
|
// all that stuff has to go in a buffer now
|
||||||
|
|
||||||
struct buffer
|
struct buffer
|
||||||
{
|
{
|
||||||
LIST_HEADER (struct buffer)
|
LIST_HEADER (struct buffer)
|
||||||
|
@ -150,12 +187,15 @@ struct buffer
|
||||||
enum buffer_type type; ///< Type of the buffer
|
enum buffer_type type; ///< Type of the buffer
|
||||||
char *name; ///< The name of the buffer
|
char *name; ///< The name of the buffer
|
||||||
|
|
||||||
unsigned unseen_messages; ///< # messages since last visited
|
// Buffer contents:
|
||||||
|
|
||||||
// TODO: now I can't just print messages with print_status() etc.,
|
struct buffer_line *lines; ///< All lines in this buffer
|
||||||
// all that stuff has to go into a buffer now
|
struct buffer_line *lines_tail; ///< The tail of buffer lines
|
||||||
|
unsigned lines_count; ///< How many lines we have
|
||||||
|
|
||||||
// Channels:
|
unsigned unseen_messages_count; ///< # messages since last visited
|
||||||
|
|
||||||
|
// Channel information:
|
||||||
|
|
||||||
char *topic; ///< Channel topic
|
char *topic; ///< Channel topic
|
||||||
struct str_map nicks; ///< Maps nicks to "nick_info"
|
struct str_map nicks; ///< Maps nicks to "nick_info"
|
||||||
|
@ -191,29 +231,41 @@ enum color_mode
|
||||||
|
|
||||||
struct app_context
|
struct app_context
|
||||||
{
|
{
|
||||||
|
// Configuration:
|
||||||
|
|
||||||
struct str_map config; ///< User configuration
|
struct str_map config; ///< User configuration
|
||||||
enum color_mode color_mode; ///< Colour output mode
|
enum color_mode color_mode; ///< Colour output mode
|
||||||
bool reconnect; ///< Whether to reconnect on conn. fail.
|
bool reconnect; ///< Whether to reconnect on conn. fail.
|
||||||
unsigned long reconnect_delay; ///< Reconnect delay in seconds
|
unsigned long reconnect_delay; ///< Reconnect delay in seconds
|
||||||
|
|
||||||
|
// Server connection:
|
||||||
|
|
||||||
int irc_fd; ///< Socket FD of the server
|
int irc_fd; ///< Socket FD of the server
|
||||||
struct str read_buffer; ///< Input yet to be processed
|
struct str read_buffer; ///< Input yet to be processed
|
||||||
struct poller_fd irc_event; ///< IRC FD event
|
struct poller_fd irc_event; ///< IRC FD event
|
||||||
bool irc_ready; ///< Whether we may send messages now
|
bool irc_ready; ///< Whether we may send messages now
|
||||||
|
|
||||||
|
SSL_CTX *ssl_ctx; ///< SSL context
|
||||||
|
SSL *ssl; ///< SSL connection
|
||||||
|
|
||||||
|
// Events:
|
||||||
|
|
||||||
struct poller_fd tty_event; ///< Terminal input event
|
struct poller_fd tty_event; ///< Terminal input event
|
||||||
struct poller_fd signal_event; ///< Signal FD event
|
struct poller_fd signal_event; ///< Signal FD event
|
||||||
struct poller_timer ping_tmr; ///< We should send a ping
|
struct poller_timer ping_tmr; ///< We should send a ping
|
||||||
struct poller_timer timeout_tmr; ///< Connection seems to be dead
|
struct poller_timer timeout_tmr; ///< Connection seems to be dead
|
||||||
struct poller_timer reconnect_tmr; ///< We should reconnect now
|
struct poller_timer reconnect_tmr; ///< We should reconnect now
|
||||||
|
|
||||||
SSL_CTX *ssl_ctx; ///< SSL context
|
struct poller poller; ///< Manages polled descriptors
|
||||||
SSL *ssl; ///< SSL connection
|
bool quitting; ///< User requested quitting
|
||||||
|
bool polling; ///< The event loop is running
|
||||||
|
|
||||||
|
// Buffers:
|
||||||
|
|
||||||
struct buffer *buffers; ///< All our buffers in order
|
struct buffer *buffers; ///< All our buffers in order
|
||||||
struct buffer *buffers_tail; ///< The tail of our buffers
|
struct buffer *buffers_tail; ///< The tail of our buffers
|
||||||
|
|
||||||
// TODO: a name -> buffer map that excludes GLOBAL and SERVER
|
struct str_map buffers_by_name; ///< Excludes GLOBAL and SERVER
|
||||||
struct buffer *global_buffer; ///< The global buffer
|
struct buffer *global_buffer; ///< The global buffer
|
||||||
struct buffer *server_buffer; ///< The server buffer
|
struct buffer *server_buffer; ///< The server buffer
|
||||||
|
|
||||||
|
@ -222,14 +274,16 @@ struct app_context
|
||||||
// TODO: So that we always output proper date change messages
|
// TODO: So that we always output proper date change messages
|
||||||
time_t last_displayed_msg_time; ///< Time of last displayed message
|
time_t last_displayed_msg_time; ///< Time of last displayed message
|
||||||
|
|
||||||
struct poller poller; ///< Manages polled descriptors
|
// Terminal:
|
||||||
bool quitting; ///< User requested quitting
|
|
||||||
bool polling; ///< The event loop is running
|
|
||||||
|
|
||||||
iconv_t term_to_utf8; ///< Terminal encoding to UTF-8
|
iconv_t term_to_utf8; ///< Terminal encoding to UTF-8
|
||||||
iconv_t term_from_utf8; ///< UTF-8 to terminal encoding
|
iconv_t term_from_utf8; ///< UTF-8 to terminal encoding
|
||||||
|
// XXX: shouldn't it be rather UTF-8 from Latin 1?
|
||||||
iconv_t term_from_latin1; ///< ISO Latin 1 to terminal encoding
|
iconv_t term_from_latin1; ///< ISO Latin 1 to terminal encoding
|
||||||
|
|
||||||
|
int lines; ///< Current terminal height
|
||||||
|
int columns; ///< Current ternimal width
|
||||||
|
|
||||||
char *readline_prompt; ///< The prompt we use for readline
|
char *readline_prompt; ///< The prompt we use for readline
|
||||||
bool readline_prompt_shown; ///< Whether the prompt is shown now
|
bool readline_prompt_shown; ///< Whether the prompt is shown now
|
||||||
}
|
}
|
||||||
|
@ -252,6 +306,9 @@ app_context_init (struct app_context *self)
|
||||||
str_init (&self->read_buffer);
|
str_init (&self->read_buffer);
|
||||||
self->irc_ready = false;
|
self->irc_ready = false;
|
||||||
|
|
||||||
|
str_map_init (&self->buffers_by_name);
|
||||||
|
self->buffers_by_name.key_xfrm = irc_strxfrm;
|
||||||
|
|
||||||
self->last_displayed_msg_time = time (NULL);
|
self->last_displayed_msg_time = time (NULL);
|
||||||
|
|
||||||
poller_init (&self->poller);
|
poller_init (&self->poller);
|
||||||
|
@ -291,12 +348,17 @@ app_context_free (struct app_context *self)
|
||||||
if (self->ssl_ctx)
|
if (self->ssl_ctx)
|
||||||
SSL_CTX_free (self->ssl_ctx);
|
SSL_CTX_free (self->ssl_ctx);
|
||||||
|
|
||||||
|
LIST_FOR_EACH (struct buffer, iter, self->buffers)
|
||||||
|
buffer_destroy (iter);
|
||||||
|
str_map_free (&self->buffers_by_name);
|
||||||
|
|
||||||
poller_free (&self->poller);
|
poller_free (&self->poller);
|
||||||
free (self->readline_prompt);
|
|
||||||
|
|
||||||
iconv_close (self->term_from_latin1);
|
iconv_close (self->term_from_latin1);
|
||||||
iconv_close (self->term_from_utf8);
|
iconv_close (self->term_from_utf8);
|
||||||
iconv_close (self->term_to_utf8);
|
iconv_close (self->term_to_utf8);
|
||||||
|
|
||||||
|
free (self->readline_prompt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Attributed output -------------------------------------------------------
|
// --- Attributed output -------------------------------------------------------
|
||||||
|
@ -566,14 +628,192 @@ setup_signal_handlers (void)
|
||||||
|
|
||||||
// --- Buffers -----------------------------------------------------------------
|
// --- Buffers -----------------------------------------------------------------
|
||||||
|
|
||||||
static void
|
static void buffer_send (struct app_context *ctx, struct buffer *buffer,
|
||||||
send_to_buffer (struct app_context *ctx, struct buffer *buffer,
|
enum buffer_line_type type, int flags, const char *origin,
|
||||||
enum buffer_line_type type, int flags,
|
const char *reason, const char *format, ...) ATTRIBUTE_PRINTF (7, 8);
|
||||||
const char *origin, const char *format, ...);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
prepare_buffers (struct app_context *ctx)
|
buffer_update_time (struct app_context *ctx, time_t now)
|
||||||
{
|
{
|
||||||
|
struct tm last, current;
|
||||||
|
if (!localtime_r (&ctx->last_displayed_msg_time, &last)
|
||||||
|
|| !localtime_r (&now, ¤t))
|
||||||
|
{
|
||||||
|
// Strange but nonfatal
|
||||||
|
print_error ("%s: %s", "localtime_r", strerror (errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->last_displayed_msg_time = now;
|
||||||
|
if (last.tm_year == current.tm_year
|
||||||
|
&& last.tm_mon == current.tm_mon
|
||||||
|
&& last.tm_mday == current.tm_mday)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char buf[32] = "";
|
||||||
|
if (soft_assert (strftime (buf, sizeof buf, "%F", ¤t)))
|
||||||
|
print_status ("%s", buf);
|
||||||
|
// Else the buffer was too small, which is pretty weird
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buffer_line_display (struct app_context *ctx, struct buffer_line *line)
|
||||||
|
{
|
||||||
|
// Normal timestamps don't include the date, this way the user won't be
|
||||||
|
// confused as to when an event has happened
|
||||||
|
buffer_update_time (ctx, line->when);
|
||||||
|
|
||||||
|
struct str text;
|
||||||
|
str_init (&text);
|
||||||
|
|
||||||
|
struct tm current;
|
||||||
|
if (!localtime_r (&line->when, ¤t))
|
||||||
|
print_error ("%s: %s", "localtime_r", strerror (errno));
|
||||||
|
else
|
||||||
|
str_append_printf (&text, "%02d:%02d:%02d ",
|
||||||
|
current.tm_hour, current.tm_min, current.tm_sec);
|
||||||
|
|
||||||
|
char *who = iconv_xstrdup (ctx->term_from_utf8, line->who, -1, NULL);
|
||||||
|
char *object = iconv_xstrdup (ctx->term_from_utf8, line->object, -1, NULL);
|
||||||
|
char *reason = iconv_xstrdup (ctx->term_from_utf8, line->reason, -1, NULL);
|
||||||
|
|
||||||
|
switch (line->type)
|
||||||
|
{
|
||||||
|
case BUFFER_LINE_PRIVMSG:
|
||||||
|
str_append_printf (&text, "<%s> %s", who, object);
|
||||||
|
break;
|
||||||
|
case BUFFER_LINE_ACTION:
|
||||||
|
str_append_printf (&text, " * %s %s", who, object);
|
||||||
|
break;
|
||||||
|
case BUFFER_LINE_NOTICE:
|
||||||
|
str_append_printf (&text, " - Notice(%s): %s", who, object);
|
||||||
|
break;
|
||||||
|
case BUFFER_LINE_JOIN:
|
||||||
|
if (who)
|
||||||
|
str_append_printf (&text, "--> %s has joined %s", who, object);
|
||||||
|
else
|
||||||
|
str_append_printf (&text, "--> You have joined %s", object);
|
||||||
|
break;
|
||||||
|
case BUFFER_LINE_PART:
|
||||||
|
if (who)
|
||||||
|
str_append_printf (&text, "<-- %s has left %s (%s)",
|
||||||
|
who, object, reason);
|
||||||
|
else
|
||||||
|
str_append_printf (&text, "<-- You have left %s (%s)",
|
||||||
|
object, reason);
|
||||||
|
break;
|
||||||
|
case BUFFER_LINE_KICK:
|
||||||
|
if (who)
|
||||||
|
str_append_printf (&text, "<-- %s has kicked %s (%s)",
|
||||||
|
who, object, reason);
|
||||||
|
else
|
||||||
|
str_append_printf (&text, "<-- You have kicked %s (%s)",
|
||||||
|
object, reason);
|
||||||
|
break;
|
||||||
|
case BUFFER_LINE_QUIT:
|
||||||
|
if (who)
|
||||||
|
str_append_printf (&text, "<-- %s has quit (%s)", who, reason);
|
||||||
|
else
|
||||||
|
str_append_printf (&text, "<-- You have quit (%s)", reason);
|
||||||
|
break;
|
||||||
|
case BUFFER_LINE_STATUS:
|
||||||
|
str_append_printf (&text, " - %s", object);
|
||||||
|
}
|
||||||
|
|
||||||
|
free (who);
|
||||||
|
free (object);
|
||||||
|
free (reason);
|
||||||
|
|
||||||
|
// TODO: hide readline if needed
|
||||||
|
|
||||||
|
printf ("%s\n", text.str);
|
||||||
|
str_free (&text);
|
||||||
|
|
||||||
|
// TODO: unhide readline if hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buffer_send (struct app_context *ctx, struct buffer *buffer,
|
||||||
|
enum buffer_line_type type, int flags,
|
||||||
|
const char *origin, const char *reason, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start (ap, format);
|
||||||
|
struct str text;
|
||||||
|
str_init (&text);
|
||||||
|
str_append_vprintf (&text, format, ap);
|
||||||
|
va_end (ap);
|
||||||
|
|
||||||
|
struct buffer_line *line = buffer_line_new ();
|
||||||
|
line->type = type;
|
||||||
|
line->flags = flags;
|
||||||
|
line->when = time (NULL);
|
||||||
|
line->who = xstrdup (origin);
|
||||||
|
line->object = str_steal (&text);
|
||||||
|
line->reason = xstrdup (reason);
|
||||||
|
|
||||||
|
LIST_APPEND_WITH_TAIL (buffer->lines, buffer->lines_tail, line);
|
||||||
|
buffer->lines_count++;
|
||||||
|
|
||||||
|
if (buffer == ctx->current_buffer)
|
||||||
|
buffer_line_display (ctx, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct buffer *
|
||||||
|
buffer_by_name (struct app_context *ctx, const char *name)
|
||||||
|
{
|
||||||
|
return str_map_find (&ctx->buffers_by_name, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buffer_add (struct app_context *ctx, struct buffer *buffer)
|
||||||
|
{
|
||||||
|
hard_assert (!buffer_by_name (ctx, buffer->name));
|
||||||
|
|
||||||
|
str_map_set (&ctx->buffers_by_name, buffer->name, buffer);
|
||||||
|
LIST_APPEND_WITH_TAIL (ctx->buffers, ctx->buffers_tail, buffer);
|
||||||
|
|
||||||
|
// TODO: refresh the prompt?
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buffer_remove (struct app_context *ctx, struct buffer *buffer)
|
||||||
|
{
|
||||||
|
hard_assert (buffer != ctx->current_buffer);
|
||||||
|
|
||||||
|
str_map_set (&ctx->buffers_by_name, buffer->name, NULL);
|
||||||
|
LIST_UNLINK_WITH_TAIL (ctx->buffers, ctx->buffers_tail, buffer);
|
||||||
|
buffer_destroy (buffer);
|
||||||
|
|
||||||
|
// It's not a good idea to remove these buffers, but it's even a worse
|
||||||
|
// one to leave the pointers point to invalid memory
|
||||||
|
if (buffer == ctx->global_buffer)
|
||||||
|
ctx->global_buffer = NULL;
|
||||||
|
if (buffer == ctx->server_buffer)
|
||||||
|
ctx->server_buffer = NULL;
|
||||||
|
|
||||||
|
// TODO: refresh the prompt?
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
buffer_activate (struct app_context *ctx, struct buffer *buffer)
|
||||||
|
{
|
||||||
|
ctx->current_buffer = buffer;
|
||||||
|
print_status ("%s", buffer->name);
|
||||||
|
|
||||||
|
// That is, minus the buffer switch line and the readline prompt
|
||||||
|
int to_display = ctx->lines - 2;
|
||||||
|
// TODO: find the to_display-th line from the back
|
||||||
|
// TODO: print all the lines in order
|
||||||
|
|
||||||
|
// TODO: switch readline history stack
|
||||||
|
// TODO: refresh the prompt?
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_buffers (struct app_context *ctx)
|
||||||
|
{
|
||||||
|
// At the moment we have only two global everpresent buffers
|
||||||
struct buffer *global = ctx->global_buffer = buffer_new ();
|
struct buffer *global = ctx->global_buffer = buffer_new ();
|
||||||
struct buffer *server = ctx->server_buffer = buffer_new ();
|
struct buffer *server = ctx->server_buffer = buffer_new ();
|
||||||
|
|
||||||
|
@ -1348,10 +1588,13 @@ on_signal_pipe_readable (const struct pollfd *fd, struct app_context *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_winch_received)
|
if (g_winch_received)
|
||||||
|
{
|
||||||
// This fucks up big time on terminals with automatic wrapping such as
|
// This fucks up big time on terminals with automatic wrapping such as
|
||||||
// rxvt-unicode or newer VTE when the current line overflows, however we
|
// rxvt-unicode or newer VTE when the current line overflows, however we
|
||||||
// can't do much about that
|
// can't do much about that
|
||||||
rl_resize_terminal ();
|
rl_resize_terminal ();
|
||||||
|
rl_get_screen_size (&ctx->lines, &ctx->columns);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1657,9 +1900,14 @@ main (int argc, char *argv[])
|
||||||
using_history ();
|
using_history ();
|
||||||
stifle_history (HISTORY_LIMIT);
|
stifle_history (HISTORY_LIMIT);
|
||||||
|
|
||||||
|
setup_signal_handlers ();
|
||||||
|
|
||||||
init_colors (&ctx);
|
init_colors (&ctx);
|
||||||
init_poller_events (&ctx);
|
init_poller_events (&ctx);
|
||||||
|
init_buffers (&ctx);
|
||||||
|
refresh_prompt (&ctx);
|
||||||
|
|
||||||
|
// TODO: connect asynchronously (first step towards multiple servers)
|
||||||
struct error *e = NULL;
|
struct error *e = NULL;
|
||||||
if (!load_config (&ctx, &e)
|
if (!load_config (&ctx, &e)
|
||||||
|| !irc_connect (&ctx, &e))
|
|| !irc_connect (&ctx, &e))
|
||||||
|
@ -1669,10 +1917,6 @@ main (int argc, char *argv[])
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_signal_handlers ();
|
|
||||||
prepare_buffers (&ctx);
|
|
||||||
refresh_prompt (&ctx);
|
|
||||||
|
|
||||||
// TODO: maybe use rl_make_bare_keymap() and start from there
|
// TODO: maybe use rl_make_bare_keymap() and start from there
|
||||||
|
|
||||||
// XXX: Since readline() installs a set of default key bindings the first
|
// XXX: Since readline() installs a set of default key bindings the first
|
||||||
|
@ -1690,8 +1934,9 @@ main (int argc, char *argv[])
|
||||||
rl_bind_keyseq ("M-n", rl_named_function ("next-history"));
|
rl_bind_keyseq ("M-n", rl_named_function ("next-history"));
|
||||||
|
|
||||||
rl_catch_sigwinch = false;
|
rl_catch_sigwinch = false;
|
||||||
ctx.readline_prompt_shown = true;
|
|
||||||
rl_callback_handler_install (ctx.readline_prompt, on_readline_input);
|
rl_callback_handler_install (ctx.readline_prompt, on_readline_input);
|
||||||
|
rl_get_screen_size (&ctx.lines, &ctx.columns);
|
||||||
|
ctx.readline_prompt_shown = true;
|
||||||
|
|
||||||
ctx.polling = true;
|
ctx.polling = true;
|
||||||
while (ctx.polling)
|
while (ctx.polling)
|
||||||
|
|
Loading…
Reference in New Issue