From 96e627d9a1ca196787cf910ca85e199bd1f5da16 Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Fri, 6 Dec 2024 13:33:07 +0100 Subject: [PATCH 1/2] ci(autocomplete): add test for file autocompletion Merge Request !31081 introduced support for file autocompletion. This adds a basic test for README files autocompletion in the root directory of the esp-idf repository. Signed-off-by: Frantisek Hrbata --- .../ci/test_autocomplete/test_autocomplete.py | 63 +++++++++++++++---- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/tools/ci/test_autocomplete/test_autocomplete.py b/tools/ci/test_autocomplete/test_autocomplete.py index 49fe24be62..96e12e6b9a 100755 --- a/tools/ci/test_autocomplete/test_autocomplete.py +++ b/tools/ci/test_autocomplete/test_autocomplete.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import collections import os @@ -7,13 +7,49 @@ import unittest import pexpect -Test = collections.namedtuple('Test', ['name', 'term', 'pattern', 'ext']) +Test = collections.namedtuple('Test', ['name', 'shell', 'term', 'prefix', 'pattern', 'ext']) +IDF_PATH = os.environ['IDF_PATH'] -TESTS = (Test('fish', 'vt100', 'all.*app.*app-flash.*bootloader.*', 'fish'), - Test('bash', 'xterm-256color', 'all.*app.*app-flash.*bootloader.*bootloader-flash.*build-system-targets.*clean.*', 'sh'), - Test('zsh', '', 'all.*app.*app-flash.*bootloader.*bootloader-flash.*build-system-targets.*clean.*', 'sh')) - +TESTS = ( + Test('base', + 'fish', + 'vt100', + '', + 'all.*app.*app-flash.*bootloader.*', + 'fish'), + Test('base', + 'bash', + 'xterm-256color', + '', + 'all.*app.*app-flash.*bootloader.*bootloader-flash.*build-system-targets.*clean.*', + 'sh'), + Test('base', + 'zsh', + '', + '', + 'all.*app.*app-flash.*bootloader.*bootloader-flash.*build-system-targets.*clean.*', + 'sh'), + # Tests for file autocompletion + Test('file', + 'fish', + 'vt100', + f'@{IDF_PATH}/README', + '.*README.*md.*', + 'fish'), + Test('file', + 'bash', + 'xterm-256color', + f'@{IDF_PATH}/README', + '.*README.*md.*', + 'sh'), + Test('file', + 'zsh', + '', + f'@{IDF_PATH}/README', + '.*README.*md.*', + 'sh') +) # Additional positional arguments for all child.expect() calls are constant so we can rely on the order and print message # about which pattern was matched @@ -34,19 +70,22 @@ def get_fail_msg(pproc: pexpect.spawn, msg: str, index: int) -> str: class UTTest(unittest.TestCase): def test_shell(self) -> None: - idf_path = os.environ['IDF_PATH'] env = os.environ.copy() for test in TESTS: with self.subTest(): - with open(os.path.join(idf_path, f'{test.name}.out'), 'wb') as o: + with open(os.path.join(IDF_PATH, f'{test.shell}.{test.name}.out'), 'wb') as o: env['TERM'] = test.term - with pexpect.spawn(f'{test.name} -i', env=env, logfile=o, timeout=200) as pproc: - pproc.sendline(f'. {idf_path}/export.{test.ext}') + with pexpect.spawn(f'{test.shell} -i', env=env, logfile=o, timeout=200) as pproc: + if test.shell == 'bash': + # The @-argument autocomplete works reliably in bash only + # if @ is not included in COMP_WORDBREAKS. + pproc.sendline('COMP_WORDBREAKS=${COMP_WORDBREAKS//@/}') + pproc.sendline(f'. {IDF_PATH}/export.{test.ext}') i = pproc.expect(['Go to the project directory and run.*idf\\.py build', *pargs]) self.assertEqual(i, 0, get_fail_msg(pproc, 'Export was not successful!', i)) - pproc.send('idf.py \t\t') + pproc.send(f'idf.py {test.prefix}\t\t') i = pproc.expect([test.pattern, *pargs], timeout=100) - self.assertEqual(i, 0, get_fail_msg(pproc, f'Autocompletion for idf.py failed in {test.name}!', i)) + self.assertEqual(i, 0, get_fail_msg(pproc, f'Autocompletion for idf.py failed in {test.shell}!', i)) if __name__ == '__main__': From a8de16b13d18153100fea3c4d10b410167538478 Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Wed, 11 Dec 2024 11:09:01 +0100 Subject: [PATCH 2/2] fix(autocomplete): handle @-argument autocompletion in bash Enable @-argument completion only if '@' is not present in COMP_WORDBREAKS. When '@' is included, the @-argument is not considered part of the completion word, causing @-argument completion to function unreliably in bash. Signed-off-by: Frantisek Hrbata --- tools/export_utils/shell_types.py | 1 + tools/idf.py | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/export_utils/shell_types.py b/tools/export_utils/shell_types.py index d2e3460672..8918eb5d8e 100644 --- a/tools/export_utils/shell_types.py +++ b/tools/export_utils/shell_types.py @@ -126,6 +126,7 @@ class BashShell(UnixShell): then echo "$WARNING_MSG" fi + export IDF_PY_COMP_WORDBREAKS="$COMP_WORDBREAKS" fi """) diff --git a/tools/idf.py b/tools/idf.py index 14730df1e1..200a557d94 100755 --- a/tools/idf.py +++ b/tools/idf.py @@ -454,7 +454,13 @@ def init_cli(verbose_output: Optional[List]=None) -> Any: return None def shell_complete(self, ctx: click.core.Context, incomplete: str) -> List[CompletionItem]: - if incomplete.startswith('@'): + # Enable @-argument completion in bash only if @ is not present in + # COMP_WORDBREAKS. When @ is included, the @-argument is not considered + # part of the completion word, causing @-argument completion to function + # unreliably in bash. + complete_file = ('bash' not in os.environ.get('_IDF.PY_COMPLETE', '') or + '@' not in os.environ.get('IDF_PY_COMP_WORDBREAKS', '')) + if incomplete.startswith('@') and complete_file: path_prefix = incomplete[1:] candidates = glob.glob(path_prefix + '*') result = [CompletionItem(f'@{c}') for c in candidates]