1
0
Fork 0

make lines reformattable

- completely removed the old textbuffer representation (
  https://github.com/shabble/irssi-docs/wiki/Notes-256-Colour#textbuffer-encoding
  )

- textbuffer-formats is an extra module, so if we unhook the signals it
  should go back to the "old way" of storing pre-rendered tex

- design uses cache, original formats and list of arguments
This commit is contained in:
ailin-nemui 2019-08-13 14:59:30 +02:00
parent 94ae7f9cd3
commit f95fc81130
21 changed files with 791 additions and 589 deletions

View File

@ -6,6 +6,7 @@
difficult message leveling system (which might be done if really
needed..). */
/* clang-format off */
/* Message levels */
enum {
MSGLEVEL_CRAP = 0x0000001,
@ -38,8 +39,12 @@ enum {
MSGLEVEL_NEVER = 0x4000000, /* never ignore / never log */
MSGLEVEL_LASTLOG = 0x8000000, /* used for /lastlog */
MSGLEVEL_HIDDEN = 0x10000000 /* Hidden from view */
MSGLEVEL_HIDDEN = 0x10000000, /* Hidden from view */
MSGLEVEL_RESERVED1 = 0x20000000,
MSGLEVEL_RESERVED2 = 0x40000000,
MSGLEVEL_FORMAT = 0x80000000 /* Format data */
};
/* clang-format on */
int level_get(const char *level);
int level2bits(const char *level, int *errorp);

View File

@ -233,6 +233,7 @@ static void event_command(const char *data)
(data[1] == *cmdchar && data[2] == '^'))
&& !command_hide_output++) {
signal_add_first("print starting", (SIGNAL_FUNC) sig_stop);
signal_add_first("print noformat", (SIGNAL_FUNC) sig_stop);
signal_add_first("print format", (SIGNAL_FUNC) sig_stop);
signal_add_first("print text", (SIGNAL_FUNC) sig_stop);
}
@ -242,6 +243,7 @@ static void event_command_last(const char *data)
{
if (command_hide_output && !--command_hide_output) {
signal_remove("print starting", (SIGNAL_FUNC) sig_stop);
signal_remove("print noformat", (SIGNAL_FUNC) sig_stop);
signal_remove("print format", (SIGNAL_FUNC) sig_stop);
signal_remove("print text", (SIGNAL_FUNC) sig_stop);
}

View File

@ -850,14 +850,13 @@ char *format_get_line_start(THEME_REC *theme, TEXT_DEST_REC *dest, time_t t)
return linestart;
}
void format_newline(WINDOW_REC *window)
void format_newline(TEXT_DEST_REC *dest)
{
g_return_if_fail(window != NULL);
g_return_if_fail(dest != NULL);
g_return_if_fail(dest->window != NULL);
signal_emit_id(signal_gui_print_text, 6, window,
GINT_TO_POINTER(-1), GINT_TO_POINTER(-1),
GINT_TO_POINTER(GUI_PRINT_FLAG_NEWLINE),
"", NULL);
signal_emit_id(signal_gui_print_text, 6, dest->window, GINT_TO_POINTER(-1),
GINT_TO_POINTER(-1), GINT_TO_POINTER(GUI_PRINT_FLAG_NEWLINE), "", dest);
}
#ifndef TERM_TRUECOLOR
@ -1269,7 +1268,7 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text)
}
if (type == '\n') {
format_newline(dest->window);
format_newline(dest);
fgcolor = theme->default_color;
bgcolor = -1;
flags &= GUI_PRINT_FLAG_INDENT|GUI_PRINT_FLAG_MONOSPACE;
@ -1415,6 +1414,90 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text)
g_free(dup);
}
void format_gui_flags(GString *out, int *last_fg, int *last_bg, int *last_flags, int fg, int bg,
int flags)
{
if (fg != *last_fg ||
(flags & GUI_PRINT_FLAG_COLOR_24_FG) != (*last_flags & GUI_PRINT_FLAG_COLOR_24_FG)) {
*last_fg = fg;
#ifdef TERM_TRUECOLOR
if (flags & GUI_PRINT_FLAG_COLOR_24_FG) {
*last_flags |= GUI_PRINT_FLAG_COLOR_24_FG;
format_24bit_color(out, 0, fg);
} else {
*last_flags &= ~GUI_PRINT_FLAG_COLOR_24_FG;
#endif
if (fg < 0) {
g_string_append_c(out, 4);
g_string_append_c(out, (char) -1);
g_string_append_c(out, FORMAT_COLOR_NOCHANGE);
} else {
format_ext_color(out, 0, fg);
}
#ifdef TERM_TRUECOLOR
}
#endif
}
if (bg != *last_bg ||
(flags & GUI_PRINT_FLAG_COLOR_24_BG) != (*last_flags & GUI_PRINT_FLAG_COLOR_24_BG)) {
*last_bg = bg;
#ifdef TERM_TRUECOLOR
if (flags & GUI_PRINT_FLAG_COLOR_24_BG) {
*last_flags |= GUI_PRINT_FLAG_COLOR_24_BG;
format_24bit_color(out, 1, bg);
} else {
*last_flags &= ~GUI_PRINT_FLAG_COLOR_24_BG;
#endif
if (bg < 0) {
g_string_append_c(out, 4);
g_string_append_c(out, FORMAT_COLOR_NOCHANGE);
g_string_append_c(out, (char) -1);
} else {
format_ext_color(out, 1, bg);
}
#ifdef TERM_TRUECOLOR
}
#endif
}
if ((flags & GUI_PRINT_FLAG_UNDERLINE) != (*last_flags & GUI_PRINT_FLAG_UNDERLINE)) {
*last_flags ^= GUI_PRINT_FLAG_UNDERLINE;
g_string_append_c(out, 4);
g_string_append_c(out, FORMAT_STYLE_UNDERLINE);
}
if ((flags & GUI_PRINT_FLAG_REVERSE) != (*last_flags & GUI_PRINT_FLAG_REVERSE)) {
*last_flags ^= GUI_PRINT_FLAG_REVERSE;
g_string_append_c(out, 4);
g_string_append_c(out, FORMAT_STYLE_REVERSE);
}
if ((flags & GUI_PRINT_FLAG_BLINK) != (*last_flags & GUI_PRINT_FLAG_BLINK)) {
*last_flags ^= GUI_PRINT_FLAG_BLINK;
g_string_append_c(out, 4);
g_string_append_c(out, FORMAT_STYLE_BLINK);
}
if ((flags & GUI_PRINT_FLAG_BOLD) != (*last_flags & GUI_PRINT_FLAG_BOLD)) {
*last_flags ^= GUI_PRINT_FLAG_BOLD;
g_string_append_c(out, 4);
g_string_append_c(out, FORMAT_STYLE_BOLD);
}
if ((flags & GUI_PRINT_FLAG_ITALIC) != (*last_flags & GUI_PRINT_FLAG_ITALIC)) {
*last_flags ^= GUI_PRINT_FLAG_ITALIC;
g_string_append_c(out, 4);
g_string_append_c(out, FORMAT_STYLE_ITALIC);
}
if ((flags & GUI_PRINT_FLAG_MONOSPACE) != (*last_flags & GUI_PRINT_FLAG_MONOSPACE)) {
*last_flags ^= GUI_PRINT_FLAG_MONOSPACE;
g_string_append_c(out, 4);
g_string_append_c(out, FORMAT_STYLE_MONOSPACE);
}
if (flags & GUI_PRINT_FLAG_INDENT) {
*last_flags ^= GUI_PRINT_FLAG_INDENT;
g_string_append_c(out, 4);
g_string_append_c(out, FORMAT_STYLE_INDENT);
}
}
static void read_settings(void)
{
timestamp_level = settings_get_bool("timestamps") ? MSGLEVEL_ALL : 0;

View File

@ -35,6 +35,7 @@ struct _FORMAT_REC {
int paramtypes[MAX_FORMAT_PARAMS];
};
/* clang-format off */
#define PRINT_FLAG_SET_LINE_START 0x0001
#define PRINT_FLAG_SET_LINE_START_IRSSI 0x0002
#define PRINT_FLAG_UNSET_LINE_START 0x0040
@ -45,6 +46,9 @@ struct _FORMAT_REC {
#define PRINT_FLAG_SET_SERVERTAG 0x0010
#define PRINT_FLAG_UNSET_SERVERTAG 0x0020
#define PRINT_FLAG_FORMAT 0x0080
/* clang-format on */
typedef struct _HILIGHT_REC HILIGHT_REC;
typedef struct _TEXT_DEST_REC {
@ -113,7 +117,7 @@ void format_create_dest_tag(TEXT_DEST_REC *dest, void *server,
const char *server_tag, const char *target,
int level, WINDOW_REC *window);
void format_newline(WINDOW_REC *window);
void format_newline(TEXT_DEST_REC *dest);
/* Return how many characters in `str' must be skipped before `len'
characters of text is skipped. */
@ -151,6 +155,8 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text);
int format_expand_styles(GString *out, const char **format, int *flags);
void format_ext_color(GString *out, int bg, int color);
void format_24bit_color(GString *out, int bg, unsigned int color);
void format_gui_flags(GString *out, int *last_fg, int *last_bg, int *last_flags, int fg, int bg,
int flags);
void formats_init(void);
void formats_deinit(void);

View File

@ -42,7 +42,7 @@ static int signal_print_noformat;
static int sending_print_starting;
static void print_line(TEXT_DEST_REC *dest, const char *text);
static void print_line(TEXT_DEST_REC *dest, const char *text, int formatted);
void printformat_module_dest_args(const char *module, TEXT_DEST_REC *dest,
int formatnum, va_list va)
@ -63,7 +63,6 @@ void printformat_module_dest_charargs(const char *module, TEXT_DEST_REC *dest,
int formatnum, char **arglist)
{
THEME_REC *theme;
char *str;
theme = window_get_theme(dest->window);
@ -75,11 +74,6 @@ void printformat_module_dest_charargs(const char *module, TEXT_DEST_REC *dest,
signal_emit_id(signal_print_format, 5, theme, module,
dest, GINT_TO_POINTER(formatnum), arglist);
str = format_get_text_theme_charargs(theme, module, dest,
formatnum, arglist);
if (str != NULL && *str != '\0') print_line(dest, str);
g_free(str);
}
void printformat_module_dest(const char *module, TEXT_DEST_REC *dest,
@ -164,29 +158,6 @@ void printformat_module_gui(const char *module, int formatnum, ...)
va_end(va);
}
static void print_line(TEXT_DEST_REC *dest, const char *text)
{
THEME_REC *theme;
char *str, *tmp, *stripped;
g_return_if_fail(dest != NULL);
g_return_if_fail(text != NULL);
theme = window_get_theme(dest->window);
tmp = format_get_level_tag(theme, dest);
str = !theme->info_eol ? format_add_linestart(text, tmp) :
format_add_lineend(text, tmp);
g_free_not_null(tmp);
/* send both the formatted + stripped (for logging etc.) */
stripped = strip_codes(str);
signal_emit_id(signal_print_text, 3, dest, str, stripped);
g_free_and_null(dest->hilight_color);
g_free(str);
g_free(stripped);
}
/* append string to `out', expand newlines. */
static void printtext_append_str(TEXT_DEST_REC *dest, GString *out,
const char *str)
@ -195,7 +166,7 @@ static void printtext_append_str(TEXT_DEST_REC *dest, GString *out,
if (*str != '\n')
g_string_append_c(out, *str);
else {
print_line(dest, out->str);
print_line(dest, out->str, 0);
g_string_truncate(out, 0);
}
str++;
@ -314,9 +285,7 @@ static void printtext_dest_args(TEXT_DEST_REC *dest, const char *text, va_list v
}
str = printtext_get_args(dest, text, va);
signal_emit_id(signal_print_noformat, 2,
dest, str);
print_line(dest, str);
print_line(dest, str, 0);
g_free(str);
}
@ -361,8 +330,8 @@ void printtext_string(void *server, const char *target, int level, const char *t
}
str = printtext_expand_formats(text, &dest.flags);
print_line(&dest, str);
g_free(str);
print_line(&dest, str, 0);
g_free(str);
}
/* Like printtext_window(), but don't handle %s etc. */
@ -383,8 +352,8 @@ void printtext_string_window(WINDOW_REC *window, int level, const char *text)
}
str = printtext_expand_formats(text, &dest.flags);
print_line(&dest, str);
g_free(str);
print_line(&dest, str, 0);
g_free(str);
}
void printtext_window(WINDOW_REC *window, int level, const char *text, ...)
@ -476,6 +445,51 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text)
signal_emit_id(signal_gui_print_text_finished, 1, dest->window);
}
static void sig_print_format(THEME_REC *theme, const char *module, TEXT_DEST_REC *dest,
void *formatnump, char **arglist)
{
int formatnum;
char *str;
formatnum = GPOINTER_TO_INT(formatnump);
str = format_get_text_theme_charargs(theme, module, dest, formatnum, arglist);
if (str != NULL && *str != '\0')
print_line(dest, str, 1);
g_free(str);
}
static void sig_print_noformat(TEXT_DEST_REC *dest, const char *text)
{
THEME_REC *theme;
char *str, *tmp, *stripped;
theme = window_get_theme(dest->window);
tmp = format_get_level_tag(theme, dest);
str = !theme->info_eol ? format_add_linestart(text, tmp) : format_add_lineend(text, tmp);
g_free_not_null(tmp);
/* send both the formatted + stripped (for logging etc.) */
stripped = strip_codes(str);
signal_emit_id(signal_print_text, 3, dest, str, stripped);
g_free_and_null(dest->hilight_color);
g_free(str);
g_free(stripped);
}
static void print_line(TEXT_DEST_REC *dest, const char *text, int formatted)
{
g_return_if_fail(dest != NULL);
g_return_if_fail(text != NULL);
if (!formatted)
signal_emit_id(signal_print_noformat, 2, dest, text);
else
sig_print_noformat(dest, text);
}
void printtext_multiline(void *server, const char *target, int level,
const char *format, const char *text)
{
@ -522,6 +536,8 @@ void printtext_init(void)
read_settings();
signal_add("print text", (SIGNAL_FUNC) sig_print_text);
signal_add("print format", (SIGNAL_FUNC) sig_print_format);
signal_add("print noformat", (SIGNAL_FUNC) sig_print_noformat);
signal_add("gui dialog", (SIGNAL_FUNC) sig_gui_dialog);
signal_add("setup changed", (SIGNAL_FUNC) read_settings);
}
@ -529,6 +545,8 @@ void printtext_init(void)
void printtext_deinit(void)
{
signal_remove("print text", (SIGNAL_FUNC) sig_print_text);
signal_remove("print format", (SIGNAL_FUNC) sig_print_format);
signal_remove("print noformat", (SIGNAL_FUNC) sig_print_noformat);
signal_remove("gui dialog", (SIGNAL_FUNC) sig_gui_dialog);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
}

