Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #10752. Added more advanced bash completion. Thanks, Arthur Koz…

…iel.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@11526 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 677ddcbb04b85541f7b39b95541f5b46817ea510 1 parent a53601c
Joseph Kocherhans authored September 11, 2009
1  AUTHORS
@@ -241,6 +241,7 @@ answer newbie questions, and generally made Django that much better:
241 241
     Igor Kolar <ike@email.si>
242 242
     Gasper Koren
243 243
     Martin Kosír <martin@martinkosir.net>
  244
+    Arthur Koziel <http://arthurkoziel.com>
244 245
     Meir Kriheli <http://mksoft.co.il/>
245 246
     Bruce Kroeze <http://coderseye.com/>
246 247
     krzysiek.pawlik@silvermedia.pl
77  django/core/management/__init__.py
@@ -261,6 +261,82 @@ def fetch_command(self, subcommand):
261 261
             sys.exit(1)
262 262
         return klass
263 263
 
  264
+    def autocomplete(self):
  265
+        """
  266
+        Output completion suggestions for BASH.
  267
+
  268
+        The output of this function is passed to BASH's `COMREPLY` variable and
  269
+        treated as completion suggestions. `COMREPLY` expects a space
  270
+        separated string as the result.
  271
+
  272
+        The `COMP_WORDS` and `COMP_CWORD` BASH environment variables are used
  273
+        to get information about the cli input. Please refer to the BASH
  274
+        man-page for more information about this variables.
  275
+
  276
+        Subcommand options are saved as pairs. A pair consists of
  277
+        the long option string (e.g. '--exclude') and a boolean
  278
+        value indicating if the option requires arguments. When printing to
  279
+        stdout, a equal sign is appended to options which require arguments.
  280
+
  281
+        Note: If debugging this function, it is recommended to write the debug
  282
+        output in a separate file. Otherwise the debug output will be treated
  283
+        and formatted as potential completion suggestions.
  284
+        """
  285
+        # Don't complete if user hasn't sourced bash_completion file.
  286
+        if not os.environ.has_key('DJANGO_AUTO_COMPLETE'):
  287
+            return
  288
+
  289
+        cwords = os.environ['COMP_WORDS'].split()[1:]
  290
+        cword = int(os.environ['COMP_CWORD'])
  291
+
  292
+        try:
  293
+            curr = cwords[cword-1]
  294
+        except IndexError:
  295
+            curr = ''
  296
+
  297
+        subcommands = get_commands().keys() + ['help']
  298
+        options = [('--help', None)]
  299
+
  300
+        # subcommand
  301
+        if cword == 1:
  302
+            print ' '.join(filter(lambda x: x.startswith(curr), subcommands))
  303
+        # subcommand options
  304
+        # special case: the 'help' subcommand has no options
  305
+        elif cwords[0] in subcommands and cwords[0] != 'help':
  306
+            subcommand_cls = self.fetch_command(cwords[0])
  307
+            # special case: 'runfcgi' stores additional options as
  308
+            # 'key=value' pairs
  309
+            if cwords[0] == 'runfcgi':
  310
+                from django.core.servers.fastcgi import FASTCGI_OPTIONS
  311
+                options += [(k, 1) for k in FASTCGI_OPTIONS]
  312
+            # special case: add the names of installed apps to options
  313
+            elif cwords[0] in ('dumpdata', 'reset', 'sql', 'sqlall',
  314
+                               'sqlclear', 'sqlcustom', 'sqlindexes',
  315
+                               'sqlreset', 'sqlsequencereset', 'test'):
  316
+                try:
  317
+                    from django.conf import settings
  318
+                    # Get the last part of the dotted path as the app name.
  319
+                    options += [(a.split('.')[-1], 0) for a in settings.INSTALLED_APPS]
  320
+                except ImportError:
  321
+                    # Fail silently if DJANGO_SETTINGS_MODULE isn't set. The
  322
+                    # user will find out once they execute the command.
  323
+                    pass
  324
