Code

Ticket #10752: django_bash_completion.diff

File django_bash_completion.diff, 9.5 KB (added by arthurk, 5 years ago)
Line 
1diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
2index f1192fe..9bb3303 100644
3--- a/django/core/management/__init__.py
4+++ b/django/core/management/__init__.py
5@@ -261,7 +261,82 @@ class ManagementUtility(object):
6                 (subcommand, self.prog_name))
7             sys.exit(1)
8         return klass
9-
10+   
11+    def autocomplete(self, parser):
12+        """
13+        Outputs a list of bash completion suggestions
14+        """
15+        if os.environ.has_key('DJANGO_AUTO_COMPLETE'):
16+            # map bash variables
17+            cwords = os.environ['COMP_WORDS'].split()
18+            cline = os.environ['COMP_LINE']
19+            cpoint = int(os.environ['COMP_POINT'])
20+            cword = int(os.environ['COMP_CWORD'])
21+
22+            # get all available subcommands & add special cases
23+            completions = get_commands().keys()
24+            completions += ['help',]
25+
26+            # subcommand options completion
27+            if cword >= 2 and cwords[1] in completions:
28+                # 'help' is a special case since it's not a option in
29+                # optparse and handled manually
30+                if cwords[1] == 'help':
31+                    sys.exit(1)
32+
33+                subcommand = self.fetch_command(cwords[1])
34+                subcmd_options = ['--help',]
35+                option_list = []
36+
37+                # runfcgi uses a python dict for its options. add the commands
38+                # manually.
39+                if cwords[1] == 'runfcgi':
40+                    from django.core.servers.fastcgi import FASTCGI_OPTIONS
41+                    subcmd_options = map(lambda x: x+'=', FASTCGI_OPTIONS)
42+                else:
43+                    option_list = subcommand.option_list
44+
45+                # get all options for the subcommand
46+                for opt in option_list:
47+                    opt_label = str(opt)
48+                    # some options are specified in the short/long format
49+                    # e.g. '-e/--exclude'. In this case only the long format
50+                    # is included
51+                    if '/' in opt_label:
52+                        opt_label = opt_label.split('/')[1]
53+
54+                    # append equal sign for options which require arguments
55+                    if opt.nargs:
56+                        opt_label += '='
57+                    subcmd_options.append(opt_label)
58+
59+                # get previously specified options
60+                prev_options = cwords[2:cword]
61+
62+                # remove already specified options
63+                for prev_option in prev_options:
64+                    # check only the key, not the value
65+                    if '=' in prev_option:
66+                        prev_option = prev_option.split('=')[0]+'='
67+
68+                    if prev_option in subcmd_options:
69+                        subcmd_options.remove(prev_option)
70+
71+                # set the remaining options as completion suggestions
72+                completions = subcmd_options
73+            try:
74+                prefix = cwords[cword]
75+            except IndexError:
76+                prefix = None
77+           
78+            # filter completions based on prefix
79+            if prefix:
80+                completions = filter(lambda x: x.startswith(prefix),
81+                                     completions)
82+            # output completions
83+            print ' '.join(completions)
84+            sys.exit(1)
85+   
86     def execute(self):
87         """
88         Given the command-line arguments, this figures out which subcommand is
89@@ -273,6 +348,7 @@ class ManagementUtility(object):
90         parser = LaxOptionParser(usage="%prog subcommand [options] [args]",
91                                  version=get_version(),
92                                  option_list=BaseCommand.option_list)
93+        self.autocomplete(parser)
94         try:
95             options, args = parser.parse_args(self.argv)
96             handle_default_options(options)
97diff --git a/extras/django_bash_completion b/extras/django_bash_completion
98index b805af9..940b470 100755
99--- a/extras/django_bash_completion
100+++ b/extras/django_bash_completion
101@@ -31,136 +31,11 @@
102 #
103 # To uninstall, just remove the line from your .bash_profile and .bashrc.
104 
105-# Enable extended pattern matching operators.
106-shopt -s extglob
107-
108 _django_completion()
109 {
110-    local cur prev opts actions action_shell_opts action_runfcgi_opts
111-    COMPREPLY=()
112-    cur="${COMP_WORDS[COMP_CWORD]}"
113-    prev="${COMP_WORDS[COMP_CWORD-1]}"
114-
115-    # Standalone options
116-    opts="--help --settings --pythonpath --noinput --noreload --format --indent --verbosity --adminmedia --version --locale --domain"
117-    # Actions
118-    actions="createcachetable createsuperuser compilemessages \
119-             dbshell diffsettings dumpdata flush inspectdb loaddata \
120-             makemessages reset runfcgi runserver shell sql sqlall sqlclear \
121-             sqlcustom sqlflush sqlindexes sqlreset sqlsequencereset startapp \
122-             startproject syncdb test validate"
123-    # Action's options
124-    action_shell_opts="--plain"
125-    action_runfcgi_opts="host port socket method maxspare minspare maxchildren daemonize pidfile workdir"
126-
127-    if [[ # django-admin.py, django-admin, ./manage, manage.py
128-          ( ${COMP_CWORD} -eq 1 &&
129-            ( ${COMP_WORDS[0]} == django-admin.py ||
130-              ${COMP_WORDS[0]} == django-admin ||
131-              ${COMP_WORDS[0]} == ./manage.py ||
132-              ${COMP_WORDS[0]} == manage.py ) )
133-          ||
134-          # python manage.py, /some/path/python manage.py (if manage.py exists)
135-          ( ${COMP_CWORD} -eq 2 &&
136-            ( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
137-            ( $( basename -- ${COMP_WORDS[1]} ) == manage.py) &&
138-            ( -r ${COMP_WORDS[1]} ) )
139-          ||
140-          ( ${COMP_CWORD} -eq 2 &&
141-            ( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
142-            ( $( basename -- ${COMP_WORDS[1]} ) == django-admin.py) &&
143-            ( -r ${COMP_WORDS[1]} ) )
144-          ||
145-          ( ${COMP_CWORD} -eq 2 &&
146-            ( $( basename -- ${COMP_WORDS[0]} ) == python?([1-9]\.[0-9]) ) &&
147-            ( $( basename -- ${COMP_WORDS[1]} ) == django-admin) &&
148-            ( -r ${COMP_WORDS[1]} ) ) ]] ; then
149-
150-        case ${cur} in
151-            -*)
152-                COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
153-                action=$COMPREPLY
154-                return 0
155-                ;;
156-            *)
157-                COMPREPLY=( $(compgen -W "${actions}" -- ${cur}) )
158-                action=$COMPREPLY
159-                return 0
160-                ;;
161-        esac
162-    else
163-        case ${prev} in
164-            dumpdata|reset| \
165-            sql|sqlall|sqlclear|sqlcustom|sqlindexes| \
166-            sqlreset|sqlsequencereset|test)
167-                # App completion
168-                settings=""
169-                # If settings.py in the PWD, use that
170-                if [ -e settings.py ] ; then
171-                    settings="$PWD/settings.py"
172-                else
173-                    # Use the ENV variable if it is set
174-                    if [ $DJANGO_SETTINGS_MODULE ] ; then
175-                        settings=$DJANGO_SETTINGS_MODULE
176-                    fi
177-                fi
178-                # Couldn't find settings so return nothing
179-                if [ -z $settings ] ; then
180-                    COMPREPLY=()
181-                # Otherwise inspect settings.py file
182-                else
183-                    apps=`sed -n "/INSTALLED_APPS = (/,/)/p" $settings | \
184-                          grep -v "django.contrib" |
185-                          sed -n "s/^[ ]*'\(.*\.\)*\(.*\)'.*$/\2 /pg" | \
186-                          tr -d "\n"`
187-                    COMPREPLY=( $(compgen -W "${apps}" -- ${cur}) )
188-                fi
189-                return 0
190-                ;;
191-
192-            createcachetable|cleanup|compilemessages|dbshell| \
193-            diffsettings|inspectdb|makemessages| \
194-            runserver|startapp|startproject|syncdb| \
195-            validate)
196-                COMPREPLY=()
197-                return 0
198-                ;;
199-            shell)
200-                COMPREPLY=( $(compgen -W "$action_shell_opts" -- ${cur}) )
201-                return 0
202-                ;;
203-            runfcgi)
204-                COMPREPLY=( $(compgen -W "$action_runfcgi_opts" -- ${cur}) )
205-                return 0
206-                ;;
207-            host*|port*|socket*|method*|maxspare*|minspare*|maxchildren*|daemonize*|pidfile*|workdir*)
208-                if [ "$action"  == "runfcgi" ] ; then
209-                    COMPREPLY=( $(compgen -W "$action_runfcgi_opts" -- ${cur}) )
210-                    return 0
211-                fi
212-                return 0
213-                ;;
214-            *)
215-                #COMPREPLY=( $(compgen -W "auth core" -- ${cur}) )
216-                COMPREPLY=()
217-                return 0
218-                ;;
219-        esac
220-    fi
221+    COMPREPLY=( $( \
222+       COMP_LINE=$COMP_LINE  COMP_POINT=$COMP_POINT \
223+       COMP_WORDS="${COMP_WORDS[*]}"  COMP_CWORD=$COMP_CWORD \
224+       DJANGO_AUTO_COMPLETE=1 $1 ) )
225 }
226-
227-complete -F _django_completion django-admin.py manage.py django-admin
228-
229-# Support for multiple interpreters.
230-unset pythons
231-if command -v whereis &>/dev/null; then
232-    python_interpreters=$(whereis python | cut -d " " -f 2-)
233-    for python in $python_interpreters; do
234-        pythons="${pythons} $(basename -- $python)"
235-    done
236-    pythons=$(echo $pythons | tr " " "\n" | sort -u | tr "\n" " ")
237-else
238-    pythons=python   
239-fi
240-
241-complete -F _django_completion -o default $pythons
242+complete -F _django_completion django-admin.py manage.py