Build the gate's display text. ``message`` may be a non-string (e.g. a YAML numeric literal that ``execute`` does not coerce), so it is rendered through ``str``. When ``show_file`` names a file, its contents (read safely, see ``_read_show_file``) are appended below t
(cls, message: object, show_file: str | None)
| 91 | |
| 92 | @classmethod |
| 93 | def _compose_prompt(cls, message: object, show_file: str | None) -> str: |
| 94 | """Build the gate's display text. |
| 95 | |
| 96 | ``message`` may be a non-string (e.g. a YAML numeric literal that |
| 97 | ``execute`` does not coerce), so it is rendered through ``str``. |
| 98 | When ``show_file`` names a file, its contents (read safely, see |
| 99 | ``_read_show_file``) are appended below the message so the operator |
| 100 | can review the referenced material before choosing. Always returns a |
| 101 | ``str`` — possibly multi-line — for ``_prompt`` to render in the box. |
| 102 | """ |
| 103 | text = str(message) |
| 104 | if not show_file: |
| 105 | return text |
| 106 | # The path is opened with the original value but displayed stripped, |
| 107 | # so a path that itself contains escapes cannot spoof the terminal. |
| 108 | header = f"{_CONTROL_CHARS.sub('', show_file)}:" |
| 109 | body = "\n".join( |
| 110 | [header, *(f" {line}" for line in cls._read_show_file(show_file))] |
| 111 | ) |
| 112 | return f"{text}\n\n{body}" |
| 113 | |
| 114 | @staticmethod |
| 115 | def _prompt(message: str, options: list[str]) -> str: |