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 - 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 - 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 ## [3.4.0] - 2025-06-14

View File

@@ -52,7 +52,7 @@ docs-online-nav:
.PHONY: docs-serve .PHONY: docs-serve
docs-serve: clean-screenshot-cache docs-online-nav 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 rm -f mkdocs-nav-online.yml
.PHONY: docs-serve-offline .PHONY: docs-serve-offline
@@ -76,7 +76,7 @@ clean-offline-docs:
.PHONY: docs-deploy .PHONY: docs-deploy
docs-deploy: clean-screenshot-cache docs-online-nav 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 rm -f mkdocs-nav-online.yml
.PHONY: build .PHONY: build

View File

@@ -2,25 +2,58 @@ from textual.app import App, ComposeResult
from textual.widgets import Markdown from textual.widgets import Markdown
EXAMPLE_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. - Typography *emphasis*, **strong**, `inline code` etc.
- Headers - Headers
- Lists (bullet and ordered) - Lists
- Syntax highlighted code blocks - 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): class MarkdownExampleApp(App):
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
yield Markdown(EXAMPLE_MARKDOWN) markdown = Markdown(EXAMPLE_MARKDOWN)
markdown.code_indent_guides = False
yield markdown
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -33,7 +33,7 @@ Tables are displayed in a DataTable widget.
## Code Blocks ## Code Blocks
Code blocks are syntax highlighted, with guidelines. Code blocks are syntax highlighted.
```python ```python
class ListViewExample(App): class ListViewExample(App):
@@ -45,12 +45,24 @@ class ListViewExample(App):
) )
yield Footer() 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): class MarkdownExampleApp(App):
def compose(self) -> ComposeResult: 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__": 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 } [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 ## Markdown
@@ -172,7 +172,7 @@ Display a markdown document.
[Markdown reference](./widgets/markdown.md){ .md-button .md-button--primary } [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 ## MaskedInput

View File

@@ -478,7 +478,7 @@ class MarkdownTableContent(Widget):
def render(self) -> Table: def render(self) -> Table:
table = Table( table = Table(
expand=True, expand=True,
box=box.SIMPLE_HEAVY, box=box.SIMPLE_HEAD,
style=self.rich_style, style=self.rich_style,
header_style=self.get_component_rich_style("markdown-table--header"), header_style=self.get_component_rich_style("markdown-table--header"),
border_style=self.get_component_rich_style("markdown-table--lines"), border_style=self.get_component_rich_style("markdown-table--lines"),
@@ -504,7 +504,7 @@ class MarkdownTable(MarkdownBlock):
DEFAULT_CSS = """ DEFAULT_CSS = """
MarkdownTable { MarkdownTable {
width: 100%; width: 100%;
background: $surface; background: $background 80%;
} }
""" """
@@ -635,7 +635,7 @@ class MarkdownFence(MarkdownBlock):
self.code, self.code,
lexer=self.lexer, lexer=self.lexer,
word_wrap=False, word_wrap=False,
indent_guides=True, indent_guides=self._markdown.code_indent_guides,
padding=(1, 2), padding=(1, 2),
theme=self.theme, theme=self.theme,
) )
@@ -722,6 +722,9 @@ class Markdown(Widget):
code_light_theme: reactive[str] = reactive("material-light") code_light_theme: reactive[str] = reactive("material-light")
"""The theme to use for code blocks when the App theme is 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__( def __init__(
self, self,
markdown: str | None = None, 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_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("") top_block = reactive("")
navigator: var[Navigator] = var(Navigator) 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 parser_factory=self._parser_factory, open_links=self._open_links
) )
markdown.can_focus = True markdown.can_focus = True
yield markdown yield markdown.data_bind(MarkdownViewer.code_indent_guides)
yield MarkdownTableOfContents(markdown) yield MarkdownTableOfContents(markdown)
def _on_markdown_table_of_contents_updated( def _on_markdown_table_of_contents_updated(