vsch / idea-multimarkdown

Markdown language support for IntelliJ IDEA.
https://plugins.jetbrains.com/plugin/7896-markdown-navigator
Apache License 2.0
813 stars 129 forks source link

Add support to render code from links like GitHub web UI does #665

Open SemanticBeeng opened 5 years ago

SemanticBeeng commented 5 years ago

If I copy a code permalink with https://github.com/ben-gibson/GitLink or github UI and embedded it in the markdown text, then the markdown rendering should show the actual code.

This would allow us to create blog posts in markdown that can also be maintained with live code sections (without having to copy and paste code snippets).

Example:

codelink https://github.com/ben-gibson/GitLink/blob/4a8cbac2eda1a68cc348b11c19b4d17248230eee/src/uk/co/ben_gibson/git/link/Container.java#L67-L74

vsch commented 5 years ago

@SemanticBeeng, I am not sure I fully understand this. I can understand that what you want is to have the code referenced by the link embedded in the markdown text. However, I fail to see how the plugin is supposed to distinguish a regular link from a link whose code is supposed to be embedded.

For example what you want is to have the link above when added to markdown generate:

[Sample Code](https://github.com/ben-gibson/GitLink/blob/4a8cbac2eda1a68cc348b11c19b4d17248230eee/src/uk/co/ben_gibson/git/link/Container.java#L67-L74)

```java
public OpenInBrowserHandler openInBrowserHandler()
{
    if (!this.hasService(OpenInBrowserHandler.class)) {
        this.registerService(new OpenInBrowserHandler(BrowserLauncher.getInstance()));
    }

    return (OpenInBrowserHandler) this.service(OpenInBrowserHandler.class);
}
```

Which will display as:

Sample Code

public OpenInBrowserHandler openInBrowserHandler()
{
    if (!this.hasService(OpenInBrowserHandler.class)) {
        this.registerService(new OpenInBrowserHandler(BrowserLauncher.getInstance()));
    }

    return (OpenInBrowserHandler) this.service(OpenInBrowserHandler.class);
}

I think this would be a neat feature which can be useful since the plugin already supports IDE reference clipboard content (when you use Copy Reference in the IDE and paste it into a markdown file). Having the ability to embed and update the fenced code that this link represents would be a neat feature. However, there are questions to make this work in general that have to be worked out.

Q: How is the plugin to keep track of changes made to the linked code so it can update the markdown document and if this should be done, regardless of whether the file is opened or not. Otherwise, your markdown files will be out of date if the code behind the link changes but you never open the markdown file in question.

I know you are talking about it being a permalink but for the plugin there is no such concept so the code behind the link can change. Also the link itself can be changed which will mean the embedded code has to be updated.

SemanticBeeng commented 5 years ago

"Having the ability to embed and update the fenced code that this link represents would be a neat feature."

Glad you like the idea.

"how the plugin is supposed to distinguish a regular link from a link whose code is supposed to be embedded."

I tried to suggest a gitlink as "language" tag. My example above was not that clear. Would this work?

vsch commented 5 years ago

@SemanticBeeng, I saw your suggestion but that is unacceptably limited because it will serve only your current use case and not make the feature generic and useful outside of your use case.

I try to add features that have general usefulness and not address specific use cases.

This means that the feature will need to have some kind of syntax sugar that the plugin can use to mark these links as ones that insert code referenced by the link in the source file.

I will give this some thought and propose ideas. If you have some ideas please post them so we can arrive at an optimal result.

SemanticBeeng commented 5 years ago

"How is the plugin to keep track of changes made to the linked code so it can update the markdown document"

Maybe it can offer an explicit "re-render" action ?

"... and if this should be done, regardless of whether the file is opened or not."

If I understand this well you are thinking how this would work with interactive code in Intellij (not just with links to code in git, right?)

For a code link like https://github.com/ben-gibson/GitLink/blob/4a8cbac2eda1a68cc348b11c19b4d17248230eee/src/uk/co/ben_gibson/git/link/Container.java#L67-L74 pointing to a commit, the plugin could extract the branch - like https://github.com/ben-gibson/GitLink/blob/2.4.0/src/uk/co/ben_gibson/git/link/Container.java - and if project open in Intellij has that branch checked out then it would treat this a "interactive" by extracting src/uk/co/ben_gibson/git/link/Container.java and resolving line numbers itself.

This is not a complete answer but you think something like this might work ?

SemanticBeeng commented 5 years ago

"the feature will need to have some kind of syntax sugar that the plugin can use to mark "

It would work like a custom language extension but the syntax would be same as for ```bash, for example.

medium tried to support something like this https://blog.medium.com/yes-we-get-the-gist-1c2a27cdfc22.

vsch commented 5 years ago

@SemanticBeeng, the real issue is not getting the code but determining which links are just links and which are supposed to extract text from the link target and embed it as fenced code following the link. The link syntax has to be compatible with markdown but distinguishable by the plugin.

For example [Some Text](someUrl) is a regular link but [```Some Text](someUrl) will embed fenced code following it or update one that already exists.

