From 4eb2fdf219b3998a63f779929cd790e7bcbdb698 Mon Sep 17 00:00:00 2001 From: Yevgen Muntyan <17531749+muntyan@users.noreply.github.com> Date: Sun, 11 Sep 2005 17:51:34 +0000 Subject: [PATCH] Added MooCmdView - widget for running commands and printing output --- moo.kdevelop | 26 +- moo/mooapp/mooapp.c | 2 +- moo/mooedit/Makefile.am | 2 + moo/mooedit/moocmdview.c | 579 ++++++++++++++++++ moo/mooedit/moocmdview.h | 71 +++ moo/mooedit/moopaneview.c | 175 +++++- moo/mooedit/moopaneview.h | 6 +- moo/mooedit/mootextview.c | 17 + moo/mooedit/mootextview.h | 3 + moo/mooedit/plugins/Makefile.am | 14 +- moo/mooedit/plugins/mooeditplugins.h | 2 +- moo/mooedit/plugins/{moogrep.c => moofind.c} | 501 ++++----------- .../plugins/{moogrep.glade => moofind.glade} | 287 --------- moo/mooutils/moomarshals.list | 2 + moo/mooutils/moostock.c | 3 +- moo/mooutils/moostock.h | 3 +- tests/medit.c.in | 2 +- 17 files changed, 993 insertions(+), 702 deletions(-) create mode 100644 moo/mooedit/moocmdview.c create mode 100644 moo/mooedit/moocmdview.h rename moo/mooedit/plugins/{moogrep.c => moofind.c} (54%) rename moo/mooedit/plugins/{moogrep.glade => moofind.glade} (54%) diff --git a/moo.kdevelop b/moo.kdevelop index a0853573..7af21ef0 100644 --- a/moo.kdevelop +++ b/moo.kdevelop @@ -36,7 +36,7 @@ debug - tests/editor + tests/medit executable / @@ -46,7 +46,7 @@ - --enable-debug=full --enable-all-gcc-warnings=fatal --enable-developer-mode --disable-moo-module --without-python --without-mooterm --without-mooui + --enable-debug=full --enable-all-gcc-warnings=fatal --enable-developer-mode --disable-moo-module --without-python --without-mooterm --without-mooui --without-mooapp build/debug kdevgccoptions kdevgppoptions @@ -54,13 +54,13 @@ -O0 -g3 -pg -O0 -g3 -pg - - - - - - - + + + + + + + --enable-all-gcc-warnings=fatal --enable-developer-mode --without-mooapp --without-mooterm --without-python @@ -251,16 +251,16 @@ - + A new empty GAP source file - + A new empty C++ file. - + A new empty header file for C/C++. - + A new empty C file. diff --git a/moo/mooapp/mooapp.c b/moo/mooapp/mooapp.c index 7c7e1dda..638b253b 100644 --- a/moo/mooapp/mooapp.c +++ b/moo/mooapp/mooapp.c @@ -717,7 +717,7 @@ static gboolean moo_app_init_real (MooApp *app) G_CALLBACK (all_editors_closed), app); - moo_grep_init (); + moo_find_init (); moo_file_selector_init (); moo_plugin_read_dir (plugin_dir); diff --git a/moo/mooedit/Makefile.am b/moo/mooedit/Makefile.am index 235cae1e..7c446dbc 100644 --- a/moo/mooedit/Makefile.am +++ b/moo/mooedit/Makefile.am @@ -35,6 +35,8 @@ libmooedit_la_LIBADD = \ libmooedit_la_SOURCES = \ moobigpaned.c \ moobigpaned.h \ + moocmdview.c \ + moocmdview.h \ mooedit.c \ mooedit.h \ mooedit-private.h \ diff --git a/moo/mooedit/moocmdview.c b/moo/mooedit/moocmdview.c new file mode 100644 index 00000000..eb9917bc --- /dev/null +++ b/moo/mooedit/moocmdview.c @@ -0,0 +1,579 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*- + * + * moopaneview.c + * + * Copyright (C) 2004-2005 by Yevgen Muntyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * See COPYING file that comes with this distribution. + */ + +#include "mooedit/moocmdview.h" +#include "mooutils/moomarshals.h" +#include + + +struct _MooCmdViewPrivate { + gboolean running; + char *cmd; + int exit_status; + GPid pid; + int stdout; + int stderr; + GIOChannel *stdout_io; + GIOChannel *stderr_io; + guint child_watch; + guint stdout_watch; + guint stderr_watch; + + GtkTextTag *error_tag; + GtkTextTag *message_tag; + GtkTextTag *stdout_tag; + GtkTextTag *stderr_tag; +}; + +static void moo_cmd_view_finalize (GObject *object); +static void moo_cmd_view_destroy (GtkObject *object); +static GObject *moo_cmd_view_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_param); + +static void moo_cmd_view_check_stop (MooCmdView *view); +static void moo_cmd_view_cleanup (MooCmdView *view); + +static gboolean moo_cmd_view_abort_real (MooCmdView *view); +static gboolean moo_cmd_view_cmd_exit (MooCmdView *view, + int status); +static gboolean moo_cmd_view_stdout_line (MooCmdView *view, + const char *line); +static gboolean moo_cmd_view_stderr_line (MooCmdView *view, + const char *line); + + + +enum { + ABORT, + CMD_EXIT, + OUTPUT_LINE, + STDOUT_LINE, + STDERR_LINE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + + +enum { + PROP_0, +}; + + +/* MOO_TYPE_CMD_VIEW */ +G_DEFINE_TYPE (MooCmdView, moo_cmd_view, MOO_TYPE_PANE_VIEW) + + +static void +moo_cmd_view_class_init (MooCmdViewClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (klass); + + gobject_class->finalize = moo_cmd_view_finalize; + gobject_class->constructor = moo_cmd_view_constructor; + + gtkobject_class->destroy = moo_cmd_view_destroy; + + klass->abort = moo_cmd_view_abort_real; + klass->cmd_exit = moo_cmd_view_cmd_exit; + klass->output_line = NULL; + klass->stdout_line = moo_cmd_view_stdout_line; + klass->stderr_line = moo_cmd_view_stderr_line; + + signals[ABORT] = + g_signal_new ("abort", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (MooCmdViewClass, abort), + g_signal_accumulator_true_handled, NULL, + _moo_marshal_BOOL__VOID, + G_TYPE_BOOLEAN, 0); + + signals[CMD_EXIT] = + g_signal_new ("cmd-exit", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MooCmdViewClass, cmd_exit), + g_signal_accumulator_true_handled, NULL, + _moo_marshal_BOOL__INT, + G_TYPE_BOOLEAN, 1, + G_TYPE_INT); + + signals[OUTPUT_LINE] = + g_signal_new ("output-line", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MooCmdViewClass, output_line), + g_signal_accumulator_true_handled, NULL, + _moo_marshal_BOOL__STRING_BOOL, + G_TYPE_BOOLEAN, 2, + G_TYPE_STRING, G_TYPE_BOOLEAN); + + signals[STDOUT_LINE] = + g_signal_new ("stdout-line", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MooCmdViewClass, stdout_line), + g_signal_accumulator_true_handled, NULL, + _moo_marshal_BOOL__STRING, + G_TYPE_BOOLEAN, 1, + G_TYPE_STRING); + + signals[STDERR_LINE] = + g_signal_new ("stderr-line", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (MooCmdViewClass, stderr_line), + g_signal_accumulator_true_handled, NULL, + _moo_marshal_BOOL__STRING, + G_TYPE_BOOLEAN, 1, + G_TYPE_STRING); +} + + +static void +moo_cmd_view_init (MooCmdView *view) +{ + view->priv = g_new0 (MooCmdViewPrivate, 1); +} + + +static void +moo_cmd_view_finalize (GObject *object) +{ + MooCmdView *view = MOO_CMD_VIEW (object); + + g_free (view->priv); + + G_OBJECT_CLASS (moo_cmd_view_parent_class)->finalize (object); +} + + +static GObject* +moo_cmd_view_constructor (GType type, + guint n_props, + GObjectConstructParam *props) +{ + GObject *object; + MooCmdView *view; + GtkTextBuffer *buffer; + + object = G_OBJECT_CLASS(moo_cmd_view_parent_class)->constructor (type, n_props, props); + view = MOO_CMD_VIEW (object); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + + view->priv->message_tag = gtk_text_buffer_create_tag (buffer, "message", NULL); + view->priv->error_tag = gtk_text_buffer_create_tag (buffer, "error", NULL); + view->priv->stdout_tag = gtk_text_buffer_create_tag (buffer, "stdout", NULL); + view->priv->stderr_tag = gtk_text_buffer_create_tag (buffer, "stderr", NULL); + + g_object_set (view->priv->error_tag, "foreground", "red", NULL); + g_object_set (view->priv->stderr_tag, "foreground", "red", NULL); + + return object; +} + + +static void +moo_cmd_view_destroy (GtkObject *object) +{ + MooCmdView *view = MOO_CMD_VIEW (object); + + moo_cmd_view_abort (view); + + if (GTK_OBJECT_CLASS (moo_cmd_view_parent_class)->destroy) + GTK_OBJECT_CLASS (moo_cmd_view_parent_class)->destroy (object); +} + + +GtkWidget* +moo_cmd_view_new (void) +{ + return g_object_new (MOO_TYPE_CMD_VIEW, NULL); +} + + +static void +command_exit (GPid pid, + gint status, + MooCmdView *view) +{ + g_return_if_fail (pid == view->priv->pid); + + view->priv->child_watch = 0; + view->priv->exit_status = status; + + g_spawn_close_pid (view->priv->pid); + view->priv->pid = 0; + + moo_cmd_view_check_stop (view); +} + + +static void +process_line (MooCmdView *view, + const char *line, + gboolean stderr) +{ + gboolean handled = FALSE; + + g_signal_emit (view, signals[OUTPUT_LINE], 0, line, stderr, &handled); + + if (!handled) + { + if (stderr) + g_signal_emit (view, signals[STDERR_LINE], 0, line, &handled); + else + g_signal_emit (view, signals[STDOUT_LINE], 0, line, &handled); + } +} + + +static gboolean +command_out_or_err (MooCmdView *view, + GIOChannel *channel, + GIOCondition condition, + gboolean stdout) +{ + char *line; + GError *error = NULL; + GIOStatus status; + + status = g_io_channel_read_line (channel, &line, NULL, NULL, &error); + + if (line) + { + process_line (view, line, !stdout); + g_free (line); + } + + if (error) + { + g_warning ("%s: %s", G_STRLOC, error->message); + g_error_free (error); + return FALSE; + } + + if (condition & (G_IO_ERR | G_IO_HUP)) + return FALSE; + + if (status == G_IO_STATUS_EOF) + return FALSE; + + return TRUE; +} + + +static gboolean +command_out (GIOChannel *channel, + GIOCondition condition, + MooCmdView *view) +{ + return command_out_or_err (view, channel, condition, TRUE); +} + + +static gboolean +command_err (GIOChannel *channel, + GIOCondition condition, + MooCmdView *view) +{ + return command_out_or_err (view, channel, condition, FALSE); +} + + +static void +try_channel_leftover (MooCmdView *view, + GIOChannel *channel, + gboolean stdout) +{ + char *text; + + g_io_channel_read_to_end (channel, &text, NULL, NULL); + + if (text) + { + char **lines, **p; + g_strdelimit (text, "\r", '\n'); + lines = g_strsplit (text, "\n", 0); + + if (lines) + { + for (p = lines; *p != NULL; p++) + if (**p) + process_line (view, *p, !stdout); + } + + g_strfreev (lines); + g_free (text); + } +} + + +static void +stdout_watch_removed (MooCmdView *view) +{ + if (view->priv->stdout_io) + { + try_channel_leftover (view, view->priv->stdout_io, TRUE); + g_io_channel_unref (view->priv->stdout_io); + } + + view->priv->stdout_io = NULL; + view->priv->stdout_watch = 0; + moo_cmd_view_check_stop (view); +} + + +static void +stderr_watch_removed (MooCmdView *view) +{ + if (view->priv->stderr_io) + { + try_channel_leftover (view, view->priv->stderr_io, TRUE); + g_io_channel_unref (view->priv->stderr_io); + } + + view->priv->stderr_io = NULL; + view->priv->stderr_watch = 0; + moo_cmd_view_check_stop (view); +} + + +gboolean +moo_cmd_view_run_command (MooCmdView *view, + const char *cmd) +{ + GError *error = NULL; + char **argv = NULL; + gboolean result = TRUE; + + g_return_val_if_fail (MOO_IS_CMD_VIEW (view), FALSE); + g_return_val_if_fail (cmd && cmd[0], FALSE); + + g_return_val_if_fail (!view->priv->running, FALSE); + + moo_pane_view_write_line (MOO_PANE_VIEW (view), cmd, -1, + view->priv->message_tag); + + argv = g_new (char*, 4); + argv[0] = g_strdup ("/bin/sh"); + argv[1] = g_strdup ("-c"); + argv[2] = g_strdup (cmd); + argv[3] = NULL; + + g_spawn_async_with_pipes (NULL, + argv, NULL, + G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, + &view->priv->pid, + NULL, + &view->priv->stdout, + &view->priv->stderr, + &error); + + if (error) + { + moo_pane_view_write_line (MOO_PANE_VIEW (view), + error->message, -1, + view->priv->error_tag); + g_error_free (error); + goto out; + } + + view->priv->running = TRUE; + view->priv->cmd = g_strdup (cmd); + + view->priv->child_watch = + g_child_watch_add (view->priv->pid, + (GChildWatchFunc) command_exit, + view); + + view->priv->stdout_io = g_io_channel_unix_new (view->priv->stdout); + g_io_channel_set_encoding (view->priv->stdout_io, NULL, NULL); + g_io_channel_set_buffered (view->priv->stdout_io, TRUE); + g_io_channel_set_flags (view->priv->stdout_io, G_IO_FLAG_NONBLOCK, NULL); + g_io_channel_set_close_on_unref (view->priv->stdout_io, TRUE); + view->priv->stdout_watch = + g_io_add_watch_full (view->priv->stdout_io, + G_PRIORITY_DEFAULT_IDLE, + G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, + (GIOFunc) command_out, view, + (GDestroyNotify) stdout_watch_removed); + + view->priv->stderr_io = g_io_channel_unix_new (view->priv->stderr); + g_io_channel_set_encoding (view->priv->stderr_io, NULL, NULL); + g_io_channel_set_buffered (view->priv->stderr_io, TRUE); + g_io_channel_set_flags (view->priv->stderr_io, G_IO_FLAG_NONBLOCK, NULL); + g_io_channel_set_close_on_unref (view->priv->stderr_io, TRUE); + view->priv->stderr_watch = + g_io_add_watch_full (view->priv->stderr_io, + G_PRIORITY_DEFAULT_IDLE, + G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, + (GIOFunc) command_err, view, + (GDestroyNotify) stderr_watch_removed); + +out: + g_strfreev (argv); + return result; +} + + +static void +moo_cmd_view_check_stop (MooCmdView *view) +{ + gboolean result; + + if (!view->priv->running) + return; + + if (!view->priv->child_watch && !view->priv->stdout_watch && !view->priv->stderr_watch) + { + g_signal_emit (view, signals[CMD_EXIT], 0, view->priv->exit_status, &result); + moo_cmd_view_cleanup (view); + } +} + + +static gboolean +moo_cmd_view_cmd_exit (MooCmdView *view, + int status) +{ + if (WIFEXITED (status)) + { + guint8 exit_code = WEXITSTATUS (status); + + if (!exit_code) + { + moo_pane_view_write_line (MOO_PANE_VIEW (view), + "*** Done ***", -1, + view->priv->message_tag); + } + else + { + char *msg = g_strdup_printf ("*** Failed with code %d ***", + exit_code); + moo_pane_view_write_line (MOO_PANE_VIEW (view), + msg, -1, + view->priv->error_tag); + g_free (msg); + } + } +#ifdef WCOREDUMP + else if (WCOREDUMP (status)) + { + moo_pane_view_write_line (MOO_PANE_VIEW (view), + "*** Dumped core ***", -1, + view->priv->error_tag); + } +#endif + else if (WIFSIGNALED (status)) + { + moo_pane_view_write_line (MOO_PANE_VIEW (view), + "*** Killed ***", -1, + view->priv->error_tag); + } + else + { + moo_pane_view_write_line (MOO_PANE_VIEW (view), + "*** ??? ***", -1, + view->priv->error_tag); + } + + return FALSE; +} + + +static void +moo_cmd_view_cleanup (MooCmdView *view) +{ + if (!view->priv->running) + return; + + view->priv->running = FALSE; + + if (view->priv->child_watch) + g_source_remove (view->priv->child_watch); + if (view->priv->stdout_watch) + g_source_remove (view->priv->stdout_watch); + if (view->priv->stderr_watch) + g_source_remove (view->priv->stderr_watch); + + if (view->priv->stdout_io) + g_io_channel_unref (view->priv->stdout_io); + if (view->priv->stderr_io) + g_io_channel_unref (view->priv->stderr_io); + + if (view->priv->pid) + { + kill (view->priv->pid, SIGTERM); + g_spawn_close_pid (view->priv->pid); + } + + g_free (view->priv->cmd); + view->priv->cmd = NULL; + view->priv->pid = 0; + view->priv->stdout = -1; + view->priv->stderr = -1; + view->priv->child_watch = 0; + view->priv->stdout_watch = 0; + view->priv->stderr_watch = 0; + view->priv->stdout_io = NULL; + view->priv->stderr_io = NULL; +} + + +static gboolean +moo_cmd_view_abort_real (MooCmdView *view) +{ + if (!view->priv->running) + return TRUE; + + g_return_val_if_fail (view->priv->pid != 0, TRUE); + + kill (view->priv->pid, SIGTERM); + return TRUE; +} + + +void +moo_cmd_view_abort (MooCmdView *view) +{ + gboolean handled; + g_return_if_fail (MOO_IS_CMD_VIEW (view)); + g_signal_emit (view, signals[ABORT], 0, &handled); +} + + +static gboolean +moo_cmd_view_stdout_line (MooCmdView *view, + const char *line) +{ + moo_pane_view_write_line (MOO_PANE_VIEW (view), line, -1, + view->priv->stdout_tag); + return FALSE; +} + + +static gboolean +moo_cmd_view_stderr_line (MooCmdView *view, + const char *line) +{ + moo_pane_view_write_line (MOO_PANE_VIEW (view), line, -1, + view->priv->stderr_tag); + return FALSE; +} diff --git a/moo/mooedit/moocmdview.h b/moo/mooedit/moocmdview.h new file mode 100644 index 00000000..6a5d807c --- /dev/null +++ b/moo/mooedit/moocmdview.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*- + * + * moocmdview.h + * + * Copyright (C) 2004-2005 by Yevgen Muntyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * See COPYING file that comes with this distribution. + */ + +#ifndef __MOO_CMD_VIEW__ +#define __MOO_CMD_VIEW__ + +#include "mooedit/moopaneview.h" + +G_BEGIN_DECLS + + +#define MOO_TYPE_CMD_VIEW (moo_cmd_view_get_type ()) +#define MOO_CMD_VIEW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MOO_TYPE_CMD_VIEW, MooCmdView)) +#define MOO_CMD_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOO_TYPE_CMD_VIEW, MooCmdViewClass)) +#define MOO_IS_CMD_VIEW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MOO_TYPE_CMD_VIEW)) +#define MOO_IS_CMD_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOO_TYPE_CMD_VIEW)) +#define MOO_CMD_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOO_TYPE_CMD_VIEW, MooCmdViewClass)) + + +typedef struct _MooCmdView MooCmdView; +typedef struct _MooCmdViewPrivate MooCmdViewPrivate; +typedef struct _MooCmdViewClass MooCmdViewClass; + +struct _MooCmdView +{ + MooPaneView parent; + MooCmdViewPrivate *priv; +}; + +struct _MooCmdViewClass +{ + MooPaneViewClass parent_class; + + /* action signal */ + gboolean (*abort) (MooCmdView *view); + + gboolean (*cmd_exit) (MooCmdView *view, + int status); + gboolean (*output_line) (MooCmdView *view, + const char *line, + gboolean std_err); + gboolean (*stdout_line) (MooCmdView *view, + const char *line); + gboolean (*stderr_line) (MooCmdView *view, + const char *line); +}; + + +GType moo_cmd_view_get_type (void) G_GNUC_CONST; + +GtkWidget *moo_cmd_view_new (void); + +gboolean moo_cmd_view_run_command (MooCmdView *view, + const char *cmd); +void moo_cmd_view_abort (MooCmdView *view); + + +G_END_DECLS + +#endif /* __MOO_CMD_VIEW__ */ diff --git a/moo/mooedit/moopaneview.c b/moo/mooedit/moopaneview.c index 87e0f22c..0ceb44ae 100644 --- a/moo/mooedit/moopaneview.c +++ b/moo/mooedit/moopaneview.c @@ -14,6 +14,8 @@ #include "mooedit/moopaneview.h" #include "mooutils/moomarshals.h" +#include "mooutils/moosignal.h" +#include struct _MooPaneViewPrivate { @@ -47,12 +49,23 @@ static void moo_pane_view_realize (GtkWidget *widget); static gboolean moo_pane_view_button_press (GtkWidget *widget, GdkEventButton *event); +static void moo_pane_view_move_cursor (GtkTextView *text_view, + GtkMovementStep step, + gint count, + gboolean extend_selection); + +static gboolean activate (MooPaneView *view, + int line); +static void activate_current_line (MooPaneView *view); + + static GtkTextBuffer *get_buffer (MooPaneView *view); static GHashTable *get_hash_table (MooPaneView *view); enum { - CLICK, + ACTIVATE, + ACTIVATE_CURRENT_LINE, LAST_SIGNAL }; @@ -72,6 +85,8 @@ static void moo_pane_view_class_init (MooPaneViewClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkTextViewClass *textview_class = GTK_TEXT_VIEW_CLASS (klass); + GtkBindingSet *binding_set; // gobject_class->set_property = moo_pane_view_set_property; // gobject_class->get_property = moo_pane_view_get_property; @@ -80,15 +95,31 @@ static void moo_pane_view_class_init (MooPaneViewClass *klass) widget_class->realize = moo_pane_view_realize; widget_class->button_press_event = moo_pane_view_button_press; - signals[CLICK] = - g_signal_new ("click", + textview_class->move_cursor = moo_pane_view_move_cursor; + + signals[ACTIVATE] = + g_signal_new ("activate", G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MooPaneViewClass, click), + G_STRUCT_OFFSET (MooPaneViewClass, activate), g_signal_accumulator_true_handled, NULL, _moo_marshal_BOOL__POINTER_INT, G_TYPE_BOOLEAN, 2, G_TYPE_POINTER, G_TYPE_INT); + + signals[ACTIVATE_CURRENT_LINE] = + moo_signal_new_cb ("activate-current-line", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_CALLBACK (activate_current_line), + NULL, NULL, + _moo_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + binding_set = gtk_binding_set_by_class (klass); + + gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, + "activate-current-line", 0); } @@ -197,9 +228,8 @@ moo_pane_view_button_press (GtkWidget *widget, { GtkTextView *textview = GTK_TEXT_VIEW (widget); MooPaneView *view = MOO_PANE_VIEW (widget); - int buffer_x, buffer_y, line; + int buffer_x, buffer_y; GtkTextIter iter; - gpointer data; gboolean handled = FALSE; if (gtk_text_view_get_window_type (textview, event->window) == GTK_TEXT_WINDOW_TEXT) @@ -211,10 +241,7 @@ moo_pane_view_button_press (GtkWidget *widget, /* XXX */ gtk_text_view_get_line_at_y (textview, &iter, buffer_y, NULL); - line = gtk_text_iter_get_line (&iter); - data = moo_pane_view_get_line_data (view, line); - - g_signal_emit (view, signals[CLICK], 0, data, line, &handled); + handled = activate (view, gtk_text_iter_get_line (&iter)); if (handled) gtk_text_buffer_place_cursor (get_buffer (view), &iter); @@ -227,6 +254,134 @@ moo_pane_view_button_press (GtkWidget *widget, } +static gboolean +activate (MooPaneView *view, + int line) +{ + gboolean handled = FALSE; + gpointer data = moo_pane_view_get_line_data (view, line); + + g_signal_emit (view, signals[ACTIVATE], 0, data, line, &handled); + + return handled; +} + + +static int +get_current_line (MooPaneView *view) +{ + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); + gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer)); + return gtk_text_iter_get_line (&iter); +} + + +static void +activate_current_line (MooPaneView *view) +{ + activate (view, get_current_line (view)); +} + + +static int +get_visible_height (GtkTextView *text_view) +{ + GdkRectangle rect; + GtkTextIter iter; + int start, end; + + gtk_text_view_get_visible_rect (text_view, &rect); + gtk_text_view_get_line_at_y (text_view, &iter, rect.y, NULL); + start = gtk_text_iter_get_line (&iter); + gtk_text_view_get_line_at_y (text_view, &iter, rect.y + rect.height - 1, NULL); + end = gtk_text_iter_get_line (&iter); + + return end - start + 1; +} + + +static void +moo_pane_view_move_cursor (GtkTextView *text_view, + GtkMovementStep step, + gint count, + gboolean extend_selection) +{ + gboolean handle; + MooPaneView *view; + GtkTextBuffer *buffer; + int current_line, new_line, height, total; + GtkTextIter iter; + + switch (step) + { + case GTK_MOVEMENT_LOGICAL_POSITIONS: + case GTK_MOVEMENT_VISUAL_POSITIONS: + case GTK_MOVEMENT_WORDS: + case GTK_MOVEMENT_PARAGRAPH_ENDS: + case GTK_MOVEMENT_HORIZONTAL_PAGES: + handle = FALSE; + break; + + default: + handle = TRUE; + } + + if (extend_selection) + handle = FALSE; + + if (!handle) + return GTK_TEXT_VIEW_CLASS(moo_pane_view_parent_class)->move_cursor (text_view, step, count, extend_selection); + + view = MOO_PANE_VIEW (text_view); + buffer = gtk_text_view_get_buffer (text_view); + + gtk_text_buffer_get_iter_at_mark (buffer, &iter, gtk_text_buffer_get_insert (buffer)); + current_line = get_current_line (view); + + height = get_visible_height (text_view); + total = gtk_text_buffer_get_line_count (buffer); + + switch (step) + { + case GTK_MOVEMENT_DISPLAY_LINES: + case GTK_MOVEMENT_PARAGRAPHS: + new_line = current_line + count; + break; + + case GTK_MOVEMENT_PAGES: + new_line = current_line + count * (height - 1); + break; + + case GTK_MOVEMENT_DISPLAY_LINE_ENDS: + case GTK_MOVEMENT_BUFFER_ENDS: + if (count < 0) + new_line = 0; + else + new_line = total - 1; + break; + + case GTK_MOVEMENT_LOGICAL_POSITIONS: + case GTK_MOVEMENT_VISUAL_POSITIONS: + case GTK_MOVEMENT_WORDS: + case GTK_MOVEMENT_PARAGRAPH_ENDS: + case GTK_MOVEMENT_HORIZONTAL_PAGES: + g_return_if_reached (); + } + + new_line = CLAMP (new_line, 0, total - 1); + gtk_text_buffer_get_iter_at_line (buffer, &iter, new_line); + gtk_text_buffer_place_cursor (buffer, &iter); + gtk_text_view_scroll_to_mark (text_view, + gtk_text_buffer_get_insert (buffer), + 0, FALSE, 0, 0); +} + + +static gboolean activate (MooPaneView *view, + int line); + + static void moo_pane_view_realize (GtkWidget *widget) { diff --git a/moo/mooedit/moopaneview.h b/moo/mooedit/moopaneview.h index 16ec6442..eecfcf44 100644 --- a/moo/mooedit/moopaneview.h +++ b/moo/mooedit/moopaneview.h @@ -42,9 +42,9 @@ struct _MooPaneViewClass { MooTextViewClass parent_class; - gboolean (*click) (MooPaneView *view, - gpointer line_data, - int line); + gboolean (*activate) (MooPaneView *view, + gpointer line_data, + int line); }; diff --git a/moo/mooedit/mootextview.c b/moo/mooedit/mootextview.c index 38d8eafa..60af7000 100644 --- a/moo/mooedit/mootextview.c +++ b/moo/mooedit/mootextview.c @@ -1042,3 +1042,20 @@ moo_text_view_set_show_tabs (MooTextView *view, if (GTK_WIDGET_DRAWABLE (view)) gtk_widget_queue_draw (GTK_WIDGET (view)); } + + +GtkTextTag* +moo_text_view_lookup_tag (MooTextView *view, + const char *name) +{ + GtkTextBuffer *buffer; + GtkTextTagTable *table; + + g_return_val_if_fail (MOO_IS_TEXT_VIEW (view), NULL); + g_return_val_if_fail (name != NULL, NULL); + + buffer = get_buffer (view); + table = gtk_text_buffer_get_tag_table (buffer); + + return gtk_text_tag_table_lookup (table, name); +} diff --git a/moo/mooedit/mootextview.h b/moo/mooedit/mootextview.h index 7a13da10..d8ea5ade 100644 --- a/moo/mooedit/mootextview.h +++ b/moo/mooedit/mootextview.h @@ -130,6 +130,9 @@ void moo_text_view_set_current_line_color (MooTextView *view, void moo_text_view_set_show_tabs (MooTextView *view, gboolean show); +GtkTextTag *moo_text_view_lookup_tag (MooTextView *view, + const char *name); + G_END_DECLS diff --git a/moo/mooedit/plugins/Makefile.am b/moo/mooedit/plugins/Makefile.am index 3fd50f60..ce1e19bc 100644 --- a/moo/mooedit/plugins/Makefile.am +++ b/moo/mooedit/plugins/Makefile.am @@ -31,12 +31,12 @@ noinst_LTLIBRARIES = libplugins.la libplugins_la_SOURCES = \ mooeditplugins.h \ fileselector.c \ - moogrep.c \ - moogrep-glade.h + moofind.c \ + moofind-glade.h -BUILT_SOURCES = moogrep-glade.h -EXTRA_DIST = moogrep.glade +BUILT_SOURCES = moofind-glade.h +EXTRA_DIST = moofind.glade -moogrep-glade.h: moogrep.glade - sh $(srcdir)/../../mooutils/xml2h.sh MOO_GREP_GLADE_XML $(srcdir)/moogrep.glade > \ - moogrep-glade.h +moofind-glade.h: moofind.glade + sh $(srcdir)/../../mooutils/xml2h.sh MOO_FIND_GLADE_XML $(srcdir)/moofind.glade > \ + moofind-glade.h diff --git a/moo/mooedit/plugins/mooeditplugins.h b/moo/mooedit/plugins/mooeditplugins.h index f649e46d..f33b133a 100644 --- a/moo/mooedit/plugins/mooeditplugins.h +++ b/moo/mooedit/plugins/mooeditplugins.h @@ -17,7 +17,7 @@ G_BEGIN_DECLS -gboolean moo_grep_init (void); +gboolean moo_find_init (void); gboolean moo_file_selector_init (void); diff --git a/moo/mooedit/plugins/moogrep.c b/moo/mooedit/plugins/moofind.c similarity index 54% rename from moo/mooedit/plugins/moogrep.c rename to moo/mooedit/plugins/moofind.c index 36e218b5..59554be1 100644 --- a/moo/mooedit/plugins/moogrep.c +++ b/moo/mooedit/plugins/moofind.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*- * - * moogrep.c + * moofind.c * * Copyright (C) 2004-2005 by Yevgen Muntyan * @@ -20,10 +20,10 @@ #endif #include "mooedit/mooplugin.h" -#include "mooedit/plugins/moogrep-glade.h" +#include "mooedit/plugins/moofind-glade.h" #include "mooedit/plugins/mooeditplugins.h" #include "mooedit/moofileview/moofileentry.h" -#include "mooedit/moopaneview.h" +#include "mooedit/moocmdview.h" #include "mooui/moouiobject.h" #include "mooutils/moostock.h" #include "mooutils/mooglade.h" @@ -32,7 +32,7 @@ #include #include -#define GREP_PLUGIN_ID "grep" +#define FIND_PLUGIN_ID "find" typedef struct { @@ -40,22 +40,14 @@ typedef struct { MooGladeXML *xml; MooFileEntryCompletion *completion; MooEditWindow *window; - MooPaneView *output; + MooCmdView *output; GtkTextTag *line_number_tag; GtkTextTag *match_tag; GtkTextTag *file_tag; GtkTextTag *error_tag; + GtkTextTag *message_tag; char *current_file; - gboolean running; - int exit_status; - GPid pid; - int stdout; - int stderr; - GIOChannel *stdout_io; - GIOChannel *stderr_io; - guint child_watch; - guint stdout_watch; - guint stderr_watch; + guint match_count; } WindowStuff; typedef struct { @@ -66,8 +58,8 @@ typedef struct { static WindowStuff *window_stuff_new (MooEditWindow *window); static void window_stuff_free (WindowStuff *stuff); -static void grep_plugin_attach (MooEditWindow *window); -static void grep_plugin_detach (MooEditWindow *window); +static void find_plugin_attach (MooEditWindow *window); +static void find_plugin_detach (MooEditWindow *window); static void do_find (MooEditWindow *window, WindowStuff *stuff); @@ -81,10 +73,15 @@ static void execute_find (const char *pattern, const char *skip_files, gboolean case_sensitive, WindowStuff *stuff); -static void stop_find (WindowStuff *stuff); -static gboolean output_click (WindowStuff *stuff, +static gboolean output_activate (WindowStuff *stuff, FileLinePair *line_data); -static void check_find_stop (WindowStuff *stuff); + +static gboolean command_exit (MooPaneView *view, + int status, + WindowStuff *stuff); +static gboolean process_line (MooPaneView *view, + const char *line, + WindowStuff *stuff); static void @@ -93,7 +90,7 @@ find_in_files_cb (MooEditWindow *window) WindowStuff *stuff; int response; - stuff = moo_plugin_get_window_data (GREP_PLUGIN_ID, window); + stuff = moo_plugin_get_window_data (FIND_PLUGIN_ID, window); g_return_if_fail (stuff != NULL); if (!stuff->dialog) @@ -113,32 +110,38 @@ find_in_files_cb (MooEditWindow *window) static void -grep_plugin_attach (MooEditWindow *window) +find_plugin_attach (MooEditWindow *window) { GtkWidget *swin; MooPaneLabel *label; WindowStuff *stuff = window_stuff_new (window); - label = moo_pane_label_new (MOO_STOCK_GREP, NULL, NULL, "Find in Files"); - stuff->output = g_object_new (MOO_TYPE_PANE_VIEW, + label = moo_pane_label_new (MOO_STOCK_FIND_IN_FILES, NULL, NULL, "Find"); + stuff->output = g_object_new (MOO_TYPE_CMD_VIEW, "highlight-current-line", TRUE, NULL); - g_signal_connect_swapped (stuff->output, "click", - G_CALLBACK (output_click), stuff); + g_signal_connect_swapped (stuff->output, "activate", + G_CALLBACK (output_activate), stuff); - stuff->line_number_tag = moo_pane_view_create_tag (stuff->output, NULL, - "weight", PANGO_WEIGHT_BOLD, - NULL); - stuff->match_tag = moo_pane_view_create_tag (stuff->output, NULL, - "foreground", "blue", - NULL); - stuff->file_tag = moo_pane_view_create_tag (stuff->output, NULL, - "foreground", "green", - NULL); - stuff->error_tag = moo_pane_view_create_tag (stuff->output, NULL, - "foreground", "red", - NULL); + stuff->line_number_tag = + moo_pane_view_create_tag (MOO_PANE_VIEW (stuff->output), + NULL, "weight", PANGO_WEIGHT_BOLD, NULL); + stuff->match_tag = + moo_pane_view_create_tag (MOO_PANE_VIEW (stuff->output), NULL, + "foreground", "blue", NULL); + stuff->file_tag = + moo_pane_view_create_tag (MOO_PANE_VIEW (stuff->output), NULL, + "foreground", "green", NULL); + stuff->error_tag = + moo_text_view_lookup_tag (MOO_TEXT_VIEW (stuff->output), "error"); + stuff->message_tag = + moo_text_view_lookup_tag (MOO_TEXT_VIEW (stuff->output), "message"); + + g_signal_connect (stuff->output, "cmd-exit", + G_CALLBACK (command_exit), stuff); + g_signal_connect (stuff->output, "stdout-line", + G_CALLBACK (process_line), stuff); swin = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin), @@ -149,10 +152,10 @@ grep_plugin_attach (MooEditWindow *window) gtk_container_add (GTK_CONTAINER (swin), GTK_WIDGET (stuff->output)); gtk_widget_show_all (swin); - moo_edit_window_add_pane (window, GREP_PLUGIN_ID, + moo_edit_window_add_pane (window, FIND_PLUGIN_ID, swin, label, MOO_PANE_POS_BOTTOM); - moo_plugin_set_window_data (GREP_PLUGIN_ID, window, stuff, + moo_plugin_set_window_data (FIND_PLUGIN_ID, window, stuff, (GDestroyNotify) window_stuff_free); } @@ -184,7 +187,7 @@ window_stuff_free (WindowStuff *stuff) static gboolean -grep_plugin_init (void) +find_plugin_init (void) { GObjectClass *klass = g_type_class_ref (MOO_TYPE_EDIT_WINDOW); g_return_val_if_fail (klass != NULL, FALSE); @@ -194,7 +197,7 @@ grep_plugin_init (void) "name", "Find In Files", "label", "Find In Files", "tooltip", "Find In Files", - "icon-stock-id", MOO_STOCK_GREP, + "icon-stock-id", MOO_STOCK_FIND_IN_FILES, "closure::callback", find_in_files_cb, NULL); @@ -204,14 +207,14 @@ grep_plugin_init (void) static void -grep_plugin_deinit (void) +find_plugin_deinit (void) { /* XXX remove action */ } gboolean -moo_grep_init (void) +moo_find_init (void) { MooPluginParams params = { TRUE }; MooPluginPrefsParams prefs_params; @@ -219,16 +222,16 @@ moo_grep_init (void) MooPluginInfo info = { MOO_PLUGIN_CURRENT_VERSION, - GREP_PLUGIN_ID, - GREP_PLUGIN_ID, - GREP_PLUGIN_ID, + FIND_PLUGIN_ID, + FIND_PLUGIN_ID, + FIND_PLUGIN_ID, "Yevgen Muntyan ", MOO_VERSION, - (MooPluginInitFunc) grep_plugin_init, - (MooPluginDeinitFunc) grep_plugin_deinit, - (MooPluginWindowAttachFunc) grep_plugin_attach, - (MooPluginWindowDetachFunc) grep_plugin_detach, + (MooPluginInitFunc) find_plugin_init, + (MooPluginDeinitFunc) find_plugin_deinit, + (MooPluginWindowAttachFunc) find_plugin_attach, + (MooPluginWindowDetachFunc) find_plugin_detach, ¶ms, &prefs_params @@ -252,9 +255,9 @@ static void create_dialog (MooEditWindow *window, WindowStuff *stuff) { - GtkWidget *dir_entry, *pattern_entry; + GtkWidget *dir_entry, *pattern_entry, *glob_entry, *skip_entry; - stuff->xml = moo_glade_xml_new_from_buf (MOO_GREP_GLADE_XML, -1, NULL, NULL); + stuff->xml = moo_glade_xml_new_from_buf (MOO_FIND_GLADE_XML, -1, "dialog", NULL); g_return_if_fail (stuff->xml != NULL); stuff->dialog = moo_glade_xml_get_widget (stuff->xml, "dialog"); @@ -283,6 +286,17 @@ create_dialog (MooEditWindow *window, "show-hidden", FALSE, NULL); moo_file_entry_completion_set_entry (stuff->completion, GTK_ENTRY (dir_entry)); + + glob_entry = moo_glade_xml_get_widget (stuff->xml, "glob_combo"); + glob_entry = GTK_BIN(glob_entry)->child; + + skip_entry = moo_glade_xml_get_widget (stuff->xml, "skip_combo"); + skip_entry = GTK_BIN(skip_entry)->child; + + gtk_entry_set_activates_default (GTK_ENTRY (pattern_entry), TRUE); + gtk_entry_set_activates_default (GTK_ENTRY (dir_entry), TRUE); + gtk_entry_set_activates_default (GTK_ENTRY (glob_entry), TRUE); + gtk_entry_set_activates_default (GTK_ENTRY (skip_entry), TRUE); } @@ -339,7 +353,7 @@ do_find (MooEditWindow *window, gboolean case_sensitive; char *dir; - pane = moo_edit_window_get_pane (window, GREP_PLUGIN_ID); + pane = moo_edit_window_get_pane (window, FIND_PLUGIN_ID); g_return_if_fail (pane != NULL); dir_entry = GTK_BIN (moo_glade_xml_get_widget (stuff->xml, "dir_combo"))->child; @@ -357,7 +371,7 @@ do_find (MooEditWindow *window, skip = gtk_entry_get_text (GTK_ENTRY (skip_entry)); case_sensitive = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (case_sensitive_button)); - moo_pane_view_clear (stuff->output); + moo_pane_view_clear (MOO_PANE_VIEW (stuff->output)); moo_big_paned_present_pane (window->paned, pane); execute_find (pattern, glob, dir, skip, @@ -365,23 +379,6 @@ do_find (MooEditWindow *window, } -static void -command_exit (GPid pid, - gint status, - WindowStuff *stuff) -{ - g_return_if_fail (pid == stuff->pid); - - stuff->child_watch = 0; - stuff->exit_status = status; - - g_spawn_close_pid (stuff->pid); - stuff->pid = 0; - - check_find_stop (stuff); -} - - static FileLinePair* file_line_pair_new (const char *filename, int line) @@ -404,10 +401,10 @@ file_line_pair_free (FileLinePair *pair) } -static void -process_line (WindowStuff *stuff, +static gboolean +process_line (MooPaneView *view, const char *line, - gboolean stderr) + WindowStuff *stuff) { char *filename = NULL; char *number = NULL; @@ -416,19 +413,9 @@ process_line (WindowStuff *stuff, int line_no; guint64 line_no_64; - if (stderr) - { - moo_pane_view_write_line (stuff->output, line, -1, - stuff->error_tag); - return; - } - - /* Binary file blah matches */ + /* 'Binary file blah matches' */ if (g_str_has_prefix (line, "Binary file ")) - { - moo_pane_view_write_line (stuff->output, line, -1, NULL); - return; - } + return FALSE; p = line; if (!(colon = strchr (p, ':')) || !colon[1]) @@ -447,10 +434,9 @@ process_line (WindowStuff *stuff, { g_free (stuff->current_file); stuff->current_file = filename; - view_line = moo_pane_view_write_line (stuff->output, - filename, -1, + view_line = moo_pane_view_write_line (view, filename, -1, stuff->file_tag); - moo_pane_view_set_line_data (stuff->output, view_line, + moo_pane_view_set_line_data (view, view_line, file_line_pair_new (filename, -1), (GDestroyNotify) file_line_pair_free); } @@ -485,136 +471,29 @@ process_line (WindowStuff *stuff, line_no = line_no_64 - 1; } - view_line = moo_pane_view_start_line (stuff->output); - moo_pane_view_write (stuff->output, number, -1, - stuff->line_number_tag); - moo_pane_view_write (stuff->output, ": ", -1, NULL); - moo_pane_view_write (stuff->output, p, -1, stuff->match_tag); - moo_pane_view_end_line (stuff->output); + view_line = moo_pane_view_start_line (view); + moo_pane_view_write (view, number, -1, stuff->line_number_tag); + moo_pane_view_write (view, ": ", -1, NULL); + moo_pane_view_write (view, p, -1, stuff->match_tag); + moo_pane_view_end_line (view); - moo_pane_view_set_line_data (stuff->output, view_line, + moo_pane_view_set_line_data (view, view_line, file_line_pair_new (stuff->current_file, line_no), (GDestroyNotify) file_line_pair_free); + stuff->match_count++; g_free (number); - return; + return TRUE; parse_error: g_warning ("%s: could not parse line '%s'", G_STRLOC, line); - moo_pane_view_write_line (stuff->output, line, -1, NULL); g_free (filename); g_free (number); + return FALSE; } -static gboolean -command_out_or_err (GIOChannel *channel, - GIOCondition condition, - gboolean stdout, - WindowStuff *stuff) -{ - char *line; - GError *error = NULL; - GIOStatus status; - - status = g_io_channel_read_line (channel, &line, NULL, NULL, &error); - - if (line) - { - process_line (stuff, line, !stdout); - g_free (line); - } - - if (error) - { - g_warning ("%s: %s", G_STRLOC, error->message); - g_error_free (error); - return FALSE; - } - - if (condition & (G_IO_ERR | G_IO_HUP)) - return FALSE; - - if (status == G_IO_STATUS_EOF) - return FALSE; - - return TRUE; -} - -static gboolean -command_out (GIOChannel *channel, - GIOCondition condition, - WindowStuff *stuff) -{ - return command_out_or_err (channel, condition, TRUE, stuff); -} - - -static gboolean -command_err (GIOChannel *channel, - GIOCondition condition, - WindowStuff *stuff) -{ - return command_out_or_err (channel, condition, FALSE, stuff); -} - -static void -try_channel_leftover (WindowStuff *stuff, - GIOChannel *channel, - gboolean stdout) -{ - char *text; - - g_io_channel_read_to_end (channel, &text, NULL, NULL); - - if (text) - { - char **lines, **p; - g_strdelimit (text, "\r", '\n'); - lines = g_strsplit (text, "\n", 0); - - if (lines) - { - for (p = lines; *p != NULL; p++) - if (**p) - process_line (stuff, *p, !stdout); - } - - g_strfreev (lines); - g_free (text); - } -} - - -static void -stdout_watch_removed (WindowStuff *stuff) -{ - if (stuff->stdout_io) - { - try_channel_leftover (stuff, stuff->stdout_io, TRUE); - g_io_channel_unref (stuff->stdout_io); - } - - stuff->stdout_io = NULL; - stuff->stdout_watch = 0; - check_find_stop (stuff); -} - -static void -stderr_watch_removed (WindowStuff *stuff) -{ - if (stuff->stderr_io) - { - try_channel_leftover (stuff, stuff->stderr_io, FALSE); - g_io_channel_unref (stuff->stderr_io); - } - - stuff->stderr_io = NULL; - stuff->stderr_watch = 0; - check_find_stop (stuff); -} - static void execute_find (const char *pattern, const char *glob, @@ -623,19 +502,15 @@ execute_find (const char *pattern, gboolean case_sensitive, WindowStuff *stuff) { - GError *error = NULL; - char **argv = NULL; GString *command = NULL; char **globs = NULL; g_return_if_fail (stuff->output != NULL); g_return_if_fail (pattern && pattern[0]); - if (stuff->running) - return; - g_free (stuff->current_file); stuff->current_file = NULL; + stuff->match_count = 0; command = g_string_new (""); g_string_printf (command, "find '%s'", dir); @@ -687,183 +562,55 @@ execute_find (const char *pattern, g_string_append_printf (command, " | xargs egrep -H -n %s-e '%s'", !case_sensitive ? "-i " : "", pattern); - moo_pane_view_write_line (stuff->output, command->str, -1, NULL); - - argv = g_new (char*, 4); - argv[0] = g_strdup ("/bin/sh"); - argv[1] = g_strdup ("-c"); - argv[2] = g_string_free (command, FALSE); - argv[3] = NULL; - - g_spawn_async_with_pipes (NULL, - argv, NULL, - G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, - NULL, NULL, - &stuff->pid, - NULL, - &stuff->stdout, - &stuff->stderr, - &error); - - if (error) - { - moo_pane_view_write_line (stuff->output, error->message, -1, - stuff->error_tag); - g_error_free (error); - goto out; - } - - stuff->running = TRUE; - - stuff->child_watch = - g_child_watch_add (stuff->pid, - (GChildWatchFunc) command_exit, - stuff); - - stuff->stdout_io = g_io_channel_unix_new (stuff->stdout); - g_io_channel_set_encoding (stuff->stdout_io, NULL, NULL); - g_io_channel_set_buffered (stuff->stdout_io, TRUE); - g_io_channel_set_flags (stuff->stdout_io, G_IO_FLAG_NONBLOCK, NULL); - g_io_channel_set_close_on_unref (stuff->stdout_io, TRUE); - stuff->stdout_watch = - g_io_add_watch_full (stuff->stdout_io, - G_PRIORITY_DEFAULT_IDLE, - G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, - (GIOFunc) command_out, stuff, - (GDestroyNotify) stdout_watch_removed); - - stuff->stderr_io = g_io_channel_unix_new (stuff->stderr); - g_io_channel_set_encoding (stuff->stderr_io, NULL, NULL); - g_io_channel_set_buffered (stuff->stderr_io, TRUE); - g_io_channel_set_flags (stuff->stderr_io, G_IO_FLAG_NONBLOCK, NULL); - g_io_channel_set_close_on_unref (stuff->stderr_io, TRUE); - stuff->stderr_watch = - g_io_add_watch_full (stuff->stderr_io, - G_PRIORITY_DEFAULT_IDLE, - G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, - (GIOFunc) command_err, stuff, - (GDestroyNotify) stderr_watch_removed); - -out: - g_strfreev (argv); + moo_cmd_view_run_command (stuff->output, command->str); + g_string_free (command, TRUE); } static void -grep_plugin_detach (MooEditWindow *window) +find_plugin_detach (MooEditWindow *window) { - WindowStuff *stuff = moo_plugin_get_window_data (GREP_PLUGIN_ID, window); + WindowStuff *stuff = moo_plugin_get_window_data (FIND_PLUGIN_ID, window); g_return_if_fail (stuff != NULL); - stop_find (stuff); -} - -static void -stop_find (WindowStuff *stuff) -{ - if (!stuff->running) - return; - - stuff->running = FALSE; - - if (stuff->child_watch) - g_source_remove (stuff->child_watch); - if (stuff->stdout_watch) - g_source_remove (stuff->stdout_watch); - if (stuff->stderr_watch) - g_source_remove (stuff->stderr_watch); - - if (stuff->stdout_io) - g_io_channel_unref (stuff->stdout_io); - if (stuff->stderr_io) - g_io_channel_unref (stuff->stderr_io); - - if (stuff->pid) - { - kill (stuff->pid, SIGTERM); - g_spawn_close_pid (stuff->pid); - } - - g_free (stuff->current_file); - stuff->current_file = NULL; - stuff->pid = 0; - stuff->stdout = -1; - stuff->stderr = -1; - stuff->child_watch = 0; - stuff->stdout_watch = 0; - stuff->stderr_watch = 0; - stuff->stdout_io = NULL; - stuff->stderr_io = NULL; -} - - -static void -check_find_stop (WindowStuff *stuff) -{ - if (!stuff->running) - return; - - if (!stuff->child_watch && !stuff->stdout_watch && !stuff->stderr_watch) - { - if (WIFEXITED (stuff->exit_status)) - { - guint8 exit_code = WEXITSTATUS (stuff->exit_status); - - /* - xargs exits with the following status: - 0 if it succeeds - 123 if any invocation of the command exited with status 1-125 - 124 if the command exited with status 255 - 125 if the command is killed by a signal - 126 if the command cannot be run - 127 if the command is not found - 1 if some other error occurred. - */ - - if (!exit_code || exit_code == 123) - { - moo_pane_view_write_line (stuff->output, - "*** Done ***", -1, - NULL); - } - else - { - char *msg = g_strdup_printf ("Command failed with status %d", - exit_code); - moo_pane_view_write_line (stuff->output, - msg, -1, stuff->error_tag); - g_free (msg); - } - } -#ifdef WCOREDUMP - else if (WCOREDUMP (stuff->exit_status)) - { - moo_pane_view_write_line (stuff->output, - "*** Dumped core ***", -1, - NULL); - } -#endif - else if (WIFSIGNALED (stuff->exit_status)) - { - moo_pane_view_write_line (stuff->output, - "*** Killed ***", -1, - NULL); - } - else - { - moo_pane_view_write_line (stuff->output, - "*** ??? ***", -1, - NULL); - } - - stop_find (stuff); - } + g_signal_handlers_disconnect_by_func (stuff->output, + (gpointer) command_exit, + stuff); + g_signal_handlers_disconnect_by_func (stuff->output, + (gpointer) process_line, + stuff); + moo_cmd_view_abort (stuff->output); } static gboolean -output_click (WindowStuff *stuff, - FileLinePair *line_data) +command_exit (MooPaneView *view, + int status, + WindowStuff *stuff) +{ + if (WIFEXITED (status)) + { + guint8 exit_code = WEXITSTATUS (status); + + /* xargs exits with code 123 if it's command exited with status 1-125*/ + if (!exit_code || exit_code == 123) + { + char *msg = g_strdup_printf ("*** %d matches found ***", + stuff->match_count); + moo_pane_view_write_line (view, msg, -1, + stuff->message_tag); + g_free (msg); + return TRUE; + } + } + + return FALSE; +} + + +static gboolean +output_activate (WindowStuff *stuff, + FileLinePair *line_data) { MooEditor *editor; MooEdit *doc; diff --git a/moo/mooedit/plugins/moogrep.glade b/moo/mooedit/plugins/moofind.glade similarity index 54% rename from moo/mooedit/plugins/moogrep.glade rename to moo/mooedit/plugins/moofind.glade index 232571d2..adeeb1c4 100644 --- a/moo/mooedit/plugins/moogrep.glade +++ b/moo/mooedit/plugins/moofind.glade @@ -332,291 +332,4 @@ - - True - window1 - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - - - - True - 0.5 - 0.5 - 1 - 1 - 6 - 6 - 6 - 6 - - - - True - False - 0 - - - - True - 4 - 2 - False - 0 - 0 - - - - True - - - 1 - 2 - 2 - 3 - - - - - - - True - - - 1 - 2 - 1 - 2 - - - - - - - True - - - 1 - 2 - 0 - 1 - - - - - - - True - - - 1 - 2 - 3 - 4 - fill - fill - - - - - - True - This entry content will be passed to grep - True - False - - - - True - _Pattern: - True - False - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 0 - 0 - - - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - Enter semicolon-separated list of globs - True - False - - - - True - Fi_les: - True - False - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 0 - 0 - - - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - You can use Tab completion in this entry. Try also Ctrl-L - True - False - - - - True - _Directory: - True - False - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 0 - 0 - - - - - 0 - 1 - 2 - 3 - fill - - - - - - - True - Enter semicolon-separated list of globs - True - False - - - - True - _Skip files: - True - False - GTK_JUSTIFY_LEFT - False - False - 1 - 0.5 - 0 - 0 - - - - - 0 - 1 - 3 - 4 - fill - - - - - - 0 - False - False - - - - - - True - False - 0 - - - - True - True - _Case sensitive - True - GTK_RELIEF_NORMAL - True - True - False - True - - - 0 - False - False - - - - - - True - True - gtk-find - True - GTK_RELIEF_NORMAL - False - - - 0 - False - False - GTK_PACK_END - - - - - 6 - False - False - - - - - - - - diff --git a/moo/mooutils/moomarshals.list b/moo/mooutils/moomarshals.list index 82899940..4f98f03d 100644 --- a/moo/mooutils/moomarshals.list +++ b/moo/mooutils/moomarshals.list @@ -1,9 +1,11 @@ BOOL:ENUM,INT BOOL:ENUM,INT,BOOL +BOOL:INT BOOL:OBJECT,OBJECT BOOL:POINTER BOOL:POINTER,INT BOOL:STRING +BOOL:STRING,BOOL BOOL:STRING,POINTER BOOL:STRING,STRING BOOL:STRING,STRING,POINTER diff --git a/moo/mooutils/moostock.c b/moo/mooutils/moostock.c index 8ad5eada..c2bf3de0 100644 --- a/moo/mooutils/moostock.c +++ b/moo/mooutils/moostock.c @@ -202,7 +202,8 @@ void moo_create_stock_items (void) register_stock_icon_alias (factory, GTK_STOCK_GO_DOWN, MOO_STOCK_COMPILE); register_stock_icon_alias (factory, GTK_STOCK_EXECUTE, MOO_STOCK_EXECUTE); - register_stock_icon_alias (factory, GTK_STOCK_FIND, MOO_STOCK_GREP); + register_stock_icon_alias (factory, GTK_STOCK_FIND, MOO_STOCK_FIND_IN_FILES); + register_stock_icon_alias (factory, GTK_STOCK_FIND, MOO_STOCK_FIND_FILE); g_object_unref (G_OBJECT (factory)); } diff --git a/moo/mooutils/moostock.h b/moo/mooutils/moostock.h index a927de17..7769f6fe 100644 --- a/moo/mooutils/moostock.h +++ b/moo/mooutils/moostock.h @@ -49,7 +49,8 @@ G_BEGIN_DECLS #define MOO_STOCK_COMPILE "moo-compile" #define MOO_STOCK_EXECUTE "moo-execute" -#define MOO_STOCK_GREP "moo-grep" +#define MOO_STOCK_FIND_IN_FILES "moo-find-in-files" +#define MOO_STOCK_FIND_FILE "moo-find-file" void moo_create_stock_items (void); diff --git a/tests/medit.c.in b/tests/medit.c.in index 16b88d06..bf9d4d74 100644 --- a/tests/medit.c.in +++ b/tests/medit.c.in @@ -44,7 +44,7 @@ int main (int argc, char **argv) moo_plugin_read_dir (plugin_dir); g_free (plugin_dir); - moo_grep_init (); + moo_find_init (); moo_file_selector_init (); editor = moo_editor_new ();