Added parsing

This commit is contained in:
Jesse van den Kieboom 2005-12-23 13:22:01 +00:00
parent fe080a3ca0
commit 00f73b51a2
1 changed files with 379 additions and 6 deletions

View File

@ -9,9 +9,12 @@
#include "../gm-pixbuf.h"
#include "../gm-support.h"
#include "../gm-debug.h"
#include "../gm-string.h"
#include "../gm-options.h"
#include "../gm-color-table.h"
#include "../gm-app.h"
#include "../parser/gm-parser.h"
#include "gm-searchable.h"
#define GM_EDITOR_VIEW_GET_PRIVATE(object)( \
@ -22,6 +25,18 @@ struct _GmEditorViewPrivate {
GmWorld *world;
GmEditor *editor;
GtkExpander *expander;
GtkWidget *message_area;
GtkWidget *error_label;
GtkWidget *warning_label;
GtkWidget *error_frame;
GtkWidget *warning_frame;
gboolean set_style;
guint timeout_handler;
guint hide_error_handler;
gboolean expanding;
gboolean was_expanded;
GtkSourceView *source_view;
};
@ -47,12 +62,19 @@ void on_gm_editor_view_saveclose_clicked(GtkToolButton *button,
GmEditorView *view);
void on_gm_editor_view_close_clicked(GtkToolButton *button,
GmEditorView *view);
void on_gm_editor_view_execute_clicked(GtkToolButton *button,
GmEditorView *view);
void on_gm_editor_view_editor_saved(GmEditor *editor, GmEditorView *view);
void on_gm_editor_view_font_changed(GmColorTable *color_table,
gchar const *desc, GmEditorView *view);
void on_gm_editor_view_modified_changed(GtkTextBuffer *buffer,
GmEditorView *view);
void on_gm_editor_view_changed(GtkTextBuffer *buffer,
GmEditorView *view);
void on_gm_editor_view_expander(GObject *object, GParamSpec *param_spec,
GmEditorView *view);
G_DEFINE_TYPE_EXTENDED(GmEditorView, gm_editor_view, GTK_TYPE_VBOX, 0, \
G_IMPLEMENT_INTERFACE(GM_TYPE_SEARCHABLE, \
@ -74,7 +96,14 @@ gm_editor_view_searchable_get_text_view(GmSearchable *sea) {
static void
gm_editor_view_finalize(GObject *object) {
//GmEditorView *obj = GM_EDITOR_VIEW(object);
GmEditorView *obj = GM_EDITOR_VIEW(object);
if (obj->priv->timeout_handler) {
g_source_remove(obj->priv->timeout_handler);
}
if (obj->priv->hide_error_handler) {
g_source_remove(obj->priv->hide_error_handler);
}
G_OBJECT_CLASS(gm_editor_view_parent_class)->finalize(object);
}
@ -111,7 +140,7 @@ gm_editor_view_class_init(GmEditorViewClass *klass) {
}
GtkSourceView *
gm_editor_create_source_view(GmEditorView *view) {
gm_editor_view_create_source_view(GmEditorView *view) {
GtkTextBuffer *buffer;
GtkWidget *source_view;
GtkTextIter iter;
@ -128,6 +157,7 @@ gm_editor_create_source_view(GmEditorView *view) {
gtk_source_buffer_set_language(GTK_SOURCE_BUFFER(buffer), language);
}
gtk_source_buffer_begin_not_undoable_action(GTK_SOURCE_BUFFER(buffer));
gtk_text_buffer_get_end_iter(buffer, &iter);
for (lines = gm_editor_lines(view->priv->editor); lines;
@ -140,6 +170,7 @@ gm_editor_create_source_view(GmEditorView *view) {
}
}
gtk_source_buffer_end_not_undoable_action(GTK_SOURCE_BUFFER(buffer));
gtk_text_buffer_set_modified(buffer, FALSE);
st = gtk_source_tag_style_new();
@ -169,19 +200,109 @@ gm_editor_create_source_view(GmEditorView *view) {
gtk_source_buffer_set_highlight(GTK_SOURCE_BUFFER(buffer), FALSE);
}
gtk_text_buffer_create_tag(buffer, "gm_error", "underline",
PANGO_UNDERLINE_ERROR, NULL);
g_signal_connect(buffer, "modified_changed",
G_CALLBACK(on_gm_editor_view_modified_changed), view);
g_signal_connect(buffer, "changed",
G_CALLBACK(on_gm_editor_view_changed), view);
gtk_widget_show(source_view);
return GTK_SOURCE_VIEW(source_view);
}
static gboolean
gm_editor_view_paint_message_area(GtkWidget *widget, GdkEventExpose *event,
GmEditorView *view) {
gtk_paint_flat_box(widget->style, widget->window, GTK_STATE_NORMAL,
GTK_SHADOW_OUT, NULL, widget, "tooltip",
widget->allocation.x + 1, widget->allocation.y + 1,
widget->allocation.width - 2, widget->allocation.height - 2);
return FALSE;
}
static void
gm_editor_view_message_area_style_set(GtkWidget *widget, GtkStyle *prev,
GmEditorView *view) {
GtkTooltips *tooltips;
GtkStyle *style;
if (view->priv->set_style) {
return;
}
tooltips = gtk_tooltips_new();
g_object_ref(G_OBJECT(tooltips));
gtk_object_sink(GTK_OBJECT(tooltips));
gtk_tooltips_force_window(tooltips);
gtk_widget_ensure_style(tooltips->tip_window);
style = gtk_widget_get_style(tooltips->tip_window);
view->priv->set_style = TRUE;
gtk_widget_set_style(widget, style);
view->priv->set_style = FALSE;
g_object_unref(tooltips);
}
static void
gm_editor_view_create_message_area(GmEditorView *view) {
GtkWidget *message_area = gtk_vbox_new(FALSE, 6);
GtkWidget *align;
GtkWidget *lbl;
gtk_container_set_border_width(GTK_CONTAINER(message_area), 10);
g_signal_connect(message_area, "expose_event",
G_CALLBACK(gm_editor_view_paint_message_area), view);
g_signal_connect(message_area, "style-set",
G_CALLBACK(gm_editor_view_message_area_style_set), view);
view->priv->message_area = message_area;
lbl = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(lbl), _("<b>Errors</b>"));
view->priv->error_frame = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(view->priv->error_frame),
GTK_SHADOW_NONE);
gtk_frame_set_label_widget(GTK_FRAME(view->priv->error_frame), lbl);
view->priv->error_label = gtk_label_new(NULL);
gtk_misc_set_alignment(GTK_MISC(view->priv->error_label), 0.0, 0.0);
align = gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0);
gtk_container_add(GTK_CONTAINER(align), view->priv->error_label);
gtk_container_add(GTK_CONTAINER(view->priv->error_frame), align);
gtk_box_pack_start(GTK_BOX(message_area), view->priv->error_frame, TRUE,
TRUE, 0);
lbl = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(lbl), _("<b>Warnings</b>"));
view->priv->warning_frame = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(view->priv->warning_frame),
GTK_SHADOW_NONE);
gtk_frame_set_label_widget(GTK_FRAME(view->priv->warning_frame), lbl);
view->priv->warning_label = gtk_label_new(NULL);
gtk_misc_set_alignment(GTK_MISC(view->priv->warning_label), 0.0, 0.0);
align = gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0);
gtk_container_add(GTK_CONTAINER(align), view->priv->warning_label);
gtk_container_add(GTK_CONTAINER(view->priv->warning_frame), align);
gtk_box_pack_start(GTK_BOX(message_area), view->priv->warning_frame, TRUE, TRUE, 0);
}
static void
gm_editor_view_init(GmEditorView *obj) {
GtkWidget *toolbar, *item;
GtkWidget *toolbar, *item, *expander, *tmp;
obj->priv = GM_EDITOR_VIEW_GET_PRIVATE(obj);
gtk_box_set_spacing(GTK_BOX(obj), 6);
gtk_box_set_spacing(GTK_BOX(obj), 0);
gtk_box_set_homogeneous(GTK_BOX(obj), FALSE);
toolbar = gtk_toolbar_new();
@ -202,8 +323,32 @@ gm_editor_view_init(GmEditorView *obj) {
G_CALLBACK(on_gm_editor_view_close_clicked), obj);
gtk_container_add(GTK_CONTAINER(toolbar), item);
item = GTK_WIDGET(gtk_tool_button_new_from_stock(GTK_STOCK_EXECUTE));
g_signal_connect(item, "clicked",
G_CALLBACK(on_gm_editor_view_execute_clicked), obj);
gtk_container_add(GTK_CONTAINER(toolbar), item);
item = GTK_WIDGET(gtk_separator_tool_item_new());
gtk_container_add(GTK_CONTAINER(toolbar), item);
item = GTK_WIDGET(gtk_tool_item_new());
tmp = gtk_alignment_new(0.0, 1.0, 0.0, 0.0);
expander = gtk_expander_new(NULL);
g_signal_connect(expander, "notify::expanded",
G_CALLBACK(on_gm_editor_view_expander), obj);
gtk_container_add(GTK_CONTAINER(tmp), expander);
gtk_container_add(GTK_CONTAINER(item), tmp);
gtk_container_add(GTK_CONTAINER(toolbar), item);
gtk_box_pack_start(GTK_BOX(obj), toolbar, FALSE, FALSE, 0);
gtk_widget_show_all(toolbar);
gtk_widget_hide(expander);
obj->priv->expander = GTK_EXPANDER(expander);
gm_editor_view_create_message_area(obj);
gtk_box_pack_start(GTK_BOX(obj), obj->priv->message_area, FALSE, FALSE, 0);
}
GmEditorView *
@ -213,7 +358,7 @@ gm_editor_view_new(GmWorld *world, GmEditor *editor) {
obj->priv->editor = editor;
obj->priv->world = world;
obj->priv->source_view = gm_editor_create_source_view(obj);
obj->priv->source_view = gm_editor_view_create_source_view(obj);
srl = gtk_scrolled_window_new(NULL, NULL);
gtk_widget_show(srl);
@ -221,7 +366,7 @@ gm_editor_view_new(GmWorld *world, GmEditor *editor) {
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(srl), GTK_WIDGET(obj->priv->source_view));
gtk_box_pack_start(GTK_BOX(obj), srl, TRUE, TRUE, 0);
gtk_box_pack_end(GTK_BOX(obj), srl, TRUE, TRUE, 0);
g_signal_connect(gm_app_color_table(gm_app_instance()), "font_changed",
G_CALLBACK(on_gm_editor_view_font_changed), obj);
@ -255,6 +400,179 @@ gm_editor_view_save(GmEditorView *view) {
gm_editor_save(view->priv->editor);
}
gboolean
gm_editor_view_no_errors(GmEditorView *view) {
gtk_widget_hide(GTK_WIDGET(view->priv->expander));
return FALSE;
}
void
gm_editor_view_parse_error(GmEditorView *view, GmParserError *error,
GString **str) {
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(
view->priv->source_view));
GtkTextIter start, end;
gchar *msg;
if (error->ch == 0) {
gtk_text_buffer_get_iter_at_line(buffer, &start,
error->line - 1);
msg = g_markup_printf_escaped(_("<u>Line %d</u>: %s\n"), error->line,
error->message);
} else {
// Underline line
gtk_text_buffer_get_iter_at_line(buffer, &start, error->line);
msg = g_markup_printf_escaped(_("<u>Line %d:%d</u>: %s\n"),
error->line + 1, error->ch + 1, error->message);
}
if (!*str) {
*str = g_string_new(msg);
} else {
*str = g_string_append(*str, msg);
}
g_free(msg);
end = start;
if (error->ch != 0) {
gtk_text_iter_forward_chars(&start, error->ch - 1);
}
gtk_text_iter_forward_to_line_end(&end);
gtk_text_buffer_apply_tag_by_name(buffer, "gm_error", &start, &end);
}
enum {
SYNTAX_OK = 0,
SYNTAX_ERRORS = 1 << 0,
SYNTAX_WARNINGS = 1 << 1
};
int
gm_editor_view_parse(GmEditorView *view) {
gchar *text;
GtkTextIter start, end;
GList *lines;
GmParserResult *result;
GList *errors;
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(
view->priv->source_view));
gchar *msg;
GString *str = NULL, *lbl = NULL;
int ret = SYNTAX_OK;
if (view->priv->hide_error_handler) {
g_source_remove(view->priv->hide_error_handler);
}
gtk_text_buffer_get_bounds(buffer, &start, &end);
text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
lines = gm_string_split(text);
result = gm_parser_parse(lines);
gtk_text_buffer_remove_tag_by_name(buffer, "gm_error", &start, &end);
if (!result->isOk) {
if (result->errors) {
for (errors = result->errors; errors; errors = errors->next) {
gm_editor_view_parse_error(view, (GmParserError *)(errors->data),
&str);
}
str = g_string_truncate(str, str->len - 1);
gtk_label_set_markup(GTK_LABEL(view->priv->error_label), str->str);
gtk_widget_show_all(view->priv->error_frame);
g_string_free(str, TRUE);
str = NULL;
if (g_list_length(result->errors) == 1) {
msg = g_strdup(_("There is 1 error"));
} else {
msg = g_strdup_printf(_("There are %d errors"),
g_list_length(result->errors));
}
lbl = g_string_new(msg);
g_free(msg);
ret |= SYNTAX_ERRORS;
} else {
gtk_widget_hide(view->priv->error_frame);
}
if (result->warnings) {
for (errors = result->warnings; errors; errors = errors->next) {
gm_editor_view_parse_error(view, (GmParserError *)(errors->data),
&str);
}
str = g_string_truncate(str, str->len - 1);
gtk_label_set_markup(GTK_LABEL(view->priv->warning_label),
str->str);
gtk_widget_show_all(view->priv->warning_frame);
g_string_free(str, TRUE);
if (g_list_length(result->warnings) == 1) {
if (!lbl) {
msg = g_strdup(_("There is 1 warning"));
} else {
msg = g_strdup_printf(_(" and 1 warning"));
}
} else {
if (!lbl) {
msg = g_strdup_printf(_("There are %d warnings"),
g_list_length(result->warnings));
} else {
msg = g_strdup_printf(_(" and %d warnings"),
g_list_length(result->warnings));
}
}
if (!lbl) {
lbl = g_string_new(msg);
} else {
lbl = g_string_append(lbl, msg);
}
g_free(msg);
ret |= SYNTAX_WARNINGS;
} else {
gtk_widget_hide(view->priv->warning_frame);
}
gtk_widget_set_sensitive(GTK_WIDGET(view->priv->expander), TRUE);
gtk_expander_set_label(view->priv->expander, lbl->str);
g_string_free(lbl, TRUE);
gtk_widget_show(GTK_WIDGET(view->priv->expander));
if (view->priv->was_expanded &&
!gtk_expander_get_expanded(view->priv->expander)) {
view->priv->expanding = TRUE;
gtk_expander_set_expanded(view->priv->expander, TRUE);
view->priv->expanding = FALSE;
}
} else {
gtk_expander_set_label(view->priv->expander, _("There are no errors"));
view->priv->expanding = TRUE;
gtk_expander_set_expanded(view->priv->expander, FALSE);
view->priv->expanding = FALSE;
gtk_widget_set_sensitive(GTK_WIDGET(view->priv->expander), FALSE);
gtk_widget_hide(view->priv->message_area);
view->priv->hide_error_handler = g_timeout_add(3000,
(GSourceFunc)gm_editor_view_no_errors, view);
}
gm_parser_result_free(result);
gm_g_list_free_simple(lines);
g_free(text);
return ret;
}
/* Callbacks */
void
@ -296,9 +614,64 @@ on_gm_editor_view_close_clicked(GtkToolButton *button,
gm_editor_close(view->priv->editor);
}
void
on_gm_editor_view_execute_clicked(GtkToolButton *button,
GmEditorView *view) {
int ret = gm_editor_view_parse(view);
if (ret == SYNTAX_OK) {
gtk_expander_set_expanded(view->priv->expander, FALSE);
gtk_widget_hide(view->priv->message_area);
gm_info_dialog(_("No errors are found"), NULL);
} else {
gtk_expander_set_expanded(view->priv->expander, TRUE);
gtk_widget_show_all(view->priv->message_area);
}
}
void
on_gm_editor_view_modified_changed(GtkTextBuffer *buffer,
GmEditorView *view) {
g_signal_emit(view, gm_editor_view_signals[MODIFIED_CHANGED], 0,
gtk_text_buffer_get_modified(buffer));
}
gboolean
gm_editor_view_timeout(GmEditorView *view) {
gm_editor_view_parse(view);
view->priv->timeout_handler = 0;
return FALSE;
}
void
on_gm_editor_view_changed(GtkTextBuffer *buffer,
GmEditorView *view) {
if (view->priv->timeout_handler != 0) {
g_source_remove(view->priv->timeout_handler);
}
if (gm_options_get_int(gm_app_options(gm_app_instance()),
"auto_check_syntax")) {
view->priv->timeout_handler = g_timeout_add(500,
(GSourceFunc)gm_editor_view_timeout, view);
}
}
void
on_gm_editor_view_expander(GObject *object, GParamSpec *param_spec,
GmEditorView *view) {
if (gtk_expander_get_expanded(view->priv->expander)) {
if (!view->priv->expanding) {
view->priv->was_expanded = TRUE;
}
gtk_widget_show(view->priv->message_area);
} else {
if (!view->priv->expanding) {
view->priv->was_expanded = FALSE;
}
gtk_widget_hide(view->priv->message_area);
}
}