From 7c8836349ea2da25c0cba1a1c4871272c81bb0cf Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Sun, 9 Apr 2000 15:05:26 +0000 Subject: [PATCH] r235: Added the Shell Command feature to the minibuffer. --- ROX-Filer/src/Docs/Manual.lyx | 133 ++++++++++++++++++++++--- ROX-Filer/src/filer.c | 5 +- ROX-Filer/src/filer.h | 6 +- ROX-Filer/src/menu.c | 11 ++- ROX-Filer/src/minibuffer.c | 223 +++++++++++++++++++++++++++++++++++------- ROX-Filer/src/minibuffer.h | 4 +- 6 files changed, 326 insertions(+), 56 deletions(-) diff --git a/ROX-Filer/src/Docs/Manual.lyx b/ROX-Filer/src/Docs/Manual.lyx index dd667f16..085fc14e 100644 --- a/ROX-Filer/src/Docs/Manual.lyx +++ b/ROX-Filer/src/Docs/Manual.lyx @@ -1,7 +1,10 @@ -#This file was created by Sun Apr 9 12:48:48 2000 +#This file was created by Sun Apr 9 16:01:14 2000 #LyX 0.12 (C) 1995-1998 Matthias Ettrich and the LyX Team \lyxformat 2.15 \textclass article +\begin_preamble +\def \Tab {\thinspace$\langle\hbox{Tab}\rangle$\thinspace} +\end_preamble \language default \inputencoding latin1 \fontscheme default @@ -946,7 +949,7 @@ The Window Menu \layout Standard \added_space_top 0.3cm \added_space_bottom 0.3cm \align center \LyXTable multicol5 -7 2 0 0 -1 -1 -1 -1 +8 2 0 0 -1 -1 -1 -1 1 1 0 0 1 1 0 0 0 1 0 0 @@ -954,6 +957,7 @@ multicol5 0 1 0 0 0 1 0 0 0 1 0 0 +0 1 0 0 8 1 0 "" "" 2 1 1 "8cm" "" 0 8 0 1 0 0 0 "" "" @@ -970,6 +974,8 @@ multicol5 0 8 0 1 0 0 0 "" "" 0 8 0 1 0 0 0 "" "" 0 8 0 1 0 0 0 "" "" +0 8 0 1 0 0 0 "" "" +0 8 0 1 0 0 0 "" "" Entry \newline @@ -1000,6 +1006,15 @@ Open the path-entry box (see section ). \newline +Shell Command +\newline +Open the shell command box (see section +\begin_inset LatexCommand \ref{sec: mini} + +\end_inset + +). +\newline Show ROX-Filer help \newline Same as selecting ROX-Filer and choosing `Help' from the menu. @@ -1174,11 +1189,19 @@ If you saw that line then it's worked! Well done! \end_inset +The mini-buffer +\layout Standard + +The mini-buffer is a white bar that appears along the bottom of the window + and allows you to enter some text. + Press Escape to get rid of it again. + It behaves in different ways depending on how you invoked it: +\layout Subsubsection + The path-entry box \layout Standard -The path-entry box is a white bar that appears along the bottom of the window. - It allows you to type in a path directly. +This allows you to type in a path directly. As you type the display is updated to show the item entered visually. The main use is to find a file in a large directory quickly, but you can also use it for navigating between directories, or for selecting a full @@ -1187,8 +1210,7 @@ The path-entry box is a white bar that appears along the bottom of the window. \layout Standard \added_space_top 0.3cm \added_space_bottom 0.3cm \align center \LyXTable multicol5 -5 2 0 0 -1 -1 -1 -1 -1 1 0 0 +4 2 0 0 -1 -1 -1 -1 1 1 0 0 0 1 0 0 0 1 0 0 @@ -1198,8 +1220,6 @@ multicol5 0 8 0 1 0 0 0 "" "" 0 8 0 1 0 0 0 "" "" 0 8 0 1 0 0 0 "" "" -0 2 0 1 0 0 0 "" "" -0 8 0 1 0 0 0 "" "" 0 8 0 1 0 0 0 "" "" 0 8 0 1 0 0 0 "" "" 0 8 0 1 0 0 0 "" "" @@ -1210,10 +1230,6 @@ Key \newline Action \newline -Escape -\newline -Close the path-entry box. -\newline Return \newline Open the currently selected item. @@ -1234,7 +1250,7 @@ Tab completion tries to fill in as many characters for you as it can. If you use tab completion on a directory and it is unique then the filer will automatically change into the directory. This behavior should be familiar to shell users. -\layout Subsubsection +\layout Subsubsection* Example \layout Standard @@ -1252,9 +1268,98 @@ Press CTRL-U to delete the existing contents - this moves you to the root directory. \layout Enumerate -Type `udowi'. +Type `u +\latex latex + +\backslash +Tab{} +\latex default +do +\latex latex + +\backslash +Tab{} +\latex default +wi +\latex latex + +\backslash +Tab{} +\latex default +'. As you type, the cursor will move to the correct subdirectory. If it beeps when you press Tab then you need to supply more letters. +\layout Subsubsection + +The shell command box +\layout Standard + +This provides a quick way of entering shell commands if you don't want to + open an xterm. + If you don't know what shell commands are, skip this section! +\layout Standard + +Just type in the command and press Return to execute it. + Up and Down arrows move through previously entered commands. + If some items are selected then they are assigned to the positional parameters + $1, $2, etc. +\layout Subsubsection* + +Example +\layout Standard + +To print all the selected files: +\layout Enumerate + +Open the minibuffer by choosing `Shell Command' from the Window menu. + I usually bind this to the bang (`!') key. +\layout Enumerate + +Type +\family typewriter +`lpr $* +\family default +' and press Return. +\layout Subsubsection* + +Notes +\layout Itemize + +Be careful; you will not be asked to confirm! If in doubt, start the command + with ` +\family typewriter +echo +\family default +' so that it will be displayed rather than executed. +\layout Itemize + +The above command won't work if some of the files contain spaces --- use + ` +\family typewriter +lpr +\latex latex +" +\latex default +$@ +\latex latex +" +\family default +\latex default +' instead to be safe. +\layout Itemize + +`sh' is always used as the name of the shell to run (mainly because bash + and csh treat positional parameters differently). + However, PATH is searched to find it so you can still use another shell + if you want by naming it sh and putting it in your path. +\layout Itemize + +Commands execute in the background, so you can say: +\begin_deeper +\layout LyX-Code + +sleep 240; xmessage Time to go! +\end_deeper \layout Subsection Action windows diff --git a/ROX-Filer/src/filer.c b/ROX-Filer/src/filer.c index ce6070e4..ef4a7d38 100644 --- a/ROX-Filer/src/filer.c +++ b/ROX-Filer/src/filer.c @@ -1287,7 +1287,7 @@ void filer_change_to(FilerWindow *filer_window, char *path, char *from) collection_set_cursor_item(filer_window->collection, -1); attach(filer_window); - if (GTK_WIDGET_VISIBLE(filer_window->minibuffer)) + if (filer_window->mini_type == MINI_PATH) gtk_idle_add((GtkFunction) minibuffer_show_cb, filer_window); } @@ -1455,6 +1455,7 @@ FilerWindow *filer_opendir(char *path, PanelType panel_type) filer_window->scanning = FALSE; filer_window->had_cursor = FALSE; filer_window->auto_select = NULL; + filer_window->mini_type = MINI_NONE; filer_window->directory = g_fscache_lookup(dir_cache, filer_window->path); @@ -2003,7 +2004,7 @@ void filer_check_mounted(char *path) static gboolean minibuffer_show_cb(FilerWindow *filer_window) { if (exists(filer_window)) - minibuffer_show(filer_window); + minibuffer_show(filer_window, MINI_PATH); return FALSE; } diff --git a/ROX-Filer/src/filer.h b/ROX-Filer/src/filer.h index c560d5b1..1eb4518f 100644 --- a/ROX-Filer/src/filer.h +++ b/ROX-Filer/src/filer.h @@ -13,8 +13,6 @@ #include "pixmaps.h" #include #include -#include "mount.h" -#include "dir.h" typedef struct _FilerWindow FilerWindow; typedef enum {PANEL_NO, PANEL_TOP, PANEL_BOTTOM} PanelType; @@ -34,6 +32,9 @@ typedef enum FILER_UPDATING = 0x02, /* (scanning) items may already exist */ } FilerFlags; +#include "mount.h" +#include "minibuffer.h" +#include "dir.h" #include "type.h" struct _FilerWindow @@ -56,6 +57,7 @@ struct _FilerWindow GtkWidget *minibuffer; int mini_cursor_base; + MiniType mini_type; }; extern FilerWindow *window_with_focus; diff --git a/ROX-Filer/src/menu.c b/ROX-Filer/src/menu.c index 2dff3562..335850d7 100644 --- a/ROX-Filer/src/menu.c +++ b/ROX-Filer/src/menu.c @@ -116,6 +116,7 @@ static void open_parent(gpointer data, guint action, GtkWidget *widget); static void new_window(gpointer data, guint action, GtkWidget *widget); static void close_window(gpointer data, guint action, GtkWidget *widget); static void enter_path(gpointer data, guint action, GtkWidget *widget); +static void shell_command(gpointer data, guint action, GtkWidget *widget); static void rox_help(gpointer data, guint action, GtkWidget *widget); static void open_as_dir(gpointer data, guint action, GtkWidget *widget); @@ -194,6 +195,7 @@ static GtkItemFactoryEntry filer_menu_def[] = { {"/Window/New Window", NULL, new_window, 0, NULL}, {"/Window/Close Window", C_"Q", close_window, 0, NULL}, {"/Window/Enter Path", NULL, enter_path, 0, NULL}, +{"/Window/Shell Command", NULL, shell_command, 0, NULL}, {"/Window/Separator", NULL, NULL, 0, ""}, {"/Window/Show ROX-Filer help", NULL, rox_help, 0, NULL}, }; @@ -1368,7 +1370,14 @@ static void enter_path(gpointer data, guint action, GtkWidget *widget) { g_return_if_fail(window_with_focus != NULL); - minibuffer_show(window_with_focus); + minibuffer_show(window_with_focus, MINI_PATH); +} + +static void shell_command(gpointer data, guint action, GtkWidget *widget) +{ + g_return_if_fail(window_with_focus != NULL); + + minibuffer_show(window_with_focus, MINI_SHELL); } static void rox_help(gpointer data, guint action, GtkWidget *widget) diff --git a/ROX-Filer/src/minibuffer.c b/ROX-Filer/src/minibuffer.c index e93b7f6b..157268fc 100644 --- a/ROX-Filer/src/minibuffer.c +++ b/ROX-Filer/src/minibuffer.c @@ -24,14 +24,19 @@ #include "config.h" #include +#include #include #include #include "collection.h" +#include "gui_support.h" #include "support.h" #include "minibuffer.h" #include "filer.h" +#include "main.h" + +static GList *shell_history = NULL; /* Static prototypes */ static gint key_press_event(GtkWidget *widget, @@ -61,7 +66,7 @@ GtkWidget *create_minibuffer(FilerWindow *filer_window) return mini; } -void minibuffer_show(FilerWindow *filer_window) +void minibuffer_show(FilerWindow *filer_window, MiniType mini_type) { Collection *collection; GtkEntry *mini; @@ -69,12 +74,30 @@ void minibuffer_show(FilerWindow *filer_window) g_return_if_fail(filer_window != NULL); g_return_if_fail(filer_window->minibuffer != NULL); - collection = filer_window->collection; - filer_window->mini_cursor_base = MAX(collection->cursor_item, 0); - mini = GTK_ENTRY(filer_window->minibuffer); - gtk_entry_set_text(mini, make_path(filer_window->path, "")->str); + filer_window->mini_type = MINI_NONE; + + switch (mini_type) + { + case MINI_PATH: + collection = filer_window->collection; + filer_window->mini_cursor_base = + MAX(collection->cursor_item, 0); + gtk_entry_set_text(mini, + make_path(filer_window->path, "")->str); + break; + case MINI_SHELL: + filer_window->mini_cursor_base = -1; /* History */ + gtk_entry_set_text(mini, ""); + break; + default: + g_warning("Bad minibuffer type\n"); + return; + } + + filer_window->mini_type = mini_type; + gtk_entry_set_position(mini, -1); gtk_widget_show(filer_window->minibuffer); @@ -85,6 +108,8 @@ void minibuffer_show(FilerWindow *filer_window) void minibuffer_hide(FilerWindow *filer_window) { + filer_window->mini_type = MINI_NONE; + gtk_widget_hide(filer_window->minibuffer); gtk_window_set_focus(GTK_WINDOW(filer_window->window), GTK_WIDGET(filer_window->collection)); @@ -95,7 +120,9 @@ void minibuffer_hide(FilerWindow *filer_window) * INTERNAL FUNCTIONS * ****************************************************************/ -static void return_pressed(FilerWindow *filer_window, GdkEventKey *event) +/* PATH ENTRY */ + +static void path_return_pressed(FilerWindow *filer_window, GdkEventKey *event) { Collection *collection = filer_window->collection; int item = collection->cursor_item; @@ -212,36 +239,7 @@ static void complete(FilerWindow *filer_window) } } -static gint key_press_event(GtkWidget *widget, - GdkEventKey *event, - FilerWindow *filer_window) -{ - switch (event->keyval) - { - case GDK_Escape: - minibuffer_hide(filer_window); - break; - case GDK_Up: - search_in_dir(filer_window, -1); - break; - case GDK_Down: - search_in_dir(filer_window, 1); - break; - case GDK_Return: - return_pressed(filer_window, event); - break; - case GDK_Tab: - complete(filer_window); - break; - default: - return FALSE; - } - - gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event"); - return TRUE; -} - -static void changed(GtkEditable *mini, FilerWindow *filer_window) +static void path_changed(GtkEditable *mini, FilerWindow *filer_window) { char *new, *slash; char *path, *real; @@ -347,3 +345,156 @@ static void search_in_dir(FilerWindow *filer_window, int dir) find_next_match(filer_window, pattern, dir); filer_window->mini_cursor_base = filer_window->collection->cursor_item; } + +/* SHELL COMMANDS */ + +static void shell_return_pressed(FilerWindow *filer_window, GdkEventKey *event) +{ + GPtrArray *argv; + int i; + guchar *entry; + Collection *collection = filer_window->collection; + + entry = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer)); + shell_history = g_list_prepend(shell_history, g_strdup(entry)); + + argv = g_ptr_array_new(); + g_ptr_array_add(argv, "sh"); + g_ptr_array_add(argv, "-c"); + g_ptr_array_add(argv, entry); + g_ptr_array_add(argv, "sh"); + + for (i = 0; i < collection->number_of_items; i++) + { + DirItem *item = (DirItem *) collection->items[i].data; + if (collection->items[i].selected) + g_ptr_array_add(argv, item->leafname); + } + + g_ptr_array_add(argv, NULL); + + switch (fork()) + { + case -1: + delayed_error("ROX-Filer", "Failed to create " + "child process"); + return; + case 0: /* Child */ + dup2(to_error_log, STDOUT_FILENO); + close_on_exec(STDOUT_FILENO, FALSE); + dup2(to_error_log, STDERR_FILENO); + close_on_exec(STDERR_FILENO, FALSE); + if (chdir(filer_window->path)) + g_printerr("chdir(%s) failed: %s\n", + filer_window->path, + g_strerror(errno)); + execvp((char *) argv->pdata[0], + (char **) argv->pdata); + g_printerr("execvp(%s, ...) failed: %s\n", + (char *) argv->pdata[0], + g_strerror(errno)); + _exit(0); + } + + g_ptr_array_free(argv, TRUE); + + minibuffer_hide(filer_window); +} + +/* Move through the shell history */ +static void shell_recall(FilerWindow *filer_window, int dir) +{ + guchar *command; + int pos = filer_window->mini_cursor_base; + + pos += dir; + if (pos >= 0) + { + command = g_list_nth_data(shell_history, pos); + if (!command) + return; + } + else + command = ""; + + if (pos < -1) + pos = -1; + filer_window->mini_cursor_base = pos; + + gtk_entry_set_text(GTK_ENTRY(filer_window->minibuffer), command); +} + +/* EVENT HANDLERS */ + +static gint key_press_event(GtkWidget *widget, + GdkEventKey *event, + FilerWindow *filer_window) +{ + if (event->keyval == GDK_Escape) + { + minibuffer_hide(filer_window); + return TRUE; + } + + switch (filer_window->mini_type) + { + case MINI_PATH: + switch (event->keyval) + { + case GDK_Up: + search_in_dir(filer_window, -1); + break; + case GDK_Down: + search_in_dir(filer_window, 1); + break; + case GDK_Return: + path_return_pressed(filer_window, + event); + break; + case GDK_Tab: + complete(filer_window); + break; + default: + return FALSE; + } + break; + + case MINI_SHELL: + switch (event->keyval) + { + case GDK_Up: + shell_recall(filer_window, 1); + break; + case GDK_Down: + shell_recall(filer_window, -1); + break; + case GDK_Tab: + break; + case GDK_Return: + shell_return_pressed(filer_window, + event); + default: + return FALSE; + } + break; + default: + break; + } + + gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event"); + return TRUE; +} + +static void changed(GtkEditable *mini, FilerWindow *filer_window) +{ + switch (filer_window->mini_type) + { + case MINI_PATH: + path_changed(mini, filer_window); + return; + case MINI_SHELL: + break; + default: + break; + } +} diff --git a/ROX-Filer/src/minibuffer.h b/ROX-Filer/src/minibuffer.h index 0c7e9f0c..0fa258f3 100644 --- a/ROX-Filer/src/minibuffer.h +++ b/ROX-Filer/src/minibuffer.h @@ -8,11 +8,13 @@ #ifndef _MINIBUFFER_H #define _MINIBUFFER_H +typedef enum {MINI_NONE, MINI_PATH, MINI_SHELL} MiniType; + #include #include "filer.h" GtkWidget *create_minibuffer(FilerWindow *filer_window); -void minibuffer_show(FilerWindow *filer_window); +void minibuffer_show(FilerWindow *filer_window, MiniType mini_type); void minibuffer_hide(FilerWindow *filer_window); #endif /* _MINIBUFFER_H */ -- 2.11.4.GIT