-
Notifications
You must be signed in to change notification settings - Fork 253
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
Render images as links? #462
Comments
Certainly. The most straightforward way to do this is to replace image events with link events before passing them onto the renderer. For example, this will work: let parser = Parser::new(markdown_input)
.map(|event| match event {
Event::Start(Tag::Image(linktype, url, title)) =>
Event::Start(Tag::Link(linktype, url, title)),
Event::End(Tag::Image(linktype, url, title)) =>
Event::End(Tag::Link(linktype, url, title)),
_ => event,
});
let mut html_output = String::new();
html::push_html(&mut html_output, parser); Note that this will create empty links for images without titles, so you may want to include a special case for them by expanding the match like this: match event {
Event::Start(Tag::Image(linktype, url, title)) if title.is_empty() =>
Event::Start(Tag::Link(linktype, url.clone(), url)),
Event::Start(Tag::Image(linktype, url, title)) =>
Event::Start(Tag::Link(linktype, url, title)),
Event::End(Tag::Image(linktype, url, title)) if title.is_empty() =>
Event::End(Tag::Link(linktype, url.clone(), url)),
Event::End(Tag::Image(linktype, url, title)) =>
Event::End(Tag::Link(linktype, url, title)),
_ => event,
} Hope this answers your question. Feel free to reopen if it doesn't :-) |
Thanks! This is exactly what I was looking for. |
@marcusklaas One more thing. I'm assuming initializing the parser like this has a performance cost. Is there a way to reuse the parser for new text with the events configured? My use case has me creating the parser as much as thousands of times per page and the performance costs can really add up. https://github.com/IronOxidizer/lemmy-lite/blob/master/src/templates.rs#L610 |
That's an interesting question. It isn't currently possible, but it may be worthwhile to 'reset' the parser so that its resources (read: allocations) can be reused. We took care to do minimal allocations, but if you're doing thousands of very small parses, it may make a measurable difference. I encourage you to open a separate issue for this so we can investigate this! |
@marcusklaas I did some tests and it appears that the image-link substitution is not working. The images are no longer rendered but no text is displayed as well: Here's an example: For reference, here's the original markdown:
It doesn't appear to be an issue with the parser as printing the URL on every image tag instance correctly prints the URL:
Curiously, this appears to only be a problem when there is no title which leads me to believe that the lack of text/link is possibly a result of a lifetime issue however, I'm not sure. Here's an example of a working image link, only because it has a title: http://lemmylite.crabdance.com/dev.lemmy.ml/post/39163 And its markdown:
|
Ah yes, my bad. Link contents are actually separate events. I forgot about that. You'd have to insert your own events into the event stream. Unfortunately, this isn't possible using the built-in iterator functions (I think!). We would need a custom iterator. Something like this seems to work: use pulldown_cmark::{html, Options, Parser, Event, Tag, CowStr};
struct ImageSwapper<'a, I> {
iter: I,
image_title: Option<CowStr<'a>>,
}
impl<'a, I> ImageSwapper<'a, I> {
fn new(iter: I) -> Self {
ImageSwapper {
iter: iter,
image_title: None,
}
}
}
impl<'a, I> Iterator for ImageSwapper<'a, I>
where I: ::std::iter::Iterator<Item = Event<'a>>
{
type Item = Event<'a>;
fn next(&mut self) -> Option<Self::Item> {
let mut title = None;
::std::mem::swap(&mut self.image_title, &mut title);
match title {
None => self.iter.next().map(|event| match event {
Event::Start(Tag::Image(linktype, url, title)) if title.is_empty() => {
self.image_title = Some(url.clone());
Event::Start(Tag::Link(linktype, url, title))
}
Event::Start(Tag::Image(linktype, url, title)) => {
self.image_title = Some(title.clone());
Event::Start(Tag::Link(linktype, url, title))
}
Event::End(Tag::Image(linktype, url, title)) =>
Event::End(Tag::Link(linktype, url, title)),
_ => event,
}),
Some(title) => {
self.image_title = None;
Some(Event::Text(title))
}
}
}
}
fn main() {
let markdown_input: &str = "";
println!("Parsing the following markdown string:\n{}", markdown_input);
// Set up options and parser. Strikethroughs are not part of the CommonMark standard
// and we therefore must enable it explicitly.
let mut options = Options::empty();
options.insert(Options::ENABLE_STRIKETHROUGH);
let mut parser = ImageSwapper::new(Parser::new(markdown_input));
// Write to String buffer.
let mut html_output: String = String::with_capacity(markdown_input.len() * 3 / 2);
html::push_html(&mut html_output, &mut parser);
// Write result to stdout.
println!("\nHTML output:\n{}", &html_output);
} This produces the following:
which looks about right. |
That works perfectly. Thanks you very much! |
Is it possible to render images as links? For my use case it would be ideal if users didn't need to load large images upon loading other users' markdown.
The text was updated successfully, but these errors were encountered: