Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

- Optimized startup https://github.com/Textualize/textual/pull/5869
- New blank visual which makes background faster to render (note this will break snapshots tests this version) https://github.com/Textualize/textual/pull/5869
- Exposed `code_indent_guides` boolean on Markdown widget https://github.com/Textualize/textual/pull/5874
- Changed code fence background to use CSS background rather than its code theme https://github.com/Textualize/textual/pull/5874

## [3.4.0] - 2025-06-14

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ docs-online-nav:

.PHONY: docs-serve
docs-serve: clean-screenshot-cache docs-online-nav
$(run) mkdocs serve --config-file mkdocs-nav-online.yml
TEXTUAL_THEME=dracula $(run) mkdocs serve --config-file mkdocs-nav-online.yml
rm -f mkdocs-nav-online.yml

.PHONY: docs-serve-offline
Expand All @@ -76,7 +76,7 @@ clean-offline-docs:

.PHONY: docs-deploy
docs-deploy: clean-screenshot-cache docs-online-nav
$(run) mkdocs gh-deploy --config-file mkdocs-nav-online.yml
TEXTUAL_THEME=dracula $(run) mkdocs gh-deploy --config-file mkdocs-nav-online.yml
rm -f mkdocs-nav-online.yml

.PHONY: build
Expand Down
57 changes: 45 additions & 12 deletions docs/examples/widgets/markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,58 @@
from textual.widgets import Markdown

EXAMPLE_MARKDOWN = """\
# Markdown Document
## Markdown

This is an example of Textual's `Markdown` widget.

## Features

Markdown syntax and extensions are supported.

- Typography *emphasis*, **strong**, `inline code` etc.
- Headers
- Lists (bullet and ordered)
- Typography *emphasis*, **strong**, `inline code` etc.
- Headers
- Lists
- Syntax highlighted code blocks
- Tables!
- Tables and more

## Quotes

> I must not fear.
> > Fear is the mind-killer.
> > Fear is the little-death that brings total obliteration.
> > I will face my fear.
> > > I will permit it to pass over me and through me.
> > > And when it has gone past, I will turn the inner eye to see its path.
> > > Where the fear has gone there will be nothing. Only I will remain.

## Tables

| Name | Type | Default | Description |
| --------------- | ------ | ------- | ---------------------------------- |
| `show_header` | `bool` | `True` | Show the table header |
| `fixed_rows` | `int` | `0` | Number of fixed rows |
| `fixed_columns` | `int` | `0` | Number of fixed columns |

## Code blocks

```python
def loop_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]:
\"\"\"Iterate and generate a tuple with a flag for last value.\"\"\"
iter_values = iter(values)
try:
previous_value = next(iter_values)
except StopIteration:
return
for value in iter_values:
yield False, previous_value
previous_value = value
yield True, previous_value
```


"""


class MarkdownExampleApp(App):

def compose(self) -> ComposeResult:
yield Markdown(EXAMPLE_MARKDOWN)
markdown = Markdown(EXAMPLE_MARKDOWN)
markdown.code_indent_guides = False
yield markdown


if __name__ == "__main__":
Expand Down
16 changes: 14 additions & 2 deletions docs/examples/widgets/markdown_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

## Code Blocks

Code blocks are syntax highlighted, with guidelines.
Code blocks are syntax highlighted.

```python
class ListViewExample(App):
Expand All @@ -45,12 +45,24 @@ def compose(self) -> ComposeResult:
)
yield Footer()
```

## Litany Against Fear