View File

@ -45,6 +45,7 @@ irssi_SOURCES = \
textbuffer.c \
textbuffer-commands.c \
textbuffer-view.c \
textbuffer-formats.c \
irssi.c \
module-formats.c
@ -57,7 +58,8 @@ pkginc_fe_text_HEADERS = \
statusbar-item.h \
term.h \
textbuffer.h \
textbuffer-view.h
textbuffer-view.h \
textbuffer-formats.h
noinst_HEADERS = \
gui-entry.h \

View File

@ -19,8 +19,9 @@
*/
#include "module.h"
#include <irssi/src/core/signals.h>
#include <irssi/src/core/levels.h>
#include <irssi/src/core/settings.h>
#include <irssi/src/core/signals.h>
#include <irssi/src/fe-common/core/formats.h>
#include <irssi/src/fe-common/core/printtext.h>
@ -329,7 +330,7 @@ static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor,
GUI_WINDOW_REC *gui;
TEXT_BUFFER_VIEW_REC *view;
LINE_REC *insert_after;
LINE_INFO_REC lineinfo;
LINE_INFO_REC lineinfo = { 0 };
int fg, bg, flags, attr;
flags = GPOINTER_TO_INT(pflags);
@ -342,10 +343,16 @@ static void sig_gui_print_text(WINDOW_REC *window, void *fgcolor,
return;
}
if (dest != NULL && dest->flags & PRINT_FLAG_FORMAT) {
return;
}
lineinfo.level = dest == NULL ? 0 : dest->level;
gui = WINDOW_GUI(window);
lineinfo.time = (gui->use_insert_after && gui->insert_after_time) ?
gui->insert_after_time : time(NULL);
lineinfo.format =
dest != NULL && dest->flags & PRINT_FLAG_FORMAT ? LINE_INFO_FORMAT_SET : NULL;
view = gui->view;
insert_after = gui->use_insert_after ?
@ -378,7 +385,8 @@ static void sig_gui_printtext_finished(WINDOW_REC *window)
insert_after = WINDOW_GUI(window)->use_insert_after ?
WINDOW_GUI(window)->insert_after : view->buffer->cur_line;
view_add_eol(view, &insert_after);
if (insert_after != NULL)
view_add_eol(view, &insert_after);
remove_old_lines(view);
}

View File

@ -43,10 +43,9 @@ static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window,
gui = g_new0(GUI_WINDOW_REC, 1);
gui->parent = parent;
gui->view = textbuffer_view_create(textbuffer_create(),
window->width, window->height,
settings_get_bool("scroll"),
term_type == TERM_TYPE_UTF8);
gui->view =
textbuffer_view_create(textbuffer_create(window), window->width, window->height,
settings_get_bool("scroll"), term_type == TERM_TYPE_UTF8);
textbuffer_view_set_default_indent(gui->view,
settings_get_int("indent"),
!settings_get_bool("indent_always"),

View File

@ -71,6 +71,9 @@ void gui_expandos_deinit(void);
void textbuffer_commands_init(void);
void textbuffer_commands_deinit(void);
void textbuffer_formats_init(void);
void textbuffer_formats_deinit(void);
void lastlog_init(void);
void lastlog_deinit(void);
@ -168,6 +171,7 @@ static void textui_finish_init(void)
textbuffer_init();
textbuffer_view_init();
textbuffer_commands_init();
textbuffer_formats_init();
gui_expandos_init();
gui_printtext_init();
gui_readline_init();
@ -256,6 +260,7 @@ static void textui_deinit(void)
mainwindow_activity_deinit();
mainwindows_deinit();
gui_expandos_deinit();
textbuffer_formats_deinit();
textbuffer_commands_deinit();
textbuffer_view_deinit();
textbuffer_deinit();

View File

@ -199,7 +199,7 @@ static void show_lastlog(const char *searchtext, GHashTable *optlist,
}
/* get the line text */
textbuffer_line2text(rec, fhandle == NULL, line);
textbuffer_line2text(WINDOW_GUI(window)->view->buffer, rec, fhandle == NULL, line);
if (!settings_get_bool("timestamps")) {
struct tm *tm = localtime(&rec->info.time);
char timestamp[10];

View File

@ -23,6 +23,7 @@ executable('irssi',
'statusbar.c',
'term.c',
'textbuffer-commands.c',
'textbuffer-formats.c',
'textbuffer-view.c',
'textbuffer.c',
)
@ -53,6 +54,7 @@ install_headers(
'statusbar-item.h',
'statusbar.h',
'term.h',
'textbuffer-formats.h',
'textbuffer-view.h',
'textbuffer.h',
),

View File

@ -19,14 +19,15 @@
*/
#include "module.h"
#include <irssi/src/fe-text/module-formats.h>
#include <irssi/src/core/signals.h>
#include <irssi/src/core/commands.h>
#include <irssi/src/core/misc.h>
#include <irssi/src/core/levels.h>
#include <irssi/src/core/settings.h>
#include <irssi/src/core/servers.h>
#include <irssi/src/core/misc.h>
#include <irssi/src/core/refstrings.h>
#include <irssi/src/core/servers.h>
#include <irssi/src/core/settings.h>
#include <irssi/src/core/signals.h>
#include <irssi/src/fe-text/module-formats.h>
#include <irssi/src/fe-text/textbuffer-formats.h>
#include <irssi/src/fe-common/core/printtext.h>
#include <irssi/src/fe-text/gui-windows.h>
@ -340,14 +341,29 @@ static void cmd_scrollback_status(void)
total_lines = 0; total_mem = 0;
for (tmp = windows; tmp != NULL; tmp = tmp->next) {
WINDOW_REC *window = tmp->data;
int i;
LINE_REC *tmp;
TEXT_BUFFER_VIEW_REC *view;
view = WINDOW_GUI(window)->view;
window_mem = sizeof(TEXT_BUFFER_REC);
window_mem += g_slist_length(view->buffer->text_chunks) *
sizeof(TEXT_CHUNK_REC);
window_mem += view->buffer->lines_count * sizeof(LINE_REC);
for (tmp = view->buffer->cur_line; tmp != NULL; tmp = tmp->prev) {
if (tmp->info.text != NULL) {
window_mem += sizeof(char) * (strlen(tmp->info.text) + 1);
}
if (tmp->info.format != NULL) {
window_mem += sizeof(TEXT_BUFFER_FORMAT_REC);
for (i = 0; i < tmp->info.format->nargs; i++) {
if (tmp->info.format->args[i] != NULL) {
window_mem +=
sizeof(char) *
(strlen(tmp->info.format->args[i]) + 1);
}
}
}
}
total_lines += view->buffer->lines_count;
total_mem += window_mem;
printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP,
@ -368,6 +384,19 @@ static void cmd_scrollback_status(void)
}
}
/* SYNTAX: SCROLLBACK REDRAW */
static void cmd_scrollback_redraw(void)
{
GUI_WINDOW_REC *gui;
gui = WINDOW_GUI(active_win);
term_refresh_freeze();
textbuffer_view_reset_cache(gui->view);
gui_window_redraw(active_win);
term_refresh_thaw();
}
static void sig_away_changed(SERVER_REC *server)
{
GSList *tmp;
@ -419,6 +448,7 @@ void textbuffer_commands_init(void)
command_bind("scrollback home", NULL, (SIGNAL_FUNC) cmd_scrollback_home);
command_bind("scrollback end", NULL, (SIGNAL_FUNC) cmd_scrollback_end);
command_bind("scrollback status", NULL, (SIGNAL_FUNC) cmd_scrollback_status);
command_bind("scrollback redraw", NULL, (SIGNAL_FUNC) cmd_scrollback_redraw);
command_set_options("clear", "all");
command_set_options("scrollback clear", "all");
@ -442,6 +472,7 @@ void textbuffer_commands_deinit(void)
command_unbind("scrollback home", (SIGNAL_FUNC) cmd_scrollback_home);
command_unbind("scrollback end", (SIGNAL_FUNC) cmd_scrollback_end);
command_unbind("scrollback status", (SIGNAL_FUNC) cmd_scrollback_status);
command_unbind("scrollback redraw", (SIGNAL_FUNC) cmd_scrollback_redraw);
signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
signal_remove("away mode changed", (SIGNAL_FUNC) sig_away_changed);

View File

@ -0,0 +1,258 @@
#include "module.h"
#include <irssi/src/core/expandos.h>
#include <irssi/src/core/levels.h>
#include <irssi/src/core/refstrings.h>
#include <irssi/src/core/servers.h>
#include <irssi/src/core/signals.h>
#include <irssi/src/fe-common/core/printtext.h>
#include <irssi/src/fe-common/core/themes.h>
#include <irssi/src/fe-text/gui-printtext.h>
#include <irssi/src/fe-text/gui-windows.h>
#include <irssi/src/fe-text/textbuffer-formats.h>
#include <irssi/src/fe-text/textbuffer-view.h>
TEXT_BUFFER_REC *color_buf;
void textbuffer_format_rec_free(TEXT_BUFFER_FORMAT_REC *rec)
{
int n;
if (rec == NULL)
return;
if (rec == LINE_INFO_FORMAT_SET)
return;
i_refstr_release(rec->module);
i_refstr_release(rec->format);
i_refstr_release(rec->server_tag);
i_refstr_release(rec->target);
i_refstr_release(rec->nick);
if (rec->nargs >= 1) {
i_refstr_release(rec->args[0]);
}
for (n = 1; n < rec->nargs; n++) {
g_free(rec->args[n]);
}
rec->nargs = 0;
g_free(rec->args);
g_slice_free(TEXT_BUFFER_FORMAT_REC, rec);
}
static TEXT_BUFFER_FORMAT_REC *format_rec_new(const char *module, const char *format_tag,
const char *server_tag, const char *target,
const char *nick, int nargs, const char **args)
{
int n;
TEXT_BUFFER_FORMAT_REC *ret = g_slice_new0(TEXT_BUFFER_FORMAT_REC);
ret->module = i_refstr_intern(module);
ret->format = i_refstr_intern(format_tag);
ret->server_tag = i_refstr_intern(server_tag);
ret->target = i_refstr_intern(target);
ret->nick = i_refstr_intern(nick);
ret->nargs = nargs;
ret->args = g_new0(char *, nargs);
if (nargs >= 1) {
ret->args[0] = i_refstr_intern(args[0]);
}
for (n = 1; n < nargs; n++) {
ret->args[n] = g_strdup(args[n]);
}
return ret;
}
static LINE_INFO_REC *store_lineinfo_tmp(TEXT_DEST_REC *dest)
{
GUI_WINDOW_REC *gui;
TEXT_BUFFER_VIEW_REC *view;
TEXT_BUFFER_REC *buffer;
LINE_INFO_REC *lineinfo;
gui = WINDOW_GUI(dest->window);
view = gui->view;
buffer = view->buffer;
lineinfo = g_new0(LINE_INFO_REC, 1);
lineinfo->level = dest->level;
lineinfo->time =
(gui->use_insert_after && gui->insert_after_time) ? gui->insert_after_time : time(NULL);
buffer->cur_info = g_slist_prepend(buffer->cur_info, lineinfo);
return lineinfo;
}
static void free_lineinfo_tmp(WINDOW_REC *window)
{
GUI_WINDOW_REC *gui;
TEXT_BUFFER_REC *buffer;
LINE_INFO_REC *info;
gui = WINDOW_GUI(window);
buffer = gui->view->buffer;
if (buffer->cur_info == NULL)
return;
info = buffer->cur_info->data;
buffer->cur_info = g_slist_delete_link(buffer->cur_info, buffer->cur_info);
textbuffer_format_rec_free(info->format);
g_free(info);
}
static void sig_print_format(THEME_REC *theme, const char *module, TEXT_DEST_REC *dest,
void *formatnump, const char **args)
{
int formatnum;
FORMAT_REC *formats;
LINE_INFO_REC *info;
info = store_lineinfo_tmp(dest);
formatnum = GPOINTER_TO_INT(formatnump);
formats = g_hash_table_lookup(default_formats, module);
info->format = format_rec_new(module, formats[formatnum].tag, dest->server_tag,
dest->target, dest->nick, formats[formatnum].params, args);
info->format->flags = dest->flags;
dest->flags |= PRINT_FLAG_FORMAT;
signal_continue(5, theme, module, dest, formatnump, args);
free_lineinfo_tmp(dest->window);
}
static void sig_print_noformat(TEXT_DEST_REC *dest, const char *text)
{
LINE_INFO_REC *info;
info = store_lineinfo_tmp(dest);
info->format = format_rec_new(NULL, NULL, dest->server_tag, dest->target, dest->nick, 2,
(const char *[]){ NULL, text });
info->format->flags = dest->flags;
dest->flags |= PRINT_FLAG_FORMAT;
signal_continue(2, dest, text);
free_lineinfo_tmp(dest->window);
}
static void sig_gui_print_text_finished(WINDOW_REC *window)
{
GUI_WINDOW_REC *gui;
LINE_REC *insert_after;
LINE_INFO_REC *info;
TEXT_BUFFER_REC *buffer;
gui = WINDOW_GUI(window);
buffer = gui->view->buffer;
insert_after = gui->use_insert_after ? gui->insert_after : buffer->cur_line;
if (buffer->cur_info == NULL)
return;
info = buffer->cur_info->data;
if (info->format == NULL)
return;
info->level |= MSGLEVEL_FORMAT;
/* the line will be inserted into the view with textbuffer_view_insert_line by
gui-printtext.c:view_add_eol */
insert_after = textbuffer_insert(buffer, insert_after, (const unsigned char[]){}, 0, info);
/* the TEXT_BUFFER_FORMAT_REC pointer is now owned by the textbuffer */
info->format = LINE_INFO_FORMAT_SET;
if (gui->use_insert_after)
gui->insert_after = insert_after;
}
char *textbuffer_line_get_text(TEXT_BUFFER_REC *buffer, LINE_REC *line)
{
GUI_WINDOW_REC *gui;
LINE_REC *curr;
g_return_val_if_fail(buffer != NULL, NULL);
g_return_val_if_fail(buffer->window != NULL, NULL);
gui = WINDOW_GUI(buffer->window);
if (line == NULL || gui == NULL)
return NULL;
if (line->info.level & MSGLEVEL_FORMAT) {
TEXT_DEST_REC dest;
THEME_REC *theme;
int formatnum;
TEXT_BUFFER_FORMAT_REC *format_rec;
char *text, *tmp, *str;
curr = line;
line = NULL;
format_rec = curr->info.format;
format_create_dest(
&dest,
format_rec->server_tag != NULL ? server_find_tag(format_rec->server_tag) : NULL,
format_rec->target, curr->info.level & ~MSGLEVEL_FORMAT, buffer->window);
theme = window_get_theme(dest.window);
if (format_rec->format != NULL) {
char *arglist[MAX_FORMAT_PARAMS] = { 0 };
formatnum = format_find_tag(format_rec->module, format_rec->format);
memcpy(arglist, format_rec->args, format_rec->nargs * sizeof(char *));
text = format_get_text_theme_charargs(theme, format_rec->module, &dest,
formatnum, arglist);
} else {
text = g_strdup(format_rec->args[1]);
}
if (*text != '\0') {
current_time = curr->info.time;
tmp = format_get_level_tag(theme, &dest);
str = !theme->info_eol ? format_add_linestart(text, tmp) :
format_add_lineend(text, tmp);
g_free_not_null(tmp);
g_free_not_null(text);
text = str;
tmp = format_get_line_start(theme, &dest, curr->info.time);
str = !theme->info_eol ? format_add_linestart(text, tmp) :
format_add_lineend(text, tmp);
g_free_not_null(tmp);
g_free_not_null(text);
text = str;
/* str = g_strconcat(text, "\n", NULL); */
/* g_free(text); */
dest.flags |= PRINT_FLAG_FORMAT;
current_time = (time_t) -1;
return str;
} else if (format_rec->format != NULL) {
g_free(text);
return NULL;
} else {
return text;
}
} else {
return g_strdup(line->info.text);
}
}
void textbuffer_formats_init(void)
{
signal_add("print format", (SIGNAL_FUNC) sig_print_format);
signal_add("print noformat", (SIGNAL_FUNC) sig_print_noformat);
signal_add_first("gui print text finished", (SIGNAL_FUNC) sig_gui_print_text_finished);
}
void textbuffer_formats_deinit(void)
{
signal_remove("print format", (SIGNAL_FUNC) sig_print_format);
signal_remove("print noformat", (SIGNAL_FUNC) sig_print_noformat);
signal_remove("gui print text finished", (SIGNAL_FUNC) sig_gui_print_text_finished);
}

View File

@ -0,0 +1,22 @@
#ifndef IRSSI_FE_TEXT_TEXTBUFFER_FORMATS_H
#define IRSSI_FE_TEXT_TEXTBUFFER_FORMATS_H
#include <irssi/src/fe-text/textbuffer.h>
typedef struct _TEXT_BUFFER_FORMAT_REC {
char *module;
char *format;
char *server_tag;
char *target;
char *nick;
char **args;
int nargs;
int flags;
} TEXT_BUFFER_FORMAT_REC;
void textbuffer_format_rec_free(TEXT_BUFFER_FORMAT_REC *rec);
char *textbuffer_line_get_text(TEXT_BUFFER_REC *buffer, LINE_REC *line);
void textbuffer_formats_init(void);
void textbuffer_formats_deinit(void);
#endif

View File

@ -21,9 +21,12 @@
#define G_LOG_DOMAIN "TextBufferView"
#include "module.h"
#include <irssi/src/fe-text/textbuffer-view.h>
#include <irssi/src/core/levels.h>
#include <irssi/src/core/signals.h>
#include <irssi/src/core/utf8.h>
#include <irssi/src/fe-common/core/formats.h>
#include <irssi/src/fe-text/textbuffer-formats.h>
#include <irssi/src/fe-text/textbuffer-view.h>
typedef struct {
char *name;
@ -93,6 +96,7 @@ textbuffer_cache_get(GSList *views, int width)
static int line_cache_destroy(void *key, LINE_CACHE_REC *cache)
{
g_free(cache->line_text);
g_free(cache);
return TRUE;
}
@ -114,52 +118,6 @@ static void textbuffer_cache_unref(TEXT_BUFFER_CACHE_REC *cache)
#define FGATTR (ATTR_NOCOLORS | ATTR_RESETFG | FG_MASK | ATTR_FGCOLOR24)
#define BGATTR (ATTR_NOCOLORS | ATTR_RESETBG | BG_MASK | ATTR_BGCOLOR24)
static void update_cmd_color(unsigned char cmd, int *color)
{
if ((cmd & 0x80) == 0) {
if (cmd & LINE_COLOR_BG) {
/* set background color */
*color &= FGATTR;
if ((cmd & LINE_COLOR_DEFAULT) == 0)
*color |= (cmd & 0x0f) << BG_SHIFT;
else {
*color = (*color & FGATTR) | ATTR_RESETBG;
}
} else {
/* set foreground color */
*color &= BGATTR;
if ((cmd & LINE_COLOR_DEFAULT) == 0)
*color |= cmd & 0x0f;
else {
*color = (*color & BGATTR) | ATTR_RESETFG;
}
}
} else switch (cmd) {
case LINE_CMD_UNDERLINE:
*color ^= ATTR_UNDERLINE;
break;
case LINE_CMD_REVERSE:
*color ^= ATTR_REVERSE;
break;
case LINE_CMD_BLINK:
*color ^= ATTR_BLINK;
break;
case LINE_CMD_BOLD:
*color ^= ATTR_BOLD;
break;
case LINE_CMD_ITALIC:
*color ^= ATTR_ITALIC;
break;
case LINE_CMD_MONOSPACE:
/* ignored */
break;
case LINE_CMD_COLOR0:
*color &= BGATTR;
*color &= ~ATTR_FGCOLOR24;
break;
}
}
#ifdef TERM_TRUECOLOR
static void unformat_24bit_line_color(const unsigned char **ptr, int off, int *flags, unsigned int *fg, unsigned int *bg)
{
@ -167,6 +125,8 @@ static void unformat_24bit_line_color(const unsigned char **ptr, int off, int *f
unsigned char rgbx[4];
unsigned int i;
for (i = 0; i < 4; ++i) {
if ((*ptr)[i + off] == '\0')
return;
rgbx[i] = (*ptr)[i + off];
}
rgbx[3] -= 0x20;
@ -202,6 +162,94 @@ static inline unichar read_unichar(const unsigned char *data, const unsigned cha
return chr;
}
static inline void unformat(const unsigned char **ptr, int *color, unsigned int *fg24,
unsigned int *bg24)
{
switch (**ptr) {
case FORMAT_STYLE_BLINK:
*color ^= ATTR_BLINK;
break;
case FORMAT_STYLE_UNDERLINE:
*color ^= ATTR_UNDERLINE;
break;
case FORMAT_STYLE_BOLD:
*color ^= ATTR_BOLD;
break;
case FORMAT_STYLE_REVERSE:
*color ^= ATTR_REVERSE;
break;
case FORMAT_STYLE_ITALIC:
*color ^= ATTR_ITALIC;
break;
case FORMAT_STYLE_MONOSPACE:
/* *color ^= ATTR_MONOSPACE; */
break;
case FORMAT_STYLE_DEFAULTS:
*color = ATTR_RESET;
break;
case FORMAT_STYLE_CLRTOEOL:
break;
case FORMAT_COLOR_EXT1:
*color &= ~ATTR_FGCOLOR24;
*color = (*color & BGATTR) | (0x10 + *++*ptr - FORMAT_COLOR_NOCHANGE);
break;
case FORMAT_COLOR_EXT1_BG:
*color &= ~ATTR_BGCOLOR24;
*color = (*color & FGATTR) | (0x10 + *++*ptr - FORMAT_COLOR_NOCHANGE);
break;
case FORMAT_COLOR_EXT2:
*color &= ~ATTR_FGCOLOR24;
*color = (*color & BGATTR) | (0x60 + *++*ptr - FORMAT_COLOR_NOCHANGE);
break;
case FORMAT_COLOR_EXT2_BG:
*color &= ~ATTR_BGCOLOR24;
*color = (*color & FGATTR) | (0x60 + *++*ptr - FORMAT_COLOR_NOCHANGE);
break;
case FORMAT_COLOR_EXT3:
*color &= ~ATTR_FGCOLOR24;
*color = (*color & BGATTR) | (0xb0 + *++*ptr - FORMAT_COLOR_NOCHANGE);
break;
case FORMAT_COLOR_EXT3_BG:
*color &= ~ATTR_BGCOLOR24;
*color = (*color & FGATTR) | (0xb0 + *++*ptr - FORMAT_COLOR_NOCHANGE);
break;
#ifdef TERM_TRUECOLOR
case FORMAT_COLOR_24:
unformat_24bit_line_color(ptr, 1, color, fg24, bg24);
break;
#endif
default:
if (**ptr != FORMAT_COLOR_NOCHANGE) {
if (**ptr == (unsigned char) 0xff) {
*color = (*color & BGATTR) | ATTR_RESETFG;
} else {
*color = (*color & BGATTR) | (((unsigned char) **ptr - '0') & 0xf);
}
}
if ((*ptr)[1] == '\0')
break;
(*ptr)++;
if (**ptr != FORMAT_COLOR_NOCHANGE) {
if (**ptr == (unsigned char) 0xff) {
*color = (*color & FGATTR) | ATTR_RESETBG;
} else {
*color = (*color & FGATTR) |
((((unsigned char) **ptr - '0') & 0xf) << BG_SHIFT);
}
}
}
if (**ptr == '\0')
return;
(*ptr)++;
}
#define NEXT_CHAR_OR_BREAK(p) \
(p)++; \
if (*(p) == '\0') \
break
static LINE_CACHE_REC *
view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
{
@ -209,14 +257,12 @@ view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
LINE_CACHE_REC *rec;
LINE_CACHE_SUB_REC *sub;
GSList *lines;
unsigned char cmd;
char *line_text;
const unsigned char *ptr, *next_ptr, *last_space_ptr;
int xpos, pos, indent_pos, last_space, last_color, color, linecount;
unsigned int last_bg24, last_fg24, bg24, fg24;
int char_width;
g_return_val_if_fail(line->text != NULL, NULL);
color = ATTR_RESETFG | ATTR_RESETBG;
xpos = 0; indent_pos = view->default_indent;
last_space = last_color = 0; last_space_ptr = NULL; sub = NULL;
@ -225,114 +271,132 @@ view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line)
indent_func = view->default_indent_func;
linecount = 1;
lines = NULL;
for (ptr = line->text;;) {
if (*ptr == '\0') {
/* command */
ptr++;
cmd = *ptr;
ptr++;
if (cmd == LINE_CMD_EOL)
line_text = textbuffer_line_get_text(view->buffer, line);
if (line_text != NULL) {
for (ptr = (unsigned char *) line_text;;) {
if (*ptr == '\0')
break;
if (cmd == LINE_CMD_CONTINUE) {
unsigned char *tmp;
if (*ptr == '\n') {
/* newline */
xpos = 0;
last_space = 0;
sub = g_new0(LINE_CACHE_SUB_REC, 1);
sub->start = ++ptr;
sub->color = color;
#ifdef TERM_TRUECOLOR
sub->fg24 = fg24;
sub->bg24 = bg24;
#endif
lines = g_slist_append(lines, sub);
linecount++;
memcpy(&tmp, ptr, sizeof(char *));
ptr = tmp;
continue;
}
if (cmd == LINE_CMD_INDENT) {
/* set indentation position here - don't do
it if we're too close to right border */
if (xpos < view->width-5) indent_pos = xpos;
} else if (cmd == LINE_COLOR_EXT) {
color &= ~ATTR_FGCOLOR24;
color = (color & BGATTR) | *ptr++;
} else if (cmd == LINE_COLOR_EXT_BG) {
color &= ~ATTR_BGCOLOR24;
color = (color & FGATTR) | (*ptr++ << BG_SHIFT);
}
#ifdef TERM_TRUECOLOR
else if (cmd == LINE_COLOR_24)
unformat_24bit_line_color(&ptr, 0, &color, &fg24, &bg24);
#endif
else
update_cmd_color(cmd, &color);
continue;
}
if (*ptr == 4) {
/* format */
NEXT_CHAR_OR_BREAK(ptr);
if (!view->utf8) {
/* MH */
if (term_type != TERM_TYPE_BIG5 ||
ptr[1] == '\0' || !is_big5(ptr[0], ptr[1]))
char_width = 1;
else
char_width = 2;
next_ptr = ptr+char_width;
} else {
read_unichar(ptr, &next_ptr, &char_width);
}
if (xpos + char_width > view->width && sub != NULL &&
(last_space <= indent_pos || last_space <= 10) &&
view->longword_noindent) {
/* long word, remove the indentation from this line */
xpos -= sub->indent;
sub->indent = 0;
sub->indent_func = NULL;
}
if (xpos + char_width > view->width) {
xpos = indent_func == NULL ? indent_pos :
indent_func(view, line, -1);
sub = g_new0(LINE_CACHE_SUB_REC, 1);
if (last_space > indent_pos && last_space > 10) {
/* go back to last space */
color = last_color; fg24 = last_fg24; bg24 = last_bg24;
ptr = last_space_ptr;
while (*ptr == ' ') ptr++;
} else if (view->longword_noindent) {
/* long word, no indentation in next line */
xpos = 0;
sub->continues = TRUE;
if (*ptr == FORMAT_STYLE_INDENT) {
/* set indentation position here - don't do
it if we're too close to right border */
if (xpos < view->width - 5)
indent_pos = xpos;
ptr++;
} else {
unformat(&ptr, &color, &fg24, &bg24);
}
continue;
}
sub->start = ptr;
sub->indent = xpos;
sub->indent_func = indent_func;
sub->color = color;
if (!view->utf8) {
/* MH */
if (term_type != TERM_TYPE_BIG5 || ptr[1] == '\0' ||
!is_big5(ptr[0], ptr[1]))
char_width = 1;
else
char_width = 2;
next_ptr = ptr + char_width;
} else {
read_unichar(ptr, &next_ptr, &char_width);
}
if (xpos + char_width > view->width && sub != NULL &&
(last_space <= indent_pos || last_space <= 10) &&
view->longword_noindent) {
/* long word, remove the indentation from this line */
xpos -= sub->indent;
sub->indent = 0;
sub->indent_func = NULL;
}
if (xpos + char_width > view->width) {
xpos =
indent_func == NULL ? indent_pos : indent_func(view, line, -1);
sub = g_new0(LINE_CACHE_SUB_REC, 1);
if (last_space > indent_pos && last_space > 10) {
/* go back to last space */
color = last_color;
fg24 = last_fg24;
bg24 = last_bg24;
ptr = last_space_ptr;
while (*ptr == ' ')
ptr++;
} else if (view->longword_noindent) {
/* long word, no indentation in next line */
xpos = 0;
sub->continues = TRUE;
}
sub->start = ptr;
sub->indent = xpos;
sub->indent_func = indent_func;
sub->color = color;
#ifdef TERM_TRUECOLOR
sub->fg24 = fg24; sub->bg24 = bg24;
sub->fg24 = fg24;
sub->bg24 = bg24;
#endif
lines = g_slist_append(lines, sub);
linecount++;
lines = g_slist_append(lines, sub);
linecount++;
last_space = 0;
continue;
last_space = 0;
continue;
}
if (view->break_wide && char_width > 1) {
last_space = xpos;
last_space_ptr = next_ptr;
last_color = color;
last_fg24 = fg24;
last_bg24 = bg24;
} else if (*ptr == ' ') {
last_space = xpos;
last_space_ptr = ptr;
last_color = color;
last_fg24 = fg24;
last_bg24 = bg24;
}
xpos += char_width;
ptr = next_ptr;
}
if (view->break_wide && char_width > 1) {
last_space = xpos;
last_space_ptr = next_ptr;
last_color = color; last_fg24 = fg24; last_bg24 = bg24;
} else if (*ptr == ' ') {
last_space = xpos;
last_space_ptr = ptr;
last_color = color; last_fg24 = fg24; last_bg24 = bg24;
}
xpos += char_width;
ptr = next_ptr;
}
rec = g_malloc(sizeof(LINE_CACHE_REC)-sizeof(LINE_CACHE_SUB_REC) +
sizeof(LINE_CACHE_SUB_REC) * (linecount-1));
rec->last_access = time(NULL);
if (line_text == NULL) {
linecount = 0;
}
rec->count = linecount;
rec->line_text = line_text;
if (rec->count > 1) {
for (pos = 0; lines != NULL; pos++) {
@ -398,12 +462,9 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
INDENT_FUNC indent_func;
LINE_CACHE_REC *cache;
const unsigned char *text, *end, *text_newline;
unsigned char *tmp;
unichar chr;
int xpos, color, drawcount, first, need_move, need_clrtoeol, char_width;
#ifdef TERM_TRUECOLOR
unsigned int fg24, bg24;
#endif
if (view->dirty) /* don't bother drawing anything - redraw is coming */
return 0;
@ -416,7 +477,8 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
need_move = TRUE; need_clrtoeol = FALSE;
xpos = drawcount = 0; first = TRUE;
text_newline = text =
subline == 0 ? line->text : cache->lines[subline-1].start;
subline == 0 ? (unsigned char *) cache->line_text : cache->lines[subline - 1].start;
for (;;) {
if (text == text_newline) {
if (need_clrtoeol && xpos < view->width + (view->width == term_width ? 0 : 1)) {
@ -484,31 +546,29 @@ static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line,
subline++;
}
if (*text == '\0') {
/* command */
text++;
if (*text == LINE_CMD_EOL)
break;
if (*text == '\n') {
/* newline */
NEXT_CHAR_OR_BREAK(text);
continue;