+            options += [(s_opt.get_opt_string(), s_opt.nargs) for s_opt in
  325
+                        subcommand_cls.option_list]
  326
+            # filter out previously specified options from available options
  327
+            prev_opts = [x.split('=')[0] for x in cwords[1:cword-1]]
  328
+            options = filter(lambda (x, v): x not in prev_opts, options)
  329
+
  330
+            # filter options by current input
  331
+            options = [(k, v) for k, v in options if k.startswith(curr)]
  332
+            for option in options:
  333
+                opt_label = option[0]
  334
+                # append '=' to options which require args
  335
+                if option[1]:
  336
+                    opt_label += '='
  337
+                print opt_label
  338
+        sys.exit(1)
  339
+
264 340
     def execute(self):
265 341
         """
266 342
         Given the command-line arguments, this figures out which subcommand is
@@ -272,6 +348,7 @@ def execute(self):
272 348
         parser = LaxOptionParser(usage="%prog subcommand [options] [args]",
273 349
                                  version=get_version(),
274 350
                                  option_list=BaseCommand.option_list)
  351
+        self.autocomplete()
275 352
         try:
276 353
             options, args = parser.parse_args(self.argv)
277 354
             handle_default_options(options)
134  extras/django_bash_completion
@@ -31,136 +31,10 @@
31 31
 #
32 32
 # To uninstall, just remove the line from your .bash_profile and .bashrc.
33 33
 
34  
-# Enable extended pattern matching operators.
35  
-shopt -s extglob
36  
-
37 34
 _django_completion()
38 35
 {
39  
-    local cur prev opts actions action_shell_opts action_runfcgi_opts
40  
-    COMPREPLY=()
41  
-    cur="${COMP_WORDS[COMP_CWORD]}"
42  
-    prev="${COMP_WORDS[COMP_CWORD-1]}"
43  
-
44  
-    # Standalone options
45  
-    opts="--help --settings --pythonpath --noinput --noreload --format --indent --verbosity --adminmedia --version --locale --domain"
46  
-    # Actions
47  
-    actions="createcachetable createsuperuser compilemessages \
48  
-             dbshell diffsettings dumpdata flush inspectdb loaddata \
49  
-             makemessages reset runfcgi runserver shell sql sqlall sqlclear \
50  
-             sqlcustom sqlflush sqlindexes sqlreset sqlsequencereset startapp \
51  
-             startproject syncdb test validate"
52  
-    # Action's options
53  
-    action_shell_opts="--plain"
54  
-    action_runfcgi_opts="host port socket method maxspare minspare maxchildren daemonize pidfile workdir"
55  
-
56  
-    if [[ # django-admin.py, django-admin, ./manage, manage.py
57  
-          ( ${COMP_CWORD} -eq 1 &&
58  
-            ( ${COMP_WORDS[0]} == django-admin.py ||
59  
-              ${COMP_WORDS[0]} == django-admin ||
60  
-              ${COMP_WORDS[0]} == ./manage.py ||
61  
-              ${COMP_WORDS[0]} == manage.py ) )
62  
-          ||
63  
-          # python manage.py, /some/path/python manage.py (if manage.py exists)
64  
-          ( ${COMP_CWORD} -eq 2 &&
65  
-            ( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
66  
-            ( $( basename -- ${COMP_WORDS[1]} ) == manage.py) &&
67  
-            ( -r ${COMP_WORDS[1]} ) ) 
68  
-          ||
69  
-          ( ${COMP_CWORD} -eq 2 &&
70  
-            ( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
71  
-            ( $( basename -- ${COMP_WORDS[1]} ) == django-admin.py) &&
72  
-            ( -r ${COMP_WORDS[1]} ) ) 
73  
-          ||
74  
-          ( ${COMP_CWORD} -eq 2 &&
75  
-            ( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
76  
-            ( $( basename -- ${COMP_WORDS[1]} ) == django-admin) &&
77  
-            ( -r ${COMP_WORDS[1]} ) ) ]] ; then
78  
-
79  
-        case ${cur} in
80  
-            -*)
81  
-                COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
82  
-                action=$COMPREPLY
83  
-                return 0
84  
-                ;;
85  
-            *)
86  
-                COMPREPLY=( $(compgen -W "${actions}" -- ${cur}) )
87  
-                action=$COMPREPLY
88  
-                return 0
89  
-                ;;
90  
-        esac
91  
-    else
92  
-        case ${prev} in
93  
-            dumpdata|reset| \
94  
-            sql|sqlall|sqlclear|sqlcustom|sqlindexes| \
95  
-            sqlreset|sqlsequencereset|test)
96  
-                # App completion
97  
-                settings=""
98  
-                # If settings.py in the PWD, use that
99  
-                if [ -e settings.py ] ; then
100  
-                    settings="$PWD/settings.py"
101  
-                else
102  
-                    # Use the ENV variable if it is set
103  
-                    if [ $DJANGO_SETTINGS_MODULE ] ; then
104  
-                        settings=$DJANGO_SETTINGS_MODULE
105  
-                    fi
106  
-                fi
107  
-                # Couldn't find settings so return nothing
108  
-                if [ -z $settings ] ; then
109  
-                    COMPREPLY=()
110  
-                # Otherwise inspect settings.py file
111  
-                else
112  
-                    apps=`sed -n "/INSTALLED_APPS = (/,/)/p" $settings | \
113  
-                          grep -v "django.contrib" | 
114  
-                          sed -n "s/^[ ]*'\(.*\.\)*\(.*\)'.*$/\2 /pg" | \
115  
-                          tr -d "\n"`
116  
-                    COMPREPLY=( $(compgen -W "${apps}" -- ${cur}) )
117  
-                fi
118  
-                return 0
119  
-                ;;
120  
-
121  
-            createcachetable|cleanup|compilemessages|dbshell| \
122  
-            diffsettings|inspectdb|makemessages| \
123  
-            runserver|startapp|startproject|syncdb| \
124  
-            validate)
125  
-                COMPREPLY=()
126  
-                return 0
127  
-                ;;
128  
-            shell)
129  
-                COMPREPLY=( $(compgen -W "$action_shell_opts" -- ${cur}) )
130  
-                return 0
131  
-                ;;
132  
-            runfcgi)
133  
-                COMPREPLY=( $(compgen -W "$action_runfcgi_opts" -- ${cur}) )
134  
-                return 0
135  
-                ;;
136  
-            host*|port*|socket*|method*|maxspare*|minspare*|maxchildren*|daemonize*|pidfile*|workdir*)
137  
-                if [ "$action"  == "runfcgi" ] ; then
138  
-                    COMPREPLY=( $(compgen -W "$action_runfcgi_opts" -- ${cur}) )
139  
-                    return 0
140  
-                fi
141  
-                return 0
142  
-                ;;
143  
-            *)
144  
-                #COMPREPLY=( $(compgen -W "auth core" -- ${cur}) )
145  
-                COMPREPLY=()
146  
-                return 0
147  
-                ;;
148  
-        esac
149  
-    fi
  36
+    COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \
  37
+                   COMP_CWORD=$COMP_CWORD \
  38
+	               DJANGO_AUTO_COMPLETE=1 $1 ) )
150 39
 }
151  
-
152  
-complete -F _django_completion django-admin.py manage.py django-admin
153  
-
154  
-# Support for multiple interpreters.
155  
-unset pythons
156  
-if command -v whereis &>/dev/null; then
157  
-    python_interpreters=$(whereis python | cut -d " " -f 2-) 
158  
-    for python in $python_interpreters; do
159  
-        pythons="${pythons} $(basename -- $python)"
160  
-    done
161  
-    pythons=$(echo $pythons | tr " " "\n" | sort -u | tr "\n" " ")
162  
-else
163  
-    pythons=python    
164  
-fi
165  
-
166  
-complete -F _django_completion -o default $pythons
  40
+complete -F _django_completion -o default django-admin.py manage.py

0 notes on commit 677ddcb

Please sign in to comment.
Something went wrong with that request. Please try again.