Expose code intend guides

This commit is contained in:
Will McGugan
2025-06-20 12:56:13 +01:00
parent 8f85ece761
commit 6980c470b0
6 changed files with 74 additions and 22 deletions

View File

@@ -11,6 +11,7 @@ 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
## [3.4.0] - 2025-06-14

View File

@@ -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
@@ -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

View File

@@ -2,25 +2,58 @@ from textual.app import App, ComposeResult
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__":

View File

@@ -33,7 +33,7 @@ Tables are displayed in a DataTable widget.
## Code Blocks
Code blocks are syntax highlighted, with guidelines.
Code blocks are syntax highlighted.
```python
class ListViewExample(App):
@@ -45,12 +45,24 @@ class ListViewExample(App):
)
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__":

View File

@@ -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="140" lines="50" press="tab,down"}
```
## Markdown
@@ -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="140" lines="51"}
```
## MaskedInput

View File

@@ -478,7 +478,7 @@ class MarkdownTableContent(Widget):
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"),
@@ -504,7 +504,7 @@ class MarkdownTable(MarkdownBlock):
DEFAULT_CSS = """
MarkdownTable {
width: 100%;
background: $surface;
background: $background 80%;
}
"""
@@ -635,7 +635,7 @@ class MarkdownFence(MarkdownBlock):
self.code,
lexer=self.lexer,
word_wrap=False,
indent_guides=True,
indent_guides=self._markdown.code_indent_guides,
padding=(1, 2),
theme=self.theme,
)
@@ -722,6 +722,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,
@@ -1157,6 +1160,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)
@@ -1241,7 +1247,7 @@ class MarkdownViewer(VerticalScroll, can_focus=False, can_focus_children=True):
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(