/usr/share/doc/python-cement-doc/html/_sources/examples/bash_auto_completion.txt is in python-cement-doc 2.10.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | BASH Auto Completion
--------------------
Auto Completion, or "TAB Completion" is a very common and familiar feature in
BASH (and other modern shells). It is possible to auto-complete Cement apps
(using BASH for this example) including sub-levels for nested controllers.
The difficulty is that this auto-completion code must be maintained outside of
Cement and your application code, and be implemented in the shell environment
generally by use of an "RC" file, or similar means. This then must be updated
anytime your application is modified (or atleast any time the
sub-commands/controllers/arguments are modified).
Note that, in the future, we would love to include some form of
"BASH RC Generator" that will do this for you, however in the meantime the
following is a working example that can be used as a model for adding BASH
auto-completion to your app.
Update: As of Cement 2.7.x, the
:ref:`Argcomplete Framework Extension<cement.ext.ext_argcomplete>` can be
used as an alternative to this example. Both are viable options though
this route is much more manual, and the Argcomplete route might not fit your
needs.
Example Cement App
^^^^^^^^^^^^^^^^^^
The following application code implements three levels of namespaces, or
sub-commands, that are implemented via nested-controllers.
.. code-block:: python
from cement.core.foundation import CementApp
from cement.core.controller import CementBaseController, expose
class BaseController(CementBaseController):
class Meta:
label = 'base'
@expose()
def base_cmd1(self):
print("Inside BaseController.base_cmd1()")
class EmbeddedController(CementBaseController):
class Meta:
label = 'embedded'
description = "embedded with base namespace"
stacked_on = 'base'
stacked_type = 'embedded'
@expose()
def base_cmd2(self):
print("Inside EmbeddedController.base_cmd2()")
@expose()
def embedded_cmd3(self):
print("Inside EmbeddedController.embedded_cmd3()")
class SecondLevelController(CementBaseController):
class Meta:
label = 'second'
description = ''
stacked_on = 'base'
stacked_type = 'nested'
@expose()
def second_cmd4(self):
print("Inside SecondLevelController.second_cmd4()")
@expose()
def second_cmd5(self):
print("Inside SecondLevelController.second_cmd5()")
class ThirdLevelController(CementBaseController):
class Meta:
label = 'third'
description = ''
stacked_on = 'second'
stacked_type = 'nested'
@expose()
def third_cmd6(self):
print("Inside ThirdLevelController.third_cmd6()")
@expose()
def third_cmd7(self):
print("Inside ThirdLevelController.third_cmd7()")
class MyApp(CementApp):
class Meta:
label = 'myapp'
handlers = [
BaseController,
EmbeddedController,
SecondLevelController,
ThirdLevelController,
]
def main():
with MyApp() as app:
app.run()
if __name__ == '__main__':
main()
This looks like:
.. code-block:: bash
$ python myapp.py --help
usage: myapp.py (sub-commands ...) [options ...] {arguments ...}
Base Controller
commands:
base-cmd1
base-cmd2
embedded-cmd3
second
$ python myapp.py second --help
commands:
second-cmd4
second-cmd5
third
$ python myapp.py second third --help
commands:
third-cmd6
third-cmd7
For demonstration purposes, we are going to create a BASH alias here so that
we can call our `myapp` command name as if we would in production (not
development):
.. code-block:: bash
$ alias myapp="python ./myapp.py"
In the "real world" your actual `myapp` command would be setup/installed by
something like this in `setup.py`:
.. code-block:: python
entry_points="""
[console_scripts]
myapp = myapp.cli.main:main
""",
Or by simply copying `myapp.py` to `/usr/bin/myapp`, or similar.
Example BASH RC
^^^^^^^^^^^^^^^
The following is a BASH RC script that will setup auto-completiong for the
above Cement App `myapp`. You **will** need to modify this, it is just an
example and is not intended to be copy and pasted:
.. code-block:: bash
alias myapp="python ./myapp.py"
_myapp_complete()
{
local cur prev BASE_LEVEL
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
# SETUP THE BASE LEVEL (everything after "myapp")
if [ $COMP_CWORD -eq 1 ]; then
COMPREPLY=( $(compgen \
-W "base-cmd1 base-cmd2 embedded-cmd3 second" \
-- $cur) )
# SETUP THE SECOND LEVEL (EVERYTHING AFTER "myapp second")
elif [ $COMP_CWORD -eq 2 ]; then
case "$prev" in
# HANDLE EVERYTHING AFTER THE SECOND LEVEL NAMESPACE
"second")
COMPREPLY=( $(compgen \
-W "second-cmd4 second-cmd5 third" \
-- $cur) )
;;
# IF YOU HAD ANOTHER CONTROLLER, YOU'D HANDLE THAT HERE
"some-other-controller")
COMPREPLY=( $(compgen \
-W "some-other-sub-command" \
-- $cur) )
;;
# EVERYTHING ELSE
*)
;;
esac
# SETUP THE THIRD LEVEL (EVERYTHING AFTER "myapp second third")
elif [ $COMP_CWORD -eq 3 ]; then
case "$prev" in
# HANDLE EVERYTHING AFTER THE THIRD LEVEL NAMESPACE
"third")
COMPREPLY=( $(compgen \
-W "third-cmd6 third-cmd7" \
-- $cur) )
;;
# IF YOU HAD ANOTHER CONTROLLER, YOU'D HANDLE THAT HERE
"some-other-controller")
COMPREPLY=( $(compgen \
-W "some-other-sub-command" \
-- $cur) )
;;
*)
;;
esac
fi
return 0
} &&
complete -F _myapp_complete myapp
You would then "source" the RC file:
.. code-block:: bash
$ source myapp.rc
In the "real world" you would probably put this in a system wide location
such at ``/etc/profile.d`` or similar (in a production deployment).
Finally, this is what it looks like:
.. code-block:: bash
# show all sub-commands at the base level
$ myapp [tab] [tab]
base-cmd1 base-cmd2 embedded-cmd3 second
# auto-complete a partial matching sub-command
$ myapp base [tab]
$ myapp base-cmd [tab] [tab]
base-cmd1 base-cmd2
# auto-complete a full matching sub-command
$ myapp sec [tab]
$ myapp second
# show all sub-commands under the second namespace
$ myapp second [tab] [tab]
second-cmd4 second-cmd5 third
# show all sub-commands under the third namespace
$ myapp second third [tab] [tab]
third-cmd6 third-cmd7
|