diff --git a/docs/en/api-guides/build-system.rst b/docs/en/api-guides/build-system.rst
index 4470ca2e02..78f4421543 100644
--- a/docs/en/api-guides/build-system.rst
+++ b/docs/en/api-guides/build-system.rst
@@ -89,6 +89,12 @@ Multiple ``idf.py`` commands can be combined into one. For example, ``idf.py -p
For commands that are not known to ``idf.py`` an attempt to execute them as a build system target will be made.
+The command ``idf.py`` supports `shell autocompletion `_ for bash, zsh and fish shells.
+In order to make `shell autocompletion `_ supported, please make sure you have at least Python 3.5 and `click `_ 7.1 or newer (:ref:`see also `).
+To enable autocompletion for ``idf.py`` use the ``export`` command (:ref:`see this `).
+Autocompletion is initiated by pressing the TAB key.
+Type "idf.py -" and press the TAB key to autocomplete options. The autocomplete support for PowerShell is planned in the future.
+
.. note:: The environment variables ``ESPPORT`` and ``ESPBAUD`` can be used to set default values for the ``-p`` and ``-b`` options, respectively. Providing these options on the command line overrides the default.
.. _idf.py-size:
@@ -124,7 +130,6 @@ Start a new project
Use the command ``idf.py create-project`` for starting a new project. Execute ``idf.py create-project --help`` for more information.
-
Example:
.. code-block:: bash
@@ -320,7 +325,7 @@ Renaming ``main`` component
The build system provides special treatment to the ``main`` component. It is a component that gets automatically added to the build provided
that it is in the expected location, PROJECT_DIR/main. All other components in the build are also added as its dependencies,
saving the user from hunting down dependencies and providing a build that works right out of the box. Renaming the ``main`` component
-causes the loss of these behind-the-scences heavy lifting, requiring the user to specify the location of the newly renamed component
+causes the loss of these behind-the-scenes heavy lifting, requiring the user to specify the location of the newly renamed component
and manually specifying its dependencies. Specifically, the steps to renaming ``main`` are as follows:
1. Rename ``main`` directory.
@@ -1054,7 +1059,7 @@ To select the target before building the project, use ``idf.py set-target > {$IDF_PATH}/debug.out')
+ child.send("idf.py \t\t")
+ result = child.expect(["all.*app.*app-flash.*bootloader.*", pexpect.EOF, pexpect.TIMEOUT], timeout=5)
+ self.assertEqual(result, 0, "Autocompletion for idf.py failed in fish!")
+ result = child.expect(["bootloader-flash.*build-system-targets.*clean.*", pexpect.EOF, pexpect.TIMEOUT],
+ timeout=5)
+ self.assertEqual(result, 0, "Autocompletion for idf.py failed in fish!")
+
+ def test_bash(self):
+ os.environ["TERM"] = "xterm-256color"
+ child = pexpect.spawn("bash -i")
+ child.logfile = open(os.environ["IDF_PATH"] + "/bash.out", "wb")
+ child.sendline(
+ '. ${IDF_PATH}/export.sh >> ${IDF_PATH}/debug.out')
+ child.send("idf.py \t\t")
+ result = child.expect(
+ ["all.*app.*app-flash.*bootloader.*bootloader-flash.*build-system-targets.*clean.*", pexpect.EOF,
+ pexpect.TIMEOUT], timeout=5)
+ self.assertEqual(result, 0, "Autocompletion for idf.py failed in bash!")
+
+ def test_zsh(self):
+ child = pexpect.spawn("zsh -i")
+ child.logfile = open(os.environ["IDF_PATH"] + "/zsh.out", "wb")
+ child.sendline(
+ '. ${IDF_PATH}/export.sh >> ${IDF_PATH}/debug.out ')
+ child.send("idf.py \t")
+ result = child.expect(
+ ["all.*app.*app-flash.*bootloader.*bootloader-flash.*build-system-targets.*clean.*", pexpect.EOF,
+ pexpect.TIMEOUT], timeout=5)
+ self.assertEqual(result, 0, "Autocompletion for idf.py failed in zsh!")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tools/idf.py b/tools/idf.py
index 74f06b0e63..a581fe6268 100755
--- a/tools/idf.py
+++ b/tools/idf.py
@@ -38,7 +38,7 @@ from importlib import import_module
from pkgutil import iter_modules
# pyc files remain in the filesystem when switching between branches which might raise errors for incompatible
-# idf.py extentions. Therefore, pyc file generation is turned off:
+# idf.py extensions. Therefore, pyc file generation is turned off:
sys.dont_write_bytecode = True
from idf_py_actions.errors import FatalError # noqa: E402
@@ -53,7 +53,7 @@ os.environ["PYTHON"] = sys.executable
# Name of the program, normally 'idf.py'.
# Can be overridden from idf.bat using IDF_PY_PROGRAM_NAME
-PROG = os.getenv("IDF_PY_PROGRAM_NAME", sys.argv[0])
+PROG = os.getenv("IDF_PY_PROGRAM_NAME", "idf.py")
def check_environment():
@@ -184,7 +184,7 @@ def init_cli(verbose_output=None):
return ("Deprecated! " + text) if self.deprecated else text
def check_deprecation(ctx):
- """Prints deprectation warnings for arguments in given context"""
+ """Prints deprecation warnings for arguments in given context"""
for option in ctx.command.params:
default = () if option.multiple else option.default
if isinstance(option, Option) and option.deprecated and ctx.params[option.name] != default:
@@ -533,7 +533,7 @@ def init_cli(verbose_output=None):
print(
"WARNING: Command%s found in the list of commands more than once. " %
("s %s are" % dupes if len(dupplicated_tasks) > 1 else " %s is" % dupes) +
- "Only first occurence will be executed.")
+ "Only first occurrence will be executed.")
for task in tasks:
# Show help and exit if help is in the list of commands
@@ -640,11 +640,11 @@ def init_cli(verbose_output=None):
"ignore_unknown_options": True
},
)
- @click.option("-C", "--project-dir", default=os.getcwd())
+ @click.option("-C", "--project-dir", default=os.getcwd(), type=click.Path())
def parse_project_dir(project_dir):
return realpath(project_dir)
-
- project_dir = parse_project_dir(standalone_mode=False)
+ # Set `complete_var` to not existing environment variable name to prevent early cmd completion
+ project_dir = parse_project_dir(standalone_mode=False, complete_var="_IDF.PY_COMPLETE_NOT_EXISTING")
all_actions = {}
# Load extensions from components dir
@@ -660,7 +660,7 @@ def init_cli(verbose_output=None):
extensions = {}
for directory in extension_dirs:
if directory and not os.path.exists(directory):
- print('WARNING: Directroy with idf.py extensions doesn\'t exist:\n %s' % directory)
+ print('WARNING: Directory with idf.py extensions doesn\'t exist:\n %s' % directory)
continue
sys.path.append(directory)
@@ -709,7 +709,8 @@ def init_cli(verbose_output=None):
def main():
checks_output = check_environment()
cli = init_cli(verbose_output=checks_output)
- cli(sys.argv[1:], prog_name=PROG)
+ # the argument `prog_name` must contain name of the file - not the absolute path to it!
+ cli(sys.argv[1:], prog_name=PROG, complete_var="_IDF.PY_COMPLETE")
def _valid_unicode_config():
diff --git a/tools/idf_py_actions/serial_ext.py b/tools/idf_py_actions/serial_ext.py
index 60c4c017c4..f947f2a5ef 100644
--- a/tools/idf_py_actions/serial_ext.py
+++ b/tools/idf_py_actions/serial_ext.py
@@ -172,13 +172,13 @@ def action_extensions(base_actions, project_path):
port, {
"names": ["--print-filter", "--print_filter"],
"help":
- ("Filter monitor output.\n"
+ ("Filter monitor output. "
"Restrictions on what to print can be specified as a series of : items "
"where is the tag string and is a character from the set "
"{N, E, W, I, D, V, *} referring to a level. "
'For example, "tag1:W" matches and prints only the outputs written with '
'ESP_LOGW("tag1", ...) or at lower verbosity level, i.e. ESP_LOGE("tag1", ...). '
- 'Not specifying a or using "*" defaults to Verbose level.\n'
+ 'Not specifying a or using "*" defaults to Verbose level. '
'Please see the IDF Monitor section of the ESP-IDF documentation '
'for a more detailed description and further examples.'),
"default":
@@ -187,7 +187,7 @@ def action_extensions(base_actions, project_path):
"names": ["--monitor-baud", "-B"],
"type":
click.INT,
- "help": ("Baud rate for monitor.\n"
+ "help": ("Baud rate for monitor. "
"If this option is not provided IDF_MONITOR_BAUD and MONITORBAUD "
"environment variables and project_description.json in build directory "
"(generated by CMake from project's sdkconfig) "
@@ -195,7 +195,7 @@ def action_extensions(base_actions, project_path):
}, {
"names": ["--encrypted", "-E"],
"is_flag": True,
- "help": ("Enable encrypted flash targets.\n"
+ "help": ("Enable encrypted flash targets. "
"IDF Monitor will invoke encrypted-flash and encrypted-app-flash targets "
"if this option is set. This option is set by default if IDF Monitor was invoked "
"together with encrypted-flash or encrypted-app-flash target."),