From 6ae642bfda30552b1d3243b676d7db0410f8358b Mon Sep 17 00:00:00 2001 From: Jesse van den Kieboom Date: Mon, 2 Jan 2006 17:55:40 +0000 Subject: [PATCH] Added highlight signal, added triggers --- gnoemoe/gm-world.c | 178 ++++++++++++++++++++++++++++++++++++++++++++- gnoemoe/gm-world.h | 26 +++++-- 2 files changed, 193 insertions(+), 11 deletions(-) diff --git a/gnoemoe/gm-world.c b/gnoemoe/gm-world.c index 8c31cdc..b0026e4 100644 --- a/gnoemoe/gm-world.c +++ b/gnoemoe/gm-world.c @@ -67,6 +67,7 @@ enum { NAME_CHANGED, ACTIVE_CHANGED, ACTIVITY_CHANGED, + HIGHLIGHT, NUM_SIGNALS }; @@ -234,6 +235,19 @@ gm_world_class_init(GmWorldClass *klass) { G_TYPE_NONE, 1, G_TYPE_INT); + + world_signals[HIGHLIGHT] = + g_signal_new("highlight", + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GmWorldClass, highlight), + NULL, NULL, + gm_marshal_VOID__INT_INT_STRING, + G_TYPE_NONE, + 3, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_STRING); g_type_class_add_private(object_class, sizeof(GmWorldPrivate)); } @@ -663,11 +677,144 @@ gm_world_parse_legacy_editing_start(GmWorld *world, gchar *line) { einfo->lines = NULL; } +#define MAX_MATCHES 10 + +gchar * +gm_world_triggers_subst(gchar const *data, gchar const *text, + regmatch_t *matches) { + gchar *tmp = (gchar *)data; + gchar *p, *ptr, *tmp2; + GString *result = NULL; + gint n; + gunichar c; + + result = g_string_new(NULL); + + while ((p = g_utf8_strchr(tmp, -1, '\\'))) { + n = 0; + ptr = g_utf8_next_char(p); + + g_string_append_len(result, tmp, g_utf8_strlen(tmp, -1) - + g_utf8_strlen(p, -1)); + + if (g_unichar_isdigit(g_utf8_get_char(ptr))) { + while ((c = (g_utf8_get_char(ptr))) != 0 && g_unichar_isdigit(c)) { + n = (n * 10) + g_unichar_digit_value(c); + ptr = g_utf8_next_char(ptr); + } + + /* Replace it */ + if (n < MAX_MATCHES) { + tmp2 = g_strndup(g_utf8_offset_to_pointer(text, + matches[n].rm_so), matches[n].rm_eo); + g_string_append(result, tmp2); + g_free(tmp2); + } + tmp = ptr; + } else { + tmp = ptr; + } + } + + g_string_append(result, tmp); + tmp = result->str; + g_string_free(result, FALSE); + + return tmp; +} + +void +gm_world_apply_trigger(GmWorld *world, GmTrigger *trigger, gchar const *text, + regmatch_t *matches) { + GList *item; + GmTriggerData *data; + gint i, nargs; + gchar **spawn_args, *tmp, *argstr; + + for (item = trigger->actions; item; item = item->next) { + data = (GmTriggerData *)(item->data); + + switch (data->type) { + case TAT_HIGHLIGHT_LINE: + g_signal_emit(world, world_signals[HIGHLIGHT], 0, -1, -1, + data->data); + break; + case TAT_HIGHLIGHT_MATCH: + for (i = 0; matches[i].rm_so != -1; ++i) { + g_signal_emit(world, world_signals[HIGHLIGHT], 0, + matches[i].rm_so, matches[i].rm_eo, data->data); + } + break; + case TAT_BEEP: + gdk_beep(); + break; + case TAT_PLAY_SOUND: + tmp = gm_world_triggers_subst(data->data, text, matches); + // TODO + g_free(tmp); + break; + case TAT_NOTIFY: + tmp = gm_world_triggers_subst(data->data, text, matches); + // TODO + g_free(tmp); + break; + case TAT_RUN_SCRIPT: + #ifdef HAVE_RUBY + tmp = gm_world_triggers_subst(data->data, text, matches); + argstr = g_utf8_strchr(tmp, -1, ' '); + + if (argstr) { + *argstr = '\0'; + argstr = g_utf8_next_char(argstr); + } + + gm_scripts_run(gm_app_scripts(gm_app_instance()), + world, tmp, argstr); + + g_free(tmp); + #endif + break; + case TAT_RUN: + tmp = gm_world_triggers_subst(data->data, text, matches); + + if (g_shell_parse_argv(tmp, &nargs, &spawn_args, NULL)) { + g_spawn_async(NULL, spawn_args, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, NULL); + g_strfreev(spawn_args); + } + + g_free(tmp); + break; + default: + break; + } + } +} + +void +gm_world_process_triggers(GmWorld *world, gchar *text) { + GList const *item; + GmTrigger *trigger; + regmatch_t matches[MAX_MATCHES]; + + for (item = gm_triggers_list(world->priv->triggers); item; + item = item->next) { + trigger = (GmTrigger *)(item->data); + + if (trigger->event == TT_OUTPUT) { + if (gm_trigger_match(trigger, text, matches, MAX_MATCHES)) { + gm_world_apply_trigger(world, trigger, text, matches); + } + } + } +} + void gm_world_process_line(GmWorld *world, gchar *line) { gchar *non_text_start = NULL; GmEditingInfo *einfo = &(world->priv->editing_info); GmEditor *editor; + gchar *no_ansi; if (strncmp(line, "\x1B[0m", 4) == 0) { non_text_start = g_strdup(line + 4); @@ -695,7 +842,8 @@ gm_world_process_line(GmWorld *world, gchar *line) { g_list_free(einfo->lines); einfo->lines = NULL; } else { - einfo->lines = g_list_append(einfo->lines, g_strdup(non_text_start)); + einfo->lines = g_list_append(einfo->lines, + g_strdup(non_text_start)); } } else if (strncmp(non_text_start, "#$#", 3) == 0) { if (strncasecmp(non_text_start + 3, " edit ", 6) == 0) { @@ -711,17 +859,27 @@ gm_world_process_line(GmWorld *world, gchar *line) { if (strncmp(non_text_start, "#$\"", 3) == 0) { if (strlen(non_text_start) != strlen(line)) { - g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\x1B[0m"); + g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, + "\x1B[0m"); } - gm_world_log(world, LOG_IN, non_text_start + 3); - g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, non_text_start + 3); + g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, + non_text_start + 3); g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\n"); + + gm_world_log(world, LOG_IN, non_text_start + 3); + no_ansi = gm_ansi_strip(g_strdup(non_text_start + 3)); } else { g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, line); g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\n"); + gm_world_log(world, LOG_IN, line); + no_ansi = gm_ansi_strip(g_strdup(line)); } + + /* Process triggers */ + gm_world_process_triggers(world, no_ansi); + g_free(no_ansi); } g_free(non_text_start); @@ -938,6 +1096,18 @@ void on_gm_world_net_state_changed(GmNet *net, GmNetState state, GmWorld *world) { if (state == GM_NET_STATE_CONNECTED) { gm_world_auto_login(world); + + #ifdef HAVE_RUBY + gm_scripts_run(gm_app_scripts(gm_app_instance()), world, "on_connect", + NULL); + #endif + } + + if (state == GM_NET_STATE_DISCONNECTED) { + #ifdef HAVE_RUBY + gm_scripts_run(gm_app_scripts(gm_app_instance()), world, + "on_disconnect", NULL); + #endif } } diff --git a/gnoemoe/gm-world.h b/gnoemoe/gm-world.h index 87f7614..3848068 100644 --- a/gnoemoe/gm-world.h +++ b/gnoemoe/gm-world.h @@ -2,6 +2,8 @@ #define __GM_WORLD_H__ #include +#include + #include "gm-options.h" #include "gm-net.h" #include "gm-editor.h" @@ -13,13 +15,19 @@ G_BEGIN_DECLS /* * Type checking and casting macros */ -#define GM_TYPE_WORLD (gm_world_get_type()) -#define GM_WORLD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD, GmWorld)) -#define GM_WORLD_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GM_TYPE_WORLD, GmWorld const)) -#define GM_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GM_TYPE_WORLD, GmWorldClass)) -#define GM_IS_WORLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GM_TYPE_WORLD)) -#define GM_IS_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GM_TYPE_WORLD)) -#define GM_WORLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GM_TYPE_WORLD, GmWorldClass)) +#define GM_TYPE_WORLD (gm_world_get_type()) +#define GM_WORLD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GM_TYPE_WORLD, GmWorld)) +#define GM_WORLD_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GM_TYPE_WORLD, GmWorld const)) +#define GM_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), \ + GM_TYPE_WORLD, GmWorldClass)) +#define GM_IS_WORLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), \ + GM_TYPE_WORLD)) +#define GM_IS_WORLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + GM_TYPE_WORLD)) +#define GM_WORLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GM_TYPE_WORLD, GmWorldClass)) /** \ingroup world * \brief struct for world editing information @@ -85,6 +93,8 @@ struct _GmWorldClass { void (* name_changed) (GmWorld *world, gchar const *name); void (* active_changed) (GmWorld *world, gboolean active); void (* activity_changed) (GmWorld *world, gint activity); + void (* highlight) (GmWorld *world, gint start, gint end, + gchar const *color); }; GType gm_world_get_type(void) G_GNUC_CONST; @@ -126,6 +136,8 @@ void gm_world_sendln(GmWorld *world, gchar *text); void gm_world_writeln(GmWorld *world, gchar *text); void gm_world_process_input(GmWorld *world, gchar *text); void gm_world_log(GmWorld *world, GmLogType type, gchar *text); +void gm_world_apply_trigger(GmWorld *world, GmTrigger *trigger, + gchar const *text, regmatch_t *matches); G_END_DECLS #endif /* __GM_WORLD_H__ */