Added highlight signal, added triggers
This commit is contained in:
parent
4dddfc7cdc
commit
6ae642bfda
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Reference in New Issue