gvfs bash completion



Hey,

So here's a simple patch I've been wanting to write for some time. It
provides completion on the URI in bash(1) for the various gvfs-*
commandline tools. 

There's also some fixes for gvfs-ls including making -h actually work
(previously hidden files were shown by default) and also a -l option
similar to ls(1) (without it we only print the names; previously we
showed more info).

In [1] is a sample bash session using this.

     David

[1] :

[davidz oneill ~]$ gvfs-info 
file:///                   gphoto2://[usb:001,011]/
file:///media/EOS_DIGITAL  sftp://hook.local/
[davidz oneill ~]$ gvfs-info gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_00
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0006.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0007.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0008.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0009.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0010.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0011.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0012.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0013.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0014.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0015.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0016.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0017.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0018.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0019.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0020.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0021.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0022.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0023.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0024.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0025.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0026.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0027.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0028.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0029.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0030.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0031.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0032.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0033.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0034.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0035.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0036.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0037.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0038.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0039.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0040.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0041.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0042.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0043.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0044.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0045.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0046.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0047.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0048.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0049.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0050.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0051.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0052.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0053.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0054.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0055.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0056.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0057.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0058.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0059.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0060.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0061.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0062.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0063.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0064.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0067.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0068.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0069.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0070.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0071.JPG
gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0072.JPG
[davidz oneill ~]$ gvfs-info gphoto2://[usb:001,011]/DCIM/100APPLE/IMG_0072.JPG
display name: IMG_0072.JPG
name: IMG_0072.JPG
type: regular
size: 332791
attributes:
  standard::name: IMG_0072.JPG
  standard::display-name: IMG_0072.JPG
  standard::icon: GThemedIcon:0x8a19c50
  standard::type: 1
  standard::content-type: image/jpeg
  standard::size: 332791
  access::can-read: TRUE
  access::can-write: FALSE
  access::can-delete: FALSE
  access::can-execute: FALSE
  access::can-trash: FALSE
  access::can-rename: FALSE
  id::filesystem: host='[usb:001,011]',type='gphoto2',mount_prefix='/'
  thumbnail::path: /home/davidz/.thumbnails/normal/dcc65a0b4c80c0339e7600bd68f8af21.png
  time::modified: 1202675218
  time::modified-usec: 0