I must not fear.
Fear is the mind-killer.
Fear is the little-death that brings total obliteration.
I will face my fear.
I will permit it to pass over me and through me.
And when it has gone past, I will turn the inner eye to see its path.
Where the fear has gone there will be nothing. Only I will remain.
"""


class MarkdownExampleApp(App):
def compose(self) -> ComposeResult:
yield MarkdownViewer(EXAMPLE_MARKDOWN, show_table_of_contents=True)
markdown_viewer = MarkdownViewer(EXAMPLE_MARKDOWN, show_table_of_contents=True)
markdown_viewer.code_indent_guides = False
yield markdown_viewer


if __name__ == "__main__":
Expand Down
4 changes: 2 additions & 2 deletions docs/widget_gallery.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Display and interact with a Markdown document (adds a table of contents and brow
[MarkdownViewer reference](./widgets/markdown_viewer.md){ .md-button .md-button--primary }


```{.textual path="docs/examples/widgets/markdown_viewer.py" columns="100" lines="42"}
```{.textual path="docs/examples/widgets/markdown_viewer.py" columns="120" lines="50" press="tab,down"}
```

## Markdown
Expand All @@ -172,7 +172,7 @@ Display a markdown document.
[Markdown reference](./widgets/markdown.md){ .md-button .md-button--primary }


```{.textual path="docs/examples/widgets/markdown.py"}
```{.textual path="docs/examples/widgets/markdown.py" columns="120" lines="51"}
```

## MaskedInput
Expand Down
31 changes: 25 additions & 6 deletions src/textual/widgets/_markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ class MarkdownBlockQuote(MarkdownBlock):
DEFAULT_CSS = """
MarkdownBlockQuote {
background: $boost;
border-left: outer $success-darken-2;
border-left: outer $primary 50%;
margin: 1 0;
padding: 0 1;
}
Expand Down Expand Up @@ -478,7 +478,7 @@ def __init__(self, headers: list[Text], rows: list[list[Text]]):
def render(self) -> Table:
table = Table(
expand=True,
box=box.SIMPLE_HEAVY,
box=box.SIMPLE_HEAD,
style=self.rich_style,
header_style=self.get_component_rich_style("markdown-table--header"),
border_style=self.get_component_rich_style("markdown-table--lines"),
Expand All @@ -504,7 +504,10 @@ class MarkdownTable(MarkdownBlock):
DEFAULT_CSS = """
MarkdownTable {
width: 100%;
background: $surface;
background: black 10%;
&:light {
background: white 30%;
}
}
"""

Expand Down Expand Up @@ -555,7 +558,7 @@ class MarkdownBullet(Widget):
DEFAULT_CSS = """
MarkdownBullet {
width: auto;
color: $success;
color: $text;
text-style: bold;
&:light {
color: $secondary;
Expand Down Expand Up @@ -613,6 +616,11 @@ class MarkdownFence(MarkdownBlock):
height: auto;
max-height: 20;
color: rgb(210,210,210);
background: black 10%;

&:light {
background: white 30%;
}
}

MarkdownFence > * {
Expand All @@ -630,14 +638,19 @@ def __init__(self, markdown: Markdown, code: str, lexer: str) -> None:
else self._markdown.code_light_theme
)

def notify_style_update(self) -> None:
self.call_later(self._retheme)

def _block(self) -> Syntax:
_, background_color = self.background_colors
return Syntax(
self.code,
lexer=self.lexer,
word_wrap=False,
indent_guides=True,
indent_guides=self._markdown.code_indent_guides,
padding=(1, 2),
theme=self.theme,
background_color=background_color.css,
)

def _on_mount(self, _: Mount) -> None:
Expand Down Expand Up @@ -722,6 +735,9 @@ class Markdown(Widget):
code_light_theme: reactive[str] = reactive("material-light")
"""The theme to use for code blocks when the App theme is light."""

code_indent_guides: reactive[bool] = reactive(True)
"""Should code fences display indent guides?"""

def __init__(
self,
markdown: str | None = None,
Expand Down Expand Up @@ -1157,6 +1173,9 @@ class MarkdownViewer(VerticalScroll, can_focus=False, can_focus_children=True):
"""

show_table_of_contents = reactive(True)
"""Show the table of contents?"""
code_indent_guides: reactive[bool] = reactive(True)
"""Should code fences display indent guides?"""
top_block = reactive("")

navigator: var[Navigator] = var(Navigator)
Expand Down Expand Up @@ -1241,7 +1260,7 @@ def compose(self) -> ComposeResult:
parser_factory=self._parser_factory, open_links=self._open_links
)
markdown.can_focus = True
yield markdown
yield markdown.data_bind(MarkdownViewer.code_indent_guides)
yield MarkdownTableOfContents(markdown)

def _on_markdown_table_of_contents_updated(
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading