# HG changeset patch # User Chris Eldredge # Date 1344879192 -3600 # Node ID 8659ef2c4757c892fe48f194c46c2f6d18f8cebd # Parent 1d3416da68e052588f4c60daa512e6a9b2031151 Replace /markdown/_preview/ URL pattern with simpler /preview/ pattern. Wrap default "file" web command with one that redirects to markdown view for .md and .markdown files. Dynamically rebase img links to /rawfile to allow images to be embedded. diff -r 1d3416da68e0 -r 8659ef2c4757 __init__.py --- a/__init__.py Thu Aug 09 23:47:58 2012 +0100 +++ b/__init__.py Mon Aug 13 18:33:12 2012 +0100 @@ -4,30 +4,81 @@ # If using TortoiseHg, obtain Python-Markdown and tell Python where to find it: #sys.path.append("c:/python27/Lib/site-packages/markdown-2.2.0-py2.7.egg") -import markdown +import logging, markdown, mimetypes +from mercurial import extensions, encoding, util from mercurial.hgweb import webcommands, webutil, common -from mercurial import extensions, encoding, util -import logging +from mercurial.hgweb.common import ErrorResponse, HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND +import mdx_urlrebase + logging.basicConfig() -def filerevision_markdown(web, req, tmpl): +def preview_markdown(web, req, tmpl): + f = req.form.get('node', [''])[0] + path = req.form.get('file', [''])[0] + if path: + f = f + '/' + path + + if not f: + f = find_working_copy_readme(web.repo.root) + + parts = os.path.splitext(f) + + try: + text = file(web.repo.root + "/" + f, "rb").read() + except IOError: + raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + f) + + if not parts[1] == '.markdown' and not parts[1] == '.md': + return preview_sendraw(web, req, f, text) + + md = markdown.Markdown(extensions=['wikilinks(base_url={0},end_url={1})'.format('', parts[1])]) + html = md.convert(text) + + args = {'file':f, + 'readmefilename':parts[0].split('/')[-1], + 'path':webutil.up(f), + 'readme':html, + 'rev':'PREVIEW', + 'node':'PREVIEW'} + + return tmpl("markdown", **args) + +def preview_sendraw(web, req, path, data): + guessmime = web.configbool('web', 'guessmime', False) + + if util.binary(data): + mt = 'application/binary' + else: + mt = 'text/plain' + + if guessmime: + mt = mimetypes.guess_type(path)[0] + if mt is None: + mt = binary(text) and 'application/binary' or 'text/plain' + if mt.startswith('text/'): + mt += '; charset="%s"' % encoding.encoding + + req.respond(HTTP_OK, mt, path, len(data)) + return [data] + +def file_markdown(orig, web, req, tmpl): f = req.form.get('file', [''])[0] parts = os.path.splitext(f) - - if not parts[1] == '.markdown' and not parts[1] == '.md': - return rawfile(web, req, tmpl) - previewMode = 'node' in req.form and req.form['node'][0] == '_preview' - - if previewMode: - text = file(web.repo.root + "/" + f).read() - else: + try: fctx = webutil.filectx(web.repo, req) text = fctx.data() - + except LookupError, inst: + try: + return webcommands.manifest(web, req, tmpl) + except ErrorResponse: + raise inst + if util.binary(text): - # todo: handle preview mode - return rawfile(web, req, tmpl) + return webcommands.rawfile(web, req, tmpl) + + if not parts[1] == '.markdown' and not parts[1] == '.md': + return orig(web, req, tmpl) md = markdown.Markdown(extensions=['wikilinks(base_url={0},end_url={1})'.format('', parts[1])]) html = md.convert(text) @@ -37,22 +88,24 @@ 'path':webutil.up(f), 'readme':html} - if previewMode: - args.update({'rev':'PREVIEW', 'node':'PREVIEW'}) - else: - args.update({'rev':fctx.rev(), - 'node':fctx.hex(), - 'author':fctx.user(), - 'date':fctx.date(), - 'desc':fctx.description(), - 'branch':webutil.nodebranchnodefault(fctx), - 'parent':webutil.parents(fctx), - 'child':webutil.children(fctx)}) + args.update({'rev':fctx.rev(), + 'node':fctx.hex(), + 'author':fctx.user(), + 'date':fctx.date(), + 'desc':fctx.description(), + 'branch':webutil.nodebranchnodefault(fctx), + 'parent':webutil.parents(fctx), + 'child':webutil.children(fctx)}) return tmpl("markdown", **args) def summary_markdown(orig, web, req, tmpl): - changeid = 'default' # todo: add hgrc config setting + """ + Decorates the default summary view by adding 'readme' and 'readmefile' content + to the template. + """ + + changeid = web.config('web', 'markdown.changeid', 'tip') previewMode = False text = None @@ -67,11 +120,22 @@ if text: ext = os.path.splitext(readmefile)[1] - base_url = tmpl.defaults['url'] + 'markdown/' + changeid + "/" + base_url = tmpl.defaults['url'] + 'file/' + changeid + "/" + base_raw_url = tmpl.defaults['url'] + 'rawfile/' + changeid + "/" + + def rebase(proc, e, attr): + uri = e.get(attr, '') + if '://' in uri or uri.startswith('/'): + return + base = base_url + if attr == 'src': + base = base_raw_url + e.set(attr, proc.rebase(base, uri)) + + ext = mdx_urlrebase.UrlRebaseExtension(configs=[('rebase', rebase)]) md = markdown.Markdown( - extensions=['urlrebase', 'wikilinks'], + extensions=[ext, 'wikilinks'], extension_configs={ - 'urlrebase' : [('base_url', base_url)], 'wikilinks' : [('base_url', base_url), ('end_url', ext)]}) readme = md.convert(text) else: @@ -83,12 +147,13 @@ return orig(web, req, tmpl) -def find_working_copy_readme(repo): - for filename in os.listdir(repo.root): +def find_working_copy_readme(dir): + for filename in os.listdir(dir): if filename.lower() == 'readme.md' or filename.lower() == 'readme.markdown': return filename def extsetup(): + extensions.wrapfunction(webcommands, 'file', file_markdown) extensions.wrapfunction(webcommands, 'summary', summary_markdown) - webcommands.markdown = filerevision_markdown - webcommands.__all__.append('markdown') + webcommands.preview = preview_markdown + webcommands.__all__.append('preview') diff -r 1d3416da68e0 -r 8659ef2c4757 mdx_urlrebase.py --- a/mdx_urlrebase.py Thu Aug 09 23:47:58 2012 +0100 +++ b/mdx_urlrebase.py Mon Aug 13 18:33:12 2012 +0100 @@ -4,6 +4,7 @@ def __init__ (self, configs): # set extension defaults self.config = { + 'rebase' : [None, 'Callable to rebase elementes with custom logic.'], 'base_url' : ['/', 'String to append to beginning or URL.'], } @@ -21,15 +22,23 @@ self.config = config def run(self, root): + rebase = self.rebase_element + if "rebase" in self.config: + rebase = self.config["rebase"] + for a in root.findall(".//a"): - uri = a.get('href', '') - if '://' in uri or uri.startswith('/'): - continue - a.set('href', self.rebase(uri)) + rebase(self, a, 'href') + for i in root.findall(".//img"): + rebase(self, i, 'src') return root - def rebase(self, uri): - base = self.config['base_url'] + def rebase_element(self, also_self, e, attr): + uri = e.get(attr, '') + if '://' in uri or uri.startswith('/'): + return + e.set(attr, self.rebase(uri)) + + def rebase(self, base, uri): if base[0] and not base.endswith('/'): base = base + '/' return base + uri