Compare commits

...

14 Commits

Author SHA1 Message Date
Nick Treleaven
b7f525852d Fix not saving project filetype execute commands after dialog editing 2019-10-05 12:31:09 +01:00
Nick Treleaven
381024d333 Update docs for independent execute
Reword build menu configurable groups paragraph.
2019-10-05 12:31:09 +01:00
Nick Treleaven
dfc55085a0 More robust fix for uninitialized BuildDestination::dst 2019-10-05 12:31:09 +01:00
Nick Treleaven
f24d43e7d2 Call build_remove_menu_item instead of manually clearing GeanyBuildCommand 2019-10-05 12:31:09 +01:00
Nick Treleaven
ca8490ffd9 Use g_print for PRINTBUILDCMDS and add info
printf doesn't show with MSYS.
2019-10-05 12:31:09 +01:00
Nick Treleaven
ce0f57d176 Fix segfault after editing project filetype execute command 2019-10-05 12:31:09 +01:00
Nick Treleaven
8de8571c4c Allow overriding number of independent execute commands 2019-10-05 12:31:09 +01:00
Nick Treleaven
84e07f25da Show independent run menu items 2019-10-05 12:31:09 +01:00
Nick Treleaven
e4cd4a09e7 load & save independent exec group instead of ft exec 2019-10-05 12:31:09 +01:00
Nick Treleaven
d138d56cd6 Replace run_info with run_pids
Note: RunInfo.file_type_id is not needed.
2019-10-05 12:31:09 +01:00
Nick Treleaven
9219e983c1 Make build_run_cmd support independent execute & add keybinding 2019-10-05 12:31:09 +01:00
Nick Treleaven
1f7d846cc9 Begin separating filetype-independent execute commands from FT execute
Add GEANY_GBG_EXEC_IND.
2019-10-05 12:31:09 +01:00
Nick Treleaven
e5e2a28dac Replace unhygienic macro calls with array of struct 2019-10-05 12:31:09 +01:00
Nick Treleaven
78a26acdde build.c: Replace return_cmd_if macros with simpler BREAK_IF_CMD macro
Use GeanyFiletypePrivate empty_ftp to avoid checking for NULL filetype.
Rename get_next_build_cmd() `from` parameter to psrc.
2019-10-05 12:31:09 +01:00
8 changed files with 198 additions and 148 deletions

1
TODO
View File

@ -15,7 +15,6 @@ Note: features included in brackets have lower priority.
programming languages (done for C-like filetypes using
filetypes.common named styles)
o asynchronous build commands on Windows
o (filetype-independent run command in build dialog & keybinding)
o (better custom filetype support)
o (custom template insertion - so user can add licenses, etc)
o (selectable menu of arguments to use for Make, from Make Custom)

View File

