1. Vastly improved backtick code blocks and added support for Textile

2. Refactored Octopress filters into Liquid filters and pre/post render filters (using post_filters plugin)
3. Added methods to raw plugin to prevent Markdown and Textile from parsing blocks
4. Updated render partial to invoke the pre_render method of post_filters
5. Moved Rubypants filter out of default.html into Octopress post_render filters
6. Added raw's safe_wrapper method to codeblock and include_code filters
This commit is contained in:
Brandon Mathis 2011-09-07 18:32:57 -05:00
parent b25db54f93
commit 3d2d1a8be4
7 changed files with 107 additions and 55 deletions

View File

@ -5,7 +5,7 @@
<nav role=navigation>{% include navigation.html %}</nav> <nav role=navigation>{% include navigation.html %}</nav>
<div id="main"> <div id="main">
<div id="content"> <div id="content">
{{ content | expand_urls: root_url | backtick_codeblock | smart_quotes }} {{ content | expand_urls: root_url }}
</div> </div>
</div> </div>
<footer>{% include footer.html %}</footer> <footer>{% include footer.html %}</footer>

View File

@ -0,0 +1,42 @@
require './plugins/pygments_code'
module BacktickCodeBlock
include HighlightCode
AllOptions = /([^\s]+)\s+(.+?)(https?:\/\/\S+)\s*(.+)?/i
LangCaption = /([^\s]+)\s*(.+)?/i
def render_code_block(input)
@caption = nil
@lang = nil
@url = nil
@title = nil
input.gsub /^`{3} *([^\n]+)?\n(.+?)\n`{3}/m do
options = $1
str = $2
if options =~ AllOptions
@lang = $1
@caption = "<figcaption><span>#{$2}</span><a href='#{$3}'>#{$4 || 'link'}</a></figcaption>"
elsif options =~ LangCaption
@lang = $1
@caption = "<figcaption><span>#{$2}</span></figcaption>"
end
if str.match(/\A {4}/)
str = str.gsub /^ {4}/, ''
end
if @lang.nil? || @lang == 'plain'
code = tableize_code(str.gsub('<','&lt;').gsub('>','&gt;'))
"<figure role=code>#{@caption}#{code}</figure>"
else
if @lang.include? "-raw"
raw = "``` #{@lang.sub('-raw', '')}\n"
raw += str
raw += "\n```\n"
else
code = highlight(str, @lang)
"<figure role=code>#{@caption}#{code}</figure>"
end
end
end
end
end

View File

@ -42,11 +42,13 @@
# </figure> # </figure>
# #
require './plugins/pygments_code' require './plugins/pygments_code'
require './plugins/raw'
module Jekyll module Jekyll
class CodeBlock < Liquid::Block class CodeBlock < Liquid::Block
include HighlightCode include HighlightCode
include TemplateWrapper
CaptionUrlTitle = /(\S[\S\s]*)\s+(https?:\/\/)(\S+)\s+(.+)/i CaptionUrlTitle = /(\S[\S\s]*)\s+(https?:\/\/)(\S+)\s+(.+)/i
CaptionUrl = /(\S[\S\s]*)\s+(https?:\/\/)(\S+)/i CaptionUrl = /(\S[\S\s]*)\s+(https?:\/\/)(\S+)/i
Caption = /(\S[\S\s]*)/ Caption = /(\S[\S\s]*)/
@ -78,14 +80,15 @@ module Jekyll
def render(context) def render(context)
output = super output = super
code = super.join code = super.join
source = "<div><figure role=code>" source = "<figure role=code>"
source += @caption if @caption source += @caption if @caption
source = context['pygments_prefix'] + source if context['pygments_prefix']
if @filetype if @filetype
source += " #{highlight(code, @filetype)}</figure></div>" source += " #{highlight(code, @filetype)}</figure>"
else else
source += "#{tableize_code(code.lstrip.rstrip.gsub(/</,'&lt;'))}</figure></div>" source += "#{tableize_code(code.lstrip.rstrip.gsub(/</,'&lt;'))}</figure>"
end end
source = safe_wrap(source)
source = context['pygments_prefix'] + source if context['pygments_prefix']
source = source + context['pygments_suffix'] if context['pygments_suffix'] source = source + context['pygments_suffix'] if context['pygments_suffix']
end end
end end

View File

@ -21,12 +21,14 @@
# #
require './plugins/pygments_code' require './plugins/pygments_code'
require './plugins/raw'
require 'pathname' require 'pathname'
module Jekyll module Jekyll
class IncludeCodeTag < Liquid::Tag class IncludeCodeTag < Liquid::Tag
include HighlightCode include HighlightCode
include TemplateWrapper
def initialize(tag_name, markup, tokens) def initialize(tag_name, markup, tokens)
@title = nil @title = nil
@file = nil @file = nil
@ -59,8 +61,9 @@ module Jekyll
@filetype = file.extname.sub('.','') if @filetype.nil? @filetype = file.extname.sub('.','') if @filetype.nil?
title = @title ? "#{@title} (#{file.basename})" : file.basename title = @title ? "#{@title} (#{file.basename})" : file.basename
url = "/#{code_dir}/#{@file}" url = "/#{code_dir}/#{@file}"
source = "<div><figure role=code><figcaption><span>#{title}</span> <a href='#{url}'>download</a></figcaption>\n" source = "<figure role=code><figcaption><span>#{title}</span> <a href='#{url}'>download</a></figcaption>\n"
source += " #{highlight(code, @filetype)}</figure></div>" source += " #{highlight(code, @filetype)}</figure>"
safe_wrap(source)
end end
end end
end end

