diff --git a/docs/reference/gtk/gtk4-builder-tool.xml b/docs/reference/gtk/gtk4-builder-tool.xml index b7be944fe6..843b6ae8fb 100644 --- a/docs/reference/gtk/gtk4-builder-tool.xml +++ b/docs/reference/gtk/gtk4-builder-tool.xml @@ -57,7 +57,8 @@ Simplifies the .ui file by removing properties that - are set to their default values and write the resulting XML to stdout. + are set to their default values and write the resulting XML to stdout, + or back to the input file. @@ -71,6 +72,16 @@ +Simplify Options + The command accepts the following options: + + + + Write the content back to the .ui file instead of stdout. + + + + Preview Options The command accepts the following options: diff --git a/gtk/gtk-builder-tool.c b/gtk/gtk-builder-tool.c index f3cfbaafd6..7c5eb18131 100644 --- a/gtk/gtk-builder-tool.c +++ b/gtk/gtk-builder-tool.c @@ -19,9 +19,11 @@ #include #include +#include #include #include +#include #include #include "gtkbuilderprivate.h" @@ -40,6 +42,9 @@ typedef struct { GString *value; gboolean unclosed_starttag; gint indent; + char *input_filename; + char *output_filename; + FILE *output; } MyParserData; static void @@ -226,7 +231,7 @@ maybe_start_packing (MyParserData *data) { if (!data->packing_started) { - g_printf ("%*s\n", data->indent, ""); + g_fprintf (data->output, "%*s\n", data->indent, ""); data->indent += 2; data->packing_started = TRUE; } @@ -240,7 +245,7 @@ maybe_start_cell_packing (MyParserData *data) { if (!data->cell_packing_started) { - g_printf ("%*s\n", data->indent, ""); + g_fprintf (data->output, "%*s\n", data->indent, ""); data->indent += 2; data->cell_packing_started = TRUE; } @@ -254,7 +259,7 @@ maybe_start_child (MyParserData *data) { if (data->child_started < data->in_child) { - g_printf ("%*s\n", data->indent, ""); + g_fprintf (data->output, "%*s\n", data->indent, ""); data->indent += 2; data->child_started += 1; } @@ -309,7 +314,7 @@ maybe_emit_property (MyParserData *data) maybe_start_packing (data); maybe_start_cell_packing (data); - g_printf ("%*sindent, ""); + g_fprintf (data->output, "%*sindent, ""); for (i = 0; data->attribute_names[i]; i++) { if (!translatable && @@ -322,28 +327,28 @@ maybe_emit_property (MyParserData *data) if (strcmp (data->attribute_names[i], "name") == 0) canonicalize_key (escaped); - g_printf (" %s=\"%s\"", data->attribute_names[i], escaped); + g_fprintf (data->output, " %s=\"%s\"", data->attribute_names[i], escaped); g_free (escaped); } if (bound) { - g_printf ("/>\n"); + g_fprintf (data->output, "/>\n"); } else { - g_printf (">"); + g_fprintf (data->output, ">"); if (property_is_boolean (data, class_name, property_name)) { - g_printf ("%s", canonical_boolean_value (data, value_string)); + g_fprintf (data->output, "%s", canonical_boolean_value (data, value_string)); } else { escaped = g_markup_escape_text (value_string, -1); - g_printf ("%s", escaped); + g_fprintf (data->output, "%s", escaped); g_free (escaped); } - g_printf ("\n"); + g_fprintf (data->output, "\n"); } } @@ -352,7 +357,7 @@ maybe_close_starttag (MyParserData *data) { if (data->unclosed_starttag) { - g_printf (">\n"); + g_fprintf (data->output, ">\n"); data->unclosed_starttag = FALSE; } } @@ -479,11 +484,11 @@ start_element (GMarkupParseContext *context, } } - g_printf ("%*s<%s", data->indent, "", element_name); + g_fprintf (data->output, "%*s<%s", data->indent, "", element_name); for (i = 0; attribute_names[i]; i++) { escaped = g_markup_escape_text (attribute_values[i], -1); - g_printf (" %s=\"%s\"", attribute_names[i], escaped); + g_fprintf (data->output, " %s=\"%s\"", attribute_names[i], escaped); g_free (escaped); } data->unclosed_starttag = TRUE; @@ -543,10 +548,10 @@ end_element (GMarkupParseContext *context, gchar *escaped; if (data->unclosed_starttag) - g_printf (">"); + g_fprintf (data->output, ">"); escaped = g_markup_escape_text (data->value->str, -1); - g_printf ("%s\n", escaped, element_name); + g_fprintf (data->output, "%s\n", escaped, element_name); g_free (escaped); g_string_free (data->value, TRUE); @@ -555,9 +560,9 @@ end_element (GMarkupParseContext *context, else { if (data->unclosed_starttag) - g_printf ("/>\n"); + g_fprintf (data->output, "/>\n"); else - g_printf ("%*s\n", data->indent - 2, "", element_name); + g_fprintf (data->output, "%*s\n", data->indent - 2, "", element_name); } data->indent -= 2; @@ -591,7 +596,7 @@ passthrough (GMarkupParseContext *context, maybe_close_starttag (data); - g_printf ("%*s%s\n", data->indent, "", text); + g_fprintf (data->output, "%*s%s\n", data->indent, "", text); } GMarkupParser parser = { @@ -603,14 +608,62 @@ GMarkupParser parser = { }; static void -do_simplify (const gchar *filename) +do_simplify (int *argc, + const char ***argv) { GMarkupParseContext *context; - GError *error = NULL; gchar *buffer; MyParserData data; + gboolean replace = FALSE; + char **filenames = NULL; + GOptionContext *ctx; + const GOptionEntry entries[] = { + { "replace", 0, 0, G_OPTION_ARG_NONE, &replace, NULL, NULL }, + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, NULL }, + { NULL, } + }; + GError *error = NULL; - if (!g_file_get_contents (filename, &buffer, NULL, &error)) + ctx = g_option_context_new (NULL); + g_option_context_set_help_enabled (ctx, FALSE); + g_option_context_add_main_entries (ctx, entries, NULL); + + if (!g_option_context_parse (ctx, argc, (char ***)argv, &error)) + { + g_printerr ("%s\n", error->message); + g_error_free (error); + exit (1); + } + + g_option_context_free (ctx); + + if (filenames == NULL) + { + g_printerr ("No .ui file specified\n"); + exit (1); + } + + if (g_strv_length (filenames) > 1) + { + g_printerr ("Can only simplify a single .ui file\n"); + exit (1); + } + + data.input_filename = filenames[0]; + data.output_filename = NULL; + + if (replace) + { + int fd; + fd = g_file_open_tmp ("gtk-builder-tool-XXXXXX", &data.output_filename, NULL); + data.output = fdopen (fd, "w"); + } + else + { + data.output = stdout; + } + + if (!g_file_get_contents (filenames[0], &buffer, NULL, &error)) { g_printerr (_("Can't load file: %s\n"), error->message); exit (1); @@ -636,6 +689,26 @@ do_simplify (const gchar *filename) g_printerr (_("Can't parse file: %s\n"), error->message); exit (1); } + + fclose (data.output); + + if (data.output_filename) + { + char *content; + gsize length; + + if (!g_file_get_contents (data.output_filename, &content, &length, &error)) + { + g_printerr ("Failed to read %s: %s\n", data.output_filename, error->message); + exit (1); + } + + if (!g_file_set_contents (data.input_filename, content, length, &error)) + { + g_printerr ("Failed to write %s: %s\n", data.input_filename, error->message); + exit (1); + } + } } static GType @@ -933,7 +1006,8 @@ do_preview (int *argc, const GOptionEntry entries[] = { { "id", 0, 0, G_OPTION_ARG_STRING, &id, NULL, NULL }, { "css", 0, 0, G_OPTION_ARG_FILENAME, &css, NULL, NULL }, - { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, NULL } + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, NULL }, + { NULL, } }; GError *error = NULL; @@ -977,10 +1051,13 @@ usage (void) "\n" "Commands:\n" " validate Validate the file\n" - " simplify Simplify the file\n" + " simplify [OPTIONS] Simplify the file\n" " enumerate List all named objects\n" " preview [OPTIONS] Preview the file\n" "\n" + "Simplify Options:\n" + " --replace Replace the file\n" + "\n" "Preview Options:\n" " --id=ID Preview only the named object\n" " --css=FILE Use style from CSS file\n" @@ -1010,7 +1087,7 @@ main (int argc, const char *argv[]) if (strcmp (argv[0], "validate") == 0) do_validate (argv[1]); else if (strcmp (argv[0], "simplify") == 0) - do_simplify (argv[1]); + do_simplify (&argc, &argv); else if (strcmp (argv[0], "enumerate") == 0) do_enumerate (argv[1]); else if (strcmp (argv[0], "preview") == 0)