rust-lang / mdBook

Create book from markdown files. Like Gitbook but implemented in Rust
https://rust-lang.github.io/mdBook/
Mozilla Public License 2.0
17.62k stars 1.61k forks source link

Mdbook should translate internal references #408

Closed Kordalien closed 6 years ago

Kordalien commented 7 years ago

When working with links on a page, it would be nice if mdbook could translate a reference to a .md file to a reference to a generated HTML file.

E.g. if I have [Chapter 0](./chapter0.md) [Chapter 1](./chapter1.md)

In my SUMMARY.md file,

it would be nice to be able to write something like: In [chapter 1](./chapter1.md) we explain x... In chapter 0, and have mdbook replace the link with chapter1.html.

This has the advantage of allowing the raw markdown to stay functional as well as the generated html/other possible future formats.

Kordalien commented 7 years ago

If someone had advice on where to start implementing the feature, I'd be happy to work on it; but I figured it would be best to make sure there wasn't some hidden problem with his idea before diving into it.

azerupi commented 7 years ago

Hi, thanks for the feature request. That is indeed something useful we could do. 👍

If you want to take a stab at this, you can probably look at the preprocess::links::replace_all function called in the handlebars renderer. Implementing this feature would probably be quite similar to it.

If you have any questions or need guidance, don't hesitate to ask here. :)

mfoe87 commented 6 years ago

I took a stab at this and failed miserably, while waiting for this fix i simply added an additional JS that alters links with .md files to .html

$(document).ready(function(){
    $("a")
    .each(function()
    { 
    this.href = this.href.replace(".md", 
        ".html");
    });
});
Michael-F-Bryan commented 6 years ago

It may be better to handle this as part of the rendering process. It sounds a lot like something which would benefit from a plugin architecture, as a post-processing/pre-rendering step you'd run some plugin over our internal representation of a book and replace the relative urls (e.g. ./chapter_1.md) with their equivalents.

We're actually working on refactoring the internals so that it's easy to introduce alternative renderers and plugins (#409).

Michael-F-Bryan commented 6 years ago

Just an update on this, @JaimeValdemoros is currently working on refactoring the internals (#532) so we can create our own preprocessors. Once his PR lands we'll be able to implement this.

diegooliveira commented 6 years ago

I started to look at this issue and was looking for another solution other than a plugin architecture. The way I see we have two moments to do the reference translation. Just after loading the book to memory, for example in the load_book method or during rendering in the convert method.

The first approach is the easiest but one would use some sort of find/replace to find the link and there is a chance miss any markdown specificity.

The second approach is more dificult but the link parsing will be done by the markdown engine, tanking care of any special case.

Michael-F-Bryan commented 6 years ago

I started to look at this issue and was looking for another solution other than a plugin architecture.

For now we aren't allowing people to provide their own Preprocessors so it's purely an abstraction we're using internally to formalise/clean up the build process. It's essentially just a pass we do immediately after loading a book and before handing it off to the renderer, so I think we're talking about the same thing here.

The way I see we have two moments to do the reference translation. Just after loading the book to memory, for example in the load_book method or during rendering in the convert method.

In terms of implementation, I was thinking I'd make a preprocessor that uses pulldown_cmark to scan through each chapter's content and find the location of all the links. Then we can do some simple string replacements to update any links which need updating. The Parser from pulldown_cmark gives you access to the current byte index into a string, so it's easy enough to stash away a link's location. I did a very similar thing in the mdbook-linkcheck backend, so we can steal a bunch of code from there.

Either way, I'd prefer to pull this out into its own pass. We've spent a lot of time trying to refactor the internals to be less convoluted/coupled, and lots of little passes/processes is easier to maintain than putting orthogonal features together (markdown rendering and link tweaking).