View File

@ -1,8 +1,38 @@
#custom filters for Octopress #custom filters for Octopress
require './plugins/pygments_code' require './plugins/backtick_code_block'
require './plugins/post_filters'
require './plugins/raw'
require 'rubypants'
module OctopressFilters module OctopressFilters
include HighlightCode include BacktickCodeBlock
include TemplateWrapper
def pre_filter(input)
input = render_code_block(input)
input.gsub /(<figure.+?>.+?<\/figure>)/m do
safe_wrap($1)
end
end
def post_filter(input)
input = unwrap(input)
RubyPants.new(input).to_html
end
end
module Jekyll
class ContentFilters < PostFilter
include OctopressFilters
def pre_render(post)
post.content = pre_filter(post.content)
end
def post_render(post)
post.content = post_filter(post.content)
end
end
end
module OctopressLiquidFilters
# Used on the blog index to split posts on the <!--more--> marker # Used on the blog index to split posts on the <!--more--> marker
def excerpt(input) def excerpt(input)
if input.index(/<!--\s*more\s*-->/i) if input.index(/<!--\s*more\s*-->/i)
@ -26,45 +56,6 @@ module OctopressFilters
end end
end end
# for Github style codeblocks eg.
# ``` ruby
# code snippet
# ```
def backtick_codeblock(input)
code = nil
# Markdown support
input = input.gsub /<p>`{3}\s*(\w+)?<\/p>\s*<pre><code>\s*(.+?)\s*<\/code><\/pre>\s*<p>`{3}<\/p>/m do
lang = $1
if lang != ''
str = $2.gsub('&lt;','<').gsub('&gt;','>').gsub('&amp;','&')
code = highlight(str, lang)
"<figure role=code>#{code}</figure>"
else
code = tableize_code($2)
"<figure role=code>#{code}</figure>"
end
end
# Textile warning
input = input.gsub /<p>`{3}\s*(\w+)?<br\s*\/>\n(.+?)`{3}<\/p>/m do
lang = $1
"<pre><code>Back tick code blocks are not supported for Textile.\nTry HTML or Markdown instead or use the codeblock tag.\n\n{% codeblock #{lang} %}\nYour code snippet\n{% endcodeblock %}</code></pre>"
end
# Regular HTML support
input.gsub /^`{3}\s*(\w+)?\n(.+?)\n`{3}/m do
lang = $1
str = $2.gsub(/^\s{4}/, '')
if lang != ''
code = highlight(str, lang)
"<figure role=code>#{code}</figure>"
else
code = tableize_code($2.gsub('<','&lt;').gsub('>','&gt;'))
"<figure role=code>#{code}</figure>"
end
end
end
# Replaces relative urls with full urls # Replaces relative urls with full urls
def expand_urls(input, url='') def expand_urls(input, url='')
url ||= '/' url ||= '/'
@ -88,12 +79,6 @@ module OctopressFilters
end end
end end
# replaces primes with smartquotes using RubyPants
def smart_quotes(input)
require 'rubypants'
RubyPants.new(input).to_html
end
# Returns a title cased string based on John Gruber's title case http://daringfireball.net/2008/08/title_case_update # Returns a title cased string based on John Gruber's title case http://daringfireball.net/2008/08/title_case_update
def titlecase(input) def titlecase(input)
input.titlecase input.titlecase
@ -127,5 +112,5 @@ module OctopressFilters
end end
end end
end end
Liquid::Template.register_filter OctopressFilters Liquid::Template.register_filter OctopressLiquidFilters

View File

@ -1,3 +1,19 @@
# Author: Brandon Mathis
# Description: Provides plugins with a method for wrapping and unwrapping input to prevent Markdown and Textile from parsing it.
# Purpose: This is useful for preventing Markdown and Textile from being too aggressive and incorrectly parsing in-line HTML.
module TemplateWrapper
# Wrap input with a <div>
def safe_wrap(input)
"<div class='bogus-wrapper'><notextile>#{input}</notextile></div>"
end
# This must be applied after the
def unwrap(input)
input.gsub /<div class='bogus-wrapper'><notextile>(.+?)<\/notextile><\/div>/m do
$1
end
end
end
# Author: phaer, https://github.com/phaer # Author: phaer, https://github.com/phaer
# Source: https://gist.github.com/1020852 # Source: https://gist.github.com/1020852
# Description: Raw tag for jekyll. Keeps liquid from parsing text betweeen {% raw %} and {% endraw %} # Description: Raw tag for jekyll. Keeps liquid from parsing text betweeen {% raw %} and {% endraw %}

View File

@ -22,10 +22,12 @@
# #
require 'pathname' require 'pathname'
require './plugins/octopress_filters'
module Jekyll module Jekyll
class RenderPartialTag < Liquid::Tag class RenderPartialTag < Liquid::Tag
include OctopressFilters
def initialize(tag_name, markup, tokens) def initialize(tag_name, markup, tokens)
@file = nil @file = nil
@raw = false @raw = false
@ -50,6 +52,7 @@ module Jekyll
if contents =~ /\A-{3}.+[^\A]-{3}\n(.+)/m if contents =~ /\A-{3}.+[^\A]-{3}\n(.+)/m
contents = $1.lstrip contents = $1.lstrip
end end
contents = pre_filter(contents)
if @raw if @raw
contents contents
else else