Repository: Textualize/textual

Issue:
MD links inside a MD table in Markdown Widget do not generate Markdown.LinkClicked when clicked
### Problem 
When using the Markdown widget, links inside a table are not posting `Markdown.LinkClicked` events when they are clicked. The links are rendered properly, just not firing `Markdown.LinkClicked`. 

Other links inside the document but outside of a table work as expected. 

### Expected Outcome:  

Links inside tables generate `Markdown.LinkClicked` events

The following App renders some markdown which includes links inside and outside of a MD table. The links in the table do not generate the `LinkClicked` event, so no app notification  will be displayed. 



```python
from textual import on
from textual.app import App, ComposeResult
from textual.widgets import Markdown 


EXAMPLE_MARKDOWN = """
# Markdown Document

[this link works](https://www.textualize.io/)

| [this title link does not work](https://www.textualize.io/) | col1 | col2 |
|-------|------|------|
| [does this one??](https://www.textualize.io/) | i  | wonder |
| foo | bar  | textual | 
"""
class SelectApp(App):
   
    def compose(self) -> ComposeResult:
        yield Markdown(EXAMPLE_MARKDOWN)

    @on(Markdown.LinkClicked)
    async def on_markdown_link_clicked(self, event: Markdown.LinkClicked) -> None:
        self.notify(f"on_markdown_link_clicked  - {event.href}")

if __name__ == "__main__":
    app = SelectApp()
    app.run() 

```


I've tried this on my windows 11 laptop as well as Ubuntu via wsl. Here are the textual diagnose outputs for both:



# Textual Diagnostics for Windows 11

## Versions

| Name    | Value  |
|---------|--------|
| Textual | 0.70.0 |
| Rich    | 13.7.1 |

## Python

| Name           | Value                                                           |
|----------------|-----------------------------------------------------------------|
| Version        | 3.12.1                                                          |
| Implementation | CPython                                                         |
| Compiler       | MSC v.1937 64 bit (AMD64)                                       |
| Executable     | c:\Users\Joel.Clegg\source\python\beaz\.venv\Scripts\python.exe |

## Operating System

| Name    | Value      |
|---------|------------|
| System  | Windows    |
| Release | 11         |
| Version | 10.0.22631 |

## Terminal

| Name                 | Value            |
|----------------------|------------------|
| Terminal Application | Windows Terminal |
| TERM                 | *Not set*        |
| COLORTERM            | *Not set*        |
| FORCE_COLOR          | *Not set*        |
| NO_COLOR             | *Not set*        |

## Rich Console options

| Name           | Value                |
|----------------|----------------------|
| size           | width=143, height=37 |
| legacy_windows | False                |
| min_width      | 1                    |
| max_width      | 143                  |
| is_terminal    | True                 |
| encoding       | utf-8                |
| max_height     | 37                   |
| justify        | None                 |
| overflow       | None                 |
| no_wrap        | False                |
| highlight      | None                 |
| markup         | None                 |
| height         | None                 |

----

<!-- This is valid Markdown, please paste the following directly in to a GitHub issue -->
# Textual Diagnostics for linux container

## Versions

| Name    | Value  |
|---------|--------|
| Textual | 0.58.0 |
| Rich    | 13.7.1 |

## Python

| Name           | Value                                                       |
|----------------|-------------------------------------------------------------|
| Version        | 3.10.12                                                     |
| Implementation | CPython                                                     |
| Compiler       | GCC 11.4.0                                                  |
| Executable     | /mnt/c/Users/Joel.Clegg/source/python/beaz/.env/bin/python3 |

## Operating System

| Name    | Value                               |
|---------|-------------------------------------|
| System  | Linux                               |
| Release | 5.15.153.1-microsoft-standard-WSL2  |
| Version | #1 SMP Fri Mar 29 23:14:13 UTC 2024 |

## Terminal

| Name                 | Value            |
|----------------------|------------------|
| Terminal Application | Windows Terminal |
| TERM                 | xterm-256color   |
| COLORTERM            | *Not set*        |
| FORCE_COLOR          | *Not set*        |
| NO_COLOR             | *Not set*        |

## Rich Console options

| Name           | Value                |
|----------------|----------------------|
| size           | width=132, height=33 |
| legacy_windows | False                |
| min_width      | 1                    |
| max_width      | 132                  |
| is_terminal    | True                 |
| encoding       | utf-8                |
| max_height     | 33                   |
| justify        | None                 |
| overflow       | None                 |
| no_wrap        | False                |
| highlight      | None                 |
| markup         | None                 |
| height         | None                 |



Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 94f03d027..084829b86 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 - Fixed grid + keyline when the grid has auto dimensions https://github.com/Textualize/textual/pull/4680
 - Fixed mouse code leakage https://github.com/Textualize/textual/pull/4681
+- Fixed link inside markdown table not posting a `Markdown.LinkClicked` message https://github.com/Textualize/textual/issues/4683
 
 
 ## [0.70.0] - 2024-06-19
diff --git a/src/textual/widgets/_markdown.py b/src/textual/widgets/_markdown.py
index b42edfc4a..5bcc22782 100644
--- a/src/textual/widgets/_markdown.py
+++ b/src/textual/widgets/_markdown.py
@@ -487,6 +487,11 @@ class MarkdownTableContent(Widget):
                 table.add_row(*row)
         return table
 
+    async def action_link(self, href: str) -> None:
+        """Pass a link action on to the MarkdownTable parent."""
+        if isinstance(self.parent, MarkdownTable):
+            await self.parent.action_link(href)
+
 
 class MarkdownTable(MarkdownBlock):
     """A Table markdown Block."""


Test patch:
diff --git a/tests/test_markdown.py b/tests/test_markdown.py
index 43060c254..4cedf9b6c 100644
--- a/tests/test_markdown.py
+++ b/tests/test_markdown.py
@@ -164,3 +164,36 @@ async def test_update_of_document_posts_table_of_content_update_message() -> Non
         await pilot.app.query_one(Markdown).update("")
         await pilot.pause()
         assert messages == ["TableOfContentsUpdated", "TableOfContentsUpdated"]
+
+
+async def test_link_in_markdown_table_posts_message_when_clicked():
+    """A link inside a markdown table should post a `Markdown.LinkClicked`
+    message when clicked.
+
+    Regression test for https://github.com/Textualize/textual/issues/4683
+    """
+
+    markdown_table = """\
+| Textual Links                                    |
+| ------------------------------------------------ |
+| [GitHub](https://github.com/textualize/textual/) |
+| [Documentation](https://textual.textualize.io/)  |\
+"""
+
+    class MarkdownTableApp(App):
+        messages = []
+
+        def compose(self) -> ComposeResult:
+            yield Markdown(markdown_table)
+
+        @on(Markdown.LinkClicked)
+        def log_markdown_link_clicked(
+            self,
+            event: Markdown.LinkClicked,
+        ) -> None:
+            self.messages.append(event.__class__.__name__)
+
+    app = MarkdownTableApp()
+    async with app.run_test() as pilot:
+        await pilot.click(Markdown, offset=(3, 3))
+        assert app.messages == ["LinkClicked"]