On Sat, Jun 16, 2018 at 03:12:09PM +0100, John Keeping wrote: > > >> 3) You can see on the top level of the tree, the README.md references > > >> > > >> <img alt="lws-overview" src="./doc-assets/lws-overview.png"> > > >> > > >> This url format works in github. In the cgit About view, this resolves > > >> to > > >> > > >> /git/libwebsockets/about/doc-assets/lws-overview.png > > >> > > >> which also serves the right mimetype and content. So that kind of URL > > >> format is useful. But when we render the same markup and relative path > > >> via /tree/, it tries to show an html page containing the content. > > >> That's why the picture is missing in the /tree/ view... other pictures > > >> in that markup are coming with absolute URLs outside of cgit and are > > >> working. > > >> > > >> I can have the direct content from cgit generally, but either the markup > > >> needs fixing up to > > >> > > >> /git/libwebsockets/plain/doc-assets/lws-overview.png > > >> > > >> or /tree/ needs to learn to do what /about/ does. > > >> > > >> I'm wondering whether mmd2html might grow an environment var to know the > > >> base part for URLS that want to direct-render from cgit. Or if better > > >> to follow what /about/ did in /tree/. > > > > > > Making tree do this will break the normal use of tree unless we add some > > > extra query parameter or path element. Given that, I think teaching the > > > renderer to use a path to /about/ is the right thing to do. > > > > OK. Unfortunately I don't know python very well. It looks like the > > markdown python library is able to be told to use extensions that are > > capable to do this > > > > https://python-markdown.github.io/extensions/api/ > > > > from the md2html wrapper. But I don't know enough python to do it. > > > > It's a shame, because in-tree assets correctly follow the ref context > > being viewed, eg, if you look at a v2 branch you see v2 pngs, master you > > see master pngs etc. > > > > I'll "solve" this part for now by changing the README to use external URLs. > > Yeah, I think we have to solve it by having the filter apply a mapping. > We have ui-plain which provides the right content for images, but what > should we do for link targets? > > For the purpose of discussion, consider the following HTML fragment that > could be generated by rendering a README file: > > <img src="dataflow.png"> > <p>For more details see <a href="dataflow.html">the dedicated > data flow document.</p> > > If dataflow.html is generated from a source file in a similar way, then > it doesn't exist in the repository and we can't link to it, so the ideal > output ends up being something like: > > <img src="/repo/plain/dataflow.png"> > <p>For more details see <a href="dataflow.txt">the dedicated > data flow document.</p> > > The render filter API isn't finalised yet, so we can change the > parameters that are passed in order to add more information for the > renderer to use. At the very least I think we should add a parameter > for the asset prefix which is essentially the tree path with /tree/ > replaces with /plain/. > > However, I'm not sure how to handle relative links: do we need to pass > additional parameters for this? Or can we rely on a render filter doing > the right thing?
Modifying md2html to use the extension API is reasonably straightforward. Below is a modified version which remaps the "src" attribute on <img> elements according to a second command line argument, you can try it out with: md2html <README.md README.md /path/to/plain/directory/ The trailing "/" is important. The differences are the AssetMapping classes at the top and the extension setup at the bottom; the rest is unchanged from the version in CGit's source tree. -- >8 -- #!/usr/bin/env python3 import markdown import sys import io from markdown.util import etree from pygments.formatters import HtmlFormatter from urllib.parse import urljoin class AssetMappingProcessor(markdown.treeprocessors.Treeprocessor): def __init__(self, asset_prefix): self.asset_prefix = asset_prefix def run(self, root): asset_prefix = self.asset_prefix for img in root.iter('img'): src = img.get('src') if src is None: continue img.set('src', urljoin(asset_prefix, src)) class AssetMappingExtension(markdown.extensions.Extension): def __init__(self, **kwargs): self.config = {'asset_prefix': ['', 'prefix for relative asset URLs']} super(AssetMappingExtension, self).__init__(**kwargs) def extendMarkdown(self, md, md_globals): asset_prefix = self.getConfig('asset_prefix') if not asset_prefix: return md.treeprocessors.add('asset_mapping', AssetMappingProcessor(asset_prefix), '_end') sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stdout.write(''' <style> .markdown-body { font-size: 14px; line-height: 1.6; overflow: hidden; } .markdown-body>*:first-child { margin-top: 0 !important; } .markdown-body>*:last-child { margin-bottom: 0 !important; } .markdown-body a.absent { color: #c00; } .markdown-body a.anchor { display: block; padding-left: 30px; margin-left: -30px; cursor: pointer; position: absolute; top: 0; left: 0; bottom: 0; } .markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6 { margin: 20px 0 10px; padding: 0; font-weight: bold; -webkit-font-smoothing: antialiased; cursor: text; position: relative; } .markdown-body h1 .mini-icon-link, .markdown-body h2 .mini-icon-link, .markdown-body h3 .mini-icon-link, .markdown-body h4 .mini-icon-link, .markdown-body h5 .mini-icon-link, .markdown-body h6 .mini-icon-link { display: none; color: #000; } .markdown-body h1:hover a.anchor, .markdown-body h2:hover a.anchor, .markdown-body h3:hover a.anchor, .markdown-body h4:hover a.anchor, .markdown-body h5:hover a.anchor, .markdown-body h6:hover a.anchor { text-decoration: none; line-height: 1; padding-left: 0; margin-left: -22px; top: 15%} .markdown-body h1:hover a.anchor .mini-icon-link, .markdown-body h2:hover a.anchor .mini-icon-link, .markdown-body h3:hover a.anchor .mini-icon-link, .markdown-body h4:hover a.anchor .mini-icon-link, .markdown-body h5:hover a.anchor .mini-icon-link, .markdown-body h6:hover a.anchor .mini-icon-link { display: inline-block; } .markdown-body h1 tt, .markdown-body h1 code, .markdown-body h2 tt, .markdown-body h2 code, .markdown-body h3 tt, .markdown-body h3 code, .markdown-body h4 tt, .markdown-body h4 code, .markdown-body h5 tt, .markdown-body h5 code, .markdown-body h6 tt, .markdown-body h6 code { font-size: inherit; } .markdown-body h1 { font-size: 28px; color: #000; } .markdown-body h2 { font-size: 24px; border-bottom: 1px solid #ccc; color: #000; } .markdown-body h3 { font-size: 18px; } .markdown-body h4 { font-size: 16px; } .markdown-body h5 { font-size: 14px; } .markdown-body h6 { color: #777; font-size: 14px; } .markdown-body p, .markdown-body blockquote, .markdown-body ul, .markdown-body ol, .markdown-body dl, .markdown-body table, .markdown-body pre { margin: 15px 0; } .markdown-body hr { background: transparent url("/dirty-shade.png") repeat-x 0 0; border: 0 none; color: #ccc; height: 4px; padding: 0; } .markdown-body>h2:first-child, .markdown-body>h1:first-child, .markdown-body>h1:first-child+h2, .markdown-body>h3:first-child, .markdown-body>h4:first-child, .markdown-body>h5:first-child, .markdown-body>h6:first-child { margin-top: 0; padding-top: 0; } .markdown-body a:first-child h1, .markdown-body a:first-child h2, .markdown-body a:first-child h3, .markdown-body a:first-child h4, .markdown-body a:first-child h5, .markdown-body a:first-child h6 { margin-top: 0; padding-top: 0; } .markdown-body h1+p, .markdown-body h2+p, .markdown-body h3+p, .markdown-body h4+p, .markdown-body h5+p, .markdown-body h6+p { margin-top: 0; } .markdown-body li p.first { display: inline-block; } .markdown-body ul, .markdown-body ol { padding-left: 30px; } .markdown-body ul.no-list, .markdown-body ol.no-list { list-style-type: none; padding: 0; } .markdown-body ul li>:first-child, .markdown-body ul li ul:first-of-type, .markdown-body ul li ol:first-of-type, .markdown-body ol li>:first-child, .markdown-body ol li ul:first-of-type, .markdown-body ol li ol:first-of-type { margin-top: 0px; } .markdown-body ul li p:last-of-type, .markdown-body ol li p:last-of-type { margin-bottom: 0; } .markdown-body ul ul, .markdown-body ul ol, .markdown-body ol ol, .markdown-body ol ul { margin-bottom: 0; } .markdown-body dl { padding: 0; } .markdown-body dl dt { font-size: 14px; font-weight: bold; font-style: italic; padding: 0; margin: 15px 0 5px; } .markdown-body dl dt:first-child { padding: 0; } .markdown-body dl dt>:first-child { margin-top: 0px; } .markdown-body dl dt>:last-child { margin-bottom: 0px; } .markdown-body dl dd { margin: 0 0 15px; padding: 0 15px; } .markdown-body dl dd>:first-child { margin-top: 0px; } .markdown-body dl dd>:last-child { margin-bottom: 0px; } .markdown-body blockquote { border-left: 4px solid #DDD; padding: 0 15px; color: #777; } .markdown-body blockquote>:first-child { margin-top: 0px; } .markdown-body blockquote>:last-child { margin-bottom: 0px; } .markdown-body table th { font-weight: bold; } .markdown-body table th, .markdown-body table td { border: 1px solid #ccc; padding: 6px 13px; } .markdown-body table tr { border-top: 1px solid #ccc; background-color: #fff; } .markdown-body table tr:nth-child(2n) { background-color: #f8f8f8; } .markdown-body img { max-width: 100%; -moz-box-sizing: border-box; box-sizing: border-box; } .markdown-body span.frame { display: block; overflow: hidden; } .markdown-body span.frame>span { border: 1px solid #ddd; display: block; float: left; overflow: hidden; margin: 13px 0 0; padding: 7px; width: auto; } .markdown-body span.frame span img { display: block; float: left; } .markdown-body span.frame span span { clear: both; color: #333; display: block; padding: 5px 0 0; } .markdown-body span.align-center { display: block; overflow: hidden; clear: both; } .markdown-body span.align-center>span { display: block; overflow: hidden; margin: 13px auto 0; text-align: center; } .markdown-body span.align-center span img { margin: 0 auto; text-align: center; } .markdown-body span.align-right { display: block; overflow: hidden; clear: both; } .markdown-body span.align-right>span { display: block; overflow: hidden; margin: 13px 0 0; text-align: right; } .markdown-body span.align-right span img { margin: 0; text-align: right; } .markdown-body span.float-left { display: block; margin-right: 13px; overflow: hidden; float: left; } .markdown-body span.float-left span { margin: 13px 0 0; } .markdown-body span.float-right { display: block; margin-left: 13px; overflow: hidden; float: right; } .markdown-body span.float-right>span { display: block; overflow: hidden; margin: 13px auto 0; text-align: right; } .markdown-body code, .markdown-body tt { margin: 0 2px; padding: 0px 5px; border: 1px solid #eaeaea; background-color: #f8f8f8; border-radius: 3px; } .markdown-body code { white-space: nowrap; } .markdown-body pre>code { margin: 0; padding: 0; white-space: pre; border: none; background: transparent; } .markdown-body .highlight pre, .markdown-body pre { background-color: #f8f8f8; border: 1px solid #ccc; font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-radius: 3px; } .markdown-body pre code, .markdown-body pre tt { margin: 0; padding: 0; background-color: transparent; border: none; } ''') sys.stdout.write(HtmlFormatter(style='pastie').get_style_defs('.highlight')) sys.stdout.write(''' </style> ''') sys.stdout.write("<div class='markdown-body'>") sys.stdout.flush() extensions = [ "markdown.extensions.fenced_code", "markdown.extensions.codehilite", "markdown.extensions.tables" ] extension_configs = { "markdown.extensions.codehilite":{"css_class":"highlight"} } if len(sys.argv) > 2: extensions.append(AssetMappingExtension(asset_prefix=sys.argv[2])) # Note: you may want to run this through bleach for sanitization markdown.markdownFromFile(output_format="html5", extensions=extensions, extension_configs=extension_configs) sys.stdout.write("</div>") _______________________________________________ CGit mailing list CGit@lists.zx2c4.com https://lists.zx2c4.com/mailman/listinfo/cgit