Browse code

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

Brandon Mathis authored on 07/09/2011 at 23:32:57
Showing 7 changed files
... ...
@@ -5,7 +5,7 @@
5 5
   <nav role=navigation>{% include navigation.html %}</nav>
6 6
   <div id="main">
7 7
     <div id="content">
8
-      {{ content | expand_urls: root_url | backtick_codeblock | smart_quotes }}
8
+      {{ content | expand_urls: root_url }}
9 9
     </div>
10 10
   </div>
11 11
   <footer>{% include footer.html %}</footer>
12 12
new file mode 100644
... ...
@@ -0,0 +1,42 @@
0
+require './plugins/pygments_code'
1
+
2
+module BacktickCodeBlock
3
+  include HighlightCode
4
+  AllOptions = /([^\s]+)\s+(.+?)(https?:\/\/\S+)\s*(.+)?/i
5
+  LangCaption = /([^\s]+)\s*(.+)?/i
6
+  def render_code_block(input)
7
+    @caption = nil
8
+    @lang = nil
9
+    @url = nil
10
+    @title = nil
11
+    input.gsub /^`{3} *([^\n]+)?\n(.+?)\n`{3}/m do
12
+      options = $1
13
+      str = $2
14
+
15
+      if options =~ AllOptions
16
+        @lang = $1
17
+        @caption = "<figcaption><span>#{$2}</span><a href='#{$3}'>#{$4 || 'link'}</a></figcaption>"
18
+      elsif options =~ LangCaption
19
+        @lang = $1
20
+        @caption = "<figcaption><span>#{$2}</span></figcaption>"
21
+      end
22
+
23
+      if str.match(/\A {4}/)
24
+        str = str.gsub /^ {4}/, ''
25
+      end
26
+      if @lang.nil? || @lang == 'plain'
27
+        code = tableize_code(str.gsub('<','&lt;').gsub('>','&gt;'))
28
+        "<figure role=code>#{@caption}#{code}</figure>"
29
+      else
30
+        if @lang.include? "-raw"
31
+          raw = "``` #{@lang.sub('-raw', '')}\n"
32
+          raw += str
33
+          raw += "\n```\n"
34
+        else
35
+          code = highlight(str, @lang)
36
+          "<figure role=code>#{@caption}#{code}</figure>"
37
+        end
38
+      end
39
+    end
40
+  end
41
+end
... ...
@@ -42,11 +42,13 @@
42 42
 # </figure>
43 43
 #
44 44
 require './plugins/pygments_code'
45
+require './plugins/raw'
45 46
 
46 47
 module Jekyll
47 48
 
48 49
   class CodeBlock < Liquid::Block
49 50
     include HighlightCode
51
+    include TemplateWrapper
50 52
     CaptionUrlTitle = /(\S[\S\s]*)\s+(https?:\/\/)(\S+)\s+(.+)/i
51 53
     CaptionUrl = /(\S[\S\s]*)\s+(https?:\/\/)(\S+)/i
52 54
     Caption = /(\S[\S\s]*)/
... ...
@@ -78,14 +80,15 @@ module Jekyll
78 78
     def render(context)
79 79
       output = super
80 80
       code = super.join
81
-      source = "<div><figure role=code>"
81
+      source = "<figure role=code>"
82 82
       source += @caption if @caption
83
-      source = context['pygments_prefix'] + source if context['pygments_prefix']
84 83
       if @filetype
85
-        source += " #{highlight(code, @filetype)}</figure></div>"
84
+        source += " #{highlight(code, @filetype)}</figure>"
86 85
       else
87
-        source += "#{tableize_code(code.lstrip.rstrip.gsub(/</,'&lt;'))}</figure></div>"
86
+        source += "#{tableize_code(code.lstrip.rstrip.gsub(/</,'&lt;'))}</figure>"
88 87
       end
88
+      source = safe_wrap(source)
89
+      source = context['pygments_prefix'] + source if context['pygments_prefix']
89 90
       source = source + context['pygments_suffix'] if context['pygments_suffix']
90 91
     end
91 92
   end
... ...
@@ -21,12 +21,14 @@
21 21
 #
22 22
 
23 23
 require './plugins/pygments_code'
24
+require './plugins/raw'
24 25
 require 'pathname'
25 26
 
26 27
 module Jekyll
27 28
 
28 29
   class IncludeCodeTag < Liquid::Tag
29 30
     include HighlightCode
31
+    include TemplateWrapper
30 32
     def initialize(tag_name, markup, tokens)
31 33
       @title = nil
32 34
       @file = nil
... ...
@@ -59,8 +61,9 @@ module Jekyll
59 59
         @filetype = file.extname.sub('.','') if @filetype.nil?
60 60
         title = @title ? "#{@title} (#{file.basename})" : file.basename
61 61
         url = "/#{code_dir}/#{@file}"
62
-        source = "<div><figure role=code><figcaption><span>#{title}</span> <a href='#{url}'>download</a></figcaption>\n"
63
-        source += " #{highlight(code, @filetype)}</figure></div>"
62
+        source = "<figure role=code><figcaption><span>#{title}</span> <a href='#{url}'>download</a></figcaption>\n"
63
+        source += " #{highlight(code, @filetype)}</figure>"
64
+        safe_wrap(source)
64 65
       end
65 66
     end
66 67
   end
... ...
@@ -1,8 +1,38 @@
1 1
 #custom filters for Octopress
2
-require './plugins/pygments_code'
2
+require './plugins/backtick_code_block'
3
+require './plugins/post_filters'
4
+require './plugins/raw'
5
+require 'rubypants'
3 6
 
