This proposal shouldn't be too bad. But please tell me if you see thing that should be changed.
If it's OK, I will make a proper pull request.
<details> <summary>show code diff</summary>
```c diff --git a/src/build.c b/src/build.c index 56ec9d613..4e7a5a48b 100644 --- a/src/build.c +++ b/src/build.c @@ -168,6 +168,7 @@ static void run_exit_cb(GPid child_pid, gint status, gpointer user_data); static void on_set_build_commands_activate(GtkWidget *w, gpointer u); static void on_build_next_error(GtkWidget *menuitem, gpointer user_data); static void on_build_previous_error(GtkWidget *menuitem, gpointer user_data); +static void on_build_current_line_error(GtkWidget *menuitem, gpointer user_data); static void kill_process(GPid *pid); static void show_build_result_message(gboolean failure); static void process_build_output_line(gchar *msg, gint color); @@ -1030,6 +1031,7 @@ static void process_build_output_line(gchar *msg, gint color) { gtk_widget_set_sensitive(build_get_menu_items(-1)->menu_item[GBG_FIXED][GBF_NEXT_ERROR], TRUE); gtk_widget_set_sensitive(build_get_menu_items(-1)->menu_item[GBG_FIXED][GBF_PREV_ERROR], TRUE); + gtk_widget_set_sensitive(build_get_menu_items(-1)->menu_item[GBG_FIXED][GBF_CUR_LINE_ERROR], TRUE); } } g_free(filename); @@ -1318,7 +1320,8 @@ static void on_build_menu_item(GtkWidget *w, gpointer user_data) /* the fixed items */ #define MENU_NEXT_ERROR (MENU_SEPARATOR + 1) #define MENU_PREV_ERROR (MENU_NEXT_ERROR + 1) -#define MENU_COMMANDS (MENU_PREV_ERROR + 1) +#define MENU_CUR_LINE_ERROR (MENU_PREV_ERROR + 1) +#define MENU_COMMANDS (MENU_CUR_LINE_ERROR + 1) #define MENU_DONE (MENU_COMMANDS + 1)
@@ -1352,6 +1355,8 @@ static struct BuildMenuItemSpec { GBF_NEXT_ERROR, N_("_Next Error"), on_build_next_error}, {GTK_STOCK_GO_UP, GEANY_KEYS_BUILD_PREVIOUSERROR, MENU_PREV_ERROR, GBF_PREV_ERROR, N_("_Previous Error"), on_build_previous_error}, + {NULL, GEANY_KEYS_BUILD_CURRENTLINEERROR, MENU_CUR_LINE_ERROR, + GBF_CUR_LINE_ERROR, N_("_Current Line Error"), on_build_current_line_error}, {NULL, -1, MENU_SEPARATOR, GBF_SEP_3, NULL, NULL}, {GTK_STOCK_EXECUTE, GEANY_KEYS_BUILD_RUN, GBO_TO_GBG(GEANY_GBO_EXEC), @@ -1489,6 +1494,7 @@ void build_menu_update(GeanyDocument *doc) break; case MENU_NEXT_ERROR: case MENU_PREV_ERROR: + case MENU_CUR_LINE_ERROR: gtk_widget_set_sensitive(menu_items.menu_item[GBG_FIXED][bs->build_cmd], have_errors); vis |= TRUE; break; @@ -1702,6 +1708,18 @@ static void on_build_previous_error(GtkWidget *menuitem, gpointer user_data) }
+static void on_build_current_line_error(GtkWidget *menuitem, gpointer user_data) +{ + if (ui_tree_view_find_cur_line(GTK_TREE_VIEW(msgwindow.tree_compiler), + msgwin_goto_compiler_file_line)) + { + gtk_notebook_set_current_page(GTK_NOTEBOOK(msgwindow.notebook), MSG_COMPILER); + } + else + ui_set_statusbar(FALSE, _("No more build errors.")); +} + + void build_toolbutton_build_clicked(GtkAction *action, gpointer unused) { if (last_toolbutton_action == GBO_TO_POINTER(GEANY_GBO_BUILD)) @@ -2807,6 +2825,9 @@ gboolean build_keybinding(guint key_id) case GEANY_KEYS_BUILD_PREVIOUSERROR: item = menu_items->menu_item[GBG_FIXED][GBF_PREV_ERROR]; break; + case GEANY_KEYS_BUILD_CURRENTLINEERROR: + item = menu_items->menu_item[GBG_FIXED][GBF_CUR_LINE_ERROR]; + break; case GEANY_KEYS_BUILD_RUN: item = menu_items->menu_item[GEANY_GBG_EXEC][GBO_TO_CMD(GEANY_GBO_EXEC)]; break; diff --git a/src/build.h b/src/build.h index f9d720d06..eab27bfe2 100644 --- a/src/build.h +++ b/src/build.h @@ -82,6 +82,7 @@ enum GeanyBuildFixedMenuItems { GBF_NEXT_ERROR, GBF_PREV_ERROR, + GBF_CUR_LINE_ERROR, GBF_COMMANDS, GBF_SEP_1, GBF_SEP_2, diff --git a/src/keybindings.c b/src/keybindings.c index 1721fcd1b..439a212d4 100644 --- a/src/keybindings.c +++ b/src/keybindings.c @@ -705,6 +705,8 @@ static void init_default_kb(void) 0, 0, "build_nexterror", _("Next error"), NULL); add_kb(group, GEANY_KEYS_BUILD_PREVIOUSERROR, NULL, 0, 0, "build_previouserror", _("Previous error"), NULL); + add_kb(group, GEANY_KEYS_BUILD_CURRENTLINEERROR, NULL, + GDK_KEY_F3, 0, "build_currentlineerror", _("Current line error"), NULL); add_kb(group, GEANY_KEYS_BUILD_RUN, NULL, GDK_KEY_F5, 0, "build_run", _("Run"), NULL); add_kb(group, GEANY_KEYS_BUILD_OPTIONS, NULL, diff --git a/src/keybindings.h b/src/keybindings.h index e88bebc7f..787c0ff41 100644 --- a/src/keybindings.h +++ b/src/keybindings.h @@ -229,6 +229,7 @@ enum GeanyKeyBindingID GEANY_KEYS_SELECT_ALL, /**< Keybinding. */ GEANY_KEYS_DOCUMENT_RELOADTAGLIST, /**< Keybinding. */ GEANY_KEYS_BUILD_NEXTERROR, /**< Keybinding. */ + GEANY_KEYS_BUILD_CURRENTLINEERROR, /**< Keybinding. */ GEANY_KEYS_NOTEBOOK_MOVETABLAST, /**< Keybinding. */ GEANY_KEYS_SELECT_PARAGRAPH, /**< Keybinding. */ GEANY_KEYS_EDITOR_DELETELINE, /**< Keybinding. */ diff --git a/src/msgwindow.c b/src/msgwindow.c index 350ec3880..94b30bf89 100644 --- a/src/msgwindow.c +++ b/src/msgwindow.c @@ -180,7 +180,7 @@ static gboolean on_msgwin_key_press_event(GtkWidget *widget, GdkEventKey *event, { case MSG_COMPILER: { /* key press in the compiler treeview */ - msgwin_goto_compiler_file_line(enter_or_return); + msgwin_goto_compiler_file_line(enter_or_return, FALSE); break; } case MSG_MESSAGE: @@ -793,7 +793,7 @@ static gboolean goto_compiler_file_line(const gchar *fname, gint line, gboolean }
-gboolean msgwin_goto_compiler_file_line(gboolean focus_editor) +gboolean msgwin_goto_compiler_file_line(gboolean focus_editor, gboolean cur_line_mode) { GtkTreeIter iter; GtkTreeModel *model; @@ -821,6 +821,9 @@ gboolean msgwin_goto_compiler_file_line(gboolean focus_editor) gchar *filename, *dir; GtkTreePath *path; gboolean ret; + GeanyDocument *doc = document_get_current(); + gint pos = sci_get_current_position(doc->editor->sci); + guint cur_line = sci_get_line_from_position(doc->editor->sci, pos) + 1;
path = gtk_tree_model_get_path(model, &iter); find_prev_build_dir(path, model, &dir); @@ -829,7 +832,18 @@ gboolean msgwin_goto_compiler_file_line(gboolean focus_editor) g_free(string); g_free(dir);
- ret = goto_compiler_file_line(filename, line, focus_editor); + if (cur_line_mode) + { + ret = FALSE; + if (line == cur_line) + { + ret = goto_compiler_file_line(filename, line, focus_editor); + } + } + else + { + ret = goto_compiler_file_line(filename, line, focus_editor); + } g_free(filename); return ret; } @@ -1218,7 +1232,7 @@ static gboolean on_msgwin_button_press_event(GtkWidget *widget, GdkEventButton * { case MSG_COMPILER: { /* mouse click in the compiler treeview */ - msgwin_goto_compiler_file_line(double_click); + msgwin_goto_compiler_file_line(double_click, FALSE); break; } case MSG_MESSAGE: diff --git a/src/msgwindow.h b/src/msgwindow.h index 07b06dbc7..9f38f0b6d 100644 --- a/src/msgwindow.h +++ b/src/msgwindow.h @@ -100,7 +100,7 @@ void msgwin_show_hide_tabs(void);
void msgwin_menu_add_common_items(GtkMenu *menu);
-gboolean msgwin_goto_compiler_file_line(gboolean focus_editor); +gboolean msgwin_goto_compiler_file_line(gboolean focus_editor, gboolean cur_line);
void msgwin_parse_compiler_error_line(const gchar *string, const gchar *dir, gchar **filename, gint *line); diff --git a/src/ui_utils.c b/src/ui_utils.c index 729feae94..a2ae7103c 100644 --- a/src/ui_utils.c +++ b/src/ui_utils.c @@ -1768,28 +1768,41 @@ static gboolean tree_model_iter_get_next(GtkTreeModel *model, GtkTreeIter *iter,
/* note: the while loop might be more efficient when searching upwards if it * used tree paths instead of tree iters, but in practice it probably doesn't matter much. */ -static gboolean tree_view_find(GtkTreeView *treeview, TVMatchCallback cb, gboolean down) +static gboolean tree_view_find(GtkTreeView *treeview, TVMatchCallback cb, + GeanyMenuCompileErrorSearchMode err_search_mode) { GtkTreeSelection *treesel; GtkTreeIter iter; GtkTreeModel *model;
treesel = gtk_tree_view_get_selection(treeview); - if (gtk_tree_selection_get_selected(treesel, &model, &iter)) + gboolean active_selection = gtk_tree_selection_get_selected(treesel, &model, &iter); + gboolean down = err_search_mode == GEANY_MENU_COMPILE_NEXT_ERROR || GEANY_MENU_COMPILE_CUR_LINE_ERROR; + if (err_search_mode == GEANY_MENU_COMPILE_CUR_LINE_ERROR) { - /* get the next selected item */ - if (! tree_model_iter_get_next(model, &iter, down)) - return FALSE; /* no more items */ + if (active_selection) + tree_model_iter_get_next(model, &iter, TRUE); + if (! gtk_tree_model_get_iter_first(model, &iter)) + return TRUE; } - else /* no selection */ + else { - if (! gtk_tree_model_get_iter_first(model, &iter)) - return TRUE; /* no items */ + if (active_selection) + { + /* get the next selected item */ + if (! tree_model_iter_get_next(model, &iter, down)) + return FALSE; /* no more items */ + } + else /* no selection */ + { + if (! gtk_tree_model_get_iter_first(model, &iter)) + return TRUE; /* no items */ + } } while (TRUE) { gtk_tree_selection_select_iter(treesel, &iter); - if (cb(FALSE)) + if (cb(FALSE, err_search_mode == GEANY_MENU_COMPILE_CUR_LINE_ERROR)) break; /* found next message */
if (! tree_model_iter_get_next(model, &iter, down)) @@ -1811,14 +1824,21 @@ static gboolean tree_view_find(GtkTreeView *treeview, TVMatchCallback cb, gboole /* Returns FALSE if the treeview has items but no matching next item. */ gboolean ui_tree_view_find_next(GtkTreeView *treeview, TVMatchCallback cb) { - return tree_view_find(treeview, cb, TRUE); + return tree_view_find(treeview, cb, GEANY_MENU_COMPILE_NEXT_ERROR); }
/* Returns FALSE if the treeview has items but no matching next item. */ gboolean ui_tree_view_find_previous(GtkTreeView *treeview, TVMatchCallback cb) { - return tree_view_find(treeview, cb, FALSE); + return tree_view_find(treeview, cb, GEANY_MENU_COMPILE_PREV_ERROR); +} + + +/* Returns FALSE if the treeview has items but no matching next item. */ +gboolean ui_tree_view_find_cur_line(GtkTreeView *treeview, TVMatchCallback cb) +{ + return tree_view_find(treeview, cb, GEANY_MENU_COMPILE_CUR_LINE_ERROR); }
diff --git a/src/ui_utils.h b/src/ui_utils.h index f71790a54..eb0a5f94e 100644 --- a/src/ui_utils.h +++ b/src/ui_utils.h @@ -232,6 +232,15 @@ typedef enum GeanyUIEditorFeatures;
+typedef enum +{ + GEANY_MENU_COMPILE_NEXT_ERROR, + GEANY_MENU_COMPILE_PREV_ERROR, + GEANY_MENU_COMPILE_CUR_LINE_ERROR +} +GeanyMenuCompileErrorSearchMode; + + void ui_widget_show_hide(GtkWidget *widget, gboolean show);
gchar *ui_menu_item_get_text(GtkMenuItem *menu_item); @@ -340,7 +349,7 @@ void ui_update_recent_project_menu(void); void ui_update_tab_status(GeanyDocument *doc);
-typedef gboolean TVMatchCallback(gboolean); +typedef gboolean TVMatchCallback(gboolean, gboolean);
gboolean ui_tree_view_find_next(GtkTreeView *treeview, TVMatchCallback cb);
```
</details>