-
Notifications
You must be signed in to change notification settings - Fork 788
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
markdown_viewer: jump to anchor position when clicking on an anchor link #2941
Conversation
23b669d
to
b4cdf37
Compare
45cc853
to
779bba4
Compare
Hi @davep if you have time to make a quick review for this PR that would be great. |
Sure thing, when one of us gets the time to review we will. :-) |
9a07d4e
to
1b5b502
Compare
Just to let you know: haven't forgotten about this; just been deep in some longer-running stuff, but should look at sweeping this up with the other issue soon. |
Thanks for the update @davep it's not urgent anyway. Let me know if there is something I can do. |
tests/test_markdown.py
Outdated
@@ -125,3 +125,18 @@ async def test_load_non_existing_file() -> None: | |||
await pilot.app.query_one(Markdown).load( | |||
Path("---this-does-not-exist---.it.is.not.a.md") | |||
) | |||
async def test_anchor_links() -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking good (I'm looking to pull this in, in part as a fix for #3094), but I don't think I understand what the test is trying to do here; especially given that it fails.
What is it aiming to test exactly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I committed by error I didn't know the right way to test it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine, I just wanted to check first. I'm happy to look at adding any appropriate testing. 🙂
67519f5
to
c554122
Compare
@blob42 If you wish to make another change to this, could I ask a favour? Don't force push changes. I'd merged in |
I'm going to do a little more work on this; it looks like it runs into a problem that I ran into with Frogmouth too, in that loading a document needs to take into account the original location of the document. |
My bad sorry I didn't know. I hope you still had a local copy of the changes ! No changes to add on my side and I will never use force push again. |
Turns out it's fine, I'm just bad at writing tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes look reasonable to me.
I thought we could have hyperlinks in markdown documents and they'd work well, i.e., I could click them and open web pages.
I just tested it on the Textual README.md and it doesn't open URLs.
Since we're handling clicks in the PR, is this something that makes sense fixing here?
I don't recall that ever being part of the Markdown viewer (it is part of Frogmouth though). I sense it's somewhat out of scope for this PR as this is mostly about handling a genuine crash. Might be worth adding an issue to the effect of the above though. |
Keep in mind that most modern terminal emulators handle url clicks usually ctrl+click. They require the full link to be rendered to the terminal. I don't know if Textual is planning to implement some modern terminal protocol like Kitty, which would solve all these issues. Using Markdown from rich I can disable link rendering which allows me to use my native emulator url handler. Maybe the same option could be added to the widget to disable rendering urls but would ignore relative links used for jumping around. It seems out of scope for this PR though. |
Not ready to merge yet
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A good first pass, but needs work...
What happens if the very first URL we visit has a fragment?
toc = self.table_of_contents.table_of_contents | ||
assert toc is not None | ||
for _, name, block_id in toc: | ||
if name.lower().replace(" ", "-") == anchor: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is making a somewhat naive assumption about how fragments are generated from headers. It wont always be as simple as converting spaces to hyphens and lower casing. Consider characters with accents for example.
I think it makes sense to match what GitHub markdown does, and replicate that.
if message.href.find("#") == -1: | ||
await self.go(message.href) | ||
else: | ||
link, anchor = message.href.split("#", 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest using str.partition
here, so we can avoid the additional branch.
self.scroll_to_widget(block, top=True) | ||
break | ||
|
||
self.call_later(scroll_to_anchor) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
call_later
probably isn't the right approach here. It will execute after all other messages have been processed. This is normally very quick, but it is possible that an entirely new document has been loaded in the meantime.
I think this functionality should be built in to go
, so we can be sure that it applies to the correct document.
link, anchor = message.href.split("#", 1) | ||
await self.go(link) | ||
|
||
def scroll_to_anchor() -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a docstring. I know it seems self explanatory, but it's how we roll.
@blob42 Do you want to make the changes based on Will's feedback? |
I am a bit busy this week but will have time to properly work on it next week. Feel free to do the changes if you would like. |
@blob42 That's fine; not sure if I'll get back to this before next week either so let's say whoever gets back here first. :-) |
Picking this up again. |
#3236 is now merged into main, which should give a good basis for handling Markdown header slugs. |
I've taken the core idea here and created #3244. |
I think we hit this and some other stuff with #3244 so I'll close this one. Thanks again! |
A little patch to handle links with anchors in
MarkdownViewer
and jumps to the anchor position after loading the new md file.I need help for adding tests if they are necessary.
Rationale
I am trying to build an offline sphinx documentation that is generated into markdown output. With the current MarkdownViewer any link containing an anchor does not open the target file. This patch loads the target file and jumps to the anchor position.