@ -2651,7 +2651,9 @@ number_ft_menu_items The maximum number of menu items in the 2
number_non_ft_menu_items The maximum number of menu items in the 3 on restart
independent build section.
number_exec_menu_items The maximum number of menu items in the 2 on restart
execute section of the Build menu.
filetype execute section.
number_exec_ind_menu_items The maximum number of menu items in the 2 on restart
independent execute section.
================================ =========================================== ========== ===========
Statusbar Templates
@ -3027,24 +3029,26 @@ in to be configured. For example, if you change one of the default make
commands to run say 'waf' you can also change the label to match.
These settings are saved automatically when Geany is shut down.
The build menu is divided into four groups of items each with different
The build menu has four configurable groups of items each with different
behaviors:
* Filetype build commands - are configurable and depend on the filetype of the
current document; they capture output in the compiler tab and parse it for
- *Filetype build commands* - these depend on the filetype of the
current document. They capture output in the compiler tab and parse it for
errors.
* Independent build commands - are configurable and mostly don't depend on the
filetype of the current document; they also capture output in the
compiler tab and parse it for errors.
* Execute commands - are configurable and intended for executing your
program or other long running programs. The output is not parsed for
errors and is directed to the terminal command selected in `Tools
preferences`_.
* Fixed commands - these perform built-in actions:
- *Independent build commands* - these (mostly) don't depend on the
current filetype. They also capture and parse the output.
- *Filetype execute commands* - these depend on the current filetype
and they are intended for executing your program or other long running
programs. The output is not parsed for errors and is directed to the
terminal command selected in `Tools preferences`_.
- *Independent execute commands* - as above but not dependent on the
current filetype.
* Go to the next error.
* Go to the previous error.
* Show the build menu commands dialog.
The menu also has fixed commands - these perform built-in actions:
* Go to the next error.
* Go to the previous error.
* Show the build menu commands dialog.
The maximum numbers of items in each of the configurable groups can be
configured in `Various preferences`_. Even though the maximum number of
@ -3085,15 +3089,18 @@ is shown in the following table:
| | | | | Label: Make _Object |
| | | | | Command: make %e.o |
+--------------+---------------------+--------------------------+-------------------+-------------------------------+
| Execute | Loads From: project | Loads From: | Loads From: | Label: _Execute |
| | file or else | geany.conf file in | filetypes.xxx in | Command: ./%e |
| | filetype defined in | ~/.config/geany or else | Geany install | |
| | project file | filetypes.xxx file in | | |
| | | ~/.config/geany/filedefs | Saves To: as user | |
| | Saves To: | | preferences left. | |
| | project file | Saves To: | | |
| | | filetypes.xxx file in | | |
| | | ~/.config/geany/filedefs | | |
| Filetype | Loads From: | Loads From: | Loads From: | Label: _Execute |
| Execute | filetype setting | filetypes.xxx file in | filetypes.xxx in | Command: ./%e |
| | stored in | ~/.config/geany/filedefs | Geany install | |
| | project file | | | |
| | | Saves To: Same | Saves To: as user | |
| | Saves To: Same | | preferences left. | |
+--------------+---------------------+--------------------------+-------------------+-------------------------------+
| Independent | Loads From: project | Loads From: | None | None |
| Execute | file | geany.conf file in | | |
| | | ~/.config/geany | | |
| | Saves To: Same | | | |
| | | Saves To: Same | | |
+--------------+---------------------+--------------------------+-------------------+-------------------------------+
The following notes on the table may reference cells by coordinate as *(group, source)*:
@ -3114,10 +3121,9 @@ The following notes on the table may reference cells by coordinate as *(group, s
filetype-independent commands in a filetype file, this provides the ability to
define filetype dependent default menu items.
* *(Execute, Project and Preferences)* - the project independent
execute and preferences independent execute commands can only be set by hand
editing the appropriate file, see `Preferences file format`_ and `Project file
format`_.
* Independent execute - the project and preferences independent execute
commands can only be set by hand editing the appropriate file, see
`Preferences file format`_ and `Project file format`_.
Set Build Commands dialog
^^^^^^^^^^^^^^^^^^^^^^^^^
@ -3190,7 +3196,8 @@ Keyboard shortcuts can be defined for:
* the first two filetype build menu items
* the first three independent build menu items
* the first execute menu item
* the first filetype execute menu item
* the first independent execute menu item
* the fixed menu items (Next/Previous Error, Set Commands)
In the keybindings configuration dialog (see `Keybinding preferences`_)

View File

@ -69,14 +69,6 @@ GeanyBuildInfo build_info = {GEANY_GBG_FT, 0, 0, NULL, GEANY_FILETYPES_NONE, NUL
static gchar *current_dir_entered = NULL;
typedef struct RunInfo
{
GPid pid;
gint file_type_id;
} RunInfo;
static RunInfo *run_info;
#ifndef G_OS_WIN32
static const gchar RUN_SCRIPT_CMD[] = "geany_run_script_XXXXXX.sh";
#endif
@ -155,7 +147,7 @@ static struct
}
widgets;
static guint build_groups_count[GEANY_GBG_COUNT] = { 3, 4, 2 };
static guint build_groups_count[GEANY_GBG_COUNT] = { 3, 4, 2, 2 };
static guint build_items_count = 9;
static void build_exit_cb(GPid pid, gint status, gpointer user_data);
@ -349,84 +341,102 @@ static void printfcmds(void)
}
/* macros to save typing and make the logic visible */
#define return_cmd_if(src, cmds)\
if (cmds != NULL && cmds[cmdindex].exists && below>src)\
{ \
*fr=src; \
if (printbuildcmds) \
printf("cmd[%u,%u]=%u\n",cmdgrp,cmdindex,src); \
return &(cmds[cmdindex]); \
}
#define return_ft_cmd_if(src, cmds)\
if (ft != NULL && ft->priv->cmds != NULL \
&& ft->priv->cmds[cmdindex].exists && below>src)\
{ \
*fr=src; \
if (printbuildcmds) \
printf("cmd[%u,%u]=%u\n",cmdgrp,cmdindex,src); \
return &(ft->priv->cmds[cmdindex]); \
}
/* get the next lowest command taking priority into account */
static GeanyBuildCommand *get_next_build_cmd(GeanyDocument *doc, guint cmdgrp, guint cmdindex,
guint below, guint *from)
typedef struct CommandSet
{
/* Note: parameter below used in macros above */
GeanyFiletype *ft = NULL;
guint sink, *fr = &sink;
GeanyBuildSource src;
GeanyBuildCommand *cmds;
} CommandSet;
// Note: Could return CommandSet instead of using psrc
/* get the next lowest command taking priority into account
* below = only consider GeanyBuildSource values less than this parameter
* psrc = Address to write GeanyBuildSource */
static GeanyBuildCommand *get_next_build_cmd(GeanyDocument *doc,
guint cmdgrp, guint cmdindex, guint below, guint *psrc)
{
g_return_val_if_fail(doc == NULL || doc->is_valid, NULL);
if (printbuildcmds)
printfcmds();
if (cmdgrp >= GEANY_GBG_COUNT)
return NULL;
if (from != NULL)
fr = from;
if (doc == NULL)
doc = document_get_current();
if (doc != NULL)
ft = doc->file_type;
GeanyFiletypePrivate empty_ftp = {}, *ftp =
doc ? doc->file_type->priv : &empty_ftp; // avoid checking for null
CommandSet overloads[6] = {};
switch (cmdgrp)
{
case GEANY_GBG_FT: /* order proj ft, home ft, ft, defft */
if (ft != NULL)
{
return_ft_cmd_if(GEANY_BCS_PROJ, projfilecmds);
return_ft_cmd_if(GEANY_BCS_PREF, homefilecmds);
return_ft_cmd_if(GEANY_BCS_FT, filecmds);
}
return_cmd_if(GEANY_BCS_DEF, ft_def);
case GEANY_GBG_FT: /* order proj ft, home ft, ft, def ft */
{
CommandSet cs[] = {
{GEANY_BCS_PROJ, ftp->projfilecmds},
{GEANY_BCS_PREF, ftp->homefilecmds},
{GEANY_BCS_FT, ftp->filecmds},
{GEANY_BCS_DEF, ft_def},
};
memcpy(overloads, cs, sizeof(cs));
break;
}
case GEANY_GBG_NON_FT: /* order proj, pref, def */
return_cmd_if(GEANY_BCS_PROJ, non_ft_proj);
return_cmd_if(GEANY_BCS_PREF, non_ft_pref);
return_ft_cmd_if(GEANY_BCS_FT, ftdefcmds);
return_cmd_if(GEANY_BCS_DEF, non_ft_def);
{
CommandSet cs[] = {
{GEANY_BCS_PROJ, non_ft_proj},
{GEANY_BCS_PREF, non_ft_pref},
{GEANY_BCS_FT, ftp->ftdefcmds},
{GEANY_BCS_DEF, non_ft_def},
};
memcpy(overloads, cs, sizeof(cs));
break;
case GEANY_GBG_EXEC: /* order proj, proj ft, pref, home ft, ft, def */
return_cmd_if(GEANY_BCS_PROJ, exec_proj);
return_ft_cmd_if(GEANY_BCS_PROJ_FT, projexeccmds);
return_cmd_if(GEANY_BCS_PREF, exec_pref);
return_ft_cmd_if(GEANY_BCS_FT, homeexeccmds);
return_ft_cmd_if(GEANY_BCS_FT, execcmds);
return_cmd_if(GEANY_BCS_DEF, exec_def);
}
case GEANY_GBG_EXEC: /* order proj ft, home ft, ft, def */
{
CommandSet cs[] = {
{GEANY_BCS_PROJ_FT, ftp->projexeccmds},
{GEANY_BCS_FT, ftp->homeexeccmds},
{GEANY_BCS_FT, ftp->execcmds},
{GEANY_BCS_DEF, exec_def},
};
memcpy(overloads, cs, sizeof(cs));
break;
}
case GEANY_GBG_EXEC_IND: /* order proj, pref */
{
CommandSet cs[] = {
{GEANY_BCS_PROJ, exec_proj},
{GEANY_BCS_PREF, exec_pref},
};
memcpy(overloads, cs, sizeof(cs));
break;
}
default:
break;
return NULL;
}
for (guint i = 0; i < G_N_ELEMENTS(overloads); i++)
{
GeanyBuildCommand *cmds = overloads[i].cmds;
guint src = overloads[i].src;
if (cmds != NULL && cmds[cmdindex].exists && src < below)
{
if (psrc)
*psrc = src;
if (printbuildcmds)
g_print("cmd[%u,%u]=%u below=%u; %s\n", cmdgrp, cmdindex, src, below, cmds[cmdindex].command);
return &(cmds[cmdindex]);
}
}
return NULL;
}
/* shortcut to start looking at the top */
static GeanyBuildCommand *get_build_cmd(GeanyDocument *doc, guint grp, guint cmdindex, guint *from)
// Note: could remove psrc parameter, only passed once
static GeanyBuildCommand *get_build_cmd(GeanyDocument *doc, guint grp, guint cmdindex, guint *psrc)
{
return get_next_build_cmd(doc, grp, cmdindex, GEANY_BCS_COUNT, from);
return get_next_build_cmd(doc, grp, cmdindex, GEANY_BCS_COUNT, psrc);
}
@ -505,14 +515,21 @@ static GeanyBuildCommand **get_build_group_pointer(const GeanyBuildSource src, c
case GEANY_BCS_FT: return ft ? &(ft->priv->execcmds): NULL;
case GEANY_BCS_HOME_FT: return ft ? &(ft->priv->homeexeccmds): NULL;
case GEANY_BCS_PROJ_FT: return ft ? &(ft->priv->projexeccmds): NULL;
default: return NULL;
}
break;
case GEANY_GBG_EXEC_IND:
switch (src)
{
case GEANY_BCS_PREF: return &(exec_pref);
case GEANY_BCS_PROJ: return &(exec_proj);
default: return NULL;
}
break;
default:
return NULL;
break;
}
return NULL;
}
@ -833,16 +850,13 @@ static void build_spawn_cmd(GeanyDocument *doc, const gchar *cmd, const gchar *d
* the command; otherwise the command itself is returned. working_dir is a pointer
* to the working directory from which the command is executed. Both strings are
* in the locale encoding. */
static gchar *prepare_run_cmd(GeanyDocument *doc, gchar **working_dir, guint cmdindex)
static gchar *prepare_run_cmd(GeanyDocument *doc, GeanyBuildCommand *cmd, gchar **working_dir)
{
GeanyBuildCommand *cmd = NULL;
const gchar *cmd_working_dir;
gboolean autoclose = FALSE;
gchar *cmd_string_utf8, *working_dir_utf8, *run_cmd, *cmd_string;
GError *error = NULL;
cmd = get_build_cmd(doc, GEANY_GBG_EXEC, cmdindex, NULL);
cmd_string_utf8 = build_replace_placeholder(doc, cmd->command);
cmd_working_dir = cmd->working_dir;
if (EMPTY(cmd_working_dir))
@ -900,20 +914,31 @@ static gchar *prepare_run_cmd(GeanyDocument *doc, gchar **working_dir, guint cmd
}
static void build_run_cmd(GeanyDocument *doc, guint cmdindex)
// array of filetype run IDs followed by independent run IDs
static GPid *run_pids = NULL;
static GPid *get_run_pid(GeanyBuildGroup grp, guint cmd)
{
if (grp == GEANY_GBG_EXEC_IND)
cmd += build_groups_count[GEANY_GBG_EXEC];
return &run_pids[cmd];
}
static void build_run_cmd(GeanyDocument *doc, guint group, guint cmdindex)
{
gchar *working_dir;
gchar *run_cmd = NULL;
if (! DOC_VALID(doc) || doc->file_name == NULL)
return;
run_cmd = prepare_run_cmd(doc, &working_dir, cmdindex);
GeanyBuildCommand *cmd = get_build_cmd(doc, group, cmdindex, NULL);
if (!cmd)
return;
run_cmd = prepare_run_cmd(doc, cmd, &working_dir);
if (run_cmd == NULL)
return;
run_info[cmdindex].file_type_id = doc->file_type->id;
#ifdef HAVE_VTE
if (vte_info.have_vte && vc->run_in_vte)
{
@ -943,7 +968,7 @@ static void build_run_cmd(GeanyDocument *doc, guint cmdindex)
gtk_widget_grab_focus(vc->vte);
msgwin_show_hide(TRUE);
run_info[cmdindex].pid = 1;
*get_run_pid(group, cmdindex) = 1;
g_free(vte_cmd);
}
else
@ -969,11 +994,11 @@ static void build_run_cmd(GeanyDocument *doc, guint cmdindex)
utils_str_replace_all(&locale_term_cmd, "%c", run_cmd);
if (spawn_async(working_dir, locale_term_cmd, NULL, NULL, &(run_info[cmdindex].pid),
GPid *pid = get_run_pid(group, cmdindex);
if (spawn_async(working_dir, locale_term_cmd, NULL, NULL, pid,
&error))
{
g_child_watch_add(run_info[cmdindex].pid, (GChildWatchFunc) run_exit_cb,
(gpointer) &(run_info[cmdindex]));
g_child_watch_add(*pid, run_exit_cb, pid);
build_menu_update(doc);
}
else
@ -986,10 +1011,9 @@ static void build_run_cmd(GeanyDocument *doc, guint cmdindex)
#ifndef G_OS_WIN32
g_unlink(run_cmd);
#endif
run_info[cmdindex].pid = (GPid) 0;
*get_run_pid(group, cmdindex) = (GPid) 0;
}
}
g_free(working_dir);
g_free(run_cmd);
}
@ -1127,11 +1151,11 @@ static void build_exit_cb(GPid child_pid, gint status, gpointer user_data)
static void run_exit_cb(GPid child_pid, gint status, gpointer user_data)
{
RunInfo *run_info_data = user_data;
GPid *pid = user_data;
g_spawn_close_pid(child_pid);
run_info_data->pid = 0;
*pid = 0;
/* reset the stop button and menu item to the original meaning */
build_menu_update(NULL);
}
@ -1274,11 +1298,12 @@ static void on_build_menu_item(GtkWidget *w, gpointer user_data)
}
return;
}
else if (grp == GEANY_GBG_EXEC)
else if (grp == GEANY_GBG_EXEC || grp == GEANY_GBG_EXEC_IND)
{
if (run_info[cmd].pid > (GPid) 1)
GPid *pid = get_run_pid(grp, cmd);
if (*pid > (GPid) 1)
{
kill_process(&run_info[cmd].pid);
kill_process(pid);
return;
}
bc = get_build_cmd(doc, grp, cmd, NULL);
@ -1294,7 +1319,7 @@ static void on_build_menu_item(GtkWidget *w, gpointer user_data)
g_free(uri);
}
else
build_run_cmd(doc, cmd);
build_run_cmd(doc, grp, cmd);
}
else
build_command(doc, grp, cmd, NULL);
@ -1308,6 +1333,7 @@ static void on_build_menu_item(GtkWidget *w, gpointer user_data)
#define MENU_FT_REST (GEANY_GBG_COUNT + GEANY_GBG_FT)
#define MENU_NON_FT_REST (GEANY_GBG_COUNT + GEANY_GBG_NON_FT)
#define MENU_EXEC_REST (GEANY_GBG_COUNT + GEANY_GBG_EXEC)
#define MENU_EXEC_IND_REST (GEANY_GBG_COUNT + GEANY_GBG_EXEC_IND)
/* the separator */
#define MENU_SEPARATOR (2*GEANY_GBG_COUNT)
/* the fixed items */
@ -1353,6 +1379,12 @@ static struct BuildMenuItemSpec {
GBO_TO_CMD(GEANY_GBO_EXEC), NULL, on_build_menu_item},
{NULL, -1, MENU_EXEC_REST,
GBO_TO_CMD(GEANY_GBO_EXEC) + 1, NULL, on_build_menu_item},
{NULL, -1, MENU_SEPARATOR,
GBF_SEP_5, NULL, NULL},
{GTK_STOCK_EXECUTE, GEANY_KEYS_BUILD_RUNINDEPENDENT, GEANY_GBG_EXEC_IND,
0, NULL, on_build_menu_item},
{NULL, -1, MENU_EXEC_IND_REST,
1, NULL, on_build_menu_item},
{NULL, -1, MENU_SEPARATOR,
GBF_SEP_4, NULL, NULL},
{GTK_STOCK_PREFERENCES, GEANY_KEYS_BUILD_OPTIONS, MENU_COMMANDS,
@ -1395,6 +1427,7 @@ static void create_build_menu(BuildMenuItems *build_menu_items)
build_menu_items->menu_item[GEANY_GBG_FT] = g_new0(GtkWidget*, build_groups_count[GEANY_GBG_FT]);
build_menu_items->menu_item[GEANY_GBG_NON_FT] = g_new0(GtkWidget*, build_groups_count[GEANY_GBG_NON_FT]);
build_menu_items->menu_item[GEANY_GBG_EXEC] = g_new0(GtkWidget*, build_groups_count[GEANY_GBG_EXEC]);
build_menu_items->menu_item[GEANY_GBG_EXEC_IND] = g_new0(GtkWidget*, build_groups_count[GEANY_GBG_EXEC_IND]);
build_menu_items->menu_item[GBG_FIXED] = g_new0(GtkWidget*, GBF_COUNT);
for (i = 0; build_menu_specs[i].build_grp != MENU_DONE; ++i)
@ -1527,7 +1560,7 @@ void build_menu_update(GeanyDocument *doc)
else
{
GtkWidget *image;
exec_running = run_info[cmd].pid > (GPid) 1;
exec_running = *get_run_pid(grp, cmd) > (GPid) 1;
cmd_sensitivity = (bc != NULL) || exec_running;
gtk_widget_set_sensitive(menu_item, cmd_sensitivity);
if (cmd == GBO_TO_CMD(GEANY_GBO_EXEC))
@ -2200,20 +2233,16 @@ static gboolean build_read_commands(BuildDestination *dst, BuildTableData table_
void build_read_project(GeanyFiletype *ft, BuildTableData build_properties)
{
BuildDestination menu_dst;
BuildDestination menu_dst = {0};
if (ft != NULL)
{
menu_dst.dst[GEANY_GBG_FT] = &(ft->priv->projfilecmds);
menu_dst.dst[GEANY_GBG_EXEC] = &ft->priv->projexeccmds;
menu_dst.fileregexstr = &(ft->priv->projerror_regex_string);
}
else
{
menu_dst.dst[GEANY_GBG_FT] = NULL;
menu_dst.fileregexstr = NULL;
}
menu_dst.dst[GEANY_GBG_NON_FT] = &non_ft_proj;
menu_dst.dst[GEANY_GBG_EXEC] = &exec_proj;
menu_dst.dst[GEANY_GBG_EXEC_IND] = &exec_proj;
menu_dst.nonfileregexstr = &regex_proj;
build_read_commands(&menu_dst, build_properties, GTK_RESPONSE_ACCEPT);
@ -2228,7 +2257,6 @@ static void show_build_commands_dialog(void)
const gchar *title = _("Set Build Commands");
gint response;
BuildTableData table_data;
BuildDestination prefdsts;
if (doc != NULL)
ft = doc->file_type;
@ -2243,6 +2271,7 @@ static void show_build_commands_dialog(void)
/* run modally to prevent user changing idx filetype */
response = gtk_dialog_run(GTK_DIALOG(dialog));
BuildDestination prefdsts = {0};
prefdsts.dst[GEANY_GBG_NON_FT] = &non_ft_pref;
if (ft != NULL)
{
@ -2250,12 +2279,6 @@ static void show_build_commands_dialog(void)
prefdsts.fileregexstr = &(ft->priv->homeerror_regex_string);
prefdsts.dst[GEANY_GBG_EXEC] = &(ft->priv->homeexeccmds);
}
else
{
prefdsts.dst[GEANY_GBG_FT] = NULL;
prefdsts.fileregexstr = NULL;
prefdsts.dst[GEANY_GBG_EXEC] = NULL;
}
prefdsts.nonfileregexstr = &regex_pref;
if (build_read_commands(&prefdsts, table_data, response) && ft != NULL)
filetypes_save_commands(ft);
@ -2289,7 +2312,7 @@ static const gchar *build_grp_name = "build-menu";
* where gg = FT, NF, EX for the command group
* nn = 2 digit command number
* xx = LB for label, CM for command and WD for working dir */
static const gchar *groups[GEANY_GBG_COUNT] = { "FT", "NF", "EX" };
static const gchar *groups[GEANY_GBG_COUNT] = { "FT", "NF", "EX", "EX" };
static const gchar *fixedkey="xx_xx_xx";
#define set_key_grp(key, grp) (key[prefixlen + 0] = grp[0], key[prefixlen + 1] = grp[1])
@ -2391,12 +2414,12 @@ void build_load_menu(GKeyFile *config, GeanyBuildSource src, gpointer p)
break;
case GEANY_BCS_PREF:
build_load_menu_grp(config, &non_ft_pref, GEANY_GBG_NON_FT, NULL, FALSE);
build_load_menu_grp(config, &exec_pref, GEANY_GBG_EXEC, NULL, FALSE);
build_load_menu_grp(config, &exec_pref, GEANY_GBG_EXEC_IND, NULL, FALSE);
SETPTR(regex_pref, g_key_file_get_string(config, build_grp_name, "error_regex", NULL));
break;
case GEANY_BCS_PROJ:
build_load_menu_grp(config, &non_ft_proj, GEANY_GBG_NON_FT, NULL, FALSE);
build_load_menu_grp(config, &exec_proj, GEANY_GBG_EXEC, NULL, FALSE);
build_load_menu_grp(config, &exec_proj, GEANY_GBG_EXEC_IND, NULL, FALSE);
SETPTR(regex_proj, g_key_file_get_string(config, build_grp_name, "error_regex", NULL));
pj = (GeanyProject*)p;
if (p == NULL)
@ -2481,7 +2504,7 @@ void build_load_menu(GKeyFile *config, GeanyBuildSource src, gpointer p)
if (!EMPTY(value))
{
if (exec_proj == NULL)
exec_proj = g_new0(GeanyBuildCommand, build_groups_count[GEANY_GBG_EXEC]);
exec_proj = g_new0(GeanyBuildCommand, build_groups_count[GEANY_GBG_EXEC_IND]);
if (! exec_proj[GBO_TO_CMD(GEANY_GBO_EXEC)].exists)
{
exec_proj[GBO_TO_CMD(GEANY_GBO_EXEC)].exists = TRUE;
@ -2598,7 +2621,7 @@ void build_save_menu(GKeyFile *config, gpointer ptr, GeanyBuildSource src)
break;
case GEANY_BCS_PREF:
build_save_menu_grp(config, non_ft_pref, GEANY_GBG_NON_FT, NULL);
build_save_menu_grp(config, exec_pref, GEANY_GBG_EXEC, NULL);
build_save_menu_grp(config, exec_pref, GEANY_GBG_EXEC_IND, NULL);
if (!EMPTY(regex_pref))
g_key_file_set_string(config, build_grp_name, "error_regex", regex_pref);
else
@ -2607,7 +2630,7 @@ void build_save_menu(GKeyFile *config, gpointer ptr, GeanyBuildSource src)
case GEANY_BCS_PROJ:
pj = (GeanyProject*)ptr;
build_save_menu_grp(config, non_ft_proj, GEANY_GBG_NON_FT, NULL);
build_save_menu_grp(config, exec_proj, GEANY_GBG_EXEC, NULL);
build_save_menu_grp(config, exec_proj, GEANY_GBG_EXEC_IND, NULL);
if (!EMPTY(regex_proj))
g_key_file_set_string(config, build_grp_name, "error_regex", regex_proj);
else
@ -2703,7 +2726,8 @@ void build_init(void)
ft_def = g_new0(GeanyBuildCommand, build_groups_count[GEANY_GBG_FT]);
non_ft_def = g_new0(GeanyBuildCommand, build_groups_count[GEANY_GBG_NON_FT]);
exec_def = g_new0(GeanyBuildCommand, build_groups_count[GEANY_GBG_EXEC]);
run_info = g_new0(RunInfo, build_groups_count[GEANY_GBG_EXEC]);
run_pids = g_new0(GPid, build_groups_count[GEANY_GBG_EXEC] +
build_groups_count[GEANY_GBG_EXEC_IND]);
for (cmdindex = 0; default_cmds[cmdindex].command != NULL; ++cmdindex)
{
@ -2815,6 +2839,9 @@ gboolean build_keybinding(guint key_id)
case GEANY_KEYS_BUILD_RUN:
item = menu_items->menu_item[GEANY_GBG_EXEC][GBO_TO_CMD(GEANY_GBO_EXEC)];
break;
case GEANY_KEYS_BUILD_RUNINDEPENDENT:
item = menu_items->menu_item[GEANY_GBG_EXEC_IND][0];
break;
case GEANY_KEYS_BUILD_OPTIONS:
item = menu_items->menu_item[GBG_FIXED][GBF_COMMANDS];
break;

View File

@ -36,6 +36,7 @@ typedef enum
GEANY_GBG_FT, /**< filetype items */
GEANY_GBG_NON_FT, /**< non filetype items.*/
GEANY_GBG_EXEC, /**< execute items */
GEANY_GBG_EXEC_IND, /**< independent execute items */
GEANY_GBG_COUNT /**< count of groups. */
} GeanyBuildGroup;
@ -87,6 +88,7 @@ enum GeanyBuildFixedMenuItems
GBF_SEP_2,
GBF_SEP_3,
GBF_SEP_4,
GBF_SEP_5,
GBF_COUNT
};

View File

@ -704,6 +704,8 @@ static void init_default_kb(void)
0, 0, "build_previouserror", _("Previous error"), NULL);
add_kb(group, GEANY_KEYS_BUILD_RUN, NULL,
GDK_F5, 0, "build_run", _("Run"), NULL);
add_kb(group, GEANY_KEYS_BUILD_RUNINDEPENDENT, NULL,
GDK_F5, GDK_SHIFT_MASK, "build_run_ind", _("_Independent Run"), NULL);
add_kb(group, GEANY_KEYS_BUILD_OPTIONS, NULL,
0, 0, "build_options", _("Build options"), NULL);

View File

@ -273,8 +273,9 @@ enum GeanyKeyBindingID
GEANY_KEYS_FORMAT_SENDTOCMD8, /**< Keybinding. */
GEANY_KEYS_FORMAT_SENDTOCMD9, /**< Keybinding. */
GEANY_KEYS_EDITOR_DELETELINETOBEGINNING, /**< Keybinding. */
GEANY_KEYS_DOCUMENT_STRIPTRAILINGSPACES, /**< Keybinding.
* @since 1.34 (API 238) */
GEANY_KEYS_DOCUMENT_STRIPTRAILINGSPACES, /**< Keybinding. */
GEANY_KEYS_BUILD_RUNINDEPENDENT, /**< Keybinding.
* @since 1.34 (API 239) */
GEANY_KEYS_COUNT /* must not be used by plugins */
};

View File

@ -117,6 +117,7 @@ static struct
gint number_ft_menu_items;
gint number_non_ft_menu_items;
gint number_exec_menu_items;
gint number_exec_ind_menu_items;
}
build_menu_prefs;
@ -284,6 +285,8 @@ static void init_pref_groups(void)
"number_non_ft_menu_items", 0);
stash_group_add_integer(group, &build_menu_prefs.number_exec_menu_items,
"number_exec_menu_items", 0);
stash_group_add_integer(group, &build_menu_prefs.number_exec_ind_menu_items,
"number_exec_ind_menu_items", 0);
}
@ -1000,6 +1003,7 @@ static void load_dialog_prefs(GKeyFile *config)
build_set_group_count(GEANY_GBG_FT, build_menu_prefs.number_ft_menu_items);
build_set_group_count(GEANY_GBG_NON_FT, build_menu_prefs.number_non_ft_menu_items);
build_set_group_count(GEANY_GBG_EXEC, build_menu_prefs.number_exec_menu_items);
build_set_group_count(GEANY_GBG_EXEC_IND, build_menu_prefs.number_exec_ind_menu_items);
build_load_menu(config, GEANY_BCS_PREF, NULL);
}