Index: programs/gvfs-ls.c
===================================================================
--- programs/gvfs-ls.c	(revision 1340)
+++ programs/gvfs-ls.c	(working copy)
@@ -1,3 +1,5 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
 /* GIO - GLib Input, Output and Streaming Library
  * 
  * Copyright (C) 2006-2007 Red Hat, Inc.
@@ -29,11 +31,17 @@
 
 static char *attributes = NULL;
 static gboolean show_hidden = FALSE;
+static gboolean show_mounts = FALSE;
+static gboolean show_long = FALSE;
+static char *show_completions = NULL;
 
 static GOptionEntry entries[] = 
 {
 	{ "attributes", 'a', 0, G_OPTION_ARG_STRING, &attributes, "The attributes to get", NULL },
 	{ "hidden", 'h', 0, G_OPTION_ARG_NONE, &show_hidden, "Show hidden files", NULL },
+        { "long", 'l', 0, G_OPTION_ARG_NONE, &show_long, "Use a long listing format", NULL },
+        { "show-completions", 'c', 0, G_OPTION_ARG_STRING, &show_completions, "Show completions", NULL}, 
+        { "show-mounts", 'm', 0, G_OPTION_ARG_NONE, &show_mounts, "Show mounts", NULL },
 	{ NULL }
 };
 
@@ -86,7 +94,14 @@
 
   size = g_file_info_get_size (info);
   type = type_to_string (g_file_info_get_file_type (info));
-  g_print ("%s\t%"G_GUINT64_FORMAT"\t(%s)", name, (guint64)size, type);
+  if (show_long)
+    {
+      g_print ("%s\t%"G_GUINT64_FORMAT"\t(%s)", name, (guint64)size, type);
+    }
+  else
+    {
+      g_print ("%s", name);
+    }
 
   first_attr = TRUE;
   attributes = g_file_info_list_attributes (info, NULL);
@@ -94,9 +109,11 @@
     {
       char *val_as_string;
 
-      if (strcmp (attributes[i], G_FILE_ATTRIBUTE_STANDARD_NAME) == 0 ||
+      if (!show_long ||
+          strcmp (attributes[i], G_FILE_ATTRIBUTE_STANDARD_NAME) == 0 ||
 	  strcmp (attributes[i], G_FILE_ATTRIBUTE_STANDARD_SIZE) == 0 ||
-	  strcmp (attributes[i], G_FILE_ATTRIBUTE_STANDARD_TYPE) == 0)
+	  strcmp (attributes[i], G_FILE_ATTRIBUTE_STANDARD_TYPE) == 0 ||
+	  strcmp (attributes[i], G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN) == 0)
 	continue;
 
       if (first_attr)
@@ -130,7 +147,7 @@
   enumerator = g_file_enumerate_children (file, attributes, 0, NULL, &error);
   if (enumerator == NULL)
     {
-      g_print ("Error: %s\n", error->message);
+      g_printerr ("Error: %s\n", error->message);
       g_error_free (error);
       error = NULL;
       return;
@@ -145,19 +162,131 @@
 
   if (error)
     {
-      g_print ("Error: %s\n", error->message);
+      g_printerr ("Error: %s\n", error->message);
       g_error_free (error);
       error = NULL;
     }
 	 
   if (!g_file_enumerator_close (enumerator, NULL, &error))
     {
-      g_print ("Error closing enumerator: %s\n", error->message);
+      g_printerr ("Error closing enumerator: %s\n", error->message);
       g_error_free (error);
       error = NULL;
     }
 }
 
+static void
+print_mounts (const char *prefix)
+{
+  GList *l;
+  GList *mounts;
+  GVolumeMonitor *volume_monitor;
+  
+  volume_monitor = g_volume_monitor_get ();
+  mounts = g_volume_monitor_get_mounts (volume_monitor);
+  if (mounts != NULL)
+    {
+      for (l = mounts; l != NULL; l = l->next)
+        {
+          GMount *mount = l->data;
+          GFile *mount_root;
+          char *uri;
+          
+          mount_root = g_mount_get_root (mount);
+          uri = g_file_get_uri (mount_root);
+          if (prefix == NULL || g_str_has_prefix (uri, prefix))
+            {
+              g_print ("%s\n", uri);
+            }
+          g_free (uri);
+          g_object_unref (mount_root);
+          g_object_unref (mount);
+        }
+      g_list_free (mounts);
+    }
+  g_object_unref (volume_monitor);
+
+  if (prefix == NULL || g_str_has_prefix ("file:///", prefix))
+    {
+      g_print ("file:///\n");
+    }
+}
+
+static void
+print_completions (const char *uri)
+{
+  GFile *f;
+  GFile *parent;
+
+  f = g_file_new_for_uri (uri);
+  if (!g_file_is_native (f))
+    {
+      GMount *mount;
+      mount = g_file_find_enclosing_mount (f, NULL, NULL);
+      if (mount == NULL)
+        {
+          print_mounts (uri);
+          g_object_unref (f);
+          return;
+        }
+      g_object_unref (mount);
+    }
+
+  if (g_str_has_suffix (uri, "/"))
+    {
+      parent = g_object_ref (f);
+    }
+  else
+    {
+      parent = g_file_get_parent (f);
+    }
+  
+  if (parent != NULL)
+    {
+      GFileEnumerator *enumerator;
+      enumerator = g_file_enumerate_children (parent, 
+                                              G_FILE_ATTRIBUTE_STANDARD_NAME ","
+                                              G_FILE_ATTRIBUTE_STANDARD_TYPE,
+                                              0, 
+                                              NULL, 
+                                              NULL);
+      if (enumerator != NULL)
+        {
+          GFileInfo *info;
+          while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL)
+            {
+              const char *name;
+              GFileType type;
+              
+              name = g_file_info_get_name (info);
+              type = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
+              if (name != NULL)
+                {
+                  GFile *entry;
+                  char *entry_uri;
+                  entry = g_file_get_child (parent, name);
+                  entry_uri = g_file_get_uri (entry);
+                  g_object_unref (entry);
+                  
+                  if (g_str_has_prefix (entry_uri, uri))
+                    {
+                      g_print ("%s", entry_uri);
+                      if (type & G_FILE_TYPE_DIRECTORY)
+                        {
+                          g_print ("/");
+                        }
+                      g_print ("\n");
+                    }
+                  g_free (entry_uri);
+                }
+              g_object_unref (info);
+            }
+          g_file_enumerator_close (enumerator, NULL, NULL);
+        }
+      g_object_unref (parent);
+    }
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -175,12 +304,30 @@
   g_option_context_parse (context, &argc, &argv, &error);
   g_option_context_free (context);
 
+  if (attributes != NULL)
+    {
+      /* asking for attributes implies -l; otherwise it won't get shown */
+      show_long = TRUE;
+    }
+
   attributes = g_strconcat (G_FILE_ATTRIBUTE_STANDARD_NAME ","
 			    G_FILE_ATTRIBUTE_STANDARD_TYPE ","
-			    G_FILE_ATTRIBUTE_STANDARD_SIZE,
+			    G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+			    G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN,
 			    attributes != NULL ? "," : "",
 			    attributes,
 			    NULL);
