Added highlight signal, added triggers

This commit is contained in:
Jesse van den Kieboom 2006-01-02 17:55:40 +00:00
parent 4dddfc7cdc
commit 6ae642bfda
2 changed files with 193 additions and 11 deletions

View File

@ -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
}
}

View File

@ -2,6 +2,8 @@
#define __GM_WORLD_H__
#include <gtk/gtk.h>
#include <regex.h>
#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__ */