View File

@ -443,6 +443,7 @@ static void destroy_project(gboolean open_default)
/* remove project non filetype build menu items */
build_remove_menu_item(GEANY_BCS_PROJ, GEANY_GBG_NON_FT, -1);
build_remove_menu_item(GEANY_BCS_PROJ, GEANY_GBG_EXEC, -1);
build_remove_menu_item(GEANY_BCS_PROJ, GEANY_GBG_EXEC_IND, -1);
g_free(app->project->name);
g_free(app->project->description);
@ -810,8 +811,6 @@ static gboolean update_config(const PropertyDialogElements *e, gboolean new_proj
GtkTextIter start, end;
GtkTextBuffer *buffer;
GeanyDocument *doc = document_get_current();
GeanyBuildCommand *oldvalue;
GeanyFiletype *ft = doc ? doc->file_type : NULL;
GtkWidget *widget;
gchar *tmp;
GString *str;
@ -827,16 +826,25 @@ static gboolean update_config(const PropertyDialogElements *e, gboolean new_proj
stash_group_update(node->data, e->dialog);
/* read the project build menu */
oldvalue = ft ? ft->priv->projfilecmds : NULL;
build_read_project(ft, e->build_properties);
if (ft != NULL && ft->priv->projfilecmds != oldvalue && ft->priv->project_list_entry < 0)
GeanyFiletype *ft = doc ? doc->file_type : NULL;
if (ft && ft->priv->project_list_entry < 0)
{
if (p->priv->build_filetypes_list == NULL)
p->priv->build_filetypes_list = g_ptr_array_new();
ft->priv->project_list_entry = p->priv->build_filetypes_list->len;
g_ptr_array_add(p->priv->build_filetypes_list, ft);
GeanyBuildCommand *oldbuild = ft->priv->projfilecmds;
GeanyBuildCommand *oldexec = ft->priv->projexeccmds;
build_read_project(ft, e->build_properties);
if (ft->priv->projfilecmds != oldbuild ||
ft->priv->projexeccmds != oldexec)
{
if (p->priv->build_filetypes_list == NULL)
p->priv->build_filetypes_list = g_ptr_array_new();
ft->priv->project_list_entry = p->priv->build_filetypes_list->len;
g_ptr_array_add(p->priv->build_filetypes_list, ft);
}
}
else
build_read_project(NULL, e->build_properties);
build_menu_update(doc);
widget = ui_lookup_widget(e->dialog, "radio_long_line_disabled_project");