The automatic gist!

One thing I wish for any blog platform is the ability to automatically gist all of the code snippets found in a particular blog entry.

I find it very strange that NOBODY (that I know of) has really publicly implemented this as a solution to “gists” for bloggers. The only implementation that I know of was privately announced on a post by Ben Nadel but since then I’ve not found anyone else…

The reason Ben and I like to handle Gists this way is because sometimes your blogs code snippets are better served from your blog… giving you the freedom to later switch syntax highlighters and keep your code indexed within your own blog database or flat files. Removing this dependency on github’s javascript loader, and lettings your code snippets render regardless if github is a slug today or not.

Since I just started using Octopress I’ve decided I’m going to take a stab at implementing this.

Project requirements

  • Fastest and simplest way is to just use the gist gem which offers a command line method for posting gists.
  • Each gist is unique to the post
  • Some sort of unique identifier needs to be referenced everytime a gist is created / updated as to not keep creating new unique gists everytime you compile your Octopress blog.
  • rake generate should handle the gist creation commands, I’m thinking this would be somewhere in the backtick_code_block.rb

WARNING: All code is conceptual, do not use it yet! I’m just brainstorming in this entry…

Modify Octopress Backtick Code Block Plugin

I’m not certain I should be modifying this plugin to make this work but I’m a total Ruby n00b so I’m just finding a nice place to put my thoughts. I’m certain this will end up becoming it’s own plugin.

#!ruby
require './plugins/pygments_code'

module BacktickCodeBlock
  include HighlightCode
  AllOptions = /([^\s]+)\s+(.+?)(https?:\/\/\S+)\s*(.+)?/i
  LangCaption = /([^\s]+)\s*(.+)?/i
  def render_code_block(input)
    @options = nil
    @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}|\t)/)
        str = str.gsub(/^( {4}|\t)/, '')
      end
      if @lang.nil? || @lang == 'plain'
        code = tableize_code(str.gsub('<','&lt;').gsub('>','&gt;'))
        "<figure class='code'>#{@caption}#{code}</figure>"

        system "echo ""#{code}"" | gist -t plain"
      else
        if @lang.include? "-raw"
          raw = "``` #{@options.sub('-raw', '')}\n"
          raw += str
          raw += "\n```\n"
        else
          code = highlight(str, @lang)
          "<figure class='code'>#{@caption}#{code}</figure>"

          system "echo ""#{str}"" | gist -t #{@lang}"
        end
      end
    end
  end
end

A new Octopress AutoGist plugin

No idea how to implement my own Octopress plugin yet but it may look like this?
I’m not sure how to do this but we will need to gather all code blocks into an array…
Save each one as a separate file in a temp directory with a file format based on the title of the code block?

#!ruby #contents of file 1

Would create a file like “_gist_temp/932423_file1.rb

      #contents of file 2

Would create a file like “_gist_temp/932423_file2.rb”

The 932423 would be some sort of “post” id (not sure if one of those exists)
Possibly a hash of the post filename?

#!ruby
require './plugins/pygments_code'

module AutoGist
  include HighlightCode
  AllOptions = /([^\s]+)\s+(.+?)(https?:\/\/\S+)\s*(.+)?/i
  LangCaption = /([^\s]+)\s*(.+)?/i
  def render_code_block(input)
    @options = nil
    @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
      elsif @options =~ LangCaption
        @lang = $1
      end

      if str.match(/\A( {4}|\t)/)
        str = str.gsub(/^( {4}|\t)/, '')
      end
      if @lang.nil? || @lang == 'plain'
          system "echo ""#{str}"" | gist -t plain"
      else
          system "echo ""#{str}"" | gist -t #{@lang}"
        end
      end
    end
  end
end

Well, that’s all the time I have for today so I’ll be thinking more about this and make some changes appropriately. If I get a new plugin released, I’ll definitely share it! Let me know if anyone has any input on how they would invision this working.

Leave a Reply

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax