Update: - Spurred on by Daniel Nouri, configuration examples have been upgraded to 0.7.
I'm having a completely great time with Blogofile. Publishing the whole site static and in one step, letting Disqus handle all the community is so much better than worrying about upgrades and spam. I've noticed some other folks using Blogofile and I wanted to share the key changes I used to make it work the way I want. Ideally, Blogofile itself could provide these features since they are pretty basic; I'm being somewhat lazy by just posting them here rather than requesting features via the BF mailing list, but the changes aren't generic to a plain Blogofile install so they would need to be "featurized" in order to be part of Blogofile's default setup. Until then, these adjustments work right now for an 0.6 installation.
Getting Syntax Highlighting to work with ReST
We're all using Sphinx for our docs now so we've all become experts at Restructured Text. I know this because I can actually type out `[text] <[hyperlink]>`_ from memory. Blogofile supports .rst but the syntax highlighting that's included appears to be tailored towards Markdown. My approach here to allow .rst highlighting is not as nice as that of Sphinx since I continue to be very mystified by Docutils, but it gets the job done.
Step 1 - Put the RST Filter First
We'll be using Docutils' built in system of :: followed by indentation to establish a code block, so the syntax highlighter will detect the HTML generated, instead of Blogofile's default approach of using a special tag $$code(lang=python) which doesn't make it through the rst parser in any case (in fact it's the Pygments HTML the filter generates that doesn't). Change the order in _config.py as follows:
blog.post_default_filters = { "rst": "rst, syntax_highlight" }
Step 2 - New Syntax Filter
I don't need a lot of options in my code blocks other than what language is in use. Below is a simplified syntax_highlight.py that looks for a language name using a comment of the form #!<language name>:
import re import os from pygments import util, formatters, lexers, highlight import blogofile_bf as bf css_files_written = set() code_block_re = re.compile( r"<pre class=\"literal-block\">\n" r"(?:#\!(?P<lang>\w+)\n)?" r"(?P<code>.*?)" r"</pre>", re.DOTALL ) def highlight_code(code, language, formatter): try: lexer = lexers.get_lexer_by_name(language) except util.ClassNotFound: lexer = lexers.get_lexer_by_name("text") highlighted = "\n\n" + \ highlight(code, lexer, formatter) + \ "\n\n" return highlighted def write_pygments_css(style, formatter, location="/css"): path = bf.util.path_join("_site",bf.util.fs_site_path_helper(location)) bf.util.mkdir(path) css_path = os.path.join(path,"pygments_"+style+".css") if css_path in css_files_written: return #already written, no need to overwrite it. f = open(css_path,"w") f.write(formatter.get_style_defs(".pygments_"+style)) f.close() css_files_written.add(css_path) from mako.filters import html_entities_unescape def run(src): style = bf.config.filters.syntax_highlight.style css_class = "pygments_"+style formatter = formatters.HtmlFormatter( linenos=False, cssclass=css_class, style=style) write_pygments_css(style,formatter) def repl(m): lang = m.group('lang') code = m.group('code') code = html_entities_unescape(code) return highlight_code(code,lang,formatter) return code_block_re.sub(repl, src)
That's it. All you do now when writing a code example:
This is some blog text. Some code:: #!python print "hello world"
Permalinks
Blogofile's auto-permalink regular expression needs some serious help. Any kind of punctuation characters or whatever just get dumped into the URL, and there's no hook to change how the auto-permalink generation works. We definitely don't want to have to type permalinks into all our posts that look just like the titles.
With Blogofile 0.6, I had a post-processor in the 0.initial.py controller file that rewrote the permalink on each Post object. As of Blogofile 0.7, the 0.initial.py controller seems to be gone, but the Post class is now part of the blog buildout in the file _controllers/blog/post.py, allowing you to change how things are done. So inside the __post_process() method of Post, I replace the "slug" generation code with the following:
--- _controllers/blog/post.py +++ _controllers/blog/post.py @@ -166,7 +168,24 @@ datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) if not self.slug: - self.slug = re.sub("[ ?]", "-", self.title).lower() + + ########## THIS CODE ADDED FOR TECHSPOT ############# + slug = self.title.lower() + + # convert ellipses to spaces + slug = re.sub(r'\.{2,}', ' ', slug) + + # flatten everything non alpha or . into a single - + slug = re.sub(r'[^0-9a-zA-Z\.]+', '-', slug) + + # trim off leading/trailing - + slug = re.sub(r'^-+|-+$', '', slug) + self.slug = slug + + ####################################################### + + # original + #self.slug = re.sub("[ ?]", "-", self.title).lower()
This allows the blog.auto_permalink.path configuration in _config.py to remain at "/:year/:month/:day/:title", and special characters will be nicely treated in permalinks.
You need to have permalink generation turned on for the above to work - if your posts don't have permalinks inside them, they don't appear to be generated otherwise.
Hope these are helpful and happy static file blogging !