diff --git a/docs/usage/index.md b/docs/usage/index.md index 79765fa..daa2444 100644 --- a/docs/usage/index.md +++ b/docs/usage/index.md @@ -36,6 +36,7 @@ linking to their related documentation: - [`session`](#sessions): Execute code blocks within a named session, reusing previously defined variables, etc.. - [`source`](#render-the-source-code-as-well): Render the source as well as the output. - [`tabs`](#change-the-titles-of-tabs): When rendering the source using tabs, choose the tabs titles. +- [`width`](#change-the-console-width): Change the console width through the `COLUMNS` environment variable. - [`workdir`](#change-the-working-directory): Change the working directory. - [`title`](#additional-options): Title is a [Material for MkDocs][material] option. - [`updatetoc`](#generated-headings-in-table-of-contents): Whether to update the Table of Contents with generated headings. @@ -273,6 +274,25 @@ $ cat .git/config WARNING: **Limitation** Wrapping the result is not possible when HTML output is enabled. +## Change the console width + +To change the console width for the execution of a code block, use the `width` option. +Internally, Markdown Exec will set the `COLUMNS` environment variable accordingly, +and restore its previous value after execution. + +If the executed code doesn't support this environment variable, +the default console width will be used (it could be the current width or some arbitrary value). + +````md exec="1" source="tabbed-left" +```bash exec="1" width="10" +echo $COLUMNS +``` + +```bash exec="1" width="1000" +echo $COLUMNS +``` +```` + ## Change the working directory To change the working directory for the execution of a code block, use the `workdir` option. diff --git a/src/markdown_exec/__init__.py b/src/markdown_exec/__init__.py index 6536bd1..9ffaf14 100644 --- a/src/markdown_exec/__init__.py +++ b/src/markdown_exec/__init__.py @@ -79,6 +79,7 @@ def validator( tabs_value = inputs.pop("tabs", "|".join(default_tabs)) tabs = tuple(_tabs_re.split(tabs_value, maxsplit=1)) workdir_value = inputs.pop("workdir", None) + width_value = int(inputs.pop("width", "0")) options["id"] = id_value options["id_prefix"] = id_prefix_value options["html"] = html_value @@ -89,6 +90,7 @@ def validator( options["update_toc"] = update_toc_value options["tabs"] = tabs options["workdir"] = workdir_value + options["width"] = width_value options["extra"] = inputs return True diff --git a/src/markdown_exec/formatters/base.py b/src/markdown_exec/formatters/base.py index db8dc20..5302b12 100644 --- a/src/markdown_exec/formatters/base.py +++ b/src/markdown_exec/formatters/base.py @@ -38,6 +38,29 @@ def working_directory(path: str | None = None) -> Iterator[None]: yield +@contextmanager +def console_width(width: int | None = None) -> Iterator[None]: + """Set the console width for the duration of the context. + + The console width is set using the `COLUMNS` environment variable. + + Parameters: + width: The width to set the console to. + """ + if width: + old_width = os.environ.get("COLUMNS", None) + os.environ["COLUMNS"] = str(width) + try: + yield + finally: + if old_width is None: + del os.environ["COLUMNS"] + else: + os.environ["COLUMNS"] = old_width + else: + yield + + class ExecutionError(Exception): """Exception raised for errors during execution of a code block. @@ -76,6 +99,7 @@ def base_format( session: str | None = None, update_toc: bool = True, workdir: str | None = None, + width: int | None = None, **options: Any, ) -> Markup: """Execute code and return HTML. @@ -114,7 +138,7 @@ def base_format( source_output = code try: - with working_directory(workdir): + with working_directory(workdir), console_width(width): output = run(source_input, returncode=returncode, session=session, id=id, **extra) except ExecutionError as error: identifier = id or extra.get("title", "") diff --git a/tests/test_base_formatter.py b/tests/test_base_formatter.py index 3451220..60b1da0 100644 --- a/tests/test_base_formatter.py +++ b/tests/test_base_formatter.py @@ -91,3 +91,20 @@ def test_changing_working_directory(md: Markdown) -> None: workdir="/", ) assert markup == "

/

" + + +def test_console_width(md: Markdown) -> None: + """Assert we can change the console width with `width`. + + Parameters: + md: A Markdown instance (fixture). + """ + for width in (10, 1000): + markup = base_format( + language="bash", + run=lambda code, **_: subprocess.check_output(code, shell=True, text=True), # noqa: S602, + code="echo width: $COLUMNS", + md=md, + width=width, + ) + assert f"width: {width}" in markup