There is also an issue of links being inline elements to they can be part of a paragraph, which means there can be several of them in one paragraph, making figuring out what the following fenced code should be updated or embedded.

Can the embedding links be forced to be the only item in a paragraph. Otherwise it will be treated as a regular link.

So this text [```Some text](someUrl) will be treated as a simple link

but the following will be treated as an embedding link:

[```Some text](someUrl)
SemanticBeeng commented 5 years ago

Hmm... so I take it you do not like my gitlink "extension" :-) and trying to reuse the regular link to achieve this.

Cannot see a difference between the two examples you gave but will review to understand better.

What do you think of these CommonMark extensions and proposals? https://github.com/commonmark/CommonMark/wiki/proposed-extensions https://talk.commonmark.org/t/code-blocks-extension-for-filenames-and-line-numbers/536

Sphynx has a similar concept : https://github.com/ericholscher/sphinx-tutorial/blob/master/step-2.rst#tell-sphinx-about-your-code

vsch commented 5 years ago

@SemanticBeeng, gitlink is too specific. Nothing against gitlink but I can see this being useful with any link to lets say a Java file in the project. The referenced lines automatically inserted in the markdown. I can use it when creating code documentation or explanations for library users. :smile:

The difference between the two examples is the fact that the second example only has the special link on the line, no other text. Adding any text would effectively make the plugin ignore it as a special link and treat it as a simple link. At least I would limit special links to be the last element in a paragraph. That way the fenced code can be inserted right after and no concern has to be given to multiple special links in a paragraph, only the last one.

I would also prefer not to have to determine the info string (language of the fenced code) so how about the following syntax for the special links:

[Any Text](sourceUrlLink "snippet::abc")

This would be rendered as a regular link with embedded code following the link as fenced code and use abc as the info (language) string. This way no part of the rendered link is affected and the link's title contains the special syntax the plugin can use. The only thing other parsers will do with it is add a funny title popup to the link.

I took a quick look at the CommonMark proposed extensions and the code blocks. I stopped following CommonMark discussions because most of the discussions are about "how many angels can dance on a pin head" and never move to real implementations, never testing their ideas against real world implementation issues. I saw no point in most of them because my interest is in implementation and use of extensions not endless debate about trivial merits of one choice over the other. If CommonMark ever gets to version 1.0 and then manages to standardize some extensions then I will address it at that point.

All the proposals for the code block are missing the point because without having a full URL there is a need to specify how to resolve file names to real files. I don't want to go there. Link resolution is complex and having to do it through another mechanism is too masochistic for me.

I will only reuse the existing link resolution mechanism which means the source file has to be given by a link or a link reference. That way I will have the mechanism for resolving the file.

I already implemented using the GitHub #Lxxx-Lyyy anchor ref parsing and implementation in the plugin. If you navigate to the target of such an anchor ref you will not only be taken to the file but will have the lines selected. So the same mechanism can be used to specify the lines to use for the fenced code.