mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
Expose code intend guides
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
4
Makefile
4
Makefile
@@ -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
|
||||
|
||||
@@ -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__":
|
||||
|
||||
@@ -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__":
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user