8659ef2c4757

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.
[view raw] [browse files]
author Chris Eldredge <chris.eldredge@gmail.com>
date Mon, 13 Aug 2012 18:33:12 +0100
parents 1d3416da68e0
children 737c9dda302a
branches/tags (none)
files __init__.py mdx_urlrebase.py

Changes

--- 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')
--- 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