+
+  if (show_mounts)
+    {
+      print_mounts (NULL);
+      return 0;
+    }
+  else if (show_completions != NULL)
+    {
+      print_completions (show_completions);
+      return 0;
+    }
   
   if (argc > 1)
     {
Index: programs/Makefile.am
===================================================================
--- programs/Makefile.am	(revision 1340)
+++ programs/Makefile.am	(working copy)
@@ -30,6 +30,9 @@
 	gvfs-less				\
 	$(NULL)
 
+profiledir = $(sysconfdir)/profile.d
+profile_SCRIPTS = gvfs-bash-completion.sh
+
 gvfs_cat_SOURCES = gvfs-cat.c
 gvfs_cat_LDADD = $(libraries)
 
--- /dev/null	2008-02-22 11:51:15.646005979 -0500
+++ programs/gvfs-bash-completion.sh	2008-02-22 23:51:15.000000000 -0500
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+# Copyright (C) 2006-2007 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
+# USA.
+#
+# Author: David Zeuthen <davidz redhat com>
+
+# Check for bash                                                                
+[ -z "$BASH_VERSION" ] && return
+
+####################################################################################################
+
+# don't misbehave on colons; See item E13 at http://tiswww.case.edu/php/chet/bash/FAQ
+COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
+
+__gvfs_multiple_uris() {
+    local IFS=$'\n'
+    local cur="${COMP_WORDS[COMP_CWORD]}"
+
+    if [ "$cur" = "" ] ; then
+        COMPREPLY=($(compgen -W "$(gvfs-ls --show-mounts)" -- $cur))
+    else
+        COMPREPLY=($(compgen -W "$(gvfs-ls --show-completions $cur)" -- $cur))
+    fi
+}
+
+####################################################################################################
+
+complete -o nospace -F __gvfs_multiple_uris gvfs-ls
+complete -o nospace -F __gvfs_multiple_uris gvfs-info
+complete -o nospace -F __gvfs_multiple_uris gvfs-cat
+complete -o nospace -F __gvfs_multiple_uris gvfs-less
+complete -o nospace -F __gvfs_multiple_uris gvfs-copy
+complete -o nospace -F __gvfs_multiple_uris gvfs-mkdir
+complete -o nospace -F __gvfs_multiple_uris gvfs-monitor-dir
+complete -o nospace -F __gvfs_multiple_uris gvfs-monitor-file
+complete -o nospace -F __gvfs_multiple_uris gvfs-move
+complete -o nospace -F __gvfs_multiple_uris gvfs-open
+complete -o nospace -F __gvfs_multiple_uris gvfs-rm
+complete -o nospace -F __gvfs_multiple_uris gvfs-save
+complete -o nospace -F __gvfs_multiple_uris gvfs-trash


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]