r612: Opening the shell minibuffer with a selection adds ' "$@' after the cursor.
[rox-filer.git] / ROX-Filer / src / minibuffer.c
blob46f3b83004c63b4f3be39c6fff443fcfdd4280ab
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2001, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* minibuffer.c - for handling the path entry box at the bottom */
24 #include "config.h"
26 #include <string.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <glob.h>
30 #include <stdio.h>
32 #include <gtk/gtk.h>
33 #include <gdk/gdkkeysyms.h>
35 #include "global.h"
37 #include "options.h"
38 #include "collection.h"
39 #include "find.h"
40 #include "gui_support.h"
41 #include "support.h"
42 #include "minibuffer.h"
43 #include "filer.h"
44 #include "main.h"
45 #include "action.h"
46 #include "dir.h"
47 #include "type.h"
49 static GList *shell_history = NULL;
51 /* Static prototypes */
52 static gint key_press_event(GtkWidget *widget,
53 GdkEventKey *event,
54 FilerWindow *filer_window);
55 static void changed(GtkEditable *mini, FilerWindow *filer_window);
56 static gboolean find_next_match(FilerWindow *filer_window,
57 char *pattern,
58 int dir);
59 static gboolean find_exact_match(FilerWindow *filer_window, char *pattern);
60 static gboolean matches(Collection *collection, int item, char *pattern);
61 static void search_in_dir(FilerWindow *filer_window, int dir);
62 static guchar *mini_contents(FilerWindow *filer_window);
63 static void show_help(FilerWindow *filer_window);
66 /****************************************************************
67 * EXTERNAL INTERFACE *
68 ****************************************************************/
70 void minibuffer_init(void)
72 option_add_int("filer_beep_fail", 1, NULL);
73 option_add_int("filer_beep_multi", 1, NULL);
76 /* Creates the minibuffer widgets, setting the appropriate fields
77 * in filer_window.
79 void create_minibuffer(FilerWindow *filer_window)
81 GtkWidget *hbox, *label, *mini;
83 hbox = gtk_hbox_new(FALSE, 0);
85 gtk_box_pack_start(GTK_BOX(hbox),
86 new_help_button((HelpFunc) show_help, filer_window),
87 FALSE, TRUE, 0);
89 label = gtk_label_new("");
90 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 2);
92 mini = gtk_entry_new();
93 gtk_box_pack_start(GTK_BOX(hbox), mini, TRUE, TRUE, 0);
94 gtk_widget_set_style(mini, fixed_style);
95 gtk_signal_connect(GTK_OBJECT(mini), "key_press_event",
96 GTK_SIGNAL_FUNC(key_press_event), filer_window);
97 gtk_signal_connect(GTK_OBJECT(mini), "changed",
98 GTK_SIGNAL_FUNC(changed), filer_window);
100 filer_window->minibuffer = mini;
101 filer_window->minibuffer_label = label;
102 filer_window->minibuffer_area = hbox;
105 void minibuffer_show(FilerWindow *filer_window, MiniType mini_type)
107 Collection *collection;
108 GtkEntry *mini;
109 int pos = -1, i;
111 g_return_if_fail(filer_window != NULL);
112 g_return_if_fail(filer_window->minibuffer != NULL);
114 mini = GTK_ENTRY(filer_window->minibuffer);
115 gtk_widget_set_style(filer_window->minibuffer, fixed_style);
117 filer_window->mini_type = MINI_NONE;
118 gtk_label_set_text(GTK_LABEL(filer_window->minibuffer_label),
119 mini_type == MINI_PATH ? _("Goto:") :
120 mini_type == MINI_SHELL ? _("Shell:") :
121 mini_type == MINI_SELECT_IF ? _("Select If:") :
122 "?");
124 collection = filer_window->collection;
125 switch (mini_type)
127 case MINI_PATH:
128 collection_move_cursor(collection, 0, 0);
129 filer_window->mini_cursor_base =
130 MAX(collection->cursor_item, 0);
131 gtk_entry_set_text(mini,
132 make_path(filer_window->path, "")->str);
133 if (filer_window->temp_show_hidden)
135 display_set_hidden(filer_window, FALSE);
136 filer_window->temp_show_hidden = FALSE;
138 break;
139 case MINI_SELECT_IF:
140 gtk_entry_set_text(mini, "");
141 filer_window->mini_cursor_base = -1; /* History */
142 break;
143 case MINI_SHELL:
144 pos = 0;
145 i = collection->cursor_item;
146 if (collection->number_selected)
147 gtk_entry_set_text(mini, " \"$@\"");
148 else if (i > -1)
150 DirItem *item = (DirItem *)
151 collection->items[i].data;
152 guchar *tmp;
154 tmp = g_strconcat(" ", item->leafname, NULL);
155 gtk_entry_set_text(mini, tmp);
156 g_free(tmp);
158 else
159 gtk_entry_set_text(mini, "");
160 filer_window->mini_cursor_base = -1; /* History */
161 break;
162 default:
163 g_warning("Bad minibuffer type\n");
164 return;
167 filer_window->mini_type = mini_type;
169 gtk_entry_set_position(mini, pos);
171 gtk_widget_show_all(filer_window->minibuffer_area);
173 gtk_window_set_focus(GTK_WINDOW(filer_window->window),
174 filer_window->minibuffer);
177 void minibuffer_hide(FilerWindow *filer_window)
179 filer_window->mini_type = MINI_NONE;
181 gtk_widget_hide(filer_window->minibuffer_area);
182 gtk_window_set_focus(GTK_WINDOW(filer_window->window),
183 GTK_WIDGET(filer_window->collection));
185 if (filer_window->temp_show_hidden)
187 display_set_hidden(filer_window, FALSE);
188 filer_window->temp_show_hidden = FALSE;
192 /* Insert this leafname at the cursor (replacing the selection, if any).
193 * Must be in SHELL mode.
195 void minibuffer_add(FilerWindow *filer_window, guchar *leafname)
197 guchar *esc;
198 GtkEditable *edit = GTK_EDITABLE(filer_window->minibuffer);
199 GtkEntry *entry = GTK_ENTRY(edit);
200 int pos;
202 g_return_if_fail(filer_window->mini_type == MINI_SHELL);
204 esc = shell_escape(leafname);
206 gtk_editable_delete_selection(edit);
207 pos = gtk_editable_get_position(edit);
209 if (pos > 0 && gtk_entry_get_text(entry)[pos - 1] != ' ')
210 gtk_editable_insert_text(edit, " ", 1, &pos);
212 gtk_editable_insert_text(edit, esc, strlen(esc), &pos);
213 gtk_editable_set_position(edit, pos);
215 g_free(esc);
219 /****************************************************************
220 * INTERNAL FUNCTIONS *
221 ****************************************************************/
223 static void show_help(FilerWindow *filer_window)
225 guchar *message;
227 gtk_widget_grab_focus(filer_window->minibuffer);
229 switch (filer_window->mini_type)
231 case MINI_PATH:
232 message = _("Enter the name of a file and I'll display "
233 "it for you. Press Tab to fill in the longest "
234 "match. Escape to close the minibuffer.");
235 break;
236 case MINI_SHELL:
237 message = _("Enter a shell command to execute. Click "
238 "on a file to add it to the buffer.");
239 break;
240 case MINI_SELECT_IF:
241 show_condition_help(NULL);
242 return;
243 default:
244 message = "?!?";
245 break;
248 delayed_error(PROJECT, message);
252 /* PATH ENTRY */
254 static void path_return_pressed(FilerWindow *filer_window, GdkEventKey *event)
256 Collection *collection = filer_window->collection;
257 int item = collection->cursor_item;
258 char *path, *pattern;
259 int flags = OPEN_FROM_MINI | OPEN_SAME_WINDOW;
261 path = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
262 pattern = strrchr(path, '/');
263 if (pattern)
264 pattern++;
265 else
266 pattern = path;
268 if (item == -1 || item >= collection->number_of_items ||
269 !matches(collection, item, pattern))
271 gdk_beep();
272 return;
275 if ((event->state & GDK_SHIFT_MASK) != 0)
276 flags |= OPEN_SHIFT;
278 filer_openitem(filer_window, item, flags);
281 /* Use the cursor item to fill in the minibuffer.
282 * If there are multiple matches the fill in as much as possible and
283 * (possibly) beep.
285 static void complete(FilerWindow *filer_window)
287 GtkEntry *entry;
288 Collection *collection = filer_window->collection;
289 int cursor = collection->cursor_item;
290 DirItem *item;
291 int shortest_stem = -1;
292 int current_stem;
293 int other;
294 guchar *text, *leaf;
296 if (cursor < 0 || cursor >= collection->number_of_items)
298 gdk_beep();
299 return;
302 entry = GTK_ENTRY(filer_window->minibuffer);
304 item = (DirItem *) collection->items[cursor].data;
306 text = gtk_entry_get_text(entry);
307 leaf = strrchr(text, '/');
308 if (!leaf)
310 gdk_beep();
311 return;
314 leaf++;
315 if (!matches(collection, cursor, leaf))
317 gdk_beep();
318 return;
321 current_stem = strlen(leaf);
323 /* Find the longest other match of this name. It it's longer than
324 * the currently entered text then complete only up to that length.
326 for (other = 0; other < collection->number_of_items; other++)
328 DirItem *other_item = (DirItem *) collection->items[other].data;
329 int stem = 0;
331 if (other == cursor)
332 continue;
334 while (other_item->leafname[stem] && item->leafname[stem])
336 if (other_item->leafname[stem] != item->leafname[stem])
337 break;
338 stem++;
341 /* stem is the index of the first difference */
342 if (stem >= current_stem &&
343 (shortest_stem == -1 || stem < shortest_stem))
344 shortest_stem = stem;
347 if (current_stem == shortest_stem)
349 /* We didn't add anything... */
350 if (option_get_int("filer_beep_fail"))
351 gdk_beep();
353 else if (current_stem < shortest_stem)
355 guchar *extra;
357 extra = g_strndup(item->leafname + current_stem,
358 shortest_stem - current_stem);
359 gtk_entry_append_text(entry, extra);
360 g_free(extra);
362 if (option_get_int("filer_beep_multi"))
363 gdk_beep();
365 else
367 GString *new;
369 new = make_path(filer_window->path, item->leafname);
371 if (item->base_type == TYPE_DIRECTORY &&
372 (item->flags & ITEM_FLAG_APPDIR) == 0)
373 g_string_append_c(new, '/');
375 gtk_entry_set_text(entry, new->str);
379 static void path_changed(GtkEditable *mini, FilerWindow *filer_window)
381 char *new, *slash;
382 char *path, *real;
384 new = gtk_entry_get_text(GTK_ENTRY(mini));
385 if (*new == '/')
386 new = g_strdup(new);
387 else
388 new = g_strdup_printf("/%s", new);
390 slash = strrchr(new, '/');
391 *slash = '\0';
393 if (*new == '\0')
394 path = "/";
395 else
396 path = new;
398 real = pathdup(path);
400 if (strcmp(real, filer_window->path) != 0)
402 struct stat info;
403 if (mc_stat(real, &info) == 0 && S_ISDIR(info.st_mode))
404 filer_change_to(filer_window, real, slash + 1);
405 else
406 gdk_beep();
408 else
410 if (slash[1] == '.')
412 if (!filer_window->show_hidden)
414 filer_window->temp_show_hidden = TRUE;
415 display_set_hidden(filer_window, TRUE);
418 else if (filer_window->temp_show_hidden)
420 display_set_hidden(filer_window, FALSE);
421 filer_window->temp_show_hidden = FALSE;
424 if (find_exact_match(filer_window, slash + 1) == FALSE &&
425 find_next_match(filer_window, slash + 1, 0) == FALSE)
426 gdk_beep();
429 g_free(real);
430 g_free(new);
433 /* Look for an exact match, and move the cursor to it if found.
434 * TRUE on success.
436 static gboolean find_exact_match(FilerWindow *filer_window, char *pattern)
438 Collection *collection = filer_window->collection;
439 int i;
441 for (i = 0; i < collection->number_of_items; i++)
443 DirItem *item = (DirItem *) collection->items[i].data;
445 if (strcmp(item->leafname, pattern) == 0)
447 collection_set_cursor_item(collection, i);
448 return TRUE;
452 return FALSE;
455 /* Find the next item in the collection that matches 'pattern'. Start from
456 * mini_cursor_base and loop at either end. dir is 1 for a forward search,
457 * -1 for backwards. 0 means forwards, but may stay the same.
459 * Does not automatically update mini_cursor_base.
461 * Returns TRUE if a match is found.
463 static gboolean find_next_match(FilerWindow *filer_window,
464 char *pattern,
465 int dir)
467 Collection *collection = filer_window->collection;
468 int base = filer_window->mini_cursor_base;
469 int item = base;
470 gboolean retval = TRUE;
472 if (collection->number_of_items < 1)
473 return FALSE;
475 if (base < 0 || base>= collection->number_of_items)
476 filer_window->mini_cursor_base = base = 0;
480 /* Step to the next item */
481 item += dir;
483 if (item >= collection->number_of_items)
484 item = 0;
485 else if (item < 0)
486 item = collection->number_of_items - 1;
488 if (dir == 0)
489 dir = 1;
490 else if (item == base)
492 retval = FALSE;
493 break; /* No (other) matches at all */
495 } while (!matches(collection, item, pattern));
497 collection_set_cursor_item(collection, item);
499 return retval;
502 static gboolean matches(Collection *collection, int item_number, char *pattern)
504 DirItem *item = (DirItem *) collection->items[item_number].data;
506 return strncmp(item->leafname, pattern, strlen(pattern)) == 0;
509 /* Find next match and set base for future matches. */
510 static void search_in_dir(FilerWindow *filer_window, int dir)
512 char *path, *pattern;
514 path = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
515 pattern = strrchr(path, '/');
516 if (pattern)
517 pattern++;
518 else
519 pattern = path;
521 filer_window->mini_cursor_base = filer_window->collection->cursor_item;
522 find_next_match(filer_window, pattern, dir);
523 filer_window->mini_cursor_base = filer_window->collection->cursor_item;
526 /* SHELL COMMANDS */
528 static void add_to_history(guchar *line)
530 guchar *last;
532 last = shell_history ? (guchar *) shell_history->data : NULL;
534 if (last && strcmp(last, line) == 0)
535 return; /* Duplicating last entry */
537 shell_history = g_list_prepend(shell_history, g_strdup(line));
540 static void shell_done(FilerWindow *filer_window)
542 if (filer_exists(filer_window))
543 filer_update_dir(filer_window, TRUE);
546 /* Given a list of matches, return the longest stem. g_free() the result.
547 * Special chars are escaped. If there is only a single (non-dir) match
548 * then a trailing space is added.
550 static guchar *best_match(FilerWindow *filer_window, glob_t *matches)
552 gchar *first = matches->gl_pathv[0];
553 int i;
554 int longest, path_len;
555 guchar *path, *tmp;
557 longest = strlen(first);
559 for (i = 1; i < matches->gl_pathc; i++)
561 int j;
562 guchar *m = matches->gl_pathv[i];
564 for (j = 0; j < longest; j++)
565 if (m[j] != first[j])
566 longest = j;
569 path_len = strlen(filer_window->path);
570 if (strncmp(filer_window->path, first, path_len) == 0 &&
571 first[path_len] == '/' && first[path_len + 1])
573 path = g_strndup(first + path_len + 1, longest - path_len - 1);
575 else
576 path = g_strndup(first, longest);
578 tmp = shell_escape(path);
579 g_free(path);
581 if (matches->gl_pathc == 1 && tmp[strlen(tmp) - 1] != '/')
583 path = g_strdup_printf("%s ", tmp);
584 g_free(tmp);
585 return path;
588 return tmp;
591 static void shell_tab(FilerWindow *filer_window)
593 int i;
594 guchar *entry;
595 guchar quote;
596 int pos;
597 GString *leaf;
598 glob_t matches;
599 int leaf_start;
601 entry = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
602 pos = gtk_editable_get_position(GTK_EDITABLE(filer_window->minibuffer));
603 leaf = g_string_new(NULL);
605 quote = '\0';
606 for (i = 0; i < pos; i++)
608 guchar c = entry[i];
610 if (leaf->len == 0)
611 leaf_start = i;
613 if (c == ' ')
615 g_string_truncate(leaf, 0);
616 continue;
618 else if (c == '\\' && i + 1 < pos)
619 c = entry[++i];
620 else if (c == '"' || c == '\'')
622 guchar cc;
624 for (++i; i < pos; i++)
626 cc = entry[i];
628 if (cc == '\\' && i + 1 < pos)
629 cc = entry[++i];
630 else if (entry[i] == c)
631 break;
632 g_string_append_c(leaf, entry[i]);
634 continue;
637 g_string_append_c(leaf, c);
640 if (leaf->len == 0)
641 leaf_start = pos;
643 if (leaf->str[0] != '/' && leaf->str[0] != '~')
645 g_string_prepend_c(leaf, '/');
646 g_string_prepend(leaf, filer_window->path);
649 g_string_append_c(leaf, '*');
651 if (glob(leaf->str,
652 #ifdef GLOB_TILDE
653 GLOB_TILDE |
654 #endif
655 GLOB_MARK, NULL, &matches) == 0)
657 if (matches.gl_pathc > 0)
659 guchar *best;
660 GtkEditable *edit =
661 GTK_EDITABLE(filer_window->minibuffer);
663 best = best_match(filer_window, &matches);
665 gtk_editable_delete_text(edit, leaf_start, pos);
666 gtk_editable_insert_text(edit, best, strlen(best),
667 &leaf_start);
668 gtk_editable_set_position(edit, leaf_start);
670 g_free(best);
672 if (matches.gl_pathc != 1)
673 gdk_beep();
675 globfree(&matches);
678 g_string_free(leaf, TRUE);
681 /* Either execute the command or make it the default run action */
682 static void shell_return_pressed(FilerWindow *filer_window)
684 GPtrArray *argv;
685 int i;
686 guchar *entry;
687 Collection *collection = filer_window->collection;
688 int child;
690 entry = mini_contents(filer_window);
692 if (!entry)
693 goto out;
695 add_to_history(entry);
697 argv = g_ptr_array_new();
698 g_ptr_array_add(argv, "sh");
699 g_ptr_array_add(argv, "-c");
700 g_ptr_array_add(argv, entry);
701 g_ptr_array_add(argv, "sh");
703 for (i = 0; i < collection->number_of_items; i++)
705 DirItem *item = (DirItem *) collection->items[i].data;
706 if (collection->items[i].selected)
707 g_ptr_array_add(argv, item->leafname);
710 g_ptr_array_add(argv, NULL);
712 child = fork();
714 switch (child)
716 case -1:
717 delayed_error(PROJECT, _("Failed to create "
718 "child process"));
719 break;
720 case 0: /* Child */
721 /* Ensure output is noticed - send stdout to stderr */
722 dup2(STDERR_FILENO, STDOUT_FILENO);
723 close_on_exec(STDOUT_FILENO, FALSE);
724 if (chdir(filer_window->path))
725 g_printerr("chdir(%s) failed: %s\n",
726 filer_window->path,
727 g_strerror(errno));
728 execvp((char *) argv->pdata[0],
729 (char **) argv->pdata);
730 g_printerr("execvp(%s, ...) failed: %s\n",
731 (char *) argv->pdata[0],
732 g_strerror(errno));
733 _exit(0);
734 default:
735 on_child_death(child,
736 (CallbackFn) shell_done, filer_window);
737 break;
740 g_ptr_array_free(argv, TRUE);
742 out:
743 minibuffer_hide(filer_window);
746 /* Move through the shell history */
747 static void shell_recall(FilerWindow *filer_window, int dir)
749 guchar *command;
750 int pos = filer_window->mini_cursor_base;
752 pos += dir;
753 if (pos >= 0)
755 command = g_list_nth_data(shell_history, pos);
756 if (!command)
757 return;
759 else
760 command = "";
762 if (pos < -1)
763 pos = -1;
764 filer_window->mini_cursor_base = pos;
766 gtk_entry_set_text(GTK_ENTRY(filer_window->minibuffer), command);
769 /* SELECT IF */
771 static void select_return_pressed(FilerWindow *filer_window)
773 FindCondition *cond;
774 int i, n;
775 guchar *entry;
776 Collection *collection = filer_window->collection;
777 FindInfo info;
779 entry = mini_contents(filer_window);
781 if (!entry)
782 goto out;
784 add_to_history(entry);
786 cond = find_compile(entry);
787 if (!cond)
789 delayed_error(PROJECT, "Invalid Find condition");
790 return;
793 info.now = time(NULL);
794 info.prune = FALSE; /* (don't care) */
795 n = collection->number_of_items;
797 /* If an item at the start is selected then we could lose the
798 * primary selection after checking that item and then need to
799 * gain it again at the end. Therefore, if anything is selected
800 * then select the last item until the end of the search.
802 if (collection->number_selected)
803 collection_select_item(collection, n - 1);
805 for (i = 0; i < n; i++)
807 DirItem *item = (DirItem *) collection->items[i].data;
809 info.leaf = item->leafname;
810 info.fullpath = make_path(filer_window->path, info.leaf)->str;
812 if (lstat(info.fullpath, &info.stats) == 0 &&
813 find_test_condition(cond, &info))
814 collection_select_item(collection, i);
815 else
816 collection_unselect_item(collection, i);
819 find_condition_free(cond);
821 out:
822 minibuffer_hide(filer_window);
826 /* EVENT HANDLERS */
828 static gint key_press_event(GtkWidget *widget,
829 GdkEventKey *event,
830 FilerWindow *filer_window)
832 if (event->keyval == GDK_Escape)
834 if (filer_window->mini_type == MINI_SHELL)
836 guchar *line;
838 line = mini_contents(filer_window);
839 if (line)
840 add_to_history(line);
843 minibuffer_hide(filer_window);
844 return TRUE;
847 switch (filer_window->mini_type)
849 case MINI_PATH:
850 switch (event->keyval)
852 case GDK_Up:
853 search_in_dir(filer_window, -1);
854 break;
855 case GDK_Down:
856 search_in_dir(filer_window, 1);
857 break;
858 case GDK_Return:
859 path_return_pressed(filer_window,
860 event);
861 break;
862 case GDK_Tab:
863 complete(filer_window);
864 break;
865 default:
866 return FALSE;
868 break;
870 case MINI_SHELL:
871 switch (event->keyval)
873 case GDK_Up:
874 shell_recall(filer_window, 1);
875 break;
876 case GDK_Down:
877 shell_recall(filer_window, -1);
878 break;
879 case GDK_Tab:
880 shell_tab(filer_window);
881 break;
882 case GDK_Return:
883 shell_return_pressed(filer_window);
884 break;
885 default:
886 return FALSE;
888 break;
889 case MINI_SELECT_IF:
890 switch (event->keyval)
892 case GDK_Up:
893 shell_recall(filer_window, 1);
894 break;
895 case GDK_Down:
896 shell_recall(filer_window, -1);
897 break;
898 case GDK_Tab:
899 break;
900 case GDK_Return:
901 select_return_pressed(filer_window);
902 break;
903 default:
904 return FALSE;
906 break;
907 default:
908 break;
911 gtk_signal_emit_stop_by_name(GTK_OBJECT(widget), "key_press_event");
912 return TRUE;
915 static void changed(GtkEditable *mini, FilerWindow *filer_window)
917 switch (filer_window->mini_type)
919 case MINI_PATH:
920 path_changed(mini, filer_window);
921 return;
922 case MINI_SELECT_IF:
923 set_find_string_colour(GTK_WIDGET(mini),
924 gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer)));
925 return;
926 default:
927 break;
931 /* Returns a string (which must NOT be freed), or NULL if the buffer
932 * is blank (whitespace only).
934 static guchar *mini_contents(FilerWindow *filer_window)
936 guchar *entry, *c;
938 entry = gtk_entry_get_text(GTK_ENTRY(filer_window->minibuffer));
940 for (c = entry; *c; c++)
941 if (!isspace(*c))
942 return entry;
944 return NULL;