[geany/geany] 6e92c5: Altered tools.c to work with the new spawning module
Dimitar Zhekov
git-noreply at xxxxx
Fri May 15 17:07:37 UTC 2015
Branch: refs/heads/master
Author: Dimitar Zhekov <dimitar.zhekov at gmail.com>
Committer: Dimitar Zhekov <dimitar.zhekov at gmail.com>
Date: Mon, 23 Mar 2015 17:46:04 UTC
Commit: 6e92c5f64aa4bcf4434a8d2b191f7e85724d231e
https://github.com/geany/geany/commit/6e92c5f64aa4bcf4434a8d2b191f7e85724d231e
Log Message:
-----------
Altered tools.c to work with the new spawning module
The tools (from Edit -> Format -> Send Selection to) are now spawned
synchronously, which guarantees that both the document and it's
selection will be unchanged when the tool completes.
Modified Paths:
--------------
src/tools.c
Modified: src/tools.c
257 lines changed, 34 insertions(+), 223 deletions(-)
===================================================================
@@ -33,6 +33,7 @@
#include "document.h"
#include "keybindings.h"
#include "sciwrappers.h"
+#include "spawn.h"
#include "support.h"
#include "ui_utils.h"
#include "utils.h"
@@ -48,7 +49,6 @@
#ifdef G_OS_UNIX
# include <sys/types.h>
# include <sys/wait.h>
-# include <signal.h>
#endif
@@ -76,26 +76,6 @@ struct cc_dialog
GtkWidget *button_down;
};
-/* data required by the custom command callbacks */
-struct cc_data
-{
- const gchar *command; /* command launched */
- GeanyDocument *doc; /* document in which replace the selection */
- GString *buffer; /* buffer holding stdout content, or NULL */
- gboolean error; /* whether and error occurred */
- gboolean finished; /* whether the command has finished */
-};
-
-
-static gboolean cc_exists_command(const gchar *command)
-{
- gchar *path = g_find_program_in_path(command);
-
- g_free(path);
-
- return path != NULL;
-}
-
/* update STATUS and TOOLTIP columns according to cmd */
static void cc_dialog_update_row_status(GtkListStore *store, GtkTreeIter *iter, const gchar *cmd)
@@ -103,19 +83,9 @@ static void cc_dialog_update_row_status(GtkListStore *store, GtkTreeIter *iter,
GError *err = NULL;
const gchar *stock_id = GTK_STOCK_NO;
gchar *tooltip = NULL;
- gint argc;
- gchar **argv;
- if (EMPTY(cmd))
+ if (EMPTY(cmd) || spawn_check_command(cmd, TRUE, &err))
stock_id = GTK_STOCK_YES;
- else if (g_shell_parse_argv(cmd, &argc, &argv, &err))
- {
- if (argc > 0 && cc_exists_command(argv[0]))
- stock_id = GTK_STOCK_YES;
- else
- tooltip = g_strdup_printf(_("Invalid command: %s"), _("Command not found"));
- g_strfreev(argv);
- }
else
{
tooltip = g_strdup_printf(_("Invalid command: %s"), err->message);
@@ -227,218 +197,59 @@ static void cc_on_dialog_move_down_clicked(GtkButton *button, struct cc_dialog *
}
-static gboolean cc_iofunc(GIOChannel *ioc, GIOCondition cond, gpointer user_data)
+/* Executes command (which should include all necessary command line args) and passes the current
+ * selection through the standard input of command. The whole output of command replaces the
+ * current selection. */
+void tools_execute_custom_command(GeanyDocument *doc, const gchar *command)
{
- struct cc_data *data = user_data;
-
- if (cond & (G_IO_IN | G_IO_PRI))
- {
- gchar *msg = NULL;
- GIOStatus rv;
- GError *err = NULL;
-
- if (! data->buffer)
- data->buffer = g_string_sized_new(256);
-
- do
- {
- rv = g_io_channel_read_line(ioc, &msg, NULL, NULL, &err);
- if (msg != NULL)
- {
- g_string_append(data->buffer, msg);
- g_free(msg);
- }
- if (G_UNLIKELY(err != NULL))
- {
- geany_debug("%s: %s", G_STRFUNC, err->message);
- g_error_free(err);
- err = NULL;
- }
- } while (rv == G_IO_STATUS_NORMAL || rv == G_IO_STATUS_AGAIN);
-
- if (G_UNLIKELY(rv != G_IO_STATUS_EOF))
- { /* Something went wrong? */
- g_warning("%s: %s\n", G_STRFUNC, "Incomplete command output");
- }
- }
- return FALSE;
-}
-
+ GError *error = NULL;
+ gchar *sel;
+ SpawnWriteData input;
+ GString *output = g_string_sized_new(256);
+ GString *errors = g_string_new(NULL);
+ gint status;
+
+ g_return_if_fail(doc != NULL && command != NULL);
+
+ if (! sci_has_selection(doc->editor->sci))
+ editor_select_lines(doc->editor, FALSE);
-static gboolean cc_iofunc_err(GIOChannel *ioc, GIOCondition cond, gpointer user_data)
-{
- struct cc_data *data = user_data;
+ sel = sci_get_selection_contents(doc->editor->sci);
+ input.ptr = sel;
+ input.size = strlen(sel);
+ ui_set_statusbar(TRUE, _("Passing data and executing custom command: %s"), command);
- if (cond & (G_IO_IN | G_IO_PRI))
+ if (spawn_sync(NULL, command, NULL, NULL, &input, output, errors, &status, &error))
{
- gchar *msg = NULL;
- GString *str = g_string_sized_new(256);
- GIOStatus rv;
-
- do
+ if (*errors->str)
{
- rv = g_io_channel_read_line(ioc, &msg, NULL, NULL, NULL);
- if (msg != NULL)
- {
- g_string_append(str, msg);
- g_free(msg);
- }
- } while (rv == G_IO_STATUS_NORMAL || rv == G_IO_STATUS_AGAIN);
-
- if (!EMPTY(str->str))
- {
- g_warning("%s: %s\n", data->command, str->str);
+ g_warning("%s: %s\n", command, errors->str);
ui_set_statusbar(TRUE,
_("The executed custom command returned an error. "
"Your selection was not changed. Error message: %s"),
- str->str);
- data->error = TRUE;
-
+ errors->str);
}
- g_string_free(str, TRUE);
- }
- data->finished = TRUE;
- return FALSE;
-}
-
-
-static gboolean cc_replace_sel_cb(gpointer user_data)
-{
- struct cc_data *data = user_data;
-
- if (! data->finished)
- { /* keep this function in the main loop until cc_iofunc_err() has finished */
- return TRUE;
- }
-
- if (! data->error && data->buffer != NULL && DOC_VALID(data->doc))
- { /* Command completed successfully */
- sci_replace_sel(data->doc->editor->sci, data->buffer->str);
- }
-
- if (data->buffer)
- g_string_free(data->buffer, TRUE);
- g_slice_free1(sizeof *data, data);
-
- return FALSE;
-}
-
-
-/* check whether the executed command failed and if so do nothing.
- * If it returned with a sucessful exit code, replace the selection. */
-static void cc_exit_cb(GPid child_pid, gint status, gpointer user_data)
-{
- struct cc_data *data = user_data;
-
- /* if there was already an error, skip further checks */
- if (! data->error)
- {
-#ifdef G_OS_UNIX
- if (WIFEXITED(status))
+ else if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS)
{
- if (WEXITSTATUS(status) != EXIT_SUCCESS)
- data->error = TRUE;
- }
- else if (WIFSIGNALED(status))
- { /* the terminating signal: WTERMSIG (status)); */
- data->error = TRUE;
- }
- else
- { /* any other failure occured */
- data->error = TRUE;
- }
-#else
- data->error = ! win32_get_exit_status(child_pid);
-#endif
-
- if (data->error)
- { /* here we are sure data->error was set due to an unsuccessful exit code
- * and so we add an error message */
/* TODO maybe include the exit code in the error message */
ui_set_statusbar(TRUE,
_("The executed custom command exited with an unsuccessful exit code."));
}
- }
-
- g_idle_add(cc_replace_sel_cb, data);
- g_spawn_close_pid(child_pid);
-}
-
-
-/* Executes command (which should include all necessary command line args) and passes the current
- * selection through the standard input of command. The whole output of command replaces the
- * current selection. */
-void tools_execute_custom_command(GeanyDocument *doc, const gchar *command)
-{
- GError *error = NULL;
- GPid pid;
- gchar **argv;
- gint stdin_fd;
- gint stdout_fd;
- gint stderr_fd;
-
- g_return_if_fail(DOC_VALID(doc) && command != NULL);
-
- if (! sci_has_selection(doc->editor->sci))
- editor_select_lines(doc->editor, FALSE);
-
- if (!g_shell_parse_argv(command, NULL, &argv, &error))
- {
- ui_set_statusbar(TRUE, _("Custom command failed: %s"), error->message);
- g_error_free(error);
- return;
- }
- ui_set_statusbar(TRUE, _("Passing data and executing custom command: %s"), command);
-
- if (g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
- NULL, NULL, &pid, &stdin_fd, &stdout_fd, &stderr_fd, &error))
- {
- gchar *sel;
- gint remaining, wrote;
- struct cc_data *data = g_slice_alloc(sizeof *data);
-
- data->error = FALSE;
- data->finished = FALSE;
- data->buffer = NULL;
- data->doc = doc;
- data->command = command;
-
- g_child_watch_add(pid, cc_exit_cb, data);
-
- /* use GIOChannel to monitor stdout */
- utils_set_up_io_channel(stdout_fd, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- FALSE, cc_iofunc, data);
- /* copy program's stderr to Geany's stdout to help error tracking */
- utils_set_up_io_channel(stderr_fd, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- FALSE, cc_iofunc_err, data);
-
- /* get selection */
- sel = sci_get_selection_contents(doc->editor->sci);
-
- /* write data to the command */
- remaining = strlen(sel);
- do
- {
- wrote = write(stdin_fd, sel, remaining);
- if (G_UNLIKELY(wrote < 0))
- {
- g_warning("%s: %s: %s\n", G_STRFUNC, "Failed sending data to command",
- g_strerror(errno));
- break;
- }
- remaining -= wrote;
- } while (remaining > 0);
- close(stdin_fd);
- g_free(sel);
+ else if (output)
+ { /* Command completed successfully */
+ sci_replace_sel(doc->editor->sci, output->str);
+ }
}
else
{
- geany_debug("g_spawn_async_with_pipes() failed: %s", error->message);
+ geany_debug("spawn_sync() failed: %s", error->message);
ui_set_statusbar(TRUE, _("Custom command failed: %s"), error->message);
g_error_free(error);
}
- g_strfreev(argv);
+ g_string_free(output, TRUE);
+ g_string_free(errors, TRUE);
+ g_free(sel);
}
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
More information about the Commits
mailing list