From a2225f78f8a0ecf71fdeb35ff17bec190456f061 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Mon, 12 May 2025 17:50:47 +0200 Subject: [PATCH] ansible-doc: fix indent and line wrapping for first line of (sub-)option and (sub-)return value descriptions (#84690) (#84994) * Fix initial indent for descriptions of suboptions. * Fix line width for initial line of option descriptions. (cherry picked from commit 352d8ec33a2e80c1cb58a3ae5e6e949dfd2a51f9) --- .../84690-ansible-doc-indent-wrapping.yml | 3 +++ lib/ansible/cli/doc.py | 21 ++++++++++++------- .../randommodule-text-verbose.output | 6 +++--- .../ansible-doc/randommodule-text.output | 16 +++++++------- .../ansible-doc/test_docs_returns.output | 2 +- .../ansible-doc/test_docs_suboptions.output | 8 +++---- .../ansible-doc/test_docs_yaml_anchors.output | 4 ++-- 7 files changed, 36 insertions(+), 24 deletions(-) create mode 100644 changelogs/fragments/84690-ansible-doc-indent-wrapping.yml diff --git a/changelogs/fragments/84690-ansible-doc-indent-wrapping.yml b/changelogs/fragments/84690-ansible-doc-indent-wrapping.yml new file mode 100644 index 00000000000..e9ffbca5310 --- /dev/null +++ b/changelogs/fragments/84690-ansible-doc-indent-wrapping.yml @@ -0,0 +1,3 @@ +bugfixes: + - "ansible-doc - fix indentation for first line of descriptions of suboptions and sub-return values (https://github.com/ansible/ansible/pull/84690)." + - "ansible-doc - fix line wrapping for first line of description of options and return values (https://github.com/ansible/ansible/pull/84690)." diff --git a/lib/ansible/cli/doc.py b/lib/ansible/cli/doc.py index 4f7e733154d..c0eb3c1aa65 100755 --- a/lib/ansible/cli/doc.py +++ b/lib/ansible/cli/doc.py @@ -1158,12 +1158,16 @@ class DocCLI(CLI, RoleMixin): return 'version %s' % (version_added, ) @staticmethod - def warp_fill(text, limit, initial_indent='', subsequent_indent='', **kwargs): + def warp_fill(text, limit, initial_indent='', subsequent_indent='', initial_extra=0, **kwargs): result = [] for paragraph in text.split('\n\n'): - result.append(textwrap.fill(paragraph, limit, initial_indent=initial_indent, subsequent_indent=subsequent_indent, - break_on_hyphens=False, break_long_words=False, drop_whitespace=True, **kwargs)) + wrapped = textwrap.fill(paragraph, limit, initial_indent=initial_indent + ' ' * initial_extra, subsequent_indent=subsequent_indent, + break_on_hyphens=False, break_long_words=False, drop_whitespace=True, **kwargs) + if initial_extra and wrapped.startswith(' ' * initial_extra): + wrapped = wrapped[initial_extra:] + result.append(wrapped) initial_indent = subsequent_indent + initial_extra = 0 return '\n'.join(result) @staticmethod @@ -1195,20 +1199,23 @@ class DocCLI(CLI, RoleMixin): text.append('') # TODO: push this to top of for and sort by size, create indent on largest key? - inline_indent = base_indent + ' ' * max((len(opt_indent) - len(o)) - len(base_indent), 2) - sub_indent = inline_indent + ' ' * (len(o) + 3) + inline_indent = ' ' * max((len(opt_indent) - len(o)) - len(base_indent), 2) + extra_indent = base_indent + ' ' * (len(o) + 3) + sub_indent = inline_indent + extra_indent if is_sequence(opt['description']): for entry_idx, entry in enumerate(opt['description'], 1): if not isinstance(entry, string_types): raise AnsibleError("Expected string in description of %s at index %s, got %s" % (o, entry_idx, type(entry))) if entry_idx == 1: - text.append(key + DocCLI.warp_fill(DocCLI.tty_ify(entry), limit, initial_indent=inline_indent, subsequent_indent=sub_indent)) + text.append(key + DocCLI.warp_fill(DocCLI.tty_ify(entry), limit, + initial_indent=inline_indent, subsequent_indent=sub_indent, initial_extra=len(extra_indent))) else: text.append(DocCLI.warp_fill(DocCLI.tty_ify(entry), limit, initial_indent=sub_indent, subsequent_indent=sub_indent)) else: if not isinstance(opt['description'], string_types): raise AnsibleError("Expected string in description of %s, got %s" % (o, type(opt['description']))) - text.append(key + DocCLI.warp_fill(DocCLI.tty_ify(opt['description']), limit, initial_indent=inline_indent, subsequent_indent=sub_indent)) + text.append(key + DocCLI.warp_fill(DocCLI.tty_ify(opt['description']), limit, + initial_indent=inline_indent, subsequent_indent=sub_indent, initial_extra=len(extra_indent))) del opt['description'] suboptions = [] diff --git a/test/integration/targets/ansible-doc/randommodule-text-verbose.output b/test/integration/targets/ansible-doc/randommodule-text-verbose.output index cfcba46ff9e..f7beb77de30 100644 --- a/test/integration/targets/ansible-doc/randommodule-text-verbose.output +++ b/test/integration/targets/ansible-doc/randommodule-text-verbose.output @@ -23,13 +23,13 @@ OPTIONS (= indicates it is required): type: dict options: - - subtest2 Another suboption. + - subtest2 Another suboption. default: null type: float added in: version 1.1.0 suboptions: - - subtest A suboption. + - subtest A suboption. default: null type: int added in: version 1.1.0 of testns.testcol @@ -67,7 +67,7 @@ RETURN VALUES: type: dict contains: - - suboption A suboption. + - suboption A suboption. choices: [ARF, BARN, c_without_capital_first_letter] type: str added in: version 1.4.0 of testns.testcol diff --git a/test/integration/targets/ansible-doc/randommodule-text.output b/test/integration/targets/ansible-doc/randommodule-text.output index e8905165fab..1a95662abbd 100644 --- a/test/integration/targets/ansible-doc/randommodule-text.output +++ b/test/integration/targets/ansible-doc/randommodule-text.output @@ -17,8 +17,8 @@ DEPRECATED: OPTIONS (= indicates it is required): -- sub Suboptions. Contains `sub.subtest', which can be set to `123'. - You can use `TEST_ENV' to set this. +- sub Suboptions. Contains `sub.subtest', which can be set to + `123'. You can use `TEST_ENV' to set this. set_via: env: - deprecated: @@ -31,15 +31,17 @@ OPTIONS (= indicates it is required): type: dict options: - - subtest2 Another suboption. Useful when [[ansible.builtin.shuffle]] - is used with value `[a,b,),d\]'. + - subtest2 Another suboption. Useful when + [[ansible.builtin.shuffle]] is used with value + `[a,b,),d\]'. default: null type: float added in: version 1.1.0 suboptions: - - subtest A suboption. Not compatible to `path=c:\foo(1).txt' (of - module ansible.builtin.copy). + - subtest A suboption. Not compatible to + `path=c:\foo(1).txt' (of module + ansible.builtin.copy). default: null type: int added in: version 1.1.0 of testns.testcol @@ -102,7 +104,7 @@ RETURN VALUES: type: dict contains: - - suboption A suboption. + - suboption A suboption. choices: [ARF, BARN, c_without_capital_first_letter] type: str added in: version 1.4.0 of testns.testcol diff --git a/test/integration/targets/ansible-doc/test_docs_returns.output b/test/integration/targets/ansible-doc/test_docs_returns.output index 3fea978c307..17d5f70eec1 100644 --- a/test/integration/targets/ansible-doc/test_docs_returns.output +++ b/test/integration/targets/ansible-doc/test_docs_returns.output @@ -17,7 +17,7 @@ RETURN VALUES: type: dict contains: - - suboption A suboption. + - suboption A suboption. choices: [ARF, BARN, c_without_capital_first_letter] type: str diff --git a/test/integration/targets/ansible-doc/test_docs_suboptions.output b/test/integration/targets/ansible-doc/test_docs_suboptions.output index 2ca337753d9..6523960c72a 100644 --- a/test/integration/targets/ansible-doc/test_docs_suboptions.output +++ b/test/integration/targets/ansible-doc/test_docs_suboptions.output @@ -8,20 +8,20 @@ OPTIONS (= indicates it is required): type: dict suboptions: - - a_first The first suboption. + - a_first The first suboption. default: null type: str - - m_middle The suboption in the middle. + - m_middle The suboption in the middle. Has its own suboptions. default: null suboptions: - - a_suboption A sub-suboption. + - a_suboption A sub-suboption. default: null type: str - - z_last The last suboption. + - z_last The last suboption. default: null type: str diff --git a/test/integration/targets/ansible-doc/test_docs_yaml_anchors.output b/test/integration/targets/ansible-doc/test_docs_yaml_anchors.output index abe26a486fa..ab6fe805b81 100644 --- a/test/integration/targets/ansible-doc/test_docs_yaml_anchors.output +++ b/test/integration/targets/ansible-doc/test_docs_yaml_anchors.output @@ -12,7 +12,7 @@ OPTIONS (= indicates it is required): type: list suboptions: - = port Rule port + = port Rule port type: int - ingress Ingress firewall rules @@ -21,7 +21,7 @@ OPTIONS (= indicates it is required): type: list suboptions: - = port Rule port + = port Rule port type: int - last_one Short desc