From 1f4e5b72b21d35dfe22d68d2a1d480408ad30a70 Mon Sep 17 00:00:00 2001 From: Lex Trotman Date: Fri, 17 Oct 2008 08:00:22 +0000 Subject: [PATCH] The first partial prototype of project build commands. git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/branches/build-system@3108 ea778897-0a13-0410-b9d1-a72fbfd435f5 --- ChangeLog | 22 +++++ src/build.c | 217 +++++++++++++++++++++++++++++++++++++++++++------- src/build.h | 1 + src/project.c | 22 ++++- src/project.h | 6 ++ 5 files changed, 240 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index b77c543d..b092e055 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2008-10-17 Lex Trotman + + Prototype of project customisable build menu commands + + * src/build.h: + added build_default_menu() to interface, used by projects + * src/build.c: + build_make_file() changed to take commands from project or default + create_build_menu_gen() changed to create the menu from the project + settings or default & unref old menu so callable more than once + build_default_menu() added + on_includes_arguments_dialog_response() added getting the values for + the project fields + show_includes_arguments_gen() added the extra fields for project commands + * src/project.h: + added command and label fields to the project structure + * src/project.c: + update_ui() calls build_default_menu to make menu match project status + load_config() added loads for build commands & labels + write_config() added saves for build commands and labels + + 2008-10-10 Nick Treleaven * doc/geany.txt, doc/geany.html, src/about.c, THANKS: diff --git a/src/build.c b/src/build.c index 4718807e..0ce0fa1c 100644 --- a/src/build.c +++ b/src/build.c @@ -315,35 +315,45 @@ static GPid build_make_file(GeanyDocument *doc, gint build_opts) { GString *cmdstr; gchar *dir = NULL; + gchar *part1=NULL; + gchar *part2=NULL; GPid pid; if (doc == NULL || doc->file_name == NULL) return (GPid) 1; - cmdstr = g_string_new(tool_prefs.make_cmd); - g_string_append_c(cmdstr, ' '); - + part1 = tool_prefs.make_cmd; + if (build_opts == GBO_MAKE_OBJECT) { - gchar *tmp; - build_info.type = build_opts; - tmp = get_object_filename(doc); - g_string_append(cmdstr, tmp); - g_free(tmp); + if( app->project!=NULL && app->project->build_3_cmd != NULL ) + part1 = app->project->build_3_cmd; + else part2 = "\"%e.o\""; } else if (build_opts == GBO_MAKE_CUSTOM && build_info.custom_target) { build_info.type = GBO_MAKE_CUSTOM; - g_string_append(cmdstr, build_info.custom_target); + if( app->project != NULL && app->project->build_2_cmd != NULL ) + part1 = app->project->build_2_cmd; + else part2 = build_info.custom_target; dir = project_get_make_dir(); } else /* GBO_MAKE_ALL */ { build_info.type = GBO_MAKE_ALL; - g_string_append(cmdstr, "all"); + if( app->project != NULL && app->project->build_1_cmd != NULL ) + part1 = app->project->build_1_cmd; + else part2 = "all"; dir = project_get_make_dir(); } + + cmdstr = g_string_new(part1); + if( part2!=NULL ) + { + g_string_append_c(cmdstr, ' '); + g_string_append( cmdstr, part2 ); + } pid = build_spawn_cmd(doc, cmdstr->str, dir); /* if dir is NULL, idx filename is used */ g_free(dir); @@ -441,7 +451,6 @@ static GPid build_spawn_cmd(GeanyDocument *doc, const gchar *cmd, const gchar *d gint stderr_fd; g_return_val_if_fail(doc != NULL, (GPid) 1); - clear_errors(doc); setptr(current_dir_entered, NULL); @@ -1029,6 +1038,8 @@ static void add_menu_accel(GeanyKeyGroup *group, guint kb_id, static void create_build_menu_gen(BuildMenuItems *menu_items) { GtkWidget *menu, *item = NULL, *image, *separator; + struct GeanyProject *proj; + gchar *tiptext; GtkAccelGroup *accel_group = gtk_accel_group_new(); GtkTooltips *tooltips = GTK_TOOLTIPS(lookup_widget(main_widgets.window, "tooltips")); GeanyKeyGroup *group = g_ptr_array_index(keybinding_groups, GEANY_KEY_GROUP_BUILD); @@ -1061,35 +1072,60 @@ static void create_build_menu_gen(BuildMenuItems *menu_items) gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(menu), item); - /* build the code with make all */ - item = gtk_image_menu_item_new_with_mnemonic(_("_Make All")); + /* build the code with make all or prefs or project command*/ + proj = app->project; + if( proj!=NULL && proj->build_1_label!=NULL ) + { + item = gtk_image_menu_item_new_with_mnemonic( proj->build_1_label ); + tiptext = NULL; /* user label so no tip needed */ + }/* else if prefs */ + else + { + item = gtk_image_menu_item_new_with_mnemonic(_("_Make All")); + tiptext = _("Builds the current file with the make tool and the default target"); + } gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(menu), item); - gtk_tooltips_set_tip(tooltips, item, _("Builds the current file with the " - "make tool and the default target"), NULL); + if( tiptext != NULL )gtk_tooltips_set_tip(tooltips, item, tiptext, NULL); GEANY_ADD_WIDGET_ACCEL(GEANY_KEYS_BUILD_MAKE, item); g_signal_connect(item, "activate", G_CALLBACK(on_build_make_activate), GINT_TO_POINTER(GBO_MAKE_ALL)); menu_items->item_make_all = item; /* build the code with make custom */ - item = gtk_image_menu_item_new_with_mnemonic(_("Make Custom _Target")); + if( proj!=NULL && proj->build_2_label!=NULL ) + { + item = gtk_image_menu_item_new_with_mnemonic( proj->build_2_label ); + tiptext = _("Dialog contents appended to this command"); + }/* else if prefs */ + else + { + item = gtk_image_menu_item_new_with_mnemonic(_("Make Custom _Target")); + tiptext = _("Builds the current file with the make tool and the specified target"); + } gtk_widget_show(item); GEANY_ADD_WIDGET_ACCEL(GEANY_KEYS_BUILD_MAKEOWNTARGET, item); gtk_container_add(GTK_CONTAINER(menu), item); - gtk_tooltips_set_tip(tooltips, item, _("Builds the current file with the " - "make tool and the specified target"), NULL); + gtk_tooltips_set_tip(tooltips, item, tiptext, NULL); g_signal_connect(item, "activate", G_CALLBACK(on_build_make_activate), GINT_TO_POINTER(GBO_MAKE_CUSTOM)); menu_items->item_make_custom = item; /* build the code with make object */ - item = gtk_image_menu_item_new_with_mnemonic(_("Make _Object")); + if( proj!=NULL && proj->build_2_label!=NULL ) + { + item = gtk_image_menu_item_new_with_mnemonic( proj->build_2_label ); + tiptext = NULL; + }/* else if prefs */ + else + { + item = gtk_image_menu_item_new_with_mnemonic(_("Make _Object")); + tiptext = _("Compiles the current file using the make tool"); + } gtk_widget_show(item); GEANY_ADD_WIDGET_ACCEL(GEANY_KEYS_BUILD_MAKEOBJECT, item); gtk_container_add(GTK_CONTAINER(menu), item); - gtk_tooltips_set_tip(tooltips, item, _("Compiles the current file using the " - "make tool"), NULL); + gtk_tooltips_set_tip(tooltips, item, tiptext, NULL); g_signal_connect(item, "activate", G_CALLBACK(on_build_make_activate), GINT_TO_POINTER(GBO_MAKE_OBJECT)); menu_items->item_make_object = item; @@ -1132,7 +1168,7 @@ static void create_build_menu_gen(BuildMenuItems *menu_items) gtk_widget_set_sensitive(separator, FALSE); /* arguments */ - item = gtk_image_menu_item_new_with_mnemonic(_("_Set Includes and Arguments")); + item = gtk_image_menu_item_new_with_mnemonic(_("_Set Build Menu Commands")); gtk_widget_show(item); GEANY_ADD_WIDGET_ACCEL(GEANY_KEYS_BUILD_OPTIONS, item); gtk_container_add(GTK_CONTAINER(menu), item); @@ -1145,10 +1181,17 @@ static void create_build_menu_gen(BuildMenuItems *menu_items) g_signal_connect(item, "activate", G_CALLBACK(on_build_arguments_activate), NULL); menu_items->item_set_args = item; + if( menu_items->menu ) g_object_unref( (gpointer)menu_items->menu ); /* free it */ menu_items->menu = menu; g_object_ref((gpointer)menu_items->menu); /* to hold it after removing */ } +/* externally callable build default menu for when projects change menu */ + +void build_default_menu() +{ + create_build_menu_gen( &default_menu_items ); +}; static void create_build_menu_tex(BuildMenuItems *menu_items) { @@ -1501,14 +1544,56 @@ on_includes_arguments_dialog_response (GtkDialog *dialog, programs->modified = TRUE; } } + if( app->project!=NULL ) + { + struct GeanyProject *proj = app->project; + + newstr = gtk_entry_get_text( GTK_ENTRY( lookup_widget( GTK_WIDGET(dialog), "build_1_label" ) ) ); + if( !utils_str_equal( newstr, proj->build_1_label ) ) + { + if( proj->build_1_label ) g_free( proj->build_1_label ); + proj->build_1_label = g_strdup(newstr); + } + newstr = gtk_entry_get_text( GTK_ENTRY( lookup_widget( GTK_WIDGET(dialog), "build_1_cmd" ) ) ); + if( !utils_str_equal( newstr, proj->build_1_cmd ) ) + { + if( proj->build_1_cmd ) g_free( proj->build_1_cmd ); + proj->build_1_cmd = g_strdup(newstr); + } + newstr = gtk_entry_get_text( GTK_ENTRY( lookup_widget( GTK_WIDGET(dialog), "build_2_label" ) ) ); + if( !utils_str_equal( newstr, proj->build_2_label ) ) + { + if( proj->build_2_label ) g_free( proj->build_2_label ); + proj->build_2_label = g_strdup(newstr); + } + newstr = gtk_entry_get_text( GTK_ENTRY( lookup_widget( GTK_WIDGET(dialog), "build_2_cmd" ) ) ); + if( !utils_str_equal( newstr, proj->build_2_cmd ) ) + { + if( proj->build_2_cmd ) g_free( proj->build_2_cmd ); + proj->build_2_cmd = g_strdup(newstr); + } + newstr = gtk_entry_get_text( GTK_ENTRY( lookup_widget( GTK_WIDGET(dialog), "build_3_label" ) ) ); + if( !utils_str_equal( newstr, proj->build_3_label ) ) + { + if( proj->build_3_label ) g_free( proj->build_3_label ); + proj->build_3_label = g_strdup(newstr); + } + newstr = gtk_entry_get_text( GTK_ENTRY( lookup_widget( GTK_WIDGET(dialog), "build_3_cmd" ) ) ); + if( !utils_str_equal( newstr, proj->build_3_cmd ) ) + { + if( proj->build_3_cmd ) g_free( proj->build_3_cmd ); + proj->build_3_cmd = g_strdup(newstr); + } + } } } static void show_includes_arguments_gen(void) { - GtkWidget *dialog, *label, *entries[3], *vbox; + GtkWidget *dialog, *label, *entries[3], *vbox, *build_entry; GtkWidget *ft_table = NULL; + GtkWidget *pr_table = NULL; gint row = 0; gint response; GeanyDocument *doc = document_get_current(); @@ -1518,21 +1603,21 @@ static void show_includes_arguments_gen(void) ft = doc->file_type; g_return_if_fail(ft != NULL); - dialog = gtk_dialog_new_with_buttons(_("Set Includes and Arguments"), GTK_WINDOW(main_widgets.window), + dialog = gtk_dialog_new_with_buttons(_("Build Menu Commands"), GTK_WINDOW(main_widgets.window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); vbox = ui_dialog_vbox_new(GTK_DIALOG(dialog)); gtk_widget_set_name(dialog, "GeanyDialog"); - label = gtk_label_new(_("Set the commands for building and running programs.")); + label = gtk_label_new(_("Set the commands for the build menu.")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_container_add(GTK_CONTAINER(vbox), label); if (ft->actions->can_compile || ft->actions->can_link || ft->actions->can_exec) { GtkWidget *align, *frame; - /* in-dialog heading for the "Set Includes and Arguments" dialog */ + /* in-dialog heading for the file type part of the build commands dialog */ gchar *frame_title = g_strdup_printf(_("%s commands"), ft->title); frame = ui_frame_new_with_alignment(frame_title, &align); @@ -1612,6 +1697,85 @@ static void show_includes_arguments_gen(void) gtk_widget_set_sensitive(entries[2], FALSE); } + /* see if need project based command fields */ + + if( app->project!=NULL ) + { + GtkWidget *align, *frame; + /* in-dialog heading for the project part of the build commands dialog */ + gchar *frame_title = g_strdup_printf(_("%s build menu commands"), "project"); + struct GeanyProject *proj = app->project; + + frame = ui_frame_new_with_alignment(frame_title, &align); + gtk_container_add(GTK_CONTAINER(vbox), frame); + g_free(frame_title); + + pr_table = gtk_table_new(3, 3, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(pr_table), 6); + gtk_container_add(GTK_CONTAINER(align), pr_table); + + /* label and cmd 1 */ + build_entry = gtk_entry_new(); + gtk_entry_set_width_chars( GTK_ENTRY(build_entry), 10 ); + if( proj->build_1_label!=NULL ) + { + gtk_entry_set_text( GTK_ENTRY(build_entry), proj->build_1_label ); + } + gtk_table_attach_defaults( GTK_TABLE(pr_table), build_entry, 0, 1, 0, 1 ); + g_object_set_data_full( G_OBJECT(dialog), "build_1_label", + gtk_widget_ref(build_entry), (GDestroyNotify)gtk_widget_unref ); + build_entry = gtk_entry_new(); + gtk_entry_set_width_chars( GTK_ENTRY(build_entry), 30 ); + if( proj->build_1_cmd!=NULL ) + { + gtk_entry_set_text( GTK_ENTRY(build_entry), proj->build_1_cmd ); + } + gtk_table_attach_defaults( GTK_TABLE(pr_table), build_entry, 1, 3, 0, 1 ); + g_object_set_data_full(G_OBJECT(dialog), "build_1_cmd", + gtk_widget_ref(build_entry), (GDestroyNotify)gtk_widget_unref); + + /* label and cmd 2 */ + build_entry = gtk_entry_new(); + gtk_entry_set_width_chars( GTK_ENTRY(build_entry), 10 ); + if( proj->build_2_label!=NULL ) + { + gtk_entry_set_text( GTK_ENTRY(build_entry), proj->build_2_label ); + } + gtk_table_attach_defaults( GTK_TABLE(pr_table), build_entry, 0, 1, 1, 2 ); + g_object_set_data_full( G_OBJECT(dialog), "build_2_label", + gtk_widget_ref(build_entry), (GDestroyNotify)gtk_widget_unref ); + build_entry = gtk_entry_new(); + gtk_entry_set_width_chars( GTK_ENTRY(build_entry), 30 ); + if( proj->build_2_cmd!=NULL ) + { + gtk_entry_set_text( GTK_ENTRY(build_entry), proj->build_2_cmd ); + } + gtk_table_attach_defaults( GTK_TABLE(pr_table), build_entry, 1, 3, 1, 2 ); + g_object_set_data_full(G_OBJECT(dialog), "build_2_cmd", + gtk_widget_ref(build_entry), (GDestroyNotify)gtk_widget_unref); + + /* label and cmd 3 */ + build_entry = gtk_entry_new(); + gtk_entry_set_width_chars( GTK_ENTRY(build_entry), 10 ); + if( proj->build_3_label!=NULL ) + { + gtk_entry_set_text( GTK_ENTRY(build_entry), proj->build_3_label ); + } + gtk_table_attach_defaults( GTK_TABLE(pr_table), build_entry, 0, 1, 2, 3 ); + g_object_set_data_full( G_OBJECT(dialog), "build_3_label", + gtk_widget_ref(build_entry), (GDestroyNotify)gtk_widget_unref ); + build_entry = gtk_entry_new(); + gtk_entry_set_width_chars( GTK_ENTRY(build_entry), 30 ); + if( proj->build_3_cmd!=NULL ) + { + gtk_entry_set_text( GTK_ENTRY(build_entry), proj->build_3_cmd ); + } + gtk_table_attach_defaults( GTK_TABLE(pr_table), build_entry, 1, 3, 2, 3 ); + g_object_set_data_full(G_OBJECT(dialog), "build_3_cmd", + gtk_widget_ref(build_entry), (GDestroyNotify)gtk_widget_unref); + + } + label = gtk_label_new(_("%f will be replaced by the current filename, e.g. test_file.c\n" "%e will be replaced by the filename without extension, e.g. test_file")); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); @@ -1690,7 +1854,6 @@ void build_menu_update(GeanyDocument *doc) can_build = can_make && ! is_c_header(doc->file_name); else can_build = can_make; - if (menu_items->item_compile) gtk_widget_set_sensitive(menu_items->item_compile, can_build && ft->actions->can_compile); if (menu_items->item_link) diff --git a/src/build.h b/src/build.h index 3ae096e4..57d5e4f0 100644 --- a/src/build.h +++ b/src/build.h @@ -74,5 +74,6 @@ void build_menu_update(GeanyDocument *doc); BuildMenuItems *build_get_menu_items(gint filetype_idx); +void build_default_menu(); #endif diff --git a/src/project.c b/src/project.c index c22a61ad..a7858e6e 100644 --- a/src/project.c +++ b/src/project.c @@ -296,6 +296,7 @@ void project_open() /* Called when creating, opening, closing and updating projects. */ static void update_ui(void) { + build_default_menu(); ui_set_window_title(NULL); build_menu_update(NULL); } @@ -901,6 +902,13 @@ static gboolean load_config(const gchar *filename) p->make_in_base_path = utils_get_setting_boolean(config, "project", "make_in_base_path", TRUE); p->run_cmd = utils_get_setting_string(config, "project", "run_cmd", ""); p->file_patterns = g_key_file_get_string_list(config, "project", "file_patterns", NULL, NULL); + + p->build_1_cmd = utils_get_setting_string(config, "build_menu", "cmd_1", NULL ); + p->build_2_cmd = utils_get_setting_string(config, "build_menu", "cmd_2", NULL ); + p->build_3_cmd = utils_get_setting_string(config, "build_menu", "cmd_3", NULL ); + p->build_1_label = utils_get_setting_string(config, "build_menu", "label_1", NULL ); + p->build_2_label = utils_get_setting_string(config, "build_menu", "label_2", NULL ); + p->build_3_label = utils_get_setting_string(config, "build_menu", "label_3", NULL ); if (project_prefs.project_session) { @@ -951,8 +959,20 @@ static gboolean write_config(gboolean emit_signal) if (p->description) g_key_file_set_string(config, "project", "description", p->description); g_key_file_set_boolean(config, "project", "make_in_base_path", p->make_in_base_path); - if (p->run_cmd) + if (p->run_cmd) /* left in project section for backward compatibility */ g_key_file_set_string(config, "project", "run_cmd", p->run_cmd); + if (p->build_1_cmd) + g_key_file_set_string(config, "build_menu", "cmd_1", p->build_1_cmd); + if (p->build_2_cmd) + g_key_file_set_string(config, "build_menu", "cmd_2", p->build_2_cmd); + if (p->build_3_cmd) + g_key_file_set_string(config, "build_menu", "cmd_3", p->build_3_cmd); + if (p->build_1_label) + g_key_file_set_string(config, "build_menu", "label_1", p->build_1_label); + if (p->build_2_label) + g_key_file_set_string(config, "build_menu", "label_2", p->build_2_label); + if (p->build_3_label) + g_key_file_set_string(config, "build_menu", "label_3", p->build_3_label); if (p->file_patterns) g_key_file_set_string_list(config, "project", "file_patterns", (const gchar**) p->file_patterns, g_strv_length(p->file_patterns)); diff --git a/src/project.h b/src/project.h index 9ffe8b5b..86bfa2c8 100644 --- a/src/project.h +++ b/src/project.h @@ -36,6 +36,12 @@ typedef struct GeanyProject gchar *file_name; /**< Where the project file is stored (in UTF-8). */ gchar *base_path; /**< Base path of the project directory (in UTF-8, maybe relative). */ gchar *run_cmd; /**< Project run command (in UTF-8). */ + gchar *build_1_cmd; /**< Project build menu item 1 cmd (in UTF-8). */ + gchar *build_2_cmd; /**< Project build menu item 2 cmd (in UTF-8). */ + gchar *build_3_cmd; /**< Project build menu item 3 cmd (in UTF-8). */ + gchar *build_1_label; /**< Project build menu item 1 label (in UTF-8). */ + gchar *build_2_label; /**< Project build menu item 2 label (in UTF-8). */ + gchar *build_3_label; /**< Project build menu item 3 label (in UTF-8). */ /** Identifier whether it is a pure Geany project or modified/extended * by a plugin. */ gint type;