2 * build.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2005-2010 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5 * Copyright 2006-2010 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
6 * Copyright 2009 Lex Trotman <elextr(at)gmail(dot)com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 * Build commands and menu items.
37 #include <glib/gstdio.h>
40 # include <sys/types.h>
41 # include <sys/wait.h>
53 #include "msgwindow.h"
54 #include "filetypes.h"
55 #include "keybindings.h"
61 #include "geanymenubuttonaction.h"
63 /* Number of editor indicators to draw - limited as this can affect performance */
64 #define GEANY_BUILD_ERR_HIGHLIGHT_MAX 50
67 GeanyBuildInfo build_info
= {GEANY_GBG_FT
, 0, 0, NULL
, GEANY_FILETYPES_NONE
, NULL
, 0};
69 static gchar
*current_dir_entered
= NULL
;
71 typedef struct RunInfo
77 static RunInfo
*run_info
;
80 static const gchar RUN_SCRIPT_CMD
[] = "geany_run_script.bat";
82 static const gchar RUN_SCRIPT_CMD
[] = "./geany_run_script.sh";
85 /* pack group (<8) and command (<32) into a user_data pointer */
86 #define GRP_CMD_TO_POINTER(grp, cmd) GINT_TO_POINTER((((grp)&7) << 5) | ((cmd)&0x1f))
87 #define GBO_TO_POINTER(gbo) (GRP_CMD_TO_POINTER(GBO_TO_GBG(gbo), GBO_TO_CMD(gbo)))
88 #define GPOINTER_TO_CMD(gptr) (GPOINTER_TO_INT(gptr)&0x1f)
89 #define GPOINTER_TO_GRP(gptr) ((GPOINTER_TO_INT(gptr)&0xe0) >> 5)
91 static gpointer last_toolbutton_action
= GBO_TO_POINTER(GEANY_GBO_BUILD
);
93 static BuildMenuItems menu_items
= {NULL
, {NULL
, NULL
, NULL
, NULL
}};
97 GtkAction
*run_action
;
98 GtkAction
*compile_action
;
99 GtkAction
*build_action
;
102 GtkWidget
*toolitem_build
;
103 GtkWidget
*toolitem_make_all
;
104 GtkWidget
*toolitem_make_custom
;
105 GtkWidget
*toolitem_make_object
;
106 GtkWidget
*toolitem_set_args
;
110 static gint build_groups_count
[GEANY_GBG_COUNT
] = { 3, 4, 2 };
111 static gint build_items_count
= 9;
114 static void build_exit_cb(GPid child_pid
, gint status
, gpointer user_data
);
115 static gboolean
build_iofunc(GIOChannel
*ioc
, GIOCondition cond
, gpointer data
);
117 static gboolean
build_create_shellscript(const gchar
*fname
, const gchar
*cmd
, gboolean autoclose
);
118 static GPid
build_spawn_cmd(GeanyDocument
*doc
, const gchar
*cmd
, const gchar
*dir
);
119 static void set_stop_button(gboolean stop
);
120 static void run_exit_cb(GPid child_pid
, gint status
, gpointer user_data
);
121 static void on_set_build_commands_activate(GtkWidget
*w
, gpointer u
);
122 static void on_build_next_error(GtkWidget
*menuitem
, gpointer user_data
);
123 static void on_build_previous_error(GtkWidget
*menuitem
, gpointer user_data
);
124 static void kill_process(GPid
*pid
);
125 static void show_build_result_message(gboolean failure
);
126 static void process_build_output_line(const gchar
*line
, gint color
);
127 static void show_build_commands_dialog(void);
130 void build_finalize(void)
132 g_free(build_info
.dir
);
133 g_free(build_info
.custom_target
);
135 if (menu_items
.menu
!= NULL
&& GTK_IS_WIDGET(menu_items
.menu
))
136 gtk_widget_destroy(menu_items
.menu
);
140 /* note: copied from keybindings.c, may be able to go away */
141 static void add_menu_accel(GeanyKeyGroup
*group
, guint kb_id
,
142 GtkAccelGroup
*accel_group
, GtkWidget
*menuitem
)
144 GeanyKeyBinding
*kb
= keybindings_get_item(group
, kb_id
);
147 gtk_widget_add_accelerator(menuitem
, "activate", accel_group
,
148 kb
->key
, kb
->mods
, GTK_ACCEL_VISIBLE
);
152 /* convenience routines to access parts of GeanyBuildCommand */
153 static gchar
*id_to_str(GeanyBuildCommand
*bc
, gint id
)
155 return bc
->entries
[id
];
159 static gchar
*buildcmd_label(GeanyBuildCommand
*bc
)
161 return _(id_to_str(bc
, GEANY_BC_LABEL
));
165 static gchar
*buildcmd_cmd(GeanyBuildCommand
*bc
)
167 return id_to_str(bc
, GEANY_BC_COMMAND
);
171 static gchar
*buildcmd_working_dir(GeanyBuildCommand
*bc
)
173 return id_to_str(bc
, GEANY_BC_WORKING_DIR
);
177 static const gchar
*config_keys
[] = {
178 [GEANY_BC_LABEL
] = "LB",
179 [GEANY_BC_COMMAND
] = "CM",
180 [GEANY_BC_WORKING_DIR
] = "WD"
183 /*-----------------------------------------------------
185 * Execute commands and handle results
187 *-----------------------------------------------------*/
189 /* the various groups of commands not in the filetype struct */
190 static GeanyBuildCommand
*ft_def
= NULL
;
191 static GeanyBuildCommand
*non_ft_proj
= NULL
;
192 static GeanyBuildCommand
*non_ft_pref
= NULL
;
193 static GeanyBuildCommand
*non_ft_def
= NULL
;
194 static GeanyBuildCommand
*exec_proj
= NULL
;
195 static GeanyBuildCommand
*exec_pref
= NULL
;
196 static GeanyBuildCommand
*exec_def
= NULL
;
197 /* and the regexen not in the filetype structure */
198 static gchar
*regex_pref
= NULL
;
199 /* project non-fileregex string */
200 static gchar
*regex_proj
= NULL
;
202 /* control if build commands are printed by get_build_cmd, for debug purposes only*/
203 #ifndef PRINTBUILDCMDS
204 #define PRINTBUILDCMDS FALSE
206 static gboolean printbuildcmds
= PRINTBUILDCMDS
;
209 /* for debug only, print the commands structures in priority order */
210 static void printfcmds(void)
212 GeanyBuildCommand
**cl
[GEANY_GBG_COUNT
][GEANY_BCS_COUNT
] = {
213 /* GEANY_BCS_DEF, GEANY_BCS_FT, GEANY_BCS_HOME_FT, GEANY_BCS_PREF,
214 * GEANY_BCS_FT_PROJ, GEANY_BCS_PROJ */
215 { &ft_def
, NULL
, NULL
, NULL
, NULL
, NULL
},
216 { &non_ft_def
, NULL
, NULL
, &non_ft_pref
, NULL
, &non_ft_proj
},
217 { &exec_def
, NULL
, NULL
, &exec_pref
, NULL
, &exec_proj
}
219 GeanyFiletype
*ft
= NULL
;
222 enum GeanyBuildCmdEntries n
;
223 gint cc
[GEANY_BCS_COUNT
];
226 doc
= document_get_current();
231 printf("filetype %s\n",ft
->name
);
232 cl
[GEANY_GBG_FT
][GEANY_BCS_FT
] = &(ft
->filecmds
);
233 cl
[GEANY_GBG_FT
][GEANY_BCS_HOME_FT
] = &(ft
->homefilecmds
);
234 cl
[GEANY_GBG_FT
][GEANY_BCS_PROJ
] = &(ft
->projfilecmds
);
235 cl
[GEANY_GBG_NON_FT
][GEANY_BCS_FT
] = &(ft
->ftdefcmds
);
236 cl
[GEANY_GBG_EXEC
][GEANY_BCS_FT
] = &(ft
->execcmds
);
237 cl
[GEANY_GBG_EXEC
][GEANY_BCS_HOME_FT
] = &(ft
->homeexeccmds
);
238 cl
[GEANY_GBG_EXEC
][GEANY_BCS_PROJ_FT
] = &(ft
->projexeccmds
);
240 for (i
= 0; i
< GEANY_BCS_COUNT
; ++i
)
243 for (j
= 0; j
< GEANY_GBG_COUNT
; ++j
)
245 for (k
= 0; k
< build_groups_count
[j
]; ++k
)
246 if (cl
[j
][i
] != NULL
&& *(cl
[j
][i
]) != NULL
&& (*(cl
[j
][i
]))[k
].exists
)
248 for (n
= 0; n
< GEANY_BC_CMDENTRIES_COUNT
; n
++)
250 if ((*(cl
[j
][i
]))[k
].entries
[n
] != NULL
&&
251 (l
= strlen((*(cl
[j
][i
]))[k
].entries
[n
])) > m
)
260 for (i
= 0; i
< GEANY_GBG_COUNT
; ++i
)
262 for (k
= 0; k
< build_groups_count
[i
]; ++k
)
264 for (l
= 0; l
< 2; ++l
)
267 for (j
= 0; j
< GEANY_BCS_COUNT
; ++j
)
269 if (cl
[i
][j
] != NULL
&& *(cl
[i
][j
]) != NULL
&& (*(cl
[i
][j
]))[k
].exists
)
271 for (n
= 0; n
< GEANY_BC_CMDENTRIES_COUNT
; n
++)
273 if ((*(cl
[i
][j
]))[k
].entries
[i
] != NULL
)
274 printf("%c %*.*s",c
,cc
[j
],cc
[j
],(*(cl
[i
][j
]))[k
].entries
[i
]);
276 printf("%c %*.*s",c
,cc
[j
],cc
[j
]," ");
280 printf("%c %*.*s",c
,cc
[j
],cc
[j
]," ");
291 /* macros to save typing and make the logic visible */
292 #define return_cmd_if(src, cmds)\
293 if (cmds != NULL && cmds[cmdindex].exists && below>src)\
296 if (printbuildcmds) \
297 printf("cmd[%d,%d]=%d\n",cmdgrp,cmdindex,src); \
298 return &(cmds[cmdindex]); \
301 #define return_ft_cmd_if(src, cmds)\
302 if (ft != NULL && ft->cmds != NULL \
303 && ft->cmds[cmdindex].exists && below>src)\
306 if (printbuildcmds) \
307 printf("cmd[%d,%d]=%d\n",cmdgrp,cmdindex,src); \
308 return &(ft->cmds[cmdindex]); \
312 /* get the next lowest command taking priority into account */
313 static GeanyBuildCommand
*get_next_build_cmd(GeanyDocument
*doc
, gint cmdgrp
, gint cmdindex
,
314 gint below
, gint
*from
)
316 /* Note: parameter below used in macros above */
317 GeanyFiletype
*ft
= NULL
;
318 gint sink
, *fr
= &sink
;
322 if (cmdgrp
>= GEANY_GBG_COUNT
)
327 doc
= document_get_current();
333 case GEANY_GBG_FT
: /* order proj ft, home ft, ft, defft */
336 return_ft_cmd_if(GEANY_BCS_PROJ
, projfilecmds
);
337 return_ft_cmd_if(GEANY_BCS_PREF
, homefilecmds
);
338 return_ft_cmd_if(GEANY_BCS_FT
, filecmds
);
340 return_cmd_if(GEANY_BCS_DEF
, ft_def
);
342 case GEANY_GBG_NON_FT
: /* order proj, pref, def */
343 return_cmd_if(GEANY_BCS_PROJ
, non_ft_proj
);
344 return_cmd_if(GEANY_BCS_PREF
, non_ft_pref
);
345 return_ft_cmd_if(GEANY_BCS_FT
, ftdefcmds
);
346 return_cmd_if(GEANY_BCS_DEF
, non_ft_def
);
348 case GEANY_GBG_EXEC
: /* order proj, proj ft, pref, home ft, ft, def */
349 return_cmd_if(GEANY_BCS_PROJ
, exec_proj
);
350 return_ft_cmd_if(GEANY_BCS_PROJ_FT
, projexeccmds
);
351 return_cmd_if(GEANY_BCS_PREF
, exec_pref
);
352 return_ft_cmd_if(GEANY_BCS_FT
, homeexeccmds
);
353 return_ft_cmd_if(GEANY_BCS_FT
, execcmds
);
354 return_cmd_if(GEANY_BCS_DEF
, exec_def
);
363 /* shortcut to start looking at the top */
364 static GeanyBuildCommand
*get_build_cmd(GeanyDocument
*doc
, gint grp
, gint cmdindex
, gint
*from
)
366 return get_next_build_cmd(doc
, grp
, cmdindex
, GEANY_BCS_COUNT
, from
);
370 #define return_nonblank_regex(src, ptr)\
372 { *fr = (src); return &(ptr); }
375 /* like get_build_cmd, but for regexen, used by filetypes */
376 gchar
**build_get_regex(GeanyBuildGroup grp
, GeanyFiletype
*ft
, gint
*from
)
378 gint sink
, *fr
= &sink
;
382 if (grp
== GEANY_GBG_FT
)
386 GeanyDocument
*doc
= document_get_current();
392 return_nonblank_regex(GEANY_BCS_PROJ
, ft
->projerror_regex_string
);
393 return_nonblank_regex(GEANY_BCS_HOME_FT
, ft
->homeerror_regex_string
);
394 return_nonblank_regex(GEANY_BCS_FT
, ft
->error_regex_string
);
396 else if (grp
== GEANY_GBG_NON_FT
)
398 return_nonblank_regex(GEANY_BCS_PROJ
, regex_proj
);
399 return_nonblank_regex(GEANY_BCS_PREF
, regex_pref
);
405 /* get pointer to the command group array */
406 static GeanyBuildCommand
*get_build_group(GeanyBuildSource src
, GeanyBuildGroup grp
)
409 GeanyFiletype
*ft
= NULL
;
414 if ((doc
= document_get_current()) == NULL
)
416 if ((ft
= doc
->file_type
) == NULL
)
421 case GEANY_BCS_DEF
: return ft
->ftdefcmds
;
422 case GEANY_BCS_FT
: return ft
->filecmds
;
423 case GEANY_BCS_HOME_FT
: return ft
->homefilecmds
;
424 case GEANY_BCS_PREF
: return ft
->homefilecmds
;
425 case GEANY_BCS_PROJ
: return ft
->projfilecmds
;
426 default: return NULL
;
429 case GEANY_GBG_NON_FT
:
432 case GEANY_BCS_DEF
: return non_ft_def
;
433 case GEANY_BCS_PREF
: return non_ft_pref
;
434 case GEANY_BCS_PROJ
: return non_ft_proj
;
435 default: return NULL
;
439 if ((doc
= document_get_current()) != NULL
)
443 case GEANY_BCS_DEF
: return exec_def
;
444 case GEANY_BCS_FT
: return ft
? ft
->execcmds
: NULL
;
445 case GEANY_BCS_HOME_FT
: return ft
? ft
->homeexeccmds
: NULL
;
446 case GEANY_BCS_PROJ_FT
: return ft
? ft
->projexeccmds
: NULL
;
447 case GEANY_BCS_PREF
: return exec_pref
;
448 case GEANY_BCS_PROJ
: return exec_proj
;
449 default: return NULL
;
458 /** Remove the specified Build menu item.
460 * Makes the specified menu item configuration no longer exist. This
461 * is different to setting fields to blank because the menu item
462 * will be deleted from the configuration file on saving
463 * (except the system filetypes settings @see Build Menu Configuration
464 * section of the Manual).
466 * @param src the source of the menu item to remove.
467 * @param grp the group of the command to remove.
468 * @param cmd the index (from 0) of the command within the group. A negative
469 * value will remove the whole group.
471 * If any parameter is out of range does nothing.
473 * @see build_menu_update
475 void build_remove_menu_item(GeanyBuildSource src
, GeanyBuildGroup grp
, gint cmd
)
477 GeanyBuildCommand
*bc
;
480 bc
= get_build_group(src
, grp
);
485 for (i
= 0; i
< build_groups_count
[grp
]; ++i
)
486 bc
[i
].exists
= FALSE
;
488 else if (cmd
< build_groups_count
[grp
])
489 bc
[cmd
].exists
= FALSE
;
493 /** Get the @a GeanyBuildCommand structure for the specified Build menu item.
495 * Get the command for any menu item specified by @a src, @a grp and @a cmd even if it is
496 * hidden by higher priority commands.
498 * @param src the source of the specified menu item.
499 * @param grp the group of the specified menu item.
500 * @param cmd the index of the command within the group.
502 * @return a pointer to the @a GeanyBuildCommand structure or @a NULL if it doesn't exist.
503 * This is a pointer to an internal structure and must not be freed.
505 * @see build_menu_update
507 GeanyBuildCommand
*build_get_menu_item(GeanyBuildSource src
, GeanyBuildGroup grp
, gint cmd
)
509 GeanyBuildCommand
*bc
;
511 if (src
>= GEANY_BCS_COUNT
|| grp
>= GEANY_GBG_COUNT
|| cmd
>= build_groups_count
[grp
])
513 bc
= get_build_group(src
, grp
);
520 /** Get the @a GeanyBuildCommand structure for the menu item.
522 * Get the current highest priority command specified by @a grp and @a cmd. This is the one
523 * that the menu item will use if activated.
525 * @param grp the group of the specified menu item.
526 * @param cmd the index of the command within the group.
527 * @param src pointer to @a gint to return which source provided the command. Ignored if @a NULL.
528 * Values are one of @a GeanyBuildSource but returns a signed type not the enum.
530 * @return a pointer to the @a GeanyBuildCommand structure or @a NULL if it doesn't exist.
531 * This is a pointer to an internal structure and must not be freed.
533 * @see build_menu_update
535 /* parameter checked version of get_build_cmd for external interface */
536 GeanyBuildCommand
*build_get_current_menu_item(GeanyBuildGroup grp
, gint cmd
, gint
*src
)
538 if (*src
>= GEANY_BCS_COUNT
|| grp
>= GEANY_GBG_COUNT
|| cmd
>= build_groups_count
[grp
])
540 return get_build_cmd(NULL
, grp
, cmd
, src
);
544 /* Clear all error indicators in all documents. */
545 static void clear_errors(GeanyDocument
*doc
)
549 for (i
= 0; i
< documents_array
->len
; i
++)
551 if (documents
[i
]->is_valid
)
552 editor_indicator_clear_errors(documents
[i
]->editor
);
558 static void parse_build_output(const gchar
**output
, gint status
)
561 gchar
*line
, **lines
;
563 for (x
= 0; x
< 2; x
++)
567 lines
= g_strsplit_set(output
[x
], "\r\n", -1);
568 len
= g_strv_length(lines
);
570 for (i
= 0; i
< len
; i
++)
575 while (*line
!= '\0')
576 { /* replace any conrol characters in the output */
581 process_build_output_line(lines
[i
], COLOR_BLACK
);
588 show_build_result_message(status
!= 0);
592 /* enable build items again */
593 build_menu_update(NULL
);
598 /* Replaces occurences of %e and %p with the appropriate filenames,
599 * %d and %p replacements should be in UTF8 */
600 static gchar
*build_replace_placeholder(const GeanyDocument
*doc
, const gchar
*src
)
603 gchar
*filename
= NULL
;
605 gchar
*executable
= NULL
;
606 gchar
*ret_str
; /* to be freed when not in use anymore */
608 stack
= g_string_new(src
);
609 if (doc
!= NULL
&& doc
->file_name
!= NULL
)
611 filename
= utils_get_utf8_from_locale(doc
->file_name
);
613 /* replace %f with the filename (including extension) */
614 replacement
= g_path_get_basename(filename
);
615 utils_string_replace_all(stack
, "%f", replacement
);
618 /* replace %d with the absolute path of the dir of the current file */
619 replacement
= g_path_get_dirname(filename
);
620 utils_string_replace_all(stack
, "%d", replacement
);
623 /* replace %e with the filename (excluding extension) */
624 executable
= utils_remove_ext_from_filename(filename
);
625 replacement
= g_path_get_basename(executable
);
626 utils_string_replace_all(stack
, "%e", replacement
);
630 /* replace %p with the current project's (absolute) base directory */
631 replacement
= NULL
; /* prevent double free if no replacement found */
634 replacement
= project_get_base_path();
636 else if (strstr(stack
->str
, "%p"))
637 { /* fall back to %d */
638 ui_set_statusbar(FALSE
, _("failed to substitute %%p, no project active"));
639 if (doc
!= NULL
&& filename
!= NULL
)
640 replacement
= g_path_get_dirname(filename
);
643 utils_string_replace_all(stack
, "%p", replacement
);
646 ret_str
= utils_get_utf8_from_locale(stack
->str
);
649 g_string_free(stack
, TRUE
);
651 return ret_str
; /* don't forget to free src also if needed */
655 /* dir is the UTF-8 working directory to run cmd in. It can be NULL to use the
656 * idx document directory */
657 static GPid
build_spawn_cmd(GeanyDocument
*doc
, const gchar
*cmd
, const gchar
*dir
)
659 GError
*error
= NULL
;
662 gchar
*utf8_working_dir
;
664 gchar
*utf8_cmd_string
;
673 if (!((doc
!= NULL
&& NZV(doc
->file_name
)) || NZV(dir
)))
675 geany_debug("Failed to run command with no working directory");
676 ui_set_statusbar(TRUE
, _("Process failed, no working directory"));
682 setptr(current_dir_entered
, NULL
);
684 cmd_string
= g_strdup(cmd
);
687 argv
= g_strsplit(cmd_string
, " ", 0);
689 argv
= g_new0(gchar
*, 4);
690 argv
[0] = g_strdup("/bin/sh");
691 argv
[1] = g_strdup("-c");
692 argv
[2] = cmd_string
;
696 utf8_cmd_string
= utils_get_utf8_from_locale(cmd_string
);
697 utf8_working_dir
= NZV(dir
) ? g_strdup(dir
) : g_path_get_dirname(doc
->file_name
);
698 working_dir
= utils_get_locale_from_utf8(utf8_working_dir
);
700 gtk_list_store_clear(msgwindow
.store_compiler
);
701 gtk_notebook_set_current_page(GTK_NOTEBOOK(msgwindow
.notebook
), MSG_COMPILER
);
702 msgwin_compiler_add(COLOR_BLUE
, _("%s (in directory: %s)"), utf8_cmd_string
, utf8_working_dir
);
703 g_free(utf8_working_dir
);
704 g_free(utf8_cmd_string
);
706 /* set the build info for the message window */
707 g_free(build_info
.dir
);
708 build_info
.dir
= g_strdup(working_dir
);
709 build_info
.file_type_id
= (doc
== NULL
) ? GEANY_FILETYPES_NONE
: FILETYPE_ID(doc
->file_type
);
710 build_info
.message_count
= 0;
713 if (! utils_spawn_sync(working_dir
, argv
, NULL
, G_SPAWN_SEARCH_PATH
,
714 NULL
, NULL
, &output
[0], &output
[1], &status
, &error
))
716 if (! g_spawn_async_with_pipes(working_dir
, argv
, NULL
,
717 G_SPAWN_SEARCH_PATH
| G_SPAWN_DO_NOT_REAP_CHILD
, NULL
, NULL
,
718 &(build_info
.pid
), NULL
, &stdout_fd
, &stderr_fd
, &error
))
721 geany_debug("g_spawn_async_with_pipes() failed: %s", error
->message
);
722 ui_set_statusbar(TRUE
, _("Process failed (%s)"), error
->message
);
731 parse_build_output((const gchar
**) output
, status
);
735 if (build_info
.pid
> 0)
737 g_child_watch_add(build_info
.pid
, (GChildWatchFunc
) build_exit_cb
, NULL
);
738 build_menu_update(doc
);
739 ui_progress_bar_start(NULL
);
742 /* use GIOChannels to monitor stdout and stderr */
743 utils_set_up_io_channel(stdout_fd
, G_IO_IN
| G_IO_PRI
| G_IO_ERR
| G_IO_HUP
| G_IO_NVAL
,
744 TRUE
, build_iofunc
, GINT_TO_POINTER(0));
745 utils_set_up_io_channel(stderr_fd
, G_IO_IN
| G_IO_PRI
| G_IO_ERR
| G_IO_HUP
| G_IO_NVAL
,
746 TRUE
, build_iofunc
, GINT_TO_POINTER(1));
752 return build_info
.pid
;
756 /* Returns: NULL if there was an error, or the working directory the script was created in.
757 * vte_cmd_nonscript is the location of a string which is filled with the command to be used
758 * when vc->skip_run_script is set, otherwise it will be set to NULL */
759 static gchar
*prepare_run_script(GeanyDocument
*doc
, gchar
**vte_cmd_nonscript
, gint cmdindex
)
761 gchar
*locale_filename
= NULL
;
762 gboolean have_project
;
763 GeanyProject
*project
= app
->project
;
764 GeanyBuildCommand
*cmd
= NULL
;
765 gchar
*executable
= NULL
;
766 gchar
*working_dir
= NULL
;
767 const gchar
*cmd_working_dir
;
768 gboolean autoclose
= FALSE
;
769 gboolean result
= FALSE
;
773 if (vte_cmd_nonscript
!= NULL
)
774 *vte_cmd_nonscript
= NULL
;
776 locale_filename
= utils_get_locale_from_utf8(doc
->file_name
);
778 have_project
= project
!= NULL
;
779 cmd
= get_build_cmd(doc
, GEANY_GBG_EXEC
, cmdindex
, NULL
);
781 cmd_string
= build_replace_placeholder(doc
, buildcmd_cmd(cmd
));
782 cmd_working_dir
= buildcmd_working_dir(cmd
);
783 if (! NZV(cmd_working_dir
))
784 cmd_working_dir
= "%d";
785 working_dir
= build_replace_placeholder(doc
, cmd_working_dir
); /* in utf-8 */
787 /* only test whether working dir exists, don't change it or else Windows support will break
788 * (gspawn-win32-helper.exe is used by GLib and must be in $PATH which means current working
789 * dir where geany.exe was started from, so we can't change it) */
790 if (!NZV(working_dir
) || ! g_file_test(working_dir
, G_FILE_TEST_EXISTS
) ||
791 ! g_file_test(working_dir
, G_FILE_TEST_IS_DIR
))
793 ui_set_statusbar(TRUE
, _("Failed to change the working directory to \"%s\""),
794 NZV(working_dir
) ? working_dir
: "<NULL>" );
795 utils_free_pointers(2, cmd_string
, working_dir
, NULL
);
800 if (vte_info
.load_vte
&& vc
!= NULL
&& vc
->run_in_vte
)
802 if (vc
->skip_run_script
)
804 if (vte_cmd_nonscript
!= NULL
)
805 *vte_cmd_nonscript
= cmd_string
;
807 utils_free_pointers(2, executable
, locale_filename
, NULL
);
811 /* don't wait for user input at the end of script when we are running in VTE */
816 /* RUN_SCRIPT_CMD should be ok in UTF8 without converting in locale because it
817 * contains no umlauts */
818 tmp
= g_build_filename(working_dir
, RUN_SCRIPT_CMD
, NULL
);
819 result
= build_create_shellscript(tmp
, cmd_string
, autoclose
);
822 ui_set_statusbar(TRUE
, _("Failed to execute \"%s\" (start-script could not be created)"),
823 NZV(cmd_string
) ? cmd_string
: NULL
);
826 utils_free_pointers(4, cmd_string
, tmp
, executable
, locale_filename
, NULL
);
836 static GPid
build_run_cmd(GeanyDocument
*doc
, gint cmdindex
)
839 gchar
*vte_cmd_nonscript
= NULL
;
840 GError
*error
= NULL
;
842 if (doc
== NULL
|| doc
->file_name
== NULL
)
845 working_dir
= prepare_run_script(doc
, &vte_cmd_nonscript
, cmdindex
);
846 if (working_dir
== NULL
)
849 run_info
[cmdindex
].file_type_id
= FILETYPE_ID(doc
->file_type
);
852 if (vte_info
.load_vte
&& vc
!= NULL
&& vc
->run_in_vte
)
856 if (vc
->skip_run_script
)
858 setptr(vte_cmd_nonscript
, utils_get_utf8_from_locale(vte_cmd_nonscript
));
859 vte_cmd
= g_strconcat(vte_cmd_nonscript
, "\n", NULL
);
860 g_free(vte_cmd_nonscript
);
863 vte_cmd
= g_strconcat("\n/bin/sh ", RUN_SCRIPT_CMD
, "\n", NULL
);
865 /* change into current directory if it is not done by default */
866 if (! vc
->follow_path
)
868 /* we need to convert the working_dir back to UTF-8 because the VTE expects it */
869 gchar
*utf8_working_dir
= utils_get_utf8_from_locale(working_dir
);
870 vte_cwd(utf8_working_dir
, TRUE
);
871 g_free(utf8_working_dir
);
873 if (! vte_send_cmd(vte_cmd
))
875 ui_set_statusbar(FALSE
,
876 _("Could not execute the file in the VTE because it probably contains a command."));
877 geany_debug("Could not execute the file in the VTE because it probably contains a command.");
881 gtk_notebook_set_current_page(GTK_NOTEBOOK(msgwindow
.notebook
), MSG_VTE
);
882 gtk_widget_grab_focus(vc
->vte
);
883 msgwin_show_hide(TRUE
);
885 run_info
[cmdindex
].pid
= 1;
892 gchar
*locale_term_cmd
= NULL
;
893 gchar
**term_argv
= NULL
;
894 guint term_argv_len
, i
;
897 /* get the terminal path */
898 locale_term_cmd
= utils_get_locale_from_utf8(tool_prefs
.term_cmd
);
899 /* split the term_cmd, so arguments will work too */
900 term_argv
= g_strsplit(locale_term_cmd
, " ", -1);
901 term_argv_len
= g_strv_length(term_argv
);
903 /* check that terminal exists (to prevent misleading error messages) */
904 if (term_argv
[0] != NULL
)
906 gchar
*tmp
= term_argv
[0];
907 /* g_find_program_in_path checks whether tmp exists and is executable */
908 term_argv
[0] = g_find_program_in_path(tmp
);
911 if (term_argv
[0] == NULL
)
913 ui_set_statusbar(TRUE
,
914 _("Could not find terminal \"%s\" "
915 "(check path for Terminal tool setting in Preferences)"), tool_prefs
.term_cmd
);
916 run_info
[cmdindex
].pid
= (GPid
) 1;
920 argv
= g_new0(gchar
*, term_argv_len
+ 3);
921 for (i
= 0; i
< term_argv_len
; i
++)
923 argv
[i
] = g_strdup(term_argv
[i
]);
926 /* command line arguments only for cmd.exe */
927 if (strstr(argv
[0], "cmd.exe") != NULL
)
929 argv
[term_argv_len
] = g_strdup("/Q /C");
930 argv
[term_argv_len
+ 1] = g_strdup(RUN_SCRIPT_CMD
);
934 argv
[term_argv_len
] = g_strdup(RUN_SCRIPT_CMD
);
935 argv
[term_argv_len
+ 1] = NULL
;
938 argv
[term_argv_len
] = g_strdup("-e");
939 argv
[term_argv_len
+ 1] = g_strconcat("/bin/sh ", RUN_SCRIPT_CMD
, NULL
);
941 argv
[term_argv_len
+ 2] = NULL
;
943 if (! g_spawn_async(working_dir
, argv
, NULL
, G_SPAWN_DO_NOT_REAP_CHILD
,
944 NULL
, NULL
, &(run_info
[cmdindex
].pid
), &error
))
946 geany_debug("g_spawn_async() failed: %s", error
->message
);
947 ui_set_statusbar(TRUE
, _("Process failed (%s)"), error
->message
);
948 g_unlink(RUN_SCRIPT_CMD
);
951 run_info
[cmdindex
].pid
= (GPid
) 0;
954 if (run_info
[cmdindex
].pid
> 0)
956 g_child_watch_add(run_info
[cmdindex
].pid
, (GChildWatchFunc
) run_exit_cb
,
957 (gpointer
)&(run_info
[cmdindex
]));
958 build_menu_update(doc
);
962 g_strfreev(term_argv
);
963 g_free(locale_term_cmd
);
967 return run_info
[cmdindex
].pid
;
971 static void process_build_output_line(const gchar
*str
, gint color
)
984 if (build_parse_make_dir(msg
, &tmp
))
986 setptr(current_dir_entered
, tmp
);
988 msgwin_parse_compiler_error_line(msg
, current_dir_entered
, &filename
, &line
);
990 if (line
!= -1 && filename
!= NULL
)
992 GeanyDocument
*doc
= document_find_by_filename(filename
);
994 /* limit number of indicators */
995 if (doc
&& editor_prefs
.use_indicators
&&
996 build_info
.message_count
< GEANY_BUILD_ERR_HIGHLIGHT_MAX
)
998 if (line
> 0) /* some compilers, like pdflatex report errors on line 0 */
999 line
--; /* so only adjust the line number if it is greater than 0 */
1000 editor_indicator_set_on_line(doc
->editor
, GEANY_INDICATOR_ERROR
, line
);
1002 build_info
.message_count
++;
1003 color
= COLOR_RED
; /* error message parsed on the line */
1007 msgwin_compiler_add_string(color
, msg
);
1013 static gboolean
build_iofunc(GIOChannel
*ioc
, GIOCondition cond
, gpointer data
)
1015 if (cond
& (G_IO_IN
| G_IO_PRI
))
1020 while ((st
= g_io_channel_read_line(ioc
, &msg
, NULL
, NULL
, NULL
)) == G_IO_STATUS_NORMAL
&& msg
)
1022 gint color
= (GPOINTER_TO_INT(data
)) ? COLOR_DARK_RED
: COLOR_BLACK
;
1024 process_build_output_line(msg
, color
);
1027 if (st
== G_IO_STATUS_ERROR
|| st
== G_IO_STATUS_EOF
) return FALSE
;
1029 if (cond
& (G_IO_ERR
| G_IO_HUP
| G_IO_NVAL
))
1037 gboolean
build_parse_make_dir(const gchar
*string
, gchar
**prefix
)
1046 if ((pos
= strstr(string
, "Entering directory")) != NULL
)
1051 /* get the start of the path */
1052 pos
= strstr(string
, "/");
1057 input
= g_strdup(pos
);
1059 /* kill the ' at the end of the path */
1060 len
= strlen(input
);
1061 input
[len
- 1] = '\0';
1062 input
= g_realloc(input
, len
); /* shorten by 1 */
1068 if (strstr(string
, "Leaving directory") != NULL
)
1078 static void show_build_result_message(gboolean failure
)
1084 msg
= _("Compilation failed.");
1085 msgwin_compiler_add_string(COLOR_BLUE
, msg
);
1086 /* If msgwindow is hidden, user will want to display it to see the error */
1087 if (! ui_prefs
.msgwindow_visible
)
1089 gtk_notebook_set_current_page(GTK_NOTEBOOK(msgwindow
.notebook
), MSG_COMPILER
);
1090 msgwin_show_hide(TRUE
);
1093 if (gtk_notebook_get_current_page(GTK_NOTEBOOK(msgwindow
.notebook
)) != MSG_COMPILER
)
1094 ui_set_statusbar(FALSE
, "%s", msg
);
1098 msg
= _("Compilation finished successfully.");
1099 msgwin_compiler_add_string(COLOR_BLUE
, msg
);
1100 if (! ui_prefs
.msgwindow_visible
||
1101 gtk_notebook_get_current_page(GTK_NOTEBOOK(msgwindow
.notebook
)) != MSG_COMPILER
)
1102 ui_set_statusbar(FALSE
, "%s", msg
);
1108 static void build_exit_cb(GPid child_pid
, gint status
, gpointer user_data
)
1110 gboolean failure
= FALSE
;
1112 if (WIFEXITED(status
))
1114 if (WEXITSTATUS(status
) != EXIT_SUCCESS
)
1117 else if (WIFSIGNALED(status
))
1119 /* the terminating signal: WTERMSIG (status)); */
1123 { /* any other failure occured */
1126 show_build_result_message(failure
);
1129 g_spawn_close_pid(child_pid
);
1132 /* enable build items again */
1133 build_menu_update(NULL
);
1134 ui_progress_bar_stop();
1139 static void run_exit_cb(GPid child_pid
, gint status
, gpointer user_data
)
1141 RunInfo
*run_info_data
= (RunInfo
*)user_data
;
1143 g_spawn_close_pid(child_pid
);
1145 run_info_data
->pid
= 0;
1146 /* reset the stop button and menu item to the original meaning */
1147 build_menu_update(NULL
);
1151 /* write a little shellscript to call the executable (similar to anjuta_launcher but "internal")
1152 * fname is the full file name (including path) for the script to create */
1153 static gboolean
build_create_shellscript(const gchar
*fname
, const gchar
*cmd
, gboolean autoclose
)
1158 gchar
*expanded_cmd
;
1161 fp
= g_fopen(fname
, "w");
1165 /* Expand environment variables like %blah%. */
1166 expanded_cmd
= win32_expand_environment_variables(cmd
);
1167 str
= g_strdup_printf("%s\n\n%s\ndel \"%%0\"\n\npause\n", expanded_cmd
, (autoclose
) ? "" : "pause");
1168 g_free(expanded_cmd
);
1170 str
= g_strdup_printf(
1171 "#!/bin/sh\n\nrm $0\n\n%s\n\necho \"\n\n------------------\n(program exited with code: $?)\" \
1172 \n\n%s\n", cmd
, (autoclose
) ? "" :
1173 "\necho \"Press return to continue\"\n#to be more compatible with shells like "
1174 "dash\ndummy_var=\"\"\nread dummy_var");
1186 typedef void Callback(GtkWidget
*w
, gpointer u
);
1188 /* run the command catenating cmd_cat if present */
1189 static void build_command(GeanyDocument
*doc
, GeanyBuildGroup grp
, gint cmd
, gchar
*cmd_cat
)
1192 gchar
*full_command
, *subs_command
;
1193 GeanyBuildCommand
*buildcmd
= get_build_cmd(doc
, grp
, cmd
, NULL
);
1196 if (buildcmd
== NULL
)
1199 cmdstr
= buildcmd_cmd(buildcmd
);
1201 if (cmd_cat
!= NULL
)
1204 full_command
= g_strconcat(cmdstr
, cmd_cat
, NULL
);
1206 full_command
= g_strdup(cmd_cat
);
1209 full_command
= cmdstr
;
1211 dir
= build_replace_placeholder(doc
, buildcmd_working_dir(buildcmd
));
1212 subs_command
= build_replace_placeholder(doc
, full_command
);
1213 build_info
.grp
= grp
;
1214 build_info
.cmd
= cmd
;
1215 build_spawn_cmd(doc
, subs_command
, dir
);
1216 g_free(subs_command
);
1218 if (cmd_cat
!= NULL
)
1219 g_free(full_command
);
1220 build_menu_update(doc
);
1225 /*----------------------------------------------------------------
1227 * Create build menu and handle callbacks (&toolbar callbacks)
1229 *----------------------------------------------------------------*/
1230 static void on_make_custom_input_response(const gchar
*input
)
1232 GeanyDocument
*doc
= document_get_current();
1234 setptr(build_info
.custom_target
, g_strdup(input
));
1235 build_command(doc
, GBO_TO_GBG(GEANY_GBO_CUSTOM
), GBO_TO_CMD(GEANY_GBO_CUSTOM
),
1236 build_info
.custom_target
);
1240 static void on_build_menu_item(GtkWidget
*w
, gpointer user_data
)
1242 GeanyDocument
*doc
= document_get_current();
1243 GeanyBuildCommand
*bc
;
1244 gint grp
= GPOINTER_TO_GRP(user_data
);
1245 gint cmd
= GPOINTER_TO_CMD(user_data
);
1247 if (doc
&& doc
->changed
)
1248 document_save_file(doc
, FALSE
);
1249 if (grp
== GEANY_GBG_NON_FT
&& cmd
== GBO_TO_CMD(GEANY_GBO_CUSTOM
))
1251 static GtkWidget
*dialog
= NULL
; /* keep dialog for combo history */
1255 dialog
= dialogs_show_input_persistent(_("Custom Text"),
1256 _("Enter custom text here, all entered text is appended to the command."),
1257 build_info
.custom_target
, &on_make_custom_input_response
);
1261 gtk_widget_show(dialog
);
1265 else if (grp
== GEANY_GBG_EXEC
)
1267 if (run_info
[cmd
].pid
> (GPid
) 1)
1269 kill_process(&run_info
[cmd
].pid
);
1272 bc
= get_build_cmd(doc
, grp
, cmd
, NULL
);
1273 if (bc
!= NULL
&& strcmp(buildcmd_cmd(bc
), "builtin") == 0)
1278 uri
= g_strconcat("file:///", g_path_skip_root(doc
->file_name
), NULL
);
1279 utils_open_browser(uri
);
1284 build_run_cmd(doc
, cmd
);
1287 build_command(doc
, grp
, cmd
, NULL
);
1291 /* group codes for menu items other than the known commands
1292 * value order is important, see the following table for use */
1294 /* the rest in each group */
1295 #define MENU_FT_REST (GEANY_GBG_COUNT + GEANY_GBG_FT)
1296 #define MENU_NON_FT_REST (GEANY_GBG_COUNT + GEANY_GBG_NON_FT)
1297 #define MENU_EXEC_REST (GEANY_GBG_COUNT + GEANY_GBG_EXEC)
1299 #define MENU_SEPARATOR (2*GEANY_GBG_COUNT)
1300 /* the fixed items */
1301 #define MENU_NEXT_ERROR (MENU_SEPARATOR + 1)
1302 #define MENU_PREV_ERROR (MENU_NEXT_ERROR + 1)
1303 #define MENU_COMMANDS (MENU_PREV_ERROR + 1)
1304 #define MENU_DONE (MENU_COMMANDS + 1)
1307 static struct BuildMenuItemSpec
{
1308 const gchar
*stock_id
;
1309 const gint key_binding
;
1310 const gint build_grp
;
1311 const gint build_cmd
;
1312 const gchar
*fix_label
;
1314 } build_menu_specs
[] = {
1315 {GTK_STOCK_CONVERT
, GEANY_KEYS_BUILD_COMPILE
, GBO_TO_GBG(GEANY_GBO_COMPILE
),
1316 GBO_TO_CMD(GEANY_GBO_COMPILE
), NULL
, on_build_menu_item
},
1317 {GEANY_STOCK_BUILD
, GEANY_KEYS_BUILD_LINK
, GBO_TO_GBG(GEANY_GBO_BUILD
),
1318 GBO_TO_CMD(GEANY_GBO_BUILD
), NULL
, on_build_menu_item
},
1319 {NULL
, -1, MENU_FT_REST
,
1320 GBO_TO_CMD(GEANY_GBO_BUILD
) + 1, NULL
, on_build_menu_item
},
1321 {NULL
, -1, MENU_SEPARATOR
,
1322 GBF_SEP_1
, NULL
, NULL
},
1323 {NULL
, GEANY_KEYS_BUILD_MAKE
, GBO_TO_GBG(GEANY_GBO_MAKE_ALL
),
1324 GBO_TO_CMD(GEANY_GBO_MAKE_ALL
), NULL
, on_build_menu_item
},
1325 {NULL
, GEANY_KEYS_BUILD_MAKEOWNTARGET
, GBO_TO_GBG(GEANY_GBO_CUSTOM
),
1326 GBO_TO_CMD(GEANY_GBO_CUSTOM
), NULL
, on_build_menu_item
},
1327 {NULL
, GEANY_KEYS_BUILD_MAKEOBJECT
, GBO_TO_GBG(GEANY_GBO_MAKE_OBJECT
),
1328 GBO_TO_CMD(GEANY_GBO_MAKE_OBJECT
), NULL
, on_build_menu_item
},
1329 {NULL
, -1, MENU_NON_FT_REST
,
1330 GBO_TO_CMD(GEANY_GBO_MAKE_OBJECT
) + 1, NULL
, on_build_menu_item
},
1331 {NULL
, -1, MENU_SEPARATOR
,
1332 GBF_SEP_2
, NULL
, NULL
},
1333 {NULL
, GEANY_KEYS_BUILD_NEXTERROR
, MENU_NEXT_ERROR
,
1334 GBF_NEXT_ERROR
, N_("_Next Error"), on_build_next_error
},
1335 {NULL
, GEANY_KEYS_BUILD_PREVIOUSERROR
, MENU_PREV_ERROR
,
1336 GBF_PREV_ERROR
, N_("_Previous Error"), on_build_previous_error
},
1337 {NULL
, -1, MENU_SEPARATOR
,
1338 GBF_SEP_3
, NULL
, NULL
},
1339 {GTK_STOCK_EXECUTE
, GEANY_KEYS_BUILD_RUN
, GBO_TO_GBG(GEANY_GBO_EXEC
),
1340 GBO_TO_CMD(GEANY_GBO_EXEC
), NULL
, on_build_menu_item
},
1341 {NULL
, -1, MENU_EXEC_REST
,
1342 GBO_TO_CMD(GEANY_GBO_EXEC
) + 1, NULL
, on_build_menu_item
},
1343 {NULL
, -1, MENU_SEPARATOR
,
1344 GBF_SEP_4
, NULL
, NULL
},
1345 {GTK_STOCK_PREFERENCES
, GEANY_KEYS_BUILD_OPTIONS
, MENU_COMMANDS
,
1346 GBF_COMMANDS
, N_("_Set Build Commands"), on_set_build_commands_activate
},
1347 {NULL
, -1, MENU_DONE
,
1352 static void create_build_menu_item(GtkWidget
*menu
, GeanyKeyGroup
*group
, GtkAccelGroup
*ag
,
1353 struct BuildMenuItemSpec
*bs
, const gchar
*lbl
, gint grp
, gint cmd
)
1355 GtkWidget
*item
= gtk_image_menu_item_new_with_mnemonic(lbl
);
1357 if (bs
->stock_id
!= NULL
)
1359 GtkWidget
*image
= gtk_image_new_from_stock(bs
->stock_id
, GTK_ICON_SIZE_MENU
);
1360 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
), image
);
1362 gtk_widget_show(item
);
1363 if (bs
->key_binding
>= 0)
1364 add_menu_accel(group
, bs
->key_binding
, ag
, item
);
1365 gtk_container_add(GTK_CONTAINER(menu
), item
);
1368 g_signal_connect(item
, "activate", G_CALLBACK(bs
->cb
), GRP_CMD_TO_POINTER(grp
,cmd
));
1370 menu_items
.menu_item
[grp
][cmd
] = item
;
1374 static void create_build_menu(BuildMenuItems
*build_menu_items
)
1377 GtkAccelGroup
*accel_group
= gtk_accel_group_new();
1378 GeanyKeyGroup
*keygroup
= g_ptr_array_index(keybinding_groups
, GEANY_KEY_GROUP_BUILD
);
1381 menu
= gtk_menu_new();
1382 build_menu_items
->menu_item
[GEANY_GBG_FT
] = g_new0(GtkWidget
*, build_groups_count
[GEANY_GBG_FT
]);
1383 build_menu_items
->menu_item
[GEANY_GBG_NON_FT
] = g_new0(GtkWidget
*, build_groups_count
[GEANY_GBG_NON_FT
]);
1384 build_menu_items
->menu_item
[GEANY_GBG_EXEC
] = g_new0(GtkWidget
*, build_groups_count
[GEANY_GBG_EXEC
]);
1385 build_menu_items
->menu_item
[GBG_FIXED
] = g_new0(GtkWidget
*, GBF_COUNT
);
1387 for (i
= 0; build_menu_specs
[i
].build_grp
!= MENU_DONE
; ++i
)
1389 struct BuildMenuItemSpec
*bs
= &(build_menu_specs
[i
]);
1390 if (bs
->build_grp
== MENU_SEPARATOR
)
1392 GtkWidget
*item
= gtk_separator_menu_item_new();
1393 gtk_widget_show(item
);
1394 gtk_container_add(GTK_CONTAINER(menu
), item
);
1395 build_menu_items
->menu_item
[GBG_FIXED
][bs
->build_cmd
] = item
;
1397 else if (bs
->fix_label
!= NULL
)
1399 create_build_menu_item(menu
, keygroup
, accel_group
, bs
, _(bs
->fix_label
),
1400 GBG_FIXED
, bs
->build_cmd
);
1402 else if (bs
->build_grp
>= MENU_FT_REST
&& bs
->build_grp
<= MENU_SEPARATOR
)
1404 gint grp
= bs
->build_grp
- GEANY_GBG_COUNT
;
1405 for (j
= bs
->build_cmd
; j
< build_groups_count
[grp
]; ++j
)
1407 GeanyBuildCommand
*bc
= get_build_cmd(NULL
, grp
, j
, NULL
);
1408 const gchar
*lbl
= (bc
== NULL
) ? "" : buildcmd_label(bc
);
1409 create_build_menu_item(menu
, keygroup
, accel_group
, bs
, lbl
, grp
, j
);
1414 GeanyBuildCommand
*bc
= get_build_cmd(NULL
, bs
->build_grp
, bs
->build_cmd
, NULL
);
1415 const gchar
*lbl
= (bc
== NULL
) ? "" : buildcmd_label(bc
);
1416 create_build_menu_item(menu
, keygroup
, accel_group
, bs
, lbl
, bs
->build_grp
, bs
->build_cmd
);
1419 build_menu_items
->menu
= menu
;
1420 gtk_widget_show(menu
);
1421 gtk_menu_item_set_submenu(GTK_MENU_ITEM(ui_lookup_widget(main_widgets
.window
, "menu_build1")), menu
);
1425 /* portability to various GTK versions needs checking
1426 * conforms to description of gtk_accel_label as child of menu item
1427 * NB 2.16 adds set_label but not yet set_label_mnemonic */
1428 static void geany_menu_item_set_label(GtkWidget
*w
, const gchar
*label
)
1430 GtkWidget
*c
= gtk_bin_get_child(GTK_BIN(w
));
1432 gtk_label_set_text_with_mnemonic(GTK_LABEL(c
), label
);
1436 /** Update the build menu to reflect changes in configuration or status.
1438 * Sets the labels and number of visible items to match the highest
1439 * priority configured commands. Also sets sensitivity if build commands are
1440 * running and switches executes to stop when commands are running.
1442 * @param doc The current document, if available, to save looking it up.
1443 * If @c NULL it will be looked up.
1445 * Call this after modifying any fields of a GeanyBuildCommand structure.
1447 * @see Build Menu Configuration section of the Manual.
1450 void build_menu_update(GeanyDocument
*doc
)
1452 gint i
, cmdcount
, cmd
, grp
;
1453 gboolean vis
= FALSE
;
1454 gboolean have_path
, build_running
, exec_running
, have_errors
, cmd_sensitivity
;
1455 gboolean can_compile
, can_build
, can_make
, run_sensitivity
= FALSE
, run_running
= FALSE
;
1456 GeanyBuildCommand
*bc
;
1458 if (menu_items
.menu
== NULL
)
1459 create_build_menu(&menu_items
);
1461 doc
= document_get_current();
1462 have_path
= doc
!= NULL
&& doc
->file_name
!= NULL
;
1463 build_running
= build_info
.pid
> (GPid
) 1;
1464 have_errors
= gtk_tree_model_iter_n_children(GTK_TREE_MODEL(msgwindow
.store_compiler
), NULL
) > 0;
1465 for (i
= 0; build_menu_specs
[i
].build_grp
!= MENU_DONE
; ++i
)
1467 struct BuildMenuItemSpec
*bs
= &(build_menu_specs
[i
]);
1468 switch (bs
->build_grp
)
1470 case MENU_SEPARATOR
:
1473 gtk_widget_show_all(menu_items
.menu_item
[GBG_FIXED
][bs
->build_cmd
]);
1477 gtk_widget_hide_all(menu_items
.menu_item
[GBG_FIXED
][bs
->build_cmd
]);
1479 case MENU_NEXT_ERROR
:
1480 case MENU_PREV_ERROR
:
1481 gtk_widget_set_sensitive(menu_items
.menu_item
[GBG_FIXED
][bs
->build_cmd
], have_errors
);
1487 default: /* all configurable commands */
1488 if (bs
->build_grp
>= GEANY_GBG_COUNT
)
1490 grp
= bs
->build_grp
- GEANY_GBG_COUNT
;
1491 cmdcount
= build_groups_count
[grp
];
1495 grp
= bs
->build_grp
;
1496 cmdcount
= bs
->build_cmd
+ 1;
1498 for (cmd
= bs
->build_cmd
; cmd
< cmdcount
; ++cmd
)
1500 GtkWidget
*menu_item
= menu_items
.menu_item
[grp
][cmd
];
1502 bc
= get_build_cmd(doc
, grp
, cmd
, NULL
);
1504 label
= buildcmd_label(bc
);
1508 if (grp
< GEANY_GBG_EXEC
)
1511 (grp
== GEANY_GBG_FT
&& bc
!= NULL
&& have_path
&& ! build_running
) ||
1512 (grp
== GEANY_GBG_NON_FT
&& bc
!= NULL
&& ! build_running
);
1513 gtk_widget_set_sensitive(menu_item
, cmd_sensitivity
);
1514 if (bc
!= NULL
&& NZV(label
))
1516 geany_menu_item_set_label(menu_item
, label
);
1517 gtk_widget_show_all(menu_item
);
1521 gtk_widget_hide_all(menu_item
);
1526 exec_running
= run_info
[cmd
].pid
> (GPid
) 1;
1527 cmd_sensitivity
= (bc
!= NULL
) || exec_running
;
1528 gtk_widget_set_sensitive(menu_item
, cmd_sensitivity
);
1529 if (cmd
== GBO_TO_CMD(GEANY_GBO_EXEC
))
1530 run_sensitivity
= cmd_sensitivity
;
1533 image
= gtk_image_new_from_stock(bs
->stock_id
, GTK_ICON_SIZE_MENU
);
1537 image
= gtk_image_new_from_stock(GTK_STOCK_STOP
, GTK_ICON_SIZE_MENU
);
1539 if (cmd
== GBO_TO_CMD(GEANY_GBO_EXEC
))
1540 run_running
= exec_running
;
1541 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item
), image
);
1542 if (bc
!= NULL
&& NZV(label
))
1544 geany_menu_item_set_label(menu_item
, label
);
1545 gtk_widget_show_all(menu_item
);
1549 gtk_widget_hide_all(menu_item
);
1555 run_sensitivity
&= (doc
!= NULL
);
1556 can_build
= get_build_cmd(doc
, GEANY_GBG_FT
, GBO_TO_CMD(GEANY_GBO_BUILD
), NULL
) != NULL
1557 && have_path
&& ! build_running
;
1558 if (widgets
.toolitem_build
!= NULL
)
1559 gtk_widget_set_sensitive(widgets
.toolitem_build
, can_build
);
1561 if (widgets
.toolitem_make_all
!= NULL
)
1562 gtk_widget_set_sensitive(widgets
.toolitem_make_all
,
1563 (can_make
|= get_build_cmd(doc
, GEANY_GBG_FT
, GBO_TO_CMD(GEANY_GBO_MAKE_ALL
), NULL
) != NULL
1564 && ! build_running
));
1565 if (widgets
.toolitem_make_custom
!= NULL
)
1566 gtk_widget_set_sensitive(widgets
.toolitem_make_custom
,
1567 (can_make
|= get_build_cmd(doc
, GEANY_GBG_FT
, GBO_TO_CMD(GEANY_GBO_CUSTOM
), NULL
) != NULL
1568 && ! build_running
));
1569 if (widgets
.toolitem_make_object
!= NULL
)
1570 gtk_widget_set_sensitive(widgets
.toolitem_make_object
,
1571 (can_make
|= get_build_cmd(doc
, GEANY_GBG_FT
, GBO_TO_CMD(GEANY_GBO_MAKE_OBJECT
), NULL
) != NULL
1572 && ! build_running
));
1573 if (widgets
.toolitem_set_args
!= NULL
)
1574 gtk_widget_set_sensitive(widgets
.toolitem_set_args
, TRUE
);
1576 can_compile
= get_build_cmd(doc
, GEANY_GBG_FT
, GBO_TO_CMD(GEANY_GBO_COMPILE
), NULL
) != NULL
1577 && have_path
&& ! build_running
;
1578 gtk_action_set_sensitive(widgets
.compile_action
, can_compile
);
1579 gtk_action_set_sensitive(widgets
.build_action
, can_make
);
1580 gtk_action_set_sensitive(widgets
.run_action
, run_sensitivity
);
1582 /* show the stop command if a program is running from execute 0 , otherwise show run command */
1583 set_stop_button(run_running
);
1588 /* Call build_menu_update() instead of calling this directly. */
1589 static void set_stop_button(gboolean stop
)
1591 const gchar
*button_stock_id
= NULL
;
1592 GtkToolButton
*run_button
;
1594 run_button
= GTK_TOOL_BUTTON(toolbar_get_widget_by_name("Run"));
1595 if (run_button
!= NULL
)
1596 button_stock_id
= gtk_tool_button_get_stock_id(run_button
);
1598 if (stop
&& utils_str_equal(button_stock_id
, "gtk-stop"))
1600 if (! stop
&& utils_str_equal(button_stock_id
, "gtk-execute"))
1603 /* use the run button also as stop button */
1606 if (run_button
!= NULL
)
1607 gtk_tool_button_set_stock_id(run_button
, "gtk-stop");
1611 if (run_button
!= NULL
)
1612 gtk_tool_button_set_stock_id(run_button
, "gtk-execute");
1617 static void on_set_build_commands_activate(GtkWidget
*w
, gpointer u
)
1619 /* For now, just show the project dialog */
1621 project_build_properties();
1623 show_build_commands_dialog();
1627 static void on_toolbutton_build_activate(GtkWidget
*menuitem
, gpointer user_data
)
1629 last_toolbutton_action
= user_data
;
1630 g_object_set(widgets
.build_action
, "tooltip", _("Build the current file"), NULL
);
1631 on_build_menu_item(menuitem
, user_data
);
1635 static void on_toolbutton_make_activate(GtkWidget
*menuitem
, gpointer user_data
)
1640 last_toolbutton_action
= user_data
;
1641 grp
= GPOINTER_TO_GRP(user_data
);
1642 cmd
= GPOINTER_TO_CMD(user_data
);
1643 if (last_toolbutton_action
== GBO_TO_POINTER(GEANY_GBO_MAKE_ALL
))
1644 msg
= _("Build the current file with Make and the default target");
1645 else if (last_toolbutton_action
== GBO_TO_POINTER(GEANY_GBO_CUSTOM
))
1646 msg
= _("Build the current file with Make and the specified target");
1647 else if (last_toolbutton_action
== GBO_TO_POINTER(GEANY_GBO_MAKE_OBJECT
))
1648 msg
= _("Compile the current file with Make");
1651 g_object_set(widgets
.build_action
, "tooltip", msg
, NULL
);
1652 on_build_menu_item(menuitem
, user_data
);
1656 static void kill_process(GPid
*pid
)
1658 /* Unix: SIGQUIT is not the best signal to use because it causes a core dump (this should not
1659 * perforce necessary for just killing a process). But we must use a signal which we can
1660 * ignore because the main process get it too, it is declared to ignore in main.c. */
1664 g_return_if_fail(*pid
!= NULL
);
1665 result
= TerminateProcess(*pid
, 0);
1666 /* TerminateProcess() returns TRUE on success, for the check below we have to convert
1667 * it to FALSE (and vice versa) */
1670 g_return_if_fail(*pid
> 1);
1671 result
= kill(*pid
, SIGQUIT
);
1675 ui_set_statusbar(TRUE
, _("Process could not be stopped (%s)."), g_strerror(errno
));
1679 build_menu_update(NULL
);
1684 static void on_build_next_error(GtkWidget
*menuitem
, gpointer user_data
)
1686 if (ui_tree_view_find_next(GTK_TREE_VIEW(msgwindow
.tree_compiler
),
1687 msgwin_goto_compiler_file_line
))
1689 gtk_notebook_set_current_page(GTK_NOTEBOOK(msgwindow
.notebook
), MSG_COMPILER
);
1692 ui_set_statusbar(FALSE
, _("No more build errors."));
1696 static void on_build_previous_error(GtkWidget
*menuitem
, gpointer user_data
)
1698 if (ui_tree_view_find_previous(GTK_TREE_VIEW(msgwindow
.tree_compiler
),
1699 msgwin_goto_compiler_file_line
))
1701 gtk_notebook_set_current_page(GTK_NOTEBOOK(msgwindow
.notebook
), MSG_COMPILER
);
1704 ui_set_statusbar(FALSE
, _("No more build errors."));
1708 void build_toolbutton_build_clicked(GtkAction
*action
, gpointer unused
)
1710 if (last_toolbutton_action
== GBO_TO_POINTER(GEANY_GBO_BUILD
))
1712 on_build_menu_item(NULL
, GBO_TO_POINTER(GEANY_GBO_BUILD
));
1716 on_build_menu_item(NULL
, last_toolbutton_action
);
1721 /*------------------------------------------------------
1723 * Create and handle the build menu configuration dialog
1725 *-------------------------------------------------------*/
1726 typedef struct RowWidgets
1728 GtkWidget
*entries
[GEANY_BC_CMDENTRIES_COUNT
];
1729 GeanyBuildSource src
;
1730 GeanyBuildSource dst
;
1731 GeanyBuildCommand
*cmdsrc
;
1738 static void set_build_command_entry_text(GtkWidget
*wid
, const gchar
*text
)
1740 if (GTK_IS_BUTTON(wid
))
1741 gtk_button_set_label(GTK_BUTTON(wid
), text
);
1743 gtk_entry_set_text(GTK_ENTRY(wid
), text
);
1747 static void on_clear_dialog_row(GtkWidget
*unused
, gpointer user_data
)
1749 RowWidgets
*r
= (RowWidgets
*)user_data
;
1751 enum GeanyBuildCmdEntries i
;
1752 GeanyBuildCommand
*bc
= get_next_build_cmd(NULL
, r
->grp
, r
->cmd
, r
->dst
, &src
);
1758 for (i
= 0; i
< GEANY_BC_CMDENTRIES_COUNT
; i
++)
1760 set_build_command_entry_text(r
->entries
[i
],
1761 id_to_str(bc
,i
) != NULL
? id_to_str(bc
,i
) : "");
1767 for (i
= 0; i
< GEANY_BC_CMDENTRIES_COUNT
; i
++)
1769 set_build_command_entry_text(r
->entries
[i
], "");
1776 static void on_clear_dialog_regex_row(GtkEntry
*regex
, gpointer unused
)
1778 gtk_entry_set_text(regex
,"");
1782 static void on_label_button_clicked(GtkWidget
*wid
)
1784 const gchar
*old
= gtk_button_get_label(GTK_BUTTON(wid
));
1785 gchar
*str
= dialogs_show_input(_("Set menu item label"), NULL
, old
);
1787 gtk_button_set_label(GTK_BUTTON(wid
), str
);
1792 /* Column headings, array NULL-terminated */
1793 static const gchar
*colheads
[] =
1798 N_("Working directory"),
1803 #define DC_ENTRIES 1
1807 static const guint entry_x_padding
= 3;
1808 static const guint entry_y_padding
= 0;
1811 static RowWidgets
*build_add_dialog_row(GeanyDocument
*doc
, GtkTable
*table
, guint row
,
1812 GeanyBuildSource dst
, gint grp
, gint cmd
, gboolean dir
)
1814 GtkWidget
*label
, *clear
, *clearicon
;
1816 GeanyBuildCommand
*bc
;
1818 enum GeanyBuildCmdEntries i
;
1821 label
= gtk_label_new(g_strdup_printf("%d:", cmd
+ 1));
1822 gtk_table_attach(table
, label
, column
, column
+ 1, row
, row
+ 1, GTK_FILL
,
1823 GTK_FILL
| GTK_EXPAND
, entry_x_padding
, entry_y_padding
);
1824 roww
= g_new0(RowWidgets
, 1);
1825 roww
->src
= GEANY_BCS_COUNT
;
1829 for (i
= 0; i
< GEANY_BC_CMDENTRIES_COUNT
; i
++)
1831 gint xflags
= (i
== GEANY_BC_COMMAND
) ? GTK_FILL
| GTK_EXPAND
: GTK_FILL
;
1834 if (i
== GEANY_BC_LABEL
)
1836 GtkWidget
*wid
= roww
->entries
[i
] = gtk_button_new();
1837 gtk_button_set_use_underline(GTK_BUTTON(wid
), TRUE
);
1838 ui_widget_set_tooltip_text(wid
, _("Click to set menu item label"));
1839 g_signal_connect(wid
, "clicked", G_CALLBACK(on_label_button_clicked
), NULL
);
1842 roww
->entries
[i
] = gtk_entry_new();
1843 gtk_table_attach(table
, roww
->entries
[i
], column
, column
+ 1, row
, row
+ 1, xflags
,
1844 GTK_FILL
| GTK_EXPAND
, entry_x_padding
, entry_y_padding
);
1847 clearicon
= gtk_image_new_from_stock(GTK_STOCK_CLEAR
, GTK_ICON_SIZE_MENU
);
1848 clear
= gtk_button_new();
1849 gtk_button_set_image(GTK_BUTTON(clear
), clearicon
);
1850 g_signal_connect(clear
, "clicked", G_CALLBACK(on_clear_dialog_row
), roww
);
1851 gtk_table_attach(table
, clear
, column
, column
+ 1, row
, row
+ 1, GTK_FILL
,
1852 GTK_FILL
| GTK_EXPAND
, entry_x_padding
, entry_y_padding
);
1853 roww
->cmdsrc
= bc
= get_build_cmd(doc
, grp
, cmd
, &src
);
1857 for (i
= 0; i
< GEANY_BC_CMDENTRIES_COUNT
; i
++)
1859 const gchar
*str
= "";
1860 if (bc
!= NULL
&& (str
= bc
->entries
[i
]) == NULL
)
1862 set_build_command_entry_text(roww
->entries
[i
], str
);
1864 if (bc
!= NULL
&& (src
> (gint
)dst
|| (grp
== GEANY_GBG_FT
&& (doc
== NULL
|| doc
->file_type
== NULL
))))
1866 for (i
= 0; i
< GEANY_BC_CMDENTRIES_COUNT
; i
++)
1867 gtk_widget_set_sensitive(roww
->entries
[i
], FALSE
);
1868 gtk_widget_set_sensitive(clear
, FALSE
);
1874 typedef struct BuildTableFields
1877 GtkWidget
*fileregex
;
1878 GtkWidget
*nonfileregex
;
1879 gchar
**fileregexstring
;
1880 gchar
**nonfileregexstring
;
1884 GtkWidget
*build_commands_table(GeanyDocument
*doc
, GeanyBuildSource dst
, BuildTableData
*table_data
,
1887 GtkWidget
*label
, *sep
, *clearicon
, *clear
;
1888 BuildTableFields
*fields
;
1892 guint col
, row
, cmdindex
;
1895 gboolean sensitivity
;
1896 guint sep_padding
= entry_y_padding
+ 3;
1898 table
= GTK_TABLE(gtk_table_new(build_items_count
+ 12, 5, FALSE
));
1899 fields
= g_new0(BuildTableFields
, 1);
1900 fields
->rows
= g_new0(RowWidgets
*, build_items_count
);
1901 for (ch
= colheads
, col
= 0; *ch
!= NULL
; ch
++, col
++)
1903 label
= gtk_label_new(_(*ch
));
1904 gtk_table_attach(table
, label
, col
, col
+ 1, 0, 1,
1905 GTK_FILL
, GTK_FILL
| GTK_EXPAND
, entry_x_padding
, entry_y_padding
);
1907 sep
= gtk_hseparator_new();
1908 gtk_table_attach(table
, sep
, 0, DC_N_COL
, 1, 2, GTK_FILL
, GTK_FILL
| GTK_EXPAND
,
1909 entry_x_padding
, sep_padding
);
1910 if (ft
!= NULL
&& ft
->id
!= GEANY_FILETYPES_NONE
)
1911 txt
= g_strdup_printf(_("%s Commands"), ft
->title
);
1913 txt
= g_strdup_printf(_("%s Commands"), _("No Filetype"));
1914 label
= ui_label_new_bold(txt
);
1916 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0.5);
1917 gtk_table_attach(table
, label
, 0, DC_N_COL
, 2, 3, GTK_FILL
, GTK_FILL
| GTK_EXPAND
,
1918 entry_x_padding
, entry_y_padding
);
1919 for (row
= 3, cmdindex
= 0, cmd
= 0; cmd
< build_groups_count
[GEANY_GBG_FT
]; ++row
, ++cmdindex
, ++cmd
)
1920 fields
->rows
[cmdindex
] = build_add_dialog_row(doc
, table
, row
, dst
, GEANY_GBG_FT
, cmd
, FALSE
);
1921 label
= gtk_label_new(_("Error Regular Expression:"));
1922 gtk_table_attach(table
, label
, 0, DC_ENTRIES
+ 1, row
, row
+ 1, GTK_FILL
, GTK_FILL
| GTK_EXPAND
,
1923 entry_x_padding
, entry_y_padding
);
1924 fields
->fileregex
= gtk_entry_new();
1925 fields
->fileregexstring
= build_get_regex(GEANY_GBG_FT
, NULL
, &src
);
1926 sensitivity
= (ft
== NULL
) ? FALSE
: TRUE
;
1927 if (fields
->fileregexstring
!= NULL
&& *(fields
->fileregexstring
) != NULL
)
1929 gtk_entry_set_text(GTK_ENTRY(fields
->fileregex
), *(fields
->fileregexstring
));
1930 if (src
> (gint
)dst
)
1931 sensitivity
= FALSE
;
1933 gtk_table_attach(table
, fields
->fileregex
, DC_ENTRIES
+ 1, DC_CLEAR
, row
, row
+ 1, GTK_FILL
,
1934 GTK_FILL
| GTK_EXPAND
, entry_x_padding
, entry_y_padding
);
1935 clearicon
= gtk_image_new_from_stock(GTK_STOCK_CLEAR
, GTK_ICON_SIZE_MENU
);
1936 clear
= gtk_button_new();
1937 gtk_button_set_image(GTK_BUTTON(clear
), clearicon
);
1938 g_signal_connect_swapped(clear
, "clicked",
1939 G_CALLBACK(on_clear_dialog_regex_row
), (fields
->fileregex
));
1940 gtk_table_attach(table
, clear
, DC_CLEAR
, DC_CLEAR
+ 1, row
, row
+ 1, GTK_FILL
,
1941 GTK_FILL
| GTK_EXPAND
, entry_x_padding
, entry_y_padding
);
1942 gtk_widget_set_sensitive(fields
->fileregex
, sensitivity
);
1943 gtk_widget_set_sensitive(clear
, sensitivity
);
1945 sep
= gtk_hseparator_new();
1946 gtk_table_attach(table
, sep
, 0, DC_N_COL
, row
, row
+ 1, GTK_FILL
, GTK_FILL
| GTK_EXPAND
,
1947 entry_x_padding
, sep_padding
);
1949 label
= ui_label_new_bold(_("Non-Filetype Commands"));
1950 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0.5);
1951 gtk_table_attach(table
, label
, 0, DC_N_COL
, row
, row
+ 1, GTK_FILL
, GTK_FILL
| GTK_EXPAND
,
1952 entry_x_padding
, entry_y_padding
);
1953 for (++row
, cmd
= 0; cmd
< build_groups_count
[GEANY_GBG_NON_FT
]; ++row
, ++cmdindex
, ++cmd
)
1954 fields
->rows
[cmdindex
] = build_add_dialog_row(
1955 doc
, table
, row
, dst
, GEANY_GBG_NON_FT
, cmd
, TRUE
);
1956 label
= gtk_label_new(_("Error Regular Expression:"));
1957 gtk_table_attach(table
, label
, 0, DC_ENTRIES
+ 1, row
, row
+ 1, GTK_FILL
,
1958 GTK_FILL
| GTK_EXPAND
, entry_x_padding
, entry_y_padding
);
1959 fields
->nonfileregex
= gtk_entry_new();
1960 fields
->nonfileregexstring
= build_get_regex(GEANY_GBG_NON_FT
, NULL
, &src
);
1962 if (fields
->nonfileregexstring
!= NULL
&& *(fields
->nonfileregexstring
) != NULL
)
1964 gtk_entry_set_text(GTK_ENTRY(fields
->nonfileregex
), *(fields
->nonfileregexstring
));
1965 sensitivity
= src
> (gint
)dst
? FALSE
: TRUE
;
1967 gtk_table_attach(table
, fields
->nonfileregex
, DC_ENTRIES
+ 1, DC_CLEAR
, row
, row
+ 1, GTK_FILL
,
1968 GTK_FILL
| GTK_EXPAND
, entry_x_padding
, entry_y_padding
);
1969 clearicon
= gtk_image_new_from_stock(GTK_STOCK_CLEAR
, GTK_ICON_SIZE_MENU
);
1970 clear
= gtk_button_new();
1971 gtk_button_set_image(GTK_BUTTON(clear
), clearicon
);
1972 g_signal_connect_swapped(clear
, "clicked",
1973 G_CALLBACK(on_clear_dialog_regex_row
), (fields
->nonfileregex
));
1974 gtk_table_attach(table
, clear
, DC_CLEAR
, DC_CLEAR
+ 1, row
, row
+ 1, GTK_FILL
,
1975 GTK_FILL
| GTK_EXPAND
, entry_x_padding
, entry_y_padding
);
1976 gtk_widget_set_sensitive(fields
->nonfileregex
, sensitivity
);
1977 gtk_widget_set_sensitive(clear
, sensitivity
);
1979 label
= gtk_label_new(_("Note: Item 2 opens a dialog and appends the response to the command."));
1980 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0.5);
1981 gtk_table_attach(table
, label
, 0, DC_N_COL
, row
, row
+ 1, GTK_FILL
, GTK_FILL
| GTK_EXPAND
,
1982 entry_x_padding
, entry_y_padding
);
1984 sep
= gtk_hseparator_new();
1985 gtk_table_attach(table
, sep
, 0, DC_N_COL
, row
, row
+ 1, GTK_FILL
, GTK_FILL
| GTK_EXPAND
,
1986 entry_x_padding
, sep_padding
);
1988 label
= ui_label_new_bold(_("Execute Commands"));
1989 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0.5);
1990 gtk_table_attach(table
, label
, 0, DC_N_COL
, row
, row
+ 1, GTK_FILL
, GTK_FILL
| GTK_EXPAND
,
1991 entry_x_padding
, entry_y_padding
);
1992 for (++row
, cmd
= 0; cmd
< build_groups_count
[GEANY_GBG_EXEC
]; ++row
, ++cmdindex
, ++cmd
)
1993 fields
->rows
[cmdindex
] = build_add_dialog_row(doc
, table
, row
, dst
, GEANY_GBG_EXEC
, cmd
, TRUE
);
1994 sep
= gtk_hseparator_new();
1995 gtk_table_attach(table
, sep
, 0, DC_N_COL
, row
, row
+ 1, GTK_FILL
, GTK_FILL
| GTK_EXPAND
,
1996 entry_x_padding
, sep_padding
);
1998 label
= gtk_label_new(
1999 _("%d, %e, %f, %p are substituted in command and directory fields, see manual for details."));
2000 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0.5);
2001 gtk_table_attach(table
, label
, 0, DC_N_COL
, row
, row
+ 1, GTK_FILL
, GTK_FILL
| GTK_EXPAND
,
2002 entry_x_padding
, entry_y_padding
);
2003 /*printf("%d extra rows in dialog\n", row-build_items_count);*/
2005 *table_data
= fields
;
2006 return GTK_WIDGET(table
);
2010 void build_free_fields(BuildTableData table_data
)
2014 for (cmdindex
= 0; cmdindex
< build_items_count
; ++cmdindex
)
2015 g_free(table_data
->rows
[cmdindex
]);
2016 g_free(table_data
->rows
);
2021 /* string compare where null pointers match null or 0 length strings */
2022 static gint
stcmp(const gchar
*a
, const gchar
*b
)
2024 if (a
== NULL
&& b
== NULL
)
2026 if (a
== NULL
&& b
!= NULL
)
2028 if (a
!= NULL
&& b
== NULL
)
2030 return strcmp(a
, b
);
2034 static const gchar
*get_build_command_entry_text(GtkWidget
*wid
)
2036 if (GTK_IS_BUTTON(wid
))
2037 return gtk_button_get_label(GTK_BUTTON(wid
));
2039 return gtk_entry_get_text(GTK_ENTRY(wid
));
2043 static gboolean
read_row(BuildDestination
*dst
, BuildTableData table_data
, gint drow
, gint grp
, gint cmd
)
2045 gchar
*entries
[GEANY_BC_CMDENTRIES_COUNT
];
2046 gboolean changed
= FALSE
;
2047 GeanyBuildSource src
;
2048 enum GeanyBuildCmdEntries i
;
2050 src
= table_data
->rows
[drow
]->src
;
2052 for (i
= 0; i
< GEANY_BC_CMDENTRIES_COUNT
; i
++)
2054 entries
[i
] = g_strdup(get_build_command_entry_text(table_data
->rows
[drow
]->entries
[i
]));
2056 if (table_data
->rows
[drow
]->cleared
)
2058 if (dst
->dst
[grp
] != NULL
)
2060 if (*(dst
->dst
[grp
]) == NULL
)
2061 *(dst
->dst
[grp
]) = g_new0(GeanyBuildCommand
, build_groups_count
[grp
]);
2062 (*(dst
->dst
[grp
]))[cmd
].exists
= FALSE
;
2063 (*(dst
->dst
[grp
]))[cmd
].changed
= TRUE
;
2069 table_data
->rows
[drow
]->cmdsrc
== NULL
/* originally there was no content */
2072 NZV(entries
[GEANY_BC_LABEL
]) /* but now one field has some */
2073 || NZV(entries
[GEANY_BC_COMMAND
])
2074 || NZV(entries
[GEANY_BC_WORKING_DIR
])
2079 table_data
->rows
[drow
]->cmdsrc
!= NULL
/* originally there was content */
2081 ( /* and some of it was changed */
2082 stcmp(entries
[GEANY_BC_LABEL
], table_data
->rows
[drow
]->cmdsrc
->entries
[GEANY_BC_LABEL
]) != 0
2083 || stcmp(entries
[GEANY_BC_COMMAND
], table_data
->rows
[drow
]->cmdsrc
->entries
[GEANY_BC_COMMAND
]) != 0
2084 || stcmp(entries
[GEANY_BC_WORKING_DIR
],
2085 table_data
->rows
[drow
]->cmdsrc
->entries
[GEANY_BC_WORKING_DIR
]) != 0
2090 if (dst
->dst
[grp
] != NULL
)
2092 if (*(dst
->dst
[grp
]) == NULL
)
2093 *(dst
->dst
[grp
]) = g_new0(GeanyBuildCommand
, build_groups_count
[grp
]);
2094 for (i
= 0; i
< GEANY_BC_CMDENTRIES_COUNT
; i
++)
2095 setptr((*(dst
->dst
[grp
]))[cmd
].entries
[i
], entries
[i
]);
2096 (*(dst
->dst
[grp
]))[cmd
].exists
= TRUE
;
2097 (*(dst
->dst
[grp
]))[cmd
].changed
= TRUE
;
2103 for (i
= 0; i
< GEANY_BC_CMDENTRIES_COUNT
; i
++)
2110 static gboolean
read_regex(GtkWidget
*regexentry
, gchar
**src
, gchar
**dst
)
2112 gboolean changed
= FALSE
;
2113 gchar
*reg
= g_strdup(gtk_entry_get_text(GTK_ENTRY(regexentry
)));
2117 (src
== NULL
/* originally there was no regex */
2118 || *src
== NULL
/* or it was NULL*/
2120 && NZV(reg
) > 0 /* and something was typed */
2122 ||(src
!= NULL
/* originally there was a regex*/
2123 && strcmp(*src
, reg
) != 0 /* and it has been changed */
2137 static gboolean
build_read_commands(BuildDestination
*dst
, BuildTableData table_data
, gint response
)
2140 gboolean changed
= FALSE
;
2142 if (response
== GTK_RESPONSE_ACCEPT
)
2144 for (cmdindex
= 0, cmd
= 0; cmd
< build_groups_count
[GEANY_GBG_FT
]; ++cmdindex
, ++cmd
)
2145 changed
|= read_row(dst
, table_data
, cmdindex
, GEANY_GBG_FT
, cmd
);
2146 for (cmd
= 0; cmd
< build_groups_count
[GEANY_GBG_NON_FT
]; ++cmdindex
, ++cmd
)
2147 changed
|= read_row(dst
, table_data
, cmdindex
, GEANY_GBG_NON_FT
, cmd
);
2148 for (cmd
= 0; cmd
< build_groups_count
[GEANY_GBG_EXEC
]; ++cmdindex
, ++cmd
)
2149 changed
|= read_row(dst
, table_data
, cmdindex
, GEANY_GBG_EXEC
, cmd
);
2150 changed
|= read_regex(table_data
->fileregex
, table_data
->fileregexstring
, dst
->fileregexstr
);
2151 changed
|= read_regex(table_data
->nonfileregex
, table_data
->nonfileregexstring
, dst
->nonfileregexstr
);
2157 void build_read_project(GeanyFiletype
*ft
, BuildTableData build_properties
)
2159 BuildDestination menu_dst
;
2163 menu_dst
.dst
[GEANY_GBG_FT
] = &(ft
->projfilecmds
);
2164 menu_dst
.fileregexstr
= &(ft
->projerror_regex_string
);
2168 menu_dst
.dst
[GEANY_GBG_FT
] = NULL
;
2169 menu_dst
.fileregexstr
= NULL
;
2171 menu_dst
.dst
[GEANY_GBG_NON_FT
] = &non_ft_proj
;
2172 menu_dst
.dst
[GEANY_GBG_EXEC
] = &exec_proj
;
2173 menu_dst
.nonfileregexstr
= ®ex_proj
;
2175 build_read_commands(&menu_dst
, build_properties
, GTK_RESPONSE_ACCEPT
);
2179 static void show_build_commands_dialog(void)
2181 GtkWidget
*dialog
, *table
, *vbox
;
2182 GeanyDocument
*doc
= document_get_current();
2183 GeanyFiletype
*ft
= NULL
;
2184 const gchar
*title
= _("Set Build Commands");
2186 BuildTableData table_data
;
2187 BuildDestination prefdsts
;
2190 ft
= doc
->file_type
;
2191 dialog
= gtk_dialog_new_with_buttons(title
, GTK_WINDOW(main_widgets
.window
),
2192 GTK_DIALOG_DESTROY_WITH_PARENT
,
2193 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
2194 GTK_STOCK_OK
, GTK_RESPONSE_ACCEPT
, NULL
);
2195 table
= build_commands_table(doc
, GEANY_BCS_PREF
, &table_data
, ft
);
2196 vbox
= ui_dialog_vbox_new(GTK_DIALOG(dialog
));
2197 gtk_box_pack_start(GTK_BOX(vbox
), table
, TRUE
, TRUE
, 0);
2198 gtk_widget_show_all(dialog
);
2199 /* run modally to prevent user changing idx filetype */
2200 response
= gtk_dialog_run(GTK_DIALOG(dialog
));
2202 prefdsts
.dst
[GEANY_GBG_NON_FT
] = &non_ft_pref
;
2205 prefdsts
.dst
[GEANY_GBG_FT
] = &(ft
->homefilecmds
);
2206 prefdsts
.fileregexstr
= &(ft
->homeerror_regex_string
);
2207 prefdsts
.dst
[GEANY_GBG_EXEC
] = &(ft
->homeexeccmds
);
2211 prefdsts
.dst
[GEANY_GBG_FT
] = NULL
;
2212 prefdsts
.fileregexstr
= NULL
;
2213 prefdsts
.dst
[GEANY_GBG_EXEC
] = NULL
;
2215 prefdsts
.nonfileregexstr
= ®ex_pref
;
2216 if (build_read_commands(&prefdsts
, table_data
, response
) && ft
!= NULL
)
2217 ft
->home_save_needed
= TRUE
;
2218 build_free_fields(table_data
);
2220 build_menu_update(doc
);
2221 gtk_widget_destroy(dialog
);
2225 /* Creates the relevant build menu if necessary. */
2226 BuildMenuItems
*build_get_menu_items(gint filetype_idx
)
2228 BuildMenuItems
*items
;
2230 items
= &menu_items
;
2231 if (items
->menu
== NULL
)
2232 create_build_menu(items
);
2237 /* set non_ft working directory entries to %p for project */
2238 void build_set_non_ft_wd_to_proj(BuildTableData table_data
)
2242 start
= build_groups_count
[GEANY_GBG_FT
];
2243 end
= start
+ build_groups_count
[GEANY_GBG_NON_FT
];
2244 for (i
= start
; i
< end
; ++i
)
2245 gtk_entry_set_text(GTK_ENTRY(table_data
->rows
[i
]->entries
[GEANY_BC_WORKING_DIR
]), "%p");
2249 /*----------------------------------------------------------
2251 * Load and store configuration
2253 * ---------------------------------------------------------*/
2254 static const gchar
*build_grp_name
= "build-menu";
2256 /* config format for build-menu group is prefix_gg_nn_xx=value
2257 * where gg = FT, NF, EX for the command group
2258 * nn = 2 digit command number
2259 * xx = LB for label, CM for command and WD for working dir */
2260 static const gchar
*groups
[GEANY_GBG_COUNT
] = { "FT", "NF", "EX" };
2261 static const gchar
*fixedkey
="xx_xx_xx";
2263 #define set_key_grp(key, grp) (key[prefixlen + 0] = grp[0], key[prefixlen + 1] = grp[1])
2264 #define set_key_cmd(key, cmd) (key[prefixlen + 3] = cmd[0], key[prefixlen + 4] = cmd[1])
2265 #define set_key_fld(key, fld) (key[prefixlen + 6] = fld[0], key[prefixlen + 7] = fld[1])
2267 static void build_load_menu_grp(GKeyFile
*config
, GeanyBuildCommand
**dst
, gint grp
,
2268 gchar
*prefix
, gboolean loc
)
2270 gint cmd
, prefixlen
; /* NOTE prefixlen used in macros above */
2271 GeanyBuildCommand
*dstcmd
;
2273 static gchar cmdbuf
[3] = " ";
2276 *dst
= g_new0(GeanyBuildCommand
, build_groups_count
[grp
]);
2278 prefixlen
= prefix
== NULL
? 0 : strlen(prefix
);
2279 key
= g_strconcat(prefix
== NULL
? "" : prefix
, fixedkey
, NULL
);
2280 for (cmd
= 0; cmd
< build_groups_count
[grp
]; ++cmd
)
2283 if (cmd
< 0 || cmd
>= 100)
2284 return; /* ensure no buffer overflow */
2285 sprintf(cmdbuf
, "%02d", cmd
);
2286 set_key_grp(key
, groups
[grp
]);
2287 set_key_cmd(key
, cmdbuf
);
2288 set_key_fld(key
, "LB");
2290 label
= g_key_file_get_locale_string(config
, build_grp_name
, key
, NULL
, NULL
);
2292 label
= g_key_file_get_string(config
, build_grp_name
, key
, NULL
);
2295 dstcmd
[cmd
].exists
= TRUE
;
2296 setptr(dstcmd
[cmd
].entries
[GEANY_BC_LABEL
], label
);
2297 set_key_fld(key
,"CM");
2298 setptr(dstcmd
[cmd
].entries
[GEANY_BC_COMMAND
],
2299 g_key_file_get_string(config
, build_grp_name
, key
, NULL
));
2300 set_key_fld(key
,"WD");
2301 setptr(dstcmd
[cmd
].entries
[GEANY_BC_WORKING_DIR
],
2302 g_key_file_get_string(config
, build_grp_name
, key
, NULL
));
2304 else dstcmd
[cmd
].exists
= FALSE
;
2310 /* for the specified source load new format build menu items or try to make some sense of
2311 * old format setings, not done perfectly but better than ignoring them */
2312 void build_load_menu(GKeyFile
*config
, GeanyBuildSource src
, gpointer p
)
2317 gchar
*value
, *basedir
, *makebasedir
;
2318 gboolean bvalue
= FALSE
;
2320 if (g_key_file_has_group(config
, build_grp_name
))
2325 ft
= (GeanyFiletype
*)p
;
2328 build_load_menu_grp(config
, &(ft
->filecmds
), GEANY_GBG_FT
, NULL
, TRUE
);
2329 build_load_menu_grp(config
, &(ft
->ftdefcmds
), GEANY_GBG_NON_FT
, NULL
, TRUE
);
2330 build_load_menu_grp(config
, &(ft
->execcmds
), GEANY_GBG_EXEC
, NULL
, TRUE
);
2331 setptr(ft
->error_regex_string
,
2332 g_key_file_get_string(config
, build_grp_name
, "error_regex", NULL
));
2334 case GEANY_BCS_HOME_FT
:
2335 ft
= (GeanyFiletype
*)p
;
2338 build_load_menu_grp(config
, &(ft
->homefilecmds
), GEANY_GBG_FT
, NULL
, FALSE
);
2339 build_load_menu_grp(config
, &(ft
->homeexeccmds
), GEANY_GBG_EXEC
, NULL
, FALSE
);
2340 setptr(ft
->homeerror_regex_string
,
2341 g_key_file_get_string(config
, build_grp_name
, "error_regex", NULL
));
2343 case GEANY_BCS_PREF
:
2344 build_load_menu_grp(config
, &non_ft_pref
, GEANY_GBG_NON_FT
, NULL
, FALSE
);
2345 build_load_menu_grp(config
, &exec_pref
, GEANY_GBG_EXEC
, NULL
, FALSE
);
2346 setptr(regex_pref
, g_key_file_get_string(config
, build_grp_name
, "error_regex", NULL
));
2348 case GEANY_BCS_PROJ
:
2349 build_load_menu_grp(config
, &non_ft_proj
, GEANY_GBG_NON_FT
, NULL
, FALSE
);
2350 build_load_menu_grp(config
, &exec_proj
, GEANY_GBG_EXEC
, NULL
, FALSE
);
2351 setptr(regex_proj
, g_key_file_get_string(config
, build_grp_name
, "error_regex", NULL
));
2352 pj
= (GeanyProject
*)p
;
2355 ftlist
= g_key_file_get_string_list(config
, build_grp_name
, "filetypes", NULL
, NULL
);
2359 if (pj
->build_filetypes_list
== NULL
)
2360 pj
->build_filetypes_list
= g_ptr_array_new();
2361 g_ptr_array_set_size(pj
->build_filetypes_list
, 0);
2362 for (ftname
= ftlist
; *ftname
!= NULL
; ++ftname
)
2364 ft
= filetypes_lookup_by_name(*ftname
);
2367 gchar
*regkey
= g_strdup_printf("%serror_regex", *ftname
);
2368 g_ptr_array_add(pj
->build_filetypes_list
, ft
);
2369 setptr(ft
->projerror_regex_string
,
2370 g_key_file_get_string(config
, build_grp_name
, regkey
, NULL
));
2372 build_load_menu_grp(config
, &(ft
->projfilecmds
), GEANY_GBG_FT
, *ftname
, FALSE
);
2373 build_load_menu_grp(config
, &(ft
->projexeccmds
), GEANY_GBG_EXEC
, *ftname
, FALSE
);
2379 default: /* defaults don't load from config, see build_init */
2384 /* load old [build_settings] values if there is no value defined by [build-menu] */
2386 /* set GeanyBuildCommand if it doesn't already exist and there is a command */
2387 #define ASSIGNIF(type, id, string, value) \
2388 if (NZV(value) && ! type[GBO_TO_CMD(id)].exists) { \
2389 type[GBO_TO_CMD(id)].exists = TRUE; \
2390 setptr(type[GBO_TO_CMD(id)].entries[GEANY_BC_LABEL], g_strdup(string)); \
2391 setptr(type[GBO_TO_CMD(id)].entries[GEANY_BC_COMMAND], (value)); \
2392 setptr(type[GBO_TO_CMD(id)].entries[GEANY_BC_WORKING_DIR], NULL); \
2393 type[GBO_TO_CMD(id)].old = TRUE; \
2400 ft
= (GeanyFiletype
*)p
;
2401 value
= g_key_file_get_string(config
, "build_settings", "compiler", NULL
);
2404 if (ft
->filecmds
== NULL
)
2405 ft
->filecmds
= g_new0(GeanyBuildCommand
, build_groups_count
[GEANY_GBG_FT
]);
2406 ASSIGNIF(ft
->filecmds
, GEANY_GBO_COMPILE
, _("_Compile"), value
);
2408 value
= g_key_file_get_string(config
, "build_settings", "linker", NULL
);
2411 if (ft
->filecmds
== NULL
)
2412 ft
->filecmds
= g_new0(GeanyBuildCommand
, build_groups_count
[GEANY_GBG_FT
]);
2413 ASSIGNIF(ft
->filecmds
, GEANY_GBO_BUILD
, _("_Build"), value
);
2415 value
= g_key_file_get_string(config
, "build_settings", "run_cmd", NULL
);
2418 if (ft
->execcmds
== NULL
)
2419 ft
->execcmds
= g_new0(GeanyBuildCommand
, build_groups_count
[GEANY_GBG_EXEC
]);
2420 ASSIGNIF(ft
->execcmds
, GEANY_GBO_EXEC
, _("_Execute"), value
);
2422 if (ft
->error_regex_string
== NULL
)
2423 ft
->error_regex_string
= g_key_file_get_string(config
, "build_settings", "error_regex", NULL
);
2425 case GEANY_BCS_PROJ
:
2426 if (non_ft_pref
== NULL
)
2427 non_ft_pref
= g_new0(GeanyBuildCommand
, build_groups_count
[GEANY_GBG_NON_FT
]);
2428 basedir
= project_get_base_path();
2429 if (basedir
== NULL
)
2430 basedir
= g_strdup("%d");
2431 bvalue
= g_key_file_get_boolean(config
, "project", "make_in_base_path", NULL
);
2433 makebasedir
= g_strdup(basedir
);
2435 makebasedir
= g_strdup("%d");
2436 if (non_ft_pref
[GBO_TO_CMD(GEANY_GBO_MAKE_ALL
)].old
)
2437 setptr(non_ft_pref
[GBO_TO_CMD(GEANY_GBO_MAKE_ALL
)].entries
[GEANY_BC_WORKING_DIR
], g_strdup(makebasedir
));
2438 if (non_ft_pref
[GBO_TO_CMD(GEANY_GBO_CUSTOM
)].old
)
2439 setptr(non_ft_pref
[GBO_TO_CMD(GEANY_GBO_CUSTOM
)].entries
[GEANY_BC_WORKING_DIR
], g_strdup(makebasedir
));
2440 if (non_ft_pref
[GBO_TO_CMD(GEANY_GBO_MAKE_OBJECT
)].old
)
2441 setptr(non_ft_pref
[GBO_TO_CMD(GEANY_GBO_MAKE_OBJECT
)].entries
[GEANY_BC_WORKING_DIR
], g_strdup("%d"));
2442 value
= g_key_file_get_string(config
, "project", "run_cmd", NULL
);
2445 if (exec_proj
== NULL
)
2446 exec_proj
= g_new0(GeanyBuildCommand
, build_groups_count
[GEANY_GBG_EXEC
]);
2447 if (! exec_proj
[GBO_TO_CMD(GEANY_GBO_EXEC
)].exists
)
2449 exec_proj
[GBO_TO_CMD(GEANY_GBO_EXEC
)].exists
= TRUE
;
2450 setptr(exec_proj
[GBO_TO_CMD(GEANY_GBO_EXEC
)].entries
[GEANY_BC_LABEL
], g_strdup(_("_Execute")));
2451 setptr(exec_proj
[GBO_TO_CMD(GEANY_GBO_EXEC
)].entries
[GEANY_BC_COMMAND
], value
);
2452 setptr(exec_proj
[GBO_TO_CMD(GEANY_GBO_EXEC
)].entries
[GEANY_BC_WORKING_DIR
], g_strdup(basedir
));
2453 exec_proj
[GBO_TO_CMD(GEANY_GBO_EXEC
)].old
= TRUE
;
2456 g_free(makebasedir
);
2459 case GEANY_BCS_PREF
:
2460 value
= g_key_file_get_string(config
, "tools", "make_cmd", NULL
);
2463 if (non_ft_pref
== NULL
)
2464 non_ft_pref
= g_new0(GeanyBuildCommand
, build_groups_count
[GEANY_GBG_NON_FT
]);
2465 ASSIGNIF(non_ft_pref
, GEANY_GBO_CUSTOM
, _("Make Custom _Target"),
2466 g_strdup_printf("%s ", value
));
2467 ASSIGNIF(non_ft_pref
, GEANY_GBO_MAKE_OBJECT
, _("Make _Object"),
2468 g_strdup_printf("%s %%e.o",value
));
2469 ASSIGNIF(non_ft_pref
, GEANY_GBO_MAKE_ALL
, _("_Make"), value
);
2478 static gint
build_save_menu_grp(GKeyFile
*config
, GeanyBuildCommand
*src
, gint grp
, gchar
*prefix
)
2480 gint cmd
, prefixlen
; /* NOTE prefixlen used in macros above */
2483 enum GeanyBuildCmdEntries i
;
2487 prefixlen
= prefix
== NULL
? 0 : strlen(prefix
);
2488 key
= g_strconcat(prefix
== NULL
? "" : prefix
, fixedkey
, NULL
);
2489 for (cmd
= 0; cmd
< build_groups_count
[grp
]; ++cmd
)
2491 if (src
[cmd
].exists
) ++count
;
2492 if (src
[cmd
].changed
)
2494 static gchar cmdbuf
[4] = " ";
2495 if (cmd
< 0 || cmd
>= 100)
2496 return count
; /* ensure no buffer overflow */
2497 sprintf(cmdbuf
, "%02d", cmd
);
2498 set_key_grp(key
, groups
[grp
]);
2499 set_key_cmd(key
, cmdbuf
);
2500 if (src
[cmd
].exists
)
2502 for (i
= 0; i
< GEANY_BC_CMDENTRIES_COUNT
; i
++)
2504 set_key_fld(key
, config_keys
[i
]);
2505 g_key_file_set_string(config
, build_grp_name
, key
, src
[cmd
].entries
[i
]);
2510 for (i
= 0; i
< GEANY_BC_CMDENTRIES_COUNT
; i
++)
2512 set_key_fld(key
, config_keys
[i
]);
2513 g_key_file_remove_key(config
, build_grp_name
, key
, NULL
);
2523 typedef struct ForEachData
2526 GPtrArray
*ft_names
;
2530 static void foreach_project_filetype(gpointer data
, gpointer user_data
)
2532 GeanyFiletype
*ft
= (GeanyFiletype
*) data
;
2533 ForEachData
*d
= (ForEachData
*) user_data
;
2535 gchar
*regkey
= g_strdup_printf("%serror_regex", ft
->name
);
2537 i
+= build_save_menu_grp(d
->config
, ft
->projfilecmds
, GEANY_GBG_FT
, ft
->name
);
2538 i
+= build_save_menu_grp(d
->config
, ft
->projexeccmds
, GEANY_GBG_EXEC
, ft
->name
);
2539 if (NZV(ft
->projerror_regex_string
))
2541 g_key_file_set_string(d
->config
, build_grp_name
, regkey
, ft
->projerror_regex_string
);
2545 g_key_file_remove_key(d
->config
, build_grp_name
, regkey
, NULL
);
2548 g_ptr_array_add(d
->ft_names
, ft
->name
);
2552 void build_save_menu(GKeyFile
*config
, gpointer ptr
, GeanyBuildSource src
)
2561 case GEANY_BCS_HOME_FT
:
2562 ft
= (GeanyFiletype
*)ptr
;
2565 build_save_menu_grp(config
, ft
->homefilecmds
, GEANY_GBG_FT
, NULL
);
2566 build_save_menu_grp(config
, ft
->homeexeccmds
, GEANY_GBG_EXEC
, NULL
);
2567 regkey
= g_strdup_printf("%serror_regex", ft
->name
);
2568 if (NZV(ft
->homeerror_regex_string
))
2569 g_key_file_set_string(config
, build_grp_name
, regkey
, ft
->projerror_regex_string
);
2571 g_key_file_remove_key(config
, build_grp_name
, regkey
, NULL
);
2574 case GEANY_BCS_PREF
:
2575 build_save_menu_grp(config
, non_ft_pref
, GEANY_GBG_NON_FT
, NULL
);
2576 build_save_menu_grp(config
, exec_pref
, GEANY_GBG_EXEC
, NULL
);
2577 if (NZV(regex_pref
))
2578 g_key_file_set_string(config
, build_grp_name
, "error_regex", regex_pref
);
2580 g_key_file_remove_key(config
, build_grp_name
, "error_regex", NULL
);
2582 case GEANY_BCS_PROJ
:
2583 pj
= (GeanyProject
*)ptr
;
2584 build_save_menu_grp(config
, non_ft_proj
, GEANY_GBG_NON_FT
, NULL
);
2585 build_save_menu_grp(config
, exec_proj
, GEANY_GBG_EXEC
, NULL
);
2586 if (NZV(regex_proj
))
2587 g_key_file_set_string(config
, build_grp_name
, "error_regex", regex_proj
);
2589 g_key_file_remove_key(config
, build_grp_name
, "error_regex", NULL
);
2590 if (pj
->build_filetypes_list
!= NULL
)
2592 data
.config
= config
;
2593 data
.ft_names
= g_ptr_array_new();
2594 g_ptr_array_foreach(pj
->build_filetypes_list
, foreach_project_filetype
, (gpointer
)(&data
));
2595 if (data
.ft_names
->pdata
!= NULL
)
2596 g_key_file_set_string_list(config
, build_grp_name
, "filetypes",
2597 (const gchar
**)(data
.ft_names
->pdata
), data
.ft_names
->len
);
2599 g_key_file_remove_key(config
, build_grp_name
, "filetypes", NULL
);
2600 g_ptr_array_free(data
.ft_names
, TRUE
);
2603 default: /* defaults and GEANY_BCS_FT can't save */
2609 void build_set_group_count(GeanyBuildGroup grp
, gint count
)
2613 if (count
> build_groups_count
[grp
])
2614 build_groups_count
[grp
] = count
;
2615 for (i
= 0, sum
= 0; i
< GEANY_GBG_COUNT
; ++i
)
2616 sum
+= build_groups_count
[i
];
2617 build_items_count
= sum
;
2621 gint
build_get_group_count(GeanyBuildGroup grp
)
2623 return build_groups_count
[grp
];
2627 static void on_project_close(void)
2629 /* remove project regexen */
2630 setptr(regex_proj
, NULL
);
2636 const gchar
*entries
[GEANY_BC_CMDENTRIES_COUNT
];
2637 GeanyBuildCommand
**ptr
;
2639 } default_cmds
[] = {
2640 { {N_("_Make"), "make", NULL
}, &non_ft_def
, GBO_TO_CMD(GEANY_GBO_MAKE_ALL
)},
2641 { {N_("Make Custom _Target"), "make ", NULL
}, &non_ft_def
, GBO_TO_CMD(GEANY_GBO_CUSTOM
)},
2642 { {N_("Make _Object"), "make %e.o", NULL
}, &non_ft_def
, GBO_TO_CMD(GEANY_GBO_MAKE_OBJECT
)},
2643 { {N_("_Execute"), "./%e", NULL
}, &exec_def
, GBO_TO_CMD(GEANY_GBO_EXEC
)},
2644 { {NULL
, NULL
, NULL
}, NULL
, 0 }
2648 void build_init(void)
2651 GtkWidget
*toolmenu
;
2654 g_signal_connect(geany_object
, "project-close", on_project_close
, NULL
);
2656 ft_def
= g_new0(GeanyBuildCommand
, build_groups_count
[GEANY_GBG_FT
]);
2657 non_ft_def
= g_new0(GeanyBuildCommand
, build_groups_count
[GEANY_GBG_NON_FT
]);
2658 exec_def
= g_new0(GeanyBuildCommand
, build_groups_count
[GEANY_GBG_EXEC
]);
2659 run_info
= g_new0(RunInfo
, build_groups_count
[GEANY_GBG_EXEC
]);
2660 for (cmdindex
= 0; default_cmds
[cmdindex
].entries
[GEANY_BC_COMMAND
] != NULL
; ++cmdindex
)
2662 enum GeanyBuildCmdEntries k
;
2663 GeanyBuildCommand
*cmd
= &((*(default_cmds
[cmdindex
].ptr
))[ default_cmds
[cmdindex
].index
]);
2665 for (k
= 0; k
< GEANY_BC_CMDENTRIES_COUNT
; k
++)
2667 cmd
->entries
[k
] = g_strdup(default_cmds
[cmdindex
].entries
[k
]);
2671 /* create the toolbar Build item sub menu */
2672 toolmenu
= gtk_menu_new();
2673 g_object_ref(toolmenu
);
2675 /* build the code */
2676 item
= ui_image_menu_item_new(GEANY_STOCK_BUILD
, _("_Build"));
2677 gtk_widget_show(item
);
2678 gtk_container_add(GTK_CONTAINER(toolmenu
), item
);
2679 g_signal_connect(item
, "activate", G_CALLBACK(on_toolbutton_build_activate
),
2680 GBO_TO_POINTER(GEANY_GBO_BUILD
));
2681 widgets
.toolitem_build
= item
;
2683 item
= gtk_separator_menu_item_new();
2684 gtk_widget_show(item
);
2685 gtk_container_add(GTK_CONTAINER(toolmenu
), item
);
2687 /* build the code with make all */
2688 item
= gtk_image_menu_item_new_with_mnemonic(_("_Make All"));
2689 gtk_widget_show(item
);
2690 gtk_container_add(GTK_CONTAINER(toolmenu
), item
);
2691 g_signal_connect(item
, "activate", G_CALLBACK(on_toolbutton_make_activate
),
2692 GBO_TO_POINTER(GEANY_GBO_MAKE_ALL
));
2693 widgets
.toolitem_make_all
= item
;
2695 /* build the code with make custom */
2696 item
= gtk_image_menu_item_new_with_mnemonic(_("Make Custom _Target"));
2697 gtk_widget_show(item
);
2698 gtk_container_add(GTK_CONTAINER(toolmenu
), item
);
2699 g_signal_connect(item
, "activate", G_CALLBACK(on_toolbutton_make_activate
),
2700 GBO_TO_POINTER(GEANY_GBO_CUSTOM
));
2701 widgets
.toolitem_make_custom
= item
;
2703 /* build the code with make object */
2704 item
= gtk_image_menu_item_new_with_mnemonic(_("Make _Object"));
2705 gtk_widget_show(item
);
2706 gtk_container_add(GTK_CONTAINER(toolmenu
), item
);
2707 g_signal_connect(item
, "activate", G_CALLBACK(on_toolbutton_make_activate
),
2708 GBO_TO_POINTER(GEANY_GBO_MAKE_OBJECT
));
2709 widgets
.toolitem_make_object
= item
;
2711 item
= gtk_separator_menu_item_new();
2712 gtk_widget_show(item
);
2713 gtk_container_add(GTK_CONTAINER(toolmenu
), item
);
2716 item
= ui_image_menu_item_new(GTK_STOCK_PREFERENCES
, _("_Set Build Menu Commands"));
2717 gtk_widget_show(item
);
2718 gtk_container_add(GTK_CONTAINER(toolmenu
), item
);
2719 g_signal_connect(item
, "activate", G_CALLBACK(on_set_build_commands_activate
), NULL
);
2720 widgets
.toolitem_set_args
= item
;
2722 /* get toolbar action pointers */
2723 widgets
.build_action
= toolbar_get_action_by_name("Build");
2724 widgets
.compile_action
= toolbar_get_action_by_name("Compile");
2725 widgets
.run_action
= toolbar_get_action_by_name("Run");
2726 widgets
.toolmenu
= toolmenu
;
2727 /* set the submenu to the toolbar item */
2728 geany_menu_button_action_set_menu(GEANY_MENU_BUTTON_ACTION(widgets
.build_action
), toolmenu
);