4 7
 module OctopressFilters
5
-  include HighlightCode
8
+  include BacktickCodeBlock
9
+  include TemplateWrapper
10
+  def pre_filter(input)
11
+    input = render_code_block(input)
12
+    input.gsub /(<figure.+?>.+?<\/figure>)/m do
13
+      safe_wrap($1)
14
+    end
15
+  end
16
+  def post_filter(input)
17
+    input = unwrap(input)
18
+    RubyPants.new(input).to_html
19
+  end
20
+end
21
+
22
+module Jekyll
23
+  class ContentFilters < PostFilter
24
+    include OctopressFilters
25
+    def pre_render(post)
26
+      post.content = pre_filter(post.content)
27
+    end
28
+    def post_render(post)
29
+      post.content = post_filter(post.content)
30
+    end
31
+  end
32
+end
33
+
34
+
35
+module OctopressLiquidFilters
6 36
   # Used on the blog index to split posts on the <!--more--> marker
7 37
   def excerpt(input)
8 38
     if input.index(/<!--\s*more\s*-->/i)
... ...
@@ -26,45 +56,6 @@ module OctopressFilters
26 26
     end
27 27
   end
28 28
 
29
-  # for Github style codeblocks eg.
30
-  # ``` ruby
31
-  #     code snippet
32
-  # ```
33
-  def backtick_codeblock(input)
34
-    code = nil
35
-    # Markdown support
36
-    input = input.gsub /<p>`{3}\s*(\w+)?<\/p>\s*<pre><code>\s*(.+?)\s*<\/code><\/pre>\s*<p>`{3}<\/p>/m do
37
-      lang = $1
38
-      if lang != ''
39
-        str  = $2.gsub('&lt;','<').gsub('&gt;','>').gsub('&amp;','&')
40
-        code = highlight(str, lang)
41
-        "<figure role=code>#{code}</figure>"
42
-      else
43
-        code = tableize_code($2)
44
-        "<figure role=code>#{code}</figure>"
45
-      end
46
-    end
47
-
48
-    # Textile warning
49
-    input = input.gsub /<p>`{3}\s*(\w+)?<br\s*\/>\n(.+?)`{3}<\/p>/m do
50
-      lang = $1
51
-      "<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>"
52
-    end
53
-
54
-    # Regular HTML support
55
-    input.gsub /^`{3}\s*(\w+)?\n(.+?)\n`{3}/m do
56
-      lang = $1
57
-      str  = $2.gsub(/^\s{4}/, '')
58
-      if lang != ''
59
-        code = highlight(str, lang)
60
-        "<figure role=code>#{code}</figure>"
61
-      else
62
-        code = tableize_code($2.gsub('<','&lt;').gsub('>','&gt;'))
63
-        "<figure role=code>#{code}</figure>"
64
-      end
65
-    end
66
-  end
67
-
68 29
   # Replaces relative urls with full urls
69 30
   def expand_urls(input, url='')
70 31
     url ||= '/'
... ...
@@ -88,12 +79,6 @@ module OctopressFilters
88 88
     end
89 89
   end
90 90
 
91
-  # replaces primes with smartquotes using RubyPants
92
-  def smart_quotes(input)
93
-    require 'rubypants'
94
-    RubyPants.new(input).to_html
95
-  end
96
-
97 91
   # Returns a title cased string based on John Gruber's title case http://daringfireball.net/2008/08/title_case_update
98 92
   def titlecase(input)
99 93
     input.titlecase
... ...
@@ -127,5 +112,5 @@ module OctopressFilters
127 127
     end
128 128
   end
129 129
 end
130
-Liquid::Template.register_filter OctopressFilters
130
+Liquid::Template.register_filter OctopressLiquidFilters
131 131
 
... ...
@@ -1,3 +1,19 @@
1
+# Author: Brandon Mathis
2
+# Description: Provides plugins with a method for wrapping and unwrapping input to prevent Markdown and Textile from parsing it.
3
+# Purpose: This is useful for preventing Markdown and Textile from being too aggressive and incorrectly parsing in-line HTML.
4
+module TemplateWrapper
5
+  # Wrap input with a <div>
6
+  def safe_wrap(input)
7
+    "<div class='bogus-wrapper'><notextile>#{input}</notextile></div>"
8
+  end
9
+  # This must be applied after the
10
+  def unwrap(input)
11
+    input.gsub /<div class='bogus-wrapper'><notextile>(.+?)<\/notextile><\/div>/m do
12
+      $1
13
+    end
14
+  end
15
+end
16
+
1 17
 # Author: phaer, https://github.com/phaer
2 18
 # Source: https://gist.github.com/1020852
3 19
 # Description: Raw tag for jekyll. Keeps liquid from parsing text betweeen {% raw %} and {% endraw %}
... ...
@@ -22,10 +22,12 @@
22 22
 #
23 23
 
24 24
 require 'pathname'
25
+require './plugins/octopress_filters'
25 26
 
26 27
 module Jekyll
27 28
 
28 29
   class RenderPartialTag < Liquid::Tag
30
+    include OctopressFilters
29 31
     def initialize(tag_name, markup, tokens)
30 32
       @file = nil
31 33
       @raw = false
... ...
@@ -50,6 +52,7 @@ module Jekyll
50 50
         if contents =~ /\A-{3}.+[^\A]-{3}\n(.+)/m
51 51
           contents = $1.lstrip
52 52
         end
53
+        contents = pre_filter(contents)
53 54
         if @raw
54 55
           contents
55 56
         else